Update to balena-lint and enable javascript linting

Change-type: patch
This commit is contained in:
Pagan Gazzard 2020-03-23 18:42:27 +00:00
parent 34e28173a0
commit 81966446d9
15 changed files with 531 additions and 446 deletions

View File

@ -2,7 +2,7 @@
"*.coffee": [ "*.coffee": [
"resin-lint" "resin-lint"
], ],
"*.ts": [ "*.ts$|!(*webpack.config).js$": [
"resin-lint --typescript --fix", "resin-lint --typescript --fix",
], ],
"test/**/*.coffee": [ "test/**/*.coffee": [

129
package-lock.json generated
View File

@ -82,6 +82,71 @@
} }
} }
}, },
"@balena/lint": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/@balena/lint/-/lint-4.1.0.tgz",
"integrity": "sha512-5db6EhVYblBh70J8k9LZYww1ntd3xwL/4hkysyB70itS/wBQLIMqGIVaiqfpayN61mYdbs24Fm5ijgDkhT4OLQ==",
"dev": true,
"requires": {
"@types/depcheck": "^0.6.0",
"@types/glob": "^7.1.1",
"@types/lodash": "^4.14.149",
"@types/node": "^8.10.59",
"@types/optimist": "0.0.29",
"@types/prettier": "^1.18.3",
"coffee-script": "^1.10.0",
"coffeelint": "^1.15.0",
"coffeescope2": "^0.4.5",
"depcheck": "^0.6.7",
"glob": "^7.1.6",
"lodash": "^4.17.15",
"optimist": "^0.6.1",
"prettier": "^1.19.1",
"tslint": "^5.20.1",
"tslint-config-prettier": "^1.18.0",
"tslint-no-unused-expression-chai": "^0.1.4",
"typescript": "^3.7.5"
},
"dependencies": {
"@types/glob": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz",
"integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==",
"dev": true,
"requires": {
"@types/events": "*",
"@types/minimatch": "*",
"@types/node": "*"
}
},
"@types/node": {
"version": "8.10.59",
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.59.tgz",
"integrity": "sha512-8RkBivJrDCyPpBXhVZcjh7cQxVBSmRk9QM7hOketZzp6Tg79c0N8kkpAIito9bnJ3HCVCHVYz+KHTEbfQNfeVQ==",
"dev": true
},
"coffee-script": {
"version": "1.12.7",
"resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.12.7.tgz",
"integrity": "sha512-fLeEhqwymYat/MpTPUjSKHVYYl0ec2mOyALEMLmzr5i1isuG+6jfI2j2d5oBO3VIzgUXgBVIcOT9uH1TFxBckw==",
"dev": true
},
"glob": {
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"dev": true,
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
}
}
},
"@resin.io/types-hidepath": { "@resin.io/types-hidepath": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@resin.io/types-hidepath/-/types-hidepath-1.0.1.tgz", "resolved": "https://registry.npmjs.org/@resin.io/types-hidepath/-/types-hidepath-1.0.1.tgz",
@ -398,9 +463,9 @@
"dev": true "dev": true
}, },
"@types/prettier": { "@types/prettier": {
"version": "1.19.0", "version": "1.19.1",
"resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-1.19.0.tgz", "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-1.19.1.tgz",
"integrity": "sha512-gDE8JJEygpay7IjA/u3JiIURvwZW08f0cZSZLAzFoX/ZmeqvS0Sqv+97aKuHpNsalAMMhwPe+iAS6fQbfmbt7A==", "integrity": "sha512-5qOlnZscTn4xxM5MeGXAMOsIOIKIbh9e85zJWfBRVPlRMEVawzoPhINYbRGkBZCI8LxvBe7tJCdWiarA99OZfQ==",
"dev": true "dev": true
}, },
"@types/range-parser": { "@types/range-parser": {
@ -6363,7 +6428,7 @@
"dependencies": { "dependencies": {
"ansi-escapes": { "ansi-escapes": {
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", "resolved": "http://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz",
"integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=",
"dev": true "dev": true
}, },
@ -7059,7 +7124,7 @@
}, },
"chalk": { "chalk": {
"version": "2.3.2", "version": "2.3.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", "resolved": "http://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz",
"integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==",
"dev": true, "dev": true,
"requires": { "requires": {
@ -9673,60 +9738,6 @@
"lodash": "^4.0.0" "lodash": "^4.0.0"
} }
}, },
"resin-lint": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/resin-lint/-/resin-lint-3.2.4.tgz",
"integrity": "sha512-VtsEAG8fgSkZMnZ2CPLtukEqJMjFBSya8T//AjUHGEqFr/M8aUfdSZvIXq8vVFholaCMW84XBmVu9zWK8H0arg==",
"dev": true,
"requires": {
"@types/depcheck": "^0.6.0",
"@types/glob": "^5.0.35",
"@types/lodash": "^4.14.149",
"@types/node": "^8.10.59",
"@types/optimist": "0.0.29",
"@types/prettier": "^1.18.3",
"coffee-script": "^1.10.0",
"coffeelint": "^1.15.0",
"coffeescope2": "^0.4.5",
"depcheck": "^0.6.7",
"glob": "^7.1.6",
"lodash": "^4.17.15",
"optimist": "^0.6.1",
"prettier": "^1.19.1",
"tslint": "^5.20.1",
"tslint-config-prettier": "^1.18.0",
"tslint-no-unused-expression-chai": "^0.1.4",
"typescript": "^3.7.5"
},
"dependencies": {
"@types/node": {
"version": "8.10.59",
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.59.tgz",
"integrity": "sha512-8RkBivJrDCyPpBXhVZcjh7cQxVBSmRk9QM7hOketZzp6Tg79c0N8kkpAIito9bnJ3HCVCHVYz+KHTEbfQNfeVQ==",
"dev": true
},
"coffee-script": {
"version": "1.12.7",
"resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.12.7.tgz",
"integrity": "sha512-fLeEhqwymYat/MpTPUjSKHVYYl0ec2mOyALEMLmzr5i1isuG+6jfI2j2d5oBO3VIzgUXgBVIcOT9uH1TFxBckw==",
"dev": true
},
"glob": {
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"dev": true,
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
}
}
},
"resin-register-device": { "resin-register-device": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "http://registry.npmjs.org/resin-register-device/-/resin-register-device-3.0.0.tgz", "resolved": "http://registry.npmjs.org/resin-register-device/-/resin-register-device-3.0.0.tgz",

View File

@ -17,7 +17,7 @@
"coverage": "istanbul report text && istanbul report html", "coverage": "istanbul report text && istanbul report html",
"test:fast": "TEST=1 mocha --opts test/fast-mocha.opts", "test:fast": "TEST=1 mocha --opts test/fast-mocha.opts",
"test:debug": "npm run test:build && TEST=1 mocha --inspect-brk", "test:debug": "npm run test:build && TEST=1 mocha --inspect-brk",
"prettify": "resin-lint --typescript --fix src/ test/ typings/", "prettify": "balena-lint -e ts -e js --typescript --fix src/ test/ typings/ webpack.config.js",
"typescript:test-build": "tsc --project tsconfig.json", "typescript:test-build": "tsc --project tsconfig.json",
"typescript:release": "tsc --project tsconfig.release.json && cp -r build/src/* build && rm -rf build/src", "typescript:release": "tsc --project tsconfig.release.json && cp -r build/src/* build && rm -rf build/src",
"coffeescript:test": "coffee -m -c -o build .", "coffeescript:test": "coffee -m -c -o build .",
@ -26,8 +26,8 @@
"migrations:copy-test": "cp -r src/migrations build/src", "migrations:copy-test": "cp -r src/migrations build/src",
"packagejson:copy": "cp package.json build/", "packagejson:copy": "cp package.json build/",
"testitems:copy": "cp -r test/data build/test/", "testitems:copy": "cp -r test/data build/test/",
"lint:coffee": "resin-lint src/ test/", "lint:coffee": "balena-lint src/ test/",
"lint:typescript": "resin-lint --typescript src/ test/ typings/ && tsc --noEmit" "lint:typescript": "balena-lint -e ts -e js --typescript src/ test/ typings/ && tsc --noEmit"
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
@ -38,6 +38,7 @@
}, },
"devDependencies": { "devDependencies": {
"@balena/contrato": "^0.2.1", "@balena/contrato": "^0.2.1",
"@balena/lint": "^4.1.0",
"@types/bluebird": "^3.5.30", "@types/bluebird": "^3.5.30",
"@types/chai": "^4.2.10", "@types/chai": "^4.2.10",
"@types/chai-as-promised": "^7.1.2", "@types/chai-as-promised": "^7.1.2",
@ -104,7 +105,6 @@
"pinejs-client-request": "^5.2.0", "pinejs-client-request": "^5.2.0",
"pretty-ms": "^5.1.0", "pretty-ms": "^5.1.0",
"request": "^2.88.2", "request": "^2.88.2",
"resin-lint": "^3.2.4",
"resin-register-device": "^3.0.0", "resin-register-device": "^3.0.0",
"resumable-request": "^2.0.0", "resumable-request": "^2.0.0",
"rimraf": "^2.6.2", "rimraf": "^2.6.2",

View File

@ -7,130 +7,150 @@
// a few dropColumn and dropTable calls to delete things that were removed throughout the supervisor's // a few dropColumn and dropTable calls to delete things that were removed throughout the supervisor's
// history without actually adding drop statements (mostly just becoming unused, but still there). // history without actually adding drop statements (mostly just becoming unused, but still there).
exports.up = function (knex, Promise) { exports.up = function(knex, Promise) {
const addColumn = function (table, column, type) { const addColumn = function(table, column, type) {
return knex.schema.hasColumn(table, column) return knex.schema.hasColumn(table, column).then(exists => {
.then((exists) => { if (!exists) {
if (!exists) { return knex.schema.table(table, t => {
return knex.schema.table(table, (t) => { return t[type](column) }) return t[type](column);
} });
}) }
} });
const dropColumn = function (table, column) { };
return knex.schema.hasColumn(table, column) const dropColumn = function(table, column) {
.then((exists) => { return knex.schema.hasColumn(table, column).then(exists => {
if (exists) { if (exists) {
return knex.schema.table(table, (t) => { return t.dropColumn(column) }) return knex.schema.table(table, t => {
} return t.dropColumn(column);
}) });
} }
const createTableOrRun = function (tableName, tableCreator, runIfTableExists) { });
return knex.schema.hasTable(tableName) };
.then((exists) => { const createTableOrRun = function(tableName, tableCreator, runIfTableExists) {
if (!exists) { return knex.schema.hasTable(tableName).then(exists => {
return knex.schema.createTable(tableName, tableCreator) if (!exists) {
} else if (runIfTableExists != null) { return knex.schema.createTable(tableName, tableCreator);
return runIfTableExists() } else if (runIfTableExists != null) {
} return runIfTableExists();
}) }
} });
const dropTable = function (tableName) { };
return knex.schema.hasTable(tableName) const dropTable = function(tableName) {
.then((exists) => { return knex.schema.hasTable(tableName).then(exists => {
if (exists) { if (exists) {
return knex.schema.dropTable(tableName) return knex.schema.dropTable(tableName);
} }
}) });
} };
return Promise.all([ return Promise.all([
createTableOrRun('config', (t) => { createTableOrRun('config', t => {
t.string('key').primary() t.string('key').primary();
t.string('value') t.string('value');
}), }),
createTableOrRun('deviceConfig', (t) => { createTableOrRun('deviceConfig', t => {
t.json('values') t.json('values');
t.json('targetValues') t.json('targetValues');
}).then(() => { }).then(() => {
return knex('deviceConfig').select() return knex('deviceConfig')
.then((deviceConfigs) => { .select()
if (deviceConfigs.length == 0) { .then(deviceConfigs => {
return knex('deviceConfig').insert({ values: '{}', targetValues: '{}' }) if (deviceConfigs.length === 0) {
return knex('deviceConfig').insert({
values: '{}',
targetValues: '{}',
});
} }
}) });
}),
createTableOrRun('app', (t) => {
t.increments('id').primary()
t.string('name')
t.string('containerName')
t.string('commit')
t.string('imageId')
t.string('appId')
t.boolean('privileged')
t.json('env')
t.json('config')
t.boolean('markedForDeletion')
}, () => {
return Promise.all([
addColumn('app', 'commit', 'string'),
addColumn('app', 'appId', 'string'),
addColumn('app', 'containerName', 'string'),
addColumn('app', 'config', 'json'),
addColumn('app', 'markedForDeletion', 'boolean'),
dropColumn('app', 'containerId')
]).then(() => {
//When updating from older supervisors, config can be null
return knex('app').update({ config: '{}' }).whereNull('config')
.then(() => {
knex('app').update({ markedForDeletion: false }).whereNull('markedForDeletion')
})
})
}),
createTableOrRun('dependentApp', (t) => {
t.increments('id').primary()
t.string('appId')
t.string('parentAppId')
t.string('name')
t.string('commit')
t.string('imageId')
t.json('config')
t.json('environment')
}, () => {
return addColumn('dependentApp', 'environment', 'json')
}),
createTableOrRun('dependentDevice', (t) => {
t.increments('id').primary()
t.string('uuid')
t.string('appId')
t.string('localId')
t.string('device_type')
t.string('logs_channel')
t.string('deviceId')
t.boolean('is_online')
t.string('name')
t.string('status')
t.string('download_progress')
t.string('is_managed_by')
t.dateTime('lock_expiry_date')
t.string('commit')
t.string('targetCommit')
t.json('environment')
t.json('targetEnvironment')
t.json('config')
t.json('targetConfig')
t.boolean('markedForDeletion')
}, () => {
return Promise.all([
addColumn('dependentDevice', 'markedForDeletion', 'boolean'),
addColumn('dependentDevice', 'localId', 'string'),
addColumn('dependentDevice', 'is_managed_by', 'string'),
addColumn('dependentDevice', 'lock_expiry_date', 'dateTime')
])
}), }),
createTableOrRun(
'app',
t => {
t.increments('id').primary();
t.string('name');
t.string('containerName');
t.string('commit');
t.string('imageId');
t.string('appId');
t.boolean('privileged');
t.json('env');
t.json('config');
t.boolean('markedForDeletion');
},
() => {
return Promise.all([
addColumn('app', 'commit', 'string'),
addColumn('app', 'appId', 'string'),
addColumn('app', 'containerName', 'string'),
addColumn('app', 'config', 'json'),
addColumn('app', 'markedForDeletion', 'boolean'),
dropColumn('app', 'containerId'),
]).then(() => {
//When updating from older supervisors, config can be null
return knex('app')
.update({ config: '{}' })
.whereNull('config')
.then(() => {
knex('app')
.update({ markedForDeletion: false })
.whereNull('markedForDeletion');
});
});
},
),
createTableOrRun(
'dependentApp',
t => {
t.increments('id').primary();
t.string('appId');
t.string('parentAppId');
t.string('name');
t.string('commit');
t.string('imageId');
t.json('config');
t.json('environment');
},
() => {
return addColumn('dependentApp', 'environment', 'json');
},
),
createTableOrRun(
'dependentDevice',
t => {
t.increments('id').primary();
t.string('uuid');
t.string('appId');
t.string('localId');
t.string('device_type');
t.string('logs_channel');
t.string('deviceId');
t.boolean('is_online');
t.string('name');
t.string('status');
t.string('download_progress');
t.string('is_managed_by');
t.dateTime('lock_expiry_date');
t.string('commit');
t.string('targetCommit');
t.json('environment');
t.json('targetEnvironment');
t.json('config');
t.json('targetConfig');
t.boolean('markedForDeletion');
},
() => {
return Promise.all([
addColumn('dependentDevice', 'markedForDeletion', 'boolean'),
addColumn('dependentDevice', 'localId', 'string'),
addColumn('dependentDevice', 'is_managed_by', 'string'),
addColumn('dependentDevice', 'lock_expiry_date', 'dateTime'),
]);
},
),
dropTable('image'), dropTable('image'),
dropTable('container') dropTable('container'),
]) ]);
} };
exports.down = function(knex, Promise) { exports.down = function(knex, Promise) {
return Promise.reject(new Error('Not implemented')) return Promise.reject(new Error('Not implemented'));
} };

View File

@ -1,24 +1,23 @@
const _ = require('lodash') const _ = require('lodash');
var tryParse = function (obj) { var tryParse = function(obj) {
try { try {
return JSON.parse(obj) return JSON.parse(obj);
} catch (e) {
return {};
} }
catch(e) { };
return {}
}
}
var singleToMulticontainerApp = function (app) { var singleToMulticontainerApp = function(app) {
// From *very* old supervisors, env or config may be null // From *very* old supervisors, env or config may be null
// so we ignore errors parsing them // so we ignore errors parsing them
const conf = tryParse(app.config) const conf = tryParse(app.config);
const env = tryParse(app.env) const env = tryParse(app.env);
const environment = {} const environment = {};
const appId = parseInt(app.appId) const appId = parseInt(app.appId, 10);
for (let key in env) { for (let key in env) {
if (!/^RESIN_/.test(key)) { if (!/^RESIN_/.test(key)) {
environment[key] = env[key] environment[key] = env[key];
} }
} }
const newApp = { const newApp = {
@ -27,13 +26,17 @@ var singleToMulticontainerApp = function (app) {
name: app.name, name: app.name,
releaseId: 1, releaseId: 1,
networks: {}, networks: {},
volumes: {} volumes: {},
} };
const defaultVolume = 'resin-data' const defaultVolume = 'resin-data';
newApp.volumes[defaultVolume] = {} newApp.volumes[defaultVolume] = {};
const updateStrategy = _.get(conf, 'RESIN_SUPERVISOR_UPDATE_STRATEGY', 'download-then-kill') const updateStrategy = _.get(
const handoverTimeout = _.get(conf, 'RESIN_SUPERVISOR_HANDOVER_TIMEOUT', '') conf,
const restartPolicy = _.get(conf, 'RESIN_APP_RESTART_POLICY', 'always') 'RESIN_SUPERVISOR_UPDATE_STRATEGY',
'download-then-kill',
);
const handoverTimeout = _.get(conf, 'RESIN_SUPERVISOR_HANDOVER_TIMEOUT', '');
const restartPolicy = _.get(conf, 'RESIN_APP_RESTART_POLICY', 'always');
newApp.services = [ newApp.services = [
{ {
serviceId: 1, serviceId: 1,
@ -45,9 +48,7 @@ var singleToMulticontainerApp = function (app) {
image: app.imageId, image: app.imageId,
privileged: true, privileged: true,
networkMode: 'host', networkMode: 'host',
volumes: [ volumes: [`${defaultVolume}:/data`],
`${defaultVolume}:/data`
],
labels: { labels: {
'io.resin.features.kernel-modules': '1', 'io.resin.features.kernel-modules': '1',
'io.resin.features.firmware': '1', 'io.resin.features.firmware': '1',
@ -56,26 +57,26 @@ var singleToMulticontainerApp = function (app) {
'io.resin.features.resin-api': '1', 'io.resin.features.resin-api': '1',
'io.resin.update.strategy': updateStrategy, 'io.resin.update.strategy': updateStrategy,
'io.resin.update.handover-timeout': handoverTimeout, 'io.resin.update.handover-timeout': handoverTimeout,
'io.resin.legacy-container': '1' 'io.resin.legacy-container': '1',
}, },
environment: environment, environment: environment,
restart: restartPolicy, restart: restartPolicy,
running: true running: true,
} },
] ];
return newApp return newApp;
} };
var jsonifyAppFields = function (app) { var jsonifyAppFields = function(app) {
const newApp = _.clone(app) const newApp = _.clone(app);
newApp.services = JSON.stringify(app.services) newApp.services = JSON.stringify(app.services);
newApp.networks = JSON.stringify(app.networks) newApp.networks = JSON.stringify(app.networks);
newApp.volumes = JSON.stringify(app.volumes) newApp.volumes = JSON.stringify(app.volumes);
return newApp return newApp;
} };
var imageForApp = function (app) { var imageForApp = function(app) {
const service = app.services[0] const service = app.services[0];
return { return {
name: service.image, name: service.image,
appId: service.appId, appId: service.appId,
@ -83,11 +84,11 @@ var imageForApp = function (app) {
serviceName: service.serviceName, serviceName: service.serviceName,
imageId: service.imageId, imageId: service.imageId,
releaseId: service.releaseId, releaseId: service.releaseId,
dependent: 0 dependent: 0,
} };
} };
var imageForDependentApp = function (app) { var imageForDependentApp = function(app) {
return { return {
name: app.image, name: app.image,
appId: app.appId, appId: app.appId,
@ -95,203 +96,225 @@ var imageForDependentApp = function (app) {
serviceName: null, serviceName: null,
imageId: app.imageId, imageId: app.imageId,
releaseId: null, releaseId: null,
dependent: 1 dependent: 1,
} };
} };
// TODO: this whole thing is WIP // TODO: this whole thing is WIP
exports.up = function (knex, Promise) { exports.up = function(knex, Promise) {
return knex.schema.createTable('image', (t) => { return knex.schema
t.increments('id').primary() .createTable('image', t => {
t.string('name') t.increments('id').primary();
t.integer('appId') t.string('name');
t.integer('serviceId') t.integer('appId');
t.string('serviceName') t.integer('serviceId');
t.integer('imageId') t.string('serviceName');
t.integer('releaseId') t.integer('imageId');
t.boolean('dependent') t.integer('releaseId');
t.boolean('dependent');
}) })
.then(() => knex('app').select().whereNot({ markedForDeletion: true }).orWhereNull('markedForDeletion')) .then(() =>
.tap((apps) => { knex('app')
.select()
.whereNot({ markedForDeletion: true })
.orWhereNull('markedForDeletion'),
)
.tap(apps => {
if (apps.length > 0) { if (apps.length > 0) {
return knex('config').insert({ key: 'legacyAppsPresent', value: 'true' }) return knex('config').insert({
key: 'legacyAppsPresent',
value: 'true',
});
} }
}) })
.tap(() => { .tap(() => {
// We're in a transaction, and it's easier to drop and recreate // We're in a transaction, and it's easier to drop and recreate
// than to migrate each field... // than to migrate each field...
return knex.schema.dropTable('app') return knex.schema.dropTable('app').then(() => {
.then(() => { return knex.schema.createTable('app', t => {
return knex.schema.createTable('app', (t) => { t.increments('id').primary();
t.increments('id').primary() t.string('name');
t.string('name') t.integer('releaseId');
t.integer('releaseId') t.string('commit');
t.string('commit') t.integer('appId');
t.integer('appId') t.json('services');
t.json('services') t.json('networks');
t.json('networks') t.json('volumes');
t.json('volumes') });
}) });
})
}) })
.map((app) => { .map(app => {
const migratedApp = singleToMulticontainerApp(app) const migratedApp = singleToMulticontainerApp(app);
return knex('app').insert(jsonifyAppFields(migratedApp)) return knex('app')
.then(() => knex('image').insert(imageForApp(migratedApp))) .insert(jsonifyAppFields(migratedApp))
.then(() => knex('image').insert(imageForApp(migratedApp)));
}) })
.then(() => { .then(() => {
// For some reason dropping a column in this table doesn't work. Anyways, we don't want to store old targetValues. // For some reason dropping a column in this table doesn't work. Anyways, we don't want to store old targetValues.
// Instead, on first run the supervisor will store current device config values as targets - so we want to // Instead, on first run the supervisor will store current device config values as targets - so we want to
// make the old values that refer to supervisor config be the *current* values, and we do that by inserting // make the old values that refer to supervisor config be the *current* values, and we do that by inserting
// to the config table. // to the config table.
return knex('deviceConfig').select() return knex('deviceConfig')
.then((deviceConf) => { .select()
return knex.schema.dropTable('deviceConfig') .then(deviceConf => {
.then(() => { return knex.schema.dropTable('deviceConfig').then(() => {
const values = JSON.parse(deviceConf[0].values) const values = JSON.parse(deviceConf[0].values);
const configKeys = { const configKeys = {
'RESIN_SUPERVISOR_POLL_INTERVAL': 'appUpdatePollInterval', RESIN_SUPERVISOR_POLL_INTERVAL: 'appUpdatePollInterval',
'RESIN_SUPERVISOR_LOCAL_MODE': 'localMode', RESIN_SUPERVISOR_LOCAL_MODE: 'localMode',
'RESIN_SUPERVISOR_CONNECTIVITY_CHECK': 'connectivityCheckEnabled', RESIN_SUPERVISOR_CONNECTIVITY_CHECK: 'connectivityCheckEnabled',
'RESIN_SUPERVISOR_LOG_CONTROL': 'loggingEnabled', RESIN_SUPERVISOR_LOG_CONTROL: 'loggingEnabled',
'RESIN_SUPERVISOR_DELTA': 'delta', RESIN_SUPERVISOR_DELTA: 'delta',
'RESIN_SUPERVISOR_DELTA_REQUEST_TIMEOUT': 'deltaRequestTimeout', RESIN_SUPERVISOR_DELTA_REQUEST_TIMEOUT: 'deltaRequestTimeout',
'RESIN_SUPERVISOR_DELTA_APPLY_TIMEOUT': 'deltaApplyTimeout', RESIN_SUPERVISOR_DELTA_APPLY_TIMEOUT: 'deltaApplyTimeout',
'RESIN_SUPERVISOR_DELTA_RETRY_COUNT': 'deltaRetryCount', RESIN_SUPERVISOR_DELTA_RETRY_COUNT: 'deltaRetryCount',
'RESIN_SUPERVISOR_DELTA_RETRY_INTERVAL': 'deltaRequestTimeout', RESIN_SUPERVISOR_DELTA_RETRY_INTERVAL: 'deltaRequestTimeout',
'RESIN_SUPERVISOR_OVERRIDE_LOCK': 'lockOverride' RESIN_SUPERVISOR_OVERRIDE_LOCK: 'lockOverride',
};
return Promise.map(Object.keys(values), envVarName => {
if (configKeys[envVarName] != null) {
return knex('config').insert({
key: configKeys[envVarName],
value: values[envVarName],
});
} }
return Promise.map(Object.keys(values), (envVarName) => { });
if (configKeys[envVarName] != null) { });
return knex('config').insert({ key: configKeys[envVarName], value: values[envVarName]})
}
})
})
}) })
.then(() => { .then(() => {
return knex.schema.createTable('deviceConfig', (t) => { return knex.schema.createTable('deviceConfig', t => {
t.json('targetValues') t.json('targetValues');
}) });
}) })
.then(() => knex('deviceConfig').insert({ targetValues: '{}' })) .then(() => knex('deviceConfig').insert({ targetValues: '{}' }));
}) })
.then(() => knex('dependentApp').select()) .then(() => knex('dependentApp').select())
.then((dependentApps) => { .then(dependentApps => {
return knex.schema.dropTable('dependentApp') return knex.schema
.dropTable('dependentApp')
.then(() => { .then(() => {
return knex.schema.createTable('dependentApp', (t) => { return knex.schema.createTable('dependentApp', t => {
t.increments('id').primary() t.increments('id').primary();
t.integer('appId') t.integer('appId');
t.integer('parentApp') t.integer('parentApp');
t.string('name') t.string('name');
t.string('commit') t.string('commit');
t.integer('releaseId') t.integer('releaseId');
t.integer('imageId') t.integer('imageId');
t.string('image') t.string('image');
t.json('environment') t.json('environment');
t.json('config') t.json('config');
}) });
}) })
.then(() => { .then(() => {
return knex.schema.createTable('dependentAppTarget', (t) => { return knex.schema.createTable('dependentAppTarget', t => {
t.increments('id').primary() t.increments('id').primary();
t.integer('appId') t.integer('appId');
t.integer('parentApp') t.integer('parentApp');
t.string('name') t.string('name');
t.string('commit') t.string('commit');
t.integer('releaseId') t.integer('releaseId');
t.integer('imageId') t.integer('imageId');
t.string('image') t.string('image');
t.json('environment') t.json('environment');
t.json('config') t.json('config');
}) });
}) })
.then(() => { .then(() => {
return Promise.map(dependentApps, (app) => { return Promise.map(dependentApps, app => {
const newApp = { const newApp = {
appId: parseInt(app.appId), appId: parseInt(app.appId, 10),
parentApp: parseInt(app.parentAppId), parentApp: parseInt(app.parentAppId, 10),
image: app.imageId, image: app.imageId,
releaseId: null, releaseId: null,
commit: app.commit, commit: app.commit,
name: app.name, name: app.name,
config: JSON.stringify(tryParse(app.config)), config: JSON.stringify(tryParse(app.config)),
environment: JSON.stringify(tryParse(app.environment)) environment: JSON.stringify(tryParse(app.environment)),
} };
const image = imageForDependentApp(newApp) const image = imageForDependentApp(newApp);
return knex('image').insert(image) return knex('image')
.insert(image)
.then(() => knex('dependentApp').insert(newApp)) .then(() => knex('dependentApp').insert(newApp))
.then(() => knex('dependentAppTarget').insert(newApp)) .then(() => knex('dependentAppTarget').insert(newApp));
}) });
}) });
}) })
.then(() => knex('dependentDevice').select()) .then(() => knex('dependentDevice').select())
.then((dependentDevices) => { .then(dependentDevices => {
return knex.schema.dropTable('dependentDevice') return knex.schema
.dropTable('dependentDevice')
.then(() => { .then(() => {
return knex.schema.createTable('dependentDevice', (t) => { return knex.schema.createTable('dependentDevice', t => {
t.increments('id').primary() t.increments('id').primary();
t.string('uuid') t.string('uuid');
t.integer('appId') t.integer('appId');
t.string('localId') t.string('localId');
t.string('device_type') t.string('device_type');
t.string('logs_channel') t.string('logs_channel');
t.integer('deviceId') t.integer('deviceId');
t.boolean('is_online') t.boolean('is_online');
t.string('name') t.string('name');
t.string('status') t.string('status');
t.string('download_progress') t.string('download_progress');
t.integer('is_managed_by') t.integer('is_managed_by');
t.dateTime('lock_expiry_date') t.dateTime('lock_expiry_date');
t.string('commit') t.string('commit');
t.string('targetCommit') t.string('targetCommit');
t.json('environment') t.json('environment');
t.json('targetEnvironment') t.json('targetEnvironment');
t.json('config') t.json('config');
t.json('targetConfig') t.json('targetConfig');
t.boolean('markedForDeletion') t.boolean('markedForDeletion');
}) });
}) })
.then(() => { .then(() => {
return knex.schema.createTable('dependentDeviceTarget', (t) => { return knex.schema.createTable('dependentDeviceTarget', t => {
t.increments('id').primary() t.increments('id').primary();
t.string('uuid') t.string('uuid');
t.string('name') t.string('name');
t.json('apps') t.json('apps');
}) });
}) })
.then(() => { .then(() => {
return Promise.map(dependentDevices, (device) => { return Promise.map(dependentDevices, device => {
const newDevice = _.clone(device) const newDevice = _.clone(device);
newDevice.appId = parseInt(device.appId) newDevice.appId = parseInt(device.appId, 10);
newDevice.deviceId = parseInt(device.deviceId) newDevice.deviceId = parseInt(device.deviceId, 10);
if (device.is_managed_by != null) { if (device.is_managed_by != null) {
newDevice.is_managed_by = parseInt(device.is_managed_by) newDevice.is_managed_by = parseInt(device.is_managed_by, 10);
} }
newDevice.config = JSON.stringify(tryParse(device.config)) newDevice.config = JSON.stringify(tryParse(device.config));
newDevice.environment = JSON.stringify(tryParse(device.environment)) newDevice.environment = JSON.stringify(
newDevice.targetConfig = JSON.stringify(tryParse(device.targetConfig)) tryParse(device.environment),
newDevice.targetEnvironment = JSON.stringify(tryParse(device.targetEnvironment)) );
newDevice.targetConfig = JSON.stringify(
tryParse(device.targetConfig),
);
newDevice.targetEnvironment = JSON.stringify(
tryParse(device.targetEnvironment),
);
if (newDevice.markedForDeletion == null) { if (newDevice.markedForDeletion == null) {
newDevice.markedForDeletion = false newDevice.markedForDeletion = false;
} }
const deviceTarget = { const deviceTarget = {
uuid: device.uuid, uuid: device.uuid,
name: device.name, name: device.name,
apps: {} apps: {},
} };
deviceTarget.apps[device.appId] = { deviceTarget.apps[device.appId] = {
commit: newDevice.targetCommit, commit: newDevice.targetCommit,
config: newDevice.targetConfig, config: newDevice.targetConfig,
environment: newDevice.targetEnvironment environment: newDevice.targetEnvironment,
} };
return knex('dependentDevice').insert(newDevice) return knex('dependentDevice')
.then(() => knex('dependentDeviceTarget').insert(deviceTarget)) .insert(newDevice)
}) .then(() => knex('dependentDeviceTarget').insert(deviceTarget));
}) });
}) });
} });
};
exports.down = function(knex, Promise) { exports.down = function(knex, Promise) {
return Promise.reject(new Error('Not implemented')) return Promise.reject(new Error('Not implemented'));
} };

View File

@ -1,10 +1,10 @@
// Adds a dockerImageId column to the image table to identify images downloaded with deltas // Adds a dockerImageId column to the image table to identify images downloaded with deltas
exports.up = function (knex, Promise) { exports.up = function(knex, Promise) {
return knex.schema.table('image', (t) => { return knex.schema.table('image', t => {
t.string('dockerImageId') t.string('dockerImageId');
}) });
} };
exports.down = function(knex, Promise) { exports.down = function(knex, Promise) {
return Promise.reject(new Error('Not implemented')) return Promise.reject(new Error('Not implemented'));
} };

View File

@ -1,39 +1,45 @@
const fs = require('fs'); const fs = require('fs');
const configJsonPath = process.env.CONFIG_MOUNT_POINT; const configJsonPath = process.env.CONFIG_MOUNT_POINT;
exports.up = function (knex, Promise) { exports.up = function(knex, Promise) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!configJsonPath) { if (!configJsonPath) {
console.log('Unable to locate config.json! Things may fail unexpectedly!'); console.log(
'Unable to locate config.json! Things may fail unexpectedly!',
);
resolve({}); resolve({});
} }
fs.readFile(configJsonPath, (err, data) => { fs.readFile(configJsonPath, (err, data) => {
if (err) { if (err) {
console.log('Failed to read config.json! Things may fail unexpectedly!'); console.log(
'Failed to read config.json! Things may fail unexpectedly!',
);
resolve({}); resolve({});
return; return;
} }
try { try {
const parsed = JSON.parse(data.toString()); const parsed = JSON.parse(data.toString());
resolve(parsed); resolve(parsed);
} catch(e) { } catch (e) {
console.log('Failed to parse config.json! Things may fail unexpectedly!'); console.log(
'Failed to parse config.json! Things may fail unexpectedly!',
);
resolve({}); resolve({});
} }
}); });
}) }).then(config => {
.then((config) => { return knex.schema
return knex.schema.table('app', (t) => { .table('app', t => {
// Create a new column on the table and add the apiEndpoint config json // Create a new column on the table and add the apiEndpoint config json
// field if it exists // field if it exists
t.string('source'); t.string('source');
}) })
.then(() => { .then(() => {
return knex('app').update({ source: (config.apiEndpoint || '') }); return knex('app').update({ source: config.apiEndpoint || '' });
}); });
}); });
} };
exports.down = function (knex, Promise) { exports.down = function(knex, Promise) {
return Promise.reject(new Error('Not Implemented')) return Promise.reject(new Error('Not Implemented'));
} };

View File

@ -1,16 +1,20 @@
const fs = require('fs'); const fs = require('fs');
const configJsonPath = process.env.CONFIG_MOUNT_POINT; const configJsonPath = process.env.CONFIG_MOUNT_POINT;
exports.up = function (knex, Promise) { exports.up = function(knex, Promise) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!configJsonPath) { if (!configJsonPath) {
console.log('Unable to locate config.json! Things may fail unexpectedly!'); console.log(
'Unable to locate config.json! Things may fail unexpectedly!',
);
resolve({}); resolve({});
return; return;
} }
fs.readFile(configJsonPath, (err, data) => { fs.readFile(configJsonPath, (err, data) => {
if (err) { if (err) {
console.log('Failed to read config.json! Things may fail unexpectedly!'); console.log(
'Failed to read config.json! Things may fail unexpectedly!',
);
resolve({}); resolve({});
return; return;
} }
@ -18,7 +22,9 @@ exports.up = function (knex, Promise) {
const parsed = JSON.parse(data.toString()); const parsed = JSON.parse(data.toString());
resolve(parsed); resolve(parsed);
} catch (e) { } catch (e) {
console.log('Failed to parse config.json! Things may fail unexpectedly!'); console.log(
'Failed to parse config.json! Things may fail unexpectedly!',
);
resolve({}); resolve({});
} }
}); });
@ -26,18 +32,20 @@ exports.up = function (knex, Promise) {
.tap(() => { .tap(() => {
// take the logsChannelSecret, and the apiEndpoint config field, // take the logsChannelSecret, and the apiEndpoint config field,
// and store them in a new table // and store them in a new table
return knex.schema.hasTable('logsChannelSecret').then((exists) => { return knex.schema.hasTable('logsChannelSecret').then(exists => {
if (!exists) { if (!exists) {
return knex.schema.createTable('logsChannelSecret', (t) => { return knex.schema.createTable('logsChannelSecret', t => {
t.string('backend'); t.string('backend');
t.string('secret'); t.string('secret');
}); });
} }
}); });
}) })
.then((config) => { .then(config => {
return knex('config').where({ key: 'logsChannelSecret' }).select('value') return knex('config')
.then((results) => { .where({ key: 'logsChannelSecret' })
.select('value')
.then(results => {
if (results.length === 0) { if (results.length === 0) {
return { config, secret: null }; return { config, secret: null };
} }
@ -47,15 +55,16 @@ exports.up = function (knex, Promise) {
.then(({ config, secret }) => { .then(({ config, secret }) => {
return knex('logsChannelSecret').insert({ return knex('logsChannelSecret').insert({
backend: config.apiEndpoint || '', backend: config.apiEndpoint || '',
secret secret,
}); });
}) })
.then(() => { .then(() => {
return knex('config').where('key', 'logsChannelSecret').del(); return knex('config')
.where('key', 'logsChannelSecret')
.del();
}); });
};
} exports.down = function(knex, Promise) {
exports.down = function (knex, Promise) {
return Promise.reject(new Error('Not Implemented')); return Promise.reject(new Error('Not Implemented'));
} };

View File

@ -1,11 +1,10 @@
exports.up = (knex, Promise) => { exports.up = (knex, Promise) => {
return knex.schema.createTable('engineSnapshot', (t) => { return knex.schema.createTable('engineSnapshot', t => {
t.string('snapshot'); // Engine snapshot encoded as JSON. t.string('snapshot'); // Engine snapshot encoded as JSON.
t.string('timestamp'); // When the snapshot was created. t.string('timestamp'); // When the snapshot was created.
}); });
} };
exports.down = (knex, Promise) => { exports.down = (knex, Promise) => {
return Promise.reject(new Error('Not Implemented')); return Promise.reject(new Error('Not Implemented'));
} };

View File

@ -3,18 +3,21 @@ const _ = require('lodash');
// We take legacy deviceConfig targets and store them without the RESIN_ prefix // We take legacy deviceConfig targets and store them without the RESIN_ prefix
// (we also strip the BALENA_ prefix for completeness, even though no supervisors // (we also strip the BALENA_ prefix for completeness, even though no supervisors
// using this prefix made it to production) // using this prefix made it to production)
exports.up = function (knex, Promise) { exports.up = function(knex, Promise) {
return knex('deviceConfig').select('targetValues') return knex('deviceConfig')
.then((devConfigs) => { .select('targetValues')
.then(devConfigs => {
const devConfig = devConfigs[0]; const devConfig = devConfigs[0];
const targetValues = JSON.parse(devConfig.targetValues); const targetValues = JSON.parse(devConfig.targetValues);
const filteredTargetValues = _.mapKeys(targetValues, (_v, k) => { const filteredTargetValues = _.mapKeys(targetValues, (_v, k) => {
return k.replace(/^(?:RESIN|BALENA)_(.*)/, '$1'); return k.replace(/^(?:RESIN|BALENA)_(.*)/, '$1');
}); });
return knex('deviceConfig').update({ targetValues: JSON.stringify(filteredTargetValues) }); return knex('deviceConfig').update({
targetValues: JSON.stringify(filteredTargetValues),
});
}); });
}; };
exports.down = function (knex, Promise) { exports.down = function(knex, Promise) {
return Promise.reject(new Error('Not Implemented')); return Promise.reject(new Error('Not Implemented'));
}; };

View File

@ -3,9 +3,11 @@ const configJsonPath = process.env.CONFIG_MOUNT_POINT;
const { checkTruthy } = require('../lib/validation'); const { checkTruthy } = require('../lib/validation');
exports.up = function (knex, Promise) { exports.up = function(knex, Promise) {
return knex('config').where({ key: 'localMode' }).select('value') return knex('config')
.then((results) => { .where({ key: 'localMode' })
.select('value')
.then(results => {
if (results.length === 0) { if (results.length === 0) {
// We don't need to do anything // We don't need to do anything
return; return;
@ -14,15 +16,19 @@ exports.up = function (knex, Promise) {
let value = checkTruthy(results[0].value); let value = checkTruthy(results[0].value);
value = value != null ? value : false; value = value != null ? value : false;
return new Promise((resolve) => { return new Promise(resolve => {
if (!configJsonPath) { if (!configJsonPath) {
console.log('Unable to locate config.json! Things may fail unexpectedly!'); console.log(
'Unable to locate config.json! Things may fail unexpectedly!',
);
resolve(); resolve();
return; return;
} }
fs.readFile(configJsonPath, (err, data) => { fs.readFile(configJsonPath, (err, data) => {
if (err) { if (err) {
console.log('Failed to read config.json! Things may fail unexpectedly!'); console.log(
'Failed to read config.json! Things may fail unexpectedly!',
);
resolve(); resolve();
return; return;
} }
@ -31,27 +37,30 @@ exports.up = function (knex, Promise) {
// Assign the local mode value // Assign the local mode value
parsed.localMode = value; parsed.localMode = value;
fs.writeFile(configJsonPath, JSON.stringify(parsed), (err) => { fs.writeFile(configJsonPath, JSON.stringify(parsed), err2 => {
if (err) { if (err2) {
console.log('Failed to write config.json! Things may fail unexpectedly!'); console.log(
'Failed to write config.json! Things may fail unexpectedly!',
);
return; return;
} }
resolve(); resolve();
}); });
} catch (e) { } catch (e) {
console.log('Failed to parse config.json! Things may fail unexpectedly!'); console.log(
'Failed to parse config.json! Things may fail unexpectedly!',
);
resolve(); resolve();
} }
}); });
}) }).then(() => {
.then(() => { return knex('config')
return knex('config').where('key', 'localMode').del(); .where('key', 'localMode')
}); .del();
});
}); });
}; };
exports.down = function (knex, Promise) { exports.down = function(knex, Promise) {
return Promise.reject(new Error('Not Implemented')); return Promise.reject(new Error('Not Implemented'));
} };

View File

@ -3,16 +3,20 @@ const configJsonPath = process.env.CONFIG_MOUNT_POINT;
const { checkTruthy } = require('../lib/validation'); const { checkTruthy } = require('../lib/validation');
exports.up = function (knex, Promise) { exports.up = function(knex, Promise) {
return new Promise(resolve => { return new Promise(resolve => {
if (!configJsonPath) { if (!configJsonPath) {
console.log('Unable to locate config.json! Things may fail unexpectedly!'); console.log(
'Unable to locate config.json! Things may fail unexpectedly!',
);
return resolve(false); return resolve(false);
} }
fs.readFile(configJsonPath, (err, data) => { fs.readFile(configJsonPath, (err, data) => {
if (err) { if (err) {
console.log('Failed to read config.json! Things may fail unexpectedly!'); console.log(
'Failed to read config.json! Things may fail unexpectedly!',
);
return resolve(); return resolve();
} }
try { try {
@ -22,7 +26,9 @@ exports.up = function (knex, Promise) {
} }
return resolve(false); return resolve(false);
} catch (e) { } catch (e) {
console.log('Failed to parse config.json! Things may fail unexpectedly!'); console.log(
'Failed to parse config.json! Things may fail unexpectedly!',
);
return resolve(false); return resolve(false);
} }
}); });
@ -36,6 +42,6 @@ exports.up = function (knex, Promise) {
}); });
}; };
exports.down = function (knex, Promise) { exports.down = function(knex, Promise) {
return Promise.reject(new Error('Not Implemented')); return Promise.reject(new Error('Not Implemented'));
}; };

@ -1 +1 @@
Subproject commit 5b1459007cea18b5891d6bdf4b0694241487cc8b Subproject commit e413fcedb9e3a5365da91c01a45e633d620947af

View File

@ -1,3 +1,3 @@
{ {
"extends": ["resin-lint/config/tslint-prettier.json"] "extends": ["@balena/lint/config/tslint-prettier.json"]
} }

View File

@ -2,7 +2,6 @@ var webpack = require('webpack');
var path = require('path'); var path = require('path');
var fs = require('fs'); var fs = require('fs');
var _ = require('lodash'); var _ = require('lodash');
var path = require('path');
const CopyWebpackPlugin = require('copy-webpack-plugin'); const CopyWebpackPlugin = require('copy-webpack-plugin');
var ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); var ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
@ -122,7 +121,7 @@ module.exports = function(env) {
(m instanceof RegExp && m.test(request)) (m instanceof RegExp && m.test(request))
) { ) {
return callback(null, 'commonjs ' + request); return callback(null, 'commonjs ' + request);
} else if (typeof m != 'string' && !(m instanceof RegExp)) { } else if (typeof m !== 'string' && !(m instanceof RegExp)) {
throw new Error('Invalid entry in external modules: ' + m); throw new Error('Invalid entry in external modules: ' + m);
} }
} }