KVM support out of the box, plus a refreshed README (#56)

* support kvm

* Refresh the readme

* Update README.md

Co-authored-by: Ana Hobden <operator@hoverbear.org>

* Update README.md

Co-authored-by: Luc Perkins <lucperkins@gmail.com>

* Update README.md

---------

Co-authored-by: Ana Hobden <operator@hoverbear.org>
Co-authored-by: Luc Perkins <lucperkins@gmail.com>
This commit is contained in:
Graham Christensen 2023-11-21 14:06:06 -05:00 committed by GitHub
parent 5620eb4af6
commit 07b8bcba1b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 240 additions and 15 deletions

View file

@ -1,6 +1,19 @@
# Nix Installer Action # The Determinate Nix Installer Action
You can use [`nix-installer`](https://github.com/DeterminateSystems/nix-installer) as a Github action like so: Based on the [Determinate Nix Installer](https://github.com/DeterminateSystems/nix-installer), responsible for over tens of thousands of Nix installs daily.
The fast, friendly, and reliable GitHub Action to install Nix with Flakes.
## Supports
* ✅ **Accelerated KVM** on open source projects and larger runners. See [GitHub's announcement](https://github.blog/changelog/2023-02-23-hardware-accelerated-android-virtualization-on-actions-windows-and-linux-larger-hosted-runners/) for more info.
* ✅ Linux, x86_64, aarch64, and i686
* ✅ macOS, x86_64 and aarch64
* ✅ WSL2, x86_64 and aarch64
* ✅ Containers
* ✅ Valve's SteamOS
* ✅ GitHub Hosted, self-hosted, and long running Actions Runners
## Usage
```yaml ```yaml
on: on:
@ -11,18 +24,16 @@ on:
jobs: jobs:
lints: lints:
name: Build name: Build
runs-on: ubuntu-22.04 runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Install Nix - uses: DeterminateSystems/nix-installer-action@main
uses: DeterminateSystems/nix-installer-action@main - run: nix build .
- name: Run `nix build`
run: nix build .
``` ```
See [`.github/workflows/ci.yml`](.github/workflows/ci.yml) for a full example. ### With FlakeHub
To use private flakes from FlakeHub, use a configuration like this: To fetch private flakes from FlakeHub, update the `permissions` block and pass `flakehub: true`:
```yaml ```yaml
on: on:
@ -33,20 +44,42 @@ on:
jobs: jobs:
lints: lints:
name: Build name: Build
runs-on: ubuntu-22.04 runs-on: ubuntu-latest
permissions: permissions:
id-token: "write" id-token: "write"
contents: "read" contents: "read"
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Install Nix - uses: DeterminateSystems/nix-installer-action@main
uses: DeterminateSystems/nix-installer-action@main
with: with:
flakehub: true flakehub: true
- name: Run `nix build` - run: nix build .
run: nix build .
``` ```
See [`.github/workflows/ci.yml`](.github/workflows/ci.yml) for a full example.
### Advanced Usage
* If KVM is available, the installer sets up KVM so that Nix can use it ,and exports the `DETERMINATE_NIX_KVM` environment variable set to 1.
If KVM is not available, `DETERMINATE_NIX_KVM` is set to 0.
This can be used in combination with GitHub Actions' `if` syntax for turning on and off steps.
## Installation Differences
Differing from the upstream [Nix](https://github.com/NixOS/nix) installer scripts:
* In `nix.conf`:
+ the `nix-command` and `flakes` features are enabled
+ `bash-prompt-prefix` is set
+ `auto-optimise-store` is set to `true` (On Linux only)
* `extra-nix-path` is set to `nixpkgs=flake:nixpkgs`
* `max-jobs` is set to `auto`
* KVM is enabled by default.
* an installation receipt (for uninstalling) is stored at `/nix/receipt.json` as well as a copy of the install binary at `/nix/nix-installer`
* `nix-channel --update` is not run, `~/.nix-channels` is not provisioned
* `ssl-cert-file` is set in `/etc/nix/nix.conf` if the `ssl-cert-file` argument is used.
## Configuration ## Configuration
| Parameter | Description | Type | Default | | Parameter | Description | Type | Default |
@ -57,6 +90,7 @@ jobs:
| `flakehub` | Log in to FlakeHub to pull private flakes using the GitHub Actions [JSON Web Token](https://jwt.io) (JWT), which is bound to the `api.flakehub.com` audience. | Boolean | `false` | | `flakehub` | Log in to FlakeHub to pull private flakes using the GitHub Actions [JSON Web Token](https://jwt.io) (JWT), which is bound to the `api.flakehub.com` audience. | Boolean | `false` |
| `github-token` | A [GitHub token] for making authenticated requests (which have a higher rate-limit quota than unauthenticated requests) | string | `${{ github.token }}` | | `github-token` | A [GitHub token] for making authenticated requests (which have a higher rate-limit quota than unauthenticated requests) | string | `${{ github.token }}` |
| `init` | The init system to configure (requires `planner: linux-multi`) | enum (`none` or `systemd`) | | | `init` | The init system to configure (requires `planner: linux-multi`) | enum (`none` or `systemd`) | |
| `kvm` | Automatically configure the GitHub Actions Runner for NixOS test support, if the host supports it. | Boolean | `true` |
| `local-root` | A local `nix-installer` binary root. Overrides the `nix-installer-url` setting (a `nix-installer.sh` should exist, binaries should be named `nix-installer-$ARCH`, eg. `nix-installer-x86_64-linux`). | Boolean | `false` | | `local-root` | A local `nix-installer` binary root. Overrides the `nix-installer-url` setting (a `nix-installer.sh` should exist, binaries should be named `nix-installer-$ARCH`, eg. `nix-installer-x86_64-linux`). | Boolean | `false` |
| `log-directives` | A list of [tracing directives], comma separated with `-`s replaced with `_` (eg. `nix_installer=trace`) | string | | | `log-directives` | A list of [tracing directives], comma separated with `-`s replaced with `_` (eg. `nix_installer=trace`) | string | |
| `logger` | The logger to use during installation | enum (`pretty`, `json`, `full`, `compact`) | | | `logger` | The logger to use during installation | enum (`pretty`, `json`, `full`, `compact`) | |

View file

@ -23,6 +23,10 @@ inputs:
init: init:
description: "The init system to configure, requires `planner: linux-multi` (allowing the choice between `none` or `systemd`)" description: "The init system to configure, requires `planner: linux-multi` (allowing the choice between `none` or `systemd`)"
required: false required: false
kvm:
description: Automatically configure the GitHub Actions Runner for NixOS test supports, if the host supports it.
required: false
default: true
local-root: local-root:
description: A local `nix-installer` binary root, overrides any settings which change the `nix-installer` used (binaries should be named `nix-installer-$ARCH-$OS`, eg. `nix-installer-x86_64-linux`) description: A local `nix-installer` binary root, overrides any settings which change the `nix-installer` used (binaries should be named `nix-installer-$ARCH-$OS`, eg. `nix-installer-x86_64-linux`)
required: false required: false

81
dist/index.js vendored
View file

@ -41,6 +41,7 @@ class NixInstallerAction {
this.extra_args = action_input_string_or_null("extra-args"); this.extra_args = action_input_string_or_null("extra-args");
this.extra_conf = action_input_multiline_string_or_null("extra-conf"); this.extra_conf = action_input_multiline_string_or_null("extra-conf");
this.flakehub = action_input_bool("flakehub"); this.flakehub = action_input_bool("flakehub");
this.kvm = action_input_bool("kvm");
this.github_token = action_input_string_or_null("github-token"); this.github_token = action_input_string_or_null("github-token");
this.init = action_input_string_or_null("init"); this.init = action_input_string_or_null("init");
this.local_root = action_input_string_or_null("local-root"); this.local_root = action_input_string_or_null("local-root");
@ -236,6 +237,20 @@ class NixInstallerAction {
return; return;
} }
} }
if (this.kvm) {
_actions_core__WEBPACK_IMPORTED_MODULE_0__.startGroup("Configuring KVM");
if (await this.setup_kvm()) {
_actions_core__WEBPACK_IMPORTED_MODULE_0__.endGroup();
_actions_core__WEBPACK_IMPORTED_MODULE_0__.info("\u001b[32m Accelerated KVM is enabled \u001b[33m⚡");
_actions_core__WEBPACK_IMPORTED_MODULE_0__.exportVariable("DETERMINATE_NIX_KVM", "1");
}
else {
_actions_core__WEBPACK_IMPORTED_MODULE_0__.endGroup();
_actions_core__WEBPACK_IMPORTED_MODULE_0__.info("KVM is not available.");
_actions_core__WEBPACK_IMPORTED_MODULE_0__.exportVariable("DETERMINATE_NIX_KVM", "0");
}
_actions_core__WEBPACK_IMPORTED_MODULE_0__.exportVariable("DETERMINATE_NIX_KVM", "0");
}
// Normal just doing of the install // Normal just doing of the install
const binary_path = await this.fetch_binary(); const binary_path = await this.fetch_binary();
await this.execute_install(binary_path); await this.execute_install(binary_path);
@ -305,6 +320,72 @@ class NixInstallerAction {
return false; return false;
} }
} }
async setup_kvm() {
const kvm_rules = "/etc/udev/rules.d/99-determinate-nix-installer-kvm.rules";
try {
const write_file_exit_code = await _actions_exec__WEBPACK_IMPORTED_MODULE_3__.exec("sh", [
"-c",
`echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee ${kvm_rules} > /dev/null`,
], {
listeners: {
stderr: (data) => {
const trimmed = data.toString("utf-8").trimEnd();
if (trimmed.length >= 0) {
_actions_core__WEBPACK_IMPORTED_MODULE_0__.debug(trimmed);
}
},
},
});
if (write_file_exit_code !== 0) {
throw new Error(`Non-zero exit code of \`${write_file_exit_code}\` detected while writing '${kvm_rules}'`);
}
const debug_run_throw = async (action, command, args) => {
const reload_exit_code = await _actions_exec__WEBPACK_IMPORTED_MODULE_3__.exec(command, args, {
listeners: {
stdout: (data) => {
const trimmed = data.toString("utf-8").trimEnd();
if (trimmed.length >= 0) {
_actions_core__WEBPACK_IMPORTED_MODULE_0__.debug(trimmed);
}
},
stderr: (data) => {
const trimmed = data.toString("utf-8").trimEnd();
if (trimmed.length >= 0) {
_actions_core__WEBPACK_IMPORTED_MODULE_0__.debug(trimmed);
}
},
},
});
if (reload_exit_code !== 0) {
throw new Error(`Non-zero exit code of \`${reload_exit_code}\` detected while ${action}.`);
}
};
await debug_run_throw("reloading udev rules", `sudo`, [
"udevadm",
"control",
"--reload-rules",
]);
await debug_run_throw("triggering udev against kvm", `sudo`, [
"udevadm",
"trigger",
"--name-match=kvm",
]);
return true;
}
catch (error) {
await _actions_exec__WEBPACK_IMPORTED_MODULE_3__.exec("sudo", ["rm", "-f", kvm_rules], {
listeners: {
stderr: (data) => {
const trimmed = data.toString("utf-8").trimEnd();
if (trimmed.length >= 0) {
_actions_core__WEBPACK_IMPORTED_MODULE_0__.info(trimmed);
}
},
},
});
return false;
}
}
async fetch_binary() { async fetch_binary() {
if (!this.local_root) { if (!this.local_root) {
_actions_core__WEBPACK_IMPORTED_MODULE_0__.info(`Fetching binary from ${this.nix_installer_url}`); _actions_core__WEBPACK_IMPORTED_MODULE_0__.info(`Fetching binary from ${this.nix_installer_url}`);

2
dist/index.js.map vendored

File diff suppressed because one or more lines are too long

View file

@ -15,6 +15,7 @@ class NixInstallerAction {
extra_args: string | null; extra_args: string | null;
extra_conf: string[] | null; extra_conf: string[] | null;
flakehub: boolean; flakehub: boolean;
kvm: boolean;
github_token: string | null; github_token: string | null;
// TODO: linux_init // TODO: linux_init
init: string | null; init: string | null;
@ -53,6 +54,7 @@ class NixInstallerAction {
this.extra_args = action_input_string_or_null("extra-args"); this.extra_args = action_input_string_or_null("extra-args");
this.extra_conf = action_input_multiline_string_or_null("extra-conf"); this.extra_conf = action_input_multiline_string_or_null("extra-conf");
this.flakehub = action_input_bool("flakehub"); this.flakehub = action_input_bool("flakehub");
this.kvm = action_input_bool("kvm");
this.github_token = action_input_string_or_null("github-token"); this.github_token = action_input_string_or_null("github-token");
this.init = action_input_string_or_null("init"); this.init = action_input_string_or_null("init");
this.local_root = action_input_string_or_null("local-root"); this.local_root = action_input_string_or_null("local-root");
@ -305,6 +307,24 @@ class NixInstallerAction {
return; return;
} }
} }
if (this.kvm) {
actions_core.startGroup("Configuring KVM");
if (await this.setup_kvm()) {
actions_core.endGroup();
actions_core.info(
"\u001b[32m Accelerated KVM is enabled \u001b[33m⚡",
);
actions_core.exportVariable("DETERMINATE_NIX_KVM", "1");
} else {
actions_core.endGroup();
actions_core.info("KVM is not available.");
actions_core.exportVariable("DETERMINATE_NIX_KVM", "0");
}
actions_core.exportVariable("DETERMINATE_NIX_KVM", "0");
}
// Normal just doing of the install // Normal just doing of the install
const binary_path = await this.fetch_binary(); const binary_path = await this.fetch_binary();
await this.execute_install(binary_path); await this.execute_install(binary_path);
@ -399,6 +419,92 @@ class NixInstallerAction {
} }
} }
private async setup_kvm(): Promise<boolean> {
const kvm_rules =
"/etc/udev/rules.d/99-determinate-nix-installer-kvm.rules";
try {
const write_file_exit_code = await actions_exec.exec(
"sh",
[
"-c",
`echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee ${kvm_rules} > /dev/null`,
],
{
listeners: {
stderr: (data: Buffer) => {
const trimmed = data.toString("utf-8").trimEnd();
if (trimmed.length >= 0) {
actions_core.debug(trimmed);
}
},
},
},
);
if (write_file_exit_code !== 0) {
throw new Error(
`Non-zero exit code of \`${write_file_exit_code}\` detected while writing '${kvm_rules}'`,
);
}
const debug_run_throw = async (
action: string,
command: string,
args: string[],
): Promise<void> => {
const reload_exit_code = await actions_exec.exec(command, args, {
listeners: {
stdout: (data: Buffer) => {
const trimmed = data.toString("utf-8").trimEnd();
if (trimmed.length >= 0) {
actions_core.debug(trimmed);
}
},
stderr: (data: Buffer) => {
const trimmed = data.toString("utf-8").trimEnd();
if (trimmed.length >= 0) {
actions_core.debug(trimmed);
}
},
},
});
if (reload_exit_code !== 0) {
throw new Error(
`Non-zero exit code of \`${reload_exit_code}\` detected while ${action}.`,
);
}
};
await debug_run_throw("reloading udev rules", `sudo`, [
"udevadm",
"control",
"--reload-rules",
]);
await debug_run_throw("triggering udev against kvm", `sudo`, [
"udevadm",
"trigger",
"--name-match=kvm",
]);
return true;
} catch (error) {
await actions_exec.exec("sudo", ["rm", "-f", kvm_rules], {
listeners: {
stderr: (data: Buffer) => {
const trimmed = data.toString("utf-8").trimEnd();
if (trimmed.length >= 0) {
actions_core.info(trimmed);
}
},
},
});
return false;
}
}
private async fetch_binary(): Promise<string> { private async fetch_binary(): Promise<string> {
if (!this.local_root) { if (!this.local_root) {
actions_core.info(`Fetching binary from ${this.nix_installer_url}`); actions_core.info(`Fetching binary from ${this.nix_installer_url}`);