def centos(ctx, name, image, external_network, desktop, cpu_count, ram): """Create an instance of CentOS""" body = {'network': external_network, 'name': name, 'image': image, 'desktop': desktop, 'ram': int(ram), 'cpu-count': int(cpu_count)} resp = consume_task(ctx.obj.vlab_api, endpoint='/api/2/inf/centos', message='Creating a new instance of CentOS {}'.format(image), body=body, timeout=900, pause=5) data = resp.json()['content'][name] ipv4_addrs = get_ipv4_addrs(data['ips']) if ipv4_addrs: vm_type = data['meta']['component'] with Spinner('Creating an SSH port mapping rule'): for ipv4 in ipv4_addrs: portmap_payload = {'target_addr' : ipv4, 'target_port' : 22, 'target_name' : name, 'target_component' : vm_type} ctx.obj.vlab_api.post('/api/1/ipam/portmap', json=portmap_payload) if desktop: with Spinner('Creating an RDP port mapping rule'): for ipv4 in ipv4_addrs: portmap_payload = {'target_addr' : ipv4, 'target_port' : 3389, 'target_name' : name, 'target_component' : vm_type} ctx.obj.vlab_api.post('/api/1/ipam/portmap', json=portmap_payload) output = format_machine_info(ctx.obj.vlab_api, info=data) click.echo(output) if ipv4_addrs: typewriter("\nUse 'vlab connect centos --name {}' to access your new CentOS instance".format(name))
def delete_cluster(vlab_api, cluster): """Destroy an entire OneFS cluster""" data = consume_task(vlab_api, endpoint='/api/2/inf/onefs', message='Looking up OneFS cluster {}'.format(cluster), method='GET').json() nodes = _find_cluster_nodes(cluster, all_nodes=data['content'].keys()) if not nodes: raise click.ClickException('No cluster named {} found'.format(cluster)) tasks = {} with Spinner("Deleting cluster {}".format(cluster)): for node in nodes: body = {'name': node} resp = vlab_api.delete('/api/2/inf/onefs', json=body) tasks[node] = '/api/2/inf/onefs/task/{}'.format( resp.json()['content']['task-id']) block_on_tasks(vlab_api, tasks) with Spinner('Deleting port mapping rules'): for node in nodes: all_ports = vlab_api.get('/api/1/ipam/portmap', params={ 'name': node }).json()['content']['ports'] for port in all_ports.keys(): vlab_api.delete('/api/1/ipam/portmap', json={'conn_port': int(port)}) click.echo('OK!')
def portmap(ctx, name, protocol, ip_address): """Create a network port mapping/forwarding rule""" info = consume_task(ctx.obj.vlab_api, endpoint='/api/1/inf/inventory', message='Collecting information about your inventory', method='GET').json() the_vm = info['content'].get(name, None) if the_vm is None: error = "You own no machine named {}. See 'vlab status' for help".format(name) raise click.ClickException(error) vm_type = the_vm['meta']['component'] validate_ip(name, vm_type, the_vm['ips'], ip_address, the_vm['state']) target_addr = determine_which_ip(the_vm['ips'], ip_address) valid_protocols = get_component_protocols(vm_type) if not protocol or protocol not in valid_protocols: protocol = invoke_portmap_clippy(ctx.obj.username, vm_type, valid_protocols) target_port = get_protocol_port(vm_type, protocol) payload = {'target_addr' : target_addr, 'target_port' : target_port, 'target_name' : name, 'target_component' : vm_type} with Spinner('Creating a port mapping rule to {} for {}'.format(name, protocol)): ctx.obj.vlab_api.post('/api/1/ipam/portmap', json=payload) typewriter("OK! Use 'vlab connect {} --name {} --protocol {}' to access that machine".format(vm_type.lower(), name, protocol))
def dd(ctx, name, image, external_network): """Create a Data Domain server""" body = {'network': external_network, 'name': name, 'image': image} resp = consume_task( ctx.obj.vlab_api, endpoint='/api/2/inf/data-domain', message='Creating a new Data Domain server running {}'.format(image), body=body, timeout=900, pause=5) data = resp.json()['content'][name] ipv4_addrs = get_ipv4_addrs(data['ips']) if ipv4_addrs: with Spinner("Creating port mapping rules for HTTPS and SSH"): vm_type = data['meta']['component'] https_port = https_to_port(vm_type.lower()) portmap_payload = { 'target_addr': ipv4_addrs[0], 'target_port': https_port, 'target_name': name, 'target_component': vm_type } ctx.obj.vlab_api.post('/api/1/ipam/portmap', json=portmap_payload) portmap_payload['target_port'] = 22 ctx.obj.vlab_api.post('/api/1/ipam/portmap', json=portmap_payload) output = format_machine_info(ctx.obj.vlab_api, info=data) click.echo(output) if ipv4_addrs: typewriter( "\nUse 'vlab connect dd --name {}' to configure your new Data Domain server." .format(name)) typewriter("Initial/default credentials are 'sysadmin' and 'changeme'")
def windows(ctx, name, image, external_network): """Create a new Windows Desktop client""" body = {'network': external_network, 'name': name, 'image': image} resp = consume_task( ctx.obj.vlab_api, endpoint='/api/2/inf/windows', message='Creating a new instance of Windows {}'.format(image), body=body, timeout=900, pause=5) data = resp.json()['content'][name] ipv4_addrs = get_ipv4_addrs(data['ips']) if ipv4_addrs: vm_type = data['meta']['component'] with Spinner('Creating an RDP port mapping rule'): for ipv4 in ipv4_addrs: portmap_payload = { 'target_addr': ipv4, 'target_port': 3389, 'target_name': name, 'target_component': vm_type } ctx.obj.vlab_api.post('/api/1/ipam/portmap', json=portmap_payload) output = format_machine_info(ctx.obj.vlab_api, info=data) click.echo(output) if ipv4_addrs: typewriter( "\nUse 'vlab connect windows --name {}' to access your new Windows client" .format(name))
def portmap(ctx, verbose): """Display configured port mapping/forwarding rules""" table = "No portmap rules exist" with Spinner('Looking up port mapping rules'): data = ctx.obj.vlab_api.get('/api/1/ipam/portmap').json()['content'] rules = data['ports'] gateway_ip = data['gateway_ip'] header = ['Name', 'Type', 'Port', 'Protocol'] if verbose: header.append('Target IP') rows = [] for conn_port, details in rules.items(): name = details.get('name', 'Error') vm_type = details.get('component', 'Unknown') vm_port = details.get('target_port', 0) protocol = port_to_protocol(vm_type, vm_port) target_ip = details.get('target_addr', 'Unknown') if verbose: row = [name, vm_type, conn_port, protocol, target_ip] else: row = [name, vm_type, conn_port, protocol] rows.append(row) table = tabulate(rows, headers=header, tablefmt='presto', numalign="center") click.echo('\nGateway IP: {}'.format(gateway_ip)) click.echo(table)
def everything(ctx): """Destroy everything you own.""" click.confirm(" Are you sure you want to destroy your entire lab?", abort=True) click.confirm( " Really sure? You cannot undo this, just like you cannot un-bake a cake.", abort=True) consume_task(ctx.obj.vlab_api, endpoint='/api/1/inf/power', body={ 'machine': 'all', 'power': 'off' }, message='Powering down your lab', timeout=300, pause=5) consume_task(ctx.obj.vlab_api, endpoint='/api/1/inf/inventory', message='Destroying inventory', method='DELETE') resp = consume_task(ctx.obj.vlab_api, endpoint='/api/2/inf/vlan', message='Determining what networks you own', method='GET') vlans = resp.json()['content'] tasks = {} with Spinner('Deleting networks'): for vlan in vlans.keys(): resp = ctx.obj.vlab_api.delete('/api/2/inf/vlan', json={'vlan-name': vlan}) tasks[vlan] = resp.links['status']['url'] block_on_tasks(ctx.obj.vlab_api, tasks, pause=1)
def ana(ctx, name, image, static_ip, external_netmask, default_gateway, dns_servers, domain, external_network): """Create a new Avamar NDMP accelerator.""" body = {'network': external_network, 'name': name, 'image': image, 'ip-config': {'static-ip': static_ip, 'default-gateway': default_gateway, 'netmask': external_netmask, 'dns': dns_servers, 'domain': domain } } resp = consume_task(ctx.obj.vlab_api, endpoint='/api/2/inf/avamar/ndmp-accelerator', message='Creating a new Avamar NDMP accelerator running version {}'.format(image), body=body, timeout=1800, pause=5) data = resp.json()['content'][name] vm_type = data['meta']['component'] with Spinner('Creating port mapping rules for HTTPS and SSH'): protocols = get_component_protocols(vm_type.lower()) for protocol in protocols: port = get_protocol_port(vm_type, protocol) payload = {'target_addr' : static_ip, 'target_port' : port, 'target_name' : name, 'target_component' : vm_type} ctx.obj.vlab_api.post('/api/1/ipam/portmap', json=payload) output = format_machine_info(ctx.obj.vlab_api, info=data) click.echo(output) msg = "Use 'vlab connect avamar --name {} --protocol mgmt' to setup your new Avamar Server\n".format(name) msg += "The default credentials are 'root' and 'changme'".format(name) typewriter(msg)
def insightiq(ctx, name, image, external_network): """Create an instance of InsightIQ""" body = {'network': external_network, 'name': name, 'image': image} resp = consume_task( ctx.obj.vlab_api, endpoint='/api/2/inf/insightiq', message='Creating a new instance of InsightIQ running {}'.format( image), body=body, timeout=900, pause=5) data = resp.json()['content'][name] ipv4_addrs = get_ipv4_addrs(data['ips']) if ipv4_addrs: with Spinner("Creating port mapping rules for HTTPS and SSH"): vm_type = data['meta']['component'] https_port = https_to_port(vm_type.lower()) portmap_payload = { 'target_addr': ipv4_addrs[0], 'target_port': https_port, 'target_name': name, 'target_component': 'InsightIQ' } ctx.obj.vlab_api.post('/api/1/ipam/portmap', json=portmap_payload) portmap_payload['target_port'] = 22 ctx.obj.vlab_api.post('/api/1/ipam/portmap', json=portmap_payload) output = format_machine_info(ctx.obj.vlab_api, info=data) click.echo(output) if ipv4_addrs: typewriter( "\nUse 'vlab connect insightiq --protocol console --name {}' to setup a login password" .format(name)) typewriter("for your new InsightIQ instance.")
def kemp(ctx, name, image, external_network): """Create a Kemp ECS Connection Management load balancer""" body = {'network': external_network, 'name': name, 'image': image} resp = consume_task( ctx.obj.vlab_api, endpoint='/api/2/inf/kemp', message= 'Creating a new instance of Kemp ECS connection management load balancer running {}' .format(image), body=body, timeout=900, pause=5) data = resp.json()['content'][name] ipv4_addrs = get_ipv4_addrs(data['ips']) if ipv4_addrs: with Spinner("Creating port mapping rules for HTTPS and SSH"): vm_type = data['meta']['component'] https_port = https_to_port(vm_type.lower()) portmap_payload = { 'target_addr': ipv4_addrs[0], 'target_port': https_port, 'target_name': name, 'target_component': data['meta']['component'] } ctx.obj.vlab_api.post('/api/1/ipam/portmap', json=portmap_payload) portmap_payload['target_port'] = 22 ctx.obj.vlab_api.post('/api/1/ipam/portmap', json=portmap_payload) output = format_machine_info(ctx.obj.vlab_api, info=data) click.echo(output) if ipv4_addrs: typewriter( "\nUse 'vlab connect kemp --protocol console --name {}'".format( name))
def icap(ctx, name, protocol): """Connect to an ICAP server""" if protocol == 'console': info = consume_task(ctx.obj.vlab_api, endpoint='/api/2/inf/icap', message='Looking up connection info for {}'.format(name), method='GET').json() if not info['content'].get(name, None): error = 'No ICAP VM named {} found'.format(name) raise click.ClickException(error) else: vm_moid = info['content'][name].get('moid', 'n/a') conn = Connectorizer(ctx.obj.vlab_config, gateway_ip='n/a') conn.console(vm_moid) else: target_port = get_protocol_port('icap', protocol) with Spinner('Lookin up connection information for {}'.format(name)): resp = ctx.obj.vlab_api.get('/api/1/ipam/portmap', params={'name' : name, 'target_port' : target_port}).json() try: conn_port = list(resp['content']['ports'].keys())[0] except Exception as doh: ctx.obj.log.debug(doh, exc_info=True) conn_port = None if not conn_port: error = 'No mapping rule for {} to {} exists'.format(protocol, name) raise click.ClickException(error) conn = Connectorizer(ctx.obj.vlab_config, resp['content']['gateway_ip']) conn.rdp(port=conn_port)
def init_lab(vlab_api, username, wan, switch, config, log): """Initialize the inventory, default networks, and gateway/firewall :Returns: None :param vlab_api: A valid API connection to vLab :type vlab_api: vlab_cli.lib.api.vLabApi :param username: The name of the user deleting their lab :type username: String :param switch: The name of the network switch their networks are connected to :type switch: String :param config: The parsed configuration file used by the vLab CLI :type config: configparser.ConfigParser :param log: A logging object :type log: logging.Logger """ if not config: bad_config = True elif set(config.sections()) != CONFIG_SECTIONS: bad_config = True else: bad_config = False if bad_config: try: new_info = invoke_config() except Exception as doh: log.debug(doh, exc_info=True) raise click.ClickException(doh) else: set_config(new_info) with Spinner('Initializing your lab'): tasks = {} resp1 = vlab_api.post('/api/1/inf/inventory', auto_check=False) tasks['inventory'] = resp1.links['status']['url'] body2 = {'vlan-name': 'frontend', 'switch-name': switch} resp2 = vlab_api.post('/api/2/inf/vlan', json=body2) tasks['frontend_network'] = resp2.links['status']['url'] body3 = {'vlan-name': 'backend', 'switch-name': switch} resp3 = vlab_api.post('/api/2/inf/vlan', json=body3) tasks['backend_network'] = resp3.links['status']['url'] block_on_tasks(vlab_api, tasks, auto_check=False, pause=1) body4 = {'wan': wan, 'lan': 'frontend'.format(username)} consume_task(vlab_api, endpoint='/api/2/inf/gateway', message='Deploying gateway', method='POST', body=body4, timeout=1500, pause=5, auto_check=False) invoke_init_done_help()
def avamar(ctx, name, protocol, user, password): """Connect to an Avamar server""" if protocol == 'console': info = consume_task( ctx.obj.vlab_api, endpoint='/api/2/inf/avamar/server', message='Looking up connection info for {}'.format(name), method='GET').json() if not info['content'].get(name, None): error = 'No Avamar server named {} found'.format(name) raise click.ClickException(error) else: vm_moid = info['content'][name].get('moid', 'n/a') conn = Connectorizer(ctx.obj.vlab_config, gateway_ip='n/a') conn.console(vm_moid) else: target_port = get_protocol_port('Avamar', protocol) with Spinner('Lookin up connection information for {}'.format(name)): resp = ctx.obj.vlab_api.get('/api/1/ipam/portmap', params={ 'name': name, 'target_port': target_port }).json() try: conn_port = list(resp['content']['ports'].keys())[0] except Exception as doh: ctx.obj.log.debug(doh, exc_info=True) conn_port = None if not conn_port: error = 'No mapping rule for {} to {} exists'.format( protocol, name) raise click.ClickException(error) if password: password_value = getpass.getpass('Password for {}: '.format(user)) conn = Connectorizer(ctx.obj.vlab_config, resp['content']['gateway_ip'], user=user, password=password_value) else: conn = Connectorizer(ctx.obj.vlab_config, resp['content']['gateway_ip'], user=user) if protocol == 'ssh': conn.ssh(port=conn_port) elif protocol == 'https': click.secho( "WARNING: Some parts of the Avamar WebUI only work from inside your lab.", bold=True) conn.https(port=conn_port, endpoint='/dtlt/home.html') elif protocol == 'scp': conn.scp(port=conn_port) elif protocol == 'mgmt': conn.https(port=conn_port) else: error = 'Unexpected protocol requested: {}'.format(protocol) raise RuntimeError(error)
def consume_task(vlab_api, endpoint, message, method='POST', body=None, params=None, timeout=60, pause=1, auto_check=True, base_endpoint=True): """Automates processing tasks issued by the vLab API :Returns: requests.Response :param vlab_api: A valid API connection to vLab :type vlab_api: vlab_cli.lib.api.vLabApi :param endpoint: The URL that issued the task :type endpoint: String :param message: What to tell the end user while waiting on the task :type message: String :param timeout: How long to wait for the task to complete. Default 60 seconds :type timeout: Integer :param pause: How long to wait in between checking on the status of the task. :type pause: Integer :param auto_check: Check the response code, and if needed raise an exception :type auto_check: Boolean :param base_endpoint: Set to False if the end point is for <base>/image :type base_endpoint: Boolean """ with Spinner(message): resp = vlab_api._call(method=method.lower(), endpoint=endpoint, auto_check=auto_check, json=body, params=params) task = resp.json()['content']['task-id'] if base_endpoint: url = '{}/task/{}'.format(endpoint, task) else: url = resp.links['status']['url'] for _ in range(0, timeout, pause): resp = vlab_api.get(url, auto_check=auto_check) if resp.status_code == 202: time.sleep(pause) else: break else: error = 'Timed out on task {}'.format(task) raise click.ClickException(error) return resp
def invoke_config(): """Initial config setup help""" the_os = platform.system().lower() typewriter("In order for 'vlab connect' to work, you'll need to have a") typewriter("browser, an SSH client, an SCP client and the VMware Remote Client (VMRC) installed.") typewriter("Based on your OS, I can use the following:") typewriter(", ".join(configurizer.SUPPORTED_PROGS)) if the_os == 'windows': typewriter("\nNote: 'wt' is short for Windows Terminal, which also requires 'ssh' to be installed.") typewriter("Note: mstsc is the default RDP client that comes with Windows") typewriter('\nIf you do not have the SSH, RDP, SCP and VMRC clients as well as a supported browser') typewriter("installed you'll be wasting time by continuing with this config setup.") keep_going = prompt("Continue with config setup? [Yes/no]", boolean=True, boolean_default=True) if not keep_going: raise RuntimeError("vlab connect prerequisites not met") with Spinner('Great! Give me a couple of minutes to find those programs'): found_programs = configurizer.find_programs() firefox = found_programs.get('firefox', '') chrome = found_programs.get('chrome', '') putty = found_programs.get('putty', '') secure_crt = found_programs.get('securecrt', '').lower() windows_term = found_programs.get('wt', '') winscp = found_programs.get('winscp', '').lower() filezilla = found_programs.get('filezilla', '') scp = found_programs.get('scp', '') browsers = [x for x in [firefox, chrome] if x] if firefox and chrome: forget_browsers = which_client(browsers, 'Browser') for browser in forget_browsers: found_programs.pop(browser) scp_clients = [x for x in [winscp, filezilla, scp] if x] if len(scp_clients) > 1: forget_scp = which_client(scp_clients, 'SCP') for scp_client in forget_scp: found_programs.pop(scp_client) ssh_clients = [x for x in [putty, secure_crt, windows_term] if x] if len(ssh_clients) > 1: forget_ssh_clients = which_client(ssh_clients, 'SSH') for ssh_client in forget_ssh_clients: found_programs.pop(ssh_client) if len(found_programs) != 5: # They are missing some dependency... if the_os == 'windows': scanned_drive = 'C:\\' else: scanned_drive = '/ (i.e. root)' typewriter("\nUh oh, there's a problem. I wasn't able to find everything under {}.".format(scanned_drive)) typewriter("Here are the programs I was able to locate:\n\t{}".format(' '.join(found_programs.keys()))) typewriter("Please install the missing software, then re-run the 'vlab init' command.") raise click.ClickException('Missing required dependencies') return _make_config(found_programs)
def portmap(ctx, name, protocol, ip_address, override_port): """Destroy a port mapping rule""" if ip_address and override_port: target_port = 0 protocol = 'an unknown protocol' else: info = consume_task( ctx.obj.vlab_api, endpoint='/api/1/inf/inventory', message='Collecting information about your inventory', method='GET').json() the_vm = info['content'].get(name, None) if the_vm is None: error = "You own no machine named {}. See 'vlab status' for help".format( name) raise click.ClickException(error) vm_type = the_vm['meta']['component'] validate_ip(name, vm_type, the_vm['ips'], ip_address, the_vm['state'], action='delete') target_addr = determine_which_ip(the_vm['ips'], ip_address) valid_protocols = get_component_protocols(vm_type) if not protocol or protocol not in valid_protocols: protocol = invoke_portmap_clippy(ctx.obj.username, vm_type, valid_protocols) target_port = get_protocol_port(vm_type, protocol) # Part of the fix for https://github.com/willnx/vlab/issues/61 # This chunk of code allows users to delete port mapping rules # for the bad/wrong ESRS port. if the_vm['meta']['component'].lower() == 'esrs' and override_port: target_port = override_port with Spinner('Deleting port mapping rule to {} for {}'.format( name, protocol)): resp = ctx.obj.vlab_api.get('/api/1/ipam/portmap', params={ 'name': name, 'target_port': target_port }).json() try: if not override_port: conn_port = list(resp['content']['ports'].keys())[0] else: conn_port = override_port except IndexError: # No such rule, but who cares? The target state (i.e. no rule) is true pass else: ctx.obj.vlab_api.delete('/api/1/ipam/portmap', json={'conn_port': int(conn_port)}) click.echo('OK!')
def deployment(ctx, name, protocol, user, password): """Connect to a deployed machine""" if protocol == 'console': info = consume_task( ctx.obj.vlab_api, endpoint='/api/2/inf/deployment', message='Looking up connection info for {}'.format(name), method='GET').json() if not info['content'].get(name, None): error = 'No Deployment VM named {} found'.format(name) raise click.ClickException(error) else: vm_moid = info['content'][name].get('moid', 'n/a') conn = Connectorizer(ctx.obj.vlab_config, gateway_ip='n/a') conn.console(vm_moid) else: with Spinner('Looking up connection information for {}'.format(name)): data = ctx.obj.vlab_api.get('/api/1/ipam/portmap', params={ 'name': name }).json()['content'] ports = data['ports'] port_map = {ports[x]['target_port']: x for x in ports.keys()} try: conn_port = determine_port(protocol, port_map) except Exception as doh: ctx.obj.log.debug(doh, exc_info=True) conn_port = None if not conn_port: error = 'No mapping rule for {} to {} exists'.format( protocol, name) raise click.ClickException(error) if password: password_value = getpass.getpass('Password for {}: '.format(user)) conn = Connectorizer(ctx.obj.vlab_config, data['gateway_ip'], user=user, password=password_value) else: conn = Connectorizer(ctx.obj.vlab_config, data['gateway_ip'], user=user) if protocol == 'ssh': conn.ssh(port=conn_port) elif protocol == 'scp': conn.scp(port=conn_port) elif protocol == 'rdp': conn.rdp(port=conn_port) elif protocol == 'https': conn.https(port=conn_port) else: error = 'Unexpected protocol requested: {}'.format(protocol) raise RuntimeError(error)
def dataiq(ctx, name, image, external_network, external_netmask, default_gateway, dns_servers, static_ip, disk_size, cpu_count, ram): """Create an instance of DataIQ""" error = network_config_ok(static_ip, default_gateway, external_netmask) if error: raise click.ClickException(error) body = { 'network': external_network, 'name': name, 'image': image, 'static-ip': static_ip, 'default-gateway': default_gateway, 'external-netmask': external_netmask, 'dns-servers': dns_servers, 'disk-size': int(disk_size), 'cpu-count': int(cpu_count), 'ram': int(ram) } resp = consume_task( ctx.obj.vlab_api, endpoint='/api/2/inf/dataiq', message='Creating a new instance of DataIQ {}'.format(image), body=body, timeout=1800, pause=5) data = resp.json()['content'][name] data['ips'] = [static_ip] vm_type = data['meta']['component'] protocols = get_component_protocols(vm_type.lower()) with Spinner('Creating port mapping rules for SSH, HTTPS, and RDP'): for protocol in protocols: target_port = get_protocol_port(vm_type.lower(), protocol) portmap_payload = { 'target_addr': static_ip, 'target_port': target_port, 'target_name': name, 'target_component': vm_type } ctx.obj.vlab_api.post('/api/1/ipam/portmap', json=portmap_payload) output = format_machine_info(ctx.obj.vlab_api, info=data) click.echo(output) message = """\n ***IMPORTANT*** DataIQ still needs to be installed on your new instance. Please refer to the DataIQ Admin guide for installation directions: https://www.dell.com/support/home/us/en/19/product-support/product/data-iq/docs """ click.secho(message, bold=True) typewriter( "\nUse 'vlab connect dataiq --name {}' to access your new DataIQ instance" .format(name))
def kemp(ctx, name, protocol, user, password): """Connect to a Kemp ECS Connection Management load balancer""" if protocol == 'console': info = consume_task( ctx.obj.vlab_api, endpoint='/api/2/inf/kemp', message='Looking up connection info for {}'.format(name), method='GET').json() if not info['content'].get(name, None): error = 'No Kemp ECS Connection Management load balancer named {} found'.format( name) raise click.ClickException(error) else: vm_moid = info['content'][name].get('moid', 'n/a') conn = Connectorizer(ctx.obj.vlab_config, gateway_ip='n/a') conn.console(vm_moid) else: target_port = get_protocol_port('insightiq', protocol) with Spinner('Lookin up connection information for {}'.format(name)): resp = ctx.obj.vlab_api.get('/api/1/ipam/portmap', params={ 'name': name, 'target_port': target_port }).json() try: conn_port = list(resp['content']['ports'].keys())[0] except Exception as doh: ctx.obj.log.debug(doh, exc_info=True) conn_port = None if not conn_port: error = 'No mapping rule for {} to {} exists'.format( protocol, name) raise click.ClickException(error) if password: password_value = getpass.getpass('Password for {}: '.format(user)) conn = Connectorizer(ctx.obj.vlab_config, resp['content']['gateway_ip'], user=user, password=password_value) else: conn = Connectorizer(ctx.obj.vlab_config, resp['content']['gateway_ip'], user=user) if protocol == 'ssh': conn.ssh(port=conn_port) elif protocol == 'https': conn.https(port=conn_port) elif protocol == 'scp': conn.scp(port=conn_port) else: error = 'Unexpected protocol requested: {}'.format(protocol) raise RuntimeError(error)
def avamar(ctx, name): """Delete an Avamar server""" body = {'name': name} consume_task(ctx.obj.vlab_api, endpoint='/api/2/inf/avamar/server', message='Destroying Avamar server named {}'.format(name), body=body, method='DELETE') with Spinner('Deleting port mapping rules'): all_ports = ctx.obj.vlab_api.get('/api/1/ipam/portmap', params={'name': name}).json()['content']['ports'] for port in all_ports.keys(): ctx.obj.vlab_api.delete('/api/1/ipam/portmap', json={'conn_port': int(port)}) click.echo('OK!')
def superna(ctx, name, protocol, user, password): """Connect to an Superna Eyeglass server""" if protocol == 'console': info = consume_task( ctx.obj.vlab_api, endpoint='/api/2/inf/superna', message='Looking up connection info for {}'.format(name), method='GET').json() if not info['content'].get(name, None): error = 'No Data Domain server named {} found'.format(name) raise click.ClickException(error) else: vm_moid = info['content'][name].get('moid', 'n/a') conn = Connectorizer(ctx.obj.vlab_config, gateway_ip='n/a') conn.console(vm_moid) else: if protocol.lower() == 'https': error = 'Superna web interface only accessible from a machine *inside* your lab.' raise click.ClickException(error) with Spinner('Lookin up connection information for {}'.format(name)): resp = ctx.obj.vlab_api.get('/api/1/ipam/portmap', params={ 'name': name, 'target_port': target_port }).json() try: conn_port = list(resp['content']['ports'].keys())[0] except Exception as doh: ctx.obj.log.debug(doh, exc_info=True) conn_port = None if not conn_port: error = 'No mapping rule for {} to {} exists'.format( protocol, name) raise click.ClickException(error) if password: password_value = getpass.getpass('Password for {}: '.format(user)) conn = Connectorizer(ctx.obj.vlab_config, resp['content']['gateway_ip'], user=user, password=password_value) else: conn = Connectorizer(ctx.obj.vlab_config, resp['content']['gateway_ip'], user=user) if protocol == 'ssh': conn.ssh(port=conn_port) elif protocol == 'scp': conn.scp(port=conn_port) else: error = 'Unexpected protocol requested: {}'.format(protocol) raise RuntimeError(error)
def nuke_lab(vlab_api, username, wan, switch, config, log): """Delete all VMs and Networks a user owns, and create a new one. :Returns: None :param vlab_api: A valid API connection to vLab :type vlab_api: vlab_cli.lib.api.vLabApi :param username: The name of the user deleting their lab :type username: String :param switch: The name of the network switch their networks are connected to :type switch: String :param wan: The name of the Wide Area Network their new lab should connect to :type wan: String :param config: The parsed configuration file used by the vLab CLI :type config: configparser.ConfigParser :param log: A logging object :type log: logging.Logger """ consume_task(vlab_api, endpoint='/api/1/inf/power', body={ 'machine': 'all', 'power': 'off' }, message='Powering down your lab', timeout=300, pause=5) consume_task(vlab_api, endpoint='/api/1/inf/inventory', message='Destroying inventory', method='DELETE') resp = consume_task(vlab_api, endpoint='/api/2/inf/vlan', message='Determining what networks you own', method='GET') vlans = resp.json()['content'] tasks = {} with Spinner('Deleting networks'): for vlan in vlans.keys(): resp = vlab_api.delete('/api/2/inf/vlan', json={'vlan-name': vlan}) tasks[vlan] = resp.links['status']['url'] block_on_tasks(vlab_api, tasks, pause=1) typewriter('Finished deleting old lab. Initializing a new lab.') init_lab(vlab_api, username, wan, switch, config=config, log=log)
def map_ips(vlab_api, nodes, ip_range): """Create the port mapping rules for each node""" low_ip = str(min([ipaddress.ip_address(x) for x in ip_range])) high_ip = str(max([ipaddress.ip_address(x) for x in ip_range])) ips = _generate_ips(low_ip, high_ip) https_port = https_to_port('onefs') with Spinner('Creating SSH and HTTPS mapping rules for each node'): for ip, node in zip(ips, nodes): portmap_payload = {'target_addr': ip, 'target_port': https_port, 'target_name': node, 'target_component' : 'OneFS'} vlab_api.post('/api/1/ipam/portmap', json=portmap_payload) portmap_payload['target_port'] = 22 vlab_api.post('/api/1/ipam/portmap', json=portmap_payload)
def delete_node(vlab_api, name): """Destroy one specific node""" body = {'name': name} consume_task(vlab_api, endpoint='/api/2/inf/onefs', body=body, message='Destroying OneFS node {}'.format(name), method='DELETE') with Spinner('Deleting port mapping rules'): all_ports = vlab_api.get('/api/1/ipam/portmap', params={ 'name': name }).json()['content']['ports'] for port in all_ports.keys(): vlab_api.delete('/api/1/ipam/portmap', json={'conn_port': int(port)}) click.echo('OK!')
def dns(ctx, name, image, external_network, external_netmask, default_gateway, dns_servers, static_ip): """Create a DNS server""" error = network_config_ok(static_ip, default_gateway, external_netmask) if error: raise click.ClickException(error) body = { 'network': external_network, 'name': name, 'image': image, 'static-ip': static_ip, 'default-gateway': default_gateway, 'external-netmask': external_netmask, 'dns-servers': dns_servers } resp = consume_task( ctx.obj.vlab_api, endpoint='/api/2/inf/dns', message='Creating a new DNS server running {}'.format(image), body=body, timeout=1800, pause=5) data = resp.json()['content'][name] data['ips'] = [static_ip] vm_type = data['meta']['component'] if image.lower().startswith('windows'): protocols = ['rdp'] else: protocols = ['ssh'] with Spinner('Creating a port mapping rule for {}'.format( protocols[0].upper())): for protocol in protocols: target_port = get_protocol_port(vm_type.lower(), protocol) portmap_payload = { 'target_addr': static_ip, 'target_port': target_port, 'target_name': name, 'target_component': vm_type } ctx.obj.vlab_api.post('/api/1/ipam/portmap', json=portmap_payload) output = format_machine_info(ctx.obj.vlab_api, info=data) click.echo(output) typewriter( "\nUse 'vlab connect dns --name {} --protocol {}' to access your new dns instance" .format(name, protocols[0]))
def claritynow(ctx, name, image, external_network): """Create an instance of ClarityNow""" body = {'network': external_network, 'name': name, 'image': image} resp = consume_task( ctx.obj.vlab_api, endpoint='/api/2/inf/claritynow', message='Creating a new instance of ClarityNow {}'.format(image), body=body, timeout=900, pause=5) data = resp.json()['content'][name] ipv4_addrs = get_ipv4_addrs(data['ips']) if ipv4_addrs: vm_type = data['meta']['component'] https_port = https_to_port(vm_type.lower()) with Spinner('Creating an SSH, RDP, and HTTPS port mapping rules'): for ipv4 in ipv4_addrs: portmap_payload = { 'target_addr': ipv4, 'target_port': 22, 'target_name': name, 'target_component': vm_type } ctx.obj.vlab_api.post('/api/1/ipam/portmap', json=portmap_payload) portmap_payload['target_port'] = 3389 ctx.obj.vlab_api.post('/api/1/ipam/portmap', json=portmap_payload) portmap_payload['target_port'] = https_port ctx.obj.vlab_api.post('/api/1/ipam/portmap', json=portmap_payload) output = format_machine_info(ctx.obj.vlab_api, info=data) click.echo(output) info = """\n ***IMPORTANT*** ClarityNow requires a valid license to operate. Your ClarityNow server license will expire in 60 days. """ click.secho(info, bold=True) if ipv4_addrs: typewriter( "Use 'vlab connect claritynow --name {}' to access your new ClarityNow instance" .format(name))
def dataiq(ctx, name, protocol): """Connect to a DataIQ instance""" if protocol == 'console': info = consume_task( ctx.obj.vlab_api, endpoint='/api/2/inf/dataiq', message='Looking up connection info for {}'.format(name), method='GET').json() if not info['content'].get(name, None): error = 'No dataiq VM named {} found'.format(name) raise click.ClickException(error) else: vm_moid = info['content'][name].get('moid', 'n/a') conn = Connectorizer(ctx.obj.vlab_config, gateway_ip='n/a') conn.console(vm_moid) else: target_port = get_protocol_port('dataiq', protocol) with Spinner('Lookin up connection information for {}'.format(name)): resp = ctx.obj.vlab_api.get('/api/1/ipam/portmap', params={ 'name': name, 'target_port': target_port }).json() try: conn_port = list(resp['content']['ports'].keys())[0] except Exception as doh: ctx.obj.log.debug(doh, exc_info=True) conn_port = None if not conn_port: error = 'No mapping rule for {} to {} exists'.format( protocol, name) raise click.ClickException(error) conn = Connectorizer(ctx.obj.vlab_config, resp['content']['gateway_ip']) if protocol == 'ssh': conn.ssh(port=conn_port) elif protocol == 'https': conn.https(port=conn_port) elif protocol == 'scp': conn.scp(port=conn_port) elif protocol == 'rdp': conn.rdp(port=conn_port) else: error = 'Unexpected protocol requested: {}'.format(protocol) raise RuntimeError(error)
def ecs(ctx, name): """Delete an instance of Elastic Cloud Storage""" body = {'name': name} consume_task(ctx.obj.vlab_api, endpoint='/api/2/inf/ecs', message='Destroying ECS instance named {}'.format(name), body=body, method='DELETE') with Spinner('Deleting port mapping rules'): all_ports = ctx.obj.vlab_api.get('/api/1/ipam/portmap', params={ 'name': name }).json()['content']['ports'] for port in all_ports.keys(): ctx.obj.vlab_api.delete('/api/1/ipam/portmap', json={'conn_port': int(port)}) click.echo('OK!')
def create_nodes(username, name, image, external, internal, node_count, ram, cpu_count, vlab_api): """Concurrently make all nodes :Returns: Dictionary :param username: The user who owns the new nodes :type username: String :param image: The image/version of OneFS node to create :type image: String :param external: The base name of the external network to connect the node(s) to :type external: String :param internal: The base name of the internal network to connect the node(s) to :type external: String :param node_count: The number of OneFS nodes to make :type node_count: Integer :param ram: The number of GB of ram/memory to create a OneFS node with :type ram: Integer :param cpu_count: The number of CPU cores to allocate to the vOneFS node :type cpu_count: Integer :param vlab_api: An instantiated connection to the vLab server :type vlab_api: vlab_cli.lib.api.vLabApi """ tasks = {} node_v_nodes = 'node' if node_count == 1 else 'nodes' with Spinner('Deploying {} {} running {}'.format(node_count, node_v_nodes, image)): for idx in range(node_count): node_name = '{}-{}'.format(name, idx +1) # +1 so we don't have node-0 body = {'name' : node_name, 'image': image, 'frontend': external, 'backend': internal, 'ram': ram, 'cpu-count': cpu_count, } resp = vlab_api.post('/api/2/inf/onefs', json=body) tasks[node_name] = '/api/2/inf/onefs/task/{}'.format(resp.json()['content']['task-id']) info = block_on_tasks(vlab_api, tasks) return info
def icap(ctx, name, image, external_network): """Create an ICAP Antivirus server""" body = {'network': external_network, 'name': name, 'image': image} resp = consume_task( ctx.obj.vlab_api, endpoint='/api/2/inf/icap', message='Creating a new ICAP server running version {}'.format(image), body=body, timeout=900, pause=5) data = resp.json()['content'][name] ipv4_addrs = get_ipv4_addrs(data['ips']) if ipv4_addrs: vm_type = data['meta']['component'] with Spinner('Creating an RDP port mapping rule'): for ipv4 in ipv4_addrs: portmap_payload = { 'target_addr': ipv4, 'target_port': 3389, 'target_name': name, 'target_component': vm_type } ctx.obj.vlab_api.post('/api/1/ipam/portmap', json=portmap_payload) ip_addr = ipv4_addrs[0] else: ip_addr = 'ERROR' output = format_machine_info(ctx.obj.vlab_api, info=data) click.echo(output) note = """\n ***IMPORTANT*** Before you can use your ICAP sever you must configure the IP the service listens on. To configure this, please open the console and: 1) Launch the McAfee admin panel (look at the task bar) 2) Right click on the ICAP service, and select "properties" 3) Update the IP to {} 4) Remember to click "OK" to save the setting """.format(ip_addr) click.secho(note, bold=True) if ipv4_addrs: typewriter( "Use 'vlab connect icap --name {}' to access your new ICAP server". format(name))