Merge pull request #58 from crazy-max/docker-install
Some checks failed
publish / publish (push) Has been cancelled
Some checks failed
publish / publish (push) Has been cancelled
docker: install, download and tearDown methods
This commit is contained in:
@@ -19,7 +19,7 @@ import path from 'path';
|
||||
import * as core from '@actions/core';
|
||||
import * as semver from 'semver';
|
||||
|
||||
import {Docker} from '../docker';
|
||||
import {Docker} from '../docker/docker';
|
||||
import {Exec} from '../exec';
|
||||
import {Inputs} from './inputs';
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ import * as util from 'util';
|
||||
import {Buildx} from './buildx';
|
||||
import {Context} from '../context';
|
||||
import {Exec} from '../exec';
|
||||
import {Docker} from '../docker';
|
||||
import {Docker} from '../docker/docker';
|
||||
import {Git} from '../git';
|
||||
|
||||
import {GitHubRelease} from '../types/github';
|
||||
|
||||
338
src/docker/assets.ts
Normal file
338
src/docker/assets.ts
Normal file
@@ -0,0 +1,338 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import fs from 'fs';
|
||||
import {Context} from '../context';
|
||||
|
||||
export const setupDockerLinuxSh = (): string => {
|
||||
return get('docker-setup-linux.sh', setupDockerLinuxShData, '0755');
|
||||
};
|
||||
|
||||
export const setupDockerWinPs1 = (): string => {
|
||||
return get('docker-setup-win.ps1', setupDockerWinPs1Data);
|
||||
};
|
||||
|
||||
export const dockerServiceLogsPs1 = (): string => {
|
||||
return get('docker-service-logs.ps1', dockerServiceLogsPs1Data);
|
||||
};
|
||||
|
||||
export const colimaYaml = (): string => {
|
||||
return get('colima.yaml', colimaYamlData);
|
||||
};
|
||||
|
||||
const get = (filename: string, data: string, mode?: string): string => {
|
||||
const assetPath = Context.tmpName({
|
||||
template: `docker-asset-XXXXXX-${filename}`,
|
||||
tmpdir: Context.tmpDir()
|
||||
});
|
||||
fs.writeFileSync(assetPath, data);
|
||||
if (mode) {
|
||||
fs.chmodSync(assetPath, mode);
|
||||
}
|
||||
return assetPath;
|
||||
};
|
||||
|
||||
export const setupDockerLinuxShData = `
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eu
|
||||
|
||||
: "\${TOOLDIR=}"
|
||||
: "\${RUNDIR=}"
|
||||
: "\${DOCKER_HOST=}"
|
||||
|
||||
export PATH="$TOOLDIR::$PATH"
|
||||
|
||||
if [ -z "$DOCKER_HOST" ]; then
|
||||
echo >&2 'error: DOCKER_HOST required'
|
||||
false
|
||||
fi
|
||||
|
||||
if ! command -v dockerd &> /dev/null; then
|
||||
echo >&2 'error: dockerd missing from PATH'
|
||||
false
|
||||
fi
|
||||
|
||||
mkdir -p "$RUNDIR"
|
||||
|
||||
(
|
||||
echo "Starting dockerd"
|
||||
set -x
|
||||
exec dockerd \\
|
||||
--host="$DOCKER_HOST" \\
|
||||
--exec-root="$RUNDIR/execroot" \\
|
||||
--data-root="$RUNDIR/data" \\
|
||||
--pidfile="$RUNDIR/docker.pid" \\
|
||||
--userland-proxy=false \\
|
||||
2>&1 | tee "$RUNDIR/dockerd.log"
|
||||
) &
|
||||
`;
|
||||
|
||||
export const setupDockerWinPs1Data = `
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$ToolDir,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$RunDir,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$DockerHost)
|
||||
|
||||
$pwver = (Get-ItemProperty -Path HKLM:\\SOFTWARE\\Microsoft\\PowerShell\\3\\PowerShellEngine -Name 'PowerShellVersion').PowerShellVersion
|
||||
Write-Host "PowerShell version: $pwver"
|
||||
|
||||
# Create run directory
|
||||
New-Item -ItemType Directory "$RunDir" -ErrorAction SilentlyContinue | Out-Null
|
||||
|
||||
# Remove existing service
|
||||
if (Get-Service docker -ErrorAction SilentlyContinue) {
|
||||
$dockerVersion = (docker version -f "{{.Server.Version}}")
|
||||
Write-Host "Current installed Docker version: $dockerVersion"
|
||||
# stop service
|
||||
Stop-Service -Force -Name docker
|
||||
Write-Host "Service stopped"
|
||||
# remove service
|
||||
sc.exe delete "docker"
|
||||
# removes event log entry. we could use "Remove-EventLog -LogName -Source docker"
|
||||
# but this cmd is not available atm
|
||||
$ErrorActionPreference = "SilentlyContinue"
|
||||
& reg delete "HKLM\\SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\docker" /f 2>&1 | Out-Null
|
||||
$ErrorActionPreference = "Stop"
|
||||
Write-Host "Service removed"
|
||||
}
|
||||
|
||||
$env:DOCKER_HOST = $DockerHost
|
||||
Write-Host "DOCKER_HOST: $env:DOCKER_HOST"
|
||||
|
||||
Write-Host "Creating service"
|
||||
New-Item -ItemType Directory "$RunDir\\moby-root" -ErrorAction SilentlyContinue | Out-Null
|
||||
New-Item -ItemType Directory "$RunDir\\moby-exec" -ErrorAction SilentlyContinue | Out-Null
|
||||
Start-Process -Wait -NoNewWindow "$ToolDir\\dockerd" \`
|
||||
-ArgumentList \`
|
||||
"--host=$DockerHost", \`
|
||||
"--data-root=$RunDir\\moby-root", \`
|
||||
"--exec-root=$RunDir\\moby-exec", \`
|
||||
"--pidfile=$RunDir\\docker.pid", \`
|
||||
"--register-service"
|
||||
Write-Host "Starting service"
|
||||
Start-Service -Name docker
|
||||
Write-Host "Service started successfully!"
|
||||
|
||||
$tries=20
|
||||
Write-Host "Waiting for Docker daemon to start..."
|
||||
While ($true) {
|
||||
$ErrorActionPreference = "SilentlyContinue"
|
||||
& "$ToolDir\\docker" version | Out-Null
|
||||
$ErrorActionPreference = "Stop"
|
||||
If ($LastExitCode -eq 0) {
|
||||
break
|
||||
}
|
||||
$tries--
|
||||
If ($tries -le 0) {
|
||||
Throw "Failed to get a response from Docker daemon"
|
||||
}
|
||||
Write-Host -NoNewline "."
|
||||
Start-Sleep -Seconds 1
|
||||
}
|
||||
Write-Host "Docker daemon started successfully!"
|
||||
`;
|
||||
|
||||
export const dockerServiceLogsPs1Data = `
|
||||
Get-WinEvent -ea SilentlyContinue \`
|
||||
-FilterHashtable @{ProviderName= "docker"; LogName = "application"} |
|
||||
Sort-Object @{Expression="TimeCreated";Descending=$false} |
|
||||
ForEach-Object {"$($_.TimeCreated.ToUniversalTime().ToString("o")) [$($_.LevelDisplayName)] $($_.Message)"}
|
||||
`;
|
||||
|
||||
export const colimaYamlData = `
|
||||
# Number of CPUs to be allocated to the virtual machine.
|
||||
# Default: 2
|
||||
cpu: 2
|
||||
|
||||
# Size of the disk in GiB to be allocated to the virtual machine.
|
||||
# NOTE: changing this has no effect after the virtual machine has been created.
|
||||
# Default: 60
|
||||
disk: 60
|
||||
|
||||
# Size of the memory in GiB to be allocated to the virtual machine.
|
||||
# Default: 2
|
||||
memory: 2
|
||||
|
||||
# Architecture of the virtual machine (x86_64, aarch64, host).
|
||||
# Default: host
|
||||
arch: host
|
||||
|
||||
# Container runtime to be used (docker, containerd).
|
||||
# Default: docker
|
||||
runtime: docker
|
||||
|
||||
# Kubernetes configuration for the virtual machine.
|
||||
kubernetes:
|
||||
enabled: false
|
||||
|
||||
# Auto-activate on the Host for client access.
|
||||
# Setting to true does the following on startup
|
||||
# - sets as active Docker context (for Docker runtime).
|
||||
# - sets as active Kubernetes context (if Kubernetes is enabled).
|
||||
# Default: true
|
||||
autoActivate: false
|
||||
|
||||
# Network configurations for the virtual machine.
|
||||
network:
|
||||
# Assign reachable IP address to the virtual machine.
|
||||
# NOTE: this is currently macOS only and ignored on Linux.
|
||||
# Default: false
|
||||
address: false
|
||||
|
||||
# Custom DNS resolvers for the virtual machine.
|
||||
#
|
||||
# EXAMPLE
|
||||
# dns: [8.8.8.8, 1.1.1.1]
|
||||
#
|
||||
# Default: []
|
||||
dns: []
|
||||
|
||||
# DNS hostnames to resolve to custom targets using the internal resolver.
|
||||
# This setting has no effect if a custom DNS resolver list is supplied above.
|
||||
# It does not configure the /etc/hosts files of any machine or container.
|
||||
# The value can be an IP address or another host.
|
||||
#
|
||||
# EXAMPLE
|
||||
# dnsHosts:
|
||||
# example.com: 1.2.3.4
|
||||
dnsHosts:
|
||||
host.docker.internal: host.lima.internal
|
||||
|
||||
# Network driver to use (slirp, gvproxy), (requires vmType \`qemu\`)
|
||||
# - slirp is the default user mode networking provided by Qemu
|
||||
# - gvproxy is an alternative to VPNKit based on gVisor https://github.com/containers/gvisor-tap-vsock
|
||||
# Default: gvproxy
|
||||
driver: gvproxy
|
||||
|
||||
# Forward the host's SSH agent to the virtual machine.
|
||||
# Default: false
|
||||
forwardAgent: false
|
||||
|
||||
# Docker daemon configuration that maps directly to daemon.json.
|
||||
# https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-configuration-file.
|
||||
# NOTE: some settings may affect Colima's ability to start docker. e.g. \`hosts\`.
|
||||
#
|
||||
# EXAMPLE - disable buildkit
|
||||
# docker:
|
||||
# features:
|
||||
# buildkit: false
|
||||
#
|
||||
# EXAMPLE - add insecure registries
|
||||
# docker:
|
||||
# insecure-registries:
|
||||
# - myregistry.com:5000
|
||||
# - host.docker.internal:5000
|
||||
#
|
||||
# Colima default behaviour: buildkit enabled
|
||||
# Default: {}
|
||||
docker: {}
|
||||
|
||||
# Virtual Machine type (qemu, vz)
|
||||
# NOTE: this is macOS 13 only. For Linux and macOS <13.0, qemu is always used.
|
||||
#
|
||||
# vz is macOS virtualization framework and requires macOS 13
|
||||
#
|
||||
# Default: qemu
|
||||
vmType: qemu
|
||||
|
||||
# Volume mount driver for the virtual machine (virtiofs, 9p, sshfs).
|
||||
#
|
||||
# virtiofs is limited to macOS and vmType \`vz\`. It is the fastest of the options.
|
||||
#
|
||||
# 9p is the recommended and the most stable option for vmType \`qemu\`.
|
||||
#
|
||||
# sshfs is faster than 9p but the least reliable of the options (when there are lots
|
||||
# of concurrent reads or writes).
|
||||
#
|
||||
# Default: virtiofs (for vz), sshfs (for qemu)
|
||||
mountType: 9p
|
||||
|
||||
# The CPU type for the virtual machine (requires vmType \`qemu\`).
|
||||
# Options available for host emulation can be checked with: \`qemu-system-$(arch) -cpu help\`.
|
||||
# Instructions are also supported by appending to the cpu type e.g. "qemu64,+ssse3".
|
||||
# Default: host
|
||||
cpuType: host
|
||||
|
||||
# For a more general purpose virtual machine, Ubuntu container is optionally provided
|
||||
# as a layer on the virtual machine.
|
||||
# The underlying virtual machine is still accessible via \`colima ssh --layer=false\` or running \`colima\` in
|
||||
# the Ubuntu session.
|
||||
#
|
||||
# Default: false
|
||||
layer: false
|
||||
|
||||
# Custom provision scripts for the virtual machine.
|
||||
# Provisioning scripts are executed on startup and therefore needs to be idempotent.
|
||||
#
|
||||
# EXAMPLE - script exected as root
|
||||
# provision:
|
||||
# - mode: system
|
||||
# script: apk add htop vim
|
||||
#
|
||||
# EXAMPLE - script exected as user
|
||||
# provision:
|
||||
# - mode: user
|
||||
# script: |
|
||||
# [ -f ~/.provision ] && exit 0;
|
||||
# echo provisioning as $USER...
|
||||
# touch ~/.provision
|
||||
#
|
||||
# Default: []
|
||||
provision:
|
||||
- mode: system
|
||||
script: |
|
||||
mkdir -p /tmp/docker-bins
|
||||
cd /tmp/docker-bins
|
||||
wget -qO- "https://download.docker.com/linux/static/{{dockerChannel}}/{{hostArch}}/docker-{{dockerVersion}}.tgz" | tar xvz --strip 1
|
||||
mv -f /tmp/docker-bins/* /usr/bin/
|
||||
|
||||
# Modify ~/.ssh/config automatically to include a SSH config for the virtual machine.
|
||||
# SSH config will still be generated in ~/.colima/ssh_config regardless.
|
||||
# Default: true
|
||||
sshConfig: false
|
||||
|
||||
# Configure volume mounts for the virtual machine.
|
||||
# Colima mounts user's home directory by default to provide a familiar
|
||||
# user experience.
|
||||
#
|
||||
# EXAMPLE
|
||||
# mounts:
|
||||
# - location: ~/secrets
|
||||
# writable: false
|
||||
# - location: ~/projects
|
||||
# writable: true
|
||||
#
|
||||
# Colima default behaviour: $HOME and /tmp/colima are mounted as writable.
|
||||
# Default: []
|
||||
mounts: []
|
||||
|
||||
# Environment variables for the virtual machine.
|
||||
#
|
||||
# EXAMPLE
|
||||
# env:
|
||||
# KEY: value
|
||||
# ANOTHER_KEY: another value
|
||||
#
|
||||
# Default: {}
|
||||
env: {}
|
||||
`;
|
||||
@@ -18,7 +18,7 @@ import os from 'os';
|
||||
import path from 'path';
|
||||
import * as core from '@actions/core';
|
||||
import * as io from '@actions/io';
|
||||
import {Exec} from './exec';
|
||||
import {Exec} from '../exec';
|
||||
|
||||
export class Docker {
|
||||
static get configDir(): string {
|
||||
335
src/docker/install.ts
Normal file
335
src/docker/install.ts
Normal file
@@ -0,0 +1,335 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import * as child_process from 'child_process';
|
||||
import fs from 'fs';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
import retry from 'async-retry';
|
||||
import * as handlebars from 'handlebars';
|
||||
import * as util from 'util';
|
||||
import * as core from '@actions/core';
|
||||
import * as io from '@actions/io';
|
||||
import * as tc from '@actions/tool-cache';
|
||||
|
||||
import {Exec} from '../exec';
|
||||
import {Util} from '../util';
|
||||
import {colimaYamlData, dockerServiceLogsPs1, setupDockerLinuxSh, setupDockerWinPs1} from './assets';
|
||||
|
||||
export class Install {
|
||||
public async download(version: string, channel?: string): Promise<string> {
|
||||
channel = channel || 'stable';
|
||||
const downloadURL = this.downloadURL(version, channel);
|
||||
|
||||
core.info(`Downloading ${downloadURL}`);
|
||||
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 {
|
||||
extractFolder = await tc.extractTar(downloadPath);
|
||||
}
|
||||
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');
|
||||
});
|
||||
});
|
||||
|
||||
const tooldir = await tc.cacheDir(extractFolder, `docker-${channel}`, version.replace(/(0+)([1-9]+)/, '$2'));
|
||||
core.addPath(tooldir);
|
||||
core.info('Added Docker to PATH');
|
||||
return tooldir;
|
||||
}
|
||||
|
||||
public async install(toolDir: string, runDir: string, version: string, channel?: string): Promise<void> {
|
||||
if (toolDir.length == 0) {
|
||||
throw new Error('toolDir must be set');
|
||||
}
|
||||
if (runDir.length == 0) {
|
||||
throw new Error('runDir must be set');
|
||||
}
|
||||
channel = channel || 'stable';
|
||||
switch (os.platform()) {
|
||||
case 'darwin': {
|
||||
await this.installDarwin(toolDir, version, channel);
|
||||
break;
|
||||
}
|
||||
case 'linux': {
|
||||
await this.installLinux(toolDir, runDir);
|
||||
break;
|
||||
}
|
||||
case 'win32': {
|
||||
await this.installWindows(toolDir, runDir);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new Error(`Unsupported platform: ${os.platform()}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async installDarwin(toolDir: string, version: string, channel?: string): Promise<void> {
|
||||
const colimaDir = path.join(os.homedir(), '.colima', 'default'); // TODO: create a custom colima profile to avoid overlap with other actions
|
||||
await io.mkdirP(colimaDir);
|
||||
const dockerHost = `unix://${colimaDir}/docker.sock`;
|
||||
|
||||
if (!(await Install.colimaInstalled())) {
|
||||
await core.group('Installing colima', async () => {
|
||||
await Exec.exec('brew', ['install', 'colima']);
|
||||
});
|
||||
}
|
||||
|
||||
await core.group('Creating colima config', async () => {
|
||||
const colimaCfg = handlebars.compile(colimaYamlData)({
|
||||
hostArch: Install.platformArch(),
|
||||
dockerVersion: version,
|
||||
dockerChannel: channel
|
||||
});
|
||||
core.info(`Writing colima config to ${path.join(colimaDir, 'colima.yaml')}`);
|
||||
fs.writeFileSync(path.join(colimaDir, 'colima.yaml'), colimaCfg);
|
||||
core.info(colimaCfg);
|
||||
});
|
||||
|
||||
// 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, {
|
||||
PATH: `${toolDir}:${process.env.PATH}`
|
||||
}) as {
|
||||
[key: string]: string;
|
||||
};
|
||||
await core.group('Starting colima', async () => {
|
||||
await Exec.exec('colima', ['start', '--very-verbose'], {env: envs});
|
||||
});
|
||||
|
||||
await core.group('Create Docker context', async () => {
|
||||
await Exec.exec('docker', ['context', 'create', 'setup-docker-action', '--docker', `host=${dockerHost}`]);
|
||||
await Exec.exec('docker', ['context', 'use', 'setup-docker-action']);
|
||||
});
|
||||
}
|
||||
|
||||
private async installLinux(toolDir: string, runDir: string): Promise<void> {
|
||||
const dockerHost = `unix://${path.join(runDir, 'docker.sock')}`;
|
||||
await io.mkdirP(runDir);
|
||||
|
||||
await core.group('Start Docker daemon', async () => {
|
||||
const bashPath: string = await io.which('bash', true);
|
||||
const proc = await child_process.spawn(`sudo -E ${bashPath} ${setupDockerLinuxSh()}`, [], {
|
||||
detached: true,
|
||||
shell: true,
|
||||
stdio: ['ignore', process.stdout, process.stderr],
|
||||
env: Object.assign({}, process.env, {
|
||||
TOOLDIR: toolDir,
|
||||
RUNDIR: runDir,
|
||||
DOCKER_HOST: dockerHost
|
||||
}) as {
|
||||
[key: string]: string;
|
||||
}
|
||||
});
|
||||
proc.unref();
|
||||
await retry(
|
||||
async bail => {
|
||||
await Exec.getExecOutput(`docker version`, undefined, {
|
||||
ignoreReturnCode: true,
|
||||
silent: true,
|
||||
env: Object.assign({}, process.env, {
|
||||
DOCKER_HOST: dockerHost
|
||||
}) as {
|
||||
[key: string]: string;
|
||||
}
|
||||
})
|
||||
.then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
bail(new Error(res.stderr));
|
||||
return false;
|
||||
}
|
||||
return res.exitCode == 0;
|
||||
})
|
||||
.catch(error => {
|
||||
bail(error);
|
||||
return false;
|
||||
});
|
||||
},
|
||||
{
|
||||
retries: 5
|
||||
}
|
||||
);
|
||||
core.info(`Docker daemon started started successfully`);
|
||||
});
|
||||
|
||||
await core.group('Create Docker context', async () => {
|
||||
await Exec.exec('docker', ['context', 'create', 'setup-docker-action', '--docker', `host=${dockerHost}`]);
|
||||
await Exec.exec('docker', ['context', 'use', 'setup-docker-action']);
|
||||
});
|
||||
}
|
||||
|
||||
private async installWindows(toolDir: string, runDir: string): Promise<void> {
|
||||
const dockerHost = 'npipe:////./pipe/setup_docker_action';
|
||||
|
||||
await core.group('Install Docker daemon service', async () => {
|
||||
const setupCmd = await Util.powershellCommand(setupDockerWinPs1(), {
|
||||
ToolDir: toolDir,
|
||||
RunDir: runDir,
|
||||
DockerHost: dockerHost
|
||||
});
|
||||
await Exec.exec(setupCmd.command, setupCmd.args);
|
||||
const logCmd = await Util.powershellCommand(dockerServiceLogsPs1());
|
||||
await Exec.exec(logCmd.command, logCmd.args);
|
||||
});
|
||||
|
||||
await core.group('Create Docker context', async () => {
|
||||
await Exec.exec('docker', ['context', 'create', 'setup-docker-action', '--docker', `host=${dockerHost}`]);
|
||||
await Exec.exec('docker', ['context', 'use', 'setup-docker-action']);
|
||||
});
|
||||
}
|
||||
|
||||
public async tearDown(runDir: string): Promise<void> {
|
||||
switch (os.platform()) {
|
||||
case 'darwin': {
|
||||
await this.tearDownDarwin(runDir);
|
||||
break;
|
||||
}
|
||||
case 'linux': {
|
||||
await this.tearDownLinux(runDir);
|
||||
break;
|
||||
}
|
||||
case 'win32': {
|
||||
await this.tearDownWindows();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new Error(`Unsupported platform: ${os.platform()}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async tearDownDarwin(runDir: string): Promise<void> {
|
||||
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 () => {
|
||||
await Exec.exec('docker', ['context', 'rm', '-f', 'setup-docker-action']);
|
||||
});
|
||||
await core.group(`Cleaning up runDir`, async () => {
|
||||
await Exec.exec('sudo', ['rm', '-rf', runDir]);
|
||||
});
|
||||
}
|
||||
|
||||
private async tearDownLinux(runDir: string): Promise<void> {
|
||||
await core.group('Docker daemon logs', async () => {
|
||||
core.info(fs.readFileSync(path.join(runDir, 'dockerd.log'), {encoding: 'utf8'}));
|
||||
});
|
||||
await core.group('Stopping Docker daemon', async () => {
|
||||
await Exec.exec('sudo', ['kill', fs.readFileSync(path.join(runDir, 'docker.pid')).toString().trim()]);
|
||||
});
|
||||
await core.group('Removing Docker context', async () => {
|
||||
await Exec.exec('docker', ['context', 'rm', '-f', 'setup-docker-action']);
|
||||
});
|
||||
await core.group(`Cleaning up runDir`, async () => {
|
||||
await Exec.exec('sudo', ['rm', '-rf', runDir]);
|
||||
});
|
||||
}
|
||||
|
||||
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 () => {
|
||||
await Exec.exec('docker', ['context', 'rm', '-f', 'setup-docker-action']);
|
||||
});
|
||||
}
|
||||
|
||||
private downloadURL(version: string, channel: string): string {
|
||||
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 {
|
||||
switch (os.platform()) {
|
||||
case 'darwin': {
|
||||
return 'mac';
|
||||
}
|
||||
case 'linux': {
|
||||
return 'linux';
|
||||
}
|
||||
case 'win32': {
|
||||
return 'win';
|
||||
}
|
||||
default: {
|
||||
return os.platform();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static platformArch(): string {
|
||||
switch (os.arch()) {
|
||||
case 'x64': {
|
||||
return 'x86_64';
|
||||
}
|
||||
case 'ppc64': {
|
||||
return 'ppc64le';
|
||||
}
|
||||
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: {
|
||||
return 'armel';
|
||||
}
|
||||
case 7: {
|
||||
return 'armhf';
|
||||
}
|
||||
default: {
|
||||
return `v${arm_version}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
default: {
|
||||
return os.arch();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
});
|
||||
}
|
||||
}
|
||||
26
src/util.ts
26
src/util.ts
@@ -14,7 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import fs from 'fs';
|
||||
import * as core from '@actions/core';
|
||||
import * as io from '@actions/io';
|
||||
import {parse} from 'csv-parse/sync';
|
||||
|
||||
export interface InputListOpts {
|
||||
@@ -71,4 +73,28 @@ export class Util {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static async powershellCommand(script: string, params?: Record<string, string>) {
|
||||
const powershellPath: string = await io.which('powershell', true);
|
||||
const escapedScript = script.replace(/'/g, "''").replace(/"|\n|\r/g, '');
|
||||
const escapedParams: string[] = [];
|
||||
if (params) {
|
||||
for (const key in params) {
|
||||
escapedParams.push(`-${key} '${params[key].replace(/'/g, "''").replace(/"|\n|\r/g, '')}'`);
|
||||
}
|
||||
}
|
||||
return {
|
||||
command: `"${powershellPath}"`,
|
||||
args: ['-NoLogo', '-Sta', '-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Unrestricted', '-Command', `& '${escapedScript}' ${escapedParams.join(' ')}`]
|
||||
};
|
||||
}
|
||||
|
||||
public static isDirectory(p) {
|
||||
try {
|
||||
return fs.lstatSync(p).isDirectory();
|
||||
} catch (_) {
|
||||
// noop
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user