def connect_to_cvp(parameters, log_level='WARNING'): """Create a CVP connection. parameters option should at least contain following elements: - username - password - cvp (server IP or DNS hostname) Parameters ---------- parameters : dict Object with all information to create connection log_level : str Log level to use for CvpClient logger. Default is WARNING. Returns ------- cvprac.CvpClient() cvp client object """ client = CvpClient(log_level=log_level) try: client.connect(nodes=[parameters.cvp], username=parameters.username, password=parameters.password, connect_timeout=10, protocol=CVP['PROTO'], port=CVP['PORT']) logging.info('* connected to %s', CVP['HOST']) except CvpLoginError, e: # If error, then, printout message and quit program # If server cannot be reached, then no need to go further logging.error('! can\'t connect to %s', parameters.cvp) logging.error('! error message is: %s', str(e).replace('\n', ' ')) quit()
def main(): parser = argparse.ArgumentParser(description="Auto Deploy CVP Nodes") parser.add_argument("--config", action="store", help="config file location", default="config.yml") options = parser.parse_args() try: with open(options.config) as f: config = yaml.safe_load(f) except IOError: print 'Config file %s not found' % options.config exit() clnt = CvpClient() clnt.connect(config['cvp_host'], config['cvp_user'], config['cvp_pw']) #get the devices in the undefined container devices = clnt.api.get_devices_in_container('Undefined') if devices is None: print 'No devices in undefined container. Exiting' exit() else: node = None for node in devices: print node #have the netElement need to make the ma1 configlet sn = node['systemMacAddress'] configlet = make_configlet(node['ipAddress'], config) name = sn + '-MA1-CONFIG' try: configlet_key = clnt.api.add_configlet(name, configlet) except CvpApiError as e: if 'Data already exists' in str(e): #remove existing configlet and recreate remove_old_configlet(name, clnt) try: configlet_key = clnt.api.add_configlet(name, configlet) except CvpApiError as e: # if this fails again tell user to check task list: print 'unable to add configlet: %s' % str(e) exit() #add ma1 configlet to device configlet_to_add = {'name': name, 'key': configlet_key} task = None print 'Attempting to deploy device %s' % node['systemMacAddress'] try: task = clnt.api.deploy_device(node, config['target_container'], [configlet_to_add], config['image']) print 'Deploy Device task created' print 'Attempting to execute task' clnt.api.execute_task(task['data']['taskIds'][0]) print 'Task executed...' except CvpApiError as e: print "unable to deploy: %s due to %s" % ( node['systemMacAddress'], str(e))
def main(): args = parseArgs() username = args.user password = args.password if password is None: print("Please provide a password for the user {}".format(username)) password = getpass("Password:"******",")] inventory_file = args.inventory switch_info_dict = parse_switch_info_file(inventory_file) cvp = CvpClient() cvp.connect(cvp_addresses, username, password) inventory = cvp.api.get_inventory() for switch in inventory: #Check to see if switch in spreadsheet and get VRF try: switch_details = switch_info_dict[switch["hostname"]] except KeyError: print("Could not find {}'s serial number in spreadsheet".format( switch["hostname"])) continue deploy_device_with_no_configlets(cvp, switch, switch_details["Target Container"], switch_details["Image Bundle"], include_container_configlets=True)
def connect_cvp(): urllib3.disable_warnings() client = CvpClient() client.connect([config_dict()['server']], config_dict()['username'], config_dict()['password']) return client
def load_cvp_data(): clnt = CvpClient() clnt.connect([cvp_ip], cvp_user, cvp_password) api = CvpApi(clnt) leaf_inventory = api.get_devices_in_container('LEAF') leaf_fqdn_list = list() for element in leaf_inventory: hostname = re.split('\.', element['fqdn'])[0] leaf_fqdn_list.append(hostname) return leaf_fqdn_list
def main(): client = CvpClient() client.connect(['52.53.222.131'], 'arista', 'arista') inventory = client.api.get_inventory() all_hosts = [] for dev in inventory: all_hosts.append(dev['ipAddress']) formatted_inventory = dict(arista=dict(hosts=all_hosts)) output = json.dumps(formatted_inventory, indent=2) print output sys.exit(0)
def connect(module): client = CvpClient() try: client.connect( [module.params['host']], module.params['username'], module.params['password'], protocol=module.params['protocol'], port=module.params['port'], ) except CvpLoginError, e: module.fail_json(msg=str(e))
def main(): options = parseargs() # Make connection to CVP client = CvpClient() client.connect([options.cvp], options.user, options.passw) resp = client.api.get_cvp_info() if resp is None: print "Failed to get CVP info. Exiting" sys.exit(1) dev_info = client.api.get_device_by_name(options.device) if dev_info is None: print "Unable to find device %s. Exiting" % options.device sys.exit(1) print "FOUND DEVICE INFO" dev_configlets = client.api.get_configlets_by_device_id( dev_info["systemMacAddress"]) if dev_configlets is None: print "Found no configlets for device %s. Exiting" % options.device sys.exit(1) print "FOUND DEVICE CONFIGLETS" reconcile_configlet = None for configlet in dev_configlets: if "reconciled" in configlet and configlet["reconciled"] is True: reconcile_configlet = configlet if reconcile_configlet is None: print "No reconcile configlet for device %s. Exiting" % options.device sys.exit(1) print "FOUND DEVICE RECONCILE CONFIGLET" # Call function to parse interfaces and non-interfaces from Recocile Configlet automation_configlet_dict, reconcile_configlet_list = parse_reconcile_config( reconcile_configlet["config"]) # Call function to update automation configlets with necessary ports configlet_upload(client, options.device, automation_configlet_dict) # Update Reconcile Configlet to remove interfaces moved to automation print "UPDATING RECONCILE CONFIGLET TO REMOVE INTERFACES" reconcile_config = "" for line in reconcile_configlet_list: reconcile_config += str(line + "\n") data = { "name": reconcile_configlet["name"], "config": reconcile_config, "key": reconcile_configlet["key"], "reconciled": True } resp = client.post( "/provisioning/updateReconcileConfiglet.do?netElementId=" + dev_info["systemMacAddress"], data=data)
def add_configlet(configlet_name, configlet_string, switch_list): clnt = CvpClient() clnt.connect([cvp_ip], cvp_user, cvp_password) api = CvpApi(clnt) api.add_configlet(configlet_name, configlet_string) for switch_name in switch_list: switch_id = api.get_device_by_name(switch_name) configlet_id = api.get_configlet_by_name(configlet_name) api.apply_configlets_to_device('3rd-party', switch_id, [configlet_id], create_task=True) return 'Ignore'
def _open_cvp_session(self): try: client = CvpClient() client.connect( nodes=self.cvp_hosts, username=self.cvp_user, password=self.cvp_password, request_timeout=300, connect_timeout=30 ) return(client) except CvpLoginError as e: print(f"Cannot connect to CVP API: {e}") exit()
def main(): args = parseArgs() username = args.user password = args.password if password is None: print("Please provide a password for the user {}".format(username)) password = getpass("Password:"******",")] cvp = CvpClient() cvp.connect(cvp_addresses, username, password) #Define list of switches we will consolidate configlets switches = [] print("Retrieving inventory") #Check if target is a container container = None containers = cvp.api.get_containers()["data"] for c in containers: if c["name"] == args.target: container = c break #If no container is found from the target name, assume it is a device if container is not None: #Get devices in/under container if args.mode == "extended": switches = cvp.api.get_devices_under_container(args.target) else: switches = cvp.api.get_devices_in_container(args.target) else: inventory = cvp.api.get_inventory() for device in inventory: if device['hostname'] == args.target: switches.append(device) break print("Successfully retrieved inventory") if type(args.cancel) != bool and re.match(r'(?i)True', args.cancel): cancel_tasks = True else: cancel_tasks = False for switch in switches: #Check to see if switch in spreadsheet and get VRF consolidate_configlets(cvp, switch, include_container_configlets=True, cancel_tasks=cancel_tasks)
def connect(module): ''' Connects to CVP device using user provided credentials from playbook. :param module: Ansible module with parameters and client connection. :return: CvpClient object with connection instantiated. ''' client = CvpClient() try: client.connect([module.params['host']], module.params['username'], module.params['password'], protocol=module.params['protocol'], port=module.params['port'], ) except CvpLoginError, e: module.fail_json(msg=str(e))
def connect(module): ''' Connects to CVP device using user provided credentials from playbook. :param module: Ansible module with parameters and client connection. :return: CvpClient object with connection instantiated. ''' client = CvpClient() try: client.connect([module.params['host']], module.params['username'], module.params['password'], protocol=module.params['protocol'], port=module.params['port']) except CvpLoginError as e: module.fail_json(msg=str(e)) return client
def _change_passwd(self, nodes, username, old_password, new_password): ''' Helper method to change the user password on CVP. ''' # Create a new connection to handle the request. clnt = CvpClient(filename='/tmp/TestCvpClient.log') clnt.connect(nodes, username, old_password) data = { 'user': { 'userId': username, 'password': new_password, 'email': '*****@*****.**', 'userStatus': 'Enabled', }, 'roles': ['network-admin'] } result = clnt.post("/user/updateUser.do?userId=%s" % username, data) self.assertEqual('success', result['data'])
def getVersion(mac): try: clnt = CvpClient() clnt.connect(['{}'.format(host)], user, password) serialNumber = clnt.api.get_device_by_mac(mac)['serialNumber'] version = clnt.get('/api/v1/rest/{}/Eos/image'.format(serialNumber))['notifications'][0]['updates']['version']['value'] except: if trace: sys.stderr.write('cvprac api call to {} unsuccessful.\n'.format(mac)) return None else: if trace: sys.stderr.write('cvprac api call to {} successful.\n'.format(mac)) return version
def connect(hostname, username, password, port = 443): ''' Connects to a CVP device using user provided credentials from opts. ''' socket.setdefaulttimeout(3) urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) client = CvpClient() try: client.connect([hostname], username, password, protocol="https", port=port) except CvpLoginError as error: timestamp = datetime.now().replace(microsecond=0) sys.stderr.write('{} {}ERROR{}: {}.\n'.format(timestamp, bcolors.ERROR, bcolors.NORMAL, error)) sys.exit(1) return client
def _change_passwd(self, nodes, username, old_password, new_password): ''' Helper method to change the user password on CVP. ''' # Create a new connection to handle the request. clnt = CvpClient(filename='/tmp/TestCvpClient.log') clnt.connect(nodes, username, old_password) data = { 'user': { 'userId': username, 'password': new_password, 'email': '*****@*****.**', 'userStatus': 'Enabled', }, 'roles': [ 'network-admin' ] } result = clnt.post("/user/updateUser.do?userId=%s" % username, data) self.assertEqual('success', result['data'])
def connect(module): ''' Connects to CVP device using user provided credentials from playbook. :param module: Ansible module with parameters and client connection. :return: CvpClient object with connection instantiated. ''' client = CvpClient() connection = Connection(module._socket_path) host = connection.get_option("host") port = connection.get_option("port") user = connection.get_option("remote_user") pswd = connection.get_option("password") try: client.connect([host], user, pswd, protocol="https", port=port, ) except CvpLoginError, e: module.fail_json(msg=str(e))
class CVP(): def __init__(self): try: urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning ) # to supress the warnings for https self.cvprac = CvpClient() config = Global_Config.objects.get(name='master').params self.cvprac.connect(config['server'], config['user'], config['password']) except: pass def connect(self): try: config = Global_Config.objects.get(name='master').params self.cvprac.connect(config['server'], config['user'], config['password']) return True except Exception as e: print(e) return False def status(self): try: self.cvprac.api.get_cvp_info() return True except Exception as e: print(e) if self.connect(): return True else: return False def call(self, endpoint): if self.status(): try: return getattr(self.cvprac.api, endpoint)() except CvpClientError as e: return False else: return False
class TestCvpClient(DutSystemTest): ''' Test cases for the CvpClient class. ''' # pylint: disable=too-many-public-methods # pylint: disable=invalid-name def setUp(self): ''' Instantiate the CvpClient class and connect to the CVP node. Log messages to the /tmp/TestCvpClient.log ''' super(TestCvpClient, self).setUp() self.clnt = CvpClient(filename='/tmp/TestCvpClient.log') self.assertIsNotNone(self.clnt) self.assertIsNone(self.clnt.last_used_node) dut = self.duts[0] cert = False if 'cert' in dut: cert = dut['cert'] self.clnt.connect([dut['node']], dut['username'], dut['password'], 10, cert=cert) self.api = self.clnt.api self.assertIsNotNone(self.api) # Verify that there is at least one device in the inventory err_msg = 'CVP node must contain at least one device' result = self.api.get_inventory() self.assertIsNotNone(result) self.assertGreaterEqual(len(result), 1, msg=err_msg) self.device = result[0] # Get the container for the device on the list and # use that container as the parent container. result = self.api.search_topology(self.device['fqdn']) self.assertIsNotNone(result) dev_container = result['netElementContainerList'] self.assertGreaterEqual(len(dev_container), 1) info = dev_container[0] result = self.api.search_topology(info['containerName']) self.assertIsNotNone(result) self.container = result['containerList'][0] # Get the configlets assigned to the device. There must be at least 1. err_msg = 'CVP node device must have at least one configlet assigned' key = info['netElementKey'] result = self.api.get_configlets_by_device_id(key) self.assertGreaterEqual(len(result), 1, msg=err_msg) self.dev_configlets = result def tearDown(self): ''' Destroy the CvpClient class. ''' super(TestCvpClient, self).tearDown() self.api = None self.clnt = None def _get_next_task_id(self): ''' Return the next task id. Returns: task_id (str): Task ID ''' # Get all the tasks and the task id of the next task created is # the length + 1. results = self.api.get_tasks() self.assertIsNotNone(results) return str(int(results['total']) + 1) def _create_task(self): ''' Create a task by making a simple change to a configlet assigned to the device. Returns: (task_id, config) task_id (str): Task ID config (str): Previous configlets contents ''' task_id = self._get_next_task_id() # Update the lldp time in the first configlet in the list. configlet = None for conf in self.dev_configlets: if conf['netElementCount'] == 1: configlet = conf break if configlet is None: configlet = self.dev_configlets[0] config = configlet['config'] org_config = config match = re.match(r'lldp timer (\d+)', config) if match is not None: value = int(match.group(1)) + 1 repl = 'lldp timer %d' % value config = re.sub(match.group(0), repl, config) else: value = 13 config = ('lldp timer %d\n' % value) + config configlet['config'] = config # Updating the configlet will cause a task to be created to apply # the change to the device. self.api.update_configlet(config, configlet['key'], configlet['name']) # Wait 30 seconds for task to get created cnt = 30 if self.clnt.apiversion is None: self.api.get_cvp_info() if self.clnt.apiversion == 'v2': # Increase timeout by 30 sec for CVP 2018.2 and beyond cnt += 30 while cnt > 0: time.sleep(1) result = self.api.get_task_by_id(task_id) if result is not None: break cnt -= 1 err_msg = 'Timeout waiting for task id %s to be created' % task_id self.assertGreater(cnt, 0, msg=err_msg) return task_id, org_config def test_api_get_cvp_info(self): ''' Verify get_cvp_info and verify setting of client last_used_node parameter ''' result = self.api.get_cvp_info() self.assertIsNotNone(result) self.assertIn('version', result) self.assertIn(self.clnt.last_used_node, self.clnt.url_prefix) self.assertEqual(self.clnt.version, result['version']) self.assertIsNotNone(self.clnt.apiversion) def test_api_check_compliance(self): ''' Verify check_compliance ''' key = self.device['key'] ntype = self.device['type'] result = self.api.check_compliance(key, ntype) self.assertEqual(result['complianceCode'], '0000') self.assertEqual(result['complianceIndication'], 'NONE') def test_api_task_operations(self): ''' Verify get_task_by_id, get_task_by_status, add_note_to_task, get_logs_by_id, and cancel_task ''' (task_id, org_config) = self._create_task() # Test get_task_by_id result = self.api.get_task_by_id(task_id) self.assertIsNotNone(result) self.assertEqual(result['workOrderId'], task_id) # Test get_task_by_status results = self.api.get_tasks_by_status('PENDING') # More than one task may be returned. found = False for result in results: actual_task_id = result['workOrderId'] if actual_task_id == task_id: found = True break err_msg = 'Task id: %s not in list of PENDING tasks' % task_id self.assertTrue(found, msg=err_msg) # Test add_note_to_task note = 'Test Generated' self.api.add_note_to_task(task_id, note) # Verify task operations result = self.api.get_task_by_id(task_id) self.assertIsNotNone(result) self.assertEqual(result['note'], note) self.assertEqual(result['workOrderUserDefinedStatus'], 'Pending') result = self.api.check_compliance(self.device['key'], self.device['type']) self.assertEqual(result['complianceCode'], '0001') # Test cancel_task self.api.cancel_task(task_id) time.sleep(1) result = self.api.get_task_by_id(task_id) self.assertIsNotNone(result) self.assertEqual(result['workOrderUserDefinedStatus'], 'Cancelled') result = self.api.check_compliance(self.device['key'], self.device['type']) self.assertEqual(result['complianceCode'], '0001') # Get the task logs result = self.api.get_logs_by_id(task_id) self.assertIsNotNone(result) result = self.api.check_compliance(self.device['key'], self.device['type']) self.assertEqual(result['complianceCode'], '0001') # Restore the configlet to what it was before the task was created. task_id = self._get_next_task_id() configlet = None for conf in self.dev_configlets: if conf['netElementCount'] == 1: configlet = conf break if configlet is None: configlet = self.dev_configlets[0] self.api.update_configlet(org_config, configlet['key'], configlet['name']) time.sleep(2) # Cancel task self.api.cancel_task(task_id) # Check compliance self.test_api_check_compliance() def test_api_validate_config(self): ''' Verify valid config returns True ''' config = 'interface ethernet1\n description test' result = self.api.validate_config(self.device['key'], config) self.assertEqual(result, True) def test_api_validate_config_error(self): ''' Verify an invalid config returns False ''' config = 'interface ethernet1\n typocommand test' result = self.api.validate_config(self.device['key'], config) self.assertEqual(result, False) def test_api_get_task_by_id_bad(self): ''' Verify get_task_by_id with bad task id ''' result = self.api.get_task_by_id(10000000) self.assertIsNone(result) def test_api_get_task_by_id_fmt_bad(self): ''' Verify get_task_by_id with bad task id ''' result = self.api.get_task_by_id('BOGUS') self.assertIsNone(result) def test_api_get_tasks_by_s_bad(self): ''' Verify get_tasks_by_status ''' result = self.api.get_tasks_by_status('BOGUS') self.assertIsNotNone(result) def test_api_get_configlets(self): ''' Verify get_configlets ''' result = self.api.get_configlets() # Format the configlet lists into name keyed dictionaries dev_cfglts = {} for cfglt in self.dev_configlets: dev_cfglts.update({cfglt['name']: cfglt}) rslt_cfglts = {} for cfglt in result['data']: rslt_cfglts.update({cfglt['name']: cfglt}) # Make sure the device configlets are all returned by the # get_configlets call for cfglt_name in dev_cfglts: self.assertIn(cfglt_name, rslt_cfglts) self.assertDictEqual(dev_cfglts[cfglt_name], rslt_cfglts[cfglt_name]) def test_api_get_configlet_builder(self): ''' Verify get_configlet_builder ''' cfglt = self.api.get_configlet_by_name('SYS_TelemetryBuilderV2') result = self.api.get_configlet_builder(cfglt['key']) # Verify the following keys and types are # returned by the request exp_data = { u'isAssigned': bool, u'formList': list, u'main_script': dict, } # Handle unicode type for Python 2 vs Python 3 if sys.version_info.major < 3: exp_data[u'name'] = (unicode, str) else: exp_data[u'name'] = str for key in exp_data: self.assertIn(key, result['data']) self.assertIsInstance(result['data'][key], exp_data[key]) def test_api_get_configlet_by_name(self): ''' Verify get_configlet_by_name ''' configlet = None for conf in self.dev_configlets: if conf['netElementCount'] == 1: configlet = conf break if configlet is None: configlet = self.dev_configlets[0] result = self.api.get_configlet_by_name(configlet['name']) self.assertIsNotNone(result) self.assertEqual(result['key'], configlet['key']) def test_api_get_configlets_by_container_id(self): ''' Verify get_configlets_by_container_id ''' result = self.api.get_configlets_by_container_id( self.container['key'] ) # Verify the following keys and types are returned by the request exp_data = { 'configletList': list, 'total': int, 'configletMapper': dict, } for key in exp_data: self.assertIn(key, result) self.assertIsInstance(result[key], exp_data[key]) def test_api_get_configlets_by_netelement_id(self): ''' Verify get_configlets_by_netelement_id ''' result = self.api.get_configlets_by_netelement_id( self.device['key'] ) # Verify the following keys and types are returned by the request exp_data = { 'configletList': list, 'total': int, 'configletMapper': dict, } for key in exp_data: self.assertIn(key, result) self.assertIsInstance(result[key], exp_data[key]) def test_api_get_applied_devices(self): ''' Verify get_applied_devices ''' for cfglt in self.dev_configlets: result = self.api.get_applied_devices(cfglt['name']) # Verify the following keys and types are # returned by the request exp_data = { 'data': list, 'total': int, } for key in exp_data: self.assertIn(key, result) self.assertIsInstance(result[key], exp_data[key]) def test_api_get_applied_containers(self): ''' Verify get_applied_containers ''' for cfglt in self.dev_configlets: result = self.api.get_applied_containers(cfglt['name']) # Verify the following keys and types are # returned by the request exp_data = { 'data': list, 'total': int, } for key in exp_data: self.assertIn(key, result) self.assertIsInstance(result[key], exp_data[key]) def test_api_get_configlet_history(self): ''' Verify get_configlet_history ''' key = None for conf in self.dev_configlets: if conf['netElementCount'] == 1: key = conf['key'] break if key is None: key = self.dev_configlets[0]['key'] result = self.api.get_configlet_history(key) self.assertIsNotNone(result) def test_api_get_device_by_name(self): ''' Verify get_device_by_name ''' result = self.api.get_device_by_name(self.device['fqdn']) self.assertIsNotNone(result) self.assertEqual(result, self.device) def test_api_get_device_configuration(self): ''' Verify get_device_configuration ''' result = self.api.get_device_configuration(self.device['key']) self.assertIsNotNone(result) config_lines = result.splitlines() for line in config_lines: if 'hostname' in line: self.assertEqual(line, 'hostname %s' % self.device['fqdn']) def test_api_get_device_by_name_bad(self): ''' Verify get_device_by_name with bad fqdn ''' result = self.api.get_device_by_name('bogus_host_name') self.assertIsNotNone(result) self.assertEqual(result, {}) def test_api_get_device_by_name_substring(self): ''' Verify get_device_by_name with partial fqdn returns nothing ''' result = self.api.get_device_by_name(self.device['fqdn'][1:]) self.assertIsNotNone(result) self.assertEqual(result, {}) def _create_configlet(self, name, config): # Delete the configlet in case it was left by previous test run try: result = self.api.get_configlet_by_name(name) self.api.delete_configlet(name, result['key']) except CvpApiError: pass # Add the configlet key = self.api.add_configlet(name, config) self.assertIsNotNone(key) return key def test_api_add_delete_configlet(self): ''' Verify add_configlet and delete_configlet ''' name = 'test_configlet' config = 'lldp timer 9' # Add the configlet key = self._create_configlet(name, config) # Verify configlet was added result = self.api.get_configlet_by_name(name) self.assertIsNotNone(result) self.assertEqual(result['name'], name) self.assertEqual(result['config'], config) self.assertEqual(result['key'], key) # Delete the configlet self.api.delete_configlet(name, key) # Verify configlet was deleted with self.assertRaises(CvpApiError): self.api.get_configlet_by_name(name) def test_api_add_note_to_configlet(self): ''' Verify add_note_to_configlet ''' name = 'test_configlet_with_note_%d' % time.time() config = 'lldp timer 9' # Add the configlet key = self._create_configlet(name, config) # Add a note to the configlet note = 'Updated by cvprac test' result = self.api.add_note_to_configlet(key, note) # Verify note was added to configlet result = self.api.get_configlet_by_name(name) self.assertIsNotNone(result) self.assertEqual(result['name'], name) self.assertEqual(result['config'], config) self.assertEqual(result['key'], key) self.assertEqual(result['note'], note) # Delete test configlet self.api.delete_configlet(name, key) def _execute_task(self, task_id): ''' Execute a task and wait for it to complete. ''' # Test add_note_to_task self.api.add_note_to_task(task_id, 'Test Generated') self.api.execute_task(task_id) # Verify task executed within 30 seconds cnt = 30 while cnt > 0: time.sleep(1) result = self.api.get_task_by_id(task_id) status = result['workOrderUserDefinedStatus'] if status == 'Completed' or status == 'Failed': break cnt -= 1 err_msg = 'Execution for task id %s failed' % task_id self.assertNotEqual(status, 'Failed', msg=err_msg) err_msg = 'Timeout waiting for task id %s to execute' % task_id self.assertGreater(cnt, 0, msg=err_msg) def test_api_execute_task(self): ''' Verify execute_task ''' # Create task and execute it (task_id, _) = self._create_task() self._execute_task(task_id) # Check compliance self.test_api_check_compliance() def test_api_get_containers(self): ''' Verify get containers ''' result = self.api.get_containers() self.assertIsNotNone(result) total = result['total'] self.assertEqual(len(result['data']), total) def test_api_no_container_by_name(self): ''' Verify searching for a container name that doesn't exist returns None ''' container = self.api.get_container_by_name('NonExistentContainer') self.assertIsNone(container) def test_api_get_devices_in_container(self): ''' Verify searching for devices in a container returns only the devices under the given container name. ''' # Get All Devices all_devices = self.api.get_inventory() # Grab key of container to test from first device in inventory device = all_devices[0] parent_cont = device['parentContainerId'] # Make list of all devices from full inventory that are in the # same container as the first device devices_in_container = [] for dev in all_devices: if dev['parentContainerId'] == parent_cont: devices_in_container.append(dev) # Get the name of the container for the container key from # the first device all_containers = self.api.get_containers() container_name = None for container in all_containers['data']: if container['key'] == parent_cont: container_name = container['name'] result = self.api.get_devices_in_container(container_name) self.assertEqual(result, devices_in_container) def test_api_containers(self): ''' Verify add_container, get_container_by_name and delete_container ''' name = 'CVPRACTEST' parent = self.container # Verify create container self.api.add_container(name, parent['name'], parent['key']) # Verify get container for exact container name returns only that # container container = self.api.get_container_by_name(name) self.assertIsNotNone(container) self.assertEqual(container['name'], name) # Verify finding created container using search topology result = self.api.search_topology(name) self.assertEqual(len(result['containerList']), 1) container = result['containerList'][0] self.assertEqual(container['name'], name) key = container['key'] # Verify newly created container has no devices in it new_cont_devices = self.api.get_devices_in_container(name) self.assertEqual(new_cont_devices, []) # Verify move device to container device = self.api.get_inventory()[0] orig_cont = self.api.get_parent_container_for_device( device['key']) if orig_cont['key'] != 'undefined_container': task = self.api.move_device_to_container( 'test', device, container)['data']['taskIds'][0] self.api.cancel_task(task) curr_cont = self.api.get_parent_container_for_device(device['key']) self.assertEqual(curr_cont['key'], key) device = self.api.get_device_by_name(device['fqdn']) if 'parentContainerId' in device: self.assertEqual(device['parentContainerId'], key) task = self.api.move_device_to_container( 'test', device, orig_cont)['data']['taskIds'][0] self.api.cancel_task(task) curr_cont = self.api.get_parent_container_for_device(device['key']) self.assertEqual(curr_cont['key'], orig_cont['key']) device = self.api.get_device_by_name(device['fqdn']) if 'parentContainerId' in device: self.assertEqual(device['parentContainerId'], orig_cont['key']) # Verify delete container self.api.delete_container(name, key, parent['name'], parent['key']) result = self.api.search_topology(name) self.assertEqual(len(result['containerList']), 0) def test_api_container_url_encode_name(self): ''' Verify special characters can be used in container names ''' new_cont_name = 'Rack2+_DC11' parent = self.container # Verify create container self.api.add_container(new_cont_name, parent['name'], parent['key']) # Verify get container for container with special characters in name container = self.api.get_container_by_name(new_cont_name) self.assertIsNotNone(container) self.assertEqual(container['name'], new_cont_name) # Verify delete container self.api.delete_container(new_cont_name, container['key'], parent['name'], parent['key']) result = self.api.search_topology(new_cont_name) self.assertEqual(len(result['containerList']), 0) def test_api_configlets_to_device(self): ''' Verify apply_configlets_to_device and remove_configlets_from_device ''' # Create a new configlet name = 'test_configlet' config = 'alias srie show running-config interface ethernet 1' # Add the configlet key = self._create_configlet(name, config) # Get the next task ID task_id = self._get_next_task_id() # Apply the configlet to the device label = 'cvprac test' param = {'name': name, 'key': key} self.api.apply_configlets_to_device(label, self.device, [param]) # Validate task was created to apply the configlet to device # Wait 30 seconds for task to get created cnt = 30 while cnt > 0: time.sleep(1) result = self.api.get_task_by_id(task_id) if result is not None: break cnt -= 1 self.assertIsNotNone(result) self.assertEqual(result['workOrderId'], task_id) self.assertIn(label, result['description']) # Execute Task self._execute_task(task_id) # Get the next task ID task_id = self._get_next_task_id() # Remove configlet from device self.api.remove_configlets_from_device(label, self.device, [param]) # Validate task was created to remove the configlet to device # Wait 30 seconds for task to get created cnt = 30 while cnt > 0: time.sleep(1) result = self.api.get_task_by_id(task_id) if result is not None: break cnt -= 1 self.assertIsNotNone(result) self.assertEqual(result['workOrderId'], task_id) self.assertIn(label, result['description']) # Execute Task self._execute_task(task_id) # Delete the configlet self.api.delete_configlet(name, key) # Check compliance self.test_api_check_compliance() def test_api_request_timeout(self): ''' Verify api timeout ''' self.assertEqual(self.api.request_timeout, 30) self.api.request_timeout = 0.0001 with self.assertRaises(Timeout): self.api.get_cvp_info() self.api.request_timeout = 30.0 def test_api_get_all_temp_actions(self): ''' Verify get_all_temp_actions ''' # pylint: disable=protected-access name = 'test_configlet' config = 'lldp timer 9' # Add a configlet key = self._create_configlet(name, config) # Apply the configlet to the container data = { 'data': [{ 'info': 'test_api_get_all_temp_actions', 'infoPreview': 'test_api_get_all_temp_actions', 'action': 'associate', 'nodeType': 'configlet', 'nodeId': '', 'toId': self.container['key'], 'fromId': '', 'nodeName': '', 'fromName': '', 'toName': self.container['name'], 'toIdType': 'container', 'configletList': [key], 'configletNamesList': [name], 'ignoreConfigletList': [], 'ignoreConfigletNamesList': [], 'configletBuilderList' : [], 'configletBuilderNamesList' : [], 'ignoreConfigletBuilderList' : [], 'ignoreConfigletBuilderNamesList': [], }] } self.api._add_temp_action(data) # Request the list of temp actions result = self.api.get_all_temp_actions() # Delete the temporary action and the configlet self.clnt.post('//provisioning/deleteAllTempAction.do') self.api.delete_configlet(name, key) # Validate the results # There should be 1 temp action self.assertEqual(result['total'], 1) # The temp action should contain the data from the add action for dkey in data['data'][0]: self.assertIn(dkey, result['data'][0].keys()) self.assertEqual(data['data'][0][dkey], result['data'][0][dkey]) def test_api_get_event_by_id_bad(self): ''' Verify get_event_by_id returns an error for a bad ID ''' try: # The api request should fail result = self.api.get_event_by_id('\n*') self.assertIsNone(result) except CvpApiError as ebi_err: # The error should contain 'Invalid Event Id' self.assertIn('Invalid Event Id', str(ebi_err)) def test_api_get_default_snapshot_template(self): ''' Verify get_default_snapshot_template. ''' result = self.api.get_default_snapshot_template() if result is not None: expected = { u'ccTasksTagged': 0, u'classId': 63, u'commandCount': 1, u'createdBy': u'System', u'default': True, u'factoryId': 1, u'id': 63, u'isDefault': True, u'key': u'Initial_Template', u'name': u'Show_Inventory', u'note': u'', } # Remove the snapshotCount, totalSnapshotCount and # createdTimestamp, since these can change with usage result.pop('snapshotCount', None) result.pop('totalSnapshotCount', None) result.pop('createdTimestamp', None) self.assertDictEqual(result, expected) def test_api_capture_container_level_snapshot(self): ''' Verify capture_container_level_snapshot ''' # Get the container and snapshot keys container_key = self.container['key'] default_snap = self.api.get_default_snapshot_template() if default_snap is not None: snapshot_key = default_snap['key'] # Initialize the snapshot event result = self.api.capture_container_level_snapshot( snapshot_key, container_key) self.assertIn('data', result) self.assertIn('eventId', result) self.assertEqual('success', result['data']) def test_api_add_image_cancel_image(self): ''' Verify add_image and cancel_image ''' # Get number of current images orig_images = self.api.get_images() # Copy the test image file with a timestamp appended image_file_name = 'image-file-%s.swix' % time.time() image_file = 'test/fixtures/%s' % image_file_name shutil.copyfile('test/fixtures/image-file.swix', image_file) # Upload the image to the cluster add_response = self.api.add_image(image_file) # Remove the timestamp copy from the local filesystem os.remove(image_file) # Check return status good self.assertIn('result', add_response) self.assertEqual(add_response['result'], 'success') # Verify image added post_add_images = self.api.get_images() self.assertEqual(orig_images['total'] + 1, post_add_images['total']) # Cancel/Discard added image cancel_resp = self.api.cancel_image(image_file_name) self.assertEqual(cancel_resp['data'], 'success') # Verify image cancelled/discarded post_cancel_images = self.api.get_images() self.assertEqual(orig_images['total'], post_cancel_images['total']) def test_api_get_images(self): ''' Verify get images ''' result = self.api.get_images() self.assertIsNotNone(result) self.assertEqual(result['total'], len(result['data'])) def test_api_get_image_bundles(self): ''' Verify get image bundles ''' result = self.api.get_image_bundles() self.assertIsNotNone(result) self.assertEqual(result['total'], len(result['data'])) def test_api_save_update_delete_image_bundle(self): ''' Verify save_image_bundle and update_image_bundle ''' # pylint: disable=too-many-locals # Get an existing bundle bundles = self.api.get_image_bundles() total = bundles['total'] bundle = self.api.get_image_bundle_by_name(bundles['data'][0]['name']) # Get the list of images from the existing bundle images = bundle['images'] # Remove the unused keys from the images remove_keys = ['appliedContainersCount', 'appliedDevicesCount', 'factoryId', 'id', 'imageFile', 'imageFileName', 'isHotFix', 'uploadedDateinLongFormat', 'user'] for image in images: for key in remove_keys: image.pop(key, None) # Create a new bundle with the same images original_name = 'test_image_bundle_%d' % time.time() result = self.api.save_image_bundle(original_name, images) expected = r'Bundle\s*:\s+%s successfully created' % original_name self.assertRegexpMatches(result['data'], expected) # Assert bundle added new_bundles = self.api.get_image_bundles() new_total = new_bundles['total'] self.assertEqual(total + 1, new_total) # Get the bundle ID from the new bundle bundle = self.api.get_image_bundle_by_name(original_name) bundle_id = bundle['id'] # Update the name of the bundle and mark it as uncertified updated_name = original_name + "_updated" result = self.api.update_image_bundle(bundle_id, updated_name, images, certified=False) self.assertRegexpMatches(result['data'], 'Image bundle updated successfully') # Verify the updated bundle name has the correct bundle ID # and is not a certified image bundle bundle = self.api.get_image_bundle_by_name(updated_name) bundle_id = bundle['id'] bundle_name = bundle['name'] self.assertEqual(bundle['id'], bundle_id) self.assertEqual(bundle['isCertifiedImage'], 'false') # Verify the original bundle name does not exist bundle = self.api.get_image_bundle_by_name(original_name) self.assertIsNone(bundle) # Remove new bundle result = self.api.delete_image_bundle(bundle_id, bundle_name) self.assertEqual(result['data'], 'success') # Assert new bundle successfully removed new_bundles = self.api.get_image_bundles() new_total = new_bundles['total'] self.assertEqual(total, new_total) def test_api_get_image_bundle_by_name(self): ''' Verify get image bundle by name ''' bundles = self.api.get_image_bundles() if bundles['total'] > 0: bundle_name = bundles['data'][0]['name'] bundle = self.api.get_image_bundle_by_name(bundle_name) self.assertEqual(bundle['name'], bundle_name) def test_api_get_image_bundle_by_name_doesnt_exist(self): ''' Verify get image bundle by name returns none if image bundle doesn't exist ''' result = self.api.get_image_bundle_by_name('nonexistantimagebundle') self.assertIsNone(result) def test_api_apply_remove_image_device(self): ''' Verify task gets created when applying an image bundle to a device. This test only runs if at least one image bundle and one device exist in the CVP instance being used for testing. ''' bundles = self.api.get_image_bundles() devices = self.api.get_inventory() # Verify at least one image bundle and device exist if bundles['total'] > 0 and len(devices) > 0: # Get device and image bundle b = self.api.get_image_bundle_by_name(bundles['data'][0]['name']) d = self.api.get_device_by_name(devices[0]['fqdn']) applied_devices_count = b['appliedDevicesCount'] # Apply image and verify at least one task id was created result = self.api.apply_image_to_device(b, d) self.assertIsNotNone(result) self.assertEqual(result['data']['status'], 'success') taskids = result['data']['taskIds'] self.assertIsNotNone(taskids) # Verify image bundle has been applied to one additional device b = self.api.get_image_bundle_by_name(bundles['data'][0]['name']) self.assertEqual((applied_devices_count + 1), b['appliedDevicesCount']) # Verify task was created and in pending state task = self.api.get_task_by_id(taskids[0]) self.assertIsNotNone(task) self.assertEqual(task['workOrderUserDefinedStatus'], 'Pending') # Cancel task and verify it is cancelled self.api.cancel_task(taskids[0]) time.sleep(1) task = self.api.get_task_by_id(taskids[0]) self.assertIsNotNone(task) self.assertEqual(task['workOrderUserDefinedStatus'], 'Cancelled') # Un-apply image bundle from device result = self.api.remove_image_from_device(b, d) self.assertIsNotNone(result) self.assertEqual(result['data']['status'], 'success') taskids = result['data']['taskIds'] self.assertIsNotNone(taskids) # Verify image bundle applied to one less device b = self.api.get_image_bundle_by_name(bundles['data'][0]['name']) self.assertEqual(applied_devices_count, b['appliedDevicesCount']) def test_api_apply_remove_image_container(self): ''' Verify image bundle is applied to container and removed. Test only runs if at least one image bundle exists. Test creates a container to apply bundle then removes the container at the end. ''' bundles = self.api.get_image_bundles() if bundles['total'] > 0: # Create container, get container info, get bundle info name = 'imagecontainer' parent = self.container self.api.add_container(name, parent['name'], parent['key']) c = self.api.get_container_by_name(name) b = self.api.get_image_bundle_by_name(bundles['data'][0]['name']) applied_container_count = b['appliedContainersCount'] # Apply bundle to new container result = self.api.apply_image_to_container(b, c) self.assertIsNotNone(result) b = self.api.get_image_bundle_by_name(bundles['data'][0]['name']) self.assertEqual(b['appliedContainersCount'], (applied_container_count + 1)) # Remove bundle from container result = self.api.remove_image_from_container(b, c) self.assertIsNotNone(result) b = self.api.get_image_bundle_by_name(bundles['data'][0]['name']) self.assertEqual(b['appliedContainersCount'], applied_container_count) # Remove container self.api.delete_container(name, c['key'], parent['name'], parent['key']) def test_api_inventory(self): ''' Verify add_device_to_inventory and delete_device(s) ''' # Get a device full_inv = self.api.get_inventory() device = full_inv[0] # Record number of current/original non connected devices orig_non_connect_count = self.api.get_non_connected_device_count() # Get devices current container assigned orig_cont = self.api.get_parent_container_for_device(device['key']) # Get devices current configlets orig_configlets = self.api.get_configlets_by_device_id(device['key']) # delete from inventory self.api.delete_device(device['systemMacAddress']) # sleep to allow delete to complete time.sleep(1) # verify not found in inventory res = self.api.get_device_by_name(device['fqdn']) self.assertEqual(res, {}) # add back to inventory self.api.add_device_to_inventory(device['ipAddress'], orig_cont['name'], orig_cont['key']) # get non connected device count until it is back to equal or less # than the original non connected device count non_connect_count = self.api.get_non_connected_device_count() for _ in range(3): if non_connect_count <= orig_non_connect_count: break time.sleep(1) non_connect_count = self.api.get_non_connected_device_count() results = self.api.save_inventory() # Save Inventory is deprecated for 2018.2 and beyond if self.clnt.apiversion == 'v1': self.assertEqual(results['data'], 1) else: save_msg = 'Save Inventory not implemented/necessary for' +\ ' CVP 2018.2 and beyond' self.assertEqual(results['data'], 0) self.assertEqual(results['message'], save_msg) post_save_inv = self.api.get_inventory() self.assertEqual(len(post_save_inv), len(full_inv)) # verify device is found in inventory again re_added_dev = self.api.get_device_by_name(device['fqdn']) self.assertEqual(re_added_dev['systemMacAddress'], device['systemMacAddress']) # apply original configlets back to device results = self.api.apply_configlets_to_device("test_api_inventory", device, orig_configlets, create_task=True) # execute returned task and wait for it to complete task_res = self.api.execute_task(results['data']['taskIds'][0]) self.assertEqual(task_res, None) task_status = self.api.get_task_by_id(results['data']['taskIds'][0]) while task_status['taskStatus'] != 'COMPLETED': task_status = self.api.get_task_by_id( results['data']['taskIds'][0]) time.sleep(1) # delete from inventory # self.api.delete_device(device['systemMacAddress']) # verify not found in inventory # res = self.api.get_device_by_name(device['fqdn']) # self.assertEqual(res, {}) # dut = self.duts[0] # self.api.retry_add_to_inventory(device['ipAddress'], # device['systemMacAddress'], # dut['username'], dut['password']) def test_api_change_control(self): ''' Verify get_change_control_info and execute_change_control. ''' # Set client apiversion if it is not already set if self.clnt.apiversion is None: self.api.get_cvp_info() chg_ctrl_name = 'test_api_%d' % time.time() (task_id, _) = self._create_task() chg_ctrl_tasks = [{ 'taskId': task_id, 'taskOrder': 1 }] chg_ctrl = self.api.create_change_control(chg_ctrl_name, chg_ctrl_tasks, '', '', '') cc_id = chg_ctrl['ccId'] # Verify the pending change control information chg_ctrl_pending = self.api.get_change_control_info(cc_id) self.assertEqual(chg_ctrl_pending['status'], 'Pending') # Execute the change control self.api.execute_change_controls([cc_id]) # Verify the in progress/completed change control information chg_ctrl_executed = self.api.get_change_control_info(cc_id) self.assertIn(chg_ctrl_executed['status'], ('Inprogress', 'Completed')) # Wait until change control is completed before continuing # to next test for _ in range(3): chg_ctrl_executed = self.api.get_change_control_info(cc_id) if chg_ctrl_executed['status'] == 'Completed': break else: time.sleep(2) # For 2018.2 give a few extra seconds for device status to get # back in compliance. if self.clnt.apiversion == 'v2': time.sleep(5) def test_api_filter_topology(self): ''' Verify filter_topology. ''' # Set client apiversion if it is not already set if self.clnt.apiversion is None: self.api.get_cvp_info() # Verify the test container topology returns the test device info topology = self.api.filter_topology(node_id=self.container['key']) # Verify the test device is present in the returned data exp_device_key = self.device['key'] topo_devices = [x['key'] for x in topology['topology']['childNetElementList']] self.assertIn(exp_device_key, topo_devices) # Verify the test device data is consistent topo_dev_data = [x for x in topology['topology']['childNetElementList'] if x['key'] == exp_device_key][0] # The tempAction field can be either None or [] when empty, # so skip this in the comparison. topo_dev_data.pop('tempAction', None) known_dev_data = dict(self.device) known_dev_data.pop('tempAction', None) # The device containerName field appears to be null for filter # topology calls where the nodeID is a container ID. # Skip this in comparison topo_dev_data.pop('containerName', None) known_dev_data.pop('containerName', None) # Test expected parameter keys are in return data. # Test values for parameters with consistent return values # Ignore comparing values for keys with # known different return value formats diff_val_form_keys = ['dcaKey', 'modelName', 'isDANZEnabled', 'deviceInfo', 'ztpMode', 'isMLAGEnabled'] for key in topo_dev_data: self.assertIn(key, known_dev_data) if self.clnt.apiversion == 'v1' or key not in diff_val_form_keys: self.assertEqual(topo_dev_data[key], known_dev_data[key])
from cvprac.cvp_client import CvpClient from cvprac.cvp_client_errors import CvpApiError import ssl ssl._create_default_https_context = ssl._create_unverified_context import requests.packages.urllib3 requests.packages.urllib3.disable_warnings() from cvprac.cvp_client import CvpClient # Create connection to CloudVision using Service Account token with open("cvaas.tok") as f: token = f.read().strip('\n') clnt = CvpClient() clnt.connect(nodes=['www.arista.io'], username='', password='', is_cvaas=True, api_token=token) username = "******" password = "" role = "network-admin" status = "Enabled" first_name = "John" last_name = "Smith" email = "*****@*****.**" utype = "SSO" try: clnt.api.add_user(username, password, role, status, first_name, last_name, email, utype)
# Copyright (c) 2021 Arista Networks, Inc. # Use of this source code is governed by the Apache License 2.0 # that can be found in the COPYING file. from cvprac.cvp_client import CvpClient import ssl ssl._create_default_https_context = ssl._create_unverified_context import requests.packages.urllib3 requests.packages.urllib3.disable_warnings() # Create connection to CloudVision clnt = CvpClient() clnt.connect(['cvp1'], 'username', 'password') image_name = "vEOS-4.26.0.1F" image = clnt.api.get_image_bundle_by_name(image_name) device_name = "tp-avd-leaf2" device = clnt.api.get_device_by_name(device_name) clnt.api.apply_image_to_device(image, device)
configletPath = '' ignoreConfiglets = ['.git','.md'] # cvpNodes can be a single item or a list of the cluster cvpNodes = ['54.183.233.155'] cvpUsername = '******' cvpPassword = '******' # Initialize the client cvpClient = CvpClient() # Attempt to connect to CVP, if it's not available wait 60 seconds attempts = 0 while 1: try: cvpClient.connect(cvpNodes, cvpUsername, cvpPassword) if cvpClient.api.get_cvp_info()['version']: break except: attempts += 1 print "Cannot connect to CVP waiting 1 minute attempt",attempts time.sleep(60) # Function to determine if string passed is python or just text def is_python(code): try: ast.parse(code) except SyntaxError: return False return True
class TestCvpClient(DutSystemTest): ''' Test cases for the CvpClient class. ''' # pylint: disable=too-many-public-methods def setUp(self): ''' Instantiate the CvpClient class and connect to the CVP node. Log messages to the /tmp/TestCvpClient.log ''' super(TestCvpClient, self).setUp() self.clnt = CvpClient(filename='/tmp/TestCvpClient.log') self.assertIsNotNone(self.clnt) dut = self.duts[0] self.clnt.connect([dut['node']], dut['username'], dut['password']) self.api = self.clnt.api self.assertIsNotNone(self.api) # Verify that there is at least one device in the inventory err_msg = 'CVP node must contain at least one device' result = self.api.get_inventory() self.assertIsNotNone(result) self.assertGreaterEqual(len(result), 1, msg=err_msg) self.device = result[0] # Get the container for the device on the list and # use that container as the parent container. result = self.api.search_topology(self.device['fqdn']) self.assertIsNotNone(result) dev_container = result['netElementContainerList'] self.assertGreaterEqual(len(dev_container), 1) info = dev_container[0] result = self.api.search_topology(info['containerName']) self.assertIsNotNone(result) self.container = result['containerList'][0] # Get the configlets assigned to the device. There must be at least 1. err_msg = 'CVP node device must have at least one configlet assigned' key = info['netElementKey'] result = self.api.get_configlets_by_device_id(key) self.assertGreaterEqual(len(result), 1, msg=err_msg) self.dev_configlets = result def tearDown(self): ''' Destroy the CvpClient class. ''' super(TestCvpClient, self).tearDown() self.api = None self.clnt = None def _get_next_task_id(self): ''' Return the next task id. Returns: task_id (str): Task ID ''' # Get all the tasks and the task id of the next task created is # the length + 1. results = self.api.get_tasks() self.assertIsNotNone(results) return str(int(results['total']) + 1) def _create_task(self): ''' Create a task by making a simple change to a configlet assigned to the device. Returns: (task_id, config) task_id (str): Task ID config (str): Previous configlets contents ''' # Get the next task ID task_id = self._get_next_task_id() # Update the lldp time in the first configlet in the list. configlet = self.dev_configlets[0] config = configlet['config'] org_config = config match = re.match(r'lldp timer (\d+)', config) if match is not None: value = int(match.group(1)) + 1 repl = 'lldp timer %d' % value config = re.sub(match.group(0), repl, config) else: value = 13 config = ('lldp timer %d\n' % value) + config configlet['config'] = config # Updating the configlet will cause a task to be created to apply # the change to the device. self.api.update_configlet(config, configlet['key'], configlet['name']) # Wait 30 seconds for task to get created cnt = 30 while cnt > 0: time.sleep(1) result = self.api.get_task_by_id(task_id) if result is not None: break cnt -= 1 err_msg = 'Timeout waiting for task id %s to be created' % task_id self.assertGreater(cnt, 0, msg=err_msg) return (task_id, org_config) def test_api_get_cvp_info(self): ''' Verify get_cvp_info ''' result = self.api.get_cvp_info() self.assertIsNotNone(result) self.assertIn('version', result) def test_api_task_operations(self): ''' Verify get_task_by_id, get_task_by_status, add_note_to_task, get_logs_by_id, and cancel_task ''' (task_id, org_config) = self._create_task() # Test get_task_by_id result = self.api.get_task_by_id(task_id) self.assertIsNotNone(result) self.assertEqual(result['workOrderId'], task_id) # Test get_task_by_status results = self.api.get_tasks_by_status('PENDING') # More than one task may be returned. found = False for result in results: actual_task_id = result['workOrderId'] if actual_task_id == task_id: found = True break err_msg = 'Task id: %s not in list of PENDING tasks' % task_id self.assertTrue(found, msg=err_msg) # Test add_note_to_task note = 'Test Generated' self.api.add_note_to_task(task_id, note) # Verify task operations result = self.api.get_task_by_id(task_id) self.assertIsNotNone(result) self.assertEqual(result['note'], note) status = result['workOrderUserDefinedStatus'] self.assertEqual(status, 'Pending') # Restore the configlet to what it was before the task was created. configlet = self.dev_configlets[0] self.api.update_configlet(org_config, configlet['key'], configlet['name']) # Test cancel_task self.api.cancel_task(task_id) # Get the task logs result = self.api.get_logs_by_id(task_id) self.assertIsNotNone(result) # Check compliance self.test_api_check_compliance() def test_api_get_task_by_id_bad(self): ''' Verify get_task_by_id with bad task id ''' result = self.api.get_task_by_id(10000000) self.assertIsNone(result) def test_api_get_task_by_id_fmt_bad(self): ''' Verify get_task_by_id with bad task id ''' with self.assertRaises(CvpApiError): self.api.get_task_by_id('BOGUS') def test_api_get_tasks_by_s_bad(self): ''' Verify get_tasks_by_status ''' result = self.api.get_tasks_by_status('BOGUS') self.assertIsNotNone(result) def test_api_get_configlet_by_name(self): ''' Verify get_configlet_by_name ''' configlet = self.dev_configlets[0] result = self.api.get_configlet_by_name(configlet['name']) self.assertIsNotNone(result) self.assertEqual(result['key'], configlet['key']) def test_api_get_configlet_history(self): ''' Verify get_configlet_history ''' key = self.dev_configlets[0]['key'] result = self.api.get_configlet_history(key) self.assertIsNotNone(result) def test_api_get_device_by_name(self): ''' Verify get_device_by_name ''' result = self.api.get_device_by_name(self.device['fqdn']) self.assertIsNotNone(result) self.assertEqual(result, self.device) def test_api_get_device_by_name_bad(self): ''' Verify get_device_by_name with bad fqdn ''' result = self.api.get_device_by_name('bogus_host_name') self.assertIsNotNone(result) self.assertEqual(result, {}) def _create_configlet(self, name, config): # Delete the configlet in case it was left by previous test run try: result = self.api.get_configlet_by_name(name) self.api.delete_configlet(name, result['key']) except CvpApiError: pass # Add the configlet key = self.api.add_configlet(name, config) self.assertIsNotNone(key) return key def test_api_add_delete_configlet(self): ''' Verify add_configlet and delete_configlet ''' name = 'test_configlet' config = 'lldp timer 9' # Add the configlet key = self._create_configlet(name, config) # Verify configlet was added result = self.api.get_configlet_by_name(name) self.assertIsNotNone(result) self.assertEqual(result['name'], name) self.assertEqual(result['config'], config) self.assertEqual(result['key'], key) # Delete the configlet self.api.delete_configlet(name, key) # Verify configlet was deleted with self.assertRaises(CvpApiError): self.api.get_configlet_by_name(name) def _execute_task(self, task_id): ''' Execute a task and wait for it to complete. ''' # Test add_note_to_task self.api.add_note_to_task(task_id, 'Test Generated') self.api.execute_task(task_id) # Verify task executed within 30 seconds cnt = 30 while cnt > 0: time.sleep(1) result = self.api.get_task_by_id(task_id) status = result['workOrderUserDefinedStatus'] if status == 'Completed' or status == 'Failed': break cnt -= 1 err_msg = 'Execution for task id %s failed' % task_id self.assertNotEqual(status, 'Failed', msg=err_msg) err_msg = 'Timeout waiting for task id %s to execute' % task_id self.assertGreater(cnt, 0, msg=err_msg) def test_api_execute_task(self): ''' Verify execute_task ''' # Create task and execute it (task_id, _) = self._create_task() self._execute_task(task_id) # Check compliance self.test_api_check_compliance() def test_api_get_containers(self): ''' Verify get containers ''' result = self.api.get_containers() self.assertIsNotNone(result) total = result['total'] self.assertEqual(len(result['data']), total) def test_api_containers(self): ''' Verify add_container, get_container_by_name and delete_container ''' name = 'CVPRACTEST' parent = self.container # Verify create container self.api.add_container(name, parent['name'], parent['key']) # Verify get container for exact container name returns only that # container container = self.api.get_container_by_name(name) self.assertIsNotNone(container) self.assertEqual(container['name'], name) # Verify finding created container using search topology result = self.api.search_topology(name) self.assertEqual(len(result['containerList']), 1) container = result['containerList'][0] self.assertEqual(container['name'], name) key = container['key'] # Verify move device to container device = self.api.get_inventory()[0] orig_cont = self.api.get_parent_container_for_device(device['key']) if orig_cont['key'] != 'undefined_container': task = self.api.move_device_to_container( 'test', device, container)['data']['taskIds'][0] self.api.cancel_task(task) curr_cont = self.api.get_parent_container_for_device(device['key']) self.assertEqual(curr_cont['key'], key) device = self.api.get_device_by_name(device['fqdn']) if 'parentContainerId' in device: self.assertEqual(device['parentContainerId'], key) task = self.api.move_device_to_container( 'test', device, orig_cont)['data']['taskIds'][0] self.api.cancel_task(task) curr_cont = self.api.get_parent_container_for_device(device['key']) self.assertEqual(curr_cont['key'], orig_cont['key']) device = self.api.get_device_by_name(device['fqdn']) if 'parentContainerId' in device: self.assertEqual(device['parentContainerId'], orig_cont['key']) # Verify delete container self.api.delete_container(name, key, parent['name'], parent['key']) result = self.api.search_topology(name) self.assertEqual(len(result['containerList']), 0) def test_api_configlets_to_device(self): ''' Verify apply_configlets_to_device and remove_configlets_from_device ''' # Create a new configlet name = 'test_configlet' config = 'alias srie show running-config interface ethernet 1' # Add the configlet key = self._create_configlet(name, config) # Get the next task ID task_id = self._get_next_task_id() # Apply the configlet to the device label = 'cvprac test' param = {'name': name, 'key': key} self.api.apply_configlets_to_device(label, self.device, [param]) # Validate task was created to apply the configlet to device result = self.api.get_task_by_id(task_id) self.assertIsNotNone(result) self.assertEqual(result['workOrderId'], task_id) self.assertIn(label, result['description']) # Execute Task self._execute_task(task_id) # Get the next task ID task_id = self._get_next_task_id() # Remove configlet from device self.api.remove_configlets_from_device(label, self.device, [param]) # Validate task was created to remove the configlet to device result = self.api.get_task_by_id(task_id) self.assertIsNotNone(result) self.assertEqual(result['workOrderId'], task_id) self.assertIn(label, result['description']) # Execute Task self._execute_task(task_id) # Delete the configlet self.api.delete_configlet(name, key) # Check compliance self.test_api_check_compliance() def test_api_check_compliance(self): ''' Verify check_compliance ''' key = self.device['key'] ntype = self.device['type'] result = self.api.check_compliance(key, ntype) self.assertEqual(result['complianceCode'], '0000') self.assertEqual(result['complianceIndication'], 'NONE') def test_api_request_timeout(self): ''' Verify api timeout ''' self.assertEqual(self.api.request_timeout, 30) self.api.request_timeout = 0.0001 with self.assertRaises(Timeout): self.api.get_cvp_info() self.api.request_timeout = 30.0 def test_api_get_images(self): ''' Verify get images ''' result = self.api.get_images() self.assertIsNotNone(result) self.assertEqual(result['total'], len(result['data'])) def test_api_get_image_bundles(self): ''' Verify get image bundles ''' result = self.api.get_image_bundles() self.assertIsNotNone(result) self.assertEqual(result['total'], len(result['data'])) def test_api_get_image_bundle_by_name(self): ''' Verify get image bundle by name ''' bundles = self.api.get_image_bundles() if bundles['total'] > 0: bundle_name = bundles['data'][0]['name'] bundle = self.api.get_image_bundle_by_name(bundle_name) self.assertEqual(bundle['name'], bundle_name) def test_api_get_image_bundle_by_name_doesnt_exist(self): ''' Verify get image bundle by name returns none if image bundle doesn't exist ''' result = self.api.get_image_bundle_by_name('nonexistantimagebundle') self.assertIsNone(result) def test_api_apply_image_to_device(self): ''' Verify task gets created when applying an image bundle to a device. This test only runs if at least one image bundle and one device exist in the CVP instance being used for testing. ''' bundles = self.api.get_image_bundles() devices = self.api.get_inventory() # Verify at least one image bundle and device exist if bundles['total'] > 0 and len(devices) > 0: # Get device and image bundle b = self.api.get_image_bundle_by_name(bundles['data'][0]['name']) d = self.api.get_device_by_name(devices[0]['fqdn']) # Apply image and verify at least one task id was created result = self.api.apply_image_to_device(b, d) self.assertIsNotNone(result) self.assertEqual(result['data']['status'], 'success') taskids = result['data']['taskIds'] self.assertIsNotNone(taskids) # Verify task was created and in pending state task = self.api.get_task_by_id(taskids[0]) self.assertIsNotNone(task) self.assertEqual(task['workOrderUserDefinedStatus'], 'Pending') # Cancel task and verify it is cancelled self.api.cancel_task(taskids[0]) task = self.api.get_task_by_id(taskids[0]) self.assertIsNotNone(task) self.assertEqual(task['workOrderUserDefinedStatus'], 'Cancelled') def test_api_apply_remove_image_container(self): ''' Verify image bundle is applied to container and removed. Test only runs if at least one image bundle exists. Test creates a container to apply bundle then removes the container at the end. ''' bundles = self.api.get_image_bundles() if bundles['total'] > 0: # Create container, get container info, get bundle info name = 'imagecontainer' parent = self.container self.api.add_container(name, parent['name'], parent['key']) c = self.api.get_container_by_name(name) b = self.api.get_image_bundle_by_name(bundles['data'][0]['name']) applied_container_count = b['appliedContainersCount'] # Apply bundle to new container result = self.api.apply_image_to_container(b, c) self.assertIsNotNone(result) b = self.api.get_image_bundle_by_name(bundles['data'][0]['name']) self.assertEqual(b['appliedContainersCount'], (applied_container_count + 1)) # Remove bundle from container result = self.api.remove_image_from_container(b, c) self.assertIsNotNone(result) b = self.api.get_image_bundle_by_name(bundles['data'][0]['name']) self.assertEqual(b['appliedContainersCount'], applied_container_count) # Remove container self.api.delete_container(name, c['key'], parent['name'], parent['key'])
# Define URL for local eAPI connection. Uses local loopback local_url_string = "https://{}:{}@{}/command-api".format( username, password, "127.0.0.1") local_switch_req = Server(local_url_string) # Open syslog for log creation syslog.openlog('PeerInterfaceEnabler', 0, syslog.LOG_LOCAL4) # Connect to CVP for configlet push if necessary if cvp_bool == True: from cvprac.cvp_client import CvpClient from cvprac.cvp_client_errors import CvpApiError try: cvp = CvpClient(syslog=True, filename='cvprac_log') cvp.connect(cvp_ip, username, password) except: syslog.syslog( "%%PeerInt-6-LOG: Unable to connect to CVP. Continuing script") pass # Setup timeout function and signal def handler(signum, frame): syslog.syslog("%%PeerInt-6-LOG: Timed out waiting for peer eAPI.") raise Exception("timeout") signal.signal(signal.SIGALRM, handler) signal.alarm(5)
#Openfaas magic. #I need to get the entire JSON data with the device because things may need it! This includes also a new way to send the post request header. #Dockerize this thing with arguments for container, IP, Username and password. from cvprac.cvp_client import CvpClient import json import time import urllib3 import requests urllib3.disable_warnings() client = CvpClient() client.connect(['10.20.30.142'], 'daniel', 'daniel123') url = 'http://10.20.30.147:31112/function/hello-python' data_list1 = [] data_list2 = [] data_device = {} def get_devices(data_list): inventory = client.api.get_devices_in_container('DC1-Leaf') data = json.dumps(inventory, sort_keys=True, indent=4) data_dict = json.loads(data) for devices in data_dict: showdevices = devices['ipAddress'] data_list.append(showdevices) showhosts = devices['fqdn'] data_list.append(showdevices) data_device.update({showhosts: showdevices})
class TestCvpClient(DutSystemTest): ''' Test cases for the CvpClient class. ''' # pylint: disable=too-many-public-methods NEW_PASSWORD = '******' def setUp(self): ''' Instantiate the CvpClient class. Log messages to the /tmp/TestCvpClient.log ''' super(TestCvpClient, self).setUp() self.clnt = CvpClient(filename='/tmp/TestCvpClient.log') self.assertIsNotNone(self.clnt) def tearDown(self): ''' Destroy the CvpClient class. ''' super(TestCvpClient, self).tearDown() self.clnt = None def _change_passwd(self, nodes, username, old_password, new_password): ''' Helper method to change the user password on CVP. ''' # Create a new connection to handle the request. clnt = CvpClient(filename='/tmp/TestCvpClient.log') clnt.connect(nodes, username, old_password) data = { 'user': { 'userId': username, 'password': new_password, 'email': '*****@*****.**', 'userStatus': 'Enabled', }, 'roles': [ 'network-admin' ] } result = clnt.post("/user/updateUser.do?userId=%s" % username, data) self.assertEqual('success', result['data']) def test_clnt_init(self): ''' Verify CvpClient init ''' clnt = CvpClient() self.assertIsNotNone(clnt) def test_clnt_init_syslog(self): ''' Verify CvpClient init with syslog argument ''' clnt = CvpClient(syslog=True) self.assertIsNotNone(clnt) def test_clnt_init_syslog_filename(self): ''' Verify CvpClient init with syslog and filename argument ''' logfile = '/tmp/foo' clnt = CvpClient(syslog=True, logger='cvpracTmp', filename=logfile) self.assertIsNotNone(clnt) os.remove(logfile) def test_connect_http_good(self): ''' Verify http connection succeeds to a single CVP node Uses default protocol and port. ''' dut = self.duts[0] self.clnt.connect([dut['node']], dut['username'], dut['password']) def test_connect_https_good(self): ''' Verify https connection succeeds to a single CVP node Uses https protocol and port. ''' dut = self.duts[0] self.clnt.connect([dut['node']], dut['username'], dut['password'], protocol='https') def test_connect_username_bad(self): ''' Verify connect fails with bad username. ''' dut = self.duts[0] with self.assertRaises(CvpLoginError): self.clnt.connect([dut['node']], 'username', dut['password']) def test_connect_password_bad(self): ''' Verify connect fails with bad password. ''' dut = self.duts[0] with self.assertRaises(CvpLoginError): self.clnt.connect([dut['node']], dut['username'], 'password') def test_connect_node_bad(self): ''' Verify connection fails to a single bogus CVP node ''' with self.assertRaises(CvpLoginError): self.clnt.connect(['bogus'], 'username', 'password', connect_timeout=1) def test_connect_non_cvp_node(self): ''' Verify connection fails to a non-CVP node ''' with self.assertRaises(CvpLoginError): self.clnt.connect(['localhost'], 'username', 'password') def test_connect_all_nodes_bad(self): ''' Verify connection fails to a single bogus CVP node ''' with self.assertRaises(CvpLoginError): self.clnt.connect(['bogus1', 'bogus2', 'bogus3'], 'username', 'password', connect_timeout=1) def test_connect_n1_bad_n2_good(self): ''' Verify connect succeeds even if one node is bad ''' dut = self.duts[0] self.clnt.connect(['bogus', dut['node']], dut['username'], dut['password'], connect_timeout=2) def test_connect_nodes_arg_bad(self): ''' Verify non-list nodes argument raises a TypeError ''' with self.assertRaises(TypeError): self.clnt.connect('bogus', 'username', 'password') def test_connect_port_bad(self): ''' Verify non-http protocol with default port raises a TypeError ''' dut = self.duts[0] with self.assertRaises(ValueError): self.clnt.connect([dut['node']], dut['username'], dut['password'], protocol='bogus') def test_get_not_connected(self): ''' Verify get with no connection raises a ValueError ''' with self.assertRaises(ValueError): self.clnt.get('/bogus') def test_get(self): ''' Verify get of CVP info ''' dut = self.duts[0] self.clnt.connect([dut['node']], dut['username'], dut['password']) result = self.clnt.get('/cvpInfo/getCvpInfo.do') self.assertIn('version', result) def test_get_recover_session(self): ''' Verify client(get) recovers session after logout ''' dut = self.duts[0] self.clnt.connect([dut['node']], dut['username'], dut['password']) result = self.clnt.post('/login/logout.do', None) self.assertIn('data', result) self.assertEqual('success', result['data']) result = self.clnt.get('/cvpInfo/getCvpInfo.do') self.assertIn('version', result) def test_get_recover_session_bg(self): ''' Verify client(get) recovers session after logout for bad/good node ''' dut = self.duts[0] self.clnt.connect(['bogus', dut['node']], dut['username'], dut['password']) result = self.clnt.post('/login/logout.do', None) self.assertIn('data', result) self.assertEqual('success', result['data']) result = self.clnt.get('/cvpInfo/getCvpInfo.do') self.assertIn('version', result) def test_get_cvp_error(self): ''' Verify get of bad CVP request returns an error ''' dut = self.duts[0] self.clnt.connect([dut['node']], dut['username'], dut['password']) with self.assertRaises(CvpRequestError): self.clnt.get('/aaa/getServerById.do') def test_get_cvp_url_bad(self): ''' Verify get with bad URL returns an error ''' dut = self.duts[0] self.clnt.connect([dut['node']], dut['username'], dut['password']) with self.assertRaises(CvpApiError): self.clnt.get('/aaa/bogus.do') def test_get_handle_timeout(self): ''' Verify get with bad URL returns an error ''' dut = self.duts[0] self.clnt.connect([dut['node']], dut['username'], dut['password']) with self.assertRaises(Timeout): self.clnt.get('/tasks/getTasks.do', timeout=0.0001) def test_get_except_fail_reconnect(self): ''' Verify exception raised if session fails and cannot be re-established. ''' dut = self.duts[0] nodes = ['bogus', dut['node']] self.clnt.connect(nodes, dut['username'], dut['password']) # Change the password for the CVP user so that a session reconnect # to any node will fail self._change_passwd(nodes, dut['username'], dut['password'], self.NEW_PASSWORD) try: # Logout to end the current session and force a reconnect for the # next request. result = self.clnt.post('/login/logout.do', None) self.assertIn('data', result) self.assertEqual('success', result['data']) except Exception as error: # Should not have had an exception. Restore the CVP password # and re-raise the error. self._change_passwd(nodes, dut['username'], self.NEW_PASSWORD, dut['password']) raise error try: # Try a get request and expect a CvpSessionLogOutError result = self.clnt.get('/cvpInfo/getCvpInfo.do') except CvpSessionLogOutError as error: pass except Exception as error: # Unexpected error, restore password and re-raise the error. self._change_passwd(nodes, dut['username'], self.NEW_PASSWORD, dut['password']) raise error # Restore password self._change_passwd(nodes, dut['username'], self.NEW_PASSWORD, dut['password']) def test_post_not_connected(self): ''' Verify post with no connection raises a ValueError ''' with self.assertRaises(ValueError): self.clnt.post('/bogus', None) def test_post(self): ''' Verify post of CVP info ''' dut = self.duts[0] self.clnt.connect([dut['node']], dut['username'], dut['password']) result = self.clnt.post('/login/logout.do', None) self.assertIn('data', result) self.assertEqual('success', result['data']) def test_post_recover_session(self): ''' Verify client(post) recovers session after logout ''' dut = self.duts[0] self.clnt.connect([dut['node']], dut['username'], dut['password']) result = self.clnt.post('/login/logout.do', None) self.assertIn('data', result) self.assertEqual('success', result['data']) result = self.clnt.post('/login/logout.do', None) self.assertEqual('success', result['data']) def test_post_recover_session_bg(self): ''' Verify client(post) recovers session after logout for bad/good node ''' dut = self.duts[0] self.clnt.connect(['bogus', dut['node']], dut['username'], dut['password']) result = self.clnt.post('/login/logout.do', None) self.assertIn('data', result) self.assertEqual('success', result['data']) result = self.clnt.post('/login/logout.do', None) self.assertEqual('success', result['data']) def test_post_cvp_bad_schema(self): ''' Verify post with bad schema returns an error ''' dut = self.duts[0] self.clnt.connect([dut['node']], dut['username'], dut['password']) with self.assertRaises(CvpApiError): self.clnt.post('/aaa/saveAAADetails.do', None) def test_post_cvp_url_bad(self): ''' Verify post with bad URL returns an error ''' dut = self.duts[0] self.clnt.connect([dut['node']], dut['username'], dut['password']) with self.assertRaises(CvpApiError): self.clnt.post('/aaa/bogus.do', None) def test_post_except_fail_reconn(self): ''' Verify exception raised if session fails and cannot be re-established. ''' dut = self.duts[0] nodes = ['bogus', dut['node']] self.clnt.connect(nodes, dut['username'], dut['password']) # Change the password for the CVP user so that a session reconnect # to any node will fail self._change_passwd(nodes, dut['username'], dut['password'], self.NEW_PASSWORD) try: # Logout to end the current session and force a reconnect for the # next request. result = self.clnt.post('/login/logout.do', None) self.assertIn('data', result) self.assertEqual('success', result['data']) except Exception as error: # Should not have had an exception. Restore the CVP password # and re-raise the error. self._change_passwd(nodes, dut['username'], self.NEW_PASSWORD, dut['password']) raise error try: # Try a post request and expect a CvpSessionLogOutError result = self.clnt.post('/login/logout.do', None) except CvpSessionLogOutError as error: pass except Exception as error: # Unexpected error, restore password and re-raise the error. self._change_passwd(nodes, dut['username'], self.NEW_PASSWORD, dut['password']) raise error # Restore password self._change_passwd(nodes, dut['username'], self.NEW_PASSWORD, dut['password'])
class TestCvpClient(DutSystemTest): ''' Test cases for the CvpClient class. ''' # pylint: disable=too-many-public-methods NEW_PASSWORD = '******' def setUp(self): ''' Instantiate the CvpClient class. Log messages to the /tmp/TestCvpClient.log ''' super(TestCvpClient, self).setUp() self.clnt = CvpClient(filename='/tmp/TestCvpClient.log') self.assertIsNotNone(self.clnt) def tearDown(self): ''' Destroy the CvpClient class. ''' super(TestCvpClient, self).tearDown() self.clnt = None def _change_passwd(self, nodes, username, old_password, new_password): ''' Helper method to change the user password on CVP. ''' # Create a new connection to handle the request. clnt = CvpClient(filename='/tmp/TestCvpClient.log') clnt.connect(nodes, username, old_password) data = { 'user': { 'userId': username, 'password': new_password, 'email': '*****@*****.**', 'userStatus': 'Enabled', }, 'roles': ['network-admin'] } result = clnt.post("/user/updateUser.do?userId=%s" % username, data) self.assertEqual('success', result['data']) def test_clnt_init(self): ''' Verify CvpClient init ''' clnt = CvpClient() self.assertIsNotNone(clnt) self.assertEqual(clnt.log.getEffectiveLevel(), logging.INFO) def test_clnt_init_syslog(self): ''' Verify CvpClient init with syslog argument ''' clnt = CvpClient(syslog=True) self.assertIsNotNone(clnt) def test_clnt_init_syslog_filename(self): ''' Verify CvpClient init with syslog and filename argument ''' logfile = '/tmp/foo' clnt = CvpClient(syslog=True, logger='cvpracTmp', filename=logfile) self.assertIsNotNone(clnt) os.remove(logfile) def test_clnt_init_log_level(self): ''' Verify CvpClient init with setting log level ''' clnt = CvpClient(log_level='DEBUG') self.assertIsNotNone(clnt) self.assertEqual(clnt.log.getEffectiveLevel(), logging.DEBUG) def test_set_log_level(self): self.clnt.set_log_level('DEBUG') self.assertEqual(self.clnt.log.getEffectiveLevel(), logging.DEBUG) self.clnt.set_log_level('INFO') self.assertEqual(self.clnt.log.getEffectiveLevel(), logging.INFO) def test_set_log_level_invalid_value(self): self.clnt.set_log_level('blahblah') self.assertEqual(self.clnt.log.getEffectiveLevel(), logging.INFO) def test_connect_http_good(self): ''' Verify http connection succeeds to a single CVP node Uses default protocol and port. ''' dut = self.duts[0] self.clnt.connect([dut['node']], dut['username'], dut['password']) def test_connect_https_good(self): ''' Verify https connection succeeds to a single CVP node Uses https protocol and port. ''' dut = self.duts[0] self.clnt.connect([dut['node']], dut['username'], dut['password'], protocol='https') def test_connect_username_bad(self): ''' Verify connect fails with bad username. ''' dut = self.duts[0] with self.assertRaises(CvpLoginError): self.clnt.connect([dut['node']], 'username', dut['password']) def test_connect_password_bad(self): ''' Verify connect fails with bad password. ''' dut = self.duts[0] with self.assertRaises(CvpLoginError): self.clnt.connect([dut['node']], dut['username'], 'password') def test_connect_node_bad(self): ''' Verify connection fails to a single bogus CVP node ''' with self.assertRaises(CvpLoginError): self.clnt.connect(['bogus'], 'username', 'password', connect_timeout=1) def test_connect_non_cvp_node(self): ''' Verify connection fails to a non-CVP node ''' with self.assertRaises(CvpLoginError): self.clnt.connect(['localhost'], 'username', 'password') def test_connect_all_nodes_bad(self): ''' Verify connection fails to a single bogus CVP node ''' with self.assertRaises(CvpLoginError): self.clnt.connect(['bogus1', 'bogus2', 'bogus3'], 'username', 'password', connect_timeout=1) def test_connect_n1_bad_n2_good(self): ''' Verify connect succeeds even if one node is bad ''' dut = self.duts[0] self.clnt.connect(['bogus', dut['node']], dut['username'], dut['password'], connect_timeout=2) def test_connect_nodes_arg_bad(self): ''' Verify non-list nodes argument raises a TypeError ''' with self.assertRaises(TypeError): self.clnt.connect('bogus', 'username', 'password') def test_connect_port_bad(self): ''' Verify non-http protocol with default port raises a TypeError ''' dut = self.duts[0] with self.assertRaises(ValueError): self.clnt.connect([dut['node']], dut['username'], dut['password'], protocol='bogus') def test_get_not_connected(self): ''' Verify get with no connection raises a ValueError ''' with self.assertRaises(ValueError): self.clnt.get('/bogus') def test_get(self): ''' Verify get of CVP info ''' dut = self.duts[0] self.clnt.connect([dut['node']], dut['username'], dut['password']) result = self.clnt.get('/cvpInfo/getCvpInfo.do') self.assertIn('version', result) def test_get_recover_session(self): ''' Verify client(get) recovers session after logout ''' dut = self.duts[0] self.clnt.connect([dut['node']], dut['username'], dut['password']) result = self.clnt.post('/login/logout.do', None) self.assertIn('data', result) self.assertEqual('success', result['data']) result = self.clnt.get('/cvpInfo/getCvpInfo.do') self.assertIn('version', result) def test_get_recover_session_bg(self): ''' Verify client(get) recovers session after logout for bad/good node ''' dut = self.duts[0] self.clnt.connect(['bogus', dut['node']], dut['username'], dut['password']) result = self.clnt.post('/login/logout.do', None) self.assertIn('data', result) self.assertEqual('success', result['data']) result = self.clnt.get('/cvpInfo/getCvpInfo.do') self.assertIn('version', result) def test_get_cvp_error(self): ''' Verify get of bad CVP request returns an error ''' dut = self.duts[0] self.clnt.connect([dut['node']], dut['username'], dut['password']) with self.assertRaises(CvpRequestError): self.clnt.get('/aaa/getServerById.do') def test_get_cvp_url_bad(self): ''' Verify get with bad URL returns an error ''' dut = self.duts[0] self.clnt.connect([dut['node']], dut['username'], dut['password']) with self.assertRaises(CvpApiError): self.clnt.get('/aaa/bogus.do') def test_get_handle_timeout(self): ''' Verify get with bad URL returns an error ''' dut = self.duts[0] self.clnt.connect([dut['node']], dut['username'], dut['password']) with self.assertRaises(Timeout): self.clnt.get('/tasks/getTasks.do', timeout=0.0001) def test_get_except_fail_reconnect(self): ''' Verify exception raised if session fails and cannot be re-established. ''' dut = self.duts[0] nodes = ['bogus', dut['node']] self.clnt.connect(nodes, dut['username'], dut['password']) # Change the password for the CVP user so that a session reconnect # to any node will fail self._change_passwd(nodes, dut['username'], dut['password'], self.NEW_PASSWORD) try: # Logout to end the current session and force a reconnect for the # next request. result = self.clnt.post('/login/logout.do', None) self.assertIn('data', result) self.assertEqual('success', result['data']) except Exception as error: # Should not have had an exception. Restore the CVP password # and re-raise the error. self._change_passwd(nodes, dut['username'], self.NEW_PASSWORD, dut['password']) raise error try: # Try a get request and expect a CvpSessionLogOutError result = self.clnt.get('/cvpInfo/getCvpInfo.do') except CvpSessionLogOutError as error: pass except Exception as error: # Unexpected error, restore password and re-raise the error. self._change_passwd(nodes, dut['username'], self.NEW_PASSWORD, dut['password']) raise error # Restore password self._change_passwd(nodes, dut['username'], self.NEW_PASSWORD, dut['password']) def test_post_not_connected(self): ''' Verify post with no connection raises a ValueError ''' with self.assertRaises(ValueError): self.clnt.post('/bogus', None) def test_post(self): ''' Verify post of CVP info ''' dut = self.duts[0] self.clnt.connect([dut['node']], dut['username'], dut['password']) result = self.clnt.post('/login/logout.do', None) self.assertIn('data', result) self.assertEqual('success', result['data']) def test_post_recover_session(self): ''' Verify client(post) recovers session after logout ''' dut = self.duts[0] self.clnt.connect([dut['node']], dut['username'], dut['password']) result = self.clnt.post('/login/logout.do', None) self.assertIn('data', result) self.assertEqual('success', result['data']) result = self.clnt.post('/login/logout.do', None) self.assertEqual('success', result['data']) def test_post_recover_session_bg(self): ''' Verify client(post) recovers session after logout for bad/good node ''' dut = self.duts[0] self.clnt.connect(['bogus', dut['node']], dut['username'], dut['password']) result = self.clnt.post('/login/logout.do', None) self.assertIn('data', result) self.assertEqual('success', result['data']) result = self.clnt.post('/login/logout.do', None) self.assertEqual('success', result['data']) def test_post_cvp_bad_schema(self): ''' Verify post with bad schema returns an error ''' dut = self.duts[0] self.clnt.connect([dut['node']], dut['username'], dut['password']) with self.assertRaises(CvpApiError): self.clnt.post('/aaa/saveAAADetails.do', None) def test_post_cvp_url_bad(self): ''' Verify post with bad URL returns an error ''' dut = self.duts[0] self.clnt.connect([dut['node']], dut['username'], dut['password']) with self.assertRaises(CvpApiError): self.clnt.post('/aaa/bogus.do', None) def test_post_except_fail_reconn(self): ''' Verify exception raised if session fails and cannot be re-established. ''' dut = self.duts[0] nodes = ['bogus', dut['node']] self.clnt.connect(nodes, dut['username'], dut['password']) # Change the password for the CVP user so that a session reconnect # to any node will fail self._change_passwd(nodes, dut['username'], dut['password'], self.NEW_PASSWORD) try: # Logout to end the current session and force a reconnect for the # next request. result = self.clnt.post('/login/logout.do', None) self.assertIn('data', result) self.assertEqual('success', result['data']) except Exception as error: # Should not have had an exception. Restore the CVP password # and re-raise the error. self._change_passwd(nodes, dut['username'], self.NEW_PASSWORD, dut['password']) raise error try: # Try a post request and expect a CvpSessionLogOutError result = self.clnt.post('/login/logout.do', None) except CvpSessionLogOutError as error: pass except Exception as error: # Unexpected error, restore password and re-raise the error. self._change_passwd(nodes, dut['username'], self.NEW_PASSWORD, dut['password']) raise error # Restore password self._change_passwd(nodes, dut['username'], self.NEW_PASSWORD, dut['password'])
class Cvp(): def __init__(self): self.cvprac = None self.containerTree = {} self.CvpApiError = None self.devices = {} self.host_to_device = {} self.containers = {} self.configlets = {} try: from cvprac.cvp_client import CvpClient from cvprac.cvp_client_errors import CvpClientError from cvprac.cvp_client_errors import CvpApiError self.CvpClientError = CvpClientError self.CvpApiError = CvpApiError self.cvprac = CvpClient() urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) # to supress the warnings for https self.cvprac.connect([searchConfig('cvp_server')], searchConfig('cvp_user'), searchConfig('cvp_pass')) LOGGER.log("Successfully authenticated to CVP") except (ImportError, self.CvpClientError) as e: LOGGER.log("Unable to Init CVP; forcing debug mode") LOGGER.log("ERROR: {0}".format(e)) global DEBUG DEBUG = True def populate(self): try: LOGGER.log("-loading containers; please wait...") self.containers = {item['name'].lower():item for item in self.cvprac.api.get_containers()['data']} LOGGER.log("-loading configlets; please wait...") self.configlets = {item['name'].lower():item for item in self.cvprac.api.get_configlets()['data']} for name, cont in self.containers.items(): self.containerTree[name] = [_name for _name, _cont in self.containers.items() if _cont['parentName'] == cont['name']] LOGGER.log("-loading devices; please wait...") for device in self.cvprac.api.get_inventory(): sn = device['serialNumber'].lower() host = device['hostname'].lower() LOGGER.log("-loading {0} configlets; please wait...".format(host)) configlets = self.cvprac.api.get_configlets_by_device_id(device['systemMacAddress']) device['configlets'] = {item['name'].lower():item for item in configlets} self.devices[sn] = device self.host_to_device[host] = self.devices[sn] except: LOGGER.log("Unable to connect to CVP Server") sys.exit(0) def getBySerial(self, sn): return self.devices.get(sn.lower(), None) def getByHostname(self, hostname): return self.host_to_device.get(hostname.lower(), None) def getContainerByName(self, name): return self.containers.get(name.lower(), None) def getContainerDevices(self, containerName, follow = False): containerName = containerName.lower() tree = [containerName] + self.containerTree[containerName] if follow else [containerName] return [device for device in self.devices.values() if device['containerName'].lower() in tree] def fetchDevices(self, search, follow_child_containers = False): search = search if type(search) == list else [search] devices = [] for _search in search: try: device = CVP.getBySerial(_search) or CVP.getByHostname(_search) if device: devices.append((device,)) continue else: devices.append(CVP.getContainerDevices(_search, follow_child_containers)) except KeyError as e: LOGGER.log("Could not find {0}".format(_search)) return list(chain.from_iterable(devices)) def createConfiglet(self, configlet_name, configlet_content): # Configlet doesn't exist let's create one LOGGER.log("--creating configlet {0}; please wait...".format(configlet_name)) self.cvprac.api.add_configlet(configlet_name, configlet_content) return self.cvprac.api.get_configlet_by_name(configlet_name) def updateConfiglet(self, configlet, new_configlet_content): # Configlet does exist, let's update the content only if not the same (avoid empty task) configlet_name = configlet['name'] LOGGER.log("--found configlet {0}".format(configlet_name)) if configlet['config'] != new_configlet_content: LOGGER.log("---updating configlet {0}; please wait...".format(configlet_name)) self.cvprac.api.update_configlet(new_configlet_content, configlet['key'], configlet_name) return self.cvprac.api.get_configlet_by_name(configlet_name) def deployDevice(self, device, container, configlets_to_deploy): try: ids = self.cvprac.api.deploy_device(device.cvp, container, configlets_to_deploy) except self.CvpApiError as e: LOGGER.log("---deploying device {0}: failed, could not get task id from CVP".format(device.hostname)) else: ids = ','.join(map(str, ids['data']['taskIds'])) LOGGER.log("---deploying device {0}: {1} to {2} container".format(device.hostname, device.mgmt_ip, device.container)) LOGGER.log("---CREATED TASKS {0}".format(ids)) def applyConfiglets(self, to, configlets): app_name = "CVP Configlet Builder" to = to if type(to) == list else [to] configlets = configlets if type(configlets) == list else [configlets] toContainer = None toDevice = None #dest is a container, sn. or hostname string for dest in to: toContainer = self.getContainerByName(dest) if toContainer: LOGGER.log("---applying configlets to {0}; please wait...".format(toContainer.name)) _result = self.cvprac.api.apply_configlets_to_container(app_name, toContainer, configlets) dest = toContainer else: #apply to device toDevice = getBySerial(dest) or getByHostname(dest) dest = toDevice.hostname LOGGER.log("---applying configlets to {0}; please wait...".format(dest)) _result = self.cvprac.api.apply_configlets_to_device(app_name, toDevice.cvp, configlets) if toDevice else None if not (toDevice or toContainer): errorOn = [_conf['name'] for _conf in configlets] LOGGER.log("---failed to push {0}; {1} not found".format(','.join(errorOn), dest)) elif _result and _result['data']['status'] == 'success': LOGGER.log("---CREATED TASKS {0}".format(','.join(map(str, _result['data']['taskIds'])))) return None
from pprint import pprint from cvprac.cvp_client import CvpClient from cvprac.cvp_api import CvpApi import urllib3 import requests urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning ) # This will disable invalid cert warnings clnt = CvpClient() clnt.connect(['cvp.lab.local'], 'jpatterson', 'P3pp3r101!') result = clnt.get('/cvpInfo/getCvpInfo.do') test1 = clnt.get( '/cvpservice/snapshot/getSnapshots.do?startIndex=0&endIndex=0') pprint(result)
# Copyright (c) 2021 Arista Networks, Inc. # Use of this source code is governed by the Apache License 2.0 # that can be found in the COPYING file. from cvprac.cvp_client import CvpClient # Reading the service account token from a file with open("token.tok") as f: token = f.read().strip('\n') # Create connection to CloudVision clnt = CvpClient() clnt.connect(nodes=['cvp1'], username='', password='', api_token=token) tags_common = [{ "key": "topology_hint_pod", "value": "tp-avd-pod1" }, { "key": "topology_hint_datacenter", "value": "tp-avd-dc1" }] tags_leaf1 = [{"key": "topology_hint_rack", "value": "tp-avd-leafs1"}] tags_leaf2 = [{"key": "topology_hint_rack", "value": "tp-avd-leafs2"}] tags_spines = [{"key": "topology_hint_rack", "value": "tp-avd-spines"}] # Create workspace display_name = 'TestTagCVPRAC' workspace_id = "TestTagCVPRAC" clnt.api.workspace_config(workspace_id, display_name) ### Create tags
def main(): compliance = { "0001": "Config is out of sync", "0003": "Config & image out of sync", "0004": "Config, Image and Device time are in sync", "0005": "Device is not reachable", "0008": "Config, Image and Extensions are out of sync", "0009": "Config and Extensions are out of sync", "0012": "Config, Image, Extension and Device time are out of sync", "0013": "Config, Image and Device time are out of sync", "0014": "Config, Extensions and Device time are out of sync", "0016": "Config and Device time are out of sync" } # Create connection to CloudVision clnt = CvpClient() parser = argparse.ArgumentParser( description= 'Script to recreate a task, if a previous config push was cancelled') parser.add_argument('-u', '--username', default='username') parser.add_argument('-p', '--password', default=None) parser.add_argument('-c', '--cvpserver', action='append') parser.add_argument('-f', '--filter', action='append', default=None) args = parser.parse_args() if args.password is None: args.password = getpass() for cvpserver in args.cvpserver: print("Connecting to %s" % cvpserver) try: clnt.connect(nodes=[cvpserver], username=args.username, password=args.password) except Exception as e: print("Unable to connect to CVP: %s" % str(e)) # Get the current CVP version cvp_release = clnt.api.get_cvp_info()['version'] if parse_version(cvp_release) < parse_version('2020.3.0'): # For older CVP, we manually trigger a compliance check try: clnt.api.check_compliance('root', 'container') except: # Bad practice, but the check compliance applied to a container can't actually work # since the complianceIndication key doesn't exist on the container level pass else: # with continuous compliance checks, triggering the check is no longer required pass device_filters = [] if args.filter is not None: for entry in args.filter: device_filters.extend(entry.split(',')) # Get inventory print("Collecting inventory...") devices = clnt.api.get_inventory() print("%d devices in inventory" % len(devices)) for switch in devices: if (switch['status'] == 'Registered' and switch['parentContainerId'] != 'undefined_container'): if len(device_filters) > 0: # iterate over device filters, and update task for # any devices not in compliance for filter_term in device_filters: print("Checking device: %s" % switch['hostname']) if filter_term in switch['hostname']: # generate configlet list cl = clnt.api.get_configlets_by_device_id( switch['systemMacAddress']) # generate a task if config is out of sync if switch['complianceCode'] in compliance.keys(): print( clnt.api.apply_configlets_to_device( "", switch, cl)) else: print("%s is compliant, nothing to do" % switch['hostname']) else: print("Skipping %s due to filter" % switch['hostname']) else: print("Checking device: %s" % switch['hostname']) cl = clnt.api.get_configlets_by_device_id( switch['systemMacAddress']) # generate a task if config is out of sync if switch['complianceCode'] in compliance.keys(): print( clnt.api.apply_configlets_to_device( "", switch, cl)) else: print("Skipping %s, device is unregistered for provisioning" % switch['hostname']) return 0
# Use of this source code is governed by the Apache License 2.0 # that can be found in the COPYING file. # # Get list of configlets in parallel from cvprac.cvp_client import CvpClient import ssl from concurrent.futures import ThreadPoolExecutor ssl._create_default_https_context = ssl._create_unverified_context import requests.packages.urllib3 requests.packages.urllib3.disable_warnings() # Create connection to CloudVision clnt = CvpClient() clnt.connect(nodes=['cvp1'], username="******", password="******") import time from functools import wraps def get_list_of_configlets(configlets): """ Create a thread pool and download specified urls """ futures_list = [] results = [] with ThreadPoolExecutor(max_workers=40) as executor: for configlet in configlets:
from cvprac.cvp_client import CvpClient from pprint import pprint import json import sys from jinja2 import Environment, FileSystemLoader import itertools robotlist = [] countlist = [] client = CvpClient() client.connect(['10.20.30.142'],'daniel', 'daniel123') inventory = client.api.get_inventory() def initcvpyaml(): sys.stdout = open('cvp.yaml', 'w') print '---' print 'TRANSPORT: https' print 'PORT: 443' print 'USERNAME: daniel' print 'PASSWORD: daniel123' print ' ' print 'RUNFORMAT: suite' print ' ' print 'PROD_TAGS:' print ' - ignoretags' print ' ' print 'testfiles:' print ' - network_validation' print ' ' print 'nodes:'