Merge pull request #62 from crazy-max/docker-custom-context

docker: allow custom context name on install
This commit is contained in:
CrazyMax
2023-03-03 14:00:23 +01:00
committed by GitHub
3 changed files with 85 additions and 50 deletions

View File

@@ -21,19 +21,23 @@ import {Install} from '../../src/docker/install';
import {Docker} from '../../src/docker/docker'; import {Docker} from '../../src/docker/docker';
// prettier-ignore // prettier-ignore
const tmpDir = path.join(process.env.TEMP || '/tmp', 'buildx-jest'); const tmpDir = path.join(process.env.TEMP || '/tmp', 'docker-install-jest');
describe('install', () => { describe('install', () => {
// prettier-ignore // prettier-ignore
test.each(['23.0.0'])( test.each(['23.0.0'])(
'install docker %s', async (version) => { 'install docker %s', async (version) => {
await expect((async () => { await expect((async () => {
const install = new Install(); const install = new Install({
const toolPath = await install.download(version); version: version,
await install.install(toolPath, tmpDir, version); runDir: tmpDir,
contextName: 'foo'
});
await install.download();
await install.install();
await Docker.printVersion(); await Docker.printVersion();
await Docker.printInfo(); await Docker.printInfo();
await install.tearDown(tmpDir); await install.tearDown();
})()).resolves.not.toThrow(); })()).resolves.not.toThrow();
}); });
}); });

View File

@@ -23,7 +23,7 @@ import osm = require('os');
import {Install} from '../../src/docker/install'; import {Install} from '../../src/docker/install';
// prettier-ignore // prettier-ignore
const tmpDir = path.join(process.env.TEMP || '/tmp', 'buildx-jest'); const tmpDir = path.join(process.env.TEMP || '/tmp', 'docker-install-jest');
beforeEach(() => { beforeEach(() => {
jest.clearAllMocks(); jest.clearAllMocks();
@@ -43,8 +43,11 @@ describe('download', () => {
])( ])(
'acquires %p of docker (%s)', async (version, platformOS) => { 'acquires %p of docker (%s)', async (version, platformOS) => {
jest.spyOn(osm, 'platform').mockImplementation(() => platformOS); jest.spyOn(osm, 'platform').mockImplementation(() => platformOS);
const install = new Install(); const install = new Install({
const toolPath = await install.download(version); version: version,
runDir: tmpDir,
});
const toolPath = await install.download();
expect(fs.existsSync(toolPath)).toBe(true); expect(fs.existsSync(toolPath)).toBe(true);
}, 100000); }, 100000);
}); });

View File

