Add a deploy-to-resin.js and automatically deploy to the Resin API on master builds

Also, make all of the arch builds part of the Circle workflow.

Change-Type: patch
Signed-off-by: Pablo Carranza Velez <pablo@resin.io>
This commit is contained in:
Pablo Carranza Velez 2017-07-12 10:18:35 -07:00
parent 392d963348
commit 60a8ab85f4
6 changed files with 161 additions and 14 deletions

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
/node_modules/
/automation/node_modules/
*.swp
data
bin/gosuper

View File

@ -4,7 +4,14 @@ RUN apk add --no-cache \
make \
jq \
git \
bash
bash \
nodejs \
nodejs-npm
WORKDIR /src
COPY ./automation/package.json /src/automation/package.json
RUN cd automation \
&& JOBS=max npm install \
&& npm cache clean
COPY . /src

View File

@ -11,6 +11,7 @@
# * CLEANUP
# * ENABLE_TESTS
# * PUBNUB_SUBSCRIBE_KEY, PUBNUB_PUBLISH_KEY, MIXPANEL_TOKEN: default keys to inject in the supervisor image
# * EXTRA_TAG: when PUSH_IMAGES is true, additional tag to push to the registries
#
# Builds the supervisor for the architecture defined by $ARCH.
# Will produce and push an image tagged as resin/$ARCH-supervisor:$TAG
@ -109,13 +110,20 @@ make IMAGE=$TARGET_IMAGE supervisor
if [ "$PUSH_IMAGES" = "true" ]; then
make IMAGE=$TARGET_IMAGE deploy
docker tag $TARGET_IMAGE registry.resinstaging.io/$TARGET_IMAGE
make IMAGE=registry.resinstaging.io/$TARGET_IMAGE deploy
make IMAGE=registry.resinstaging.io/$TARGET_IMAGE deploy
# Try to push the intermediate images to improve caching in future builds
# But we don't care much if any of this fails.
( make IMAGE=$BASE_IMAGE base && make IMAGE=$BASE_IMAGE deploy ) || true
( make IMAGE=$GO_IMAGE gosuper && make IMAGE=$GO_IMAGE deploy ) || true
( make IMAGE=$NODE_IMAGE node && make IMAGE=$NODE_IMAGE deploy ) || true
if [ -n "$EXTRA_TAG" ]; then
docker tag $TARGET_IMAGE resin/$ARCH-supervisor:$EXTRA_TAG
make IMAGE=resin/$ARCH-supervisor:$EXTRA_TAG deploy
docker tag $TARGET_IMAGE registry.resinstaging.io/resin/$ARCH-supervisor:$EXTRA_TAG
make IMAGE=registry.resinstaging.io/resin/$ARCH-supervisor:$EXTRA_TAG deploy
fi
# Try to push the intermediate images to improve caching in future builds
# But we don't care much if any of this fails.
( make IMAGE=$BASE_IMAGE base && make IMAGE=$BASE_IMAGE deploy ) || true
( make IMAGE=$GO_IMAGE gosuper && make IMAGE=$GO_IMAGE deploy ) || true
( make IMAGE=$NODE_IMAGE node && make IMAGE=$NODE_IMAGE deploy ) || true
fi
if [ "$CLEANUP" = "true" ]; then

View File

