2020-04-06 08:53:34 +00:00
|
|
|
import * as Bluebird from 'bluebird';
|
|
|
|
import * as Docker from 'dockerode';
|
|
|
|
import { Dockerfile } from 'livepush';
|
|
|
|
|
|
|
|
import * as device from './device';
|
|
|
|
|
|
|
|
interface Opts {
|
|
|
|
address: string;
|
|
|
|
imageName: string;
|
|
|
|
imageTag: string;
|
|
|
|
docker: Docker;
|
|
|
|
dockerfile: Dockerfile;
|
|
|
|
nocache: boolean;
|
|
|
|
arch?: string;
|
|
|
|
}
|
|
|
|
|
2022-07-06 19:51:49 +00:00
|
|
|
// Source: https://github.com/balena-io/balena-cli/blob/f6d668684a6f5ea8102a964ca1942b242eaa7ae2/lib/utils/device/live.ts#L539-L547
|
|
|
|
function extractDockerArrowMessage(outputLine: string): string | undefined {
|
|
|
|
const arrowTest = /^.*\s*-+>\s*(.+)/i;
|
|
|
|
const match = arrowTest.exec(outputLine);
|
|
|
|
if (match != null) {
|
|
|
|
return match[1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Source: https://github.com/balena-io/balena-cli/blob/f6d668684a6f5ea8102a964ca1942b242eaa7ae2/lib/utils/device/live.ts#L300-L325
|
|
|
|
function getMultiStateImageIDs(buildLog: string): string[] {
|
|
|
|
const ids = [] as string[];
|
|
|
|
const lines = buildLog.split(/\r?\n/);
|
|
|
|
let lastArrowMessage: string | undefined;
|
|
|
|
for (const line of lines) {
|
|
|
|
// If this was a from line, take the last found
|
|
|
|
// image id and save it
|
|
|
|
if (
|
|
|
|
/step \d+(?:\/\d+)?\s*:\s*FROM/i.test(line) &&
|
|
|
|
lastArrowMessage != null
|
|
|
|
) {
|
|
|
|
ids.push(lastArrowMessage);
|
|
|
|
} else {
|
|
|
|
const msg = extractDockerArrowMessage(line);
|
|
|
|
if (msg != null) {
|
|
|
|
lastArrowMessage = msg;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ids;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getPathPrefix(arch: string) {
|
|
|
|
switch (arch) {
|
|
|
|
/**
|
|
|
|
* Proper paths are
|
|
|
|
* - armv6 - arm32v6
|
|
|
|
* - armv7hf - arm32v7
|
|
|
|
* - aarch64 - arm64v8
|
|
|
|
* - amd64 - amd64
|
|
|
|
* - i386 - i386
|
|
|
|
*
|
|
|
|
* We only set the prefix for v6 images since rpi devices are
|
|
|
|
* the only ones that seem to have the issue
|
|
|
|
* https://github.com/balena-os/balena-engine/issues/269
|
|
|
|
*/
|
|
|
|
case 'rpi':
|
|
|
|
return 'arm32v6';
|
|
|
|
default:
|
|
|
|
return 'library';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-06 08:53:34 +00:00
|
|
|
export async function initDevice(opts: Opts) {
|
|
|
|
const arch = opts.arch ?? (await device.getDeviceArch(opts.docker));
|
2022-07-06 19:51:49 +00:00
|
|
|
const image = `${opts.imageName}:${opts.imageTag}`;
|
2020-04-06 08:53:34 +00:00
|
|
|
|
2022-07-06 19:51:49 +00:00
|
|
|
const buildCache = await device.readBuildCache(opts.address);
|
|
|
|
|
|
|
|
const buildLog = await device.performBuild(opts.docker, opts.dockerfile, {
|
|
|
|
buildargs: { ARCH: arch, PREFIX: getPathPrefix(arch) },
|
2020-04-06 08:53:34 +00:00
|
|
|
t: image,
|
|
|
|
labels: { 'io.balena.livepush-image': '1', 'io.balena.architecture': arch },
|
2022-07-06 19:51:49 +00:00
|
|
|
cachefrom: (await device.getCacheFrom(opts.docker))
|
|
|
|
.concat(image)
|
|
|
|
.concat(buildCache),
|
2020-04-06 08:53:34 +00:00
|
|
|
nocache: opts.nocache,
|
|
|
|
});
|
|
|
|
|
2022-07-06 19:51:49 +00:00
|
|
|
const stageImages = getMultiStateImageIDs(buildLog);
|
|
|
|
|
|
|
|
// Store the list of stage images for the next time the sync
|
|
|
|
// command is called. This will only live until the device is rebooted
|
|
|
|
await device.writeBuildCache(opts.address, stageImages);
|
|
|
|
|
2020-04-06 08:53:34 +00:00
|
|
|
// Now that we have our new image on the device, we need
|
|
|
|
// to stop the supervisor, update
|
|
|
|
// /tmp/update-supervisor.conf with our version, and
|
|
|
|
// restart the supervisor
|
|
|
|
await device.stopSupervisor(opts.address);
|
2022-07-06 19:51:49 +00:00
|
|
|
await device.replaceSupervisorImage(
|
|
|
|
opts.address,
|
|
|
|
opts.imageName,
|
|
|
|
opts.imageTag,
|
|
|
|
);
|
2020-04-06 08:53:34 +00:00
|
|
|
await device.startSupervisor(opts.address);
|
|
|
|
|
|
|
|
let supervisorContainer: undefined | Docker.ContainerInfo;
|
|
|
|
while (supervisorContainer == null) {
|
|
|
|
try {
|
|
|
|
supervisorContainer = await device.getSupervisorContainer(
|
|
|
|
opts.docker,
|
|
|
|
true,
|
|
|
|
);
|
2022-09-19 15:08:16 +00:00
|
|
|
} catch {
|
2020-04-06 08:53:34 +00:00
|
|
|
await Bluebird.delay(500);
|
|
|
|
}
|
|
|
|
}
|
2022-07-06 19:51:49 +00:00
|
|
|
return { containerId: supervisorContainer.Id, stageImages };
|
2020-04-06 08:53:34 +00:00
|
|
|
}
|