Merge pull request 'Better install instructions for macos' (#2550) from arm64 into main

This commit is contained in:
clan-bot
2024-12-04 16:32:02 +00:00
20 changed files with 131 additions and 106 deletions

View File

@@ -37,13 +37,6 @@ In the `flake.nix` file:
meta.name = "Lobsters"; meta.name = "Lobsters";
# Should usually point to the directory of flake.nix # Should usually point to the directory of flake.nix
directory = ./.; directory = ./.;
machines = {
jon = {
# ...
};
# ...
}
} }
``` ```
@@ -55,13 +48,6 @@ In the `flake.nix` file:
clan = { clan = {
# Set a unique name # Set a unique name
meta.name = "Lobsters"; meta.name = "Lobsters";
machines = {
jon = {
# ...
};
# ...
}
}; };
``` ```
@@ -129,6 +115,32 @@ Adding or configuring a new machine requires two simple steps:
} }
``` ```
You can also create additional machines using the `clan machines create` command:
```
$ clan machines create --help
usage: clan [-h] [SUBCOMMAND] machines create [-h] [--tags TAGS [TAGS ...]] [--template-name TEMPLATE_NAME]
[--target-host TARGET_HOST] [--debug] [--option name value] [--flake PATH]
machine_name
positional arguments:
machine_name The name of the machine to create
options:
-h, --help show this help message and exit
--tags TAGS [TAGS ...]
Tags to associate with the machine. Can be used to assign multiple machines to services.
--template-name TEMPLATE_NAME
The name of the template machine to import
--target-host TARGET_HOST
Address of the machine to install and update, in the format of user@host:1234
--debug Enable debug logging
--option name value Nix option to set
--flake PATH path to the flake where the clan resides in, can be a remote flake or local, can be set through
the [CLAN_DIR] environment variable
```
!!! Info "Replace `__YOUR_USERNAME__` with the ip of your machine, if you use avahi you can also use your hostname" !!! Info "Replace `__YOUR_USERNAME__` with the ip of your machine, if you use avahi you can also use your hostname"
!!! Info "Replace `__IP__` with the ip of your machine, if you use avahi you can also use your hostname" !!! Info "Replace `__IP__` with the ip of your machine, if you use avahi you can also use your hostname"
!!! Info "Replace `__CHANGE_ME__` with the appropriate identifier, such as `nvme-eui.e8238fa6bf530001001b448b4aec2929`" !!! Info "Replace `__CHANGE_ME__` with the appropriate identifier, such as `nvme-eui.e8238fa6bf530001001b448b4aec2929`"

View File

@@ -68,12 +68,6 @@ sudo umount /dev/sdb1
``` ```
If you do not have an ssh key yet, you can generate one with `ssh-keygen -t ed25519` command. If you do not have an ssh key yet, you can generate one with `ssh-keygen -t ed25519` command.
- **Wifi Option**:
To add wifi credentials into the installer image append the option:
```
--wifi <ssid> <password>
```
- **List Keymaps**: - **List Keymaps**:
You can get a list of all keymaps with the following command: You can get a list of all keymaps with the following command:
``` ```
@@ -95,7 +89,7 @@ sudo umount /dev/sdb1
For x86_64: For x86_64:
```shellSession ```shellSession
https://github.com/nix-community/nixos-images/releases/download/nixos-unstable/nixos-installer-x86_64-linux.iso wget https://github.com/nix-community/nixos-images/releases/download/nixos-unstable/nixos-installer-x86_64-linux.iso
``` ```
For generic arm64 / aarch64 (probably does not work on raspberry pi...) For generic arm64 / aarch64 (probably does not work on raspberry pi...)
@@ -104,20 +98,34 @@ sudo umount /dev/sdb1
wget https://github.com/nix-community/nixos-images/releases/download/nixos-unstable/nixos-installer-aarch64-linux.iso wget https://github.com/nix-community/nixos-images/releases/download/nixos-unstable/nixos-installer-aarch64-linux.iso
``` ```
!!! Note
If you don't have `wget` installed, you can use `curl --progress-bar -OL <url>` instead.
### Step 2.5 Flash the Installer to the USB Drive ### Step 2.5 Flash the Installer to the USB Drive
!!! Danger "Specifying the wrong device can lead to unrecoverable data loss." !!! Danger "Specifying the wrong device can lead to unrecoverable data loss."
The `dd` utility will erase the disk. Make sure to specify the correct device (`of=...`) The `dd` utility will erase the disk. Make sure to specify the correct device (`of=...`)
For example if the USB device is `sdb` use `of=/dev/sdb`. For example if the USB device is `sdb` use `of=/dev/sdb` (on macOS it will look more like /dev/disk1)
On Linux, you can use the `lsblk` utility to identify the correct disko
```
lsblk --output NAME,ID-LINK,FSTYPE,SIZE,MOUNTPOINT
```
Use the `dd` utility to write the NixOS installer image to your USB drive: On macos use `diskutil`:
```
diskutil list
```
Use the `dd` utility to write the NixOS installer image to your USB drive.
Replace `/dev/sd<X>` with your external drive from above.
```shellSession ```shellSession
sudo dd bs=4M conv=fsync oflag=direct status=progress if=./nixos-installer-x86_64-linux.iso of=/dev/sd<X> sudo dd bs=4M conv=fsync status=progress if=./nixos-installer-x86_64-linux.iso of=/dev/sd<X>
``` ```

