def state(depl, d, m): if not d and (depl.definitions != None or m.obsolete): return "Obsolete" if d and m and m.obsolete: return "Revived" if not m: return "New" if deployment.is_machine( m) and depl.configs_path != m.cur_configs_path: return "Outdated" if deployment.is_machine(m): return "Up-to-date"
def op_import(args): sf = nixops.statefile.StateFile(args.state_file) existing = set(sf.query_deployments()) dump = json.loads(sys.stdin.read()) for uuid, attrs in dump.iteritems(): if uuid in existing: raise Exception( "state file already contains a deployment with UUID ‘{0}’". format(uuid)) with sf._db: depl = sf.create_deployment(uuid=uuid) depl.import_(attrs) sys.stderr.write("added deployment ‘{0}’\n".format(uuid)) if args.include_keys: for m in depl.active.itervalues(): if deployment.is_machine(m) and hasattr(m, "public_host_key"): if m.public_ipv4: nixops.known_hosts.add(m.public_ipv4, m.public_host_key) if m.private_ipv4: nixops.known_hosts.add(m.private_ipv4, m.public_host_key)
def print_deployment(depl): definitions = depl.definitions or {} # Sort machines by type, then name. Sort numbers in machine # names numerically (e.g. "foo10" comes after "foo9"). def name_to_key(name): d = definitions.get(name) r = depl.resources.get(name) return (machine_to_key(depl.uuid, name, r.get_type()) if r else machine_to_key(depl.uuid, name, d.get_type)) names = sorted(set(definitions.keys()) | set(depl.resources.keys()), key=name_to_key) for name in names: d = definitions.get(name) r = depl.resources.get(name) if deployment.is_machine(r): resource_state = "{0} / {1}".format( r.show_state() if r else "Missing", state(depl, d, r)) else: resource_state = r.show_state() if r else "Missing" if args.plain: print "\t".join(( [depl.uuid, depl.name or "(none)"] if args.all else []) + [ name, resource_state.lower(), r.show_type() if r else d.show_type(), r.resource_id or "" if r else "", r.public_ipv4 or "" if r and hasattr(r, "public_ipv4") else "", r.private_ipv4 or "" if r and deployment.is_machine(r) else "", ]) else: tbl.add_row(([depl.name or depl.uuid] if args.all else []) + [ name, resource_state, r.show_type() if r else d.show_type(), r.resource_id or "" if r else "", (hasattr(r, "public_ipv4") and r.public_ipv4) or (hasattr(r, "private_ipv4") and r.private_ipv4 ) or "" if r else "", ])
def emit_resource(r: nixops.resources.ResourceState) -> None: config = attrs_per_resource[r.name] if is_machine(r): if authorized_keys[r.name]: config.append({ ("users", "extraUsers", "root"): { ("openssh", "authorizedKeys", "keys"): authorized_keys[r.name] }, ("services", "openssh"): { "extraConfig": "PermitTunnel yes\n" }, }) config.append({ ("boot", "kernelModules"): list(kernel_modules[r.name]), ("networking", "firewall"): { "trustedInterfaces": list(trusted_interfaces[r.name]) }, }) # Add SSH public host keys for all machines in network. for m2 in active_machines.values(): if hasattr(m2, "public_host_key") and m2.public_host_key: # Using references to files in same tempdir for now, until NixOS has support # for adding the keys directly as string. This way at least it is compatible # with older versions of NixOS as well. # TODO: after reasonable amount of time replace with string option config.append({ ("services", "openssh", "knownHosts", m2.name): { "hostNames": [ m2.name + "-unencrypted", m2.name + "-encrypted", ], } })
def emit_resource(r: nixops.resources.ResourceState) -> None: config = attrs_per_resource[r.name] if is_machine(r): # NOTE: unfortunate mypy doesn't check that is_machine calls an isinstance() function r = cast(nixops.backends.GenericMachineState, r) # Skip resource emission if the machine is excluded or the associated wgKeypair is not up yet if (not r.defn or r.name not in wg_keypair_list or (wg_keypair_list[r.name].state != wg_keypair_list[r.name].UP)): return # Sort the hosts by its canonical host names. sorted_hosts = sorted(hosts[r.name].items(), key=lambda item: item[1][0]) # Just to remember the format: # ip_address canonical_hostname [aliases...] extra_hosts = {f"{ip}": names for ip, names in sorted_hosts} # Add the base wireguard nix config for machine m wg_local_ipv4 = index_to_private_ip(wg_keypair_list[r.name], r.index) # Substitute wireguard IPs for any wg-link resources name in the dns list if wg_keypair_list[r.name].dns != []: dns_list = cast(List[str], wg_keypair_list[r.name].dns).copy() for i, dns in enumerate(wg_keypair_list[r.name].dns): if dns in wg_name.values(): del dns_list[i] dns_list.insert( i, index_to_private_ip( wg_keypair_list[re.sub("-wg$", "", dns)], active_machines[re.sub("-wg$", "", dns)].index, ), ) else: dns_list = [] config.append({ ("networking", "hosts"): extra_hosts, ("networking", "firewall", "allowedUDPPorts"): [wg_keypair_list[r.name].listen_port], ( "networking", "wg-quick", "interfaces", wg_keypair_list[r.name].interface_name, ): { "address": [f"{wg_local_ipv4}/24"], "listenPort": wg_keypair_list[r.name].listen_port, "privateKeyFile": "/etc/nixops-wg-links/wireguard.private", "dns": dns_list, "mtu": wg_keypair_list[r.name].mtu if (wg_keypair_list[r.name].mtu or 0) >= 1 else None, "preUp": wg_keypair_list[r.name].pre_up, "preDown": wg_keypair_list[r.name].pre_down, "postUp": wg_keypair_list[r.name].post_up, "postDown": wg_keypair_list[r.name].post_down, "table": wg_keypair_list[r.name].table, }, ( "networking", "wg-quick", "interfaces", wg_keypair_list[r.name].interface_name, "peers", ): total_peers[r.name], })