diff --git a/annet/cli.py b/annet/cli.py index aa2d85b7..aab530ed 100644 --- a/annet/cli.py +++ b/annet/cli.py @@ -15,12 +15,12 @@ from contextlog import get_logger from valkit.python import valid_logging_level -from annet import api, cli_args, filtering, generators +from annet import api, cli_args, filtering, generators, patching from annet.api import Deployer, collapse_texts from annet.argparse import ArgParser, subcommand from annet.deploy import get_deployer, get_fetcher from annet.diff import gen_sort_diff -from annet.gen import Loader, old_raw +from annet.gen import Loader, format_config_blocks, old_new from annet.lib import get_context_path, repair_context_file from annet.output import OutputDriver, output_driver_connector from annet.storage import Device, get_storage @@ -41,32 +41,6 @@ def list_subcommands(): return globals().copy() -def _gen_current_items( - config, - stdin, - loader: Loader, - output_driver: OutputDriver, - gen_args: cli_args.GenOptions, -) -> Iterable[Tuple[str, str, bool]]: - for device, result in old_raw( - args=gen_args, - loader=loader, - config=config, - stdin=stdin, - do_files_download=True, - use_mesh=False, - ): - if device.hw.vendor != "pc": - destname = output_driver.cfg_file_names(device)[0] - yield (destname, result, False) - else: - for entire_path, entire_data in sorted(result.items(), key=operator.itemgetter(0)): - if entire_data is None: - entire_data = "" - destname = output_driver.entire_config_dest_path(device, entire_path) - yield (destname, entire_data, False) - - @contextmanager def get_loader(gen_args: cli_args.GenOptions, args: cli_args.QueryOptionsBase): exit_stack = ExitStack() @@ -84,23 +58,41 @@ def show(): pass -@subcommand(cli_args.QueryOptions, cli_args.opt_config, cli_args.FileOutOptions, parent=show) -def show_current(args: cli_args.QueryOptions, config, arg_out: cli_args.FileOutOptions) -> None: - """Show current devices' configuration""" - gen_args = cli_args.GenOptions(args, no_acl=True) +@subcommand(cli_args.ShowCurrentOptions, parent=show) +def show_current(args: cli_args.ShowCurrentOptions) -> None: + """Show current devices' configuration, optionally filtered by generator ACL (-g) and interfaces (-i)""" + args.no_acl = not (args.acl or args.allowed_gens or args.filter_ifaces) + filterer = filtering.filterer_connector.get() output_driver = output_driver_connector.get() - with get_loader(gen_args, args) as loader: + with get_loader(args, args) as loader: if not loader.devices: get_logger().error("No devices found for %s", args.query) - items = _gen_current_items( - loader=loader, - output_driver=output_driver, - gen_args=gen_args, - stdin=args.stdin(config=config), - config=config, - ) - output_driver.write_output(arg_out, items, len(loader.devices)) + def items() -> Iterable[Tuple[str, str, bool]]: + for res in old_new( + args, + config=args.config, + loader=loader, + filterer=filterer, + no_new=True, + add_implicit=False, + do_files_download=True, + ): + if res.err: + raise res.err + device = res.device + if not device.is_pc(): + if res.old: + orderer = patching.Orderer.from_hw(device.hw) + old_text = format_config_blocks(orderer.order_config(res.old), device.hw, args.indent) + yield output_driver.cfg_file_names(device)[0], old_text, False + else: + for entire_path, entire_data in sorted(res.old_files.items()): + if entire_data is None: + entire_data = "" + yield output_driver.entire_config_dest_path(device, entire_path), entire_data, False + + output_driver.write_output(args, items(), len(loader.devices)) @subcommand(cli_args.QueryOptions, cli_args.FileOutOptions, parent=show) diff --git a/annet/cli_args.py b/annet/cli_args.py index 532c4248..e146d759 100644 --- a/annet/cli_args.py +++ b/annet/cli_args.py @@ -103,6 +103,8 @@ def opt_query_factory(**kwargs): opt_no_acl = Arg("--no-acl", default=False, help="Disable ACL for config generation") +opt_acl = Arg("--acl", default=False, help="Apply generator ACL to filter output (implied by -g and -i)") + opt_no_acl_exclusive = Arg( "--no-acl-exclusive", default=False, help="Check that ACLs of the executed generators do not intersect" ) @@ -417,6 +419,11 @@ class ShowGenOptions(GenOptions, FileOutOptions): show_hosts_progress = opt_show_hosts_progress +class ShowCurrentOptions(ShowGenOptions): + config = opt_config + acl = opt_acl + + class ShowDiffOptions(DiffOptions, FileOutOptions): indent = opt_indent show_rules = opt_show_rules diff --git a/annet/gen.py b/annet/gen.py index f0b5dbfe..401a6475 100644 --- a/annet/gen.py +++ b/annet/gen.py @@ -26,10 +26,9 @@ from contextlog import get_logger from annet import generators, implicit, patching, rulebook, tracing -from annet.annlib import jsontools from annet.annlib.rbparser.acl import compile_acl_text -from annet.cli_args import DeployOptions, GenOptions, ShowGenOptions -from annet.deploy import get_fetcher, scrub_config +from annet.cli_args import GenOptions, ShowGenOptions +from annet.deploy import get_fetcher from annet.filtering import Filterer from annet.generators import ( BaseGenerator, @@ -425,51 +424,6 @@ def old_new( yield result -@tracing.function -def old_raw( - args: GenOptions, - loader: Loader, - config, - stdin=None, - do_files_download=False, - use_mesh=True, -) -> Iterable[Tuple[Device, Union[str, Dict[str, str]]]]: - device_gens = loader.resolve_gens(loader.devices) - running, failed_running = _old_resolve_running(config, loader.devices) - downloaded_files, failed_files = _old_resolve_files(config, loader.devices, device_gens, do_files_download) - if stdin is None: - stdin = args.stdin(filter_acl=args.filter_acl, config=config) - ctx = OldNewDeviceContext( - config=config, - args=args, - downloaded_files=split_downloaded_files_multi_device(downloaded_files, device_gens, loader.devices), - failed_files=failed_files, - running=running, - failed_running=failed_running, - stdin=stdin, - do_files_download=do_files_download, - device_count=len(loader.devices), - no_new=True, - add_annotations=False, - add_implicit=False, - gens=DeviceGenerators(), - fetched_packages={}, - failed_packages={}, - do_print_perf=True, - ) - for device in loader.devices: - if not device.is_pc(): - config = _old_new_get_config_cli(ctx, device) - config = scrub_config(config, device.breed) - yield device, config - else: - files = _old_new_get_config_files(ctx, device) - if files.entire_files: - yield device, files.entire_files - if files.json_fragment_files: - yield device, {path: jsontools.format_json(data) for path, data in files.json_fragment_files.items()} - - @tracing.function def worker( device_id, args: ShowGenOptions, stdin, loader: "Loader", filterer: Filterer