Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create containers remotely when currentSystem != Linux #412

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions nix/container.nix
Expand Up @@ -33,6 +33,7 @@ in

boot.isContainer = true;

nixpkgs.system = mkIf (! any (platform: platform == builtins.currentSystem) platforms.linux) (mkOverride 999 "x86_64-linux");
};

}
5 changes: 5 additions & 0 deletions nixops/backends/container.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-

from nixops.backends import MachineDefinition, MachineState
from nixops.nix_expr import py2nix
import nixops.util
import nixops.ssh_util
import subprocess
Expand Down Expand Up @@ -126,10 +127,14 @@ def create(self, defn, check, allow_reboot, allow_recreate):
if self.vm_id is None:
self.log("building initial configuration...")

eval_args = self.depl._eval_args(self.depl.nix_exprs)
eval_args['checkConfigurationOptions'] = False
expr = " ".join([
'{ imports = [ <nixops/container-base.nix> ];',
' boot.isContainer = true;',
' networking.hostName = "{0}";'.format(self.name),
' nixpkgs.system = let final = import <nixops/eval-machine-info.nix> {0};'.format(py2nix(eval_args, inline=True)),
' in final.resources.machines.{0}.nixpkgs.system;'.format(self.name),
' users.extraUsers.root.openssh.authorizedKeys.keys = [ "{0}" ];'.format(self.client_public_key),
'}'])

Expand Down
76 changes: 42 additions & 34 deletions nixops/deployment.py
Expand Up @@ -250,16 +250,26 @@ def _nix_path_flags(self):
flags.extend(["-I", "nixops=" + self.expr_path])
return flags

def _eval_args(self, exprs):
args = {key: RawValue(val) for key, val in self.args.iteritems()}
exprs_ = [RawValue(x) if x[0] == '<' else x for x in exprs]
eval_args = {
'networkExprs' : exprs_,
'args' : args,
'uuid' : self.uuid,
'deploymentName' : self.name if self.name else ""
}
return eval_args


def _eval_flags(self, exprs):
flags = self._nix_path_flags()
args = {key: RawValue(val) for key, val in self.args.iteritems()}
exprs_ = [RawValue(x) if x[0] == '<' else x for x in exprs]
args = self._eval_args(exprs)
flags.extend(
["--arg", "networkExprs", py2nix(exprs_, inline=True),
"--arg", "args", py2nix(args, inline=True),
"--argstr", "uuid", self.uuid,
"--argstr", "deploymentName", self.name if self.name else "",
["--arg", "networkExprs", py2nix(args['networkExprs'], inline=True),
"--arg", "args", py2nix(args['args'], inline=True),
"--argstr", "uuid", args['uuid'],
"--argstr", "deploymentName", args['deploymentName'],
"<nixops/eval-machine-info.nix>"])
return flags

Expand Down Expand Up @@ -592,34 +602,6 @@ def build_configs(self, include, exclude, dry_run=False, repair=False):

names = map(lambda m: m.name, selected)

# If we're not running on Linux, then perform the build on the
# target machines. FIXME: Also enable this if we're on 32-bit
# and want to deploy to 64-bit.
if platform.system() != 'Linux' and os.environ.get('NIX_REMOTE') != 'daemon':
if os.environ.get('NIX_REMOTE_SYSTEMS') == None:
remote_machines = []
for m in sorted(selected, key=lambda m: m.index):
key_file = m.get_ssh_private_key_file()
if not key_file: raise Exception("do not know private SSH key for machine ‘{0}’".format(m.name))
# FIXME: Figure out the correct machine type of ‘m’ (it might not be x86_64-linux).
remote_machines.append("root@{0} {1} {2} 2 1\n".format(m.get_ssh_name(), 'i686-linux,x86_64-linux', key_file))
# Use only a single machine for now (issue #103).
break
remote_machines_file = "{0}/nix.machines".format(self.tempdir)
with open(remote_machines_file, "w") as f:
f.write("".join(remote_machines))
os.environ['NIX_REMOTE_SYSTEMS'] = remote_machines_file
else:
self.logger.log("using predefined remote systems file: {0}".format(os.environ['NIX_REMOTE_SYSTEMS']))

# FIXME: Use ‘--option use-build-hook true’ instead of setting
# $NIX_BUILD_HOOK, once Nix supports that.
os.environ['NIX_BUILD_HOOK'] = os.path.dirname(os.path.realpath(nixops.util.which("nix-build"))) + "/../libexec/nix/build-remote.pl"

load_dir = "{0}/current-load".format(self.tempdir)
if not os.path.exists(load_dir): os.makedirs(load_dir, 0700)
os.environ['NIX_CURRENT_LOAD'] = load_dir

try:
configs_path = subprocess.check_output(
["nix-build"]
Expand Down Expand Up @@ -896,6 +878,32 @@ def worker(r):
r.create(self.definitions[r.name], check=check, allow_reboot=allow_reboot, allow_recreate=allow_recreate)

if is_machine(r):
# If we're not running on Linux, then perform the build on the
# target machines. FIXME: Also enable this if we're on 32-bit
# and want to deploy to 64-bit.
if platform.system() != 'Linux' and os.environ.get('NIX_REMOTE') != 'daemon':
if os.environ.get('NIX_REMOTE_SYSTEMS') == None:
# Use only a single machine for now (issue #103).
key_file = r.get_ssh_private_key_file()
if not key_file: raise Exception("do not know private SSH key for machine ‘{0}’".format(r.name))
# FIXME: Figure out the correct machine type of ‘m’ (it might not be x86_64-linux).
remote_machine = "root@{0} {1} {2} 2 1\n".format(r.get_ssh_name(), 'i686-linux,x86_64-linux', key_file)
remote_machines_file = "{0}/nix.machines".format(self.tempdir)
with open(remote_machines_file, "w") as f:
f.write(remote_machine)
os.environ['NIX_REMOTE_SYSTEMS'] = remote_machines_file

# FIXME: Use ‘--option use-build-hook true’ instead of setting
# $NIX_BUILD_HOOK, once Nix supports that.
os.environ['NIX_BUILD_HOOK'] = os.path.dirname(os.path.realpath(nixops.util.which("nix-build"))) + "/../libexec/nix/build-remote.pl"

load_dir = "{0}/current-load".format(self.tempdir)
if not os.path.exists(load_dir): os.makedirs(load_dir, 0700)
os.environ['NIX_CURRENT_LOAD'] = load_dir

else:
self.logger.log("using remote systems file: {0}".format(os.environ['NIX_REMOTE_SYSTEMS']))

# The first time the machine is created,
# record the state version. We get it from
# /etc/os-release, rather than from the
Expand Down