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 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 setUp(self): """ Setup for CvpClient unittests """ self.clnt = CvpClient() nodes = ['1.1.1.1'] self.clnt.nodes = nodes self.clnt.node_cnt = len(nodes) self.clnt.node_pool = cycle(nodes)
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_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)
#!/usr/bin/env python # See getting started: # https://github.com/aristanetworks/cvprac#example # sudo pip install cvprac import sys import pprint # should just fix this import urllib3 urllib3.disable_warnings() from cvprac.cvp_client import CvpClient clnt = CvpClient() if len(sys.argv) != 2: print "Usage: python sys.argv[0] ip_of_cvp" sys.exit(1) else: cvphost = sys.argv[1] clnt.connect([cvphost], 'arista', 'arista') device_info = clnt.api.get_device_by_name('leaf1.arista.test') pprint.pprint(device_info)
def test_clnt_init(self): ''' Verify CvpClient init ''' clnt = CvpClient() self.assertIsNotNone(clnt)
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)
class TestCvpClient(DutSystemTest): ''' Test cases for the CvpClient class. ''' # pylint: disable=too-many-public-methods # pylint: disable=invalid-name 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): ''' Verify changing/setting of log level using client setter method ''' 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): ''' Verify an invalid log level value will default the log level to INFO ''' 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']) def test_connect_set_request_timeout(self): ''' Verify API request timeout is set when provided to client connect method. ''' dut = self.duts[0] self.clnt.connect([dut['node']], dut['username'], dut['password'], request_timeout=34) self.assertEqual(self.clnt.api.request_timeout, 34) 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=5) 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 default port for https raises an error if appliance is not configured for the port. ''' dut = self.duts[0] with self.assertRaises(CvpLoginError): self.clnt.connect([dut['node']], dut['username'], dut['password'], port=700) 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']) if self.clnt.apiversion is None: self.clnt.api.get_cvp_info() if self.clnt.apiversion == 'v1': with self.assertRaises(CvpRequestError): self.clnt.get('/aaa/getServerById.do') else: with self.assertRaises(CvpApiError): 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, CvpApiError) 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']) if self.clnt.apiversion is None: self.clnt.api.get_cvp_info() if self.clnt.apiversion == 'v1': with self.assertRaises(CvpApiError): self.clnt.post('/aaa/saveAAADetails.do', None) else: with self.assertRaises(CvpRequestError): 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, CvpApiError) 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) 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'])
# 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(nodes=['cvp1'], username="******", password="******") configletName = "cvprac_example" configlet = """! interface Ethernet10 description test ip address 10.144.144.1/24 ! """ clnt.api.add_configlet(configletName, configlet)
# 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 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"
class TestClient(unittest.TestCase): """ Unit test cases for CvpClient """ # pylint: disable=protected-access # pylint: disable=invalid-name def setUp(self): """ Setup for CvpClient unittests """ self.clnt = CvpClient() nodes = ['1.1.1.1'] self.clnt.nodes = nodes self.clnt.node_cnt = len(nodes) self.clnt.node_pool = cycle(nodes) def test_create_session_default_https(self): """ Test connection to CVP nodes will default to https. """ url = 'https://1.1.1.1:443/web' self.clnt._reset_session = Mock() self.clnt._reset_session.return_value = None self.clnt._create_session(all_nodes=True) self.assertEqual(self.clnt.url_prefix, url) def test_create_session_https_port(self): """ Test https session with user provided port. """ self.clnt.port = 7777 url = 'https://1.1.1.1:7777/web' self.clnt._reset_session = Mock() self.clnt._reset_session.return_value = None self.clnt._create_session(all_nodes=True) self.assertEqual(self.clnt.url_prefix, url) def test_create_session_http_fallback(self): """ Test a failed https connection will attempt to fallback to http. """ self.clnt.port = None url = 'http://1.1.1.1:80/web' self.clnt._reset_session = Mock() self.clnt._reset_session.side_effect = ['Failed to connect via https', None] self.clnt._create_session(all_nodes=True) self.assertEqual(self.clnt.url_prefix, url) self.assertEqual(self.clnt.error_msg, '\n') def test_create_session_http_fallback_port(self): """ Test http fallback will use a user provided port number. """ self.clnt.port = 8888 url = 'http://1.1.1.1:8888/web' self.clnt._reset_session = Mock() self.clnt._reset_session.side_effect = ['Failed to connect via https', None] self.clnt._create_session(all_nodes=True) self.assertEqual(self.clnt.url_prefix, url) self.assertEqual(self.clnt.error_msg, '\n') def test_create_session_no_http_fallback_with_cert(self): """ If user passes a certificate to CvpClient it will only attempt to use https and not fall back to http. """ self.clnt.port = None self.clnt.cert = 'cert' url = 'https://1.1.1.1:443/web' error = '\n1.1.1.1: Failed to connect via https\n' self.clnt._reset_session = Mock() self.clnt._reset_session.return_value = 'Failed to connect via https' self.clnt._create_session(all_nodes=True) self.assertEqual(self.clnt.url_prefix, url) self.assertEqual(self.clnt.error_msg, error) def test_make_request_good(self): """ Test request does not raise exception and returns json. """ self.clnt.session = Mock() self.clnt.session.return_value = True request_return_value = Mock() self.clnt.session.get.return_value = request_return_value self.clnt._create_session = Mock() self.clnt.NUM_RETRY_REQUESTS = 2 self.clnt.connect_timeout = 2 self.clnt.node_cnt = 2 self.clnt.url_prefix = 'https://1.1.1.1:7777/web' self.clnt._is_good_response = Mock(return_value='Good') self.assertIsNone(self.clnt.last_used_node) self.clnt._make_request('GET', 'url', 2, {'data': 'data'}) request_return_value.json.assert_called_once_with() self.assertEqual(self.clnt.last_used_node, '1.1.1.1') def test_make_request_timeout(self): """ Test request timeout exception raised if hit on multiple nodes. """ self.clnt.session = Mock() self.clnt.session.return_value = True self.clnt.session.get.side_effect = ReadTimeout('Timeout') self.clnt._create_session = Mock() self.clnt.NUM_RETRY_REQUESTS = 3 self.clnt.connect_timeout = 2 self.clnt.node_cnt = 3 self.clnt.url_prefix = 'https://1.1.1.1:7777/web' self.clnt._is_good_response = Mock(return_value='Good') self.assertIsNone(self.clnt.last_used_node) with self.assertRaises(ReadTimeout): self.clnt._make_request('GET', 'url', 2, {'data': 'data'}) self.assertEqual(self.clnt.last_used_node, '1.1.1.1') def test_make_request_http_error(self): """ Test request http exception raised if hit on multiple nodes. """ self.clnt.session = Mock() self.clnt.session.return_value = True self.clnt.session.get.side_effect = HTTPError('HTTPError') self.clnt._create_session = Mock() self.clnt.NUM_RETRY_REQUESTS = 2 self.clnt.connect_timeout = 2 self.clnt.node_cnt = 2 self.clnt.url_prefix = 'https://1.1.1.1:7777/web' self.clnt._is_good_response = Mock(return_value='Good') self.assertIsNone(self.clnt.last_used_node) with self.assertRaises(HTTPError): self.clnt._make_request('GET', 'url', 2, {'data': 'data'}) self.assertEqual(self.clnt.last_used_node, '1.1.1.1') def test_make_request_no_session_error(self): """ Test request exception raised if hit on multiple nodes and _create_session fails to reset clnt.session. """ self.clnt.session = Mock() self.clnt.session.return_value = True self.clnt.session.get.side_effect = HTTPError('HTTPError') self.clnt.NUM_RETRY_REQUESTS = 2 self.clnt.connect_timeout = 0.01 self.clnt.node_cnt = 2 self.clnt.url_prefix = 'https://1.1.1.1:7777/web' self.clnt._is_good_response = Mock(return_value='Good') self.assertIsNone(self.clnt.last_used_node) with self.assertRaises(HTTPError): self.clnt._make_request('GET', 'url', 2, {'data': 'data'}) self.assertEqual(self.clnt.last_used_node, '1.1.1.1') def test_make_request_response_error(self): """ Test request exception raised from CVP response data. """ self.clnt.session = Mock() self.clnt.session.return_value = True self.clnt.session.get.return_value = Mock() self.clnt._create_session = Mock() self.clnt.NUM_RETRY_REQUESTS = 2 self.clnt.connect_timeout = 2 self.clnt.node_cnt = 2 self.clnt.url_prefix = 'https://1.1.1.1:7777/web' self.clnt._is_good_response = Mock() self.clnt._is_good_response.side_effect = CvpApiError('CvpApiError') self.assertIsNone(self.clnt.last_used_node) with self.assertRaises(CvpApiError): self.clnt._make_request('GET', 'url', 2, {'data': 'data'}) self.assertEqual(self.clnt.last_used_node, '1.1.1.1') def test_make_request_response_error_unauthorized(self): """ Test request exception raised if CVP responds unauthorized user. """ self.clnt.session = Mock() self.clnt.session.return_value = True self.clnt.session.get.return_value = Mock() self.clnt._create_session = Mock() self.clnt._reset_session = Mock() self.clnt.NUM_RETRY_REQUESTS = 2 self.clnt.connect_timeout = 2 self.clnt.node_cnt = 2 self.clnt.url_prefix = 'https://1.1.1.1:7777/web' self.clnt._is_good_response = Mock() self.clnt._is_good_response.side_effect = CvpApiError( msg='Unauthorized User') self.assertIsNone(self.clnt.last_used_node) with self.assertRaises(CvpApiError): self.clnt._make_request('GET', 'url', 2, {'data': 'data'}) self.assertEqual(self.clnt.last_used_node, '1.1.1.1') def test_make_request_response_error_logout(self): """ Test request exception raised if CVP logout error hit. """ self.clnt.session = Mock() self.clnt.session.return_value = True self.clnt.session.get.return_value = Mock() self.clnt._create_session = Mock() self.clnt._reset_session = Mock() self.clnt.NUM_RETRY_REQUESTS = 2 self.clnt.connect_timeout = 2 self.clnt.node_cnt = 2 self.clnt.url_prefix = 'https://1.1.1.1:7777/web' self.clnt._is_good_response = Mock() self.clnt._is_good_response.side_effect = CvpSessionLogOutError('bad') self.assertIsNone(self.clnt.last_used_node) with self.assertRaises(CvpSessionLogOutError): self.clnt._make_request('GET', 'url', 2, {'data': 'data'}) self.assertEqual(self.clnt.last_used_node, '1.1.1.1')
# Copyright (c) 2020 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) container_name = "TP_FABRIC" container = clnt.api.get_container_by_name(container_name) clnt.api.remove_image_from_container(image, container)
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 ' '
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 client = CvpClient() api = CvpApi(client) client.connect(['cvp.lab.local'], 'jpatterson', 'P3pp3r101!') result = client.get('/cvpInfo/getCvpInfo.do') newresult = client.get( 'https://cvp.lab.local/cvpservice/image/getImages.do?startIndex=0&endIndex=0' ) print newresult # test1 = clnt.get('/cvpservice/snapshot/getSnapshots.do?startIndex=0&endIndex=0') print result
def main(): clnt = CvpClient() clnt.connect(['192.168.130.3'], 'cvpadmin', 'mypass', protocol='https') logs = get_logs(clnt) print json.dumps(logs, indent=4, sort_keys=True)
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'name': (unicode, str), u'formList': list, u'main_script': dict, } 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, 'configletMapper': dict, 'total': int, } self.assertListEqual(exp_data.keys(), result.keys()) for key in exp_data: 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, 'configletMapper': dict, 'total': int, } self.assertListEqual(exp_data.keys(), result.keys()) for key in exp_data: 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, } self.assertListEqual(exp_data.keys(), result.keys()) for key in exp_data: 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, } self.assertListEqual(exp_data.keys(), result.keys()) for key in exp_data: 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) 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(self): ''' Verify add_image ''' # Copy the test image file with a timestamp appended image_file = 'test/fixtures/image-file-%s.swix' % time.time() shutil.copyfile('test/fixtures/image-file.swix', image_file) # Upload the image to the cluster result = self.api.add_image(image_file) # Remove the timestamp copy from the local filesystem os.remove(image_file) self.assertNotIn('errorCode', result) self.assertIn('result', result) self.assertEqual(result['result'], 'success') 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_image_bundle(self): ''' Verify save_image_bundle and update_image_bundle ''' # Get an existing bundle bundles = self.api.get_image_bundles() 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) # 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) expected = 'Image bundle updated successfully' self.assertRegexpMatches(result['data'], expected) # 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) 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) 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(1) # 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 import ssl ssl._create_default_https_context = ssl._create_unverified_context import requests.packages.urllib3 requests.packages.urllib3.disable_warnings() clnt = CvpClient() clnt.connect(nodes=['cvp1'], username="******",password="******") ts = "2021-11-19T15:04:05.0Z" # rfc3339 time uri = "/api/v3/services/compliancecheck.Compliance/GetConfig" # Fetch the inventory inventory = clnt.api.get_inventory() # Iterate through all devices and get the running-config at the specified time for each device for device in inventory: sn = device['serialNumber'] data = {"request":{ "device_id": sn, "timestamp": ts, "type":"RUNNING_CONFIG" } } try: resultRunningConfig = clnt.post(uri, data=data)[0]['config'] with open(device['hostname']+'.cfg','w') as f: f.write(resultRunningConfig) except Exception as e: print("Not able to get configuration for device {} - exception {}".format(device['fqdn'], e))
mode = args.mode # create or destroy cvaas_node = args.server # ex "www.cv-staging.corp.arista.io" cvaas_service_token = args.token # Service Token created in CVaaS device_name = args.device_name # Device name as found in CVaaS configlet_file = args.config_file configlet_string = '' with open(configlet_file, 'r') as f: configlet_string = f.read() urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) # cvprac api reference # https://github.com/aristanetworks/cvprac/blob/develop/cvprac/cvp_api.py client = CvpClient() client.connect(nodes=[cvaas_node], username='', password='', is_cvaas=True, cvaas_token=cvaas_service_token) configlet_name = device_name + '_aws_tgw_connect' device_info = client.api.get_device_by_name(device_name) if mode == 'create': # create configlet client.api.add_configlet(configlet_name, configlet_string) # get configlet info by name configlet_info = client.api.get_configlet_by_name(configlet_name)
def connect_cvp(): urllib3.disable_warnings() client = CvpClient() client.connect([config_dict()['server']], config_dict()['username'], config_dict()['password']) return client
import time import os urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) ssl._create_default_https_context = ssl._create_unverified_context parser = argparse.ArgumentParser() parser.add_argument('--username', required=True) parser.add_argument('--cvpip', required=True) args = parser.parse_args() switchuser = args.username cvpip = args.cvpip switchpass = getpass() clnt = CvpClient() clnt.connect([cvpip], switchuser, switchpass) clntapi = CvpApi(clnt) inventory = clntapi.get_inventory() d1 = time.strftime("%Y_%m_%d_%H_%M_%S", time.gmtime()) os.mkdir(d1) for device in inventory: hostname = device["hostname"] print(hostname) device_mac = device["systemMacAddress"] runningConfig = clntapi.get_device_configuration(device_mac) filename = hostname + "_show_run_" + d1 + ".txt" with open(d1 + "/" + filename, 'w') as f:
# # Example script to generate the TerminAttr token via REST API from CVaaS and CV on-prem # and save them to a file from cvprac.cvp_client import CvpClient from pprint import pprint as pp import ssl ssl._create_default_https_context = ssl._create_unverified_context import requests.packages.urllib3 requests.packages.urllib3.disable_warnings() # Reading the service account token from a file 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) terminattr_token = clnt.api.create_enroll_token('720h') with open('cv-onboarding-token', 'w') as f: f.write(terminattr_token[0]['enrollmentToken']['token']) primary = CvpClient() primary.connect(nodes=['cvp1'], username='******', password='******') terminattr_token = primary.api.create_enroll_token('720h')
except: topology = 'none' # Temp path for where repo will be cloned to (include trailing /) gitTempPath = '/tmp/atd/' # Relative path within the repo to the configlet directory configletPath = 'topologies/' + topology + '/configlets/' ignoreConfiglets = ['readme.md'] # cvpNodes can be a single item or a list of the cluster cvpNodes = ['192.168.0.5'] cvpUsername = '******' cvpPassword = '******' # Initialize the client clnt = CvpClient() # Attempt to connect to CVP, if it's not available wait 60 seconds attempts = 0 while 1: try: clnt.connect(cvpNodes, cvpUsername, cvpPassword) if clnt.api.get_cvp_info()['version']: break except: attempts += 1 print "Cannot connect to CVP waiting 1 minute attempt", attempts time.sleep(60) # Function to sync configlet to CVP
def main(): parser = argparse.ArgumentParser(description="Auto Provision CVP Nodes with Ansible") 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: logging.info('Config file %s not found' % options.config) exit() clnt = CvpClient() try: clnt.connect(config['cvp_host'], config['cvp_user'], config['cvp_pw']) except KeyError: logging.info("CVP Credentials not found in config file") exit() # determine if there is any nodes in the ansible container try: target = config['target_container'] prov_cont = config['provisioned_container'] except KeyError: logging.info("Not container info found in config file") exit() try: verbosity = config['verbosity'] except KeyError: verbosity = 'v'; try: ansible_path = config['ansible_path'] except: ansible_path = '/usr/bin/ansible-playbook' devices = clnt.api.get_devices_in_container(target) for to_provision in devices: # move the container task = move_to_container(clnt, to_provision, prov_cont) #cancel the task so we don't lose configs clnt.api.cancel_task(task['data']['taskIds'][0]) # create dynamic host file with open('cvp_provision', 'w+') as f: f.write('%s ansible_host=%s' % (to_provision['fqdn'], to_provision['ipAddress'])) logging.info("Starting to configure %s" % to_provision['fqdn']) try: logging.info("Staring to configure %s via Ansible" % to_provision['fqdn']) output = subprocess.check_output([ansible_path, '-i', 'cvp_provision' '-%s' % verbosity, config['playbook']]) logging.info(output) logging.info("Ansible completed configuration") except subprocess.CalledProcessError as e: logging.info("Ansible provision failed for host %s due to %s" % (to_provision['fqdn'], str(e))) # Ansible errored out so move device back task = move_to_container(clnt, to_provision, target) #cancel the task so we don't lose configs clnt.api.cancel_task(task['data']['taskIds'][0]) continue
def test_clnt_init(self): ''' Verify CvpClient init ''' clnt = CvpClient() self.assertIsNotNone(clnt) self.assertEqual(clnt.log.getEffectiveLevel(), logging.INFO)
"0011": "Unauthorized User", "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", "0015": "Image, Extensions and Device time are out of sync", "0016": "Config and Device time are out of sync", "0017": "Image and Device time are out of sync", "0018": "Extensions and Device time are out of sync", "0019": "Device time is out of sync" } # Create connection to CloudVision using Service account token with open("token.tok") as f: token = f.read().strip('\n') clnt = CvpClient() clnt.connect(nodes=['cvp1'], username='', password='', api_token=token) def check_devices_under_container(client, container): ''' container is the container ID ''' nodeId = container['key'] nodeName = container['name'] api = '/ztp/getAllNetElementList.do?' queryParams = "nodeId={}&queryParam=&nodeName={}&startIndex=0&endIndex=0&contextQueryParam=&ignoreAdd=false&useCache=true".format( nodeId, nodeName) return client.get(api + queryParams) container = clnt.api.get_container_by_name('TP_LEAFS')
def main(): parser = argparse.ArgumentParser(description="Auto Deploy CVP Nodes") parser.add_argument("--config", action="store", help="config file location", default="config.yml") parser.add_argument("--info", action="store", help="switch information yaml file", default="basic-switch-info.yml") parser.add_argument("--lldp", action="store", help="switch lldp yaml file", default="basic-lldp-info.yml") parser.add_argument("--monitor", action="store_true", help="make sure all tasks complete succesfully") options = parser.parse_args() info_nodes = [] try: with open(options.config) as f: config = yaml.safe_load(f) except IOError: print 'Config file %s not found' % options.config exit(-1) try: with open(options.info) as i: fyi = yaml.safe_load(i) except IOError: print 'Info file %s not found' % options.info exit(-1) try: with open(options.lldp) as ld: neighbor_file = yaml.safe_load(ld) except IOError: print 'LLDP file %s not found' % options.lldp exit(-1) for info in fyi: for key, value in info.iteritems(): if 'spine' in key.lower(): node_type = 'SPINE' elif 'leaf' in key.lower(): node_type = 'LEAF' try: info_nodes.append(Node(ip=value['mgmt-ip'], sn=value['sn'], mac_addr=value['mac'], hostname=value['hostname'], node_type=node_type)) except KeyError: print "%s did not have a required attribute (ip, sn, mac, or hostname)" % info clnt = CvpClient() clnt.connect(config['cvp_host'], config['cvp_user'], config['cvp_pw'], protocol='https') #get the devices in the undefined container devices = clnt.api.get_devices_in_container('Undefined') no_matches = [] nodes_with_tasks = [] if devices is None: print 'No devices in undefined container. Exiting' exit() else: node = None for node in devices: # try match a node in the undefinied container to informatin # in the info yaml file to_proceed = True match = find_node_match(node, info_nodes) if match is not None: #have the netElement need to make the ma1 configlet sn = node['systemMacAddress'] configlet = make_configlet(match, config) name = match.hostname + '-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(-1) #add ma1 configlet to device configlet_to_add = {'name':name, 'key':configlet_key} tasks_to_monitor = [] task = None print 'Attempting to deploy device %s' % node['systemMacAddress'] # only send image if there is one in the config file try: image = config['image'] except KeyError: image = None try: # in this task it will move the node to the container # that matches the node_type task = clnt.api.deploy_device(node, match.node_type, [configlet_to_add], image) print 'Deploy Device task created' print 'Attempting to execute task' clnt.api.execute_task(task['data']['taskIds'][0]) print 'Task executed...' nodes_with_tasks.append(match) tasks_to_monitor.append(task['data']['taskIds'][0]) except CvpApiError as e: print "unable to deploy: %s due to %s" % (node['systemMacAddress'], str(e)) else: print "no match found for %s" % node['systemMacAddress'] no_matches.append(node) if options.monitor: wait_for_tasks(tasks_to_monitor, clnt) for sw in nodes_with_tasks: sw_lldp_info = (item for item in neighbor_file if item.keys()[0] == sw.hostname).next() host = sw_lldp_info.keys()[0] eapi_node = pyeapi.client.connect(host=host, username=config['cvp_user'], password=config['cvp_pw'], return_node=True) cabling = validate_lldp(eapi_node, sw_lldp_info[host]) if cabling['success']: print 'LLDP Verified for %s' % host else: print 'LLDP error: %s for %s' % (cabling['msg'], host)
#!/usr/bin/env python ''' This program uses cvprac, the CloudVision Portal API to first get a template-ID for snapshot template: SnapshotOfConfig1 and container-ID for container: mlane1, then POST a request for CVP to capture snapshot configs for every switch in the cotainer. ''' from cvprac.cvp_client import CvpClient # Import CvpClient class module clnt = CvpClient() # create clnt object from CvpClient class clnt.connect(['192.168.1.143'], 'cvpadmin', 'cvpadmin1') # Connect to CVP # Next get Container information for mlane1 result = clnt.get( '/inventory/add/searchContainers.do?queryparam=mlane1&startIndex=0&endIndex=0' ) # And, extract the container key or container-ID. contnr = result['data'][0]['key'] # Get information for snapshot template: SnapshotOfConfig1 result2 = clnt.get( '/snapshot/getSnapshotTemplates.do?startIndex=0&endIndex=0&queryparam=SnapshotOfConfig1' ) # And, extract it's key or template-ID snapTemplt = result2['data'][0]['key'] # Build a dictionary which includes: "templateid" and "containerid" parms2 = {"templateId": snapTemplt, "containerId": contnr} # Execute a POST to the Container Snapshot module and pass the parameter dictionary: parms2 snapResult = clnt.post('/snapshot/captureContainerLevelSnapshot.do', parms2)
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 openpyxl.styles import Font from openpyxl.styles.borders import Border, Side import time import datetime import getpass print "\nEnter CVP login details:-\n" CVP_HOST = raw_input("CVP IP:") CVP_USER = raw_input("Username:"******"Password: ") ssl._create_default_https_context = ssl._create_unverified_context urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) client = CvpClient() client.connect([CVP_HOST], CVP_USER, CVP_PW, protocol='https') # Create a workbook and add a worksheet. wb = Workbook() sheet = wb.create_sheet(title='CVP_Inventory_Sheet', index=0) ws = wb.active # Data can be assigned directly to cells ws['A1'] = 'Switch Hostname' ws['B1'] = 'Switch MGMT IP' ws['C1'] = 'EOS_Version' ws['D1'] = 'Model' ws['E1'] = 'Serial_Number' ws['F1'] = 'MAC_Address'
class TestClient(unittest.TestCase): """ Unit test cases for CvpClient """ # pylint: disable=protected-access # pylint: disable=invalid-name def setUp(self): """ Setup for CvpClient unittests """ self.clnt = CvpClient() nodes = ['1.1.1.1'] self.clnt.nodes = nodes self.clnt.node_cnt = len(nodes) self.clnt.node_pool = cycle(nodes) def test_create_session_default_https(self): """ Test connection to CVP nodes will default to https. """ url = 'https://1.1.1.1:443/web' self.clnt._reset_session = Mock() self.clnt._reset_session.return_value = None self.clnt._create_session(all_nodes=True) self.assertEqual(self.clnt.url_prefix, url) def test_create_session_https_port(self): """ Test https session with user provided port. """ self.clnt.port = 7777 url = 'https://1.1.1.1:7777/web' self.clnt._reset_session = Mock() self.clnt._reset_session.return_value = None self.clnt._create_session(all_nodes=True) self.assertEqual(self.clnt.url_prefix, url) def test_create_session_http_fallback(self): """ Test a failed https connection will attempt to fallback to http. """ self.clnt.port = None url = 'http://1.1.1.1:80/web' self.clnt._reset_session = Mock() self.clnt._reset_session.side_effect = [ 'Failed to connect via https', None ] self.clnt._create_session(all_nodes=True) self.assertEqual(self.clnt.url_prefix, url) self.assertEqual(self.clnt.error_msg, '\n') def test_create_session_http_fallback_port(self): """ Test http fallback will use a user provided port number. """ self.clnt.port = 8888 url = 'http://1.1.1.1:8888/web' self.clnt._reset_session = Mock() self.clnt._reset_session.side_effect = [ 'Failed to connect via https', None ] self.clnt._create_session(all_nodes=True) self.assertEqual(self.clnt.url_prefix, url) self.assertEqual(self.clnt.error_msg, '\n') def test_create_session_no_http_fallback_with_cert(self): """ If user passes a certificate to CvpClient it will only attempt to use https and not fall back to http. """ self.clnt.port = None self.clnt.cert = 'cert' url = 'https://1.1.1.1:443/web' error = '\n1.1.1.1: Failed to connect via https\n' self.clnt._reset_session = Mock() self.clnt._reset_session.return_value = 'Failed to connect via https' self.clnt._create_session(all_nodes=True) self.assertEqual(self.clnt.url_prefix, url) self.assertEqual(self.clnt.error_msg, error) def test_make_request_good(self): """ Test request does not raise exception and returns json. """ self.clnt.session = Mock() self.clnt.session.return_value = True request_return_value = Mock() self.clnt.session.get.return_value = request_return_value self.clnt._create_session = Mock() self.clnt.NUM_RETRY_REQUESTS = 2 self.clnt.connect_timeout = 2 self.clnt.node_cnt = 2 self.clnt.url_prefix = 'https://1.1.1.1:7777/web' self.clnt._is_good_response = Mock(return_value='Good') self.assertIsNone(self.clnt.last_used_node) self.clnt._make_request('GET', 'url', 2, {'data': 'data'}) request_return_value.json.assert_called_once_with() self.assertEqual(self.clnt.last_used_node, '1.1.1.1') def test_make_request_timeout(self): """ Test request timeout exception raised if hit on multiple nodes. """ self.clnt.session = Mock() self.clnt.session.return_value = True self.clnt.session.get.side_effect = ReadTimeout('Timeout') self.clnt._create_session = Mock() self.clnt.NUM_RETRY_REQUESTS = 3 self.clnt.connect_timeout = 2 self.clnt.node_cnt = 3 self.clnt.url_prefix = 'https://1.1.1.1:7777/web' self.clnt._is_good_response = Mock(return_value='Good') self.assertIsNone(self.clnt.last_used_node) with self.assertRaises(ReadTimeout): self.clnt._make_request('GET', 'url', 2, {'data': 'data'}) self.assertEqual(self.clnt.last_used_node, '1.1.1.1') def test_make_request_http_error(self): """ Test request http exception raised if hit on multiple nodes. """ self.clnt.session = Mock() self.clnt.session.return_value = True self.clnt.session.get.side_effect = HTTPError('HTTPError') self.clnt._create_session = Mock() self.clnt.NUM_RETRY_REQUESTS = 2 self.clnt.connect_timeout = 2 self.clnt.node_cnt = 2 self.clnt.url_prefix = 'https://1.1.1.1:7777/web' self.clnt._is_good_response = Mock(return_value='Good') self.assertIsNone(self.clnt.last_used_node) with self.assertRaises(HTTPError): self.clnt._make_request('GET', 'url', 2, {'data': 'data'}) self.assertEqual(self.clnt.last_used_node, '1.1.1.1') def test_make_request_no_session_error(self): """ Test request exception raised if hit on multiple nodes and _create_session fails to reset clnt.session. """ self.clnt.session = Mock() self.clnt.session.return_value = True self.clnt.session.get.side_effect = HTTPError('HTTPError') self.clnt.NUM_RETRY_REQUESTS = 2 self.clnt.connect_timeout = 0.01 self.clnt.node_cnt = 2 self.clnt.url_prefix = 'https://1.1.1.1:7777/web' self.clnt._is_good_response = Mock(return_value='Good') self.assertIsNone(self.clnt.last_used_node) with self.assertRaises(HTTPError): self.clnt._make_request('GET', 'url', 2, {'data': 'data'}) self.assertEqual(self.clnt.last_used_node, '1.1.1.1') def test_make_request_response_error(self): """ Test request exception raised from CVP response data. """ self.clnt.session = Mock() self.clnt.session.return_value = True self.clnt.session.get.return_value = Mock() self.clnt._create_session = Mock() self.clnt.NUM_RETRY_REQUESTS = 2 self.clnt.connect_timeout = 2 self.clnt.node_cnt = 2 self.clnt.url_prefix = 'https://1.1.1.1:7777/web' self.clnt._is_good_response = Mock() self.clnt._is_good_response.side_effect = CvpApiError('CvpApiError') self.assertIsNone(self.clnt.last_used_node) with self.assertRaises(CvpApiError): self.clnt._make_request('GET', 'url', 2, {'data': 'data'}) self.assertEqual(self.clnt.last_used_node, '1.1.1.1') def test_make_request_response_error_unauthorized(self): """ Test request exception raised if CVP responds unauthorized user. """ self.clnt.session = Mock() self.clnt.session.return_value = True self.clnt.session.get.return_value = Mock() self.clnt._create_session = Mock() self.clnt._reset_session = Mock() self.clnt.NUM_RETRY_REQUESTS = 2 self.clnt.connect_timeout = 2 self.clnt.node_cnt = 2 self.clnt.url_prefix = 'https://1.1.1.1:7777/web' self.clnt._is_good_response = Mock() self.clnt._is_good_response.side_effect = CvpApiError( msg='Unauthorized User') self.assertIsNone(self.clnt.last_used_node) with self.assertRaises(CvpApiError): self.clnt._make_request('GET', 'url', 2, {'data': 'data'}) self.assertEqual(self.clnt.last_used_node, '1.1.1.1') def test_make_request_response_error_logout(self): """ Test request exception raised if CVP logout error hit. """ self.clnt.session = Mock() self.clnt.session.return_value = True self.clnt.session.get.return_value = Mock() self.clnt._create_session = Mock() self.clnt._reset_session = Mock() self.clnt.NUM_RETRY_REQUESTS = 2 self.clnt.connect_timeout = 2 self.clnt.node_cnt = 2 self.clnt.url_prefix = 'https://1.1.1.1:7777/web' self.clnt._is_good_response = Mock() self.clnt._is_good_response.side_effect = CvpSessionLogOutError('bad') self.assertIsNone(self.clnt.last_used_node) with self.assertRaises(CvpSessionLogOutError): self.clnt._make_request('GET', 'url', 2, {'data': 'data'}) self.assertEqual(self.clnt.last_used_node, '1.1.1.1')
""" Use Arista provided script from https://github.com/arista-netdevops-community/eos-scripts TODO Migrate to CVP API when it supports it """ rc = os.system("python eos_download.py --api %s --ver %s" % (apikey, targetversion)) assert (rc == 0) assert (os.path.isfile(targetimage)) return True def precheck(): pass clnt = CvpClient() clnt.connect([os.environ['CVP_HOST']], 'cvpadmin', os.environ['CVP_PASS']) latestbundle = clnt.api.get_image_bundle_by_name('EOS-latest') # we extract the images in there and upgrade the EOS one EOS = list( filter(lambda x: x['imageFileName'].startswith('EOS'), latestbundle['images']))[0] notEOS = list( filter(lambda x: not x['imageFileName'].startswith('EOS'), latestbundle['images'])) print("currentlatest: ", EOS['name']) targetRelease = findTargetVersion(EOS['name'], extractReleases()) if not targetRelease:
def test_clnt_init_syslog(self): ''' Verify CvpClient init with syslog argument ''' clnt = CvpClient(syslog=True) self.assertIsNotNone(clnt)
_create_unverified_https_context = ssl._create_unverified_context except AttributeError: # Legacy Python that doesn't verify HTTPS certificates by default pass else: # Handle target environment that doesn't support HTTPS verification ssl._create_default_https_context = _create_unverified_https_context ssl._create_default_https_context = ssl._create_unverified_context import requests.packages.urllib3 requests.packages.urllib3.disable_warnings() cvp_username = CVPGlobalVariables.getValue(GlobalVariableNames.CVP_USERNAME) cvp_password = CVPGlobalVariables.getValue(GlobalVariableNames.CVP_PASSWORD) clnt = CvpClient() clnt.connect(['localhost'], cvp_username, cvp_password) configlet_name = "cvp_1_site_users_pwd_config" output = clnt.api.get_configlet_by_name(name = configlet_name) config = output["config"] key = output["key"] new_config = "" for line in config.splitlines(): if "secret" in line or "enable" in line: words = line.split() for x in range(len(words)): if words[x] == "secret" and words[x+1] != "sha512": words[x+1] = "sha512 " + crypt.crypt(words[x+1], "$6$saltsalt$")
from pprint import pprint from cvprac.cvp_client import CvpClient from cvprac.cvp_api import CvpApi import urllib3 import time urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning ) # This will disable invalid cert warnings client = CvpClient() client.connect(['cvp.lab.local'], 'jpatterson', 'P3pp3r101!') cvp = CvpApi(client) # test = cvp.get_cvp_info() # print test # # gettask = cvp.get_tasks() # pprint(gettask) '''Get inventory of CVP, then strip out FQDN of hostname and present just hostname:''' # host_list = [] # def hostname(filter=''): # inventory = cvp.get_inventory(query=filter) # full_fqdn = 'lab.local' # for value in inventory: # if full_fqdn in value['fqdn']: # fqdn_strip = value['fqdn'][0:-10] # host_list.append(fqdn_strip) # return host_list # # hostname()
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:'