2018-10-18 18:54:19 +00:00
|
|
|
// Deploy a supervisor image as a supervisor_release in the balena API
|
2017-07-12 17:18:35 +00:00
|
|
|
//
|
|
|
|
// Environment variables:
|
2017-08-24 06:25:34 +00:00
|
|
|
// This program deploys for all device types, or only device types where the architecture matches $ARCH, if specified.
|
2017-07-12 17:18:35 +00:00
|
|
|
// It deploys to the API specified by $API_ENDPOINT and using a provided $API_TOKEN or $API_KEY
|
|
|
|
// (if both are set, API_TOKEN is preferred).
|
|
|
|
// The tag to deploy must be passed as $TAG.
|
|
|
|
//
|
|
|
|
const PineJsClient = require('pinejs-client');
|
|
|
|
const Promise = require('bluebird');
|
|
|
|
const _ = require('lodash');
|
|
|
|
const url = require('url');
|
|
|
|
|
|
|
|
const apiEndpoint = process.env.API_ENDPOINT;
|
|
|
|
const apikey = process.env.API_KEY;
|
|
|
|
const arch = process.env.ARCH;
|
|
|
|
const tag = process.env.TAG;
|
|
|
|
const apiToken = process.env.API_TOKEN;
|
|
|
|
|
|
|
|
if (_.isEmpty(apikey) && _.isEmpty(apiToken)) {
|
|
|
|
console.error('Skipping deploy due to empty API_KEY and API_TOKEN');
|
|
|
|
process.exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_.isEmpty(apiEndpoint)) {
|
|
|
|
console.error('Please set a valid $API_ENDPOINT');
|
|
|
|
process.exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_.isEmpty(tag)) {
|
|
|
|
console.error('Please set a $TAG to deploy');
|
|
|
|
process.exit(1);
|
|
|
|
}
|
|
|
|
|
2018-02-27 00:46:48 +00:00
|
|
|
const supportedArchitectures = [ 'amd64', 'rpi', 'aarch64', 'i386', 'armv7hf', 'i386-nlp' ];
|
2017-08-24 06:25:34 +00:00
|
|
|
if (!_.isEmpty(arch) && !_.includes(supportedArchitectures, arch)) {
|
2017-07-12 17:18:35 +00:00
|
|
|
console.error('Invalid architecture ' + arch);
|
|
|
|
process.exit(1);
|
|
|
|
}
|
2017-08-24 06:25:34 +00:00
|
|
|
const archs = _.isEmpty(arch) ? supportedArchitectures : [ arch ];
|
2018-01-24 16:42:08 +00:00
|
|
|
const quarkSlugs = [ 'iot2000', 'cybertan-ze250' ];
|
2017-07-12 17:18:35 +00:00
|
|
|
|
|
|
|
const requestOpts = {
|
|
|
|
gzip: true,
|
|
|
|
timeout: 30000
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!_.isEmpty(apiToken)) {
|
|
|
|
requestOpts.headers = {
|
|
|
|
Authorization: 'Bearer ' + apiToken
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const apiEndpointWithPrefix = url.resolve(apiEndpoint, '/v2/')
|
2018-10-18 18:54:19 +00:00
|
|
|
const balenaApi = new PineJsClient({
|
2017-07-12 17:18:35 +00:00
|
|
|
apiPrefix: apiEndpointWithPrefix,
|
|
|
|
passthrough: requestOpts
|
|
|
|
});
|
|
|
|
|
2018-10-18 18:54:19 +00:00
|
|
|
balenaApi._request(_.extend({
|
2017-07-12 17:18:35 +00:00
|
|
|
url: apiEndpoint + '/config/device-types',
|
|
|
|
method: 'GET'
|
2018-10-18 18:54:19 +00:00
|
|
|
}, balenaApi.passthrough))
|
2017-07-12 17:18:35 +00:00
|
|
|
.then( (deviceTypes) => {
|
|
|
|
// This is a critical step so we better do it serially
|
|
|
|
return Promise.mapSeries(deviceTypes, (deviceType) => {
|
2017-08-24 06:25:34 +00:00
|
|
|
if (archs.indexOf(deviceType.arch) >= 0) {
|
2017-07-12 17:18:35 +00:00
|
|
|
const customOptions = {};
|
2018-01-24 16:42:08 +00:00
|
|
|
let arch = deviceType.arch;
|
2017-07-12 17:18:35 +00:00
|
|
|
if (_.isEmpty(apiToken)) {
|
|
|
|
customOptions.apikey = apikey;
|
|
|
|
}
|
2018-01-24 16:42:08 +00:00
|
|
|
if (quarkSlugs.indexOf(deviceType.slug) >= 0) {
|
|
|
|
arch = 'i386-nlp';
|
|
|
|
}
|
2017-07-28 03:13:10 +00:00
|
|
|
console.log(`Deploying ${tag} for ${deviceType.slug}`);
|
2018-10-18 18:54:19 +00:00
|
|
|
return balenaApi.post({
|
2017-07-12 17:18:35 +00:00
|
|
|
resource: 'supervisor_release',
|
|
|
|
body: {
|
2018-10-18 18:54:19 +00:00
|
|
|
image_name: `balena/${arch}-supervisor`,
|
2017-07-12 17:18:35 +00:00
|
|
|
supervisor_version: tag,
|
|
|
|
device_type: deviceType.slug,
|
|
|
|
is_public: true
|
|
|
|
},
|
|
|
|
customOptions
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
})
|
|
|
|
.then( () => {
|
|
|
|
process.exit(0);
|
|
|
|
})
|
|
|
|
.catch( (err) => {
|
|
|
|
console.error(`Error when deploying the supervisor to ${apiEndpoint}`, err, err.stack);
|
|
|
|
process.exit(1);
|
|
|
|
});
|