diff --git a/nixops/backends/none.py b/nixops/backends/none.py index a5eb83fcc..a66ab0704 100644 --- a/nixops/backends/none.py +++ b/nixops/backends/none.py @@ -1,8 +1,11 @@ # -*- coding: utf-8 -*- +import os +import sys +import nixops.util from nixops.backends import MachineDefinition, MachineState -import nixops.util -import sys +from nixops.util import attr_property, create_key_pair + class NoneDefinition(MachineDefinition): """Definition of a trivial machine.""" @@ -24,21 +27,56 @@ def get_type(cls): return "none" target_host = nixops.util.attr_property("targetHost", None) + _ssh_private_key = attr_property("none.sshPrivateKey", None) + _ssh_public_key = attr_property("none.sshPublicKey", None) def __init__(self, depl, name, id): MachineState.__init__(self, depl, name, id) + @property + def resource_id(self): + return self.vm_id + + def get_physical_spec(self): + return { + ('config', 'users', 'extraUsers', 'root', 'openssh', + 'authorizedKeys', 'keys'): [self._ssh_public_key] + } if self._ssh_public_key else {} + def create(self, defn, check, allow_reboot, allow_recreate): assert isinstance(defn, NoneDefinition) self.set_common_state(defn) self.target_host = defn._target_host + if not self.vm_id: + self.log_start("generating new SSH keypair...") + key_name = "NixOps client key for {0}".format(self.name) + self._ssh_private_key, self._ssh_public_key = \ + create_key_pair(key_name=key_name) + self.log_end("done.") + self.vm_id = "nixops-{0}-{1}".format(self.depl.uuid, self.name) + def get_ssh_name(self): assert self.target_host return self.target_host + def get_ssh_private_key_file(self): + if self._ssh_private_key_file: + return self._ssh_private_key_file + else: + return self.write_ssh_private_key(self._ssh_private_key) + + def get_ssh_flags(self): + if self.vm_id and self.cur_toplevel: + return ["-o", "StrictHostKeyChecking=no", + "-i", self.get_ssh_private_key_file()] + return [] + def _check(self, res): - res.exists = True # can't really check + if not self.vm_id: + res.exists = False + return + res.exists = True res.is_up = nixops.util.ping_tcp_port(self.target_host, self.ssh_port) if res.is_up: MachineState._check(self, res) diff --git a/tests/none-backend.nix b/tests/none-backend.nix index d6ab4b126..e585b98ec 100644 --- a/tests/none-backend.nix +++ b/tests/none-backend.nix @@ -37,7 +37,6 @@ let target1 = { config, pkgs, ... }: { services.openssh.enable = true; - users.extraUsers.root.openssh.authorizedKeys.keyFiles = [ ./id_test.pub ]; # Ugly again: Replicates assignIPAddresses from build-vms.nix. networking.interfaces.eth1.ip4 = [ { address = "192.168.1.2"; @@ -70,7 +69,6 @@ let target2 = { config, pkgs, ... }: { services.openssh.enable = true; - users.extraUsers.root.openssh.authorizedKeys.keyFiles = [ ./id_test.pub ]; # Ugly again: Replicates assignIPAddresses from build-vms.nix. networking.interfaces.eth1.ip4 = [ { address = "192.168.1.3"; @@ -161,6 +159,14 @@ makeTest { $target1->succeed("vim --version >&2"); }; + # Check whether NixOps correctly generated/installed the SSH key. + subtest "authorized-keys", sub { + $coordinator->succeed("rm ~/.ssh/id_dsa"); + $coordinator->fail("ssh -o BatchMode=yes". + " -o StrictHostKeyChecking=no target1 : >&2"); + $coordinator->succeed("${env} nixops ssh-for-each : >&2"); + }; + # Test ‘nixops info’. subtest "info-after", sub { $coordinator->succeed("${env} nixops info >&2");