@ -0,0 +1,91 @@
// Deploy a supervisor image as a supervisor_release in the Resin API
//
// Environment variables:
// This program deploys only for device types where the architecture matches $ARCH.
// 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);
}
const supportedArchitectures = [ 'amd64', 'rpi', 'aarch64', 'armel', 'i386', 'armv7hf' ];
if (_.isEmpty(arch) || !_.includes(supportedArchitectures, arch)) {
console.error('Invalid architecture ' + arch);
process.exit(1);
}
const requestOpts = {
gzip: true,
timeout: 30000
};
if (!_.isEmpty(apiToken)) {
requestOpts.headers = {
Authorization: 'Bearer ' + apiToken
};
}
const apiEndpointWithPrefix = url.resolve(apiEndpoint, '/v2/')
const resinApi = new PineJsClient({
apiPrefix: apiEndpointWithPrefix,
passthrough: requestOpts
});
resinApi._request(_.extend({
url: apiEndpoint + '/config/device-types',
method: 'GET'
}, resinApi.passthrough))
.then( (deviceTypes) => {
// This is a critical step so we better do it serially
return Promise.mapSeries(deviceTypes, (deviceType) => {
if (deviceType.arch === arch) {
const customOptions = {};
if (_.isEmpty(apiToken)) {
customOptions.apikey = apikey;
}
console.log(`Deploying ${supervisor_version} for ${device_type}`);
return resinApi.post({
resource: 'supervisor_release',
body: {
image_name: `registry.resinstaging.io/resin/${arch}-supervisor`,
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);
});

16
automation/package.json Normal file
View File

@ -0,0 +1,16 @@
{
"name": "resin-supervisor-automation",
"version": "1.0.0",
"description": "Tools to build/deploy resin-supervisor",
"main": "deploy-to-resin.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Resin Inc.",
"license": "Apache-2.0",
"dependencies": {
"bluebird": "^3.5.0",
"lodash": "^4.17.4",
"pinejs-client": "^4.0.0"
}
}

View File

@ -3,16 +3,13 @@ defaults: &defaults
docker:
- image: library/docker:stable
working_directory: /tmp/build
environment:
DOCKER_USERNAME: travisciresin
DOCKER_EMAIL: accounts+travisci+docker@resin.io
steps:
- setup_remote_docker
- run:
name: Check docker is running and install git
command: |
docker info
apk update && apk upgrade && apk add --nocache git
apk update && apk upgrade && apk add --nocache git jq
- checkout
- run:
name: Initialize the submodules (yocto layers)
@ -34,9 +31,20 @@ defaults: &defaults
dind=$(docker run --privileged -d builder)
# confirm it's running
docker ps
VERSION_TAG=v$(jq .version package.json | sed 's/"//g')
if [ "${CIRCLE_BRANCH}" = "master" ]; then
EXTRA_BUILD_ARGS="-e EXTRA_TAG=$VERSION_TAG"
else
EXTRA_BUILD_ARGS=""
fi
# start the build for this architecture
docker exec -it -e TAG=${CIRCLE_BRANCH} -e ARCH=${ARCH} -e PUSH_IMAGES=${PUSH_IMAGES} ${dind} bash automation/build.sh
docker exec -ti ${dind} docker images
docker exec -it -e TAG=${CIRCLE_BRANCH} -e ARCH=${ARCH} -e PUSH_IMAGES=${PUSH_IMAGES} $EXTRA_BUILD_ARGS ${dind} bash automation/build.sh
if [ "${CIRCLE_BRANCH}" = "master" ] && [ "${DEPLOY_TO_RESIN}" = "true" ]; then
echo "Deploying to Resin API (staging)"
docker exec -it -e ARCH=${ARCH} -e TAG=$VERSION_TAG -e API_KEY=$STAGING_API_KEY -e API_ENDPOINT=$STAGING_API_ENDPOINT ${dind} node automation/deploy-to-resin.js
echo "Deploying to Resin API (production)"
docker exec -it -e ARCH=${ARCH} -e TAG=$VERSION_TAG -e API_KEY=$PRODUCTION_API_KEY -e API_ENDPOINT=$PRODUCTION_API_ENDPOINT ${dind} node automation/deploy-to-resin.js
fi
version: 2
jobs:
@ -47,6 +55,8 @@ jobs:
DOCKER_EMAIL: accounts+travisci+docker@resin.io
ARCH: amd64
PUSH_IMAGES: "true"
STAGING_API_ENDPOINT: https://api.resinstaging.io
PRODUCTION_API_ENDPOINT: https://api.resin.io
i386:
<<: *defaults
environment:
@ -54,6 +64,8 @@ jobs:
DOCKER_EMAIL: accounts+travisci+docker@resin.io
ARCH: i386
PUSH_IMAGES: "true"
STAGING_API_ENDPOINT: https://api.resinstaging.io
PRODUCTION_API_ENDPOINT: https://api.resin.io
armel:
<<: *defaults
environment:
@ -61,6 +73,8 @@ jobs:
DOCKER_EMAIL: accounts+travisci+docker@resin.io
ARCH: armel
PUSH_IMAGES: "true"
STAGING_API_ENDPOINT: https://api.resinstaging.io
PRODUCTION_API_ENDPOINT: https://api.resin.io
armv7hf:
<<: *defaults
environment:
@ -68,6 +82,8 @@ jobs:
DOCKER_EMAIL: accounts+travisci+docker@resin.io
ARCH: armv7hf
PUSH_IMAGES: "true"
STAGING_API_ENDPOINT: https://api.resinstaging.io
PRODUCTION_API_ENDPOINT: https://api.resin.io
aarch64:
<<: *defaults
environment:
@ -75,6 +91,8 @@ jobs:
DOCKER_EMAIL: accounts+travisci+docker@resin.io
ARCH: aarch64
PUSH_IMAGES: "true"
STAGING_API_ENDPOINT: https://api.resinstaging.io
PRODUCTION_API_ENDPOINT: https://api.resin.io
rpi:
<<: *defaults
environment:
@ -82,10 +100,16 @@ jobs:
DOCKER_EMAIL: accounts+travisci+docker@resin.io
ARCH: rpi
PUSH_IMAGES: "true"
STAGING_API_ENDPOINT: https://api.resinstaging.io
PRODUCTION_API_ENDPOINT: https://api.resin.io
workflows:
version: 2
build_them_all:
build_and_maybe_deploy:
jobs:
- amd64
- i386
- rpi
- armv7hf
- aarch64
- armel