Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions nixops/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@
help="activate unchanged configurations as well",
)
add_common_deployment_options(subparser)
add_common_modify_options(subparser)

subparser = add_subparser(subparsers, "send-keys", help="send encryption keys")
subparser.set_defaults(op=op_send_keys)
Expand Down
44 changes: 44 additions & 0 deletions nixops/evaluation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from dataclasses import dataclass
import subprocess
import typing
import json


@dataclass
class NetworkEval:

description: str = "Unnamed NixOps network"
enableRollback: bool = False
enableState: bool = True


def _eval_attr(
attr, nix_exprs: typing.List[str]
) -> typing.Dict[typing.Any, typing.Any]:
p = subprocess.run(
[
"nix-instantiate",
"--eval-only",
"--json",
"--strict",
# Arg
"--arg",
"checkConfigurationOptions",
"false",
# Attr
"-A",
attr,
]
+ nix_exprs,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
if p.returncode != 0:
raise RuntimeError(p.stderr.decode())

return json.loads(p.stdout)


def eval_network(nix_exprs: typing.List[str]) -> NetworkEval:
result = _eval_attr("network", nix_exprs)
return NetworkEval(**result)
45 changes: 35 additions & 10 deletions nixops/script_defs.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@
from datetime import datetime
from pprint import pprint
import importlib
from functools import lru_cache

from nixops.plugins import get_plugin_manager
from nixops.evaluation import eval_network


pm = get_plugin_manager()
Expand All @@ -37,6 +39,11 @@
]


@lru_cache()
def _create_state(state_file: str) -> nixops.statefile.StateFile:
return nixops.statefile.StateFile(state_file)


def op_list_plugins(args):
if args.verbose:
tbl = create_table([("Installed Plugins", "c"), ("Plugin Reference", "c")])
Expand Down Expand Up @@ -68,14 +75,14 @@ def sort_deployments(
# $NIXOPS_DEPLOYMENT.
def one_or_all(args: Namespace) -> List[nixops.deployment.Deployment]:
if args.all:
sf = nixops.statefile.StateFile(args.state_file)
sf = _create_state(args.state_file)
return sf.get_all_deployments()
else:
return [open_deployment(args)]


def op_list_deployments(args):
sf = nixops.statefile.StateFile(args.state_file)
sf = _create_state(args.state_file)
tbl = create_table(
[
("UUID", "l"),
Expand All @@ -99,7 +106,7 @@ def op_list_deployments(args):


def open_deployment(args):
sf = nixops.statefile.StateFile(args.state_file)
sf = _create_state(args.state_file)
depl = sf.open_deployment(uuid=args.deployment)

depl.extra_nix_path = sum(args.nix_path or [], [])
Expand Down Expand Up @@ -145,12 +152,19 @@ def modify_deployment(args, depl: nixops.deployment.Deployment):


def op_create(args):
sf = nixops.statefile.StateFile(args.state_file)
sf = _create_state(args.state_file)
depl = sf.create_deployment()
sys.stderr.write("created deployment ‘{0}’\n".format(depl.uuid))
modify_deployment(args, depl)
if args.name or args.deployment:
set_name(depl, args.name or args.deployment)

# When deployment is created without state "name" does not exist
name = args.deployment
if "name" in args:
name = args.name or args.deployment

if name:
set_name(depl, name)

sys.stdout.write(depl.uuid + "\n")


Expand Down Expand Up @@ -284,7 +298,7 @@ def name_to_key(name: str) -> Tuple[str, str, List[object]]:
)

if args.all:
sf = nixops.statefile.StateFile(args.state_file)
sf = _create_state(args.state_file)
if not args.plain:
tbl = create_table([("Deployment", "l")] + table_headers)
for depl in sort_deployments(sf.get_all_deployments()):
Expand Down Expand Up @@ -553,7 +567,18 @@ def op_restore(args):


def op_deploy(args):

# If nix expressions are passed evaluate the network first so we can figure
# out if we need to create state or not
if args.nix_exprs:
network = eval_network(args.nix_exprs)
# If state is not enabled we need to create the deployment first in the in-memory sqlite db
if not network.enableState:
args.state_file = ":memory:"
op_create(args)

depl = open_deployment(args)

if args.confirm:
depl.logger.set_autoresponse("y")
if args.evaluate_only:
Expand Down Expand Up @@ -710,7 +735,7 @@ def op_export(args):


def op_import(args):
sf = nixops.statefile.StateFile(args.state_file)
sf = _create_state(args.state_file)
existing = set(sf.query_deployments())

dump = json.loads(sys.stdin.read())
Expand Down Expand Up @@ -1064,7 +1089,7 @@ def add_subparser(
return subparser


def add_common_modify_options(subparser: ArgumentParser):
def add_common_modify_options(subparser: ArgumentParser) -> None:
subparser.add_argument(
"nix_exprs",
nargs="*",
Expand All @@ -1081,7 +1106,7 @@ def add_common_modify_options(subparser: ArgumentParser):
)


def add_common_deployment_options(subparser: ArgumentParser):
def add_common_deployment_options(subparser: ArgumentParser) -> None:
subparser.add_argument(
"--include",
nargs="+",
Expand Down
5 changes: 4 additions & 1 deletion nixops/statefile.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,10 @@ class StateFile(object):
def __init__(self, db_file: str) -> None:
self.db_file: str = db_file

if os.path.splitext(db_file)[1] not in [".nixops", ".charon"]:
if db_file != ":memory:" and os.path.splitext(db_file)[1] not in [
".nixops",
".charon",
]:
raise Exception(
"state file ‘{0}’ should have extension ‘.nixops’".format(db_file)
)
Expand Down