Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Network Settings for Ubuntu Core - closes #3155 #3168

Merged
merged 1 commit into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
- name: Install system dependencies
run: |
sudo apt -qq update
sudo apt install -y google-chrome-stable
sudo apt install -y google-chrome-stable libdbus-1-dev
- name: Install node dependencies
run: |
npm ci
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,6 @@ npm-debug.log

# Test artifacts
/coverage/

# Built packages
*.snap
20 changes: 13 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

[![Build Status](https://github.com/WebThingsIO/gateway/workflows/Build/badge.svg)](https://github.com/WebThingsIO/gateway/actions?query=workflow%3ABuild)
[![codecov](https://codecov.io/gh/WebThingsIO/gateway/branch/master/graph/badge.svg)](https://codecov.io/gh/WebThingsIO/gateway)
[![dependencies](https://david-dm.org/WebThingsIO/gateway.svg)](https://david-dm.org/WebThingsIO/gateway)
[![devDependencies](https://david-dm.org/WebThingsIO/gateway/dev-status.svg)](https://david-dm.org/WebThingsIO/gateway?type=dev)
[![license](https://img.shields.io/badge/license-MPL--2.0-blue.svg)](LICENSE)

Web of Things gateway.
Expand All @@ -12,9 +10,8 @@ Web of Things gateway.

- If you have a Rasberry Pi, the easiest way to use the gateway is to [download and flash](http://webthings.io/gateway/) a pre-built software image to an SD card.
- If you prefer to use Docker, we have a prebuilt Docker image available [here](https://hub.docker.com/r/webthingsio/gateway), for both ARM and amd64. You can also build your own image from this repository.
- On Fedora, Debian, Raspberry Pi OS, or Ubuntu, you can install the relevant .rpm or .deb package from the [releases page](https://github.com/WebThingsIO/gateway/releases).
- On Arch Linux, you can install the [webthings-gateway AUR package](https://aur.archlinux.org/packages/webthings-gateway/). The PKGBUILD for this package can also be seen [here](https://github.com/WebThingsIO/gateway-aur).
- Otherwise, you can build it from source yourself (see below).
- On Ubuntu or Ubuntu Core you can install the experimental [snap package](https://snapcraft.io/webthings-gateway) with `$ snap install webthings-gateway --edge`. (Requires the `system-observe` and `network-manager` interfaces to be connected in order to configure network settings).
- Otherwise, you can build WebThings Gateway from source yourself (see below).

## Documentation

Expand Down Expand Up @@ -50,6 +47,7 @@ $ sudo apt install \
libbluetooth-dev \
libboost-python-dev \
libboost-thread-dev \
libdbus-1-dev \
libffi-dev \
libglib2.0-dev \
libpng-dev \
Expand Down Expand Up @@ -93,11 +91,19 @@ $ brew update
$ brew install \
autoconf \
libffi \
pkg-config
$ sudo -H python2 -m pip install six
pkg-config \
python@3.10 \
dbus
$ sudo -H python3 -m pip install git+https://github.com/WebThingsIO/gateway-addon-python#egg=gateway_addon
```

To get DBus to build properly, you currently need to symlink `python` to `python3` if a python binary is not already available. E.g.

```
$ echo 'export PATH=/opt/homebrew/opt/python@3.10/libexec/bin:$PATH' >> ~/.zprofile
$ source ~/.zprofile
```

### Install Node.js

#### nvm (Recommended)
Expand Down
41 changes: 37 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"config": "^3.3.4",
"country-list": "^2.2.0",
"csv-parse": "^4.15.3",
"dbus": "^1.0.7",
"express": "^4.17.1",
"express-fileupload": "^1.2.1",
"express-handlebars": "^5.3.5",
Expand All @@ -52,11 +53,13 @@
"gateway-addon": "^1.2.0-alpha.1",
"glob-to-regexp": "^0.4.1",
"http-proxy": "^1.18.1",
"ip": "^2.0.1",
"ip-regex": "^4.3.0",
"jsonwebtoken": "^8.5.1",
"minipass": "^3.3.5",
"mkdirp": "^1.0.4",
"ncp": "^2.0.0",
"netmask": "^2.0.2",
"nocache": "^2.1.0",
"node-fetch": "^2.6.7",
"node-getopt": "^0.3.2",
Expand Down Expand Up @@ -87,6 +90,7 @@
"@types/compression": "^1.7.0",
"@types/config": "0.0.38",
"@types/country-list": "^2.1.0",
"@types/dbus": "^1.0.9",
"@types/event-to-promise": "^0.7.1",
"@types/eventsource": "^1.1.6",
"@types/express": "^4.17.11",
Expand All @@ -97,12 +101,14 @@
"@types/find": "^0.2.1",
"@types/glob-to-regexp": "^0.4.0",
"@types/http-proxy": "^1.17.5",
"@types/ip": "^1.1.3",
"@types/jest": "^27.0.1",
"@types/jsdom": "^16.2.6",
"@types/jsonfile": "^6.0.0",
"@types/jsonwebtoken": "^8.5.0",
"@types/mkdirp": "^1.0.1",
"@types/ncp": "^2.0.4",
"@types/netmask": "^2.0.5",
"@types/node": "^14.14.31",
"@types/node-fetch": "^2.5.8",
"@types/node-getopt": "^0.2.31",
Expand Down
2 changes: 2 additions & 0 deletions snap/snapcraft.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ apps:
- network
- network-bind
- system-observe
- network-manager

parts:
python-deps:
Expand Down Expand Up @@ -45,6 +46,7 @@ parts:
- libpng-dev
- libudev-dev
- libusb-1.0-0-dev
- libdbus-1-dev
override-build: |
craftctl default
npm install --only-dev
Expand Down
3 changes: 3 additions & 0 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,9 @@ function startGateway(): void {
}

function gracefulExit(): void {
if (Platform.implemented('stop')) {
Platform.stop();
}
AddonManager.unloadAddons();
TunnelService.stop();
}
Expand Down
43 changes: 38 additions & 5 deletions src/controllers/settings_controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import TunnelService from '../tunnel-service';
import * as CertificateManager from '../certificate-manager';
import pkg from '../package.json';
import { HttpErrorWithCode } from '../errors';
import { LanMode, NetworkAddresses } from '../platforms/types';

function build(): express.Router {
const auth = jwtMiddleware.middleware();
Expand Down Expand Up @@ -397,7 +398,11 @@ function build(): express.Router {
});

controller.get('/network/lan', auth, (_request, response) => {
if (Platform.implemented('getLanMode')) {
if (Platform.implemented('getLanModeAsync')) {
Platform.getLanModeAsync().then((mode: LanMode) => {
response.json(mode);
});
} else if (Platform.implemented('getLanMode')) {
response.json(Platform.getLanMode());
} else {
response.status(500).send('LAN mode not implemented');
Expand All @@ -413,7 +418,15 @@ function build(): express.Router {
const mode = request.body.mode;
const options = request.body.options;

if (Platform.implemented('setLanMode')) {
if (Platform.implemented('setLanModeAsync')) {
Platform.setLanModeAsync(mode, options).then((result: boolean) => {
if (result == true) {
response.status(200).json({});
} else {
response.status(500).send('Failed to update LAN configuration');
}
});
} else if (Platform.implemented('setLanMode')) {
if (Platform.setLanMode(mode, options)) {
response.status(200).json({});
} else {
Expand All @@ -433,7 +446,11 @@ function build(): express.Router {
});

controller.get('/network/wireless/networks', auth, (_request, response) => {
if (Platform.implemented('scanWirelessNetworks')) {
if (Platform.implemented('scanWirelessNetworksAsync')) {
Platform.scanWirelessNetworksAsync().then((networks) => {
response.json(networks);
});
} else if (Platform.implemented('scanWirelessNetworks')) {
response.json(Platform.scanWirelessNetworks());
} else {
response.status(500).send('Wireless scanning not implemented');
Expand All @@ -450,7 +467,19 @@ function build(): express.Router {
const mode = request.body.mode;
const options = request.body.options;

if (Platform.implemented('setWirelessMode')) {
if (Platform.implemented('setWirelessModeAsync')) {
Platform.setWirelessModeAsync(enabled, mode, options)
.then((result) => {
if (result === true) {
response.status(200).json({});
} else {
response.status(500).send('Failed to update wireless configuration');
}
})
.catch(() => {
response.status(500).send('Failed to update wireless configuration');
});
} else if (Platform.implemented('setWirelessMode')) {
if (Platform.setWirelessMode(enabled, mode, options)) {
response.status(200).json({});
} else {
Expand All @@ -462,7 +491,11 @@ function build(): express.Router {
});

controller.get('/network/addresses', auth, (_request, response) => {
if (Platform.implemented('getNetworkAddresses')) {
if (Platform.implemented('getNetworkAddressesAsync')) {
Platform.getNetworkAddressesAsync().then((networkAddresses: NetworkAddresses) => {
response.json(networkAddresses);
});
} else if (Platform.implemented('getNetworkAddresses')) {
response.json(Platform.getNetworkAddresses());
} else {
response.status(500).send('Network addresses not implemented');
Expand Down
33 changes: 28 additions & 5 deletions src/platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import LinuxArchPlatform from './platforms/linux-arch';
import LinuxDebianPlatform from './platforms/linux-debian';
import LinuxRaspbianPlatform from './platforms/linux-raspbian';
import LinuxUbuntuPlatform from './platforms/linux-ubuntu';
import LinuxUbuntuCorePlatform from './platforms/linux-ubuntu-core';
import {
LanMode,
NetworkAddresses,
Expand Down Expand Up @@ -68,7 +69,7 @@ export function getOS(): string {
return 'linux-unknown';
}

// Otherwise try to detect if running on Ubuntu Core.
// Otherwise try to detect Ubuntu or Ubuntu Core from inside a snap
try {
const osReleaseLines = fs
.readFileSync('/var/lib/snapd/hostfs/etc/os-release', {
Expand All @@ -85,10 +86,14 @@ export function getOS(): string {
let id = line.substring(3, line.length);
// Remove any quotation marks
id = id.replace(/"/g, '');
if (id == 'ubuntu-core') {
return 'linux-ubuntu-core';
} else {
console.log('Unknown host Linux distribution');
switch (id) {
case 'ubuntu':
return 'linux-ubuntu';
case 'ubuntu-core':
return 'linux-ubuntu-core';
default:
console.log('Unknown host Linux distribution');
break;
}
}
}
Expand Down Expand Up @@ -195,6 +200,9 @@ switch (getOS()) {
case 'linux-ubuntu':
platform = LinuxUbuntuPlatform;
break;
case 'linux-ubuntu-core':
platform = LinuxUbuntuCorePlatform;
break;
default:
platform = null;
break;
Expand All @@ -205,21 +213,35 @@ export const setDhcpServerStatus = wrapPlatform<boolean>(platform, 'setDhcpServe
export const getHostname = wrapPlatform<string>(platform, 'getHostname');
export const setHostname = wrapPlatform<boolean>(platform, 'setHostname');
export const getLanMode = wrapPlatform<LanMode>(platform, 'getLanMode');
export const getLanModeAsync = wrapPlatform<Promise<LanMode>>(platform, 'getLanModeAsync');
export const setLanMode = wrapPlatform<boolean>(platform, 'setLanMode');
export const setLanModeAsync = wrapPlatform<Promise<boolean>>(platform, 'setLanModeAsync');
export const getMacAddress = wrapPlatform<string | null>(platform, 'getMacAddress');
export const getMdnsServerStatus = wrapPlatform<boolean>(platform, 'getMdnsServerStatus');
export const setMdnsServerStatus = wrapPlatform<boolean>(platform, 'setMdnsServerStatus');
export const getNetworkAddresses = wrapPlatform<NetworkAddresses>(platform, 'getNetworkAddresses');
export const getNetworkAddressesAsync = wrapPlatform<Promise<NetworkAddresses>>(
platform,
'getNetworkAddressesAsync'
);
export const getSshServerStatus = wrapPlatform<boolean>(platform, 'getSshServerStatus');
export const setSshServerStatus = wrapPlatform<boolean>(platform, 'setSshServerStatus');
export const getWirelessMode = wrapPlatform<WirelessMode>(platform, 'getWirelessMode');
export const setWirelessMode = wrapPlatform<boolean>(platform, 'setWirelessMode');
export const setWirelessModeAsync = wrapPlatform<Promise<boolean>>(
platform,
'setWirelessModeAsync'
);
export const restartGateway = wrapPlatform<boolean>(platform, 'restartGateway');
export const restartSystem = wrapPlatform<boolean>(platform, 'restartSystem');
export const scanWirelessNetworks = wrapPlatform<WirelessNetwork[]>(
platform,
'scanWirelessNetworks'
);
export const scanWirelessNetworksAsync = wrapPlatform<Promise<WirelessNetwork[]>>(
platform,
'scanWirelessNetworksAsync'
);
export const getSelfUpdateStatus = wrapPlatform<SelfUpdateStatus>(platform, 'getSelfUpdateStatus');
export const setSelfUpdateStatus = wrapPlatform<boolean>(platform, 'setSelfUpdateStatus');
export const getValidTimezones = wrapPlatform<string[]>(platform, 'getValidTimezones');
Expand All @@ -239,6 +261,7 @@ export const getNtpStatus = (): boolean => {

return wrapPlatform<boolean>(platform, 'getNtpStatus')();
};
export const stop = wrapPlatform<string>(platform, 'stop');

export const implemented = (fn: string): boolean => {
if (platform === null) {
Expand Down
Loading
Loading