2023-02-27 09:10:57 +01:00
|
|
|
/**
|
|
|
|
|
* Copyright 2023 actions-toolkit authors
|
|
|
|
|
*
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
|
|
|
|
|
2023-03-02 13:48:24 +01:00
|
|
|
import * as child_process from 'child_process';
|
2023-02-27 09:10:57 +01:00
|
|
|
import fs from 'fs';
|
|
|
|
|
import os from 'os';
|
|
|
|
|
import path from 'path';
|
2023-03-02 13:48:24 +01:00
|
|
|
import retry from 'async-retry';
|
2023-08-27 12:23:24 +02:00
|
|
|
import yaml from 'js-yaml';
|
2023-02-27 09:59:45 +01:00
|
|
|
import * as handlebars from 'handlebars';
|
|
|
|
|
import * as util from 'util';
|
2023-02-27 09:10:57 +01:00
|
|
|
import * as core from '@actions/core';
|
2023-03-03 14:01:57 +01:00
|
|
|
import * as httpm from '@actions/http-client';
|
2023-02-27 09:10:57 +01:00
|
|
|
import * as io from '@actions/io';
|
|
|
|
|
import * as tc from '@actions/tool-cache';
|
|
|
|
|
|
2023-03-03 10:40:00 +01:00
|
|
|
import {Context} from '../context';
|
2023-02-27 09:10:57 +01:00
|
|
|
import {Exec} from '../exec';
|
|
|
|
|
import {Util} from '../util';
|
2023-08-27 12:23:24 +02:00
|
|
|
import {colimaYamlData, dockerServiceLogsPs1, qemuEntitlements, setupDockerWinPs1} from './assets';
|
2023-03-03 14:01:57 +01:00
|
|
|
import {GitHubRelease} from '../types/github';
|
2023-02-27 09:10:57 +01:00
|
|
|
|
2023-03-03 10:40:00 +01:00
|
|
|
export interface InstallOpts {
|
2023-03-03 14:01:57 +01:00
|
|
|
version?: string;
|
2023-03-03 10:40:00 +01:00
|
|
|
channel?: string;
|
|
|
|
|
runDir: string;
|
|
|
|
|
contextName?: string;
|
2023-08-27 12:23:24 +02:00
|
|
|
daemonConfig?: string;
|
2023-03-03 10:40:00 +01:00
|
|
|
}
|
|
|
|
|
|
2023-02-27 09:10:57 +01:00
|
|
|
export class Install {
|
2023-03-03 14:01:57 +01:00
|
|
|
private readonly runDir: string;
|
2023-03-03 10:40:00 +01:00
|
|
|
private readonly version: string;
|
|
|
|
|
private readonly channel: string;
|
|
|
|
|
private readonly contextName: string;
|
2023-08-27 12:23:24 +02:00
|
|
|
private readonly daemonConfig?: string;
|
2023-03-03 14:01:57 +01:00
|
|
|
private _version: string | undefined;
|
2023-03-03 10:40:00 +01:00
|
|
|
private _toolDir: string | undefined;
|
|
|
|
|
|
|
|
|
|
constructor(opts: InstallOpts) {
|
|
|
|
|
this.runDir = opts.runDir;
|
2023-03-03 14:01:57 +01:00
|
|
|
this.version = opts.version || 'latest';
|
|
|
|
|
this.channel = opts.channel || 'stable';
|
2023-03-03 10:40:00 +01:00
|
|
|
this.contextName = opts.contextName || 'setup-docker-action';
|
2023-08-27 12:23:24 +02:00
|
|
|
this.daemonConfig = opts.daemonConfig;
|
2023-03-03 10:40:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
get toolDir(): string {
|
|
|
|
|
return this._toolDir || Context.tmpDir();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async download(): Promise<string> {
|
2023-03-03 14:01:57 +01:00
|
|
|
const release: GitHubRelease = await Install.getRelease(this.version);
|
|
|
|
|
this._version = release.tag_name.replace(/^v+|v+$/g, '');
|
|
|
|
|
core.debug(`docker.Install.download version: ${this._version}`);
|
2023-02-27 09:10:57 +01:00
|
|
|
|
2023-03-03 14:01:57 +01:00
|
|
|
const downloadURL = this.downloadURL(this._version, this.channel);
|
2023-02-27 09:10:57 +01:00
|
|
|
core.info(`Downloading ${downloadURL}`);
|
2023-03-03 14:01:57 +01:00
|
|
|
|
2023-02-27 09:10:57 +01:00
|
|
|
const downloadPath = await tc.downloadTool(downloadURL);
|
|
|
|
|
core.debug(`docker.Install.download downloadPath: ${downloadPath}`);
|
|
|
|
|
|
|
|
|
|
let extractFolder: string;
|
|
|
|
|
if (os.platform() == 'win32') {
|
|
|
|
|
extractFolder = await tc.extractZip(downloadPath);
|
|
|
|
|
} else {
|
2023-02-28 20:15:33 +01:00
|
|
|
extractFolder = await tc.extractTar(downloadPath);
|
2023-02-27 09:10:57 +01:00
|
|
|
}
|
|
|
|
|
if (Util.isDirectory(path.join(extractFolder, 'docker'))) {
|
|
|
|
|
extractFolder = path.join(extractFolder, 'docker');
|
|
|
|
|
}
|
|
|
|
|
core.debug(`docker.Install.download extractFolder: ${extractFolder}`);
|
|
|
|
|
|
|
|
|
|
core.info('Fixing perms');
|
|
|
|
|
fs.readdir(path.join(extractFolder), function (err, files) {
|
|
|
|
|
if (err) {
|
|
|
|
|
throw err;
|
|
|
|
|
}
|
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
|
|
|
files.forEach(function (file, index) {
|
|
|
|
|
fs.chmodSync(path.join(extractFolder, file), '0755');
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2023-03-03 14:01:57 +01:00
|
|
|
const tooldir = await tc.cacheDir(extractFolder, `docker-${this.channel}`, this._version.replace(/(0+)([1-9]+)/, '$2'));
|
2023-02-27 09:10:57 +01:00
|
|
|
core.addPath(tooldir);
|
|
|
|
|
core.info('Added Docker to PATH');
|
2023-03-03 10:40:00 +01:00
|
|
|
|
|
|
|
|
this._toolDir = tooldir;
|
2023-02-27 09:10:57 +01:00
|
|
|
return tooldir;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-03 10:40:00 +01:00
|
|
|
public async install(): Promise<void> {
|
|
|
|
|
if (!this.toolDir) {
|
|
|
|
|
throw new Error('toolDir must be set. Run download first.');
|
2023-03-02 11:01:19 +01:00
|
|
|
}
|
2023-03-03 10:40:00 +01:00
|
|
|
if (!this.runDir) {
|
2023-03-02 11:01:19 +01:00
|
|
|
throw new Error('runDir must be set');
|
|
|
|
|
}
|
2023-02-27 09:10:57 +01:00
|
|
|
switch (os.platform()) {
|
|
|
|
|
case 'darwin': {
|
2023-03-03 10:40:00 +01:00
|
|
|
await this.installDarwin();
|
2023-02-27 09:10:57 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 'linux': {
|
2023-03-03 10:40:00 +01:00
|
|
|
await this.installLinux();
|
2023-02-27 09:10:57 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 'win32': {
|
2023-03-03 10:40:00 +01:00
|
|
|
await this.installWindows();
|
2023-02-27 09:10:57 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default: {
|
|
|
|
|
throw new Error(`Unsupported platform: ${os.platform()}`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-03 10:40:00 +01:00
|
|
|
private async installDarwin(): Promise<void> {
|
2023-02-28 20:15:33 +01:00
|
|
|
const colimaDir = path.join(os.homedir(), '.colima', 'default'); // TODO: create a custom colima profile to avoid overlap with other actions
|
2023-02-27 09:59:45 +01:00
|
|
|
await io.mkdirP(colimaDir);
|
|
|
|
|
const dockerHost = `unix://${colimaDir}/docker.sock`;
|
|
|
|
|
|
2023-02-27 09:10:57 +01:00
|
|
|
if (!(await Install.colimaInstalled())) {
|
|
|
|
|
await core.group('Installing colima', async () => {
|
|
|
|
|
await Exec.exec('brew', ['install', 'colima']);
|
|
|
|
|
});
|
|
|
|
|
}
|
2023-02-27 09:59:45 +01:00
|
|
|
|
|
|
|
|
await core.group('Creating colima config', async () => {
|
2023-08-28 02:44:20 +02:00
|
|
|
let colimaDaemonConfig = {};
|
2023-08-27 12:23:24 +02:00
|
|
|
if (this.daemonConfig) {
|
2023-08-28 02:44:20 +02:00
|
|
|
colimaDaemonConfig = JSON.parse(this.daemonConfig);
|
2023-08-27 12:23:24 +02:00
|
|
|
}
|
2023-03-02 11:01:19 +01:00
|
|
|
const colimaCfg = handlebars.compile(colimaYamlData)({
|
2023-08-28 02:44:20 +02:00
|
|
|
daemonConfig: yaml.dump(yaml.load(JSON.stringify({docker: colimaDaemonConfig}))),
|
|
|
|
|
dockerBinVersion: this._version,
|
|
|
|
|
dockerBinChannel: this.channel,
|
|
|
|
|
dockerBinArch: Install.platformArch()
|
2023-02-27 09:59:45 +01:00
|
|
|
});
|
|
|
|
|
core.info(`Writing colima config to ${path.join(colimaDir, 'colima.yaml')}`);
|
|
|
|
|
fs.writeFileSync(path.join(colimaDir, 'colima.yaml'), colimaCfg);
|
|
|
|
|
core.info(colimaCfg);
|
|
|
|
|
});
|
|
|
|
|
|
2023-08-26 09:58:59 +02:00
|
|
|
const qemuArch = await Install.qemuArch();
|
|
|
|
|
await core.group('QEMU version', async () => {
|
|
|
|
|
await Exec.exec(`qemu-system-${qemuArch} --version`);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// https://github.com/abiosoft/colima/issues/786#issuecomment-1693629650
|
|
|
|
|
if (process.env.SIGN_QEMU_BINARY === '1') {
|
|
|
|
|
await core.group('Signing QEMU binary with entitlements', async () => {
|
|
|
|
|
const qemuEntitlementsFile = path.join(Context.tmpDir(), 'qemu-entitlements.xml');
|
|
|
|
|
core.info(`Writing entitlements to ${qemuEntitlementsFile}`);
|
|
|
|
|
fs.writeFileSync(qemuEntitlementsFile, qemuEntitlements);
|
|
|
|
|
await Exec.exec(`codesign --sign - --entitlements ${qemuEntitlementsFile} --force /usr/local/bin/qemu-system-${qemuArch}`);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-27 09:10:57 +01:00
|
|
|
// colima is already started on the runner so env var added in download
|
|
|
|
|
// method is not expanded to the running process.
|
|
|
|
|
const envs = Object.assign({}, process.env, {
|
2023-03-03 10:40:00 +01:00
|
|
|
PATH: `${this.toolDir}:${process.env.PATH}`
|
2023-02-27 09:10:57 +01:00
|
|
|
}) as {
|
|
|
|
|
[key: string]: string;
|
|
|
|
|
};
|
2023-08-26 09:58:59 +02:00
|
|
|
|
2023-02-27 09:10:57 +01:00
|
|
|
await core.group('Starting colima', async () => {
|
2023-08-28 02:44:20 +02:00
|
|
|
const colimaStartArgs = ['start', '--very-verbose'];
|
|
|
|
|
if (process.env.COLIMA_START_ARGS) {
|
|
|
|
|
colimaStartArgs.push(process.env.COLIMA_START_ARGS);
|
|
|
|
|
}
|
2023-08-26 08:51:46 +02:00
|
|
|
try {
|
2023-08-28 02:44:20 +02:00
|
|
|
await Exec.exec(`colima ${colimaStartArgs.join(' ')}`, [], {env: envs});
|
2023-08-26 08:51:46 +02:00
|
|
|
} catch (e) {
|
|
|
|
|
const haStderrLog = path.join(os.homedir(), '.lima', 'colima', 'ha.stderr.log');
|
|
|
|
|
if (fs.existsSync(haStderrLog)) {
|
|
|
|
|
core.info(`Printing debug logs (${haStderrLog}):\n${fs.readFileSync(haStderrLog, {encoding: 'utf8'})}`);
|
|
|
|
|
}
|
|
|
|
|
throw e;
|
|
|
|
|
}
|
2023-02-27 09:59:45 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await core.group('Create Docker context', async () => {
|
2023-03-03 10:40:00 +01:00
|
|
|
await Exec.exec('docker', ['context', 'create', this.contextName, '--docker', `host=${dockerHost}`]);
|
|
|
|
|
await Exec.exec('docker', ['context', 'use', this.contextName]);
|
2023-02-27 09:10:57 +01:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-03 10:40:00 +01:00
|
|
|
private async installLinux(): Promise<void> {
|
|
|
|
|
const dockerHost = `unix://${path.join(this.runDir, 'docker.sock')}`;
|
|
|
|
|
await io.mkdirP(this.runDir);
|
2023-02-28 20:05:08 +01:00
|
|
|
|
2023-08-27 12:23:24 +02:00
|
|
|
const daemonConfigPath = path.join(this.runDir, 'daemon.json');
|
|
|
|
|
await fs.writeFileSync(daemonConfigPath, '{}');
|
|
|
|
|
|
|
|
|
|
let daemonConfig = undefined;
|
|
|
|
|
const daemonConfigDefaultPath = '/etc/docker/daemon.json';
|
|
|
|
|
if (fs.existsSync(daemonConfigDefaultPath)) {
|
|
|
|
|
await core.group('Default Docker daemon config found', async () => {
|
|
|
|
|
core.info(JSON.stringify(JSON.parse(fs.readFileSync(daemonConfigDefaultPath, {encoding: 'utf8'})), null, 2));
|
|
|
|
|
});
|
|
|
|
|
daemonConfig = JSON.parse(fs.readFileSync(daemonConfigDefaultPath, {encoding: 'utf8'}));
|
|
|
|
|
}
|
|
|
|
|
if (this.daemonConfig) {
|
|
|
|
|
daemonConfig = Object.assign(daemonConfig || {}, JSON.parse(this.daemonConfig));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (daemonConfig) {
|
|
|
|
|
const daemonConfigStr = JSON.stringify(daemonConfig, null, 2);
|
|
|
|
|
await core.group('Writing Docker daemon config', async () => {
|
|
|
|
|
fs.writeFileSync(daemonConfigPath, daemonConfigStr);
|
|
|
|
|
core.info(daemonConfigStr);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-02 13:48:24 +01:00
|
|
|
await core.group('Start Docker daemon', async () => {
|
2023-02-28 20:05:08 +01:00
|
|
|
const bashPath: string = await io.which('bash', true);
|
2023-08-27 12:23:24 +02:00
|
|
|
const cmd = `${this.toolDir}/dockerd --host="${dockerHost}" --config-file="${daemonConfigPath}" --exec-root="${this.runDir}/execroot" --data-root="${this.runDir}/data" --pidfile="${this.runDir}/docker.pid" --userland-proxy=false`;
|
|
|
|
|
core.info(`[command] ${cmd}`); // https://github.com/actions/toolkit/blob/3d652d3133965f63309e4b2e1c8852cdbdcb3833/packages/exec/src/toolrunner.ts#L47
|
|
|
|
|
const proc = await child_process.spawn(
|
|
|
|
|
// We can't use Exec.exec here because we need to detach the process to
|
|
|
|
|
// avoid killing it when the action finishes running. Even if detached,
|
|
|
|
|
// we also need to run dockerd in a subshell and unref the process so
|
|
|
|
|
// GitHub Action doesn't wait for it to finish.
|
|
|
|
|
`sudo -E ${bashPath} << EOF
|
|
|
|
|
( ${cmd} 2>&1 | tee "${this.runDir}/dockerd.log" ) &
|
|
|
|
|
EOF`,
|
|
|
|
|
[],
|
|
|
|
|
{
|
|
|
|
|
detached: true,
|
|
|
|
|
shell: true,
|
|
|
|
|
stdio: ['ignore', process.stdout, process.stderr]
|
2023-02-28 20:05:08 +01:00
|
|
|
}
|
2023-08-27 12:23:24 +02:00
|
|
|
);
|
2023-03-02 13:48:24 +01:00
|
|
|
proc.unref();
|
2023-08-27 12:23:24 +02:00
|
|
|
await Util.sleep(3);
|
|
|
|
|
const retries = 10;
|
2023-03-02 13:48:24 +01:00
|
|
|
await retry(
|
|
|
|
|
async bail => {
|
2023-08-27 12:23:24 +02:00
|
|
|
try {
|
|
|
|
|
await Exec.getExecOutput(`docker version`, undefined, {
|
|
|
|
|
silent: true,
|
|
|
|
|
env: Object.assign({}, process.env, {
|
|
|
|
|
DOCKER_HOST: dockerHost
|
|
|
|
|
}) as {
|
|
|
|
|
[key: string]: string;
|
2023-03-02 13:48:24 +01:00
|
|
|
}
|
|
|
|
|
});
|
2023-08-27 12:23:24 +02:00
|
|
|
} catch (e) {
|
|
|
|
|
bail(e);
|
|
|
|
|
}
|
2023-03-02 13:48:24 +01:00
|
|
|
},
|
|
|
|
|
{
|
2023-08-26 10:05:39 +02:00
|
|
|
retries: retries,
|
|
|
|
|
minTimeout: 1000,
|
|
|
|
|
onRetry: (err, i) => {
|
|
|
|
|
core.info(`${err}. Retrying (${i}/${retries})...`);
|
|
|
|
|
}
|
2023-03-02 13:48:24 +01:00
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
core.info(`Docker daemon started started successfully`);
|
2023-02-28 20:05:08 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await core.group('Create Docker context', async () => {
|
2023-03-03 10:40:00 +01:00
|
|
|
await Exec.exec('docker', ['context', 'create', this.contextName, '--docker', `host=${dockerHost}`]);
|
|
|
|
|
await Exec.exec('docker', ['context', 'use', this.contextName]);
|
2023-02-28 20:05:08 +01:00
|
|
|
});
|
2023-02-27 09:10:57 +01:00
|
|
|
}
|
|
|
|
|
|
2023-03-03 10:40:00 +01:00
|
|
|
private async installWindows(): Promise<void> {
|
2023-02-27 09:10:57 +01:00
|
|
|
const dockerHost = 'npipe:////./pipe/setup_docker_action';
|
2023-02-27 09:59:45 +01:00
|
|
|
|
2023-08-27 12:23:24 +02:00
|
|
|
let daemonConfig = undefined;
|
|
|
|
|
const daemonConfigPath = path.join(this.runDir, 'daemon.json');
|
|
|
|
|
if (fs.existsSync(daemonConfigPath)) {
|
|
|
|
|
await core.group('Default Docker daemon config found', async () => {
|
|
|
|
|
core.info(JSON.stringify(JSON.parse(fs.readFileSync(daemonConfigPath, {encoding: 'utf8'})), null, 2));
|
|
|
|
|
});
|
|
|
|
|
daemonConfig = JSON.parse(fs.readFileSync(daemonConfigPath, {encoding: 'utf8'}));
|
|
|
|
|
}
|
|
|
|
|
if (this.daemonConfig) {
|
|
|
|
|
daemonConfig = Object.assign(daemonConfig || {}, JSON.parse(this.daemonConfig));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let daemonConfigStr = '{}';
|
|
|
|
|
if (daemonConfig) {
|
|
|
|
|
daemonConfigStr = JSON.stringify(daemonConfig, null, 2);
|
|
|
|
|
await core.group('Docker daemon config', async () => {
|
|
|
|
|
core.info(daemonConfigStr);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-27 09:10:57 +01:00
|
|
|
await core.group('Install Docker daemon service', async () => {
|
2023-03-02 15:25:29 +01:00
|
|
|
const setupCmd = await Util.powershellCommand(setupDockerWinPs1(), {
|
2023-03-03 10:40:00 +01:00
|
|
|
ToolDir: this.toolDir,
|
|
|
|
|
RunDir: this.runDir,
|
2023-08-27 12:23:24 +02:00
|
|
|
DockerHost: dockerHost,
|
|
|
|
|
DaemonConfig: daemonConfigStr
|
2023-03-02 15:25:29 +01:00
|
|
|
});
|
2023-02-27 09:10:57 +01:00
|
|
|
await Exec.exec(setupCmd.command, setupCmd.args);
|
2023-03-02 15:25:29 +01:00
|
|
|
const logCmd = await Util.powershellCommand(dockerServiceLogsPs1());
|
|
|
|
|
await Exec.exec(logCmd.command, logCmd.args);
|
2023-02-27 09:10:57 +01:00
|
|
|
});
|
2023-02-27 09:59:45 +01:00
|
|
|
|
2023-02-27 09:10:57 +01:00
|
|
|
await core.group('Create Docker context', async () => {
|
2023-03-03 10:40:00 +01:00
|
|
|
await Exec.exec('docker', ['context', 'create', this.contextName, '--docker', `host=${dockerHost}`]);
|
|
|
|
|
await Exec.exec('docker', ['context', 'use', this.contextName]);
|
2023-02-27 09:10:57 +01:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-03 10:40:00 +01:00
|
|
|
public async tearDown(): Promise<void> {
|
|
|
|
|
if (!this.runDir) {
|
|
|
|
|
throw new Error('runDir must be set');
|
|
|
|
|
}
|
2023-03-02 15:25:29 +01:00
|
|
|
switch (os.platform()) {
|
|
|
|
|
case 'darwin': {
|
2023-03-03 10:40:00 +01:00
|
|
|
await this.tearDownDarwin();
|
2023-03-02 15:25:29 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 'linux': {
|
2023-03-03 10:40:00 +01:00
|
|
|
await this.tearDownLinux();
|
2023-03-02 15:25:29 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 'win32': {
|
|
|
|
|
await this.tearDownWindows();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default: {
|
|
|
|
|
throw new Error(`Unsupported platform: ${os.platform()}`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-03 10:40:00 +01:00
|
|
|
private async tearDownDarwin(): Promise<void> {
|
2023-03-02 15:25:29 +01:00
|
|
|
await core.group('Docker daemon logs', async () => {
|
|
|
|
|
await Exec.exec('colima', ['exec', '--', 'cat', '/var/log/docker.log']);
|
|
|
|
|
});
|
|
|
|
|
await core.group('Stopping colima', async () => {
|
|
|
|
|
await Exec.exec('colima', ['stop', '--very-verbose']);
|
|
|
|
|
});
|
|
|
|
|
await core.group('Removing Docker context', async () => {
|
2023-03-03 10:40:00 +01:00
|
|
|
await Exec.exec('docker', ['context', 'rm', '-f', this.contextName]);
|
2023-03-02 15:25:29 +01:00
|
|
|
});
|
|
|
|
|
await core.group(`Cleaning up runDir`, async () => {
|
2023-03-03 10:40:00 +01:00
|
|
|
await Exec.exec('sudo', ['rm', '-rf', this.runDir]);
|
2023-03-02 15:25:29 +01:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-03 10:40:00 +01:00
|
|
|
private async tearDownLinux(): Promise<void> {
|
2023-03-02 15:25:29 +01:00
|
|
|
await core.group('Docker daemon logs', async () => {
|
2023-03-03 10:40:00 +01:00
|
|
|
core.info(fs.readFileSync(path.join(this.runDir, 'dockerd.log'), {encoding: 'utf8'}));
|
2023-03-02 15:25:29 +01:00
|
|
|
});
|
|
|
|
|
await core.group('Stopping Docker daemon', async () => {
|
2023-08-26 12:15:25 +02:00
|
|
|
await Exec.exec('sudo', ['kill', '-s', 'SIGTERM', fs.readFileSync(path.join(this.runDir, 'docker.pid')).toString().trim()]);
|
|
|
|
|
await Util.sleep(5);
|
2023-03-02 15:25:29 +01:00
|
|
|
});
|
|
|
|
|
await core.group('Removing Docker context', async () => {
|
2023-03-03 10:40:00 +01:00
|
|
|
await Exec.exec('docker', ['context', 'rm', '-f', this.contextName]);
|
2023-03-02 15:25:29 +01:00
|
|
|
});
|
|
|
|
|
await core.group(`Cleaning up runDir`, async () => {
|
2023-08-26 12:15:25 +02:00
|
|
|
await Exec.exec('sudo', ['rm', '-rf', this.runDir], {
|
|
|
|
|
ignoreReturnCode: true,
|
|
|
|
|
failOnStdErr: false
|
|
|
|
|
});
|
2023-03-02 15:25:29 +01:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async tearDownWindows(): Promise<void> {
|
|
|
|
|
await core.group('Docker daemon logs', async () => {
|
|
|
|
|
const logCmd = await Util.powershellCommand(dockerServiceLogsPs1());
|
|
|
|
|
await Exec.exec(logCmd.command, logCmd.args);
|
|
|
|
|
});
|
|
|
|
|
await core.group('Removing Docker context', async () => {
|
2023-03-03 10:40:00 +01:00
|
|
|
await Exec.exec('docker', ['context', 'rm', '-f', this.contextName]);
|
2023-03-02 15:25:29 +01:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-27 09:10:57 +01:00
|
|
|
private downloadURL(version: string, channel: string): string {
|
2023-02-27 09:59:45 +01:00
|
|
|
const platformOS = Install.platformOS();
|
|
|
|
|
const platformArch = Install.platformArch();
|
|
|
|
|
const ext = platformOS === 'win' ? '.zip' : '.tgz';
|
|
|
|
|
return util.format('https://download.docker.com/%s/static/%s/%s/docker-%s%s', platformOS, channel, platformArch, version, ext);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static platformOS(): string {
|
2023-02-27 09:10:57 +01:00
|
|
|
switch (os.platform()) {
|
|
|
|
|
case 'darwin': {
|
2023-02-27 09:59:45 +01:00
|
|
|
return 'mac';
|
2023-02-27 09:10:57 +01:00
|
|
|
}
|
|
|
|
|
case 'linux': {
|
2023-02-27 09:59:45 +01:00
|
|
|
return 'linux';
|
2023-02-27 09:10:57 +01:00
|
|
|
}
|
|
|
|
|
case 'win32': {
|
2023-02-27 09:59:45 +01:00
|
|
|
return 'win';
|
2023-02-27 09:10:57 +01:00
|
|
|
}
|
|
|
|
|
default: {
|
2023-02-27 09:59:45 +01:00
|
|
|
return os.platform();
|
2023-02-27 09:10:57 +01:00
|
|
|
}
|
|
|
|
|
}
|
2023-02-27 09:59:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static platformArch(): string {
|
2023-02-27 09:10:57 +01:00
|
|
|
switch (os.arch()) {
|
|
|
|
|
case 'x64': {
|
2023-02-27 09:59:45 +01:00
|
|
|
return 'x86_64';
|
2023-02-27 09:10:57 +01:00
|
|
|
}
|
|
|
|
|
case 'ppc64': {
|
2023-02-27 09:59:45 +01:00
|
|
|
return 'ppc64le';
|
2023-02-27 09:10:57 +01:00
|
|
|
}
|
|
|
|
|
case 'arm': {
|
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
|
|
|
const arm_version = (process.config.variables as any).arm_version;
|
|
|
|
|
switch (arm_version) {
|
|
|
|
|
case 6: {
|
2023-02-27 09:59:45 +01:00
|
|
|
return 'armel';
|
2023-02-27 09:10:57 +01:00
|
|
|
}
|
|
|
|
|
case 7: {
|
2023-02-27 09:59:45 +01:00
|
|
|
return 'armhf';
|
2023-02-27 09:10:57 +01:00
|
|
|
}
|
|
|
|
|
default: {
|
2023-02-27 09:59:45 +01:00
|
|
|
return `v${arm_version}`;
|
2023-02-27 09:10:57 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
default: {
|
2023-02-27 09:59:45 +01:00
|
|
|
return os.arch();
|
2023-02-27 09:10:57 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static async colimaInstalled(): Promise<boolean> {
|
|
|
|
|
return await io
|
|
|
|
|
.which('colima', true)
|
|
|
|
|
.then(res => {
|
|
|
|
|
core.debug(`docker.Install.colimaAvailable ok: ${res}`);
|
|
|
|
|
return true;
|
|
|
|
|
})
|
|
|
|
|
.catch(error => {
|
|
|
|
|
core.debug(`docker.Install.colimaAvailable error: ${error}`);
|
|
|
|
|
return false;
|
|
|
|
|
});
|
|
|
|
|
}
|
2023-03-03 14:01:57 +01:00
|
|
|
|
2023-08-26 09:58:59 +02:00
|
|
|
private static async qemuArch(): Promise<string> {
|
|
|
|
|
switch (os.arch()) {
|
|
|
|
|
case 'x64': {
|
|
|
|
|
return 'x86_64';
|
|
|
|
|
}
|
|
|
|
|
case 'arm64': {
|
|
|
|
|
return 'aarch64';
|
|
|
|
|
}
|
|
|
|
|
default: {
|
|
|
|
|
return os.arch();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-03 14:01:57 +01:00
|
|
|
public static async getRelease(version: string): Promise<GitHubRelease> {
|
|
|
|
|
const url = `https://raw.githubusercontent.com/docker/actions-toolkit/main/.github/docker-releases.json`;
|
|
|
|
|
const http: httpm.HttpClient = new httpm.HttpClient('docker-actions-toolkit');
|
|
|
|
|
const resp: httpm.HttpClientResponse = await http.get(url);
|
|
|
|
|
const body = await resp.readBody();
|
|
|
|
|
const statusCode = resp.message.statusCode || 500;
|
|
|
|
|
if (statusCode >= 400) {
|
|
|
|
|
throw new Error(`Failed to get Docker release ${version} from ${url} with status code ${statusCode}: ${body}`);
|
|
|
|
|
}
|
|
|
|
|
const releases = <Record<string, GitHubRelease>>JSON.parse(body);
|
|
|
|
|
if (!releases[version]) {
|
|
|
|
|
throw new Error(`Cannot find Docker release ${version} in ${url}`);
|
|
|
|
|
}
|
|
|
|
|
return releases[version];
|
|
|
|
|
}
|
2023-02-27 09:10:57 +01:00
|
|
|
}
|