mirror of
https://github.com/DeterminateSystems/nix-installer-action.git
synced 2025-01-10 22:32:06 +01:00
Don't use docker shim if only using a mounted docker.sock instead of docker-in-docker
This commit is contained in:
parent
ffea801f30
commit
f4a0ffe230
3 changed files with 203 additions and 2 deletions
89
dist/index.js
generated
vendored
89
dist/index.js
generated
vendored
|
@ -130,6 +130,11 @@ class NixInstallerAction {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!this.force_docker_shim &&
|
||||||
|
(await this.detectDockerWithMountedDockerSocket())) {
|
||||||
|
_actions_core__WEBPACK_IMPORTED_MODULE_0__.debug("Detected a Docker container with a Docker socket mounted, not enabling docker shim.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_0__.startGroup("Enabling the Docker shim for running Nix on Linux in CI without Systemd.");
|
_actions_core__WEBPACK_IMPORTED_MODULE_0__.startGroup("Enabling the Docker shim for running Nix on Linux in CI without Systemd.");
|
||||||
if (this.init !== "none") {
|
if (this.init !== "none") {
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_0__.info(`Changing init from '${this.init}' to 'none'`);
|
_actions_core__WEBPACK_IMPORTED_MODULE_0__.info(`Changing init from '${this.init}' to 'none'`);
|
||||||
|
@ -142,6 +147,90 @@ class NixInstallerAction {
|
||||||
this.force_docker_shim = true;
|
this.force_docker_shim = true;
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_0__.endGroup();
|
_actions_core__WEBPACK_IMPORTED_MODULE_0__.endGroup();
|
||||||
}
|
}
|
||||||
|
// Detect if we are running under `act` or some other system which is not using docker-in-docker,
|
||||||
|
// and instead using a mounted docker socket.
|
||||||
|
// In the case of the socket mount solution, the shim will cause issues since the given mount paths will
|
||||||
|
// equate to mount paths on the host, not mount paths to the docker container in question.
|
||||||
|
async detectDockerWithMountedDockerSocket() {
|
||||||
|
let cgroups_buffer;
|
||||||
|
try {
|
||||||
|
// If we are inside a docker container, the last line of `/proc/self/cgroup` should be
|
||||||
|
// 0::/docker/$SOME_ID
|
||||||
|
//
|
||||||
|
// If we are not, the line will likely be `0::/`
|
||||||
|
cgroups_buffer = await (0,node_fs_promises__WEBPACK_IMPORTED_MODULE_4__.readFile)("/proc/self/cgroup", {
|
||||||
|
encoding: "utf-8",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
_actions_core__WEBPACK_IMPORTED_MODULE_0__.debug(`Did not detect \`/proc/self/cgroup\` existence, bailing on docker container ID detection:\n${e}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const cgroups = cgroups_buffer.trim().split("\n");
|
||||||
|
const last_cgroup = cgroups[cgroups.length - 1];
|
||||||
|
const last_cgroup_parts = last_cgroup.split(":");
|
||||||
|
const last_cgroup_path = last_cgroup_parts[last_cgroup_parts.length - 1];
|
||||||
|
if (!last_cgroup_path.includes("/docker/")) {
|
||||||
|
_actions_core__WEBPACK_IMPORTED_MODULE_0__.debug("Did not detect a container ID, bailing on docker.sock detection");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// We are in a docker container, now to determine if this container is visible from
|
||||||
|
// the `docker` command, and if so, if there is a `docker.socket` mounted.
|
||||||
|
const last_cgroup_path_parts = last_cgroup_path.split("/");
|
||||||
|
const container_id = last_cgroup_path_parts[last_cgroup_path_parts.length - 1];
|
||||||
|
// If we cannot `docker inspect` this discovered container ID, we'll fall through to the `catch` below.
|
||||||
|
let stdout_buffer = "";
|
||||||
|
let stderr_buffer = "";
|
||||||
|
let exit_code;
|
||||||
|
try {
|
||||||
|
exit_code = await _actions_exec__WEBPACK_IMPORTED_MODULE_3__.exec("docker", ["inspect", container_id], {
|
||||||
|
silent: true,
|
||||||
|
listeners: {
|
||||||
|
stdout: (data) => {
|
||||||
|
stdout_buffer += data.toString("utf-8");
|
||||||
|
},
|
||||||
|
stderr: (data) => {
|
||||||
|
stderr_buffer += data.toString("utf-8");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
_actions_core__WEBPACK_IMPORTED_MODULE_0__.debug(`Could not execute \`docker inspect ${container_id}\`, bailing on docker container inspection:\n${e}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (exit_code !== 0) {
|
||||||
|
_actions_core__WEBPACK_IMPORTED_MODULE_0__.debug(`Unable to inspect detected docker container with id \`${container_id}\`, bailing on container inspection (exit ${exit_code}):\n${stderr_buffer}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const output = JSON.parse(stdout_buffer);
|
||||||
|
// `docker inspect $ID` prints an array containing objects.
|
||||||
|
// In our use case, we should only see 1 item in the array.
|
||||||
|
if (output.length !== 1) {
|
||||||
|
_actions_core__WEBPACK_IMPORTED_MODULE_0__.debug(`Got \`docker inspect ${container_id}\` output which was not one item (was ${output.length}), bailing on docker.sock detection.`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const item = output[0];
|
||||||
|
// On this array item we want the `Mounts` field, which is an array
|
||||||
|
// containing `{ Type, Source, Destination, Mode}`.
|
||||||
|
// We are looking for a `Destination` ending with `docker.sock`.
|
||||||
|
const mounts = item["Mounts"];
|
||||||
|
if (typeof mounts !== "object") {
|
||||||
|
_actions_core__WEBPACK_IMPORTED_MODULE_0__.debug(`Got non-object in \`Mounts\` field of \`docker inspect ${container_id}\` output, bailing on docker.sock detection.`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let found_docker_sock_mount = false;
|
||||||
|
for (const mount of mounts) {
|
||||||
|
const destination = mount["Destination"];
|
||||||
|
if (typeof destination === "string") {
|
||||||
|
if (destination.endsWith("docker.sock")) {
|
||||||
|
found_docker_sock_mount = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return found_docker_sock_mount;
|
||||||
|
}
|
||||||
async executionEnvironment() {
|
async executionEnvironment() {
|
||||||
const execution_env = {};
|
const execution_env = {};
|
||||||
execution_env.NIX_INSTALLER_NO_CONFIRM = "true";
|
execution_env.NIX_INSTALLER_NO_CONFIRM = "true";
|
||||||
|
|
2
dist/index.js.map
generated
vendored
2
dist/index.js.map
generated
vendored
File diff suppressed because one or more lines are too long
114
src/main.ts
114
src/main.ts
|
@ -2,7 +2,7 @@ import * as actions_core from "@actions/core";
|
||||||
import * as github from "@actions/github";
|
import * as github from "@actions/github";
|
||||||
import * as actions_tool_cache from "@actions/tool-cache";
|
import * as actions_tool_cache from "@actions/tool-cache";
|
||||||
import * as actions_exec from "@actions/exec";
|
import * as actions_exec from "@actions/exec";
|
||||||
import { chmod, access, writeFile } from "node:fs/promises";
|
import { chmod, access, writeFile, readFile } from "node:fs/promises";
|
||||||
import { randomUUID } from "node:crypto";
|
import { randomUUID } from "node:crypto";
|
||||||
import { join } from "node:path";
|
import { join } from "node:path";
|
||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
|
@ -164,6 +164,16 @@ class NixInstallerAction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
!this.force_docker_shim &&
|
||||||
|
(await this.detectDockerWithMountedDockerSocket())
|
||||||
|
) {
|
||||||
|
actions_core.debug(
|
||||||
|
"Detected a Docker container with a Docker socket mounted, not enabling docker shim.",
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
actions_core.startGroup(
|
actions_core.startGroup(
|
||||||
"Enabling the Docker shim for running Nix on Linux in CI without Systemd.",
|
"Enabling the Docker shim for running Nix on Linux in CI without Systemd.",
|
||||||
);
|
);
|
||||||
|
@ -182,6 +192,108 @@ class NixInstallerAction {
|
||||||
actions_core.endGroup();
|
actions_core.endGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Detect if we are running under `act` or some other system which is not using docker-in-docker,
|
||||||
|
// and instead using a mounted docker socket.
|
||||||
|
// In the case of the socket mount solution, the shim will cause issues since the given mount paths will
|
||||||
|
// equate to mount paths on the host, not mount paths to the docker container in question.
|
||||||
|
async detectDockerWithMountedDockerSocket(): Promise<boolean> {
|
||||||
|
let cgroups_buffer;
|
||||||
|
try {
|
||||||
|
// If we are inside a docker container, the last line of `/proc/self/cgroup` should be
|
||||||
|
// 0::/docker/$SOME_ID
|
||||||
|
//
|
||||||
|
// If we are not, the line will likely be `0::/`
|
||||||
|
cgroups_buffer = await readFile("/proc/self/cgroup", {
|
||||||
|
encoding: "utf-8",
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
actions_core.debug(
|
||||||
|
`Did not detect \`/proc/self/cgroup\` existence, bailing on docker container ID detection:\n${e}`,
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cgroups = cgroups_buffer.trim().split("\n");
|
||||||
|
const last_cgroup = cgroups[cgroups.length - 1];
|
||||||
|
const last_cgroup_parts = last_cgroup.split(":");
|
||||||
|
const last_cgroup_path = last_cgroup_parts[last_cgroup_parts.length - 1];
|
||||||
|
if (!last_cgroup_path.includes("/docker/")) {
|
||||||
|
actions_core.debug(
|
||||||
|
"Did not detect a container ID, bailing on docker.sock detection",
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// We are in a docker container, now to determine if this container is visible from
|
||||||
|
// the `docker` command, and if so, if there is a `docker.socket` mounted.
|
||||||
|
const last_cgroup_path_parts = last_cgroup_path.split("/");
|
||||||
|
const container_id =
|
||||||
|
last_cgroup_path_parts[last_cgroup_path_parts.length - 1];
|
||||||
|
|
||||||
|
// If we cannot `docker inspect` this discovered container ID, we'll fall through to the `catch` below.
|
||||||
|
let stdout_buffer = "";
|
||||||
|
let stderr_buffer = "";
|
||||||
|
let exit_code;
|
||||||
|
try {
|
||||||
|
exit_code = await actions_exec.exec("docker", ["inspect", container_id], {
|
||||||
|
silent: true,
|
||||||
|
listeners: {
|
||||||
|
stdout: (data: Buffer) => {
|
||||||
|
stdout_buffer += data.toString("utf-8");
|
||||||
|
},
|
||||||
|
stderr: (data: Buffer) => {
|
||||||
|
stderr_buffer += data.toString("utf-8");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
actions_core.debug(
|
||||||
|
`Could not execute \`docker inspect ${container_id}\`, bailing on docker container inspection:\n${e}`,
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exit_code !== 0) {
|
||||||
|
actions_core.debug(
|
||||||
|
`Unable to inspect detected docker container with id \`${container_id}\`, bailing on container inspection (exit ${exit_code}):\n${stderr_buffer}`,
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const output = JSON.parse(stdout_buffer);
|
||||||
|
// `docker inspect $ID` prints an array containing objects.
|
||||||
|
// In our use case, we should only see 1 item in the array.
|
||||||
|
if (output.length !== 1) {
|
||||||
|
actions_core.debug(
|
||||||
|
`Got \`docker inspect ${container_id}\` output which was not one item (was ${output.length}), bailing on docker.sock detection.`,
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const item = output[0];
|
||||||
|
// On this array item we want the `Mounts` field, which is an array
|
||||||
|
// containing `{ Type, Source, Destination, Mode}`.
|
||||||
|
// We are looking for a `Destination` ending with `docker.sock`.
|
||||||
|
const mounts = item["Mounts"];
|
||||||
|
if (typeof mounts !== "object") {
|
||||||
|
actions_core.debug(
|
||||||
|
`Got non-object in \`Mounts\` field of \`docker inspect ${container_id}\` output, bailing on docker.sock detection.`,
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let found_docker_sock_mount = false;
|
||||||
|
for (const mount of mounts) {
|
||||||
|
const destination = mount["Destination"];
|
||||||
|
if (typeof destination === "string") {
|
||||||
|
if (destination.endsWith("docker.sock")) {
|
||||||
|
found_docker_sock_mount = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return found_docker_sock_mount;
|
||||||
|
}
|
||||||
|
|
||||||
private async executionEnvironment(): Promise<ExecuteEnvironment> {
|
private async executionEnvironment(): Promise<ExecuteEnvironment> {
|
||||||
const execution_env: ExecuteEnvironment = {};
|
const execution_env: ExecuteEnvironment = {};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue