mirror of
https://github.com/balena-os/balena-supervisor.git
synced 2025-04-10 12:49:54 +00:00
Replace the gosuper component with a node module that handles communication with systemd, and stop using an init system in the supervisor container
Change-Type: patch Signed-off-by: Pablo Carranza Velez <pablo@resin.io>
This commit is contained in:
parent
11e8899455
commit
348ff66cee
69
Dockerfile
69
Dockerfile
@ -1,63 +1,4 @@
|
||||
ARG ARCH=amd64
|
||||
# Build golang supervisor
|
||||
FROM debian:jessie-20170723 as gosuper
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y \
|
||||
build-essential \
|
||||
curl \
|
||||
rsync \
|
||||
&& rm -rf /var/lib/apt/lists/
|
||||
|
||||
ENV GOLANG_VERSION 1.8.3
|
||||
ENV GOLANG_DOWNLOAD_URL https://golang.org/dl/go$GOLANG_VERSION.linux-amd64.tar.gz
|
||||
ENV GOLANG_DOWNLOAD_SHA256 1862f4c3d3907e59b04a757cfda0ea7aa9ef39274af99a784f5be843c80c6772
|
||||
|
||||
COPY gosuper/go-${GOLANG_VERSION}-patches /go-${GOLANG_VERSION}-patches
|
||||
|
||||
RUN mkdir /usr/src/go \
|
||||
&& cd /usr/src/go \
|
||||
&& curl -L -o go.tar.gz $GOLANG_DOWNLOAD_URL \
|
||||
&& echo "${GOLANG_DOWNLOAD_SHA256} go.tar.gz" | sha256sum -c - \
|
||||
&& tar xzf go.tar.gz -C /usr/local \
|
||||
&& cd /usr/src \
|
||||
&& rm -rf go \
|
||||
&& export GOROOT_BOOTSTRAP=/usr/local/go-bootstrap \
|
||||
&& cp -r /usr/local/go /usr/local/go-bootstrap \
|
||||
&& cd /usr/local/go/src \
|
||||
&& patch -p2 -i /go-${GOLANG_VERSION}-patches/0001-dont-fail-when-no-mmx.patch \
|
||||
&& patch -p2 -i /go-${GOLANG_VERSION}-patches/0002-implement-atomic-quadword-ops-with-FILD-FISTP.patch \
|
||||
&& ./make.bash \
|
||||
&& rm -rf /usr/local/go-bootstrap
|
||||
|
||||
ENV UPX_VERSION 3.94
|
||||
# UPX doesn't provide fingerprints so I checked this one manually
|
||||
ENV UPX_SHA256 e1fc0d55c88865ef758c7e4fabbc439e4b5693b9328d219e0b9b3604186abe20
|
||||
|
||||
RUN mkdir /usr/src/upx \
|
||||
&& cd /usr/src/upx \
|
||||
&& curl -L -o upx.tar.xz https://github.com/upx/upx/releases/download/v$UPX_VERSION/upx-$UPX_VERSION-amd64_linux.tar.xz \
|
||||
&& echo "${UPX_SHA256} upx.tar.xz" | sha256sum -c - \
|
||||
&& tar xf upx.tar.xz --strip-components=1 \
|
||||
&& cp ./upx /usr/bin/ \
|
||||
&& cd /usr/src \
|
||||
&& rm -rf upx
|
||||
|
||||
ENV GOPATH /go
|
||||
ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH
|
||||
|
||||
COPY ./gosuper /go/src/resin-supervisor/gosuper
|
||||
|
||||
WORKDIR /go/src/resin-supervisor/gosuper
|
||||
|
||||
ENV GOOS linux
|
||||
ENV GO386=387
|
||||
|
||||
ARG ARCH
|
||||
RUN bash ./build.sh
|
||||
RUN rsync -a --delete /go/bin/gosuper /build/
|
||||
|
||||
##############################################################################
|
||||
|
||||
# The node version here should match the version of the runtime image which is
|
||||
# specified in the base-image subdirectory in the project
|
||||
@ -146,12 +87,7 @@ RUN find . -path '*/coverage/*' -o -path '*/test/*' -o -path '*/.nyc_output/*' \
|
||||
&& find . -type f -path '*/node_modules/knex/build*' -delete \
|
||||
&& rm -rf node_modules/sqlite3/node.dtps
|
||||
|
||||
# Create /var/run/resin for the gosuper to place its socket in
|
||||
RUN mkdir -p rootfs-overlay/var/run/resin
|
||||
|
||||
COPY entry.sh run.sh package.json rootfs-overlay/usr/src/app/
|
||||
|
||||
COPY inittab rootfs-overlay/etc/inittab
|
||||
COPY entry.sh package.json rootfs-overlay/usr/src/app/
|
||||
|
||||
RUN rsync -a --delete node_modules rootfs-overlay /build
|
||||
|
||||
@ -171,7 +107,6 @@ WORKDIR /usr/src/app
|
||||
|
||||
COPY --from=node-build /usr/src/app/dist ./dist
|
||||
COPY --from=node-deps /build/node_modules ./node_modules
|
||||
COPY --from=gosuper /build/gosuper ./gosuper
|
||||
COPY --from=node-deps /build/rootfs-overlay/ /
|
||||
|
||||
VOLUME /data
|
||||
@ -186,3 +121,5 @@ ENV CONFIG_MOUNT_POINT=/boot/config.json \
|
||||
|
||||
HEALTHCHECK --interval=5m --start-period=1m --timeout=30s --retries=3 \
|
||||
CMD wget -qO- http://127.0.0.1:${LISTEN_PORT:-48484}/v1/healthy || exit 1
|
||||
|
||||
CMD [ "./entry.sh" ]
|
||||
|
34
Makefile
34
Makefile
@ -6,7 +6,6 @@
|
||||
# Build targets (require Docker 17.05 or greater):
|
||||
# * supervisor (default) - builds a resin-supervisor image
|
||||
# * deploy - pushes a resin-supervisor image to the registry, retrying up to 3 times
|
||||
# * gosuper - builds the "gosuper" component (a golang image with the Go supervisor component at /go/bin/gosuper and /build/gosuper)
|
||||
# * nodedeps, nodebuild - builds the node component, with the node_modules and src at /usr/src/app and /build (also includes a rootfs-overlay there)
|
||||
# * supervisor-dind: build the development docker-in-docker supervisor that run-supervisor uses (requires a SUPERVISOR_IMAGE to be available locally)
|
||||
#
|
||||
@ -19,8 +18,6 @@
|
||||
#
|
||||
# Test/development targets:
|
||||
# * run-supervisor, stop-supervisor - build and start or stop a docker-in-docker resin-supervisor (requires aufs, ability to run privileged containers, and a SUPERVISOR_IMAGE to be available locally)
|
||||
# * format-gosuper, test-gosuper - build a gosuper image and run formatting or unit tests
|
||||
# * test-integration - run an integration test (see gosuper/supertest). Requires a docker-in-docker supervisor to be running
|
||||
#
|
||||
# Variables for test/dev targets:
|
||||
# * IMAGE: image to build and run (either for run-supervisor or test-gosuper/integration)
|
||||
@ -193,33 +190,4 @@ nodedeps:
|
||||
nodebuild:
|
||||
$(MAKE) -f $(THIS_FILE) TARGET_COMPONENT=node-build IMAGE=$(IMAGE) ARCH=$(ARCH) supervisor-image
|
||||
|
||||
gosuper:
|
||||
$(MAKE) -f $(THIS_FILE) TARGET_COMPONENT=gosuper IMAGE=$(IMAGE) ARCH=$(ARCH) supervisor-image
|
||||
|
||||
test-gosuper: gosuper
|
||||
docker run \
|
||||
--rm \
|
||||
-v /var/run/dbus:/mnt/root/run/dbus \
|
||||
-e DBUS_SYSTEM_BUS_ADDRESS="/mnt/root/run/dbus/system_bus_socket" \
|
||||
$(IMAGE) bash -c \
|
||||
'./test_formatting.sh && go test -v ./gosuper'
|
||||
|
||||
format-gosuper: gosuper
|
||||
docker run \
|
||||
--rm \
|
||||
-v $(shell pwd)/gosuper:/go/src/resin-supervisor/gosuper \
|
||||
$(IMAGE) \
|
||||
go fmt ./...
|
||||
|
||||
test-integration: gosuper
|
||||
docker run \
|
||||
--rm \
|
||||
--net=host \
|
||||
-e SUPERVISOR_IP="$(shell docker inspect --format '{{ .NetworkSettings.IPAddress }}' resin_supervisor_1)" \
|
||||
--volumes-from resin_supervisor_1 \
|
||||
-v /var/run/dbus:/mnt/root/run/dbus \
|
||||
-e DBUS_SYSTEM_BUS_ADDRESS="/mnt/root/run/dbus/system_bus_socket" \
|
||||
$(IMAGE) \
|
||||
go test -v ./supertest
|
||||
|
||||
.PHONY: supervisor deploy nodedeps nodebuild gosuper supervisor-dind run-supervisor
|
||||
.PHONY: supervisor deploy nodedeps nodebuild supervisor-dind run-supervisor
|
||||
|
@ -18,7 +18,6 @@
|
||||
#
|
||||
# It pulls intermediate images for caching, if available:
|
||||
# resin/$ARCH-supervisor-node:$TAG
|
||||
# resin/$ARCH-supervisor-go:$TAG
|
||||
#
|
||||
# In all of these cases it will use "master" if $TAG is not found.
|
||||
#
|
||||
@ -49,15 +48,12 @@ TARGET_IMAGE=resin/$ARCH-supervisor:$TAG
|
||||
# Intermediate images and cache
|
||||
NODE_IMAGE=resin/$ARCH-supervisor-node:$TAG
|
||||
NODE_BUILD_IMAGE=resin/$ARCH-supervisor-node:$TAG-build
|
||||
GO_IMAGE=resin/$ARCH-supervisor-go:$TAG
|
||||
|
||||
TARGET_CACHE=$TARGET_IMAGE
|
||||
GO_CACHE=$GO_IMAGE
|
||||
NODE_CACHE=$NODE_IMAGE
|
||||
NODE_BUILD_CACHE=$NODE_BUILD_IMAGE
|
||||
|
||||
TARGET_CACHE_MASTER=resin/$ARCH-supervisor:master
|
||||
GO_CACHE_MASTER=resin/$ARCH-supervisor-go:master
|
||||
NODE_CACHE_MASTER=resin/$ARCH-supervisor-node:master
|
||||
NODE_BUILD_CACHE_MASTER=resin/$ARCH-supervisor-node:master-build
|
||||
|
||||
@ -73,29 +69,17 @@ function tryPullForCache() {
|
||||
# Only if the pull succeeds we add a --cache-from option
|
||||
tryPullForCache $TARGET_CACHE
|
||||
tryPullForCache $TARGET_CACHE_MASTER
|
||||
tryPullForCache $GO_CACHE
|
||||
tryPullForCache $GO_CACHE_MASTER
|
||||
tryPullForCache $NODE_CACHE
|
||||
tryPullForCache $NODE_CACHE_MASTER
|
||||
tryPullForCache $NODE_BUILD_CACHE
|
||||
tryPullForCache $NODE_BUILD_CACHE_MASTER
|
||||
|
||||
if [ "$ENABLE_TESTS" = "true" ]; then
|
||||
make ARCH=$ARCH IMAGE=$GO_IMAGE test-gosuper
|
||||
fi
|
||||
|
||||
export DOCKER_BUILD_OPTIONS=${CACHE_FROM}
|
||||
export ARCH
|
||||
export PUBNUB_PUBLISH_KEY
|
||||
export PUBNUB_SUBSCRIBE_KEY
|
||||
export MIXPANEL_TOKEN
|
||||
|
||||
make IMAGE=$GO_IMAGE gosuper
|
||||
if [ "$PUSH_IMAGES" = "true" ]; then
|
||||
make IMAGE=$GO_IMAGE deploy || true
|
||||
fi
|
||||
export DOCKER_BUILD_OPTIONS="${DOCKER_BUILD_OPTIONS} --cache-from ${GO_IMAGE}"
|
||||
|
||||
make IMAGE=$NODE_BUILD_IMAGE nodebuild
|
||||
if [ "$PUSH_IMAGES" = "true" ]; then
|
||||
make IMAGE=$NODE_BUILD_IMAGE deploy || true
|
||||
@ -123,12 +107,10 @@ fi
|
||||
if [ "$CLEANUP" = "true" ]; then
|
||||
tryRemove $TARGET_IMAGE
|
||||
|
||||
tryRemove $GO_IMAGE
|
||||
tryRemove $NODE_IMAGE
|
||||
tryRemove $NODE_BUILD_IMAGE
|
||||
|
||||
tryRemove $TARGET_CACHE
|
||||
tryRemove $GO_CACHE
|
||||
tryRemove $NODE_BUILD_CACHE
|
||||
tryRemove $NODE_CACHE
|
||||
fi
|
||||
|
@ -18,7 +18,7 @@ Alternatively, the Resin API (api.resin.io) has a proxy endpoint at `POST /super
|
||||
|
||||
The API is versioned (currently at v1), except for `/ping`.
|
||||
|
||||
You might notice that the formats of some responses differ. This is because they were implemented later, and in Go instead of node.js.
|
||||
You might notice that the formats of some responses differ. This is because they were implemented later, and in Go instead of node.js - even if the Go pieces were later removed, so we kept the response format for backwards compatibility.
|
||||
|
||||
Here's the full list of endpoints implemented so far. In all examples, replace everything between `< >` for the corresponding values.
|
||||
|
||||
@ -119,7 +119,6 @@ When successful, responds with 202 accepted and a JSON object:
|
||||
"Error": ""
|
||||
}
|
||||
```
|
||||
(This is implemented in Go)
|
||||
|
||||
#### Request body
|
||||
Can contain a `force` property, which if set to `true` will cause the update lock to be overridden.
|
||||
@ -158,7 +157,6 @@ When successful, responds with 202 accepted and a JSON object:
|
||||
"Error": ""
|
||||
}
|
||||
```
|
||||
(This is implemented in Go)
|
||||
|
||||
#### Request body
|
||||
Can contain a `force` property, which if set to `true` will cause the update lock to be overridden.
|
||||
@ -197,8 +195,6 @@ When successful, responds with 200 and a JSON object:
|
||||
}
|
||||
```
|
||||
|
||||
(This is implemented in Go)
|
||||
|
||||
#### Request body
|
||||
Has to be a JSON object with an `appId` property, corresponding to the ID of the application the device is running.
|
||||
|
||||
|
15
entry.sh
15
entry.sh
@ -2,16 +2,9 @@
|
||||
|
||||
set -o errexit
|
||||
|
||||
[ -d /dev/net ] ||
|
||||
mkdir -p /dev/net
|
||||
[ -c /dev/net/tun ] ||
|
||||
mknod /dev/net/tun c 10 200
|
||||
[ -d /mnt/root/tmp/resin-supervisor ] ||
|
||||
mkdir -p /mnt/root/tmp/resin-supervisor
|
||||
|
||||
mkdir -p /var/run/resin
|
||||
mount -t tmpfs -o size=1m tmpfs /var/run/resin
|
||||
|
||||
# If DOCKER_ROOT isn't set then default it
|
||||
if [ -z "${DOCKER_ROOT}" ]; then
|
||||
DOCKER_ROOT=/mnt/root/var/lib/rce
|
||||
@ -23,3 +16,11 @@ DOCKER_LIB_PATH=${DOCKER_ROOT#/mnt/root}
|
||||
if [ ! -d "${DOCKER_LIB_PATH}" ]; then
|
||||
ln -s "${DOCKER_ROOT}" "${DOCKER_LIB_PATH}"
|
||||
fi
|
||||
|
||||
if [ -z "$DOCKER_SOCKET" ]; then
|
||||
export DOCKER_SOCKET=/run/docker.sock
|
||||
fi
|
||||
|
||||
export DBUS_SYSTEM_BUS_ADDRESS="unix:path=/mnt/root/run/dbus/system_bus_socket"
|
||||
|
||||
exec node /usr/src/app/dist/app.js
|
||||
|
7
inittab
7
inittab
@ -1,7 +0,0 @@
|
||||
# busybox inittab
|
||||
# format: tty:ignored:action:command
|
||||
|
||||
stdout::sysinit:/usr/src/app/entry.sh
|
||||
|
||||
stdout::respawn:/usr/src/app/run.sh node /usr/src/app/dist/app.js
|
||||
stdout::respawn:/usr/src/app/run.sh /usr/src/app/gosuper
|
@ -29,6 +29,7 @@
|
||||
"coffee-loader": "^0.7.3",
|
||||
"coffee-script": "~1.11.0",
|
||||
"copy-webpack-plugin": "^4.2.3",
|
||||
"dbus-native": "^0.2.5",
|
||||
"docker-delta": "^2.0.4",
|
||||
"docker-progress": "^2.7.2",
|
||||
"docker-toolbelt": "^3.2.1",
|
||||
|
22
run.sh
22
run.sh
@ -1,22 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ -z "$GOSUPER_SOCKET" ]; then
|
||||
export GOSUPER_SOCKET=/var/run/resin/gosuper.sock
|
||||
fi
|
||||
|
||||
if [ -z "$DOCKER_SOCKET" ]; then
|
||||
export DOCKER_SOCKET=/run/docker.sock
|
||||
fi
|
||||
|
||||
if [ -z "$HOST_PROC" ]; then
|
||||
export HOST_PROC=/mnt/root/proc
|
||||
fi
|
||||
|
||||
export DBUS_SYSTEM_BUS_ADDRESS="/mnt/root/run/dbus/system_bus_socket"
|
||||
|
||||
# If DOCKER_ROOT isn't set then default it
|
||||
if [ -z "${DOCKER_ROOT}" ]; then
|
||||
DOCKER_ROOT=/mnt/root/var/lib/rce
|
||||
fi
|
||||
|
||||
exec $@
|
@ -4,9 +4,10 @@ childProcess = Promise.promisifyAll(require('child_process'))
|
||||
fs = Promise.promisifyAll(require('fs'))
|
||||
|
||||
constants = require './lib/constants'
|
||||
gosuper = require './lib/gosuper'
|
||||
systemd = require './lib/systemd'
|
||||
fsUtils = require './lib/fs-utils'
|
||||
{ checkTruthy, checkInt } = require './lib/validation'
|
||||
{ UnitNotLoadedError } = require './lib/errors'
|
||||
|
||||
hostConfigConfigVarPrefix = 'RESIN_HOST_'
|
||||
bootConfigEnvVarPrefix = hostConfigConfigVarPrefix + 'CONFIG_'
|
||||
@ -33,10 +34,12 @@ forbiddenConfigKeys = [
|
||||
]
|
||||
arrayConfigKeys = [ 'dtparam', 'dtoverlay', 'device_tree_param', 'device_tree_overlay' ]
|
||||
|
||||
logToDisplayServiceName = 'resin-info@tty1'
|
||||
vpnServiceName = 'openvpn-resin'
|
||||
|
||||
module.exports = class DeviceConfig
|
||||
constructor: ({ @db, @config, @logger }) ->
|
||||
@rebootRequired = false
|
||||
@gosuperHealthy = true
|
||||
@configKeys = {
|
||||
appUpdatePollInterval: { envVarName: 'RESIN_SUPERVISOR_POLL_INTERVAL', varType: 'int', defaultValue: '60000' }
|
||||
localMode: { envVarName: 'RESIN_SUPERVISOR_LOCAL_MODE', varType: 'bool', defaultValue: 'false' }
|
||||
@ -253,27 +256,33 @@ module.exports = class DeviceConfig
|
||||
return @bootConfigToEnv(conf)
|
||||
|
||||
getLogToDisplay: ->
|
||||
gosuper.get('/v1/log-to-display', { json: true })
|
||||
.spread (res, body) ->
|
||||
if res.statusCode == 404
|
||||
return
|
||||
if res.statusCode != 200
|
||||
throw new Error("Error getting log to display status: #{res.statusCode} #{body.Error}")
|
||||
return Boolean(body.Data)
|
||||
systemd.serviceActiveState(logToDisplayServiceName)
|
||||
.then (activeState) ->
|
||||
return activeState not in [ 'inactive', 'deactivating' ]
|
||||
.catchReturn(UnitNotLoadedError, null)
|
||||
|
||||
setLogToDisplay: (val) =>
|
||||
Promise.try =>
|
||||
enable = checkTruthy(val)
|
||||
if !enable?
|
||||
throw new Error("Invalid value in call to setLogToDisplay: #{val}")
|
||||
gosuper.post('/v1/log-to-display', { json: true, body: Enable: enable })
|
||||
.spread (response, body) =>
|
||||
if response.statusCode != 200
|
||||
throw new Error("#{response.statusCode} #{body.Error}")
|
||||
@getLogToDisplay()
|
||||
.then (currentState) ->
|
||||
if !currentState? or currentState == enable
|
||||
return false
|
||||
if enable
|
||||
systemd.startService(logToDisplayServiceName)
|
||||
.then ->
|
||||
systemd.enableService(logToDisplayServiceName)
|
||||
.return(true)
|
||||
else
|
||||
if body.Data == true
|
||||
@rebootRequired = true
|
||||
return body.Data
|
||||
systemd.stopService(logToDisplayServiceName)
|
||||
.then ->
|
||||
systemd.disableService(logToDisplayServiceName)
|
||||
.return(true)
|
||||
.tap (changed) =>
|
||||
if changed
|
||||
@rebootRequired = true
|
||||
|
||||
setBootConfig: (deviceType, target) =>
|
||||
Promise.try =>
|
||||
@ -302,18 +311,14 @@ module.exports = class DeviceConfig
|
||||
@logger.logSystemMessage("Error setting boot config: #{err}", { error: err }, 'Apply boot config error')
|
||||
|
||||
getVPNEnabled: ->
|
||||
gosuper.get('/v1/vpncontrol', { json: true })
|
||||
.spread (res, body) ->
|
||||
if res.statusCode != 200
|
||||
throw new Error("Error getting vpn status: #{res.statusCode} #{body.Error}")
|
||||
@gosuperHealthy = true
|
||||
return Boolean(body.Data)
|
||||
.tapCatch (err) =>
|
||||
@gosuperHealthy = false
|
||||
systemd.serviceActiveState(vpnServiceName)
|
||||
.then (activeState) ->
|
||||
return activeState not in [ 'inactive', 'deactivating' ]
|
||||
.catchReturn(UnitNotLoadedError, null)
|
||||
|
||||
setVPNEnabled: (val) ->
|
||||
enable = checkTruthy(val) ? true
|
||||
gosuper.post('/v1/vpncontrol', { json: true, body: Enable: enable })
|
||||
.spread (response, body) ->
|
||||
if response.statusCode != 202
|
||||
throw new Error("#{response.statusCode} #{body?.Error}")
|
||||
if enable
|
||||
systemd.startService(vpnServiceName)
|
||||
else
|
||||
systemd.stopService(vpnServiceName)
|
||||
|
@ -10,7 +10,7 @@ network = require './network'
|
||||
|
||||
constants = require './lib/constants'
|
||||
validation = require './lib/validation'
|
||||
device = require './lib/device'
|
||||
systemd = require './lib/systemd'
|
||||
updateLock = require './lib/update-lock'
|
||||
{ singleToMulticontainerApp } = require './lib/migration'
|
||||
|
||||
@ -139,7 +139,7 @@ module.exports = class DeviceState extends EventEmitter
|
||||
cycleTimeMs = cycleTime[0] * 1000 + cycleTime[1] / 1e6
|
||||
cycleTimeWithinInterval = cycleTimeMs - @applications.timeSpentFetching < 2 * conf.appUpdatePollInterval
|
||||
applyTargetHealthy = conf.offlineMode or !@applyInProgress or @applications.fetchesInProgress > 0 or cycleTimeWithinInterval
|
||||
return applyTargetHealthy and @deviceConfig.gosuperHealthy
|
||||
return applyTargetHealthy
|
||||
|
||||
normaliseLegacy: =>
|
||||
# When legacy apps are present, we kill their containers and migrate their /data to a named volume
|
||||
@ -345,7 +345,7 @@ module.exports = class DeviceState extends EventEmitter
|
||||
@applications.stopAll({ force, skipLock })
|
||||
.then =>
|
||||
@logger.logSystemMessage('Rebooting', {}, 'Reboot')
|
||||
device.reboot()
|
||||
systemd.reboot()
|
||||
.tap =>
|
||||
@shuttingDown = true
|
||||
@emitAsync('shutdown')
|
||||
@ -354,7 +354,7 @@ module.exports = class DeviceState extends EventEmitter
|
||||
@applications.stopAll({ force, skipLock })
|
||||
.then =>
|
||||
@logger.logSystemMessage('Shutting down', {}, 'Shutdown')
|
||||
device.shutdown()
|
||||
systemd.shutdown()
|
||||
.tap =>
|
||||
@shuttingDown = true
|
||||
@emitAsync('shutdown')
|
||||
|
@ -1,6 +1,6 @@
|
||||
Promise = require 'bluebird'
|
||||
_ = require 'lodash'
|
||||
gosuper = require './lib/gosuper'
|
||||
systemd = require './lib/systemd'
|
||||
path = require 'path'
|
||||
constants = require './lib/constants'
|
||||
fs = Promise.promisifyAll(require('fs'))
|
||||
@ -28,18 +28,10 @@ redsocksFooter = '}\n'
|
||||
|
||||
proxyFields = [ 'type', 'ip', 'port', 'login', 'password' ]
|
||||
|
||||
proxyBasePath = path.join('/mnt/root', constants.bootMountPoint, 'system-proxy')
|
||||
proxyBasePath = path.join(constants.rootMountPoint, constants.bootMountPoint, 'system-proxy')
|
||||
redsocksConfPath = path.join(proxyBasePath, 'redsocks.conf')
|
||||
noProxyPath = path.join(proxyBasePath, 'no_proxy')
|
||||
|
||||
restartSystemdService = (serviceName) ->
|
||||
gosuper.post('/v1/restart-service', { json: true, body: Name: serviceName })
|
||||
.spread (response, body) ->
|
||||
if response.statusCode != 200
|
||||
err = new Error("Error restarting service #{serviceName}: #{response.statusCode} #{body}")
|
||||
err.statusCode = response.statusCode
|
||||
throw err
|
||||
|
||||
readProxy = ->
|
||||
fs.readFileAsync(redsocksConfPath)
|
||||
.then (redsocksConf) ->
|
||||
@ -97,11 +89,11 @@ setProxy = (conf) ->
|
||||
redsocksConf += redsocksFooter
|
||||
writeFileAtomic(redsocksConfPath, redsocksConf)
|
||||
.then ->
|
||||
restartSystemdService('resin-proxy-config')
|
||||
systemd.restartService('resin-proxy-config')
|
||||
.then ->
|
||||
restartSystemdService('redsocks')
|
||||
systemd.restartService('redsocks')
|
||||
|
||||
hostnamePath = '/mnt/root/etc/hostname'
|
||||
hostnamePath = path.join(constants.rootMountPoint, '/etc/hostname')
|
||||
readHostname = ->
|
||||
fs.readFileAsync(hostnamePath)
|
||||
.then (hostnameData) ->
|
||||
@ -110,7 +102,7 @@ readHostname = ->
|
||||
setHostname = (val, configModel) ->
|
||||
configModel.set(hostname: val)
|
||||
.then ->
|
||||
restartSystemdService('resin-hostname')
|
||||
systemd.restartService('resin-hostname')
|
||||
|
||||
|
||||
exports.get = ->
|
||||
|
@ -8,7 +8,6 @@ supervisorNetworkInterface = 'supervisor0'
|
||||
module.exports =
|
||||
rootMountPoint: rootMountPoint
|
||||
databasePath: checkString(process.env.DATABASE_PATH) ? '/data/database.sqlite'
|
||||
gosuperAddress: "http://unix:#{process.env.GOSUPER_SOCKET}:"
|
||||
dockerSocket: process.env.DOCKER_SOCKET ? '/var/run/docker.sock'
|
||||
supervisorImage: checkString(process.env.SUPERVISOR_IMAGE) ? 'resin/rpi-supervisor'
|
||||
ledFile: checkString(process.env.LED_FILE) ? '/sys/class/leds/led0/brightness'
|
||||
|
@ -1,14 +0,0 @@
|
||||
gosuper = require './gosuper'
|
||||
|
||||
gosuperAction = (action) ->
|
||||
gosuper.post("/v1/#{action}", { json: true })
|
||||
.spread (res, body) ->
|
||||
if res.statusCode != 202
|
||||
throw new Error(body.Error)
|
||||
return body
|
||||
|
||||
exports.reboot = ->
|
||||
gosuperAction('reboot')
|
||||
|
||||
exports.shutdown = ->
|
||||
gosuperAction('shutdown')
|
@ -3,3 +3,4 @@
|
||||
exports.NotFoundError = (err) -> checkInt(err.statusCode) is 404
|
||||
exports.ENOENT = (err) -> err.code is 'ENOENT'
|
||||
exports.EEXIST = (err) -> err.code is 'EEXIST'
|
||||
exports.UnitNotLoadedError = (err) -> err[0]?.endsWith?('not loaded.')
|
||||
|
@ -1,20 +0,0 @@
|
||||
Promise = require 'bluebird'
|
||||
_ = require 'lodash'
|
||||
{ request } = require './request'
|
||||
constants = require './constants'
|
||||
|
||||
emptyHostRequest = request.defaults({ headers: Host: '' })
|
||||
gosuperRequest = (method, endpoint, options = {}, callback) ->
|
||||
if _.isFunction(options)
|
||||
callback = options
|
||||
options = {}
|
||||
options.method = method
|
||||
options.url = constants.gosuperAddress + endpoint
|
||||
emptyHostRequest(options, callback)
|
||||
|
||||
gosuperPost = _.partial(gosuperRequest, 'POST')
|
||||
gosuperGet = _.partial(gosuperRequest, 'GET')
|
||||
|
||||
module.exports =
|
||||
post: Promise.promisify(gosuperPost, multiArgs: true)
|
||||
get: Promise.promisify(gosuperGet, multiArgs: true)
|
55
src/lib/systemd.coffee
Normal file
55
src/lib/systemd.coffee
Normal file
@ -0,0 +1,55 @@
|
||||
dbus = require 'dbus-native'
|
||||
Promise = require 'bluebird'
|
||||
|
||||
bus = Promise.promisifyAll(dbus.systemBus())
|
||||
|
||||
systemdManagerMethodCall = (method, signature = '', body = []) ->
|
||||
bus.invokeAsync({
|
||||
path: '/org/freedesktop/systemd1'
|
||||
destination: 'org.freedesktop.systemd1'
|
||||
interface: 'org.freedesktop.systemd1.Manager'
|
||||
member: method
|
||||
signature
|
||||
body
|
||||
})
|
||||
|
||||
exports.restartService = (serviceName) ->
|
||||
systemdManagerMethodCall('RestartUnit', 'ss', [ "#{serviceName}.service", 'fail' ])
|
||||
|
||||
exports.startService = (serviceName) ->
|
||||
systemdManagerMethodCall('StartUnit', 'ss', [ "#{serviceName}.service", 'fail' ])
|
||||
|
||||
exports.stopService = (serviceName) ->
|
||||
systemdManagerMethodCall('StopUnit', 'ss', [ "#{serviceName}.service", 'fail' ])
|
||||
|
||||
exports.enableService = (serviceName) ->
|
||||
systemdManagerMethodCall('EnableUnitFiles', 'asbb', [ [ "#{serviceName}.service" ], false, false ])
|
||||
|
||||
exports.disableService = (serviceName) ->
|
||||
systemdManagerMethodCall('DisableUnitFiles', 'asb', [ [ "#{serviceName}.service" ], false ])
|
||||
|
||||
exports.reboot = Promise.method ->
|
||||
setTimeout( ->
|
||||
systemdManagerMethodCall('Reboot')
|
||||
, 1000)
|
||||
|
||||
exports.shutdown = Promise.method ->
|
||||
setTimeout( ->
|
||||
systemdManagerMethodCall('PowerOff')
|
||||
, 1000)
|
||||
|
||||
getUnitProperty = (unitName, property) ->
|
||||
systemdManagerMethodCall('GetUnit', 's', [ unitName ])
|
||||
.then (unitPath) ->
|
||||
bus.invokeAsync({
|
||||
path: unitPath
|
||||
destination: 'org.freedesktop.systemd1'
|
||||
interface: 'org.freedesktop.DBus.Properties'
|
||||
member: 'Get'
|
||||
signature: 'ss'
|
||||
body: [ 'org.freedesktop.systemd1.Unit', property ]
|
||||
})
|
||||
.get(1).get(0)
|
||||
|
||||
exports.serviceActiveState = (serviceName) ->
|
||||
getUnitProperty("#{serviceName}.service", 'ActiveState')
|
Loading…
x
Reference in New Issue
Block a user