def ansible(env, **kwargs): """ generate ansible inventory """ if kwargs.get("output"): # user specified output filename file_name = kwargs.get("output") else: # writes to <env>_testbed.yaml by default file_name = '{}_inventory.yaml'.format(env) running = helpers.check_sim_running(env) if running: sim_name = running server = VIRLServer() roster = server.get_sim_roster(sim_name) # sim_name = "topology-fpyHFs" virl_data = server.export(sim_name, ip=True).content interfaces = server.get_interfaces(sim_name).json() inventory_yaml = ansible_inventory_generator(sim_name, virl_data, roster=roster, interfaces=interfaces) click.secho("Writing {}".format(file_name)) with open(file_name, 'w') as yaml_file: yaml_file.write(inventory_yaml) else: click.secho("couldnt generate testbed for for env: {}".format(env), fg='red')
def start(node): """ start a node """ if len(node) == 2: # we received env and node name env = node[0] running = helpers.check_sim_running(env) node = node[1] elif len(node) == 1: # assume default env env = 'default' running = helpers.check_sim_running(env) node = node[0] else: exit(call(['virl', 'start', '--help'])) if running: sim_name = running server = VIRLServer() resp = server.start_node(sim_name, node) if resp.ok: click.secho("Started node {}".format(node)) else: click.secho("Error starting Node {}: {}".format(node, resp), fg="red")
def telnet(node): """ telnet to a node """ if len(node) == 2: # we received env and node name env = node[0] running = helpers.check_sim_running(env) node = node[1] elif len(node) == 1: # assume default env env = 'default' running = helpers.check_sim_running(env) node = node[0] else: exit(call(['virl', 'telnet', '--help'])) if running: sim_name = running server = VIRLServer() details = server.get_sim_roster(sim_name) if node: try: node_dict = get_node_from_roster(node, details) node_name = node_dict.get("NodeName") ip = node_dict['managementIP'] proxy = node_dict.get("managementProxy") # use user specified telnet command if 'VIRL_TELNET_COMMAND' in server.config: cmd = server.config['VIRL_TELNET_COMMAND'] cmd = cmd.format(host=ip) print("Calling user specified command: {}".format(cmd)) exit(call(cmd.split())) if proxy == 'lxc': lxc = get_mgmt_lxc_ip(details) click.secho("Attemping telnet connection" " to {} at {} via ssh {}".format( node_name, ip, lxc)) cmd = 'ssh -t {}@{} "telnet {}"' cmd = cmd.format(server.user, lxc, ip) exit(call(cmd, shell=True)) else: # handle the "flat" networking case click.secho("Attemping telnet connection" " to {} at {}".format(node_name, ip)) exit(call(['telnet', ip])) except AttributeError: click.secho("Could not find management info " "for {}:{}".format(env, node), fg="red") except KeyError: click.secho("Unknown node {}:{}".format(env, node), fg="red") else: return details.json()
def stop1(node): """ stop a node """ if len(node) == 2: # we received env and node name env = node[0] running = helpers.check_sim_running(env) node = node[1] elif len(node) == 1: # assume default env env = "default" running = helpers.check_sim_running(env) node = node[0] else: exit(call([get_command(), "stop", "--help"])) if running: sim_name = running server = VIRLServer() resp = server.stop_node(sim_name, node) if resp.ok: click.secho("Stopped node {}".format(node)) else: click.secho("Error Stopping Node {}: {}".format(node, resp), fg="red")
def pyats1(env, **kwargs): """ Generates a pyats testbed config for an environment """ if kwargs.get("output"): # user specified output filename file_name = kwargs.get("output") else: # writes to <env>_testbed.yaml by default file_name = "{}_testbed.yaml".format(env) running = helpers.check_sim_running(env) if running: sim_name = running server = VIRLServer() roster = server.get_sim_roster(sim_name) # sim_name = "topology-fpyHFs" virl_data = server.export(sim_name, ip=True).content interfaces = server.get_interfaces(sim_name).json() testbed_yaml = pyats_testbed_generator1(sim_name, virl_data, roster=roster, interfaces=interfaces) click.secho("Writing {}".format(file_name)) with open(file_name, "w") as yaml_file: yaml_file.write(testbed_yaml) else: click.secho("couldnt generate testbed for for env: {}".format(env), fg="red")
def version1(): """ version information """ server = VIRLServer() virlutils_version = __version__ server_version = server.get_version().get("virl-version") click.secho("virlutils Version: {}".format(virlutils_version)) click.echo("VIRL Core Version: {}".format(server_version))
def save(env, ip, filename, **kwargs): """ save simulation to local virl file """ with open(filename, 'w') as fh: sim_name = get_env_sim_name(env) server = VIRLServer() resp = server.export(sim_name, ip=ip) click.secho("Saving {} to {}".format(sim_name, filename)) fh.write(resp.text)
def ssh(node): """ ssh to a node """ if len(node) == 2: # we received env and node name env = node[0] running = helpers.check_sim_running(env) node = node[1] elif len(node) == 1: # assume default env env = 'default' running = helpers.check_sim_running(env) node = node[0] else: exit(call(['virl', 'ssh', '--help'])) if running: sim_name = running server = VIRLServer() details = server.get_sim_roster(sim_name) if node: try: node_dict = get_node_from_roster(node, details) node_name = node_dict.get("NodeName") ip = node_dict['managementIP'] proxy = node_dict.get("managementProxy") if proxy == 'lxc': lxc = get_mgmt_lxc_ip(details) if lxc: click.secho("Attemping ssh connection" "to {} at {} via {}".format(node_name, ip, lxc)) cmd = 'ssh -o "ProxyCommand ssh -W %h:%p {}@{}" {}@{}' cmd = cmd.format(server.user, lxc, 'cisco', ip) exit(call(cmd, shell=True)) else: # handle the "flat" networking case click.secho("Attemping ssh connection" "to {} at {}".format(node_name, ip)) exit(call(['ssh', 'cisco@{}'.format(ip)])) except AttributeError: click.secho("Could not find management info" "for {}:{}".format(env, node), fg="red") except KeyError: click.secho("Unknown node {}:{}".format(env, node), fg="red") else: return details.json()
def nodes(env, **kwargs): """ get nodes for sim_name """ running = helpers.check_sim_running(env) if running: sim_name = running server = VIRLServer() details = server.get_sim_roster(sim_name) node_list_table(details) else: click.secho("Environment {} is not running".format(env), fg='red')
def logs1(env, **kwargs): """ Retrieves log information for the provided simulation """ running = helpers.check_sim_running(env) if running: sim_name = running server = VIRLServer() resp = server.get_logs(sim_name) log_table(resp.json()['events']) else: click.secho("could not find logs for for env: {}".format(env), fg='red')
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 nimport(node, filename): """ import a node definition """ server = VIRLServer() client = get_cml_client(server) if not os.path.isfile(filename): click.secho("Node definition file {} does not exist or is not a file", fg="red") exit(1) else: defs = client.definitions contents = None with open(filename, "r") as fd: contents = fd.read() try: defs.upload_node_definition(node, contents) except Exception as e: click.secho("Failed to import node definition for {}: {}".format( node, e), fg="red") exit(1)
def ls(**kwargs): """ list all images or the details of a specific image """ image = kwargs.get("image") server = VIRLServer() client = get_cml_client(server) pl = None # Regardless of the argument, we have to get all the flavors # In the case of no arg, we print them all. # In the case of an arg, we have to go back and get details. defs = client.definitions.image_definitions() try: pl = ViewerPlugin(viewer="image_def") except NoPluginError: pass if image: for f in list(defs): if f["name"] == image: if pl: pl.visualize(image_defs=[f]) else: image_list_table([f]) break else: if pl: pl.visualize(image_defs=defs) else: image_list_table(defs)
def __init_plugins(): """ Scan a set of plugin directories and load them if any are found. Plugins come in one of three types: command, generator, viewer. In general, plugins can override base functionality. """ server = VIRLServer() plugin_dirs = server.config.get("CML_PLUGIN_PATH", "") if plugin_dirs != "": plugin_dirs += ":" plugin_dirs += get_default_plugin_dir() load_plugins(plugin_dirs) for cmd in Plugin.get_plugins("command"): try: pl = CommandPlugin(command=cmd) except NoPluginError: continue if not check_valid_plugin(pl, pl.run, "run"): click.secho( "ERROR: Malformed plugin for command {}. The `run` method must be static and a click.command" .format(cmd), fg="red") Plugin.remove_plugin("command", cmd) else: virl.add_command(pl.run, name=cmd) # initialize the 'generate' command arguments after we've loaded # any plugins. Else the plugins will not be available init_generators()
def deregister(confirm): """ deregister the Smart License """ server = VIRLServer() client = get_cml_client(server) # As of 2.0.0b5 of virl2-client, there is no Python API for licensing. So we use # the library as much as we can, and use requests for the rest. ret = "y" if confirm: ret = input("Are you sure you want to deregister [y/N]? ") if not ret.lower().startswith("y"): click.secho("Not deregistering") exit(0) try: response = client.session.delete(client._base_url + "licensing/deregistration") response.raise_for_status() except Exception as e: click.secho("Failed to deregister the Smart License: {}".format(e), 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 use(lab, id, lab_name): """ use lab launched elsewhere """ server = VIRLServer() client = get_cml_client(server) lab_id = None if not lab and not id and not lab_name: exit(call([get_command(), "use", "--help"])) if id: lab_id = check_lab_cache_server(id, client) # Prefer --lab-name over positional argument if lab_name: lab = lab_name if not id and lab: lab_obj = safe_join_existing_lab_by_title(lab, client) if lab_obj: # Make sure this lab is cached. lab_id = check_lab_cache_server(lab_obj.id, client) if lab_id: set_current_lab(lab_id) else: click.secho("Unable to find lab in the cache or on the server", fg="red") exit(1)
def ls(all, all_users): """ lists running labs and optionally those in the cache """ server = VIRLServer() client = get_cml_client(server) labs = [] cached_labs = None lab_ids = client.get_lab_list(all_users) for id in lab_ids: labs.append(client.join_existing_lab(id)) if all: cached_labs = [] cache_root = get_cache_root() if os.path.isdir(cache_root): for f in os.listdir(cache_root): lab_id = f cached_labs.append(CachedLab(lab_id, cache_root + "/" + f)) try: pl = ViewerPlugin(viewer="lab") pl.visualize(labs=labs, cached_labs=cached_labs) except NoPluginError: lab_list_table(labs, cached_labs)
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 nso1(env, syncfrom, **kwargs): """ generate nso inventory """ if kwargs.get("output"): # user specified output filename file_name = kwargs.get("output") else: # writes to <env>.json by default file_name = None running = helpers.check_sim_running(env) if running: sim_name = running server = VIRLServer() roster = server.get_sim_roster(sim_name) # sim_name = "topology-fpyHFs" virl_data = server.export(sim_name, ip=True).content interfaces = server.get_interfaces(sim_name).json() payload = nso_payload_generator1(sim_name, virl_data, roster=roster, interfaces=interfaces) if file_name: # pragma: no cover click.secho("Writing payload to {}".format(file_name)) with open(file_name, "w") as payload_file: payload_file.write(payload) else: click.secho("Updating NSO....") nso_obj = NSO() nso_response = nso_obj.update_devices(payload) if nso_response.ok: click.secho("Successfully added VIRL 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("couldnt generate testbed for for env: {}".format(env), fg="red")
def delete(**kwargs): """ delete a specific flavor """ flavor = kwargs.get('flavor') server = VIRLServer(port=80) # Attempt to delete the flavor try: r = server.delete_flavor(flavor) print("Flavor '{}' deleted.".format(r['name'])) except IndexError as ierr: print(ierr) except HTTPError as herr: print("\nFailed to delete flavor '{}':".format(flavor)) print("\n\t{}".format(herr.response.reason))
def sid(): """ gets sim id for local environment """ server = VIRLServer() sim_dict = server.list_simulations() dirpath = os.getcwd() foldername = os.path.basename(dirpath) for k in list(sim_dict): if not k.startswith(foldername): sim_dict.pop(k) # can only accurately determine sim id if there is # only one sim running with our project name if len(sim_dict) == 1: click.echo(list(sim_dict)[0])
def ls1(all, **kwargs): """ lists running simulations in the current project """ server = VIRLServer() sim_dict = server.list_simulations() if not all: # only sims for this project dirpath = find_virl() foldername = os.path.basename(dirpath) for k in list(sim_dict): if not k.startswith(foldername): sim_dict.pop(k) sim_list_table(sim_dict)
def register(token, **kwargs): """ register with a Smart License account """ ssms = kwargs["smart_license_server"] proxy = kwargs["proxy_host"] port = None cert = kwargs["certificate"] reregister = kwargs["reregister"] server = VIRLServer() client = get_cml_client(server) licensing = client.licensing if ssms or proxy: if not ssms: ssms = DEFAULT_SSMS if proxy: port = kwargs["proxy_port"] try: licensing.set_transport(ssms, proxy, port) except Exception as e: click.secho( "Failed to configure Smart License server and proxy: {}". format(e), fg="red") exit(1) else: try: licensing.delete_certificate() except Exception: pass licensing.set_default_transport() if cert: if not os.path.isfile(cert): click.secho("Certificate {} is not a valid file!".format(cert), fg="red") exit(1) with open(cert, "r") as fd: contents = fd.read() try: licensing.upload_certificate(contents) except Exception as e: click.secho("Failed to upload certificate {}: {}".format( cert, e), fg="red") exit(1) try: licensing.register(token, reregister) except Exception as e: click.secho("Failed to register with Smart Licensing: {}".format(e), fg="red") exit(1)
def add(**kwargs): """ add a specific flavor """ flavor = kwargs.get('flavor') memory = kwargs.get('memory') vcpus = kwargs.get('vcpus') server = VIRLServer(port=80) # Attempt to delete the flavor try: r = server.add_flavor(flavor=flavor, memory=memory, vcpus=vcpus) print("Flavor '{}' ({}) added.".format(flavor, r['id'])) except HTTPError as err: print("\nFailed to create flavor '{}':".format(flavor)) print("\n\t{}\n".format(err.response.reason))
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 console(node, display, **kwargs): """ console for node """ server = VIRLServer() if len(node) == 2: # we received env and node name env = node[0] running = helpers.check_sim_running(env) node = node[1] elif display: # only displaying output env = 'default' running = helpers.check_sim_running(env) node = None elif len(node) == 1: # assume default env env = 'default' running = helpers.check_sim_running(env) node = node[0] else: # node was not specified, display usage exit(call(['virl', 'console', '--help'])) if running: sim_name = running resp = server.get_node_console(sim_name, node=node) if node: click.secho("Attempting to connect to console " "of {}".format(node)) try: ip, port = resp.json()[node].split(':') exit(call(['telnet', ip, port])) except AttributeError: click.secho("Could not find console info for " "{}:{}".format(env, node), fg="red") except KeyError: click.secho("Unknown node {}:{}".format(env, node), fg="red") else: # defaults to displaying table console_table(resp.json())
def ls(**kwargs): """ list all flavors or the details of a specific flavor """ flavor = kwargs.get('flavor') server = VIRLServer(port=80) # Regardless of the argument, we have to get all the flavors # In the case of no arg, we print them all. # In the case of an arg, we have to go back and get details. r = server.get_flavors() if flavor: for f in list(r): if f['name'] == flavor: flavor_list_table([f]) break else: flavor_list_table(r)
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)