def add_vlan( group_dev: str = typer.Argument(...), pvid: str = typer.Argument(...), ip: str = typer.Argument(None), mask: str = typer.Argument("255.255.255.0"), name: str = None, description: str = None, interface: str = None, vrid: str = None, vrrp_ip: str = None, vrrp_pri: int = None, default: bool = typer.Option(False, "-d", is_flag=True, help="Use default central account", callback=cli.default_callback), debug: bool = typer.Option(False, "--debug", envvar="ARUBACLI_DEBUG", help="Enable Additional Debug Logging", callback=cli.debug_callback), account: str = typer.Option("central_info", envvar="ARUBACLI_ACCOUNT", help="The Aruba Central Account to use (must be defined in the config)", callback=cli.account_name_callback), ) -> None: caasapi = caas.CaasAPI(central=cli.central) cmds = [] cmds += [f"vlan {pvid}", "!"] if name: cmds += [f"vlan-name {name}", "!", f"vlan {name} {pvid}", "!"] if ip: _fallback_desc = f"VLAN{pvid}-SVI" cmds += [f"interface vlan {pvid}", f"description {description or name or _fallback_desc}", f"ip address {ip} {mask}", "!"] if vrid: cmds += [f"vrrp {vrid}", f"ip address {vrrp_ip}", f"vlan {pvid}"] if vrrp_pri: cmds += [f"priority {vrrp_pri}"] cmds += ["no shutdown", "!"] resp = cli.central.request(caasapi.send_commands, group_dev, cmds) caas.eval_caas_response(resp)
def bulk_edit( input_file: Path = typer.Argument(config.bulk_edit_file, ), default: bool = typer.Option(False, "-d", is_flag=True, help="Use default central account", callback=cli.default_callback), debug: bool = typer.Option(False, "--debug", envvar="ARUBACLI_DEBUG", help="Enable Additional Debug Logging", callback=cli.debug_callback), account: str = typer.Option( "central_info", envvar="ARUBACLI_ACCOUNT", help="The Aruba Central Account to use (must be defined in the config)", callback=cli.account_name_callback), ) -> None: caasapi = caas.CaasAPI(central=cli.central) cmds = caasapi.build_cmds(file=input_file) # TODO log cli if cmds: typer.secho("Commands:", fg="bright_green") typer.echo("\n".join(cmds)) if typer.confirm("Send Commands"): for dev in caasapi.data: group_dev = f"{caasapi.data[dev]['_common'].get('group')}/{dev}" resp = cli.central.request(caasapi.send_commands, group_dev, cmds) caas.eval_caas_response(resp) else: raise typer.Abort()
def _build_pre_config(node: str, dev_type: SendConfigDevIdens, cfg_file: Path, var_file: Path = None) -> PreConfig: """Build Configuration from raw config or jinja2 template/variable file. Args: node (str): The name of the central node (group name or device MAC for gw) dev_type (str): Type of device being pre-provisioned. One of 'gw' or 'ap'. cfg_file (Path): Path of the config file. var_file (Path, optional): Path of the variable file. Defaults to None. Raises: typer.Exit: If config is j2 template but no variable file is found. typer.Exit: If result of config generation yields no commands Returns: PreConfig: PreConfig object """ if not cfg_file.exists(): print(f":warning: [cyan]{node}[/] {cfg_file} not found. Unable to generate config.") raise typer.Exit(1) br = cli.central.BatchRequest caasapi = caas.CaasAPI(central=cli.central) config_out = utils.generate_template(cfg_file, var_file=var_file) commands = utils.validate_config(config_out) if dev_type == "gw": return PreConfig(name=node, config=config_out, request=br(caasapi.send_commands, node, cli_cmds=commands)) elif dev_type == "ap": return PreConfig(name=node, config=config_out, request=br(cli.central.replace_ap_config, node, clis=commands))
def send_cmds( kw1: constants.SendCmdArgs = typer.Argument( ..., ), nodes: str = typer.Argument( None, autocompletion=cache.send_cmds_completion, metavar=iden.group_or_dev_or_site, # callback=cli.send_cmds_node_callback, # is_eager=True, ), kw2: str = typer.Argument( None, autocompletion=cache.send_cmds_completion, # callback=cli.send_cmds_node_callback, ), commands: List[str] = typer.Argument(None, callback=cli.send_cmds_node_callback), cmd_file: Path = typer.Option(None, help="Path to file containing commands (1 per line) to be sent to device", exists=True), # dev_file: Path = typer.Option(None, help="Path to file containing iden for devices to send commands to", exists=True), # group: bool = typer.Option(None, help="Send commands to all gateways in a group", autocompletion=cli.cache.group_completion), # site: bool = typer.Option(None, help="Send commands to all gateways in a site", autocompletion=cli.cache.site_completion), all: bool = typer.Option(False, "-A", help="Send command(s) to all gateways (device level update) when group is provided"), yes: bool = typer.Option(False, "-Y", help="Bypass confirmation prompts - Assume Yes"), yes_: bool = typer.Option(False, "-y", hidden=True), default: bool = typer.Option(False, "-d", is_flag=True, help="Use default central account", callback=cli.default_callback), debug: bool = typer.Option(False, "--debug", envvar="ARUBACLI_DEBUG", help="Enable Additional Debug Logging", callback=cli.debug_callback), account: str = typer.Option("central_info", envvar="ARUBACLI_ACCOUNT", help="The Aruba Central Account to use (must be defined in the config)", callback=cli.account_name_callback), ) -> None: console = Console(emoji=False) yes = yes if yes else yes_ commands = commands or [] if kw1 == "group": if all: g = cache.get_group_identifier(nodes) nodes = [cache.CentralObject(d) for d in cache.devices if d["type"] == "gw" and d["group"] == g.name] action = f"all devices in {g.name} group." else: nodes = cache.get_group_identifier(nodes) action = f"group level gateway config for {nodes.name} group." elif kw1 == "site": s = cache.get_group_identifier(nodes) nodes = [cache.CentralObject(d) for d in cache.devices if d["type"] == "gw" and d["site"] == s.name] action = f"all devices in site: {s.name}" elif kw1 == "file": dev_file = Path(nodes) file_data = config.get_file_data(dev_file, text_ok=True) if not file_data: print(f"No data parsed from file {dev_file.name}.") raise typer.Exit(1) if isinstance(file_data, list): nodes = [cache.get_identifier(d.strip(), ["dev", "group", "site"], device_type="gw") for d in file_data] else: devices = file_data.get("devices", file_data.get("gateways")) if devices: nodes = [cache.get_identifier(d.strip(), ["dev", "group", "site"], device_type="gw") for d in file_data["devices"]] elif "groups" in file_data: nodes = [cache.CentralObject(d) for d in cache.devices if d["type"] == "gw" and d["group"] in file_data["groups"]] elif "sites" in file_data: nodes = [cache.CentralObject(d) for d in cache.devices if d["type"] == "gw" and d["site"] in file_data["sites"]] else: print(f"Expected 'gateways', 'groups', or 'sites' key in {dev_file.name}.") raise typer.Exit(1) if "cmds" in file_data or "commands" in file_data: if commands: print("Providing commands on the command line and in the import file is a strange thing to do.") raise typer.Exit(1) commands = file_data.get("cmds", file_data.get("commands")) elif kw1 == "device": if not isinstance(nodes, str): print(f"nodes is of type {type(nodes)} this is unexpected.") nodes = [cache.get_identifier(nodes, ["dev"], "gw")] if cmd_file: if commands: print("Providing commands on the command line and in the import file is a strange thing to do.") raise typer.Exit(1) else: commands = [line.rstrip() for line in cmd_file.read_text().splitlines()] if not commands: print("Error No commands provided") raise typer.Exit(1) if yes or typer.confirm("\nProceed?", abort=True): caasapi = caas.CaasAPI(central=cli.central) _reqs = [ cli.central.BatchRequest( caasapi.send_commands, n.name if not n.is_dev else n.mac, cli_cmds=commands ) for n in utils.listify(nodes) ] batch_res = cli.central.batch_request(_reqs) cli.display_results(batch_res, cleaner=cleaner.parse_caas_response)
def caas_batch( key: str = typer.Argument(None,), file: Path = typer.Option(config.stored_tasks_file, exists=True,), command: str = typer.Option(None,), default: bool = typer.Option(False, "-d", is_flag=True, help="Use default central account", callback=cli.default_callback), debug: bool = typer.Option(False, "--debug", envvar="ARUBACLI_DEBUG", help="Enable Additional Debug Logging", callback=cli.debug_callback), account: str = typer.Option("central_info", envvar="ARUBACLI_ACCOUNT", help="The Aruba Central Account to use (must be defined in the config)", callback=cli.account_name_callback), ) -> None: """cencli caas batch add-vlan add-vlan-99""" caasapi = caas.CaasAPI(central=cli.central) if file == config.stored_tasks_file and not key: print("[bright_red]ERROR:[/] key is required when using the default import file") raise typer.Exit(1) data = config.get_file_data(file) if hasattr(data, "dict"): # csv data = data.dict data = {k: data[k] for k in data if data.get("key", "") == key} else: data = data.get(key) if not data: print(f"[bright_red]ERROR:[/] [cyan]{key}[/] not found in [cyan]{file}[/]. No Data to Process") raise typer.Exit(1) else: args = data.get("arguments", []) kwargs = data.get("options", {}) cmds = data.get("cmds", []) if not args: print("[bright_red]ERROR:[/] import data requires an argument specifying the group / device") raise typer.Exit(1) if command: command = command.replace('-', '_') _msg1 = typer.style( f"Proceed with {command}:", fg="cyan" ) _msg2 = f"{', '.join(args)} {', '.join([f'{k}={v}' for k, v in kwargs.items()])}" confirm_msg = typer.style(f"{_msg1} {_msg2}?", fg="bright_green") if command in globals(): fn = globals()[command] if typer.confirm(confirm_msg): fn(*args, **kwargs) # type: ignore # NoQA else: raise typer.Abort() else: typer.echo(f"{command} doesn't appear to be valid") elif cmds: print(f"\nSending the following to [cyan]{utils.unlistify(args)}[/]") if kwargs: print("\n With the following options:") _ = [print(f" {k} : {v}") for k, v in kwargs.items()] print(f" [bold]cli cmds:[/]") _ = [print(f" [cyan]{c}[/]") for c in cmds] if typer.confirm("Proceed:"): kwargs = {**kwargs, **{"cli_cmds": cmds}} resp = cli.central.request(caasapi.send_commands, *args, **kwargs) caas.eval_caas_response(resp)
def config_( group_dev: str = typer.Argument( ..., metavar="GROUP|DEVICE", help="Group or device to update.", autocompletion=cli.cache.group_dev_ap_gw_completion ), # TODO simplify structure can just remove device arg # device: str = typer.Argument( # None, # autocompletion=cli.cache.dev_ap_gw_completion # # TODO dev type gw or ap only # # autocompletion=lambda incomplete: [ # # c for c in cli.cache.dev_completion(incomplete, dev_type="gw") if c.lower().startswith(incomplete.lower()) # # ] # ), # TODO collect multi-line input as option to paste in config cli_file: Path = typer.Argument(..., help="File containing desired config/template in CLI format.", exists=True, autocompletion=lambda incomplete: tuple()), var_file: Path = typer.Argument(None, help="File containing variables for j2 config template.", exists=True, autocompletion=lambda incomplete: tuple()), # TODO --vars PATH help="File containing variables to convert jinja2 template." yes: bool = typer.Option(False, "-Y", help="Bypass confirmation prompts - Assume Yes"), yes_: bool = typer.Option(False, "-y", hidden=True), do_gw: bool = typer.Option(None, "--gw", help="Show group level config for gateways."), do_ap: bool = typer.Option(None, "--ap", help="Show group level config for APs."), debug: bool = typer.Option(False, "--debug", envvar="ARUBACLI_DEBUG", help="Enable Additional Debug Logging",), default: bool = typer.Option(False, "-d", is_flag=True, help="Use default central account", show_default=False,), account: str = typer.Option("central_info", envvar="ARUBACLI_ACCOUNT", help="The Aruba Central Account to use (must be defined in the config)",), ) -> None: yes = yes_ if yes_ else yes group_dev: CentralObject = cli.cache.get_identifier(group_dev, qry_funcs=["group", "dev"], device_type=["ap", "gw"]) config_out = utils.generate_template(cli_file, var_file=var_file) cli_cmds = utils.validate_config(config_out) # TODO render.py module with helper function to return styled rule/line console = Console(record=True, emoji=False) console.begin_capture() console.rule("Configuration to be sent") console.print("\n".join([f"[green]{line}[/green]" for line in cli_cmds])) console.rule() console.print(f"\nUpdating {'group' if group_dev.is_group else group_dev.generic_type.upper()} [cyan]{group_dev.name}") _msg = console.end_capture() if group_dev.is_group: device = None if not do_ap and not do_gw: print("Invalid Input, --gw or --ap option must be supplied for group level config.") raise typer.Exit(1) else: # group_dev is a device iden device = group_dev if do_gw or (device and device.generic_type == "gw"): if device and device.generic_type != "gw": print(f"Invalid input: --gw option conflicts with {device.name} which is an {device.generic_type}") raise typer.Exit(1) use_caas = True caasapi = caas.CaasAPI(central=cli.central) # XXX Burried import node_iden = group_dev.name if group_dev.is_group else group_dev.mac elif do_ap or (device and device.generic_type == "ap"): if device and device.generic_type != "ap": print(f"Invalid input: --ap option conflicts with {device.name} which is a {device.generic_type}") raise typer.Exit(1) use_caas = False node_iden = group_dev.name if group_dev.is_group else group_dev.serial typer.echo(_msg) if yes or typer.confirm("Proceed?", abort=True): if use_caas: resp = cli.central.request(caasapi.send_commands, node_iden, cli_cmds) cli.display_results(resp, cleaner=cleaner.parse_caas_response) else: # FIXME this is OK for group level ap config , for AP this method is not valid if group_dev.is_dev: print("Not Implemented yet for AP device level updates") raise typer.Exit(1) resp = cli.central.request(cli.central.replace_ap_config, node_iden, cli_cmds) cli.display_results(resp, tablefmt="action")