From ffd40d6ee7c435c4b886a147e6170610370d2d48 Mon Sep 17 00:00:00 2001 From: Michael Fellinger Date: Fri, 24 Apr 2020 14:50:22 +0200 Subject: [PATCH 1/2] add nixops eval subcommand --- nix/eval-machine-info.nix | 8 +++++--- nixops/__main__.py | 10 ++++++++++ nixops/deployment.py | 33 ++++++++++++++++++++++++++++++++- nixops/script_defs.py | 8 ++++++++ 4 files changed, 55 insertions(+), 4 deletions(-) diff --git a/nix/eval-machine-info.nix b/nix/eval-machine-info.nix index 0ee2cb1ae..208acda90 100644 --- a/nix/eval-machine-info.nix +++ b/nix/eval-machine-info.nix @@ -5,13 +5,15 @@ , deploymentName , args , pluginNixExprs +, evalFile ? null }: with import { inherit system; }; with lib; - -rec { +let + evaluator = if evalFile != null then (import evalFile) else id; +in evaluator (rec { importedPluginNixExprs = map (expr: import expr) @@ -200,4 +202,4 @@ rec { getNixOpsArgs = fs: lib.zipAttrs (lib.unique (lib.concatMap fileToArgs (getNixOpsExprs fs))); nixopsArguments = getNixOpsArgs networkExprs; -} +}) diff --git a/nixops/__main__.py b/nixops/__main__.py index 3bc45f247..593483195 100755 --- a/nixops/__main__.py +++ b/nixops/__main__.py @@ -527,6 +527,16 @@ help="include the physical specification in the evaluation", ) +subparser = add_subparser( + subparsers, "eval", help="eval the given file is nix code in the network expression" +) +subparser.set_defaults(op=op_eval) +subparser.add_argument("code", metavar="CODE", help="code") +subparser.add_argument( + "--json", action="store_true", help="print the option value in JSON format" +) +subparser.add_argument("--strict", action="store_true", help="enable strict evaluation") + subparser = add_subparser( subparsers, "list-generations", diff --git a/nixops/deployment.py b/nixops/deployment.py index 5171613e9..7573f4b90 100644 --- a/nixops/deployment.py +++ b/nixops/deployment.py @@ -395,7 +395,7 @@ def _eval_flags(self, exprs: List[str]) -> List[str]: "--arg", "pluginNixExprs", py2nix(extraexprs), - "", + self.expr_path + "/eval-machine-info.nix", ] ) return flags @@ -503,6 +503,37 @@ def evaluate(self) -> None: ) self.definitions[name] = defn + def evaluate_code(self, code: str, json: bool = False, strict: bool = False) -> str: + """Evaluate nix code in the deployment specification.""" + + exprs = self.nix_exprs + phys_expr = self.tempdir + "/physical.nix" + with open(phys_expr, "w") as f: + f.write(self.get_physical_spec()) + exprs.append(phys_expr) + + try: + return subprocess.check_output( + ["nix-instantiate"] + + self.extra_nix_eval_flags + + self._eval_flags(exprs) + + [ + "--eval-only", + "--arg", + "checkConfigurationOptions", + "false", + "--arg", + "evalFile", + code, + ] + + (["--strict"] if strict else []) + + (["--json"] if json else []), + stderr=self.logger.log_file, + text=True, + ) + except subprocess.CalledProcessError: + raise NixEvalError + def evaluate_option_value( self, machine_name: str, diff --git a/nixops/script_defs.py b/nixops/script_defs.py index 567f163d7..faac0d3b7 100644 --- a/nixops/script_defs.py +++ b/nixops/script_defs.py @@ -893,6 +893,14 @@ def op_show_option(args): ) +def op_eval(args): + with deployment(args) as depl: + depl.evaluate() + sys.stdout.write( + depl.evaluate_code(args.code, json=args.json, strict=args.strict) + ) + + @contextlib.contextmanager def deployment_with_rollback(args): with deployment(args) as depl: From 61b6fc5711a5c9260d15cbf55ef3d5a7d4a8937b Mon Sep 17 00:00:00 2001 From: Michael Fellinger Date: Mon, 27 Apr 2020 12:36:56 +0200 Subject: [PATCH 2/2] Improve docs of `nixops eval` --- nixops/__main__.py | 14 ++++++++++---- nixops/deployment.py | 4 ++-- nixops/script_defs.py | 2 +- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/nixops/__main__.py b/nixops/__main__.py index 593483195..bf495fcfa 100755 --- a/nixops/__main__.py +++ b/nixops/__main__.py @@ -528,14 +528,20 @@ ) subparser = add_subparser( - subparsers, "eval", help="eval the given file is nix code in the network expression" + subparsers, + "eval", + help="evaluate a Nix expression with the NixOps network as arguments", ) subparser.set_defaults(op=op_eval) -subparser.add_argument("code", metavar="CODE", help="code") +subparser.add_argument("file", metavar="FILE", help="file containing a Nix expression") subparser.add_argument( - "--json", action="store_true", help="print the option value in JSON format" + "--json", action="store_true", help="convert and print the return value as JSON" +) +subparser.add_argument( + "--strict", + action="store_true", + help="enable strict evaluation, (use with --json if value is more than a level deep)", ) -subparser.add_argument("--strict", action="store_true", help="enable strict evaluation") subparser = add_subparser( subparsers, diff --git a/nixops/deployment.py b/nixops/deployment.py index 7573f4b90..3e1a9fe87 100644 --- a/nixops/deployment.py +++ b/nixops/deployment.py @@ -503,7 +503,7 @@ def evaluate(self) -> None: ) self.definitions[name] = defn - def evaluate_code(self, code: str, json: bool = False, strict: bool = False) -> str: + def evaluate_code(self, file: str, json: bool = False, strict: bool = False) -> str: """Evaluate nix code in the deployment specification.""" exprs = self.nix_exprs @@ -524,7 +524,7 @@ def evaluate_code(self, code: str, json: bool = False, strict: bool = False) -> "false", "--arg", "evalFile", - code, + file, ] + (["--strict"] if strict else []) + (["--json"] if json else []), diff --git a/nixops/script_defs.py b/nixops/script_defs.py index faac0d3b7..f47049a08 100644 --- a/nixops/script_defs.py +++ b/nixops/script_defs.py @@ -897,7 +897,7 @@ def op_eval(args): with deployment(args) as depl: depl.evaluate() sys.stdout.write( - depl.evaluate_code(args.code, json=args.json, strict=args.strict) + depl.evaluate_code(args.file, json=args.json, strict=args.strict) )