mirror of
https://github.com/balena-os/balena-supervisor.git
synced 2025-01-31 08:25:36 +00:00
Merge pull request #844 from balena-io/local-mode-unmanaged
Unmanaged + local mode fixes
This commit is contained in:
commit
d3d0e19a16
@ -57,9 +57,9 @@ module.exports = class APIBinder
|
||||
@readyForUpdates = false
|
||||
|
||||
healthcheck: =>
|
||||
@config.getMany([ 'appUpdatePollInterval', 'offlineMode', 'connectivityCheckEnabled' ])
|
||||
@config.getMany([ 'appUpdatePollInterval', 'unmanaged', 'connectivityCheckEnabled' ])
|
||||
.then (conf) =>
|
||||
if conf.offlineMode
|
||||
if conf.unmanaged
|
||||
return true
|
||||
timeSinceLastFetch = process.hrtime(@lastTargetStateFetch)
|
||||
timeSinceLastFetchMs = timeSinceLastFetch[0] * 1000 + timeSinceLastFetch[1] / 1e6
|
||||
@ -72,10 +72,10 @@ module.exports = class APIBinder
|
||||
release()
|
||||
|
||||
initClient: =>
|
||||
@config.getMany([ 'offlineMode', 'apiEndpoint', 'currentApiKey' ])
|
||||
.then ({ offlineMode, apiEndpoint, currentApiKey }) =>
|
||||
if offlineMode
|
||||
console.log('Offline Mode is set, skipping API client initialization')
|
||||
@config.getMany([ 'unmanaged', 'apiEndpoint', 'currentApiKey' ])
|
||||
.then ({ unmanaged, apiEndpoint, currentApiKey }) =>
|
||||
if unmanaged
|
||||
console.log('Unmanaged Mode is set, skipping API client initialization')
|
||||
return
|
||||
baseUrl = url.resolve(apiEndpoint, '/v5/')
|
||||
passthrough = _.cloneDeep(requestOpts)
|
||||
@ -102,10 +102,10 @@ module.exports = class APIBinder
|
||||
@loadBackupFromMigration(retryDelay)
|
||||
|
||||
start: =>
|
||||
@config.getMany([ 'apiEndpoint', 'offlineMode', 'bootstrapRetryDelay' ])
|
||||
.then ({ apiEndpoint, offlineMode, bootstrapRetryDelay }) =>
|
||||
if offlineMode
|
||||
console.log('Offline Mode is set, skipping API binder initialization')
|
||||
@config.getMany([ 'apiEndpoint', 'unmanaged', 'bootstrapRetryDelay' ])
|
||||
.then ({ apiEndpoint, unmanaged, bootstrapRetryDelay }) =>
|
||||
if unmanaged
|
||||
console.log('Unmanaged Mode is set, skipping API binder initialization')
|
||||
# If we are offline because there is no apiEndpoint, there's a chance
|
||||
# we've went through a deprovision. We need to set the initialConfigReported
|
||||
# value to '', to ensure that when we do re-provision, we'll report
|
||||
@ -258,15 +258,15 @@ module.exports = class APIBinder
|
||||
|
||||
provisionDependentDevice: (device) =>
|
||||
@config.getMany([
|
||||
'offlineMode'
|
||||
'unmanaged'
|
||||
'provisioned'
|
||||
'apiTimeout'
|
||||
'userId'
|
||||
'deviceId'
|
||||
])
|
||||
.then (conf) =>
|
||||
if conf.offlineMode
|
||||
throw new Error('Cannot provision dependent device in offline mode')
|
||||
if conf.unmanaged
|
||||
throw new Error('Cannot provision dependent device in unmanaged mode')
|
||||
if !conf.provisioned
|
||||
throw new Error('Device must be provisioned to provision a dependent device')
|
||||
# TODO: when API supports it as per https://github.com/resin-io/hq/pull/949 remove userId
|
||||
@ -283,13 +283,13 @@ module.exports = class APIBinder
|
||||
|
||||
patchDevice: (id, updatedFields) =>
|
||||
@config.getMany([
|
||||
'offlineMode'
|
||||
'unmanaged'
|
||||
'provisioned'
|
||||
'apiTimeout'
|
||||
])
|
||||
.then (conf) =>
|
||||
if conf.offlineMode
|
||||
throw new Error('Cannot update dependent device in offline mode')
|
||||
if conf.unmanaged
|
||||
throw new Error('Cannot update dependent device in unmanaged mode')
|
||||
if !conf.provisioned
|
||||
throw new Error('Device must be provisioned to update a dependent device')
|
||||
@balenaApi.patch
|
||||
@ -338,6 +338,9 @@ module.exports = class APIBinder
|
||||
(currentState, targetConfig, defaultConfig, deviceId) =>
|
||||
currentConfig = currentState.local.config
|
||||
Promise.mapSeries _.toPairs(currentConfig), ([ key, value ]) =>
|
||||
# We want to disable local mode when joining a cloud
|
||||
if key == 'SUPERVISOR_LOCAL_MODE'
|
||||
value = 'false'
|
||||
# We never want to disable VPN if, for instance, it failed to start so far
|
||||
if key == 'SUPERVISOR_VPN_CONTROL'
|
||||
value = 'true'
|
||||
|
@ -9,7 +9,6 @@ import supervisorVersion = require('../lib/supervisor-version');
|
||||
import * as constants from '../lib/constants';
|
||||
import * as osRelease from '../lib/os-release';
|
||||
import { ConfigValue } from '../lib/types';
|
||||
import { checkTruthy } from '../lib/validation';
|
||||
|
||||
// A provider for schema entries with source 'func'
|
||||
type ConfigProviderFunctionGetter = () => Bluebird<any>;
|
||||
@ -47,17 +46,6 @@ export function createProviderFunctions(
|
||||
});
|
||||
},
|
||||
},
|
||||
offlineMode: {
|
||||
get: () => {
|
||||
return config
|
||||
.getMany(['apiEndpoint', 'supervisorOfflineMode'])
|
||||
.then(({ apiEndpoint, supervisorOfflineMode }) => {
|
||||
return (
|
||||
checkTruthy(supervisorOfflineMode as boolean) || !apiEndpoint
|
||||
);
|
||||
});
|
||||
},
|
||||
},
|
||||
provisioned: {
|
||||
get: () => {
|
||||
return config
|
||||
@ -149,5 +137,12 @@ export function createProviderFunctions(
|
||||
]);
|
||||
},
|
||||
},
|
||||
unmanaged: {
|
||||
get: () => {
|
||||
return config.get('apiEndpoint').then(apiEndpoint => {
|
||||
return !apiEndpoint;
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -46,14 +46,11 @@ class Config extends EventEmitter {
|
||||
default: constants.defaultMixpanelToken,
|
||||
},
|
||||
bootstrapRetryDelay: { source: 'config.json', default: 30000 },
|
||||
supervisorOfflineMode: { source: 'config.json', default: false },
|
||||
hostname: { source: 'config.json', mutable: true },
|
||||
persistentLogging: { source: 'config.json', default: false, mutable: true },
|
||||
localMode: { source: 'config.json', mutable: true, default: 'false' },
|
||||
|
||||
version: { source: 'func' },
|
||||
currentApiKey: { source: 'func' },
|
||||
offlineMode: { source: 'func' },
|
||||
provisioned: { source: 'func' },
|
||||
osVersion: { source: 'func' },
|
||||
osVariant: { source: 'func' },
|
||||
@ -61,6 +58,7 @@ class Config extends EventEmitter {
|
||||
mixpanelHost: { source: 'func' },
|
||||
extendedEnvOptions: { source: 'func' },
|
||||
fetchOptions: { source: 'func' },
|
||||
unmanaged: { source: 'func' },
|
||||
|
||||
// NOTE: all 'db' values are stored and loaded as *strings*,
|
||||
apiSecret: { source: 'db', mutable: true },
|
||||
@ -82,6 +80,7 @@ class Config extends EventEmitter {
|
||||
pinDevice: { source: 'db', mutable: true, default: 'null' },
|
||||
currentCommit: { source: 'db', mutable: true },
|
||||
targetStateSet: { source: 'db', mutable: true, default: 'false' },
|
||||
localMode: { source: 'db', mutable: true, default: 'false' },
|
||||
};
|
||||
|
||||
public constructor({ db, configPath }: ConfigOpts) {
|
||||
@ -187,7 +186,7 @@ class Config extends EventEmitter {
|
||||
if (oldValues[key] !== value) {
|
||||
return this.db.upsertModel(
|
||||
'config',
|
||||
{ key, value },
|
||||
{ key, value: (value || '').toString() },
|
||||
{ key },
|
||||
tx,
|
||||
);
|
||||
@ -281,15 +280,15 @@ class Config extends EventEmitter {
|
||||
'uuid',
|
||||
'deviceApiKey',
|
||||
'apiSecret',
|
||||
'offlineMode',
|
||||
]).then(({ uuid, deviceApiKey, apiSecret, offlineMode }) => {
|
||||
'unmanaged',
|
||||
]).then(({ uuid, deviceApiKey, apiSecret, unmanaged }) => {
|
||||
// These fields need to be set regardless
|
||||
if (uuid == null || apiSecret == null) {
|
||||
uuid = uuid || this.newUniqueKey();
|
||||
apiSecret = apiSecret || this.newUniqueKey();
|
||||
}
|
||||
return this.set({ uuid, apiSecret }).then(() => {
|
||||
if (offlineMode) {
|
||||
if (unmanaged) {
|
||||
return;
|
||||
}
|
||||
if (!deviceApiKey) {
|
||||
|
@ -13,6 +13,7 @@ module.exports = class DeviceConfig
|
||||
@rebootRequired = false
|
||||
@configKeys = {
|
||||
appUpdatePollInterval: { envVarName: 'SUPERVISOR_POLL_INTERVAL', varType: 'int', defaultValue: '60000' }
|
||||
localMode: { envVarName: 'SUPERVISOR_LOCAL_MODE', varType: 'bool', defaultValue: 'false' }
|
||||
connectivityCheckEnabled: { envVarName: 'SUPERVISOR_CONNECTIVITY_CHECK', varType: 'bool', defaultValue: 'true' }
|
||||
loggingEnabled: { envVarName: 'SUPERVISOR_LOG_CONTROL', varType: 'bool', defaultValue: 'true' }
|
||||
delta: { envVarName: 'SUPERVISOR_DELTA', varType: 'bool', defaultValue: 'false' }
|
||||
@ -74,11 +75,16 @@ module.exports = class DeviceConfig
|
||||
db('deviceConfig').update(confToUpdate)
|
||||
|
||||
getTarget: ({ initial = false } = {}) =>
|
||||
@db.models('deviceConfig').select('targetValues')
|
||||
.then ([ devConfig ]) =>
|
||||
Promise.all([
|
||||
@config.get('unmanaged')
|
||||
@db.models('deviceConfig').select('targetValues')
|
||||
])
|
||||
.then ([unmanaged, [ devConfig ]]) =>
|
||||
conf = JSON.parse(devConfig.targetValues)
|
||||
if initial or !conf.SUPERVISOR_VPN_CONTROL?
|
||||
conf.SUPERVISOR_VPN_CONTROL = 'true'
|
||||
if unmanaged and !conf.SUPERVISOR_LOCAL_MODE?
|
||||
conf.SUPERVISOR_LOCAL_MODE = 'true'
|
||||
for own k, { envVarName, defaultValue } of @configKeys
|
||||
conf[envVarName] ?= defaultValue
|
||||
return conf
|
||||
@ -131,10 +137,10 @@ module.exports = class DeviceConfig
|
||||
target = _.clone(targetState.local?.config ? {})
|
||||
steps = []
|
||||
Promise.all [
|
||||
@config.getMany([ 'deviceType', 'offlineMode' ])
|
||||
@config.getMany([ 'deviceType', 'unmanaged' ])
|
||||
@getConfigBackend()
|
||||
]
|
||||
.then ([{ deviceType, offlineMode }, configBackend ]) =>
|
||||
.then ([{ deviceType, unmanaged }, configBackend ]) =>
|
||||
configChanges = {}
|
||||
humanReadableConfigChanges = {}
|
||||
match = {
|
||||
@ -162,7 +168,7 @@ module.exports = class DeviceConfig
|
||||
return
|
||||
|
||||
# Check if we need to perform special case actions for the VPN
|
||||
if !checkTruthy(offlineMode) &&
|
||||
if !checkTruthy(unmanaged) &&
|
||||
!_.isEmpty(target['SUPERVISOR_VPN_CONTROL']) &&
|
||||
@checkBoolChanged(current, target, 'SUPERVISOR_VPN_CONTROL')
|
||||
steps.push({
|
||||
|
@ -140,12 +140,12 @@ module.exports = class DeviceState extends EventEmitter
|
||||
@applications.on('change', @reportCurrentState)
|
||||
|
||||
healthcheck: =>
|
||||
@config.getMany([ 'appUpdatePollInterval', 'offlineMode' ])
|
||||
@config.getMany([ 'appUpdatePollInterval', 'unmanaged' ])
|
||||
.then (conf) =>
|
||||
cycleTime = process.hrtime(@lastApplyStart)
|
||||
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
|
||||
applyTargetHealthy = conf.unmanaged or !@applyInProgress or @applications.fetchesInProgress > 0 or cycleTimeWithinInterval
|
||||
return applyTargetHealthy
|
||||
|
||||
migrateLegacyApps: (balenaApi) =>
|
||||
@ -255,7 +255,7 @@ module.exports = class DeviceState extends EventEmitter
|
||||
@config.getMany([
|
||||
'initialConfigSaved', 'listenPort', 'apiSecret', 'osVersion', 'osVariant',
|
||||
'version', 'provisioned', 'apiEndpoint', 'connectivityCheckEnabled', 'legacyAppsPresent',
|
||||
'targetStateSet', 'offlineMode'
|
||||
'targetStateSet', 'unmanaged'
|
||||
])
|
||||
.then (conf) =>
|
||||
@applications.init()
|
||||
@ -297,8 +297,8 @@ module.exports = class DeviceState extends EventEmitter
|
||||
.then =>
|
||||
@triggerApplyTarget({ initial: true })
|
||||
|
||||
initNetworkChecks: ({ apiEndpoint, connectivityCheckEnabled, offlineMode }) =>
|
||||
return if validation.checkTruthy(offlineMode)
|
||||
initNetworkChecks: ({ apiEndpoint, connectivityCheckEnabled, unmanaged }) =>
|
||||
return if validation.checkTruthy(unmanaged)
|
||||
network.startConnectivityCheck apiEndpoint, connectivityCheckEnabled, (connected) =>
|
||||
@connected = connected
|
||||
@config.on 'change', (changedConfig) ->
|
||||
@ -351,7 +351,7 @@ module.exports = class DeviceState extends EventEmitter
|
||||
.then =>
|
||||
@deviceConfig.setTarget(target.local.config, trx)
|
||||
.then =>
|
||||
if localSource
|
||||
if localSource or not apiEndpoint
|
||||
@applications.setTarget(target.local.apps, target.dependent, 'local', trx)
|
||||
else
|
||||
@applications.setTarget(target.local.apps, target.dependent, apiEndpoint, trx)
|
||||
|
@ -11,7 +11,7 @@ export type EventTrackProperties = Dictionary<any>;
|
||||
|
||||
interface InitArgs {
|
||||
uuid: string;
|
||||
offlineMode: boolean;
|
||||
unmanaged: boolean;
|
||||
mixpanelHost: { host: string; path: string } | null;
|
||||
mixpanelToken: string;
|
||||
}
|
||||
@ -41,7 +41,7 @@ export class EventTracker {
|
||||
}
|
||||
|
||||
public init({
|
||||
offlineMode,
|
||||
unmanaged,
|
||||
mixpanelHost,
|
||||
mixpanelToken,
|
||||
uuid,
|
||||
@ -52,7 +52,7 @@ export class EventTracker {
|
||||
uuid,
|
||||
supervisorVersion,
|
||||
};
|
||||
if (offlineMode || mixpanelHost == null) {
|
||||
if (unmanaged || mixpanelHost == null) {
|
||||
return;
|
||||
}
|
||||
this.client = Mixpanel.init(mixpanelToken, {
|
||||
|
@ -40,9 +40,20 @@ export class LocalModeManager {
|
||||
}
|
||||
});
|
||||
|
||||
const localMode = checkTruthy(
|
||||
(await this.config.get('localMode')) || false,
|
||||
);
|
||||
// On startup, check if we're in unmanaged mode,
|
||||
// as local mode needs to be set
|
||||
let unmanagedLocalMode = false;
|
||||
if (checkTruthy((await this.config.get('unmanaged')) || false)) {
|
||||
console.log('Starting up in unmanaged mode, activating local mode');
|
||||
await this.config.set({ localMode: true });
|
||||
unmanagedLocalMode = true;
|
||||
}
|
||||
|
||||
const localMode =
|
||||
// short circuit the next get if we know we're in local mode
|
||||
unmanagedLocalMode ||
|
||||
checkTruthy((await this.config.get('localMode')) || false);
|
||||
|
||||
if (!localMode) {
|
||||
// Remove any leftovers if necessary
|
||||
await this.removeLocalModeArtifacts();
|
||||
|
@ -17,7 +17,7 @@ interface LoggerSetupOptions {
|
||||
apiEndpoint: string;
|
||||
uuid: string;
|
||||
deviceApiKey: string;
|
||||
offlineMode: boolean;
|
||||
unmanaged: boolean;
|
||||
enableLogs: boolean;
|
||||
localMode: boolean;
|
||||
}
|
||||
@ -59,7 +59,7 @@ export class Logger {
|
||||
apiEndpoint,
|
||||
uuid,
|
||||
deviceApiKey,
|
||||
offlineMode,
|
||||
unmanaged,
|
||||
enableLogs,
|
||||
localMode,
|
||||
}: LoggerSetupOptions) {
|
||||
@ -68,7 +68,7 @@ export class Logger {
|
||||
|
||||
this.backend = localMode ? this.localBackend : this.balenaBackend;
|
||||
|
||||
this.backend.offlineMode = offlineMode;
|
||||
this.backend.unmanaged = unmanaged;
|
||||
this.backend.publishEnabled = enableLogs;
|
||||
}
|
||||
|
||||
|
@ -70,7 +70,7 @@ export class BalenaLogBackend extends LogBackend {
|
||||
}
|
||||
|
||||
public log(message: LogMessage) {
|
||||
if (this.offlineMode || !this.publishEnabled) {
|
||||
if (this.unmanaged || !this.publishEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
export type LogMessage = Dictionary<any>;
|
||||
|
||||
export abstract class LogBackend {
|
||||
public offlineMode: boolean;
|
||||
public unmanaged: boolean;
|
||||
public publishEnabled: boolean = true;
|
||||
|
||||
public abstract log(message: LogMessage): void;
|
||||
|
41
src/migrations/M00002.js
Normal file
41
src/migrations/M00002.js
Normal file
@ -0,0 +1,41 @@
|
||||
const fs = require('fs');
|
||||
const configJsonPath = process.env.CONFIG_MOUNT_POINT;
|
||||
|
||||
const { checkTruthy } = require('../lib/validation');
|
||||
|
||||
exports.up = function (knex, Promise) {
|
||||
return new Promise(resolve => {
|
||||
if (!configJsonPath) {
|
||||
console.log('Unable to locate config.json! Things may fail unexpectedly!');
|
||||
return resolve(false);
|
||||
}
|
||||
|
||||
fs.readFile(configJsonPath, (err, data) => {
|
||||
if (err) {
|
||||
console.log('Failed to read config.json! Things may fail unexpectedly!');
|
||||
return resolve();
|
||||
}
|
||||
try {
|
||||
const parsed = JSON.parse(data.toString());
|
||||
if (parsed.localMode != null) {
|
||||
return resolve(checkTruthy(parsed.localMode));
|
||||
}
|
||||
return resolve(false);
|
||||
} catch (e) {
|
||||
console.log('Failed to parse config.json! Things may fail unexpectedly!');
|
||||
return resolve(false);
|
||||
}
|
||||
});
|
||||
}).then(localMode => {
|
||||
// We can be sure that this does not already exist in the db because of the previous
|
||||
// migration
|
||||
return knex('config').insert({
|
||||
key: 'localMode',
|
||||
value: localMode.toString(),
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
exports.down = function (knex, Promise) {
|
||||
return Promise.reject(new Error('Not Implemented'));
|
||||
};
|
@ -11,19 +11,23 @@ authenticate = (config) ->
|
||||
header = req.get('Authorization') ? ''
|
||||
match = header.match(/^ApiKey (\w+)$/)
|
||||
headerKey = match?[1]
|
||||
config.getMany([ 'apiSecret', 'localMode' ])
|
||||
config.getMany([ 'apiSecret', 'localMode', 'unmanaged', 'osVariant' ])
|
||||
.then (conf) ->
|
||||
if queryKey? && bufferEq(new Buffer(queryKey), new Buffer(conf.apiSecret))
|
||||
next()
|
||||
else if headerKey? && bufferEq(new Buffer(headerKey), new Buffer(conf.apiSecret))
|
||||
next()
|
||||
else if checkTruthy(conf.localMode)
|
||||
next()
|
||||
needsAuth = if conf.unmanaged
|
||||
conf.osVariant is 'prod'
|
||||
else
|
||||
res.sendStatus(401)
|
||||
not conf.localMode
|
||||
|
||||
if needsAuth
|
||||
key = queryKey ? headerKey
|
||||
if bufferEq(Buffer.from(key), Buffer.from(conf.apiSecret))
|
||||
next()
|
||||
else
|
||||
res.sendStatus(401)
|
||||
else
|
||||
next()
|
||||
.catch (err) ->
|
||||
# This should never happen...
|
||||
res.status(503).send('Invalid API key in supervisor')
|
||||
res.status(503).send("Unexpected error: #{err}")
|
||||
|
||||
module.exports = class SupervisorAPI
|
||||
constructor: ({ @config, @eventTracker, @routers, @healthchecks }) ->
|
||||
|
@ -17,7 +17,7 @@ startupConfigFields = [
|
||||
'apiEndpoint'
|
||||
'apiSecret'
|
||||
'apiTimeout'
|
||||
'offlineMode'
|
||||
'unmanaged'
|
||||
'deviceApiKey'
|
||||
'mixpanelToken'
|
||||
'mixpanelHost'
|
||||
@ -57,7 +57,7 @@ module.exports = class Supervisor extends EventEmitter
|
||||
apiEndpoint: conf.apiEndpoint,
|
||||
uuid: conf.uuid,
|
||||
deviceApiKey: conf.deviceApiKey,
|
||||
offlineMode: checkTruthy(conf.offlineMode),
|
||||
unmanaged: checkTruthy(conf.unmanaged),
|
||||
enableLogs: checkTruthy(conf.loggingEnabled),
|
||||
localMode: checkTruthy(conf.localMode)
|
||||
})
|
||||
|
@ -21,6 +21,7 @@ mockedInitialConfig = {
|
||||
'RESIN_SUPERVISOR_DELTA_RETRY_COUNT': '30'
|
||||
'RESIN_SUPERVISOR_DELTA_RETRY_INTERVAL': '10000'
|
||||
'RESIN_SUPERVISOR_DELTA_VERSION': '2'
|
||||
'RESIN_SUPERVISOR_LOCAL_MODE': 'false'
|
||||
'RESIN_SUPERVISOR_LOG_CONTROL': 'true'
|
||||
'RESIN_SUPERVISOR_OVERRIDE_LOCK': 'false'
|
||||
'RESIN_SUPERVISOR_POLL_INTERVAL': '60000'
|
||||
@ -39,6 +40,7 @@ testTarget1 = {
|
||||
'SUPERVISOR_DELTA_RETRY_COUNT': '30'
|
||||
'SUPERVISOR_DELTA_RETRY_INTERVAL': '10000'
|
||||
'SUPERVISOR_DELTA_VERSION': '2'
|
||||
'SUPERVISOR_LOCAL_MODE': 'false'
|
||||
'SUPERVISOR_LOG_CONTROL': 'true'
|
||||
'SUPERVISOR_OVERRIDE_LOCK': 'false'
|
||||
'SUPERVISOR_POLL_INTERVAL': '60000'
|
||||
@ -120,6 +122,7 @@ testTargetWithDefaults2 = {
|
||||
'SUPERVISOR_DELTA_RETRY_COUNT': '30'
|
||||
'SUPERVISOR_DELTA_RETRY_INTERVAL': '10000'
|
||||
'SUPERVISOR_DELTA_VERSION': '2'
|
||||
'SUPERVISOR_LOCAL_MODE': 'false'
|
||||
'SUPERVISOR_LOG_CONTROL': 'true'
|
||||
'SUPERVISOR_OVERRIDE_LOCK': 'false'
|
||||
'SUPERVISOR_POLL_INTERVAL': '60000'
|
||||
|
@ -23,9 +23,9 @@ describe 'EventTracker', ->
|
||||
EventTracker.prototype.logEvent.restore()
|
||||
mixpanel.init.restore()
|
||||
|
||||
it 'initializes in offline mode', ->
|
||||
it 'initializes in unmanaged mode', ->
|
||||
promise = @eventTrackerOffline.init({
|
||||
offlineMode: true
|
||||
unmanaged: true
|
||||
uuid: 'foobar'
|
||||
mixpanelHost: { host: '', path: '' }
|
||||
})
|
||||
@ -33,11 +33,11 @@ describe 'EventTracker', ->
|
||||
.then =>
|
||||
expect(@eventTrackerOffline.client).to.be.null
|
||||
|
||||
it 'logs events in offline mode, with the correct properties', ->
|
||||
it 'logs events in unmanaged mode, with the correct properties', ->
|
||||
@eventTrackerOffline.track('Test event', { appId: 'someValue' })
|
||||
expect(@eventTrackerOffline.logEvent).to.be.calledWith('Event:', 'Test event', JSON.stringify({ appId: 'someValue' }))
|
||||
|
||||
it 'initializes a mixpanel client when not in offline mode', ->
|
||||
it 'initializes a mixpanel client when not in unmanaged mode', ->
|
||||
promise = @eventTracker.init({
|
||||
mixpanelToken: 'someToken'
|
||||
uuid: 'barbaz'
|
||||
|
@ -135,12 +135,12 @@ describe 'APIBinder', ->
|
||||
@apiBinder.fetchDevice.restore()
|
||||
balenaAPI.balenaBackend.deviceKeyHandler.restore()
|
||||
|
||||
describe 'offline mode', ->
|
||||
describe 'unmanaged mode', ->
|
||||
before ->
|
||||
initModels.call(this, '/config-apibinder-offline.json')
|
||||
|
||||
it 'does not generate a key if the device is in offline mode', ->
|
||||
@config.get('offlineMode').then (mode) =>
|
||||
it 'does not generate a key if the device is in unmanaged mode', ->
|
||||
@config.get('unmanaged').then (mode) =>
|
||||
# Ensure offline mode is set
|
||||
expect(mode).to.equal(true)
|
||||
# Check that there is no deviceApiKey
|
||||
@ -148,12 +148,12 @@ describe 'APIBinder', ->
|
||||
expect(conf['deviceApiKey']).to.be.empty
|
||||
expect(conf['uuid']).to.not.be.undefined
|
||||
|
||||
describe 'Minimal config offline mode', ->
|
||||
describe 'Minimal config unmanaged mode', ->
|
||||
before ->
|
||||
initModels.call(this, '/config-apibinder-offline2.json')
|
||||
|
||||
it 'does not generate a key with the minimal config', ->
|
||||
@config.get('offlineMode').then (mode) =>
|
||||
@config.get('unmanaged').then (mode) =>
|
||||
expect(mode).to.equal(true)
|
||||
@config.getMany([ 'deviceApiKey', 'uuid' ]).then (conf) ->
|
||||
expect(conf['deviceApiKey']).to.be.empty
|
||||
|
@ -31,7 +31,7 @@ describe 'Logger', ->
|
||||
apiEndpoint: 'https://example.com'
|
||||
uuid: 'deadbeef'
|
||||
deviceApiKey: 'secretkey'
|
||||
offlineMode: false
|
||||
unmanaged: false
|
||||
enableLogs: true
|
||||
localMode: false
|
||||
})
|
||||
|
@ -1 +1,16 @@
|
||||
{"applicationName":"supertestrpi3","applicationId":78373,"deviceType":"raspberrypi3","userId":1001,"username":"someone","appUpdatePollInterval":3000,"listenPort":2345,"vpnPort":443,"apiEndpoint":"http://0.0.0.0:3000","vpnEndpoint":"vpn.resin.io","registryEndpoint":"registry2.resin.io","deltaEndpoint":"https://delta.resin.io","mixpanelToken":"baz","apiKey":"boo","version":"2.0.6+rev3.prod","supervisorOfflineMode":true}
|
||||
{
|
||||
"applicationName": "supertestrpi3",
|
||||
"applicationId": 78373,
|
||||
"deviceType": "raspberrypi3",
|
||||
"userId": 1001,
|
||||
"username": "someone",
|
||||
"appUpdatePollInterval": 3000,
|
||||
"listenPort": 2345,
|
||||
"vpnPort": 443,
|
||||
"vpnEndpoint": "vpn.resin.io",
|
||||
"registryEndpoint": "registry2.resin.io",
|
||||
"deltaEndpoint": "https://delta.resin.io",
|
||||
"mixpanelToken": "baz",
|
||||
"apiKey": "boo",
|
||||
"version": "2.0.6+rev3.prod"
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user