diff options
author | Eric Merritt <ericbmerritt@gmail.com> | 2016-07-18 23:13:06 -0700 |
---|---|---|
committer | Franz Pletz <fpletz@fnordicwalking.de> | 2016-07-19 08:13:06 +0200 |
commit | eb92804f914a8a40339473ebd641f0a93d8576b9 (patch) | |
tree | 591417299ee8cb66b42542676cc3ea2a102d1c56 /nixos/modules | |
parent | e2199205c7012fc9cfeaf89e85fe3bb8084b82a4 (diff) | |
download | nixpkgs-eb92804f914a8a40339473ebd641f0a93d8576b9.tar nixpkgs-eb92804f914a8a40339473ebd641f0a93d8576b9.tar.gz nixpkgs-eb92804f914a8a40339473ebd641f0a93d8576b9.tar.bz2 nixpkgs-eb92804f914a8a40339473ebd641f0a93d8576b9.tar.lz nixpkgs-eb92804f914a8a40339473ebd641f0a93d8576b9.tar.xz nixpkgs-eb92804f914a8a40339473ebd641f0a93d8576b9.tar.zst nixpkgs-eb92804f914a8a40339473ebd641f0a93d8576b9.zip |
nixos-containers: init package (#16959)
This moves nixos-containers into its own package so that it can be relied upon by other packages/systems. This should make development using dynamic containers much easier.
Diffstat (limited to 'nixos/modules')
-rw-r--r-- | nixos/modules/virtualisation/containers.nix | 20 | ||||
-rw-r--r-- | nixos/modules/virtualisation/nixos-container-completion.sh | 33 | ||||
-rwxr-xr-x | nixos/modules/virtualisation/nixos-container.pl | 301 |
3 files changed, 2 insertions, 352 deletions
diff --git a/nixos/modules/virtualisation/containers.nix b/nixos/modules/virtualisation/containers.nix index 13ecb8e25ed..b3870caece0 100644 --- a/nixos/modules/virtualisation/containers.nix +++ b/nixos/modules/virtualisation/containers.nix @@ -4,22 +4,6 @@ with lib; let - nixos-container = pkgs.substituteAll { - name = "nixos-container"; - dir = "bin"; - isExecutable = true; - src = ./nixos-container.pl; - perl = "${pkgs.perl}/bin/perl -I${pkgs.perlPackages.FileSlurp}/lib/perl5/site_perl"; - su = "${pkgs.shadow.su}/bin/su"; - inherit (pkgs) utillinux; - - postInstall = '' - t=$out/etc/bash_completion.d - mkdir -p $t - cp ${./nixos-container-completion.sh} $t/nixos-container - ''; - }; - # The container's init script, a small wrapper around the regular # NixOS stage-2 init script. containerInit = pkgs.writeScript "container-init" @@ -410,7 +394,7 @@ in ExecReload = pkgs.writeScript "reload-container" '' #! ${pkgs.stdenv.shell} -e - ${nixos-container}/bin/nixos-container run "$INSTANCE" -- \ + ${pkgs.nixos-container}/bin/nixos-container run "$INSTANCE" -- \ bash --login -c "''${SYSTEM_PATH:-/nix/var/nix/profiles/system}/bin/switch-to-configuration test" ''; @@ -498,6 +482,6 @@ in networking.dhcpcd.denyInterfaces = [ "ve-*" ]; - environment.systemPackages = [ nixos-container ]; + environment.systemPackages = [ pkgs.nixos-container ]; }); } diff --git a/nixos/modules/virtualisation/nixos-container-completion.sh b/nixos/modules/virtualisation/nixos-container-completion.sh deleted file mode 100644 index 0fe8ab811a1..00000000000 --- a/nixos/modules/virtualisation/nixos-container-completion.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env bash - -_nixos-container() { - local cur prev opts - COMPREPLY=() - cur="${COMP_WORDS[COMP_CWORD]}" - prev="${COMP_WORDS[COMP_CWORD-1]}" - opts="list create destroy start stop status update login root-login run show-ip show-host-key" - startstop_opts=$(nixos-container list) - update_opts="--config" - - if [[ "$prev" == "nixos-container" ]] - then - COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) - return 0 - fi - - if [[ $(echo "$opts" | grep "$prev") ]] - then - if [[ "$prev" == "start" || "$prev" == "stop" ]] - then - COMPREPLY=( $(compgen -W "${startstop_opts}" -- ${cur}) ) - return 0 - elif [[ "$prev" == "update" ]] - then - COMPREPLY=( $(compgen -W "${update_opts}" -- ${cur}) ) - return 0 - fi - fi -} - -complete -F _nixos-container nixos-container - diff --git a/nixos/modules/virtualisation/nixos-container.pl b/nixos/modules/virtualisation/nixos-container.pl deleted file mode 100755 index eda57a9751e..00000000000 --- a/nixos/modules/virtualisation/nixos-container.pl +++ /dev/null @@ -1,301 +0,0 @@ -#! @perl@ - -use strict; -use POSIX; -use File::Path; -use File::Slurp; -use Fcntl ':flock'; -use Getopt::Long qw(:config gnu_getopt); - -my $nsenter = "@utillinux@/bin/nsenter"; -my $su = "@su@"; - -# Ensure a consistent umask. -umask 0022; - -# Parse the command line. - -sub showHelp { - print <<EOF; -Usage: nixos-container list - nixos-container create <container-name> [--system-path <path>] [--config <string>] [--ensure-unique-name] [--auto-start] - nixos-container destroy <container-name> - nixos-container start <container-name> - nixos-container stop <container-name> - nixos-container status <container-name> - nixos-container update <container-name> [--config <string>] - nixos-container login <container-name> - nixos-container root-login <container-name> - nixos-container run <container-name> -- args... - nixos-container show-ip <container-name> - nixos-container show-host-key <container-name> -EOF - exit 0; -} - -my $systemPath; -my $ensureUniqueName = 0; -my $autoStart = 0; -my $extraConfig; - -GetOptions( - "help" => sub { showHelp() }, - "ensure-unique-name" => \$ensureUniqueName, - "auto-start" => \$autoStart, - "system-path=s" => \$systemPath, - "config=s" => \$extraConfig - ) or exit 1; - -my $action = $ARGV[0] or die "$0: no action specified\n"; - - -# Execute the selected action. - -mkpath("/etc/containers", 0, 0755); -mkpath("/var/lib/containers", 0, 0700); - -if ($action eq "list") { - foreach my $confFile (glob "/etc/containers/*.conf") { - $confFile =~ /\/([^\/]+).conf$/ or next; - print "$1\n"; - } - exit 0; -} - -my $containerName = $ARGV[1] or die "$0: no container name specified\n"; -$containerName =~ /^[a-zA-Z0-9\-]+$/ or die "$0: invalid container name\n"; - -sub writeNixOSConfig { - my ($nixosConfigFile) = @_; - - my $nixosConfig = <<EOF; -{ config, lib, pkgs, ... }: - -with lib; - -{ boot.isContainer = true; - networking.hostName = mkDefault "$containerName"; - networking.useDHCP = false; - $extraConfig -} -EOF - - write_file($nixosConfigFile, $nixosConfig); -} - -if ($action eq "create") { - # Acquire an exclusive lock to prevent races with other - # invocations of ‘nixos-container create’. - my $lockFN = "/run/lock/nixos-container"; - open(my $lock, '>>', $lockFN) or die "$0: opening $lockFN: $!"; - flock($lock, LOCK_EX) or die "$0: could not lock $lockFN: $!"; - - my $confFile = "/etc/containers/$containerName.conf"; - my $root = "/var/lib/containers/$containerName"; - - # Maybe generate a unique name. - if ($ensureUniqueName) { - my $base = $containerName; - for (my $nr = 0; ; $nr++) { - $confFile = "/etc/containers/$containerName.conf"; - $root = "/var/lib/containers/$containerName"; - last unless -e $confFile || -e $root; - $containerName = "$base-$nr"; - } - } - - die "$0: container ‘$containerName’ already exists\n" if -e $confFile; - - # Due to interface name length restrictions, container names must - # be restricted too. - die "$0: container name ‘$containerName’ is too long\n" if length $containerName > 11; - - # Get an unused IP address. - my %usedIPs; - foreach my $confFile2 (glob "/etc/containers/*.conf") { - my $s = read_file($confFile2) or die; - $usedIPs{$1} = 1 if $s =~ /^HOST_ADDRESS=([0-9\.]+)$/m; - $usedIPs{$1} = 1 if $s =~ /^LOCAL_ADDRESS=([0-9\.]+)$/m; - } - - my ($ipPrefix, $hostAddress, $localAddress); - for (my $nr = 1; $nr < 255; $nr++) { - $ipPrefix = "10.233.$nr"; - $hostAddress = "$ipPrefix.1"; - $localAddress = "$ipPrefix.2"; - last unless $usedIPs{$hostAddress} || $usedIPs{$localAddress}; - $ipPrefix = undef; - } - - die "$0: out of IP addresses\n" unless defined $ipPrefix; - - my @conf; - push @conf, "PRIVATE_NETWORK=1\n"; - push @conf, "HOST_ADDRESS=$hostAddress\n"; - push @conf, "LOCAL_ADDRESS=$localAddress\n"; - push @conf, "AUTO_START=$autoStart\n"; - write_file($confFile, \@conf); - - close($lock); - - print STDERR "host IP is $hostAddress, container IP is $localAddress\n"; - - # The per-container directory is restricted to prevent users on - # the host from messing with guest users who happen to have the - # same uid. - my $profileDir = "/nix/var/nix/profiles/per-container"; - mkpath($profileDir, 0, 0700); - $profileDir = "$profileDir/$containerName"; - mkpath($profileDir, 0, 0755); - - # Build/set the initial configuration. - if (defined $systemPath) { - system("nix-env", "-p", "$profileDir/system", "--set", $systemPath) == 0 - or die "$0: failed to set initial container configuration\n"; - } else { - mkpath("$root/etc/nixos", 0, 0755); - - my $nixosConfigFile = "$root/etc/nixos/configuration.nix"; - writeNixOSConfig $nixosConfigFile; - - system("nix-env", "-p", "$profileDir/system", - "-I", "nixos-config=$nixosConfigFile", "-f", "<nixpkgs/nixos>", - "--set", "-A", "system") == 0 - or die "$0: failed to build initial container configuration\n"; - } - - print "$containerName\n" if $ensureUniqueName; - exit 0; -} - -my $root = "/var/lib/containers/$containerName"; -my $profileDir = "/nix/var/nix/profiles/per-container/$containerName"; -my $gcRootsDir = "/nix/var/nix/gcroots/per-container/$containerName"; -my $confFile = "/etc/containers/$containerName.conf"; -if (!-e $confFile) { - if ($action eq "destroy") { - exit 0; - } elsif ($action eq "status") { - print "gone\n"; - } - die "$0: container ‘$containerName’ does not exist\n" ; -} - -sub isContainerRunning { - my $status = `systemctl show 'container\@$containerName'`; - return $status =~ /ActiveState=active/; -} - -sub stopContainer { - system("systemctl", "stop", "container\@$containerName") == 0 - or die "$0: failed to stop container\n"; -} - -# Return the PID of the init process of the container. -sub getLeader { - my $s = `machinectl show "$containerName" -p Leader`; - chomp $s; - $s =~ /^Leader=(\d+)$/ or die "unable to get container's main PID\n"; - return int($1); -} - -# Run a command in the container. -sub runInContainer { - my @args = @_; - my $leader = getLeader; - exec($nsenter, "-t", $leader, "-m", "-u", "-i", "-n", "-p", "--", @args); - die "cannot run ‘nsenter’: $!\n"; -} - -# Remove a directory while recursively unmounting all mounted filesystems within -# that directory and unmounting/removing that directory afterwards as well. -# -# NOTE: If the specified path is a mountpoint, its contents will be removed, -# only mountpoints underneath that path will be unmounted properly. -sub safeRemoveTree { - my ($path) = @_; - system("find", $path, "-mindepth", "1", "-xdev", - "(", "-type", "d", "-exec", "mountpoint", "-q", "{}", ";", ")", - "-exec", "umount", "-fR", "{}", "+"); - system("rm", "--one-file-system", "-rf", $path); - if (-e $path) { - system("umount", "-fR", $path); - system("rm", "--one-file-system", "-rf", $path); - } -} - -if ($action eq "destroy") { - die "$0: cannot destroy declarative container (remove it from your configuration.nix instead)\n" - unless POSIX::access($confFile, &POSIX::W_OK); - - stopContainer if isContainerRunning; - - safeRemoveTree($profileDir) if -e $profileDir; - safeRemoveTree($gcRootsDir) if -e $gcRootsDir; - safeRemoveTree($root) if -e $root; - unlink($confFile) or die; -} - -elsif ($action eq "start") { - system("systemctl", "start", "container\@$containerName") == 0 - or die "$0: failed to start container\n"; -} - -elsif ($action eq "stop") { - stopContainer; -} - -elsif ($action eq "status") { - print isContainerRunning() ? "up" : "down", "\n"; -} - -elsif ($action eq "update") { - my $nixosConfigFile = "$root/etc/nixos/configuration.nix"; - - # FIXME: may want to be more careful about clobbering the existing - # configuration.nix. - writeNixOSConfig $nixosConfigFile if (defined $extraConfig && $extraConfig ne ""); - - system("nix-env", "-p", "$profileDir/system", - "-I", "nixos-config=$nixosConfigFile", "-f", "<nixpkgs/nixos>", - "--set", "-A", "system") == 0 - or die "$0: failed to build container configuration\n"; - - if (isContainerRunning) { - print STDERR "reloading container...\n"; - system("systemctl", "reload", "container\@$containerName") == 0 - or die "$0: failed to reload container\n"; - } -} - -elsif ($action eq "login") { - exec("machinectl", "login", "--", $containerName); -} - -elsif ($action eq "root-login") { - runInContainer("@su@", "root", "-l"); -} - -elsif ($action eq "run") { - shift @ARGV; shift @ARGV; - # Escape command. - my $s = join(' ', map { s/'/'\\''/g; "'$_'" } @ARGV); - runInContainer("@su@", "root", "-l", "-c", "exec " . $s); -} - -elsif ($action eq "show-ip") { - my $s = read_file($confFile) or die; - $s =~ /^LOCAL_ADDRESS=([0-9\.]+)$/m or die "$0: cannot get IP address\n"; - print "$1\n"; -} - -elsif ($action eq "show-host-key") { - my $fn = "$root/etc/ssh/ssh_host_ed25519_key.pub"; - $fn = "$root/etc/ssh/ssh_host_ecdsa_key.pub" unless -e $fn; - exit 1 if ! -f $fn; - print read_file($fn); -} - -else { - die "$0: unknown action ‘$action’\n"; -} |