View File

@@ -67,13 +67,21 @@ let
# Machine specific settings # Machine specific settings
clan.core.machineName = name; clan.core.machineName = name;
networking.hostName = lib.mkDefault name; networking.hostName = lib.mkDefault name;
nixpkgs.hostPlatform = lib.mkIf (system != null) (lib.mkDefault system);
# speeds up nix commands by using the nixpkgs from the host system (especially useful in VMs) # speeds up nix commands by using the nixpkgs from the host system (especially useful in VMs)
nix.registry.nixpkgs.to = lib.mkDefault { nix.registry.nixpkgs.to = lib.mkDefault {
type = "path"; type = "path";
path = lib.mkDefault nixpkgs; path = lib.mkDefault nixpkgs;
}; };
# For vars we need to override the system so we run vars
# generators on the machine that runs `clan vars generate`. If a
# users is using the `pkgsForSystem`, we don't set
# nixpkgs.hostPlatform it would conflict with the `nixpkgs.pkgs`
# option.
nixpkgs.hostPlatform = lib.mkIf (system != null && (pkgsForSystem system) != null) (
lib.mkForce system
);
} }
// lib.optionalAttrs (pkgs != null) { nixpkgs.pkgs = lib.mkForce pkgs; } // lib.optionalAttrs (pkgs != null) { nixpkgs.pkgs = lib.mkForce pkgs; }
) )

View File

