Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff509b09e3 | ||
|
|
794148e937 | ||
|
|
68fd63a69e | ||
|
|
a619d07b13 | ||
|
|
7a2707542f | ||
|
|
b9e1a8724d | ||
|
|
68633e712c | ||
|
|
8a5874c915 | ||
|
|
ad06f2a639 | ||
|
|
62397de881 |
79
.github/regclient-releases.json
vendored
79
.github/regclient-releases.json
vendored
@@ -1,31 +1,60 @@
|
|||||||
{
|
{
|
||||||
"latest": {
|
"latest": {
|
||||||
"id": 200406745,
|
"id": 214324874,
|
||||||
"tag_name": "v0.8.2",
|
"tag_name": "v0.8.3",
|
||||||
"html_url": "https://github.com/regclient/regclient/releases/tag/v0.8.2",
|
"html_url": "https://github.com/regclient/regclient/releases/tag/v0.8.3",
|
||||||
"assets": [
|
"assets": [
|
||||||
"https://github.com/regclient/regclient/releases/download/v0.8.2/metadata.tgz",
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/metadata.tgz",
|
||||||
"https://github.com/regclient/regclient/releases/download/v0.8.2/regbot-darwin-amd64",
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regbot-darwin-amd64",
|
||||||
"https://github.com/regclient/regclient/releases/download/v0.8.2/regbot-darwin-arm64",
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regbot-darwin-arm64",
|
||||||
"https://github.com/regclient/regclient/releases/download/v0.8.2/regbot-linux-amd64",
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regbot-linux-amd64",
|
||||||
"https://github.com/regclient/regclient/releases/download/v0.8.2/regbot-linux-arm64",
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regbot-linux-arm64",
|
||||||
"https://github.com/regclient/regclient/releases/download/v0.8.2/regbot-linux-ppc64le",
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regbot-linux-ppc64le",
|
||||||
"https://github.com/regclient/regclient/releases/download/v0.8.2/regbot-linux-s390x",
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regbot-linux-s390x",
|
||||||
"https://github.com/regclient/regclient/releases/download/v0.8.2/regbot-windows-amd64.exe",
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regbot-windows-amd64.exe",
|
||||||
"https://github.com/regclient/regclient/releases/download/v0.8.2/regctl-darwin-amd64",
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regctl-darwin-amd64",
|
||||||
"https://github.com/regclient/regclient/releases/download/v0.8.2/regctl-darwin-arm64",
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regctl-darwin-arm64",
|
||||||
"https://github.com/regclient/regclient/releases/download/v0.8.2/regctl-linux-amd64",
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regctl-linux-amd64",
|
||||||
"https://github.com/regclient/regclient/releases/download/v0.8.2/regctl-linux-arm64",
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regctl-linux-arm64",
|
||||||
"https://github.com/regclient/regclient/releases/download/v0.8.2/regctl-linux-ppc64le",
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regctl-linux-ppc64le",
|
||||||
"https://github.com/regclient/regclient/releases/download/v0.8.2/regctl-linux-s390x",
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regctl-linux-s390x",
|
||||||
"https://github.com/regclient/regclient/releases/download/v0.8.2/regctl-windows-amd64.exe",
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regctl-windows-amd64.exe",
|
||||||
"https://github.com/regclient/regclient/releases/download/v0.8.2/regsync-darwin-amd64",
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regsync-darwin-amd64",
|
||||||
"https://github.com/regclient/regclient/releases/download/v0.8.2/regsync-darwin-arm64",
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regsync-darwin-arm64",
|
||||||
"https://github.com/regclient/regclient/releases/download/v0.8.2/regsync-linux-amd64",
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regsync-linux-amd64",
|
||||||
"https://github.com/regclient/regclient/releases/download/v0.8.2/regsync-linux-arm64",
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regsync-linux-arm64",
|
||||||
"https://github.com/regclient/regclient/releases/download/v0.8.2/regsync-linux-ppc64le",
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regsync-linux-ppc64le",
|
||||||
"https://github.com/regclient/regclient/releases/download/v0.8.2/regsync-linux-s390x",
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regsync-linux-s390x",
|
||||||
"https://github.com/regclient/regclient/releases/download/v0.8.2/regsync-windows-amd64.exe"
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regsync-windows-amd64.exe"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"v0.8.3": {
|
||||||
|
"id": 214324874,
|
||||||
|
"tag_name": "v0.8.3",
|
||||||
|
"html_url": "https://github.com/regclient/regclient/releases/tag/v0.8.3",
|
||||||
|
"assets": [
|
||||||
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/metadata.tgz",
|
||||||
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regbot-darwin-amd64",
|
||||||
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regbot-darwin-arm64",
|
||||||
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regbot-linux-amd64",
|
||||||
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regbot-linux-arm64",
|
||||||
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regbot-linux-ppc64le",
|
||||||
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regbot-linux-s390x",
|
||||||
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regbot-windows-amd64.exe",
|
||||||
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regctl-darwin-amd64",
|
||||||
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regctl-darwin-arm64",
|
||||||
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regctl-linux-amd64",
|
||||||
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regctl-linux-arm64",
|
||||||
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regctl-linux-ppc64le",
|
||||||
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regctl-linux-s390x",
|
||||||
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regctl-windows-amd64.exe",
|
||||||
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regsync-darwin-amd64",
|
||||||
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regsync-darwin-arm64",
|
||||||
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regsync-linux-amd64",
|
||||||
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regsync-linux-arm64",
|
||||||
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regsync-linux-ppc64le",
|
||||||
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regsync-linux-s390x",
|
||||||
|
"https://github.com/regclient/regclient/releases/download/v0.8.3/regsync-windows-amd64.exe"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"v0.8.2": {
|
"v0.8.2": {
|
||||||
|
|||||||
17
.github/workflows/pr-assign-author.yml
vendored
Normal file
17
.github/workflows/pr-assign-author.yml
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
name: pr-assign-author
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request_target:
|
||||||
|
types:
|
||||||
|
- opened
|
||||||
|
- reopened
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
run:
|
||||||
|
uses: crazy-max/.github/.github/workflows/pr-assign-author.yml@1b673f36fad86812f538c1df9794904038a23cbf
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
55
__tests__/.fixtures/inspect12.txt
Normal file
55
__tests__/.fixtures/inspect12.txt
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
Name: nvidia
|
||||||
|
Driver: docker-container
|
||||||
|
Last Activity: 2025-02-14 15:57:45 +0000 UTC
|
||||||
|
|
||||||
|
Nodes:
|
||||||
|
Name: nvidia0
|
||||||
|
Endpoint: unix:///var/run/docker.sock
|
||||||
|
Driver Options: image="moby/buildkit:local"
|
||||||
|
Status: running
|
||||||
|
BuildKit daemon flags: --allow-insecure-entitlement=network.host
|
||||||
|
BuildKit version: v0.20.0-rc2-4-gd30d8e22c.m
|
||||||
|
Platforms: linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
|
||||||
|
Features:
|
||||||
|
Cache export: true
|
||||||
|
Docker exporter: true
|
||||||
|
Multi-platform build: true
|
||||||
|
OCI exporter: true
|
||||||
|
Labels:
|
||||||
|
org.mobyproject.buildkit.worker.executor: oci
|
||||||
|
org.mobyproject.buildkit.worker.hostname: 76ac9a510d96
|
||||||
|
org.mobyproject.buildkit.worker.network: host
|
||||||
|
org.mobyproject.buildkit.worker.oci.process-mode: sandbox
|
||||||
|
org.mobyproject.buildkit.worker.selinux.enabled: false
|
||||||
|
org.mobyproject.buildkit.worker.snapshotter: overlayfs
|
||||||
|
Devices:
|
||||||
|
Name: nvidia.com/gpu=all
|
||||||
|
Automatically allowed: true
|
||||||
|
Annotations:
|
||||||
|
foo: bar
|
||||||
|
org.mobyproject.buildkit.device.autoallow: true
|
||||||
|
Name: docker.com/gpu=venus
|
||||||
|
Automatically allowed: false
|
||||||
|
Annotations:
|
||||||
|
bar: baz
|
||||||
|
GC Policy rule#0:
|
||||||
|
All: false
|
||||||
|
Filters: type==source.local,type==exec.cachemount,type==source.git.checkout
|
||||||
|
Keep Duration: 48h0m0s
|
||||||
|
Max Used Space: 488.3MiB
|
||||||
|
GC Policy rule#1:
|
||||||
|
All: false
|
||||||
|
Keep Duration: 1440h0m0s
|
||||||
|
Reserved Space: 9.313GiB
|
||||||
|
Max Used Space: 93.13GiB
|
||||||
|
Min Free Space: 188.1GiB
|
||||||
|
GC Policy rule#2:
|
||||||
|
All: false
|
||||||
|
Reserved Space: 9.313GiB
|
||||||
|
Max Used Space: 93.13GiB
|
||||||
|
Min Free Space: 188.1GiB
|
||||||
|
GC Policy rule#3:
|
||||||
|
All: true
|
||||||
|
Reserved Space: 9.313GiB
|
||||||
|
Max Used Space: 93.13GiB
|
||||||
|
Min Free Space: 188.1GiB
|
||||||
@@ -466,6 +466,89 @@ baz = qux
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'inspect12.txt',
|
||||||
|
{
|
||||||
|
"name": "nvidia",
|
||||||
|
"driver": "docker-container",
|
||||||
|
"lastActivity": new Date("2025-02-14T15:57:45.000Z"),
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"buildkit": "v0.20.0-rc2-4-gd30d8e22c.m",
|
||||||
|
"buildkitd-flags": "--allow-insecure-entitlement=network.host",
|
||||||
|
"driver-opts": [
|
||||||
|
"image=moby/buildkit:local",
|
||||||
|
],
|
||||||
|
"endpoint": "unix:///var/run/docker.sock",
|
||||||
|
"name": "nvidia0",
|
||||||
|
"platforms": "linux/amd64,linux/amd64/v2,linux/amd64/v3,linux/arm64,linux/riscv64,linux/ppc64le,linux/s390x,linux/386,linux/arm/v7,linux/arm/v6",
|
||||||
|
"status": "running",
|
||||||
|
"features": {
|
||||||
|
"Cache export": true,
|
||||||
|
"Docker exporter": true,
|
||||||
|
"Multi-platform build": true,
|
||||||
|
"OCI exporter": true,
|
||||||
|
},
|
||||||
|
"labels": {
|
||||||
|
"org.mobyproject.buildkit.worker.executor": "oci",
|
||||||
|
"org.mobyproject.buildkit.worker.hostname": "76ac9a510d96",
|
||||||
|
"org.mobyproject.buildkit.worker.network": "host",
|
||||||
|
"org.mobyproject.buildkit.worker.oci.process-mode": "sandbox",
|
||||||
|
"org.mobyproject.buildkit.worker.selinux.enabled": "false",
|
||||||
|
"org.mobyproject.buildkit.worker.snapshotter": "overlayfs",
|
||||||
|
},
|
||||||
|
"devices": [
|
||||||
|
{
|
||||||
|
"annotations": {
|
||||||
|
"foo": "bar",
|
||||||
|
"org.mobyproject.buildkit.device.autoallow": "true"
|
||||||
|
},
|
||||||
|
"autoAllow": true,
|
||||||
|
"name": "nvidia.com/gpu=all"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"annotations": {
|
||||||
|
"bar": "baz"
|
||||||
|
},
|
||||||
|
"autoAllow": false,
|
||||||
|
"name": "docker.com/gpu=venus"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"gcPolicy": [
|
||||||
|
{
|
||||||
|
"all": false,
|
||||||
|
"filter": [
|
||||||
|
"type==source.local",
|
||||||
|
"type==exec.cachemount",
|
||||||
|
"type==source.git.checkout"
|
||||||
|
],
|
||||||
|
"keepDuration": "48h0m0s",
|
||||||
|
"maxUsedSpace": "488.3MiB",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"all": false,
|
||||||
|
"keepDuration": "1440h0m0s",
|
||||||
|
"maxUsedSpace": "93.13GiB",
|
||||||
|
"minFreeSpace": "188.1GiB",
|
||||||
|
"reservedSpace": "9.313GiB",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"all": false,
|
||||||
|
"maxUsedSpace": "93.13GiB",
|
||||||
|
"minFreeSpace": "188.1GiB",
|
||||||
|
"reservedSpace": "9.313GiB",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"all": true,
|
||||||
|
"maxUsedSpace": "93.13GiB",
|
||||||
|
"minFreeSpace": "188.1GiB",
|
||||||
|
"reservedSpace": "9.313GiB",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
])('given %p', async (inspectFile, expected) => {
|
])('given %p', async (inspectFile, expected) => {
|
||||||
expect(await Builder.parseInspect(fs.readFileSync(path.join(fixturesDir, inspectFile)).toString())).toEqual(expected);
|
expect(await Builder.parseInspect(fs.readFileSync(path.join(fixturesDir, inspectFile)).toString())).toEqual(expected);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -14,17 +14,31 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {describe, test, expect} from '@jest/globals';
|
import {beforeAll, describe, test, expect} from '@jest/globals';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import os from 'os';
|
import os from 'os';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
import {Install, InstallSource, InstallSourceArchive, InstallSourceImage} from '../../src/docker/install';
|
import {Install, InstallSource, InstallSourceArchive, InstallSourceImage} from '../../src/docker/install';
|
||||||
import {Docker} from '../../src/docker/docker';
|
import {Docker} from '../../src/docker/docker';
|
||||||
|
import {Regctl} from '../../src/regclient/regctl';
|
||||||
|
import {Install as RegclientInstall} from '../../src/regclient/install';
|
||||||
|
import {Undock} from '../../src/undock/undock';
|
||||||
|
import {Install as UndockInstall} from '../../src/undock/install';
|
||||||
import {Exec} from '../../src/exec';
|
import {Exec} from '../../src/exec';
|
||||||
|
|
||||||
const tmpDir = () => fs.mkdtempSync(path.join(process.env.TEMP || os.tmpdir(), 'docker-install-itg-'));
|
const tmpDir = () => fs.mkdtempSync(path.join(process.env.TEMP || os.tmpdir(), 'docker-install-itg-'));
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
const undockInstall = new UndockInstall();
|
||||||
|
const undockBinPath = await undockInstall.download('v0.10.0', true);
|
||||||
|
await undockInstall.install(undockBinPath);
|
||||||
|
|
||||||
|
const regclientInstall = new RegclientInstall();
|
||||||
|
const regclientBinPath = await regclientInstall.download('v0.8.2', true);
|
||||||
|
await regclientInstall.install(regclientBinPath);
|
||||||
|
}, 100000);
|
||||||
|
|
||||||
describe('root', () => {
|
describe('root', () => {
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
test.each(getSources(true))(
|
test.each(getSources(true))(
|
||||||
@@ -34,7 +48,9 @@ describe('root', () => {
|
|||||||
source: source,
|
source: source,
|
||||||
runDir: tmpDir(),
|
runDir: tmpDir(),
|
||||||
contextName: 'foo',
|
contextName: 'foo',
|
||||||
daemonConfig: `{"debug":true,"features":{"containerd-snapshotter":true}}`
|
daemonConfig: `{"debug":true,"features":{"containerd-snapshotter":true}}`,
|
||||||
|
regctl: new Regctl(),
|
||||||
|
undock: new Undock()
|
||||||
});
|
});
|
||||||
await expect(tryInstall(install)).resolves.not.toThrow();
|
await expect(tryInstall(install)).resolves.not.toThrow();
|
||||||
}, 30 * 60 * 1000);
|
}, 30 * 60 * 1000);
|
||||||
@@ -54,7 +70,9 @@ describe('rootless', () => {
|
|||||||
runDir: tmpDir(),
|
runDir: tmpDir(),
|
||||||
contextName: 'foo',
|
contextName: 'foo',
|
||||||
daemonConfig: `{"debug":true}`,
|
daemonConfig: `{"debug":true}`,
|
||||||
rootless: true
|
rootless: true,
|
||||||
|
regctl: new Regctl(),
|
||||||
|
undock: new Undock()
|
||||||
});
|
});
|
||||||
await expect(
|
await expect(
|
||||||
tryInstall(install, async () => {
|
tryInstall(install, async () => {
|
||||||
@@ -79,7 +97,9 @@ describe('tcp', () => {
|
|||||||
runDir: tmpDir(),
|
runDir: tmpDir(),
|
||||||
contextName: 'foo',
|
contextName: 'foo',
|
||||||
daemonConfig: `{"debug":true}`,
|
daemonConfig: `{"debug":true}`,
|
||||||
localTCPPort: 2378
|
localTCPPort: 2378,
|
||||||
|
regctl: new Regctl(),
|
||||||
|
undock: new Undock()
|
||||||
});
|
});
|
||||||
await expect(
|
await expect(
|
||||||
tryInstall(install, async () => {
|
tryInstall(install, async () => {
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ import * as rimraf from 'rimraf';
|
|||||||
import osm = require('os');
|
import osm = require('os');
|
||||||
|
|
||||||
import {Install, InstallSourceArchive, InstallSourceImage} from '../../src/docker/install';
|
import {Install, InstallSourceArchive, InstallSourceImage} from '../../src/docker/install';
|
||||||
|
import {Regctl} from '../../src/regclient/regctl';
|
||||||
|
import {Undock} from '../../src/undock/undock';
|
||||||
|
|
||||||
const tmpDir = fs.mkdtempSync(path.join(process.env.TEMP || os.tmpdir(), 'docker-install-'));
|
const tmpDir = fs.mkdtempSync(path.join(process.env.TEMP || os.tmpdir(), 'docker-install-'));
|
||||||
|
|
||||||
@@ -64,6 +66,8 @@ describe('download', () => {
|
|||||||
const install = new Install({
|
const install = new Install({
|
||||||
source: source,
|
source: source,
|
||||||
runDir: tmpDir,
|
runDir: tmpDir,
|
||||||
|
regctl: new Regctl(),
|
||||||
|
undock: new Undock()
|
||||||
});
|
});
|
||||||
const toolPath = await install.download();
|
const toolPath = await install.download();
|
||||||
expect(fs.existsSync(toolPath)).toBe(true);
|
expect(fs.existsSync(toolPath)).toBe(true);
|
||||||
|
|||||||
@@ -14,20 +14,6 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import fs from 'fs';
|
|
||||||
import os from 'os';
|
|
||||||
import path from 'path';
|
|
||||||
|
|
||||||
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-actions-toolkit-'));
|
|
||||||
|
|
||||||
process.env = Object.assign({}, process.env, {
|
|
||||||
TEMP: tmpDir,
|
|
||||||
RUNNER_TEMP: path.join(tmpDir, 'runner-temp'),
|
|
||||||
RUNNER_TOOL_CACHE: path.join(tmpDir, 'runner-tool-cache')
|
|
||||||
}) as {
|
|
||||||
[key: string]: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
testEnvironment: 'node',
|
testEnvironment: 'node',
|
||||||
moduleFileExtensions: ['js', 'ts'],
|
moduleFileExtensions: ['js', 'ts'],
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import * as core from '@actions/core';
|
|||||||
import {Buildx} from './buildx';
|
import {Buildx} from './buildx';
|
||||||
import {Exec} from '../exec';
|
import {Exec} from '../exec';
|
||||||
|
|
||||||
import {BuilderInfo, GCPolicy, NodeInfo} from '../types/buildx/builder';
|
import {BuilderInfo, Device, GCPolicy, NodeInfo} from '../types/buildx/builder';
|
||||||
|
|
||||||
export interface BuilderOpts {
|
export interface BuilderOpts {
|
||||||
buildx?: Buildx;
|
buildx?: Buildx;
|
||||||
@@ -89,6 +89,7 @@ export class Builder {
|
|||||||
let parsingType: string | undefined;
|
let parsingType: string | undefined;
|
||||||
let currentNode: NodeInfo = {};
|
let currentNode: NodeInfo = {};
|
||||||
let currentGCPolicy: GCPolicy | undefined;
|
let currentGCPolicy: GCPolicy | undefined;
|
||||||
|
let currentDevice: Device | undefined;
|
||||||
let currentFile: string | undefined;
|
let currentFile: string | undefined;
|
||||||
for (const line of data.trim().split(`\n`)) {
|
for (const line of data.trim().split(`\n`)) {
|
||||||
const [key, ...rest] = line.split(':');
|
const [key, ...rest] = line.split(':');
|
||||||
@@ -172,6 +173,10 @@ export class Builder {
|
|||||||
parsingType = 'label';
|
parsingType = 'label';
|
||||||
currentNode.labels = {};
|
currentNode.labels = {};
|
||||||
break;
|
break;
|
||||||
|
case lkey == 'devices':
|
||||||
|
parsingType = 'devices';
|
||||||
|
currentNode.devices = currentNode.devices || [];
|
||||||
|
break;
|
||||||
case lkey.startsWith('gc policy rule#'):
|
case lkey.startsWith('gc policy rule#'):
|
||||||
parsingType = 'gcpolicy';
|
parsingType = 'gcpolicy';
|
||||||
if (currentNode.gcPolicy && currentGCPolicy) {
|
if (currentNode.gcPolicy && currentGCPolicy) {
|
||||||
@@ -186,6 +191,10 @@ export class Builder {
|
|||||||
currentNode.files[currentFile] = '';
|
currentNode.files[currentFile] = '';
|
||||||
break;
|
break;
|
||||||
default: {
|
default: {
|
||||||
|
if (parsingType && parsingType !== 'devices' && currentNode.devices && currentDevice) {
|
||||||
|
currentNode.devices.push(currentDevice);
|
||||||
|
currentDevice = undefined;
|
||||||
|
}
|
||||||
switch (parsingType || '') {
|
switch (parsingType || '') {
|
||||||
case 'features': {
|
case 'features': {
|
||||||
currentNode.features = currentNode.features || {};
|
currentNode.features = currentNode.features || {};
|
||||||
@@ -197,6 +206,42 @@ export class Builder {
|
|||||||
currentNode.labels[key.trim()] = value;
|
currentNode.labels[key.trim()] = value;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'devices': {
|
||||||
|
switch (lkey.trim()) {
|
||||||
|
case 'name': {
|
||||||
|
if (currentNode.devices && currentDevice) {
|
||||||
|
currentNode.devices.push(currentDevice);
|
||||||
|
}
|
||||||
|
currentDevice = {};
|
||||||
|
currentDevice.name = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'on-demand': {
|
||||||
|
if (currentDevice && value) {
|
||||||
|
currentDevice.onDemand = value == 'true';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'automatically allowed': {
|
||||||
|
if (currentDevice && value) {
|
||||||
|
currentDevice.autoAllow = value == 'true';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'annotations': {
|
||||||
|
if (currentDevice) {
|
||||||
|
currentDevice.annotations = currentDevice.annotations || {};
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
if (currentDevice && currentDevice.annotations) {
|
||||||
|
currentDevice.annotations[key.trim()] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 'gcpolicy': {
|
case 'gcpolicy': {
|
||||||
currentNode.gcPolicy = currentNode.gcPolicy || [];
|
currentNode.gcPolicy = currentNode.gcPolicy || [];
|
||||||
currentGCPolicy = currentGCPolicy || {};
|
currentGCPolicy = currentGCPolicy || {};
|
||||||
@@ -219,6 +264,18 @@ export class Builder {
|
|||||||
currentGCPolicy.keepBytes = value;
|
currentGCPolicy.keepBytes = value;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'reserved space': {
|
||||||
|
currentGCPolicy.reservedSpace = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'max used space': {
|
||||||
|
currentGCPolicy.maxUsedSpace = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'min free space': {
|
||||||
|
currentGCPolicy.minFreeSpace = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -235,6 +292,9 @@ export class Builder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (currentDevice && currentNode.devices) {
|
||||||
|
currentNode.devices.push(currentDevice);
|
||||||
|
}
|
||||||
if (currentGCPolicy && currentNode.gcPolicy) {
|
if (currentGCPolicy && currentNode.gcPolicy) {
|
||||||
currentNode.gcPolicy.push(currentGCPolicy);
|
currentNode.gcPolicy.push(currentGCPolicy);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,11 +28,13 @@ import * as tc from '@actions/tool-cache';
|
|||||||
|
|
||||||
import {Context} from '../context';
|
import {Context} from '../context';
|
||||||
import {Docker} from './docker';
|
import {Docker} from './docker';
|
||||||
|
import {Regctl} from '../regclient/regctl';
|
||||||
|
import {Undock} from '../undock/undock';
|
||||||
import {Exec} from '../exec';
|
import {Exec} from '../exec';
|
||||||
import {Util} from '../util';
|
import {Util} from '../util';
|
||||||
import {limaYamlData, dockerServiceLogsPs1, setupDockerWinPs1} from './assets';
|
import {limaYamlData, dockerServiceLogsPs1, setupDockerWinPs1} from './assets';
|
||||||
|
|
||||||
import {GitHubRelease} from '../types/github';
|
import {GitHubRelease} from '../types/github';
|
||||||
import {HubRepository} from '../hubRepository';
|
|
||||||
import {Image} from '../types/oci/config';
|
import {Image} from '../types/oci/config';
|
||||||
|
|
||||||
export interface InstallSourceImage {
|
export interface InstallSourceImage {
|
||||||
@@ -57,6 +59,9 @@ export interface InstallOpts {
|
|||||||
daemonConfig?: string;
|
daemonConfig?: string;
|
||||||
rootless?: boolean;
|
rootless?: boolean;
|
||||||
localTCPPort?: number;
|
localTCPPort?: number;
|
||||||
|
|
||||||
|
regctl: Regctl;
|
||||||
|
undock: Undock;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface LimaImage {
|
interface LimaImage {
|
||||||
@@ -72,6 +77,8 @@ export class Install {
|
|||||||
private readonly daemonConfig?: string;
|
private readonly daemonConfig?: string;
|
||||||
private readonly rootless: boolean;
|
private readonly rootless: boolean;
|
||||||
private readonly localTCPPort?: number;
|
private readonly localTCPPort?: number;
|
||||||
|
private readonly regctl: Regctl;
|
||||||
|
private readonly undock: Undock;
|
||||||
|
|
||||||
private _version: string | undefined;
|
private _version: string | undefined;
|
||||||
private _toolDir: string | undefined;
|
private _toolDir: string | undefined;
|
||||||
@@ -91,36 +98,14 @@ export class Install {
|
|||||||
this.daemonConfig = opts.daemonConfig;
|
this.daemonConfig = opts.daemonConfig;
|
||||||
this.rootless = opts.rootless || false;
|
this.rootless = opts.rootless || false;
|
||||||
this.localTCPPort = opts.localTCPPort;
|
this.localTCPPort = opts.localTCPPort;
|
||||||
|
this.regctl = opts.regctl;
|
||||||
|
this.undock = opts.undock;
|
||||||
}
|
}
|
||||||
|
|
||||||
get toolDir(): string {
|
get toolDir(): string {
|
||||||
return this._toolDir || Context.tmpDir();
|
return this._toolDir || Context.tmpDir();
|
||||||
}
|
}
|
||||||
|
|
||||||
async downloadStaticArchive(component: 'docker' | 'docker-rootless-extras', src: InstallSourceArchive): Promise<string> {
|
|
||||||
const release: GitHubRelease = await Install.getRelease(src.version);
|
|
||||||
this._version = release.tag_name.replace(/^v+|v+$/g, '');
|
|
||||||
core.debug(`docker.Install.download version: ${this._version}`);
|
|
||||||
|
|
||||||
const downloadURL = this.downloadURL(component, this._version, src.channel);
|
|
||||||
core.info(`Downloading ${downloadURL}`);
|
|
||||||
|
|
||||||
const downloadPath = await tc.downloadTool(downloadURL);
|
|
||||||
core.debug(`docker.Install.download downloadPath: ${downloadPath}`);
|
|
||||||
|
|
||||||
let extractFolder;
|
|
||||||
if (os.platform() == 'win32') {
|
|
||||||
extractFolder = await tc.extractZip(downloadPath, extractFolder);
|
|
||||||
} else {
|
|
||||||
extractFolder = await tc.extractTar(downloadPath, extractFolder);
|
|
||||||
}
|
|
||||||
if (Util.isDirectory(path.join(extractFolder, component))) {
|
|
||||||
extractFolder = path.join(extractFolder, component);
|
|
||||||
}
|
|
||||||
core.debug(`docker.Install.download extractFolder: ${extractFolder}`);
|
|
||||||
return extractFolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async download(): Promise<string> {
|
public async download(): Promise<string> {
|
||||||
let extractFolder: string;
|
let extractFolder: string;
|
||||||
let cacheKey: string;
|
let cacheKey: string;
|
||||||
@@ -128,39 +113,9 @@ export class Install {
|
|||||||
|
|
||||||
switch (this.source.type) {
|
switch (this.source.type) {
|
||||||
case 'image': {
|
case 'image': {
|
||||||
const tag = this.source.tag;
|
this._version = this.source.tag;
|
||||||
this._version = tag;
|
|
||||||
cacheKey = `docker-image`;
|
cacheKey = `docker-image`;
|
||||||
|
extractFolder = await this.downloadSourceImage(platform);
|
||||||
core.info(`Downloading docker cli from dockereng/cli-bin:${tag}`);
|
|
||||||
const cli = await HubRepository.build('dockereng/cli-bin');
|
|
||||||
extractFolder = await cli.extractImage(tag);
|
|
||||||
|
|
||||||
const moby = await HubRepository.build('moby/moby-bin');
|
|
||||||
if (['win32', 'linux'].includes(platform)) {
|
|
||||||
core.info(`Downloading dockerd from moby/moby-bin:${tag}`);
|
|
||||||
await moby.extractImage(tag, extractFolder);
|
|
||||||
} else if (platform == 'darwin') {
|
|
||||||
// On macOS, the docker daemon binary will be downloaded inside the lima VM.
|
|
||||||
// However, we will get the exact git revision from the image config
|
|
||||||
// to get the matching systemd unit files.
|
|
||||||
core.info(`Getting git revision from moby/moby-bin:${tag}`);
|
|
||||||
|
|
||||||
// There's no macOS image for moby/moby-bin - a linux daemon is run inside lima.
|
|
||||||
const manifest = await moby.getPlatformManifest(tag, 'linux');
|
|
||||||
|
|
||||||
const config = await moby.getJSONBlob<Image>(manifest.config.digest);
|
|
||||||
core.debug(`Config ${JSON.stringify(config.config)}`);
|
|
||||||
|
|
||||||
this.gitCommit = config.config?.Labels?.['org.opencontainers.image.revision'];
|
|
||||||
if (!this.gitCommit) {
|
|
||||||
core.warning(`No git revision can be determined from the image. Will use master.`);
|
|
||||||
this.gitCommit = 'master';
|
|
||||||
}
|
|
||||||
core.info(`Git revision is ${this.gitCommit}`);
|
|
||||||
} else {
|
|
||||||
core.warning(`dockerd not supported on ${platform}, only the Docker cli will be available`);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'archive': {
|
case 'archive': {
|
||||||
@@ -170,10 +125,10 @@ export class Install {
|
|||||||
this._version = version;
|
this._version = version;
|
||||||
|
|
||||||
core.info(`Downloading Docker ${version} from ${this.source.channel} at download.docker.com`);
|
core.info(`Downloading Docker ${version} from ${this.source.channel} at download.docker.com`);
|
||||||
extractFolder = await this.downloadStaticArchive('docker', this.source);
|
extractFolder = await this.downloadSourceArchive('docker', this.source);
|
||||||
if (this.rootless) {
|
if (this.rootless) {
|
||||||
core.info(`Downloading Docker rootless extras ${version} from ${this.source.channel} at download.docker.com`);
|
core.info(`Downloading Docker rootless extras ${version} from ${this.source.channel} at download.docker.com`);
|
||||||
const extrasFolder = await this.downloadStaticArchive('docker-rootless-extras', this.source);
|
const extrasFolder = await this.downloadSourceArchive('docker-rootless-extras', this.source);
|
||||||
fs.readdirSync(extrasFolder).forEach(file => {
|
fs.readdirSync(extrasFolder).forEach(file => {
|
||||||
const src = path.join(extrasFolder, file);
|
const src = path.join(extrasFolder, file);
|
||||||
const dest = path.join(extractFolder, file);
|
const dest = path.join(extractFolder, file);
|
||||||
@@ -191,7 +146,9 @@ export class Install {
|
|||||||
}
|
}
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
files.forEach(function (file, index) {
|
files.forEach(function (file, index) {
|
||||||
fs.chmodSync(path.join(extractFolder, file), '0755');
|
if (!Util.isDirectory(path.join(extractFolder, file))) {
|
||||||
|
fs.chmodSync(path.join(extractFolder, file), '0755');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -203,6 +160,72 @@ export class Install {
|
|||||||
return tooldir;
|
return tooldir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async downloadSourceImage(platform: string): Promise<string> {
|
||||||
|
const dest = path.join(Context.tmpDir(), 'docker-install-image');
|
||||||
|
const cliImage = `dockereng/cli-bin:${this._version}`;
|
||||||
|
const engineImage = `moby/moby-bin:${this._version}`;
|
||||||
|
|
||||||
|
core.info(`Downloading Docker CLI from ${cliImage}`);
|
||||||
|
await this.undock.run({
|
||||||
|
source: cliImage,
|
||||||
|
dist: dest
|
||||||
|
});
|
||||||
|
|
||||||
|
if (['win32', 'linux'].includes(platform)) {
|
||||||
|
core.info(`Downloading Docker engine from ${engineImage}`);
|
||||||
|
await this.undock.run({
|
||||||
|
source: engineImage,
|
||||||
|
dist: dest
|
||||||
|
});
|
||||||
|
} else if (platform == 'darwin') {
|
||||||
|
// On macOS, the docker daemon binary will be downloaded inside the lima VM.
|
||||||
|
// However, we will get the exact git revision from the image config
|
||||||
|
// to get the matching systemd unit files. There's no macOS image for
|
||||||
|
// moby/moby-bin - a linux daemon is run inside lima.
|
||||||
|
try {
|
||||||
|
const engineImageConfig = await this.imageConfig(engineImage, 'linux/arm64');
|
||||||
|
core.debug(`docker.Install.downloadSourceImage engineImageConfig: ${JSON.stringify(engineImageConfig)}`);
|
||||||
|
this.gitCommit = engineImageConfig.config?.Labels?.['org.opencontainers.image.revision'];
|
||||||
|
if (!this.gitCommit) {
|
||||||
|
throw new Error(`No git revision can be determined from the image`);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
core.warning(e);
|
||||||
|
this.gitCommit = 'master';
|
||||||
|
}
|
||||||
|
|
||||||
|
core.debug(`docker.Install.downloadSourceImage gitCommit: ${this.gitCommit}`);
|
||||||
|
} else {
|
||||||
|
core.warning(`Docker engine not supported on ${platform}, only the Docker cli will be available`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async downloadSourceArchive(component: 'docker' | 'docker-rootless-extras', src: InstallSourceArchive): Promise<string> {
|
||||||
|
const release: GitHubRelease = await Install.getRelease(src.version);
|
||||||
|
this._version = release.tag_name.replace(/^v+|v+$/g, '');
|
||||||
|
core.debug(`docker.Install.downloadSourceArchive version: ${this._version}`);
|
||||||
|
|
||||||
|
const downloadURL = this.downloadURL(component, this._version, src.channel);
|
||||||
|
core.info(`Downloading ${downloadURL}`);
|
||||||
|
|
||||||
|
const downloadPath = await tc.downloadTool(downloadURL);
|
||||||
|
core.debug(`docker.Install.downloadSourceArchive downloadPath: ${downloadPath}`);
|
||||||
|
|
||||||
|
let extractFolder;
|
||||||
|
if (os.platform() == 'win32') {
|
||||||
|
extractFolder = await tc.extractZip(downloadPath, extractFolder);
|
||||||
|
} else {
|
||||||
|
extractFolder = await tc.extractTar(downloadPath, extractFolder);
|
||||||
|
}
|
||||||
|
if (Util.isDirectory(path.join(extractFolder, component))) {
|
||||||
|
extractFolder = path.join(extractFolder, component);
|
||||||
|
}
|
||||||
|
core.debug(`docker.Install.downloadSourceArchive extractFolder: ${extractFolder}`);
|
||||||
|
return extractFolder;
|
||||||
|
}
|
||||||
|
|
||||||
public async install(): Promise<string> {
|
public async install(): Promise<string> {
|
||||||
if (!this.toolDir) {
|
if (!this.toolDir) {
|
||||||
throw new Error('toolDir must be set. Run download first.');
|
throw new Error('toolDir must be set. Run download first.');
|
||||||
@@ -709,4 +732,20 @@ EOF`,
|
|||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async imageConfig(image: string, platform?: string): Promise<Image> {
|
||||||
|
const manifest = await this.regctl.manifestGet({
|
||||||
|
image: image,
|
||||||
|
platform: platform
|
||||||
|
});
|
||||||
|
const configDigest = manifest?.config?.digest;
|
||||||
|
if (!configDigest) {
|
||||||
|
throw new Error(`No config digest found for image ${image}`);
|
||||||
|
}
|
||||||
|
const blob = await this.regctl.blobGet({
|
||||||
|
repository: image,
|
||||||
|
digest: configDigest
|
||||||
|
});
|
||||||
|
return <Image>JSON.parse(blob);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,174 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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 httpm from '@actions/http-client';
|
|
||||||
import {Index} from './types/oci';
|
|
||||||
import os from 'os';
|
|
||||||
import * as core from '@actions/core';
|
|
||||||
import {Manifest} from './types/oci/manifest';
|
|
||||||
import * as tc from '@actions/tool-cache';
|
|
||||||
import fs from 'fs';
|
|
||||||
import {MEDIATYPE_IMAGE_CONFIG_V1, MEDIATYPE_IMAGE_INDEX_V1, MEDIATYPE_IMAGE_MANIFEST_V1} from './types/oci/mediatype';
|
|
||||||
import {MEDIATYPE_IMAGE_CONFIG_V1 as DOCKER_MEDIATYPE_IMAGE_CONFIG_V1, MEDIATYPE_IMAGE_MANIFEST_LIST_V2, MEDIATYPE_IMAGE_MANIFEST_V2} from './types/docker/mediatype';
|
|
||||||
import {DockerHub} from './dockerhub';
|
|
||||||
|
|
||||||
export class HubRepository {
|
|
||||||
private repo: string;
|
|
||||||
private token: string;
|
|
||||||
private static readonly http: httpm.HttpClient = new httpm.HttpClient('setup-docker-action');
|
|
||||||
|
|
||||||
private constructor(repository: string, token: string) {
|
|
||||||
this.repo = repository;
|
|
||||||
this.token = token;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async build(repository: string): Promise<HubRepository> {
|
|
||||||
const token = await this.getToken(repository);
|
|
||||||
return new HubRepository(repository, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getPlatformManifest(tagOrDigest: string, os?: string): Promise<Manifest> {
|
|
||||||
const index = await this.getManifest<Index>(tagOrDigest);
|
|
||||||
if (index.mediaType != MEDIATYPE_IMAGE_INDEX_V1 && index.mediaType != MEDIATYPE_IMAGE_MANIFEST_LIST_V2) {
|
|
||||||
core.error(`Unsupported image media type: ${index.mediaType}`);
|
|
||||||
throw new Error(`Unsupported image media type: ${index.mediaType}`);
|
|
||||||
}
|
|
||||||
const digest = HubRepository.getPlatformManifestDigest(index, os);
|
|
||||||
return await this.getManifest<Manifest>(digest);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unpacks the image layers and returns the path to the extracted image.
|
|
||||||
// Only OCI indexes/manifest list are supported for now.
|
|
||||||
public async extractImage(tag: string, destDir?: string): Promise<string> {
|
|
||||||
const manifest = await this.getPlatformManifest(tag);
|
|
||||||
|
|
||||||
const paths = manifest.layers.map(async layer => {
|
|
||||||
const url = this.blobUrl(layer.digest);
|
|
||||||
|
|
||||||
return await tc.downloadTool(url, undefined, undefined, {
|
|
||||||
authorization: `Bearer ${this.token}`
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
let files = await Promise.all(paths);
|
|
||||||
let extractFolder: string;
|
|
||||||
if (!destDir) {
|
|
||||||
extractFolder = await tc.extractTar(files[0]);
|
|
||||||
files = files.slice(1);
|
|
||||||
} else {
|
|
||||||
extractFolder = destDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
await Promise.all(
|
|
||||||
files.map(async file => {
|
|
||||||
return await tc.extractTar(file, extractFolder);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
fs.readdirSync(extractFolder).forEach(file => {
|
|
||||||
core.info(`extractImage(${this.repo}:${tag}) file: ${file}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
return extractFolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async getToken(repo: string): Promise<string> {
|
|
||||||
const url = `https://auth.docker.io/token?service=registry.docker.io&scope=repository:${repo}:pull`;
|
|
||||||
|
|
||||||
const resp = await this.http.get(url);
|
|
||||||
const body = await resp.readBody();
|
|
||||||
const statusCode = resp.message.statusCode || 500;
|
|
||||||
if (statusCode != 200) {
|
|
||||||
throw DockerHub.parseError(resp, body);
|
|
||||||
}
|
|
||||||
|
|
||||||
const json = JSON.parse(body);
|
|
||||||
return json.token;
|
|
||||||
}
|
|
||||||
|
|
||||||
private blobUrl(digest: string): string {
|
|
||||||
return `https://registry-1.docker.io/v2/${this.repo}/blobs/${digest}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getManifest<T>(tagOrDigest: string): Promise<T> {
|
|
||||||
return await this.registryGet<T>(tagOrDigest, 'manifests', [MEDIATYPE_IMAGE_INDEX_V1, MEDIATYPE_IMAGE_MANIFEST_LIST_V2, MEDIATYPE_IMAGE_MANIFEST_V1, MEDIATYPE_IMAGE_MANIFEST_V2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getJSONBlob<T>(tagOrDigest: string): Promise<T> {
|
|
||||||
return await this.registryGet<T>(tagOrDigest, 'blobs', [MEDIATYPE_IMAGE_CONFIG_V1, DOCKER_MEDIATYPE_IMAGE_CONFIG_V1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async registryGet<T>(tagOrDigest: string, endpoint: 'manifests' | 'blobs', accept: Array<string>): Promise<T> {
|
|
||||||
const url = `https://registry-1.docker.io/v2/${this.repo}/${endpoint}/${tagOrDigest}`;
|
|
||||||
|
|
||||||
const headers = {
|
|
||||||
Authorization: `Bearer ${this.token}`,
|
|
||||||
Accept: accept.join(', ')
|
|
||||||
};
|
|
||||||
|
|
||||||
const resp = await HubRepository.http.get(url, headers);
|
|
||||||
const body = await resp.readBody();
|
|
||||||
const statusCode = resp.message.statusCode || 500;
|
|
||||||
if (statusCode != 200) {
|
|
||||||
core.error(`registryGet(${this.repo}:${tagOrDigest}) failed: ${statusCode} ${body}`);
|
|
||||||
throw DockerHub.parseError(resp, body);
|
|
||||||
}
|
|
||||||
|
|
||||||
return <T>JSON.parse(body);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static getPlatformManifestDigest(index: Index, osOverride?: string): string {
|
|
||||||
// This doesn't handle all possible platforms normalizations, but it's good enough for now.
|
|
||||||
let pos: string = osOverride || os.platform();
|
|
||||||
if (pos == 'win32') {
|
|
||||||
pos = 'windows';
|
|
||||||
}
|
|
||||||
let arch = os.arch();
|
|
||||||
if (arch == 'x64') {
|
|
||||||
arch = 'amd64';
|
|
||||||
}
|
|
||||||
let variant = '';
|
|
||||||
if (arch == 'arm') {
|
|
||||||
variant = 'v7';
|
|
||||||
}
|
|
||||||
|
|
||||||
const manifest = index.manifests.find(m => {
|
|
||||||
if (!m.platform) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (m.platform.os != pos) {
|
|
||||||
core.debug(`Skipping manifest ${m.digest} because of os: ${m.platform.os} != ${pos}`);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (m.platform.architecture != arch) {
|
|
||||||
core.debug(`Skipping manifest ${m.digest} because of arch: ${m.platform.architecture} != ${arch}`);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ((m.platform.variant || '') != variant) {
|
|
||||||
core.debug(`Skipping manifest ${m.digest} because of variant: ${m.platform.variant} != ${variant}`);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
if (!manifest) {
|
|
||||||
core.error(`Cannot find manifest for ${pos}/${arch}/${variant}`);
|
|
||||||
throw new Error(`Cannot find manifest for ${pos}/${arch}/${variant}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return manifest.digest;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -34,13 +34,24 @@ export interface NodeInfo extends Node {
|
|||||||
buildkit?: string;
|
buildkit?: string;
|
||||||
features?: Record<string, boolean>;
|
features?: Record<string, boolean>;
|
||||||
labels?: Record<string, string>;
|
labels?: Record<string, string>;
|
||||||
|
devices?: Array<Device>;
|
||||||
gcPolicy?: Array<GCPolicy>;
|
gcPolicy?: Array<GCPolicy>;
|
||||||
files?: Record<string, string>;
|
files?: Record<string, string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Device {
|
||||||
|
name?: string;
|
||||||
|
annotations?: Record<string, string>;
|
||||||
|
autoAllow?: boolean;
|
||||||
|
onDemand?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface GCPolicy {
|
export interface GCPolicy {
|
||||||
all?: boolean;
|
all?: boolean;
|
||||||
filter?: string[];
|
filter?: string[];
|
||||||
keepDuration?: string;
|
keepDuration?: string;
|
||||||
keepBytes?: string;
|
keepBytes?: string; // deprecated, use reservedSpace instead
|
||||||
|
reservedSpace?: string;
|
||||||
|
maxUsedSpace?: string;
|
||||||
|
minFreeSpace?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user