@@ -25,14 +25,38 @@ import * as core from '@actions/core';
import * as io from '@actions/io'; import * as io from '@actions/io';
import * as tc from '@actions/tool-cache'; import * as tc from '@actions/tool-cache';
import {Context} from '../context';
import {Exec} from '../exec'; import {Exec} from '../exec';
import {Util} from '../util'; import {Util} from '../util';
import {colimaYamlData, dockerServiceLogsPs1, setupDockerLinuxSh, setupDockerWinPs1} from './assets'; import {colimaYamlData, dockerServiceLogsPs1, setupDockerLinuxSh, setupDockerWinPs1} from './assets';
export interface InstallOpts {
version: string;
channel?: string;
runDir: string;
contextName?: string;
}
export class Install { export class Install {
public async download(version: string, channel?: string): Promise<string> { private readonly version: string;
channel = channel || 'stable'; private readonly channel: string;
const downloadURL = this.downloadURL(version, channel); private readonly runDir: string;
private readonly contextName: string;
private _toolDir: string | undefined;
constructor(opts: InstallOpts) {
this.version = opts.version;
this.channel = opts.channel || 'stable';
this.runDir = opts.runDir;
this.contextName = opts.contextName || 'setup-docker-action';
}
get toolDir(): string {
return this._toolDir || Context.tmpDir();
}
public async download(): Promise<string> {
const downloadURL = this.downloadURL(this.version, this.channel);
core.info(`Downloading ${downloadURL}`); core.info(`Downloading ${downloadURL}`);
const downloadPath = await tc.downloadTool(downloadURL); const downloadPath = await tc.downloadTool(downloadURL);
@@ -60,31 +84,32 @@ export class Install {
}); });
}); });
const tooldir = await tc.cacheDir(extractFolder, `docker-${channel}`, version.replace(/(0+)([1-9]+)/, '$2')); const tooldir = await tc.cacheDir(extractFolder, `docker-${this.channel}`, this.version.replace(/(0+)([1-9]+)/, '$2'));
core.addPath(tooldir); core.addPath(tooldir);
core.info('Added Docker to PATH'); core.info('Added Docker to PATH');
this._toolDir = tooldir;
return tooldir; return tooldir;
} }
public async install(toolDir: string, runDir: string, version: string, channel?: string): Promise<void> { public async install(): Promise<void> {
if (toolDir.length == 0) { if (!this.toolDir) {
throw new Error('toolDir must be set'); throw new Error('toolDir must be set. Run download first.');
} }
if (runDir.length == 0) { if (!this.runDir) {
throw new Error('runDir must be set'); throw new Error('runDir must be set');
} }
channel = channel || 'stable';
switch (os.platform()) { switch (os.platform()) {
case 'darwin': { case 'darwin': {
await this.installDarwin(toolDir, version, channel); await this.installDarwin();
break; break;
} }
case 'linux': { case 'linux': {
await this.installLinux(toolDir, runDir); await this.installLinux();
break; break;
} }
case 'win32': { case 'win32': {
await this.installWindows(toolDir, runDir); await this.installWindows();
break; break;
} }
default: { default: {
@@ -93,7 +118,7 @@ export class Install {
} }
} }
private async installDarwin(toolDir: string, version: string, channel?: string): Promise<void> { private async installDarwin(): Promise<void> {
const colimaDir = path.join(os.homedir(), '.colima', 'default'); // TODO: create a custom colima profile to avoid overlap with other actions const colimaDir = path.join(os.homedir(), '.colima', 'default'); // TODO: create a custom colima profile to avoid overlap with other actions
await io.mkdirP(colimaDir); await io.mkdirP(colimaDir);
const dockerHost = `unix://${colimaDir}/docker.sock`; const dockerHost = `unix://${colimaDir}/docker.sock`;
@@ -107,8 +132,8 @@ export class Install {
await core.group('Creating colima config', async () => { await core.group('Creating colima config', async () => {
const colimaCfg = handlebars.compile(colimaYamlData)({ const colimaCfg = handlebars.compile(colimaYamlData)({
hostArch: Install.platformArch(), hostArch: Install.platformArch(),
dockerVersion: version, dockerVersion: this.version,
dockerChannel: channel dockerChannel: this.channel
}); });
core.info(`Writing colima config to ${path.join(colimaDir, 'colima.yaml')}`); core.info(`Writing colima config to ${path.join(colimaDir, 'colima.yaml')}`);
fs.writeFileSync(path.join(colimaDir, 'colima.yaml'), colimaCfg); fs.writeFileSync(path.join(colimaDir, 'colima.yaml'), colimaCfg);
@@ -118,7 +143,7 @@ export class Install {
// colima is already started on the runner so env var added in download // colima is already started on the runner so env var added in download
// method is not expanded to the running process. // method is not expanded to the running process.
const envs = Object.assign({}, process.env, { const envs = Object.assign({}, process.env, {
PATH: `${toolDir}:${process.env.PATH}` PATH: `${this.toolDir}:${process.env.PATH}`
}) as { }) as {
[key: string]: string; [key: string]: string;
}; };
@@ -127,14 +152,14 @@ export class Install {
}); });
await core.group('Create Docker context', async () => { await core.group('Create Docker context', async () => {
await Exec.exec('docker', ['context', 'create', 'setup-docker-action', '--docker', `host=${dockerHost}`]); await Exec.exec('docker', ['context', 'create', this.contextName, '--docker', `host=${dockerHost}`]);
await Exec.exec('docker', ['context', 'use', 'setup-docker-action']); await Exec.exec('docker', ['context', 'use', this.contextName]);
}); });
} }
private async installLinux(toolDir: string, runDir: string): Promise<void> { private async installLinux(): Promise<void> {
const dockerHost = `unix://${path.join(runDir, 'docker.sock')}`; const dockerHost = `unix://${path.join(this.runDir, 'docker.sock')}`;
await io.mkdirP(runDir); await io.mkdirP(this.runDir);
await core.group('Start Docker daemon', async () => { await core.group('Start Docker daemon', async () => {
const bashPath: string = await io.which('bash', true); const bashPath: string = await io.which('bash', true);
@@ -143,8 +168,8 @@ export class Install {
shell: true, shell: true,
stdio: ['ignore', process.stdout, process.stderr], stdio: ['ignore', process.stdout, process.stderr],
env: Object.assign({}, process.env, { env: Object.assign({}, process.env, {
TOOLDIR: toolDir, TOOLDIR: this.toolDir,
RUNDIR: runDir, RUNDIR: this.runDir,
DOCKER_HOST: dockerHost DOCKER_HOST: dockerHost
}) as { }) as {
[key: string]: string; [key: string]: string;
@@ -182,18 +207,18 @@ export class Install {
}); });
await core.group('Create Docker context', async () => { await core.group('Create Docker context', async () => {
await Exec.exec('docker', ['context', 'create', 'setup-docker-action', '--docker', `host=${dockerHost}`]); await Exec.exec('docker', ['context', 'create', this.contextName, '--docker', `host=${dockerHost}`]);
await Exec.exec('docker', ['context', 'use', 'setup-docker-action']); await Exec.exec('docker', ['context', 'use', this.contextName]);
}); });
} }
private async installWindows(toolDir: string, runDir: string): Promise<void> { private async installWindows(): Promise<void> {
const dockerHost = 'npipe:////./pipe/setup_docker_action'; const dockerHost = 'npipe:////./pipe/setup_docker_action';
await core.group('Install Docker daemon service', async () => { await core.group('Install Docker daemon service', async () => {
const setupCmd = await Util.powershellCommand(setupDockerWinPs1(), { const setupCmd = await Util.powershellCommand(setupDockerWinPs1(), {
ToolDir: toolDir, ToolDir: this.toolDir,
RunDir: runDir, RunDir: this.runDir,
DockerHost: dockerHost DockerHost: dockerHost
}); });
await Exec.exec(setupCmd.command, setupCmd.args); await Exec.exec(setupCmd.command, setupCmd.args);
@@ -202,19 +227,22 @@ export class Install {
}); });
await core.group('Create Docker context', async () => { await core.group('Create Docker context', async () => {
await Exec.exec('docker', ['context', 'create', 'setup-docker-action', '--docker', `host=${dockerHost}`]); await Exec.exec('docker', ['context', 'create', this.contextName, '--docker', `host=${dockerHost}`]);
await Exec.exec('docker', ['context', 'use', 'setup-docker-action']); await Exec.exec('docker', ['context', 'use', this.contextName]);
}); });
} }
public async tearDown(runDir: string): Promise<void> { public async tearDown(): Promise<void> {
if (!this.runDir) {
throw new Error('runDir must be set');
}
switch (os.platform()) { switch (os.platform()) {
case 'darwin': { case 'darwin': {
await this.tearDownDarwin(runDir); await this.tearDownDarwin();
break; break;
} }
case 'linux': { case 'linux': {
await this.tearDownLinux(runDir); await this.tearDownLinux();
break; break;
} }
case 'win32': { case 'win32': {
@@ -227,7 +255,7 @@ export class Install {
} }
} }
private async tearDownDarwin(runDir: string): Promise<void> { private async tearDownDarwin(): Promise<void> {
await core.group('Docker daemon logs', async () => { await core.group('Docker daemon logs', async () => {
await Exec.exec('colima', ['exec', '--', 'cat', '/var/log/docker.log']); await Exec.exec('colima', ['exec', '--', 'cat', '/var/log/docker.log']);
}); });
@@ -235,25 +263,25 @@ export class Install {
await Exec.exec('colima', ['stop', '--very-verbose']); await Exec.exec('colima', ['stop', '--very-verbose']);
}); });
await core.group('Removing Docker context', async () => { await core.group('Removing Docker context', async () => {
await Exec.exec('docker', ['context', 'rm', '-f', 'setup-docker-action']); await Exec.exec('docker', ['context', 'rm', '-f', this.contextName]);
}); });
await core.group(`Cleaning up runDir`, async () => { await core.group(`Cleaning up runDir`, async () => {
await Exec.exec('sudo', ['rm', '-rf', runDir]); await Exec.exec('sudo', ['rm', '-rf', this.runDir]);
}); });
} }
private async tearDownLinux(runDir: string): Promise<void> { private async tearDownLinux(): Promise<void> {
await core.group('Docker daemon logs', async () => { await core.group('Docker daemon logs', async () => {
core.info(fs.readFileSync(path.join(runDir, 'dockerd.log'), {encoding: 'utf8'})); core.info(fs.readFileSync(path.join(this.runDir, 'dockerd.log'), {encoding: 'utf8'}));
}); });
await core.group('Stopping Docker daemon', async () => { await core.group('Stopping Docker daemon', async () => {
await Exec.exec('sudo', ['kill', fs.readFileSync(path.join(runDir, 'docker.pid')).toString().trim()]); await Exec.exec('sudo', ['kill', fs.readFileSync(path.join(this.runDir, 'docker.pid')).toString().trim()]);
}); });
await core.group('Removing Docker context', async () => { await core.group('Removing Docker context', async () => {
await Exec.exec('docker', ['context', 'rm', '-f', 'setup-docker-action']); await Exec.exec('docker', ['context', 'rm', '-f', this.contextName]);
}); });
await core.group(`Cleaning up runDir`, async () => { await core.group(`Cleaning up runDir`, async () => {
await Exec.exec('sudo', ['rm', '-rf', runDir]); await Exec.exec('sudo', ['rm', '-rf', this.runDir]);
}); });
} }
@@ -263,7 +291,7 @@ export class Install {
await Exec.exec(logCmd.command, logCmd.args); await Exec.exec(logCmd.command, logCmd.args);
}); });
await core.group('Removing Docker context', async () => { await core.group('Removing Docker context', async () => {
await Exec.exec('docker', ['context', 'rm', '-f', 'setup-docker-action']); await Exec.exec('docker', ['context', 'rm', '-f', this.contextName]);
}); });
} }