mirror of
https://github.com/balena-io/balena-cli.git
synced 2024-12-23 23:42:24 +00:00
Merge pull request #1769 from balena-io/js-lib-utils-deploy-legacy
Convert lib/utils/deploy-legacy.coffee to javascript
This commit is contained in:
commit
5fef98bdf8
@ -89,7 +89,7 @@ deployProject = (docker, logger, composeOpts, opts) ->
|
||||
}
|
||||
.then (images) ->
|
||||
if opts.app.application_type?[0]?.is_legacy
|
||||
legacyDeploy = require('../utils/deploy-legacy')
|
||||
{ deployLegacy } = require('../utils/deploy-legacy')
|
||||
|
||||
msg = getChalk().yellow('Target application requires legacy deploy method.')
|
||||
logger.logWarn(msg)
|
||||
@ -107,7 +107,7 @@ deployProject = (docker, logger, composeOpts, opts) ->
|
||||
buildLogs: images[0].logs
|
||||
shouldUploadLogs: opts.shouldUploadLogs
|
||||
}
|
||||
legacyDeploy
|
||||
deployLegacy
|
||||
)
|
||||
.then (releaseId) ->
|
||||
sdk.models.release.get(releaseId, $select: [ 'commit' ])
|
||||
|
@ -1,137 +0,0 @@
|
||||
Promise = require('bluebird')
|
||||
{ getVisuals } = require('./lazy')
|
||||
|
||||
getBuilderPushEndpoint = (baseUrl, owner, app) ->
|
||||
querystring = require('querystring')
|
||||
args = querystring.stringify({ owner, app })
|
||||
"https://builder.#{baseUrl}/v1/push?#{args}"
|
||||
|
||||
getBuilderLogPushEndpoint = (baseUrl, buildId, owner, app) ->
|
||||
querystring = require('querystring')
|
||||
args = querystring.stringify({ owner, app, buildId })
|
||||
"https://builder.#{baseUrl}/v1/pushLogs?#{args}"
|
||||
|
||||
bufferImage = (docker, imageId, bufferFile) ->
|
||||
Promise = require('bluebird')
|
||||
streamUtils = require('./streams')
|
||||
|
||||
image = docker.getImage(imageId)
|
||||
imageMetadata = image.inspect()
|
||||
|
||||
Promise.join image.get(), imageMetadata.get('Size'), (imageStream, imageSize) ->
|
||||
streamUtils.buffer(imageStream, bufferFile)
|
||||
.tap (bufferedStream) ->
|
||||
bufferedStream.length = imageSize
|
||||
|
||||
showPushProgress = (message) ->
|
||||
visuals = getVisuals()
|
||||
progressBar = new visuals.Progress(message)
|
||||
progressBar.update({ percentage: 0 })
|
||||
return progressBar
|
||||
|
||||
uploadToPromise = (uploadRequest, logger) ->
|
||||
new Promise (resolve, reject) ->
|
||||
|
||||
handleMessage = (data) ->
|
||||
data = data.toString()
|
||||
logger.logDebug("Received data: #{data}")
|
||||
|
||||
try
|
||||
obj = JSON.parse(data)
|
||||
catch e
|
||||
logger.logError('Error parsing reply from remote side')
|
||||
reject(e)
|
||||
return
|
||||
|
||||
switch obj.type
|
||||
when 'error' then reject(new Error("Remote error: #{obj.error}"))
|
||||
when 'success' then resolve(obj)
|
||||
when 'status' then logger.logInfo(obj.message)
|
||||
else reject(new Error("Received unexpected reply from remote: #{data}"))
|
||||
|
||||
uploadRequest
|
||||
.on('error', reject)
|
||||
.on('data', handleMessage)
|
||||
|
||||
uploadImage = (imageStream, token, username, url, appName, logger) ->
|
||||
request = require('request')
|
||||
progressStream = require('progress-stream')
|
||||
zlib = require('zlib')
|
||||
|
||||
# Need to strip off the newline
|
||||
progressMessage = logger.formatMessage('info', 'Uploading').slice(0, -1)
|
||||
progressBar = showPushProgress(progressMessage)
|
||||
streamWithProgress = imageStream.pipe progressStream
|
||||
time: 500,
|
||||
length: imageStream.length
|
||||
, ({ percentage, eta }) ->
|
||||
progressBar.update
|
||||
percentage: Math.min(percentage, 100)
|
||||
eta: eta
|
||||
|
||||
uploadRequest = request.post
|
||||
url: getBuilderPushEndpoint(url, username, appName)
|
||||
headers:
|
||||
'Content-Encoding': 'gzip'
|
||||
auth:
|
||||
bearer: token
|
||||
body: streamWithProgress.pipe(zlib.createGzip({
|
||||
level: 6
|
||||
}))
|
||||
|
||||
uploadToPromise(uploadRequest, logger)
|
||||
|
||||
uploadLogs = (logs, token, url, buildId, username, appName) ->
|
||||
request = require('request')
|
||||
request.post
|
||||
json: true
|
||||
url: getBuilderLogPushEndpoint(url, buildId, username, appName)
|
||||
auth:
|
||||
bearer: token
|
||||
body: Buffer.from(logs)
|
||||
|
||||
###
|
||||
opts must be a hash with the following keys:
|
||||
|
||||
- appName: the name of the app to deploy to
|
||||
- imageName: the name of the image to deploy
|
||||
- buildLogs: a string with build output
|
||||
- shouldUploadLogs
|
||||
###
|
||||
module.exports = (docker, logger, token, username, url, opts) ->
|
||||
tmp = require('tmp')
|
||||
tmpNameAsync = Promise.promisify(tmp.tmpName)
|
||||
|
||||
# Ensure the tmp files gets deleted
|
||||
tmp.setGracefulCleanup()
|
||||
|
||||
{ appName, imageName, buildLogs, shouldUploadLogs } = opts
|
||||
logs = buildLogs
|
||||
|
||||
tmpNameAsync()
|
||||
.then (bufferFile) ->
|
||||
logger.logInfo('Initializing deploy...')
|
||||
bufferImage(docker, imageName, bufferFile)
|
||||
.then (stream) ->
|
||||
uploadImage(stream, token, username, url, appName, logger)
|
||||
.finally ->
|
||||
# If the file was never written to (for instance because an error
|
||||
# has occured before any data was written) this call will throw an
|
||||
# ugly error, just suppress it
|
||||
Promise.try ->
|
||||
require('mz/fs').unlink(bufferFile)
|
||||
.catchReturn()
|
||||
.tap ({ buildId }) ->
|
||||
return if not shouldUploadLogs
|
||||
|
||||
logger.logInfo('Uploading logs...')
|
||||
Promise.join(
|
||||
logs
|
||||
token
|
||||
url
|
||||
buildId
|
||||
username
|
||||
appName
|
||||
uploadLogs
|
||||
)
|
||||
.get('buildId')
|
209
lib/utils/deploy-legacy.js
Normal file
209
lib/utils/deploy-legacy.js
Normal file
@ -0,0 +1,209 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2020 Balena Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as Promise from 'bluebird';
|
||||
import { getVisuals } from './lazy';
|
||||
|
||||
const getBuilderPushEndpoint = function(baseUrl, owner, app) {
|
||||
const querystring = require('querystring');
|
||||
const args = querystring.stringify({ owner, app });
|
||||
return `https://builder.${baseUrl}/v1/push?${args}`;
|
||||
};
|
||||
|
||||
const getBuilderLogPushEndpoint = function(baseUrl, buildId, owner, app) {
|
||||
const querystring = require('querystring');
|
||||
const args = querystring.stringify({ owner, app, buildId });
|
||||
return `https://builder.${baseUrl}/v1/pushLogs?${args}`;
|
||||
};
|
||||
|
||||
const bufferImage = function(docker, imageId, bufferFile) {
|
||||
const streamUtils = require('./streams');
|
||||
|
||||
const image = docker.getImage(imageId);
|
||||
const imageMetadata = image.inspect();
|
||||
|
||||
return Promise.join(
|
||||
image.get(),
|
||||
imageMetadata.get('Size'),
|
||||
(imageStream, imageSize) =>
|
||||
streamUtils.buffer(imageStream, bufferFile).tap(bufferedStream => {
|
||||
// @ts-ignore adding an extra property
|
||||
bufferedStream.length = imageSize;
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const showPushProgress = function(message) {
|
||||
const visuals = getVisuals();
|
||||
const progressBar = new visuals.Progress(message);
|
||||
progressBar.update({ percentage: 0 });
|
||||
return progressBar;
|
||||
};
|
||||
|
||||
const uploadToPromise = (uploadRequest, logger) =>
|
||||
new Promise(function(resolve, reject) {
|
||||
const handleMessage = function(data) {
|
||||
let obj;
|
||||
data = data.toString();
|
||||
logger.logDebug(`Received data: ${data}`);
|
||||
|
||||
try {
|
||||
obj = JSON.parse(data);
|
||||
} catch (e) {
|
||||
logger.logError('Error parsing reply from remote side');
|
||||
reject(e);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (obj.type) {
|
||||
case 'error':
|
||||
reject(new Error(`Remote error: ${obj.error}`));
|
||||
break;
|
||||
case 'success':
|
||||
resolve(obj);
|
||||
break;
|
||||
case 'status':
|
||||
logger.logInfo(obj.message);
|
||||
break;
|
||||
default:
|
||||
reject(new Error(`Received unexpected reply from remote: ${data}`));
|
||||
}
|
||||
};
|
||||
|
||||
uploadRequest.on('error', reject).on('data', handleMessage);
|
||||
});
|
||||
|
||||
const uploadImage = function(
|
||||
imageStream,
|
||||
token,
|
||||
username,
|
||||
url,
|
||||
appName,
|
||||
logger,
|
||||
) {
|
||||
const request = require('request');
|
||||
const progressStream = require('progress-stream');
|
||||
const zlib = require('zlib');
|
||||
|
||||
// Need to strip off the newline
|
||||
const progressMessage = logger
|
||||
.formatMessage('info', 'Uploading')
|
||||
.slice(0, -1);
|
||||
const progressBar = showPushProgress(progressMessage);
|
||||
const streamWithProgress = imageStream.pipe(
|
||||
progressStream(
|
||||
{
|
||||
time: 500,
|
||||
length: imageStream.length,
|
||||
},
|
||||
({ percentage, eta }) =>
|
||||
progressBar.update({
|
||||
percentage: Math.min(percentage, 100),
|
||||
eta,
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
const uploadRequest = request.post({
|
||||
url: getBuilderPushEndpoint(url, username, appName),
|
||||
headers: {
|
||||
'Content-Encoding': 'gzip',
|
||||
},
|
||||
auth: {
|
||||
bearer: token,
|
||||
},
|
||||
body: streamWithProgress.pipe(
|
||||
zlib.createGzip({
|
||||
level: 6,
|
||||
}),
|
||||
),
|
||||
});
|
||||
|
||||
return uploadToPromise(uploadRequest, logger);
|
||||
};
|
||||
|
||||
const uploadLogs = function(logs, token, url, buildId, username, appName) {
|
||||
const request = require('request');
|
||||
return request.post({
|
||||
json: true,
|
||||
url: getBuilderLogPushEndpoint(url, buildId, username, appName),
|
||||
auth: {
|
||||
bearer: token,
|
||||
},
|
||||
body: Buffer.from(logs),
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
opts must be a hash with the following keys:
|
||||
|
||||
- appName: the name of the app to deploy to
|
||||
- imageName: the name of the image to deploy
|
||||
- buildLogs: a string with build output
|
||||
- shouldUploadLogs
|
||||
*/
|
||||
export const deployLegacy = function(
|
||||
docker,
|
||||
logger,
|
||||
token,
|
||||
username,
|
||||
url,
|
||||
opts,
|
||||
) {
|
||||
const tmp = require('tmp');
|
||||
const tmpNameAsync = Promise.promisify(tmp.tmpName);
|
||||
|
||||
// Ensure the tmp files gets deleted
|
||||
tmp.setGracefulCleanup();
|
||||
|
||||
const { appName, imageName, buildLogs, shouldUploadLogs } = opts;
|
||||
const logs = buildLogs;
|
||||
|
||||
return tmpNameAsync()
|
||||
.then(function(bufferFile) {
|
||||
logger.logInfo('Initializing deploy...');
|
||||
return bufferImage(docker, imageName, bufferFile)
|
||||
.then(stream =>
|
||||
uploadImage(stream, token, username, url, appName, logger),
|
||||
)
|
||||
.finally(() =>
|
||||
// If the file was never written to (for instance because an error
|
||||
// has occured before any data was written) this call will throw an
|
||||
// ugly error, just suppress it
|
||||
Promise.try(() => require('mz/fs').unlink(bufferFile)).catchReturn(
|
||||
undefined,
|
||||
),
|
||||
);
|
||||
})
|
||||
.tap(function({ buildId }) {
|
||||
if (!shouldUploadLogs) {
|
||||
return;
|
||||
}
|
||||
|
||||
logger.logInfo('Uploading logs...');
|
||||
return Promise.join(
|
||||
logs,
|
||||
token,
|
||||
url,
|
||||
buildId,
|
||||
username,
|
||||
appName,
|
||||
uploadLogs,
|
||||
);
|
||||
})
|
||||
.get('buildId');
|
||||
};
|
9
npm-shrinkwrap.json
generated
9
npm-shrinkwrap.json
generated
@ -1217,6 +1217,15 @@
|
||||
"integrity": "sha512-Zu4jAKE46yc6R8JrVkCBWbXhs18dUgI/JlbID4jziFgUBgEdAHxFekR5TlEnk9phHdGE80QlCznRBaxlk0rl7w==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/progress-stream": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/progress-stream/-/progress-stream-2.0.0.tgz",
|
||||
"integrity": "sha512-KKboL4BvIezEvnd2bdbIfIIkr3Th1p0AJOBaPdKMWm69uMoisOGd4mynzfB/iia2z0k3nwAJCmixESHfVjsrgw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/range-parser": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz",
|
||||
|
@ -129,6 +129,7 @@
|
||||
"@types/node": "^10.17.20",
|
||||
"@types/node-cleanup": "^2.1.1",
|
||||
"@types/prettyjson": "0.0.29",
|
||||
"@types/progress-stream": "^2.0.0",
|
||||
"@types/request": "^2.48.4",
|
||||
"@types/rewire": "^2.5.28",
|
||||
"@types/rimraf": "^2.0.4",
|
||||
|
Loading…
Reference in New Issue
Block a user