def save(extract, filename, **kwargs): """ save lab to a local yaml file """ server = VIRLServer() client = get_cml_client(server) current_lab = get_current_lab() if current_lab: lab = safe_join_existing_lab(current_lab, client) if lab: if extract: click.secho("Extracting configurations...") extract_configurations(lab) lab_export = lab.download() click.secho("Writing {}".format(filename)) with open(filename, "w") as fd: fd.write(lab_export) else: click.secho("Failed to find running lab {}".format(current_lab), fg="red") exit(1) else: click.secho("Current lab is not set", fg="red") exit(1)
def pyats(**kwargs): """ generates a pyats testbed config for a lab """ server = VIRLServer() client = get_cml_client(server) current_lab = get_current_lab() if current_lab: lab = safe_join_existing_lab(current_lab, client) if lab: if kwargs.get("output"): # user specified output filename file_name = kwargs.get("output") else: # writes to <lab.id>_testbed.yaml by default file_name = "{}_testbed.yaml".format(lab.id) testbed = pyats_testbed_generator(lab) if testbed: click.secho("Writing {}".format(file_name)) with open(file_name, "w") as fd: fd.write(testbed) else: click.secho("Failed to get testbed data", fg="red") exit(1) else: click.secho("Failed to find running lab {}".format(current_lab), fg="red") exit(1) else: click.secho("Current lab is not set", fg="red") exit(1)
def down(id=None, lab_name=None): """ stop a lab """ server = VIRLServer() client = get_cml_client(server) lab = None if id: lab = safe_join_existing_lab(id, client) if not lab and lab_name: lab = safe_join_existing_lab_by_title(lab_name, client) if not lab: lab_id = get_current_lab() if lab_id: lab = safe_join_existing_lab(lab_id, client) if lab: if lab.is_active(): click.secho("Shutting down lab {} (ID: {}).....".format( lab.title, lab.id)) lab.stop() click.echo(click.style("SUCCESS", fg="green")) else: click.secho( "Lab with ID {} and title {} is already stopped".format( lab.id, lab.title)) else: click.secho("Failed to find lab on server", fg="red") exit(1)
def stop(node): """ stop a node """ server = VIRLServer() client = get_cml_client(server) current_lab = get_current_lab() if current_lab: lab = safe_join_existing_lab(current_lab, client) if lab: try: node_obj = lab.get_node_by_label(node) if node_obj.is_active(): node_obj.stop(wait=True) click.secho("Stopped node {}".format(node_obj.label)) else: click.secho("Node {} is already stopped".format( node_obj.label), fg="yellow") except NodeNotFound: click.secho("Node {} was not found in lab {}".format( node, current_lab), fg="red") exit(1) else: click.secho("Unable to find lab {}".format(current_lab), fg="red") exit(1) else: click.secho("No current lab set", fg="red") exit(1)
def rm(force, confirm, from_cache): """ remove a lab """ server = VIRLServer() client = get_cml_client(server) current_lab = get_current_lab() if current_lab: lab = safe_join_existing_lab(current_lab, client) if lab: if lab.is_active() and force: lab.stop(wait=True) if lab.state() != "DEFINED_ON_CORE" and force: lab.wipe(wait=True) # Check again just to be sure. if lab.state() == "DEFINED_ON_CORE": ret = "y" if confirm: ret = input( "Are you sure you want to remove lab {} (ID: {}) [y/N]? " .format(lab.title, current_lab)) if ret.lower().startswith("y"): # We need to save the lab's title before we remove it. title = lab.title lab.remove() click.secho("Lab {} (ID: {}) removed".format( title, current_lab)) if from_cache: try: os.remove(check_lab_cache(current_lab)) except OSError: # File doesn't exist. pass click.secho( "Removed lab {} from cache".format(current_lab)) clear_current_lab() else: click.secho("Not removing lab {} (ID: {})".format( lab.title, current_lab)) else: click.secho( "Lab {} (ID: {}) is either active or not wiped; either down and wipe it or use --force" .format(lab.title, current_lab), fg="red", ) exit(1) else: click.secho("Unable to find lab {}".format(current_lab), fg="red") exit(1) else: click.secho("Current lab is not set", fg="red") exit(1)
def command(node, command, config, **kwargs): """ send a command or config to a node (requires pyATS) """ server = VIRLServer() client = get_cml_client(server) current_lab = get_current_lab() if current_lab: lab = safe_join_existing_lab(current_lab, client) if lab: pylab = None try: pylab = ClPyats(lab) except PyatsNotInstalled: click.secho("pyATS is not installed, run 'pip install pyats'", fg="red") exit(1) pyats_username = server.config.get("CML_DEVICE_USERNAME") pyats_password = server.config.get("CML_DEVICE_PASSWORD") pyats_auth_password = server.config.get( "CML_DEVICE_ENABLE_PASSWORD") if pyats_username: os.environ["PYATS_USERNAME"] = pyats_username if pyats_password: os.environ["PYATS_PASSWORD"] = pyats_password if pyats_auth_password: os.environ["PYATS_AUTH_PASS"] = pyats_auth_password pylab.sync_testbed(server.user, server.passwd) try: result = "" if config: result = pylab.run_config_command(node, command) else: result = pylab.run_command(node, command) click.secho(result) except PyatsDeviceNotFound: click.secho("Node '{}' is not supported by pyATS".format(node), fg="yellow") except Exception as e: click.secho("Failed to run '{}' on '{}': {}".format( command, node, e)) exit(1) else: click.secho("Unable to find lab {}".format(current_lab), fg="red") exit(1) else: click.secho("No current lab set", fg="red") exit(1)
def ui(): """ opens the Workbench for the current lab """ server = VIRLServer() client = get_cml_client(server) current_lab = get_current_lab() if current_lab: lab = safe_join_existing_lab(current_lab, client) if lab: url = "https://{}/lab/{}".format(server.host, current_lab) subprocess.Popen(["open", url])
def ssh(node): """ ssh to a node """ server = VIRLServer() client = get_cml_client(server) username = server.config.get("VIRL_SSH_USERNAME", "cisco") current_lab = get_current_lab() if current_lab: lab = safe_join_existing_lab(current_lab, client) if lab: node_obj = lab.get_node_by_label(node) if node_obj: if node_obj.is_active(): mgmtip = get_node_mgmt_ip(node_obj) if mgmtip: if "VIRL_SSH_COMMAND" in server.config: cmd = server.config["VIRL_SSH_COMMAND"] cmd = cmd.format(host=mgmtip, username=username) print("Calling user specified command: {}".format( cmd)) exit(call(cmd.split())) else: click.secho( "Attemping ssh connection to {} at {}".format( node_obj.label, mgmtip)) exit( call(["ssh", "{}@{}".format(username, mgmtip)])) else: click.secho( "Node {} does not have an external management IP". format(node_obj.label)) else: click.secho("Node {} is not active".format(node_obj.label), fg="yellow") else: click.secho("Node {} was not found in lab {}".format( node, current_lab), fg="red") exit(1) else: click.secho("Unable to find lab {}".format(current_lab), fg="red") exit(1) else: click.secho("No current lab set", fg="red") exit(1)
def node(node, force, confirm): """ wipe a node """ server = VIRLServer() client = get_cml_client(server) current_lab = get_current_lab() if current_lab: lab = safe_join_existing_lab(current_lab, client) if lab: node_obj = lab.get_node_by_label(node) if node_obj: if node_obj.is_active() and force: node_obj.stop() while node_obj.is_active(): time.sleep(1) if not node_obj.is_active(): ret = "y" if confirm: ret = input( "Are you sure you want to wipe node {} [y/N]? ". format(node_obj.label)) if ret.lower().startswith("y"): node_obj.wipe(wait=True) click.secho("Node {} wiped".format(node_obj.label)) else: click.secho("Not wiping node {}".format( node_obj.label)) else: click.secho( "Node {} is active; either stop it or use --force". format(node_obj.label), fg="red") exit(1) else: click.secho("Node {} was not found in lab {}".format( node, current_lab), fg="red") exit(1) else: click.secho("Unable to find lab {}".format(current_lab), fg="red") exit(1) else: click.secho("No current lab set", fg="red") exit(1)
def nso(syncfrom, **kwargs): """ generate nso inventory """ server = VIRLServer() client = get_cml_client(server) current_lab = get_current_lab() if current_lab: lab = safe_join_existing_lab(current_lab, client) if lab: if kwargs.get("output"): file_name = kwargs.get("output") else: file_name = None inv = nso_payload_generator(lab, server) if inv: if file_name: click.secho("Writing {}".format(file_name)) with open(file_name, "w") as fd: fd.write(inv) else: click.secho("Updating NSO....") nso_obj = NSO() nso_response = nso_obj.update_devices(inv) if nso_response.ok: click.secho("Successfully added CML devices to NSO") else: click.secho("Error updating NSO: ", fg="red") click.secho(nso_response.text) if syncfrom: resp = nso_obj.perform_sync_from() sync_table(resp.json()) else: click.secho("Failed to get inventory data", fg="red") exit(1) else: click.secho("Failed to find running lab {}".format(current_lab), fg="red") exit(1) else: click.secho("Current lab is not set", fg="red") exit(1)
def telnet(node): """ telnet to a node """ server = VIRLServer() client = get_cml_client(server) current_lab = get_current_lab() if current_lab: lab = safe_join_existing_lab(current_lab, client) if lab: try: node_obj = lab.get_node_by_label(node) except NodeNotFound: click.secho("Node {} was not found in lab {}".format( node, current_lab), fg="red") exit(1) if node_obj.is_active(): mgmtip = get_node_mgmt_ip(node_obj) if mgmtip: if "VIRL_TELNET_COMMAND" in server.config: cmd = server.config["VIRL_TELNET_COMMAND"] cmd = cmd.format(host=mgmtip) print("Calling user specified command: {}".format(cmd)) exit(call(cmd.split())) else: click.secho( "Attemping telnet connection to {} at {}".format( node_obj.label, mgmtip)) exit(call(["telnet", mgmtip])) else: click.secho( "Node {} does not have an external management IP". format(node_obj.label)) else: click.secho("Node {} is not active".format(node_obj.label), fg="yellow") else: click.secho("Unable to find lab {}".format(current_lab), fg="red") exit(1) else: click.secho("No current lab set", fg="red") exit(1)
def nodes(): """ get node list for the current lab """ server = VIRLServer() client = get_cml_client(server) current_lab = get_current_lab() if current_lab: lab = safe_join_existing_lab(current_lab, client) if lab: node_list_table(lab.nodes()) else: click.secho("Lab {} is not running".format(current_lab), fg="red") exit(1) else: click.secho("No current lab selected", fg="red") exit(1)
def generate(delimiter, output): """ generate generic CSV inventory """ server = VIRLServer() client = get_cml_client(server) current_lab = get_current_lab() if not current_lab: click.secho("Current lab is not set", fg="red") exit(1) lab = safe_join_existing_lab(current_lab, client) if not lab: click.secho("Failed to find running lab {}".format(current_lab), fg="red") exit(1) exit(CSVInventory.write_inventory(lab.nodes(), delimiter, output))
def lab(force, confirm): """ wipe a lab """ server = VIRLServer() client = get_cml_client(server) current_lab = get_current_lab() if current_lab: lab = safe_join_existing_lab(current_lab, client) if lab: active = check_lab_active(lab) if active and force: lab.stop(wait=True) # Check again just to be sure. if not check_lab_active(lab): ret = "y" if confirm: ret = input( "Are you sure you want to wipe lab {} (ID: {}) [y/N]? " .format(lab.title, current_lab)) if ret.lower().startswith("y"): lab.wipe(wait=True) click.secho("Lab {} (ID: {}) wiped".format( lab.title, current_lab)) else: click.secho("Not wiping lab {} (ID: {})".format( lab.title, current_lab)) else: click.secho( "Lab {} (ID: {}) is active; either down it or use --force". format(lab.title, current_lab), fg="red") exit(1) else: click.secho("Unable to find lab {}".format(current_lab), fg="red") exit(1) else: click.secho("No current lab set", fg="red") exit(1)
def extract(update_cache, **kwargs): """ extract configurations from all nodes in a lab """ server = VIRLServer() client = get_cml_client(server) current_lab = get_current_lab() if current_lab: lab = safe_join_existing_lab(current_lab, client) if lab: extract_configurations(lab) if update_cache: cache_lab(lab, force=True) else: click.secho("Failed to find running lab {}".format(current_lab), fg="red") exit(1) else: click.secho("Current lab is not set", fg="red") exit(1)
def ansible(**kwargs): """ generate ansible inventory """ server = VIRLServer() client = get_cml_client(server) current_lab = get_current_lab() if current_lab: lab = safe_join_existing_lab(current_lab, client) if lab: if kwargs.get("output"): file_name = kwargs.get("output") elif kwargs.get("style") == "ini": file_name = "{}_inventory.ini".format(lab.id) else: file_name = "{}_inventory.yaml".format(lab.id) inv = None if kwargs.get("style") == "ini": inv = ansible_inventory_generator(lab, server, style="ini") else: inv = ansible_inventory_generator(lab, server) if inv: click.secho("Writing {}".format(file_name)) with open(file_name, "w") as fd: fd.write(inv) else: click.secho("Failed to get inventory data", fg="red") exit(1) else: click.secho("Failed to find running lab {}".format(current_lab), fg="red") exit(1) else: click.secho("Current lab is not set", fg="red") exit(1)
def command(node, command, config, **kwargs): """ send a command or config to a node (requires pyATS) """ server = VIRLServer() client = get_cml_client(server) current_lab = get_current_lab() if current_lab: lab = safe_join_existing_lab(current_lab, client) if lab: pylab = None try: pylab = ClPyats(lab) except PyatsNotInstalled: click.secho("pyATS is not installed, run 'pip install pyats'", fg="red") exit(1) pylab.sync_testbed(server.user, server.passwd) try: result = "" if config: result = pylab.run_config_command(node, command) else: result = pylab.run_command(node, command) click.secho(result) except PyatsDeviceNotFound: click.secho("Node '{}' is not supported by pyATS".format(node), fg="yellow") except Exception as e: click.secho("Failed to run '{}' on '{}': {}".format(command, node, e)) exit(1) else: click.secho("Unable to find lab {}".format(current_lab), fg="red") exit(1) else: click.secho("No current lab set", fg="red") exit(1)
def run(new_title): """ re-title the current lab """ server = VIRLServer() client = get_cml_client(server) clab = get_current_lab() if not clab: click.secho("Current lab is not set", fg="red") exit(1) lab = safe_join_existing_lab(clab, client) if lab: lab.title = new_title else: click.secho( "Current lab {} is not present on the server".format(clab), fg="red") exit(1)
def nodes(): """ get node list for the current lab """ server = VIRLServer() client = get_cml_client(server) current_lab = get_current_lab() if current_lab: lab = safe_join_existing_lab(current_lab, client) if lab: try: pl = ViewerPlugin(viewer="node") pl.visualize(nodes=lab.nodes()) except NoPluginError: node_list_table(lab.nodes()) else: click.secho("Lab {} is not running".format(current_lab), fg="red") exit(1) else: click.secho("No current lab selected", fg="red") exit(1)
def lid(): """ get the current lab title and ID """ server = VIRLServer() client = get_cml_client(server) current_lab = get_current_lab() if current_lab: lab = safe_join_existing_lab(current_lab, client) # The lab really should be on the server. if not lab: try: lab = CachedLab(current_lab, get_current_lab_link()) except Exception: pass if lab: click.echo("{} (ID: {})".format(lab.title, current_lab)) else: click.secho( "Current lab is set to {}, but is not on server or in cache!". format(current_lab), fg="red")
def console(node, display, **kwargs): """ console for node """ server = VIRLServer() client = get_cml_client(server) skip_types = ["external_connector", "unmanaged_switch"] current_lab = get_current_lab() if current_lab: lab = safe_join_existing_lab(current_lab, client) if lab: try: node_obj = lab.get_node_by_label(node) except NodeNotFound: click.secho("Node {} was not found in lab {}".format( node, current_lab), fg="red") exit(1) if node_obj.node_definition not in skip_types: if node_obj.is_active(): console = "/{}/{}/0".format(lab.id, node_obj.id) if display: console_table([{"node": node, "console": console}]) else: # use user specified ssh command if "CML_CONSOLE_COMMAND" in server.config: cmd = server.config["CML_CONSOLE_COMMAND"] cmd = cmd.format(host=server.host, user=server.user, console="open " + console) print("Calling user specified command: {}".format( cmd)) exit(call(cmd.split())) # someone still uses windows elif platform.system() == "Windows": with helpers.disable_file_system_redirection(): cmd = "ssh -t {}@{} open {}".format( server.user, server.host, console) exit(call(cmd.split())) # why is shit so complicated? else: cmd = "ssh -t {}@{} open {}".format( server.user, server.host, console) exit(call(cmd.split())) else: click.secho("Node {} is not active".format(node), fg="red") exit(1) else: click.secho( "Node type {} does not support console connectivity". format(node_obj.node_definition), fg="yellow") else: click.secho("Unable to find lab {}".format(current_lab), fg="red") exit(1) else: click.secho("No current lab set", fg="red") exit(1)
def up(repo=None, provision=False, start=True, **kwargs): """ start a lab """ def_fname = kwargs["f"] alt_fname = "topology.virl" fname = def_fname lid = kwargs["id"] lab_name = kwargs["lab_name"] lab = None clab = None server = VIRLServer() client = get_cml_client(server) current_lab = get_current_lab() if current_lab: clab = safe_join_existing_lab(current_lab, client) if not clab: click.secho( "Current lab is already set to {}, but that lab is not on server; clearing it." .format(current_lab), fg="yellow") clear_current_lab() if not clab or fname or lid or lab_name: if clab: click.secho( "WARNING: Current lab is set to {} (ID: {}); clearing it". format(clab.title, current_lab), fg="yellow") clear_current_lab() if not def_fname: def_fname = "topology.yaml" fname = def_fname if not os.path.isfile(def_fname) and os.path.isfile(alt_fname): fname = alt_fname if lid: lab = safe_join_existing_lab(lid, client) if not lab: # Check the cache existing = check_lab_cache(lid) if existing: fname = existing if not lab and lab_name: lab = safe_join_existing_lab_by_title(lab_name, client) if not lab and os.path.isfile(fname): lname = get_lab_title(fname) click.secho("Importing lab {} from file {}".format(lname, fname)) lab = client.import_lab_from_path(fname, title=lname) elif not lab: # try to pull from virlfiles if repo and os.path.basename(fname) == "topology.yaml": rc = call([get_command(), "pull", repo]) if rc == 0: exit(call([get_command(), "up"])) if lab: if lab.is_active(): cache_lab(lab) set_current_lab(lab.id) click.secho( "Lab is already running (ID: {}, Title: {})".format( lab.id, lab.title)) elif start: start_lab(lab, provision) else: click.secho("Could not find a lab to start. Maybe try -f", fg="red") exit(1) elif clab: click.secho("Lab {} (ID: {}) is already set as the current lab".format( clab.title, current_lab)) if not clab.is_active() and start: start_lab(clab, provision)