@@ -83,8 +83,10 @@ def handle_io(
return b"" return b""
# Extra information passed to the logger # Extra information passed to the logger
stdout_extra = {"command_prefix": prefix} stdout_extra = {}
stderr_extra = {"command_prefix": prefix} stderr_extra = {}
if prefix:
stdout_extra["command_prefix"] = stderr_extra["command_prefix"] = prefix
if msg_color and msg_color.stderr: if msg_color and msg_color.stderr:
stdout_extra["color"] = msg_color.stderr.value stdout_extra["color"] = msg_color.stderr.value
if msg_color and msg_color.stdout: if msg_color and msg_color.stdout:
@@ -267,9 +269,6 @@ def run(
if options.cwd is None: if options.cwd is None:
options.cwd = Path.cwd() options.cwd = Path.cwd()
if options.prefix is None:
options.prefix = "$"
if options.input: if options.input:
if any(not ch.isprintable() for ch in options.input.decode("ascii", "replace")): if any(not ch.isprintable() for ch in options.input.decode("ascii", "replace")):
filtered_input = "<<binary_blob>>" filtered_input = "<<binary_blob>>"

View File

@@ -25,12 +25,9 @@ class PrefixFormatter(logging.Formatter):
print errors in red and warnings in yellow print errors in red and warnings in yellow
""" """
def __init__( def __init__(self, trace_prints: bool = False) -> None:
self, trace_prints: bool = False, default_prefix: str | None = None
) -> None:
super().__init__() super().__init__()
self.default_prefix = default_prefix
self.trace_prints = trace_prints self.trace_prints = trace_prints
self.hostnames: list[str] = [] self.hostnames: list[str] = []
self.hostname_color_offset = 0 self.hostname_color_offset = 0
@@ -51,7 +48,7 @@ class PrefixFormatter(logging.Formatter):
msg_color = AnsiColor.DEFAULT.value msg_color = AnsiColor.DEFAULT.value
# If extra["command_prefix"] is set, use that as the logging prefix. # If extra["command_prefix"] is set, use that as the logging prefix.
command_prefix = getattr(record, "command_prefix", self.default_prefix) command_prefix = getattr(record, "command_prefix", None)
# If color is disabled, don't use color. # If color is disabled, don't use color.
if DISABLE_COLOR: if DISABLE_COLOR:
@@ -154,7 +151,6 @@ def print_trace(msg: str, logger: logging.Logger, prefix: str | None) -> None:
def setup_logging( def setup_logging(
level: Any, level: Any,
root_log_name: str = __name__.split(".")[0], root_log_name: str = __name__.split(".")[0],
default_prefix: str = "clan",
) -> None: ) -> None:
# Get the root logger and set its level # Get the root logger and set its level
main_logger = logging.getLogger(root_log_name) main_logger = logging.getLogger(root_log_name)
@@ -166,5 +162,5 @@ def setup_logging(
# Create and add your custom handler # Create and add your custom handler
default_handler.setLevel(level) default_handler.setLevel(level)
trace_prints = bool(int(os.environ.get("TRACE_PRINT", "0"))) trace_prints = bool(int(os.environ.get("TRACE_PRINT", "0")))
default_handler.setFormatter(PrefixFormatter(trace_prints, default_prefix)) default_handler.setFormatter(PrefixFormatter(trace_prints))
main_logger.addHandler(default_handler) main_logger.addHandler(default_handler)

View File

@@ -23,17 +23,11 @@ from .list import list_possible_keymaps, list_possible_languages
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@dataclass
class WifiConfig:
ssid: str
@dataclass @dataclass
class SystemConfig: class SystemConfig:
language: str | None = field(default=None) language: str | None = field(default=None)
keymap: str | None = field(default=None) keymap: str | None = field(default=None)
ssh_keys_path: list[str] | None = field(default=None) ssh_keys_path: list[str] | None = field(default=None)
wifi_settings: list[WifiConfig] | None = field(default=None)
@dataclass @dataclass
@@ -65,12 +59,6 @@ def flash_machine(
) )
generate_facts([machine]) generate_facts([machine])
if system_config.wifi_settings:
wifi_settings: dict[str, dict[str, str]] = {}
for wifi in system_config.wifi_settings:
wifi_settings[wifi.ssid] = {}
system_config_nix["clan"] = {"iwd": {"networks": wifi_settings}}
if system_config.language: if system_config.language:
if system_config.language not in list_possible_languages(): if system_config.language not in list_possible_languages():
msg = ( msg = (

View File

@@ -10,7 +10,7 @@ from clan_cli.clan_uri import FlakeId
from clan_cli.completions import add_dynamic_completer, complete_machines from clan_cli.completions import add_dynamic_completer, complete_machines
from clan_cli.machines.machines import Machine from clan_cli.machines.machines import Machine
from .flash import Disk, SystemConfig, WifiConfig, flash_machine from .flash import Disk, SystemConfig, flash_machine
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@@ -69,15 +69,11 @@ def flash_command(args: argparse.Namespace) -> None:
language=args.language, language=args.language,
keymap=args.keymap, keymap=args.keymap,
ssh_keys_path=args.ssh_pubkey, ssh_keys_path=args.ssh_pubkey,
wifi_settings=None,
), ),
write_efi_boot_entries=args.write_efi_boot_entries, write_efi_boot_entries=args.write_efi_boot_entries,
nix_options=args.option, nix_options=args.option,
) )
if args.wifi:
opts.system_config.wifi_settings = [WifiConfig(ssid=ssid) for ssid in args.wifi]
machine = Machine(opts.machine, flake=opts.flake) machine = Machine(opts.machine, flake=opts.flake)
if opts.confirm and not opts.dry_run: if opts.confirm and not opts.dry_run:
disk_str = ", ".join(f"{disk.name}={disk.device}" for disk in opts.disks) disk_str = ", ".join(f"{disk.name}={disk.device}" for disk in opts.disks)
@@ -126,13 +122,6 @@ def register_flash_write_parser(parser: argparse.ArgumentParser) -> None:
Mount is useful for updating an existing system without losing data. Mount is useful for updating an existing system without losing data.
""" """
) )
parser.add_argument(
"--wifi",
type=str,
action="append",
help="wifi ssid to connect to",
default=[],
)
parser.add_argument( parser.add_argument(
"--mode", "--mode",
type=str, type=str,

View File

@@ -1,4 +1,5 @@
# DON NOT EDIT THIS FILE MANUALLY. IT IS GENERATED. # DO NOT EDIT THIS FILE MANUALLY. IT IS GENERATED.
# This file was generated by running `pkgs/clan-cli/clan_cli/inventory/update.sh`
# #
# ruff: noqa: N815 # ruff: noqa: N815
# ruff: noqa: N806 # ruff: noqa: N806

View File

@@ -1,4 +1,8 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail
jsonSchema=$(nix build .#schemas.inventory-schema-abstract --print-out-paths)/schema.json jsonSchema=$(nix build .#schemas.inventory-schema-abstract --print-out-paths)/schema.json
nix run .#classgen "$jsonSchema" "$PKG_ROOT/clan_cli/inventory/classes.py" -- --stop-at "Service" SCRIPT_DIR=$(dirname "$0")
cd "$SCRIPT_DIR"
nix run .#classgen -- "$jsonSchema" "../../../clan-cli/clan_cli/inventory/classes.py" --stop-at "Service"

View File

@@ -7,12 +7,12 @@ from pathlib import Path
from tempfile import TemporaryDirectory from tempfile import TemporaryDirectory
from clan_cli.api import API from clan_cli.api import API
from clan_cli.clan.create import git_command
from clan_cli.clan_uri import FlakeId from clan_cli.clan_uri import FlakeId
from clan_cli.cmd import Log, RunOpts, run from clan_cli.cmd import Log, RunOpts, run
from clan_cli.completions import add_dynamic_completer, complete_tags from clan_cli.completions import add_dynamic_completer, complete_tags
from clan_cli.dirs import TemplateType, clan_templates, get_clan_flake_toplevel_or_env from clan_cli.dirs import TemplateType, clan_templates, get_clan_flake_toplevel_or_env
from clan_cli.errors import ClanError from clan_cli.errors import ClanError
from clan_cli.git import commit_file
from clan_cli.inventory import Machine as InventoryMachine from clan_cli.inventory import Machine as InventoryMachine
from clan_cli.inventory import ( from clan_cli.inventory import (
MachineDeploy, MachineDeploy,
@@ -109,10 +109,8 @@ def create_machine(opts: CreateOptions) -> None:
src = tmpdirp / "machines" / opts.template_name src = tmpdirp / "machines" / opts.template_name
if ( has_inventory = (dst / "inventory.json").exists()
not (src / "configuration.nix").exists() if not (src / "configuration.nix").exists() and not has_inventory:
and not (src / "inventory.json").exists()
):
msg = f"Template machine '{opts.template_name}' does not contain a configuration.nix or inventory.json" msg = f"Template machine '{opts.template_name}' does not contain a configuration.nix or inventory.json"
description = ( description = (
"Template machine must contain a configuration.nix or inventory.json" "Template machine must contain a configuration.nix or inventory.json"
@@ -126,12 +124,16 @@ def create_machine(opts: CreateOptions) -> None:
shutil.copytree(src, dst, ignore_dangling_symlinks=True, copy_function=log_copy) shutil.copytree(src, dst, ignore_dangling_symlinks=True, copy_function=log_copy)
run(git_command(clan_dir, "add", f"machines/{machine_name}"), RunOpts(cwd=clan_dir)) commit_file(
clan_dir / "machines" / machine_name,
repo_dir=clan_dir,
commit_message=f"Add machine {machine_name}",
)
inventory = load_inventory_json(clan_dir) inventory = load_inventory_json(clan_dir)
# Merge the inventory from the template # Merge the inventory from the template
if (dst / "inventory.json").exists(): if has_inventory:
template_inventory = load_inventory_json(dst) template_inventory = load_inventory_json(dst)
merge_template_inventory(inventory, template_inventory, machine_name) merge_template_inventory(inventory, template_inventory, machine_name)
@@ -141,6 +143,13 @@ def create_machine(opts: CreateOptions) -> None:
new_machine = InventoryMachine( new_machine = InventoryMachine(
name=machine_name, deploy=deploy, tags=opts.machine.tags name=machine_name, deploy=deploy, tags=opts.machine.tags
) )
if (
not has_inventory
and len(opts.machine.tags) == 0
and new_machine.deploy.targetHost is None
):
# no need to update inventory if there are no tags or target host
return
inventory.machines.update({new_machine.name: dataclass_to_dict(new_machine)}) inventory.machines.update({new_machine.name: dataclass_to_dict(new_machine)})
set_inventory(inventory, clan_dir, "Imported machine from template") set_inventory(inventory, clan_dir, "Imported machine from template")

View File

@@ -1,4 +1,5 @@
import json import json
import logging
import os import os
import tempfile import tempfile
from pathlib import Path from pathlib import Path
@@ -8,6 +9,8 @@ from clan_cli.cmd import run, run_no_stdout
from clan_cli.dirs import nixpkgs_flake, nixpkgs_source from clan_cli.dirs import nixpkgs_flake, nixpkgs_source
from clan_cli.errors import ClanError from clan_cli.errors import ClanError
log = logging.getLogger(__name__)
def nix_command(flags: list[str]) -> list[str]: def nix_command(flags: list[str]) -> list[str]:
args = ["nix", "--extra-experimental-features", "nix-command flakes", *flags] args = ["nix", "--extra-experimental-features", "nix-command flakes", *flags]
@@ -23,38 +26,22 @@ def nix_flake_show(flake_url: str | Path) -> list[str]:
"flake", "flake",
"show", "show",
"--json", "--json",
"--show-trace", *(["--show-trace"] if log.isEnabledFor(logging.DEBUG) else []),
f"{flake_url}", str(flake_url),
] ]
) )
def nix_build(flags: list[str], gcroot: Path | None = None) -> list[str]: def nix_build(flags: list[str], gcroot: Path | None = None) -> list[str]:
if gcroot is not None: return nix_command(
return ( [
nix_command( "build",
[ "--print-out-paths",
"build", "--print-build-logs",
"--out-link", *(["--show-trace"] if log.isEnabledFor(logging.DEBUG) else []),
str(gcroot), *(["--out-root", str(gcroot)] if gcroot is not None else []),
"--print-out-paths", *flags,
"--show-trace", ]
"--print-build-logs",
]
)
+ flags
)
return (
nix_command(
[
"build",
"--no-link",
"--print-out-paths",
"--show-trace",
"--print-build-logs",
]
)
+ flags
) )
@@ -77,7 +64,7 @@ def nix_eval(flags: list[str]) -> list[str]:
default_flags = nix_command( default_flags = nix_command(
[ [
"eval", "eval",
"--show-trace", *(["--show-trace"] if log.isEnabledFor(logging.DEBUG) else []),
"--json", "--json",
"--print-build-logs", "--print-build-logs",
] ]

View File

@@ -31,7 +31,7 @@ clan_cli = [
testpaths = "tests" testpaths = "tests"
faulthandler_timeout = 60 faulthandler_timeout = 60
log_level = "DEBUG" log_level = "DEBUG"
log_format = "%(levelname)s: %(message)s\n %(pathname)s:%(lineno)d::%(funcName)s" log_format = "%(message)s"
addopts = "--cov . --cov-report term --cov-report html:.reports/html --no-cov-on-fail --durations 5 --color=yes --new-first -W error -n auto" # Add --pdb for debugging addopts = "--cov . --cov-report term --cov-report html:.reports/html --no-cov-on-fail --durations 5 --color=yes --new-first -W error -n auto" # Add --pdb for debugging
norecursedirs = "tests/helpers" norecursedirs = "tests/helpers"
markers = ["impure", "with_core"] markers = ["impure", "with_core"]

View File

@@ -20,7 +20,6 @@ struct passwd *getpwnam(const char *name) {
fprintf(stderr, "no LOGIN_SHELL set\n"); fprintf(stderr, "no LOGIN_SHELL set\n");
exit(1); exit(1);
} }
fprintf(stderr, "SHELL:%s\n", shell);
pw->pw_shell = strdup(shell); pw->pw_shell = strdup(shell);
} }
return pw; return pw;

View File

@@ -15,6 +15,7 @@
vm1 = vm1 =
{ lib, ... }: { lib, ... }:
{ {
nixpkgs.hostPlatform = "x86_64-linux";
clan.core.networking.targetHost = "__CLAN_TARGET_ADDRESS__"; clan.core.networking.targetHost = "__CLAN_TARGET_ADDRESS__";
system.stateVersion = lib.version; system.stateVersion = lib.version;
sops.age.keyFile = "__CLAN_SOPS_KEY_PATH__"; sops.age.keyFile = "__CLAN_SOPS_KEY_PATH__";
@@ -28,6 +29,7 @@
vm2 = vm2 =
{ lib, ... }: { lib, ... }:
{ {
nixpkgs.hostPlatform = "x86_64-linux";
imports = [ imports = [
clan-core.clanModules.sshd clan-core.clanModules.sshd
clan-core.clanModules.root-password clan-core.clanModules.root-password

View File

@@ -10,7 +10,15 @@ def test_machine_subcommands(
capture_output: CaptureOutput, capture_output: CaptureOutput,
) -> None: ) -> None:
cli.run( cli.run(
["machines", "create", "--flake", str(test_flake_with_core.path), "machine1"] [
"machines",
"create",
"--flake",
str(test_flake_with_core.path),
"machine1",
"--tags",
"vm",
]
) )
with capture_output as output: with capture_output as output:

View File

@@ -323,6 +323,7 @@ def test_generate_secret_for_multiple_machines(
sops_setup: SopsSetup, sops_setup: SopsSetup,
) -> None: ) -> None:
machine1_config = flake.machines["machine1"] machine1_config = flake.machines["machine1"]
machine1_config["nixpkgs"]["hostPlatform"] = "x86_64-linux"
machine1_generator = machine1_config["clan"]["core"]["vars"]["generators"][ machine1_generator = machine1_config["clan"]["core"]["vars"]["generators"][
"my_generator" "my_generator"
] ]
@@ -332,6 +333,7 @@ def test_generate_secret_for_multiple_machines(
"echo machine1 > $out/my_secret && echo machine1 > $out/my_value" "echo machine1 > $out/my_secret && echo machine1 > $out/my_value"
) )
machine2_config = flake.machines["machine2"] machine2_config = flake.machines["machine2"]
machine2_config["nixpkgs"]["hostPlatform"] = "x86_64-linux"
machine2_generator = machine2_config["clan"]["core"]["vars"]["generators"][ machine2_generator = machine2_config["clan"]["core"]["vars"]["generators"][
"my_generator" "my_generator"
] ]
@@ -384,6 +386,7 @@ def test_dependant_generators(
flake: ClanFlake, flake: ClanFlake,
) -> None: ) -> None:
config = flake.machines["my_machine"] config = flake.machines["my_machine"]
config["nixpkgs"]["hostPlatform"] = "x86_64-linux"
parent_gen = config["clan"]["core"]["vars"]["generators"]["parent_generator"] parent_gen = config["clan"]["core"]["vars"]["generators"]["parent_generator"]
parent_gen["files"]["my_value"]["secret"] = False parent_gen["files"]["my_value"]["secret"] = False
parent_gen["script"] = "echo hello > $out/my_value" parent_gen["script"] = "echo hello > $out/my_value"
@@ -426,6 +429,7 @@ def test_prompt(
input_value: str, input_value: str,
) -> None: ) -> None:
config = flake.machines["my_machine"] config = flake.machines["my_machine"]
config["nixpkgs"]["hostPlatform"] = "x86_64-linux"
my_generator = config["clan"]["core"]["vars"]["generators"]["my_generator"] my_generator = config["clan"]["core"]["vars"]["generators"]["my_generator"]
my_generator["files"]["my_value"]["secret"] = False my_generator["files"]["my_value"]["secret"] = False
my_generator["prompts"]["prompt1"]["description"] = "dream2nix" my_generator["prompts"]["prompt1"]["description"] = "dream2nix"
@@ -521,6 +525,7 @@ def test_depending_on_shared_secret_succeeds(
sops_setup: SopsSetup, sops_setup: SopsSetup,
) -> None: ) -> None:
config = flake.machines["my_machine"] config = flake.machines["my_machine"]
config["nixpkgs"]["hostPlatform"] = "x86_64-linux"
shared_generator = config["clan"]["core"]["vars"]["generators"]["shared_generator"] shared_generator = config["clan"]["core"]["vars"]["generators"]["shared_generator"]
shared_generator["share"] = True shared_generator["share"] = True
shared_generator["files"]["my_secret"]["secret"] = True shared_generator["files"]["my_secret"]["secret"] = True
@@ -550,6 +555,7 @@ def test_prompt_create_file(
Test that the createFile flag in the prompt configuration works as expected Test that the createFile flag in the prompt configuration works as expected
""" """
config = flake.machines["my_machine"] config = flake.machines["my_machine"]
config["nixpkgs"]["hostPlatform"] = "x86_64-linux"
my_generator = config["clan"]["core"]["vars"]["generators"]["my_generator"] my_generator = config["clan"]["core"]["vars"]["generators"]["my_generator"]
my_generator["prompts"]["prompt1"]["createFile"] = True my_generator["prompts"]["prompt1"]["createFile"] = True
my_generator["prompts"]["prompt2"]["createFile"] = False my_generator["prompts"]["prompt2"]["createFile"] = False
@@ -580,6 +586,7 @@ def test_api_get_prompts(
from clan_cli.vars.list import get_prompts from clan_cli.vars.list import get_prompts
config = flake.machines["my_machine"] config = flake.machines["my_machine"]
config["nixpkgs"]["hostPlatform"] = "x86_64-linux"
my_generator = config["clan"]["core"]["vars"]["generators"]["my_generator"] my_generator = config["clan"]["core"]["vars"]["generators"]["my_generator"]
my_generator["prompts"]["prompt1"]["type"] = "line" my_generator["prompts"]["prompt1"]["type"] = "line"
my_generator["files"]["prompt1"]["secret"] = False my_generator["files"]["prompt1"]["secret"] = False
@@ -604,6 +611,7 @@ def test_api_set_prompts(
from clan_cli.vars.list import set_prompts from clan_cli.vars.list import set_prompts
config = flake.machines["my_machine"] config = flake.machines["my_machine"]
config["nixpkgs"]["hostPlatform"] = "x86_64-linux"
my_generator = config["clan"]["core"]["vars"]["generators"]["my_generator"] my_generator = config["clan"]["core"]["vars"]["generators"]["my_generator"]
my_generator["prompts"]["prompt1"]["type"] = "line" my_generator["prompts"]["prompt1"]["type"] = "line"
my_generator["files"]["prompt1"]["secret"] = False my_generator["files"]["prompt1"]["secret"] = False
@@ -641,6 +649,7 @@ def test_commit_message(
sops_setup: SopsSetup, sops_setup: SopsSetup,
) -> None: ) -> None:
config = flake.machines["my_machine"] config = flake.machines["my_machine"]
config["nixpkgs"]["hostPlatform"] = "x86_64-linux"
my_generator = config["clan"]["core"]["vars"]["generators"]["my_generator"] my_generator = config["clan"]["core"]["vars"]["generators"]["my_generator"]
my_generator["files"]["my_value"]["secret"] = False my_generator["files"]["my_value"]["secret"] = False
my_generator["script"] = "echo hello > $out/my_value" my_generator["script"] = "echo hello > $out/my_value"
@@ -952,6 +961,7 @@ def test_vars_get(
flake: ClanFlake, flake: ClanFlake,
) -> None: ) -> None:
config = flake.machines["my_machine"] config = flake.machines["my_machine"]
config["nixpkgs"]["hostPlatform"] = "x86_64-linux"
my_generator = config["clan"]["core"]["vars"]["generators"]["my_generator"] my_generator = config["clan"]["core"]["vars"]["generators"]["my_generator"]
my_generator["files"]["my_value"]["secret"] = False my_generator["files"]["my_value"]["secret"] = False
my_generator["script"] = "echo -n hello > $out/my_value" my_generator["script"] = "echo -n hello > $out/my_value"
@@ -979,6 +989,7 @@ def test_invalidation(
flake: ClanFlake, flake: ClanFlake,
) -> None: ) -> None:
config = flake.machines["my_machine"] config = flake.machines["my_machine"]
config["nixpkgs"]["hostPlatform"] = "x86_64-linux"
my_generator = config["clan"]["core"]["vars"]["generators"]["my_generator"] my_generator = config["clan"]["core"]["vars"]["generators"]["my_generator"]
my_generator["files"]["my_value"]["secret"] = False my_generator["files"]["my_value"]["secret"] = False
my_generator["script"] = "echo -n $RANDOM > $out/my_value" my_generator["script"] = "echo -n $RANDOM > $out/my_value"

View File

@@ -61,6 +61,7 @@ def test_vm_persistence(
) -> None: ) -> None:
# set up a clan flake with some systemd services to test persistence # set up a clan flake with some systemd services to test persistence
config = flake.machines["my_machine"] config = flake.machines["my_machine"]
config["nixpkgs"]["hostPlatform"] = "x86_64-linux"
# logrotate-checkconf doesn't work in VM because /nix/store is owned by nobody # logrotate-checkconf doesn't work in VM because /nix/store is owned by nobody
config["systemd"]["services"]["logrotate-checkconf"]["enable"] = False config["systemd"]["services"]["logrotate-checkconf"]["enable"] = False
config["services"]["getty"]["autologinUser"] = "root" config["services"]["getty"]["autologinUser"] = "root"

View File

@@ -349,7 +349,8 @@ def run_gen(args: argparse.Namespace) -> None:
with args.output.open("w") as f: with args.output.open("w") as f:
f.write( f.write(
"""# DON NOT EDIT THIS FILE MANUALLY. IT IS GENERATED. """# DO NOT EDIT THIS FILE MANUALLY. IT IS GENERATED.
# This file was generated by running `pkgs/clan-cli/clan_cli/inventory/update.sh`
# #
# ruff: noqa: N815 # ruff: noqa: N815
# ruff: noqa: N806 # ruff: noqa: N806

View File

@@ -157,7 +157,6 @@ export const Flash = () => {
language: values.language, language: values.language,
keymap: values.keymap, keymap: values.keymap,
ssh_keys_path: values.sshKeys.map((file) => file.name), ssh_keys_path: values.sshKeys.map((file) => file.name),
wifi_settings: values.wifi,
}, },
dry_run: false, dry_run: false,
write_efi_boot_entries: false, write_efi_boot_entries: false,

View File

@@ -13,14 +13,17 @@
# Ensure this is unique among all clans you want to use. # Ensure this is unique among all clans you want to use.
meta.name = "__CHANGE_ME__"; meta.name = "__CHANGE_ME__";
# All machines in the ./machines will be imported.
# Prerequisite: boot into the installer. # Prerequisite: boot into the installer.
# See: https://docs.clan.lol/getting-started/installer # See: https://docs.clan.lol/getting-started/installer
# local> mkdir -p ./machines/machine1 # local> mkdir -p ./machines/machine1
# local> Edit ./machines/<machine>/configuration.nix to your liking. # local> Edit ./machines/<machine>/configuration.nix to your liking.
machines = { machines = {
# The name will be used as hostname by default. # You can also specify additional machines here.
jon = { }; # somemachine = {
sara = { }; # imports = [ ./some-machine/configuration.nix ];
# }
}; };
}; };
in in