def install_package(module, device): junos = SW(device) package = module.params["src"] no_copy = module.params["no_copy"] validate = module.params["validate"] force_host = module.params["force_host"] issu = module.params["issu"] def progress_log(dev, report): module.log(report) module.log("installing package") result = junos.install( package, progress=progress_log, no_copy=no_copy, validate=validate, force_host=force_host, issu=issu, ) if not result: module.fail_json(msg="Unable to install package on device") if module.params["reboot"]: module.log("rebooting system") junos.reboot()
def install_package(module, device): junos = SW(device) package = module.params['src'] no_copy = module.params['no_copy'] validate = module.params['validate'] force_host = module.params['force_host'] issu = module.params['issu'] def progress_log(dev, report): module.log(report) module.log('installing package') result = junos.install(package, progress=progress_log, no_copy=no_copy, validate=validate, force_host=force_host, issu=issu) if not result: module.fail_json(msg='Unable to install package on device') if module.params['reboot']: module.log('rebooting system') junos.reboot()
def InstallOnHost(hostname, username, password, softwareFilePath, rebootTime): dev = Device(host=hostname, user=username, password=password) softw = SW(dev) hash = SW.local_md5(softwareFilePath) softw.install(softwareFilePath, remote_path='/var/tmp', progress=dev, validate=False, checksum=hash, cleanfs=False, no_copy=False, timeout=1800) if rebootTime != 0: softw.reboot(rebootTime) dev.close()
def main(): dev = Device(host="192.168.65.61", user="******", passwd="lab123", normalize=True) dev.open() if dev.facts['junos_info']['re0']['text'] == TARGET_VERSION: print("Device OS version is already the target version") exit(1) fs = FS(dev) bytes_free = fs.storage_usage()['/dev/gpt/junos']['avail_block']*512 file_size = os.stat(IMAGE_FILE).st_size print("We have %d bytes free, image size is %d" % (bytes_free, file_size)) if bytes_free < file_size: print("Error: not enough space on device") exit(1) print("Copying image to the device...") with SCP(dev, progress=True) as scp: scp.put(IMAGE_FILE, remote_path=REMOTE_PATH) print("Installing package...") sw = SW(dev) install_result = sw.install(package=REMOTE_PATH+IMAGE_FILE, no_copy=True, validate=False, progress=True) if not install_result: print("Installation error, exiting") exit(1) print("Rebooting...") sw.reboot() for _ in range(20): print("Waiting for device reboot...") sleep(50) try: dev.open(auto_probe=10) ver = dev.facts['junos_info']['re0']['text'] except (ProbeError, ConnectError): continue dev.close() break else: print("The device did not complete reboot in time, please check.") exit(1) if ver == TARGET_VERSION: print("Reboot complete. Installation successful.") else: print("Reboot complete but something went wrong!") exit(1)
def install_package(module, device): junos = SW(device) package = module.params['src'] no_copy = module.params['no_copy'] progress_log = lambda x, y: module.log(y) module.log('installing package') result = junos.install(package, progress=progress_log, no_copy=no_copy) if not result: module.fail_json(msg='Unable to install package on device') if module.params['reboot']: module.log('rebooting system') junos.reboot()
def install_package(module, device): junos = SW(device) package = module.params['src'] no_copy = module.params['no_copy'] def progress_log(dev, report): module.log(report) module.log('installing package') result = junos.install(package, progress=progress_log, no_copy=no_copy) if not result: module.fail_json(msg='Unable to install package on device') if module.params['reboot']: module.log('rebooting system') junos.reboot()
def JunosSwUpgrade(): # initialize logging logging.basicConfig(filename=logfile, level=logging.INFO, format='%(asctime)s:%(name)s: %(message)s') logging.getLogger().name = hostName logging.getLogger().addHandler(logging.StreamHandler()) logging.info('Information logged in {0}'.format(logfile)) if no_copy == False: # verify package exists if not (os.path.isfile(package)): msg = 'Software package does not exist: {0}. '.format(package) logging.error(msg) print("Package not Exists error and exit with system exit") sys.exit() dev = Device(host=hostName, user=uName, password=uPass) try: dev.open() except ConnectError as err: logging.error('Cannot connect to device: {0}\n'.format(err)) print("Connection issue with the Target device") return # Create an instance of SW sw = SW(dev) try: logging.info('Starting the software upgrade process: {0}' \ .format(package)) print("Starting software upgrade process") ok = sw.install(package=package, remote_path=remote_path, progress=update_progress, validate=validate, no_copy=True, all_re=True) except Exception as err: msg = 'Unable to install software, {0}'.format(err) logging.error(msg) ok = False if ok is True: logging.info('Software installation complete. Rebooting') rsp = sw.reboot() logging.info('Upgrade pending reboot cycle, please be patient.') logging.info(rsp) else: msg = 'Unable to install software, {0}'.format(ok) logging.error(msg) # End the NETCONF session and close the connection dev.close()
def reboot(self): try: from jnpr.junos.utils.sw import SW sw = SW(self.device) print("Rebooting...") print(sw.reboot()) print("The system reboot successfully") except RpcError as err: print("Unable to reboot the system: {0}".format(err)) sys.exit(1)
def scrub(cls, set_data): """ Setups new routers. """ utils.colour_print(f'Generating JunOS setconf for router:') file_name = f'scrub.j2' setconf = jinja_env.get_template(file_name).render(**set_data) if cls.deploy(setconf=setconf, router_ip=set_data['router']['router_ip']): utils.colour_print('(colour_success)Successfully scrubbed router.(colour_clear)') utils.colour_print('Reboot required so rebooting the router..') with Device(host=set_data['router']['router_ip'], user='******') as router: sw = SW(router) sw.reboot(in_min=2) utils.colour_print('Rebooting the router...') else: utils.error('Failed to build router, please try again.') traceback.print_exc()
def reboot_device(ip_addr): dev = call_dev(ip_addr) try: dev.open(gather_facts=False) except Exception as err: return else: sw = SW(dev) rsp = sw.reboot() dev.close()
def main(): print("\nWelcome to Junos Upgrade Tool \n") # Request which code to upgrade with fileList = getFileList(code_path) package = getOptionAnswer("Choose a junos package", fileList) package = code_path + package # Request IP for the system to upgrade host = getInputAnswer("IP Address of the host") # Get username and password parameters username=getInputAnswer("\nEnter your device username") password=getpass(prompt="\nEnter your device password: ") # initialize logging logging.basicConfig(filename=logfile, level=logging.INFO, format='%(asctime)s:%(name)s: %(message)s') logging.getLogger().name = host sys.stdout.write('Information logged in {0}\n'.format(logfile)) # verify package exists if (os.path.isfile(package)): found = True else: msg = 'Software package does not exist: {0}. '.format(package) sys.exit(msg + '\nExiting program') dev = Device(host,user=username,password=password) try: dev.open() except Exception as err: sys.stderr.write('Cannot connect to device: {0}\n'.format(err)) return # Increase the default RPC timeout to accommodate install operations dev.timeout = 300 # Create an instance of SW sw = SW(dev) try: do_log('Starting the software upgrade process: {0}'.format(package)) ok = sw.install(package=package, remote_path=remote_path, progress=update_progress, validate=validate) except Exception as err: msg = 'Unable to install software, {0}'.format(err) do_log(msg, level='error') else: if ok is True: do_log('Software installation complete. Rebooting') rsp = sw.reboot() do_log('Upgrade pending reboot cycle, please be patient.') do_log(rsp) # End the NETCONF session and close the connection dev.close()
def main(): #iterate over csv for row in devList: #Make Device Connection dev = Device(host=row[1], user=userName, password=userPassword) try: #Print Opening Header for Status now1 = datetime.datetime.now() pprint("Work starts on " + row[0] + " | " + row[1] + " at " + now1.strftime("%Y-%m-%d %H:%M")) #Open Device with Custom Timer dev.open() dev.timeout = 900 except Exception as err: sys.stderr.write('Cannot connect to device: {0}\n'.format(err)) #Do RPC/Work try: #Start Work here #Create an instance of SW sw = SW(dev) try: ok = sw.install(package=package, remote_path=remote_path, progress=myprogress, validate=validate, no_copy=noCopy, timeout=1800) except Exception as err: msg = 'Unable to install software, {0}'.format(err) print(msg) ok = False if ok is True: print('Software installation complete. Rebooting') rsp = sw.reboot() print('Upgrade pending reboot cycle, please be patient.') print(rsp) else: msg = 'Unable to install software, {0}'.format(ok) print(msg) #Write Element Seperator print("+++++++++++++++++++++++++++++++++++++++++++++++++") #Close Device dev.close() except Exception as err: sys.stderr.write('Cannot perform RPC on device: ' + row[1] + '\n'.format(err)) print("+++++++++++++++++++++++++++++++++++++++++++++++++")
def main(): # initialize logging logging.basicConfig(filename="results.log", level=logging.DEBUG, format='%(asctime)s:%(levelname)s: %(message)s') dev = Device(host=hostname, user=junos_username, passwd=junos_password) # hard set parameters. # dev = Device(host="192.168.100.1", user="******", passwd="juniper123") try: dev.open() except ConnectError as err: sys.exit("Unfortunately the target device is unreachable. Check connection parameters.") type = (dev.facts["version"]) sw = SW(dev) if type == "18.4R3-S2": logging.info("Already on latest firmware.") print("Looks like your device is already on the latest firmware!.") elif type != "18.4R3-S2": print("Not on latest Junos version. Copying/installing latest Junos image to device. Please be patient.") try: logging.info('Starting the software upgrade process: {0}'.format(package_srx)) ok = sw.install(package=package_srx,remote_path=srx_local,validate=False,progress=update_progress) except Exception as err: msg = 'Unable to install software, {0}'.format(err) logging.error(msg) ok = False print("Unable to install software.") if ok == True: print("Software installation complete. Rebooting!") logging.info("Software installation complete. Rebooting!") rsp = sw.reboot() logging.info("Upgrade pending reboot cycle, please be patient.") logging.info(rsp) else: msg = 'Unable to install software, {0}'.format(ok) logging.error(msg) print("Unable to install software.") dev.close()
def reboot_router(hostname): ''' Reboot the routers ''' username = '******' password = '******' print(f"Rebooting hostname {hostname}") try: with Device(host=hostname, user=username, password=password, normalize=True) as dev: sw = SW(dev) print(sw.reboot()) except ConnectError as err: print(err) return False
def junos_auto_install(self, host_ip, path, device): """ Use PyEz to secure install new junos version to remote host """ sw = SW(device) path = os.path.join(os.getcwd(), path) print path, type(path) try: ok = sw.install(package=path, progress=install_progress) except Exception as err: print("Install error") raise err if ok is True: print("\nSoftware installation succeeded") else: print(ok) time.sleep(30) try: rsp = sw.reboot() print(rsp) except exception.ConnectClosedError: print("About to loose connection ..") finally: print("Please wait for the box to wake-up!") time.sleep(120) dev = self.device_connect(host_ip) feeds = dev.probe(10) while not feeds: feeds = dev.probe(20) #print("probing in 20 seconds interval") print("\n\nConnecting to box now ...") dev.open() print("Connected") print("New version:") self.print_base_info(dev) return dev
from jnpr.junos import Device from jnpr.junos.utils.sw import SW dev = Device(host='xxxx', user='******', password='******', gather_facts=False) dev.open() def update_progress(dev, report): print dev.hostname, '> ', report sw = SW(dev) ok = sw.install(package=r'/Users/nitinkr/Downloads/jinstall-1x.1xxxx.tgz', progress=update_progress) # progress takes boolean values too from 1.2.3 version onwards #ok = sw.install(package=r'/Users/nitinkr/Downloads/jinstall-1x.1xxxx.tgz', progress=True) if ok: print 'rebooting' sw.reboot()
class TestSW(unittest.TestCase): @patch('ncclient.manager.connect') def setUp(self, mock_connect): mock_connect.side_effect = self._mock_manager self.dev = Device(host='1.1.1.1', user='******', password='******', gather_facts=False) self.dev.open() self.dev.facts = facts self.sw = self.get_sw() @patch('jnpr.junos.Device.execute') def get_sw(self, mock_execute): mock_execute.side_effect = self._mock_manager return SW(self.dev) @patch('ncclient.operations.session.CloseSession.request') def tearDown(self, mock_session): self.dev.close() def test_sw_hashfile(self): with patch(builtin_string + '.open', mock_open(), create=True): import jnpr.junos.utils.sw with open('foo') as h: h.read.side_effect = ('abc', 'a', '') jnpr.junos.utils.sw._hashfile(h, MagicMock()) self.assertEqual(h.read.call_count, 3) @patch('jnpr.junos.Device.execute') def test_sw_constructor_multi_re(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw = SW(self.dev) self.assertTrue(self.sw._multi_RE) @patch('jnpr.junos.Device.execute') def test_sw_constructor_multi_vc(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw = SW(self.dev) self.assertFalse(self.sw._multi_VC) @patch(builtin_string + '.open') def test_sw_local_sha256(self, mock_built_open): package = 'test.tgz' self.assertEqual(SW.local_checksum(package, algorithm='sha256'), 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934' 'ca495991b7852b855') @patch(builtin_string + '.open') def test_sw_local_md5(self, mock_built_open): package = 'test.tgz' self.assertEqual(self.sw.local_checksum(package, algorithm='md5'), 'd41d8cd98f00b204e9800998ecf8427e') @patch(builtin_string + '.open') def test_sw_local_sha1(self, mock_built_open): package = 'test.tgz' self.assertEqual(SW.local_checksum(package, algorithm='sha1'), 'da39a3ee5e6b4b0d3255bfef95601890afd80709') def test_sw_local_checksum_unknown_alg(self): self.assertRaises(ValueError, SW.local_checksum, 'foo.tgz', algorithm='foo') def test_sw_progress(self): with self.capture(SW.progress, self.dev, 'running') as output: self.assertEqual('1.1.1.1: running\n', output) @patch('jnpr.junos.Device.execute') @patch('paramiko.SSHClient') @patch('scp.SCPClient.put') def test_sw_progress_true(self, scp_put, mock_paramiko, mock_execute): mock_execute.side_effect = self._mock_manager with self.capture(SW.progress, self.dev, 'testing') as output: self.sw.install('test.tgz', progress=True, checksum=345, cleanfs=False) self.assertEqual('1.1.1.1: testing\n', output) @patch('paramiko.SSHClient') @patch('scp.SCPClient.put') def test_sw_put(self, mock_scp_put, mock_scp): package = 'test.tgz' self.sw.put(package) self.assertTrue( call( 'test.tgz', '/var/tmp') in mock_scp_put.mock_calls) @patch('jnpr.junos.utils.sw.FTP') def test_sw_put_ftp(self, mock_ftp_put): dev = Device(host='1.1.1.1', user='******', password='******', mode='telnet', port=23, gather_facts=False) sw = SW(dev) sw.put(package='test.tgz') self.assertTrue( call( 'test.tgz', '/var/tmp') in mock_ftp_put.mock_calls) @patch('jnpr.junos.utils.scp.SCP.__exit__') @patch('jnpr.junos.utils.scp.SCP.__init__') @patch('jnpr.junos.utils.scp.SCP.__enter__') def test_sw_put_progress(self, mock_enter, mock_scp, mock_exit): package = 'test.tgz' mock_scp.side_effect = self._fake_scp with self.capture(self.sw.put, package, progress=self._my_scp_progress) as output: self.assertEqual('test.tgz 100 50\n', output) def _fake_scp(self, *args, **kwargs): progress = kwargs['progress'] progress('test.tgz', 100, 50) @patch('jnpr.junos.Device.execute') def test_sw_pkgadd(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'test.tgz' self.assertTrue(self.sw.pkgadd(package)) @patch('jnpr.junos.Device.execute') def test_sw_install_single_re(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_RE = False self.assertTrue(self.sw.install('test.tgz', no_copy=True)) @patch('jnpr.junos.Device.execute') def test_sw_install_issu(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'test.tgz' self.assertTrue(self.sw.install(package, issu=True, no_copy=True)) @patch('jnpr.junos.Device.execute') def test_sw_install_nssu(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'test.tgz' self.assertTrue(self.sw.install(package, nssu=True, no_copy=True)) @patch('jnpr.junos.Device.execute') def test_sw_install_issu_nssu_both_error(self, mock_execute): mock_execute.side_effect = self._mock_manager try: self.sw.install('test.tgz', issu=True, nssu=True) except TypeError as ex: self.assertEqual( str(ex), 'install function can either take issu or nssu not both') @patch('jnpr.junos.Device.execute') def test_sw_install_issu_single_re_error(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_RE = False try: self.sw.install('test.tgz', issu=True) except TypeError as ex: self.assertEqual(str(ex), 'ISSU/NSSU requires Multi RE setup') @patch('jnpr.junos.Device.execute') def test_sw_install_issu_nssu_single_re_error(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'test.tgz' self.sw._multi_RE = False self.assertRaises(TypeError, self.sw.install, package, nssu=True, issu=True) @patch('jnpr.junos.Device.execute') def test_sw_pkgaddISSU(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'test.tgz' self.assertTrue(self.sw.pkgaddISSU(package)) @patch('jnpr.junos.Device.execute') def test_sw_pkgaddNSSU(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'test.tgz' self.assertTrue(self.sw.pkgaddNSSU(package)) @patch('jnpr.junos.Device.execute') def test_sw_pkgadd_pkg_set(self, mock_execute): mock_execute.side_effect = self._mock_manager pkg_set = ['abc.tgz', 'pqr.tgz'] self.sw._mixed_VC = True self.sw.pkgadd(pkg_set) self.assertEqual([i.text for i in mock_execute.call_args[0][0].findall('set')], pkg_set) @patch('jnpr.junos.Device.execute') def test_sw_validate(self, mock_execute): mock_execute.side_effect = self._mock_manager self.assertTrue(self.sw.validate('package.tgz')) @patch('jnpr.junos.Device.execute') def test_sw_validate_nssu(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw.log = MagicMock() # get_config returns false self.assertFalse(self.sw.validate('package.tgz', nssu=True)) self.sw.log.assert_called_with( 'Requirement FAILED: GRES is not Enabled in configuration') @patch('jnpr.junos.Device.execute') def test_sw_validate_issu(self, mock_execute): mock_execute.side_effect = self._mock_manager self.dev.rpc.get_config = MagicMock() self.assertTrue(self.sw.validate('package.tgz', issu=True)) @patch('jnpr.junos.Device.execute') def test_sw_val_issu_request_shell_execute_gres_on(self, mock_execute): mock_execute.side_effect = self._mock_manager self.dev.rpc.get_config = MagicMock() self.dev.rpc.request_shell_execute = MagicMock() self.dev.rpc.request_shell_execute.return_value = etree.fromstring( """<rpc-reply> <output>Graceful switchover: On</output> </rpc-reply>""") self.assertTrue(self.sw.validate('package.tgz', issu=True)) @patch('jnpr.junos.Device.execute') def test_sw_validate_issu_2re_false(self, mock_execute): mock_execute.side_effect = self._mock_manager self.dev.facts['2RE'] = False self.assertFalse(self.sw.validate('package.tgz', issu=True)) self.dev.facts['2RE'] = True @patch('paramiko.SSHClient') @patch('jnpr.junos.utils.start_shell.StartShell.wait_for') def test_sw_validate_issu_request_shell_execute(self, mock_ss, mock_ssh): self._issu_test_helper() with patch('jnpr.junos.utils.start_shell.StartShell.run') as ss: ss.return_value = (True, 'Graceful switchover: On') self.assertTrue(self.sw.validate('package.tgz', issu=True)) @patch('paramiko.SSHClient') @patch('jnpr.junos.utils.start_shell.StartShell.wait_for') def test_sw_validate_issu_ss_login_other_re_fail(self, mock_ss, mock_ssh): self._issu_test_helper() with patch('jnpr.junos.utils.start_shell.StartShell.run') as ss: ss.return_value = (False, 'Graceful switchover: On') self.assertFalse(self.sw.validate('package.tgz', issu=True)) self.sw.log.assert_called_with( 'Requirement FAILED: Not able run "show system switchover"') @patch('paramiko.SSHClient') @patch('jnpr.junos.utils.start_shell.StartShell.wait_for') def test_sw_validate_issu_ss_graceful_off(self, mock_ss, mock_ssh): self._issu_test_helper() with patch('jnpr.junos.utils.start_shell.StartShell.run') as ss: ss.return_value = (True, 'Graceful switchover: Off') self.assertFalse(self.sw.validate('package.tgz', issu=True)) self.sw.log.assert_called_with( 'Requirement FAILED: Graceful switchover status is not On') def _issu_test_helper(self): self.sw.log = MagicMock() self.dev.rpc.request_shell_execute = MagicMock() self.dev.rpc = MagicMock() self.dev.rpc.get_routing_task_replication_state.return_value = \ self._read_file('get-routing-task-replication-state.xml') self.dev.rpc.check_in_service_upgrade.return_value = \ self._read_file('check-in-service-upgrade.xml') self.dev.rpc.request_shell_execute.side_effect = \ RpcError(rsp='not ok') @patch('jnpr.junos.Device.execute') def test_sw_validate_issu_stateful_replication_off(self, mock_execute): mock_execute.side_effect = self._mock_manager self.dev.rpc.get_config = MagicMock() self.dev.rpc.get_routing_task_replication_state = MagicMock() self.sw.log = MagicMock() self.assertFalse(self.sw.validate('package.tgz', issu=True)) self.sw.log.assert_called_with( 'Requirement FAILED: Either Stateful Replication is not Enabled or RE mode\nis not Master') @patch('jnpr.junos.Device.execute') def test_sw_validate_issu_commit_sync_off(self, mock_execute): mock_execute.side_effect = self._mock_manager self.dev.rpc.get_config = MagicMock() self.dev.rpc.get_config.return_value = etree.fromstring(""" <configuration> <chassis> <redundancy> <graceful-switchover> </graceful-switchover> </redundancy> </chassis> </configuration>""") self.sw.log = MagicMock() self.assertFalse(self.sw.validate('package.tgz', issu=True)) self.sw.log.assert_called_with( 'Requirement FAILED: commit synchronize is not Enabled in configuration') @patch('jnpr.junos.Device.execute') def test_sw_validate_issu_nonstop_routing_off(self, mock_execute): mock_execute.side_effect = self._mock_manager self.dev.rpc.get_config = MagicMock() self.dev.rpc.get_config.side_effect = iter([etree.fromstring(""" <configuration> <chassis> <redundancy> <graceful-switchover> </graceful-switchover> </redundancy> </chassis> </configuration>"""), etree.fromstring(""" <configuration> <system> <commit> <synchronize/> </commit> </system> </configuration>"""), etree.fromstring("""<configuration> <routing-options></routing-options> </configuration>""")]) self.sw.log = MagicMock() self.assertFalse(self.sw.validate('package.tgz', issu=True)) self.sw.log.assert_called_with( 'Requirement FAILED: NSR is not Enabled in configuration') @patch('jnpr.junos.Device.execute') def test_sw_validate_issu_validation_succeeded(self, mock_execute): rpc_reply = """<rpc-reply><output>mgd: commit complete Validation succeeded </output> <package-result>1</package-result> </rpc-reply>""" mock_execute.side_effect = etree.fromstring(rpc_reply) package = 'package.tgz' self.assertFalse(self.sw.validate(package, issu=True)) @patch('jnpr.junos.Device.execute') def test_sw_remote_checksum_not_found(self, mock_execute): xml = '''<rpc-error> <error-severity>error</error-severity> <error-message> md5: /var/tmp/123: No such file or directory </error-message> </rpc-error>''' mock_execute.side_effect = RpcError(rsp=etree.fromstring(xml)) package = 'test.tgz' self.assertEqual(self.sw.remote_checksum(package), None) @patch('jnpr.junos.Device.execute') def test_sw_remote_checksum_not_rpc_error(self, mock_execute): xml = '''<rpc-error> <error-severity>error</error-severity> <error-message> something else! </error-message> </rpc-error>''' mock_execute.side_effect = RpcError(rsp=etree.fromstring(xml)) package = 'test.tgz' with self.assertRaises(RpcError): self.sw.remote_checksum(package) @patch('jnpr.junos.Device.execute') def test_sw_remote_checksum_md5(self, mock_execute): xml = '''<rpc-reply> <checksum-information> <file-checksum> <computation-method>MD5</computation-method> <input-file>/var/tmp/foo.tgz</input-file> <checksum>8a04cfc475e21507be5145bc0e82ce09</checksum> </file-checksum> </checksum-information> </rpc-reply>''' mock_execute.side_effect = etree.fromstring(xml) package = 'foo.tgz' self.assertEqual(self.sw.remote_checksum(package), '8a04cfc475e21507be5145bc0e82ce09') @patch('jnpr.junos.Device.execute') def test_sw_remote_checksum_sha1(self, mock_execute): xml = '''<rpc-reply> <checksum-information> <file-checksum> <computation-method>SHA1</computation-method> <input-file>/var/tmp/foo.tgz</input-file> <checksum>33c12913e81599452270ee849511e2e7578db00c</checksum> </file-checksum> </checksum-information> </rpc-reply>''' mock_execute.side_effect = etree.fromstring(xml) package = 'foo.tgz' self.assertEqual(self.sw.remote_checksum(package, algorithm='sha1'), '33c12913e81599452270ee849511e2e7578db00c') @patch('jnpr.junos.Device.execute') def test_sw_remote_checksum_sha256(self, mock_execute): xml = '''<rpc-reply> <checksum-information> <file-checksum> <computation-method>SHA256</computation-method> <input-file>/var/tmp/foo.tgz</input-file> <checksum>27bccf64babe4ea6687d3461e6d724d165aa140933e77b582af615dad4f02170</checksum> </file-checksum> </checksum-information> </rpc-reply>''' mock_execute.side_effect = etree.fromstring(xml) package = 'foo.tgz' self.assertEqual(self.sw.remote_checksum(package, algorithm='sha256'), '27bccf64babe4ea6687d3461e6d724d165aa140933e77b582af615dad4f02170') @patch('jnpr.junos.Device.execute') def test_sw_safe_copy(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'safecopy.tgz' self.sw.put = MagicMock() with patch('jnpr.junos.utils.sw.SW.local_md5'): self.assertTrue(self.sw.safe_copy(package, progress=self._myprogress, cleanfs=True, checksum='96a35ab371e1ca10408c3caecdbd8a67')) @patch('jnpr.junos.Device.execute') @patch('jnpr.junos.utils.sw.SW.local_checksum') def test_sw_safe_copy_missing_local_file(self, mock_checksum, mock_execute): mock_execute.side_effect = self._mock_manager mock_checksum.side_effect = IOError() package = 'foo.tgz' self.assertFalse(self.sw.safe_copy(package, progress=self._myprogress, cleanfs=True)) @patch('jnpr.junos.Device.execute') def test_sw_safe_copy_cleanfs_fail(self, mock_execute): mock_execute.side_effect = RpcError() package = 'foo.tgz' self.assertFalse(self.sw.safe_copy(package, progress=self._myprogress, cleanfs=True, checksum='96a35ab371e1ca10408c3caecdbd8a67')) @patch('jnpr.junos.Device.execute') def test_sw_safe_copy_return_false(self, mock_execute): # not passing checksum value, will get random from magicmock mock_execute.side_effect = self._mock_manager package = 'safecopy.tgz' self.sw.put = MagicMock() with patch('jnpr.junos.utils.sw.SW.local_md5'): self.assertFalse(self.sw.safe_copy(package, progress=self._myprogress, cleanfs=True)) @patch('jnpr.junos.Device.execute') def test_sw_safe_copy_checksum_none(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'safecopy.tgz' self.sw.put = MagicMock() with patch('jnpr.junos.utils.sw.SW.local_md5', MagicMock(return_value='96a35ab371e1ca10408c3caecdbd8a67')): self.assertTrue(self.sw.safe_copy(package, progress=self._myprogress, cleanfs=True)) @patch('jnpr.junos.Device.execute') def test_sw_safe_install(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'install.tgz' self.sw.put = MagicMock() with patch('jnpr.junos.utils.sw.SW.local_md5', MagicMock(return_value='96a35ab371e1ca10408c3caecdbd8a67')): self.assertTrue( self.sw.install( package, progress=self._myprogress, cleanfs=True)) @patch('jnpr.junos.utils.sw.SW.safe_copy') def test_sw_safe_install_copy_fail(self, mock_copy): mock_copy.return_value = False self.assertFalse(self.sw.install('file')) @patch('jnpr.junos.utils.sw.SW.validate') def test_sw_install_validate(self, mock_validate): mock_validate.return_value = False self.assertFalse(self.sw.install('file', validate=True, no_copy=True)) @patch(builtin_string + '.print') @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_multi_mx(self, mock_pkgadd, mock_print): mock_pkgadd.return_value = True self.sw._multi_RE = True self.sw._multi_MX = True self.assertTrue(self.sw.install('file', no_copy=True, progress=True)) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_multi_vc(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._multi_RE = True self.sw._multi_VC = True self.sw._RE_list = ('version_RE0', 'version_RE1') self.assertTrue(self.sw.install('file', no_copy=True)) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_mixed_vc(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._mixed_VC = True self.sw._RE_list = ('version_RE0', 'version_RE1') self.assertTrue(self.sw.install(pkg_set=['abc.tgz', 'pqr.tgz'], no_copy=True)) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_multi_vc_mode_disabled(self, mock_pkgadd): mock_pkgadd.return_value = True self.dev._facts = {'2RE': True, 'domain': None, 'RE1': { 'status': 'OK', 'model': 'RE-EX8208', 'mastership_state': 'backup'}, 'ifd_style': 'SWITCH', 'version_RE1': '12.3R7.7', 'version_RE0': '12.3', 'serialnumber': 'XXXXXX', 'fqdn': 'XXXXXX', 'RE0': {'status': 'OK', 'model': 'RE-EX8208', 'mastership_state': 'master'}, 'switch_style': 'VLAN', 'version': '12.3R5-S3.1', 'master': 'RE0', 'hostname': 'XXXXXX', 'HOME': '/var/home/sn', 'vc_mode': 'Disabled', 'model': 'EX8208', 'vc_capable': True, 'personality': 'SWITCH'} sw = self.get_sw() sw.install(package='abc.tgz', no_copy=True) self.assertFalse(sw._multi_VC) calls = [call('/var/tmp/abc.tgz', dev_timeout=1800, re0=True), call('/var/tmp/abc.tgz', dev_timeout=1800, re1=True)] mock_pkgadd.assert_has_calls(calls) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_mixed_vc_with_copy(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._mixed_VC = True self.sw.put = MagicMock() self.sw.remote_checksum = MagicMock( return_value='d41d8cd98f00b204e9800998ecf8427e') self.sw._RE_list = ('version_RE0', 'version_RE1') with patch('jnpr.junos.utils.sw.SW.local_md5', MagicMock(return_value='d41d8cd98f00b204e9800998ecf8427e')): self.assertTrue( self.sw.install( pkg_set=[ 'install.tgz', 'install.tgz'], cleanfs=False)) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_mixed_vc_safe_copy_false(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._mixed_VC = True self.sw.safe_copy = MagicMock(return_value=False) self.sw.remote_checksum = MagicMock( return_value='d41d8cd98f00b204e9800998ecf8427e') self.sw._RE_list = ('version_RE0', 'version_RE1') with patch('jnpr.junos.utils.sw.SW.local_md5', MagicMock(return_value='d41d8cd98f00b204e9800998ecf8427e')): self.assertFalse( self.sw.install( pkg_set=[ 'install.tgz', 'install.tgz'], cleanfs=False)) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_mixed_vc_ValueError(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._mixed_VC = True self.sw.remote_checksum = MagicMock( return_value='d41d8cd98f00b204e9800998ecf8427e') self.sw._RE_list = ('version_RE0', 'version_RE1') with patch('jnpr.junos.utils.sw.SW.local_md5', MagicMock(return_value='d41d8cd98f00b204e9800998ecf8427e')): self.assertRaises( ValueError, self.sw.install, pkg_set='install.tgz', cleanfs=False) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_mixed_vc_TypeError(self, mock_pkgadd): self.assertRaises(TypeError, self.sw.install, cleanfs=False) @patch('jnpr.junos.Device.execute') def test_sw_install_kwargs_force_host(self, mock_execute): self.sw.install('file', no_copy=True, force_host=True) rpc = [ '<request-package-add><force-host/><no-validate/><re1/><package-name>/var/tmp/file</package-name></request-package-add>', '<request-package-add><package-name>/var/tmp/file</package-name><no-validate/><force-host/><re1/></request-package-add>', '<request-package-add><package-name>/var/tmp/file</package-name><no-validate/><re1/><force-host/></request-package-add>', '<request-package-add><force-host/><no-validate/><package-name>/var/tmp/file</package-name><re1/></request-package-add>', '<request-package-add><force-host/><re1/><no-validate/><package-name>/var/tmp/file</package-name></request-package-add>', '<request-package-add><no-validate/><re1/><package-name>/var/tmp/file</package-name><force-host/></request-package-add>', '<request-package-add><no-validate/><package-name>/var/tmp/file</package-name><force-host/><re1/></request-package-add>', '<request-package-add><force-host/><package-name>/var/tmp/file</package-name><no-validate/><re1/></request-package-add>', '<request-package-add><re1/><no-validate/><package-name>/var/tmp/file</package-name><force-host/></request-package-add>', '<request-package-add><re1/><force-host/><package-name>/var/tmp/file</package-name><no-validate/></request-package-add>', '<request-package-add><re1/><package-name>/var/tmp/file</package-name><force-host/><no-validate/></request-package-add>', '<request-package-add><re1/><force-host/><no-validate/><package-name>/var/tmp/file</package-name></request-package-add>', '<request-package-add><no-validate/><force-host/><re1/><package-name>/var/tmp/file</package-name></request-package-add>', '<request-package-add><package-name>/var/tmp/file</package-name><force-host/><no-validate/><re1/></request-package-add>', '<request-package-add><no-validate/><re1/><force-host/><package-name>/var/tmp/file</package-name></request-package-add>', '<request-package-add><package-name>/var/tmp/file</package-name><force-host/><re1/><no-validate/></request-package-add>', '<request-package-add><no-validate/><force-host/><package-name>/var/tmp/file</package-name><re1/></request-package-add>', '<request-package-add><force-host/><no-validate/><package-name>/var/tmp/file</package-name></request-package-add>', '<request-package-add><force-host/><package-name>/var/tmp/file</package-name><no-validate/></request-package-add>', '<request-package-add><package-name>/var/tmp/file</package-name><no-validate/><force-host/></request-package-add>', '<request-package-add><no-validate/><force-host/><package-name>/var/tmp/file</package-name></request-package-add>', '<request-package-add><no-validate/><package-name>/var/tmp/file</package-name><force-host/></request-package-add>', '<request-package-add><package-name>/var/tmp/file</package-name><force-host/><no-validate/></request-package-add>', '<request-package-add><package-name>/var/tmp/file</package-name><re1/><no-validate/><force-host/></request-package-add>', '<request-package-add><package-name>/var/tmp/file</package-name><re1/><force-host/><no-validate/></request-package-add>', '<request-package-add><force-host/><package-name>/var/tmp/file</package-name><re1/><no-validate/></request-package-add>', '<request-package-add><re1/><package-name>/var/tmp/file</package-name><no-validate/><force-host/></request-package-add>', '<request-package-add><no-validate/><package-name>/var/tmp/file</package-name><re1/><force-host/></request-package-add>', '<request-package-add><re1/><no-validate/><force-host/><package-name>/var/tmp/file</package-name></request-package-add>', '<request-package-add><force-host/><re1/><package-name>/var/tmp/file</package-name><no-validate/></request-package-add>'] self.assertTrue(etree.tostring( mock_execute.call_args[0][0]).decode('utf-8') in rpc) @patch('jnpr.junos.Device.execute') def test_sw_rollback(self, mock_execute): rsp = '<rpc-reply><output>junos-vsrx-12.1X46-D30.2-domestic will become active at next reboot</output></rpc-reply>' mock_execute.side_effect = etree.XML(rsp) msg = 'junos-vsrx-12.1X46-D30.2-domestic will become active at next reboot' self.assertEqual(self.sw.rollback(), msg) @patch('jnpr.junos.Device.execute') def test_sw_rollback_multi(self, mock_execute): mock_execute.side_effect = self._mock_manager msg = {'fpc1': "Junos version 'D10.2' will become active at next reboot", 'fpc0': 'JUNOS version "D10.2" will become active at next reboot'} self.assertEqual(eval(self.sw.rollback()), msg) @patch('jnpr.junos.Device.execute') def test_sw_rollback_multi_exception(self, mock_execute): fname = 'request-package-rollback-multi-error.xml' mock_execute.side_effect = self._read_file(fname) self.assertRaises(SwRollbackError, self.sw.rollback) @patch('jnpr.junos.Device.execute') def test_sw_rollback_exception(self, mock_execute): rsp = '<rpc-reply><output>WARNING: Cannot rollback, /packages/junos.old is not valid</output></rpc-reply>' mock_execute.side_effect = etree.XML(rsp) self.assertRaises(SwRollbackError, self.sw.rollback) def test_sw_inventory(self): self.sw.dev.rpc.file_list = \ MagicMock(side_effect=self._mock_manager) self.assertEqual( self.sw.inventory, { 'current': None, 'rollback': None}) @patch('jnpr.junos.Device.execute') def test_sw_reboot(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_MX = True self.assertTrue('Shutdown NOW' in self.sw.reboot()) @patch('jnpr.junos.Device.execute') def test_sw_reboot_at(self, mock_execute): mock_execute.side_effect = self._mock_manager self.assertTrue('Shutdown at' in self.sw.reboot(at='201407091815')) @patch('jnpr.junos.Device.execute') def test_sw_reboot_multi_re_vc(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_RE = True self.sw._multi_VC = False self.assertTrue('Shutdown NOW' in self.sw.reboot()) @patch('jnpr.junos.Device.execute') def test_sw_reboot_mixed_vc(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._mixed_VC = True self.sw._multi_VC = True self.sw.reboot() self.assertTrue('all-members' in (etree.tostring(mock_execute.call_args[0][0]).decode('utf-8'))) @patch('jnpr.junos.Device.execute') def test_sw_reboot_mixed_vc_all_re_false(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._mixed_VC = True self.sw._multi_VC = True self.sw.reboot(all_re=False) self.assertTrue('all-members' not in (etree.tostring(mock_execute.call_args[0][0]).decode('utf-8'))) @patch('jnpr.junos.Device.execute') def test_sw_reboot_exception(self, mock_execute): rsp = etree.XML('<rpc-reply><a>test</a></rpc-reply>') mock_execute.side_effect = RpcError(rsp=rsp) self.assertRaises(Exception, self.sw.reboot) @patch('jnpr.junos.Device.execute') def test_sw_reboot_exception_RpcTimeoutError(self, mock_execute): rsp = (self.dev, 'request-reboot', 60) mock_execute.side_effect = RpcTimeoutError(*rsp) self.assertRaises(Exception, self.sw.reboot) @patch('jnpr.junos.Device.execute') def test_sw_poweroff(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_MX = True self.assertTrue('Shutdown NOW' in self.sw.poweroff()) @patch('jnpr.junos.Device.execute') def test_sw_poweroff_exception(self, mock_execute): rsp = etree.XML('<rpc-reply><a>test</a></rpc-reply>') mock_execute.side_effect = RpcError(rsp=rsp) self.assertRaises(Exception, self.sw.poweroff) @patch('jnpr.junos.Device.execute') def test_sw_poweroff_multi_re_vc(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_RE = True self.sw._multi_VC = False self.assertTrue('Shutdown NOW' in self.sw.poweroff()) def _myprogress(self, dev, report): pass def _my_scp_progress(self, _path, _total, _xfrd): print (_path, _total, _xfrd) @contextmanager def capture(self, command, *args, **kwargs): out, sys.stdout = sys.stdout, StringIO() command(*args, **kwargs) sys.stdout.seek(0) yield sys.stdout.read() sys.stdout = out def _read_file(self, fname): from ncclient.xml_ import NCElement fpath = os.path.join(os.path.dirname(__file__), 'rpc-reply', fname) foo = open(fpath).read() rpc_reply = NCElement( foo, self.dev._conn._device_handler.transform_reply())._NCElement__doc[0] return rpc_reply def _mock_manager(self, *args, **kwargs): if kwargs: # Little hack for mocked execute if 'dev_timeout' in kwargs: return self._read_file(args[0].tag + '.xml') if 'path' in kwargs: if kwargs['path'] == '/packages': return self._read_file('file-list_dir.xml') device_params = kwargs['device_params'] device_handler = make_device_handler(device_params) session = SSHSession(device_handler) return Manager(session, device_handler) elif args: if args[0].find('at') is not None: return self._read_file('request-reboot-at.xml') else: return self._read_file(args[0].tag + '.xml')
from jnpr.junos import Device from jnpr.junos.utils.sw import SW USER = "******" PASSWD = "lab123" DEVICE_IP = "10.254.0.41" def update_progress(dev, report): print(report) dev = Device(host=DEVICE_IP, user=USER, password=PASSWD) dev.open() sw = SW(dev) ok = sw.install(package="/var/tmp/junos-vmx-x86-64-17.1R2.7.tgz", no_copy=True, progress=update_progress, validate=False) print(ok) sw.reboot()
class JunosDevice(BaseDevice): """Juniper JunOS Device Implementation.""" vendor = "juniper" def __init__(self, host, username, password, *args, **kwargs): super().__init__(host, username, password, *args, device_type="juniper_junos_netconf", **kwargs) self.native = JunosNativeDevice(*args, host=host, user=username, passwd=password, **kwargs) self.open() self.cu = JunosNativeConfig(self.native) self.fs = JunosNativeFS(self.native) self.sw = JunosNativeSW(self.native) def _file_copy_local_file_exists(self, filepath): return os.path.isfile(filepath) def _file_copy_local_md5(self, filepath, blocksize=2**20): if self._file_copy_local_file_exists(filepath): m = hashlib.md5() # nosec with open(filepath, "rb") as f: buf = f.read(blocksize) while buf: m.update(buf) buf = f.read(blocksize) return m.hexdigest() def _file_copy_remote_md5(self, filename): return self.fs.checksum(filename) def _get_interfaces(self): eth_ifaces = EthPortTable(self.native) eth_ifaces.get() loop_ifaces = LoopbackTable(self.native) loop_ifaces.get() ifaces = eth_ifaces.keys() ifaces.extend(loop_ifaces.keys()) return ifaces def _image_booted(self, image_name, **vendor_specifics): raise NotImplementedError def _uptime_components(self, uptime_full_string): match_days = re.search(r"(\d+) days?", uptime_full_string) match_hours = re.search(r"(\d+) hours?", uptime_full_string) match_minutes = re.search(r"(\d+) minutes?", uptime_full_string) match_seconds = re.search(r"(\d+) seconds?", uptime_full_string) days = int(match_days.group(1)) if match_days else 0 hours = int(match_hours.group(1)) if match_hours else 0 minutes = int(match_minutes.group(1)) if match_minutes else 0 seconds = int(match_seconds.group(1)) if match_seconds else 0 return days, hours, minutes, seconds def _uptime_to_seconds(self, uptime_full_string): days, hours, minutes, seconds = self._uptime_components( uptime_full_string) seconds += days * 24 * 60 * 60 seconds += hours * 60 * 60 seconds += minutes * 60 return seconds def _uptime_to_string(self, uptime_full_string): days, hours, minutes, seconds = self._uptime_components( uptime_full_string) return "%02d:%02d:%02d:%02d" % (days, hours, minutes, seconds) def _wait_for_device_reboot(self, timeout=3600): start = time.time() while time.time() - start < timeout: try: self.open() return except: # noqa E722 # nosec pass raise RebootTimeoutError(hostname=self.hostname, wait_time=timeout) def backup_running_config(self, filename): with open(filename, "w") as f: f.write(self.running_config) @property def boot_options(self): return self.os_version def checkpoint(self, filename): self.save(filename) def close(self): if self.connected: self.native.close() def config(self, commands, format="set"): """Send configuration commands to a device. Args: commands (str, list): String with single command, or list with multiple commands. Raises: ConfigLoadError: Issue with loading the command. CommandError: Issue with the command provided, if its a single command, passed in as a string. CommandListError: Issue with a command in the list provided. """ if isinstance(commands, str): try: self.cu.load(commands, format=format) self.cu.commit() except ConfigLoadError as e: raise CommandError(commands, e.message) else: try: for command in commands: self.cu.load(command, format=format) self.cu.commit() except ConfigLoadError as e: raise CommandListError(commands, command, e.message) def config_list(self, commands, format="set"): """Send configuration commands in list format to a device. DEPRECATED - Use the `config` method. Args: commands (list): List with multiple commands. """ warnings.warn("config_list() is deprecated; use config().", DeprecationWarning) self.config(commands, format=format) @property def connected(self): return self.native.connected @property def uptime(self): try: native_uptime_string = self.native.facts["RE0"]["up_time"] except (AttributeError, TypeError): native_uptime_string = None if self._uptime is None: if native_uptime_string is not None: self._uptime = self._uptime_to_seconds(native_uptime_string) return self._uptime @property def uptime_string(self): try: native_uptime_string = self.native.facts["RE0"]["up_time"] except (AttributeError, TypeError): native_uptime_string = None if self._uptime_string is None: self._uptime_string = self._uptime_to_string(native_uptime_string) return self._uptime_string @property def hostname(self): if self._hostname is None: self._hostname = self.native.facts.get("hostname") return self._hostname @property def interfaces(self): if self._interfaces is None: self._interfaces = self._get_interfaces() return self._interfaces @property def fqdn(self): if self._fqdn is None: self._fqdn = self.native.facts.get("fqdn") return self._fqdn @property def model(self): if self._model is None: self._model = self.native.facts.get("model") return self._model @property def os_version(self): if self._os_version is None: self._os_version = self.native.facts.get("version") return self._os_version @property def serial_number(self): if self._serial_number is None: self._serial_number = self.native.facts.get("serialnumber") return self._serial_number def file_copy(self, src, dest=None, **kwargs): if not self.file_copy_remote_exists(src, dest, **kwargs): if dest is None: dest = os.path.basename(src) with SCP(self.native) as scp: scp.put(src, remote_path=dest) if not self.file_copy_remote_exists(src, dest, **kwargs): raise FileTransferError( message= "Attempted file copy, but could not validate file existed after transfer" ) # TODO: Make this an internal method since exposing file_copy should be sufficient def file_copy_remote_exists(self, src, dest=None, **kwargs): if dest is None: dest = os.path.basename(src) local_hash = self._file_copy_local_md5(src) remote_hash = self._file_copy_remote_md5(dest) if local_hash is not None and local_hash == remote_hash: return True return False def install_os(self, image_name, **vendor_specifics): raise NotImplementedError def open(self): if not self.connected: self.native.open() def reboot(self, timer=0, **kwargs): """ Reload the controller or controller pair. Args: timer (int, optional): The time to wait before reloading. Defaults to 0. Example: >>> device = JunosDevice(**connection_args) >>> device.reboot() >>> """ if kwargs.get("confirm"): warnings.warn("Passing 'confirm' to reboot method is deprecated.", DeprecationWarning) self.sw = JunosNativeSW(self.native) self.sw.reboot(in_min=timer) def rollback(self, filename): self.native.timeout = 60 temp_file = NamedTemporaryFile() with SCP(self.native) as scp: scp.get(filename, local_path=temp_file.name) self.cu.load(path=temp_file.name, format="text", overwrite=True) self.cu.commit() temp_file.close() self.native.timeout = 30 @property def running_config(self): return self.show("show config") def save(self, filename=None): if filename is None: self.cu.commit() return temp_file = NamedTemporaryFile() temp_file.write(self.show("show config")) temp_file.flush() with SCP(self.native) as scp: scp.put(temp_file.name, remote_path=filename) temp_file.close() return True def set_boot_options(self, sys): raise NotImplementedError def show(self, commands): """Send configuration commands to a device. Args: commands (str, list): String with single command, or list with multiple commands. Raises: CommandError: Issue with the command provided. CommandListError: Issue with a command in the list provided. """ original_commands_is_str = isinstance(commands, str) if original_commands_is_str: commands = [commands] responses = [] for command in commands: if not command.startswith("show"): if original_commands_is_str: raise CommandError( command, 'Juniper "show" commands must begin with "show".') raise CommandListError( commands, command, 'Juniper "show" commands must begin with "show".') response = self.native.cli(command, warning=False) responses.append(response) if original_commands_is_str: return responses[0] return responses def show_list(self, commands, raw_text=True): """Send show commands in list format to a device. DEPRECATED - Use the `show` method. Args: commands (list): List with multiple commands. """ warnings.warn("show_list() is deprecated; use show().", DeprecationWarning) return self.show(commands) @property def startup_config(self): return self.show("show config")
def upgrade_device(self, ip, hostname, tar_code, reboot="askReboot"): # Upgrade single device # Status dictionary for post-upgrade reporting statusDict = {} if Menu.upgrade_list == '': statusDict['Upgrade_List'] = 'Juniper-Upgrade_' + Menu.username else: statusDict['Upgrade_List'] = Menu.upgrade_list statusDict['Upgrade_Start'] = '' statusDict['Upgrade_Finish'] = '' statusDict['IP'] = ip statusDict['Connected'] = 'N' statusDict['OS_installed'] = 'N' statusDict['Rebooted'] = 'N' statusDict['IST_Confirm_Loaded'] = '' statusDict['IST_Confirm_Rebooted'] = '' statusDict['Comments'] = '' # Start Logging now = datetime.datetime.now() date_time = now.strftime("%Y-%m-%d-%H%M") install_log = Menu.log_dir + "juniper-install-LOG_" + date_time + "_" + Menu.username + ".log" logging.basicConfig(filename=install_log, level=logging.INFO, format='%(asctime)s:%(name)s: %(message)s') logging.getLogger().name = ip print('Information logged in {0}'.format(install_log)) # Upgrade Information self.do_log("Device: {0} ({1})".format(hostname, ip)) self.do_log("JunOS: {0}".format(tar_code)) # Verify package exists before starting upgrade process fullpathfile = Menu.image_dir + tar_code if os.path.isfile(fullpathfile): dev = Device(ip, user=Menu.username, password=Menu.password) self.do_log('\n') self.do_log( '------------------------- Opening connection to: {0} -------------------------\n' .format(ip)) self.do_log('User: {0}'.format(Menu.username)) # Try to open a connection to the device try: dev.open() # If there is an error when opening the connection, display error and exit upgrade process except Exception as err: sys.stderr.write('Cannot connect to device {0} : {1}'.format( ip, err)) # If else: # Record connection achieved statusDict['Connected'] = 'Y' # Increase the default RPC timeout to accommodate install operations dev.timeout = 600 # Create an instance of SW sw = SW(dev) try: # Logging... self.do_log( 'Starting the software upgrade process: {0}'.format( tar_code)) now = datetime.datetime.now() statusDict['Upgrade_Start'] = now.strftime( "%Y-%m-%d %H:%M") self.do_log('Timestamp: {0}'.format( statusDict['Upgrade_Start'])) # Actual Upgrade Function ok = sw.install(package=fullpathfile, remote_path=Menu.remote_path, progress=True, validate=True) # Failed install method... # ok = sw.install(package=fullPathFile, remote_path=Menu.remote_path, progress=self.update_progress, validate=True) except Exception as err: msg = 'Unable to install software, {0}'.format(err) self.do_log(msg, level='error') else: if ok is True: # Logging... statusDict['OS_installed'] = 'Y' self.do_log('Software installation complete.') now = datetime.datetime.now() statusDict['Upgrade_Finish'] = now.strftime( "%Y-%m-%d %H:%M") self.do_log('Timestamp: {0}'.format( statusDict['Upgrade_Finish'])) # Check rebooting status... if reboot == "askReboot": answer = getYNAnswer('Would you like to reboot') if answer == 'y': reboot = "doReboot" else: reboot = "noReboot" if reboot == "doReboot": rsp = sw.reboot() statusDict['Rebooted'] = 'Y' self.do_log( 'Upgrade pending reboot cycle, please be patient.' ) self.do_log(rsp) # Open a command terminal to monitor device connectivity # os.system("start cmd /c ping -t " + ip) elif reboot == "noReboot": self.do_log( 'Reboot NOT performed. System must be rebooted to complete upgrade.' ) # End the NETCONF session and close the connection dev.close() self.do_log('\n') self.do_log( '------------------------- Closed connection to: {0} -------------------------\n' .format(ip)) else: msg = 'Software package does not exist: {0}. '.format(fullpathfile) sys.exit(msg + '\nExiting program') return statusDict
class JunosDevice(BaseDevice): """Juniper JunOS Device Implementation.""" vendor = "juniper" def __init__(self, host, username, password, *args, **kwargs): super().__init__(host, username, password, *args, device_type="juniper_junos_netconf", **kwargs) self.native = JunosNativeDevice(*args, host=host, user=username, passwd=password, **kwargs) self.open() self.cu = JunosNativeConfig(self.native) self.fs = JunosNativeFS(self.native) self.sw = JunosNativeSW(self.native) def _file_copy_local_file_exists(self, filepath): return os.path.isfile(filepath) def _file_copy_local_md5(self, filepath, blocksize=2**20): if self._file_copy_local_file_exists(filepath): m = hashlib.md5() with open(filepath, "rb") as f: buf = f.read(blocksize) while buf: m.update(buf) buf = f.read(blocksize) return m.hexdigest() def _file_copy_remote_md5(self, filename): return self.fs.checksum(filename) def _get_interfaces(self): eth_ifaces = EthPortTable(self.native) eth_ifaces.get() loop_ifaces = LoopbackTable(self.native) loop_ifaces.get() ifaces = eth_ifaces.keys() ifaces.extend(loop_ifaces.keys()) return ifaces def _image_booted(self, image_name, **vendor_specifics): raise NotImplementedError def _uptime_components(self, uptime_full_string): match_days = re.search(r"(\d+) days?", uptime_full_string) match_hours = re.search(r"(\d+) hours?", uptime_full_string) match_minutes = re.search(r"(\d+) minutes?", uptime_full_string) match_seconds = re.search(r"(\d+) seconds?", uptime_full_string) days = int(match_days.group(1)) if match_days else 0 hours = int(match_hours.group(1)) if match_hours else 0 minutes = int(match_minutes.group(1)) if match_minutes else 0 seconds = int(match_seconds.group(1)) if match_seconds else 0 return days, hours, minutes, seconds def _uptime_to_seconds(self, uptime_full_string): days, hours, minutes, seconds = self._uptime_components( uptime_full_string) seconds += days * 24 * 60 * 60 seconds += hours * 60 * 60 seconds += minutes * 60 return seconds def _uptime_to_string(self, uptime_full_string): days, hours, minutes, seconds = self._uptime_components( uptime_full_string) return "%02d:%02d:%02d:%02d" % (days, hours, minutes, seconds) def _wait_for_device_reboot(self, timeout=3600): start = time.time() while time.time() - start < timeout: try: self.open() return except: # noqa E722 pass raise RebootTimeoutError(hostname=self.facts["hostname"], wait_time=timeout) def backup_running_config(self, filename): with open(filename, "w") as f: f.write(self.running_config) @property def boot_options(self): return self.facts["os_version"] def checkpoint(self, filename): self.save(filename) def close(self): if self.connected: self.native.close() def config(self, command, format="set"): try: self.cu.load(command, format=format) self.cu.commit() except ConfigLoadError as e: raise CommandError(command, e.message) def config_list(self, commands, format="set"): try: for command in commands: self.cu.load(command, format=format) self.cu.commit() except ConfigLoadError as e: raise CommandListError(commands, command, e.message) @property def connected(self): return self.native.connected @property def facts(self): if self._facts is None: native_facts = self.native.facts try: native_uptime_string = native_facts["RE0"]["up_time"] except (AttributeError, TypeError): native_uptime_string = None self._facts = { "hostname": native_facts.get("hostname"), "fqdn": native_facts.get("fqdn"), "model": native_facts.get("model"), "uptime": None, "uptime_string": None, "serial_number": native_facts.get("serialnumber"), "interfaces": self._get_interfaces(), "vendor": self.vendor, "version": native_facts.get("version"), } # TODO: Use a more reliable method for determining uptime (show system uptime) if native_uptime_string is not None: self._facts["uptime"] = self._uptime_to_seconds( native_uptime_string) self._facts["uptime_string"] = self._uptime_to_string( native_uptime_string) return self._facts def file_copy(self, src, dest=None, **kwargs): if not self.file_copy_remote_exists(src, dest, **kwargs): if dest is None: dest = os.path.basename(src) with SCP(self.native) as scp: scp.put(src, remote_path=dest) if not self.file_copy_remote_exists(src, dest, **kwargs): raise FileTransferError( message= "Attempted file copy, but could not validate file existed after transfer" ) # TODO: Make this an internal method since exposing file_copy should be sufficient def file_copy_remote_exists(self, src, dest=None, **kwargs): if dest is None: dest = os.path.basename(src) local_hash = self._file_copy_local_md5(src) remote_hash = self._file_copy_remote_md5(dest) if local_hash is not None and local_hash == remote_hash: return True return False def install_os(self, image_name, **vendor_specifics): raise NotImplementedError def open(self): if not self.connected: self.native.open() def reboot(self, timer=0, confirm=False): self.sw = JunosNativeSW(self.native) if confirm: self.sw.reboot(in_min=timer) else: print("Need to confirm reboot with confirm=True") def rollback(self, filename): self.native.timeout = 60 temp_file = NamedTemporaryFile() with SCP(self.native) as scp: scp.get(filename, local_path=temp_file.name) self.cu.load(path=temp_file.name, format="text", overwrite=True) self.cu.commit() temp_file.close() self.native.timeout = 30 @property def running_config(self): return self.show("show config") def save(self, filename=None): if filename is None: self.cu.commit() return temp_file = NamedTemporaryFile() temp_file.write(self.show("show config")) temp_file.flush() with SCP(self.native) as scp: scp.put(temp_file.name, remote_path=filename) temp_file.close() return True def set_boot_options(self, sys): raise NotImplementedError def show(self, command, raw_text=True): if not raw_text: raise ValueError('Juniper only supports raw text output. \ Append " | display xml" to your commands for a structured string.' ) if not command.startswith("show"): raise CommandError( command, 'Juniper "show" commands must begin with "show".') return self.native.cli(command, warning=False) def show_list(self, commands, raw_text=True): responses = [] for command in commands: responses.append(self.show(command, raw_text=raw_text)) return responses @property def startup_config(self): return self.show("show config")
class TestSW(unittest.TestCase): @patch('ncclient.manager.connect') def setUp(self, mock_connect): mock_connect.side_effect = self._mock_manager self.dev = Device(host='1.1.1.1', user='******', password='******', gather_facts=False) self.dev.open() self.dev._facts = facts self.sw = self.get_sw() @patch('jnpr.junos.Device.execute') def get_sw(self, mock_execute): mock_execute.side_effect = self._mock_manager return SW(self.dev) @patch('ncclient.operations.session.CloseSession.request') def tearDown(self, mock_session): self.dev.close() def test_sw_hashfile(self): with patch(builtin_string + '.open', mock_open(), create=True): import jnpr.junos.utils.sw with open('foo') as h: h.read.side_effect = ('abc', 'a', '') jnpr.junos.utils.sw._hashfile(h, MagicMock()) self.assertEqual(h.read.call_count, 3) @patch('jnpr.junos.Device.execute') def test_sw_constructor_multi_re(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw = SW(self.dev) self.assertTrue(self.sw._multi_RE) @patch('jnpr.junos.Device.execute') def test_sw_constructor_multi_vc(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw = SW(self.dev) self.assertFalse(self.sw._multi_VC) @patch(builtin_string + '.open') def test_sw_local_sha256(self, mock_built_open): package = 'test.tgz' self.assertEqual(SW.local_sha256(package), 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934' 'ca495991b7852b855') @patch(builtin_string + '.open') def test_sw_local_md5(self, mock_built_open): package = 'test.tgz' self.assertEqual(self.sw.local_md5(package), 'd41d8cd98f00b204e9800998ecf8427e') @patch(builtin_string + '.open') def test_sw_local_sha1(self, mock_built_open): package = 'test.tgz' self.assertEqual(SW.local_sha1(package), 'da39a3ee5e6b4b0d3255bfef95601890afd80709') def test_sw_progress(self): with self.capture(SW.progress, self.dev, 'running') as output: self.assertEqual('1.1.1.1: running\n', output) def test_sw_progress(self): with self.capture(SW.progress, self.dev, 'running') as output: self.assertEqual('1.1.1.1: running\n', output) @patch('jnpr.junos.Device.execute') @patch('paramiko.SSHClient') @patch('scp.SCPClient.put') def test_sw_progress_true(self, scp_put, mock_paramiko, mock_execute): mock_execute.side_effect = self._mock_manager with self.capture(SW.progress, self.dev, 'testing') as output: self.sw.install('test.tgz', progress=True, checksum=345, cleanfs=False) self.assertEqual('1.1.1.1: testing\n', output) @patch('paramiko.SSHClient') @patch('scp.SCPClient.put') def test_sw_put(self, mock_scp_put, mock_scp): package = 'test.tgz' self.sw.put(package) self.assertTrue( call( 'test.tgz', '/var/tmp') in mock_scp_put.mock_calls) @patch('jnpr.junos.utils.sw.FTP') def test_sw_put_ftp(self, mock_ftp_put): dev = Device(host='1.1.1.1', user='******', password='******', mode='telnet', port=23, gather_facts=False) sw = SW(dev) sw.put(package='test.tgz') self.assertTrue( call( 'test.tgz', '/var/tmp') in mock_ftp_put.mock_calls) @patch('jnpr.junos.utils.scp.SCP.__exit__') @patch('jnpr.junos.utils.scp.SCP.__init__') @patch('jnpr.junos.utils.scp.SCP.__enter__') def test_sw_put_progress(self, mock_enter, mock_scp, mock_exit): package = 'test.tgz' mock_scp.side_effect = self._fake_scp with self.capture(self.sw.put, package, progress=self._my_scp_progress) as output: self.assertEqual('test.tgz 100 50\n', output) def _fake_scp(self, *args, **kwargs): progress = kwargs['progress'] progress('test.tgz', 100, 50) @patch('jnpr.junos.Device.execute') def test_sw_pkgadd(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'test.tgz' self.assertTrue(self.sw.pkgadd(package)) @patch('jnpr.junos.Device.execute') def test_sw_install_issu(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'test.tgz' self.assertTrue(self.sw.install(package, issu=True, no_copy=True)) @patch('jnpr.junos.Device.execute') def test_sw_install_nssu(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'test.tgz' self.assertTrue(self.sw.install(package, nssu=True, no_copy=True)) @patch('jnpr.junos.Device.execute') def test_sw_install_issu_nssu_both_error(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'test.tgz' self.assertRaises(TypeError, self.sw.install, package, nssu=True, issu=True) @patch('jnpr.junos.Device.execute') def test_sw_install_issu_single_re_error(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'test.tgz' self.sw._multi_RE = False self.assertRaises(TypeError, self.sw.install, package, nssu=True, issu=True) @patch('jnpr.junos.Device.execute') def test_sw_pkgaddISSU(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'test.tgz' self.assertTrue(self.sw.pkgaddISSU(package)) @patch('jnpr.junos.Device.execute') def test_sw_pkgaddNSSU(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'test.tgz' self.assertTrue(self.sw.pkgaddNSSU(package)) @patch('jnpr.junos.Device.execute') def test_sw_pkgadd_pkg_set(self, mock_execute): mock_execute.side_effect = self._mock_manager pkg_set = ['abc.tgz', 'pqr.tgz'] self.sw._mixed_VC = True self.sw.pkgadd(pkg_set) self.assertEqual([i.text for i in mock_execute.call_args[0][0].findall('set')], pkg_set) @patch('jnpr.junos.Device.execute') def test_sw_validate(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'package.tgz' self.assertTrue(self.sw.validate(package)) @patch('jnpr.junos.Device.execute') def test_sw_validate_issu(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'package.tgz' self.assertTrue(self.sw.validate(package, issu=True)) @patch('jnpr.junos.Device.execute') def test_sw_validate_issu(self, mock_execute): rpc_reply = """<rpc-reply><output>mgd: commit complete Validation succeeded </output> <package-result>1</package-result> </rpc-reply>""" mock_execute.side_effect = etree.fromstring(rpc_reply) package = 'package.tgz' self.assertFalse(self.sw.validate(package, issu=True)) @patch('jnpr.junos.Device.execute') def test_sw_remote_checksum_not_found(self, mock_execute): xml = '''<rpc-error> <error-severity>error</error-severity> <error-message> md5: /var/tmp/123: No such file or directory </error-message> </rpc-error>''' mock_execute.side_effect = RpcError(rsp=etree.fromstring(xml)) package = 'test.tgz' self.assertEqual(self.sw.remote_checksum(package), None) @patch('jnpr.junos.Device.execute') def test_sw_remote_checksum_not_rpc_error(self, mock_execute): xml = '''<rpc-error> <error-severity>error</error-severity> <error-message> something else! </error-message> </rpc-error>''' mock_execute.side_effect = RpcError(rsp=etree.fromstring(xml)) package = 'test.tgz' with self.assertRaises(RpcError): self.sw.remote_checksum(package) @patch('jnpr.junos.Device.execute') def test_sw_safe_copy(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'safecopy.tgz' self.sw.put = MagicMock() with patch('jnpr.junos.utils.sw.SW.local_md5'): self.assertTrue(self.sw.safe_copy(package, progress=self._myprogress, cleanfs=True, checksum='96a35ab371e1ca10408c3caecdbd8a67')) @patch('jnpr.junos.Device.execute') def test_sw_safe_copy_return_false(self, mock_execute): # not passing checksum value, will get random from magicmock mock_execute.side_effect = self._mock_manager package = 'safecopy.tgz' self.sw.put = MagicMock() with patch('jnpr.junos.utils.sw.SW.local_md5'): self.assertFalse(self.sw.safe_copy(package, progress=self._myprogress, cleanfs=True)) @patch('jnpr.junos.Device.execute') def test_sw_safe_copy_checksum_none(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'safecopy.tgz' self.sw.put = MagicMock() with patch('jnpr.junos.utils.sw.SW.local_md5', MagicMock(return_value='96a35ab371e1ca10408c3caecdbd8a67')): self.assertTrue(self.sw.safe_copy(package, progress=self._myprogress, cleanfs=True)) @patch('jnpr.junos.Device.execute') def test_sw_safe_install(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'install.tgz' self.sw.put = MagicMock() with patch('jnpr.junos.utils.sw.SW.local_md5', MagicMock(return_value='96a35ab371e1ca10408c3caecdbd8a67')): self.assertTrue( self.sw.install( package, progress=self._myprogress, cleanfs=True)) @patch('jnpr.junos.utils.sw.SW.safe_copy') def test_sw_safe_install_copy_fail(self, mock_copy): mock_copy.return_value = False self.assertFalse(self.sw.install('file')) @patch('jnpr.junos.utils.sw.SW.validate') def test_sw_install_validate(self, mock_validate): mock_validate.return_value = False self.assertFalse(self.sw.install('file', validate=True, no_copy=True)) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_multi_mx(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._multi_RE = True self.sw._multi_MX = True self.assertTrue(self.sw.install('file', no_copy=True)) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_multi_vc(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._multi_RE = True self.sw._multi_VC = True self.sw._RE_list = ('version_RE0', 'version_RE1') self.assertTrue(self.sw.install('file', no_copy=True)) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_mixed_vc(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._mixed_VC = True self.sw._RE_list = ('version_RE0', 'version_RE1') self.assertTrue(self.sw.install(pkg_set=['abc.tgz', 'pqr.tgz'], no_copy=True)) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_multi_vc_mode_disabled(self, mock_pkgadd): mock_pkgadd.return_value = True self.dev._facts = {'2RE': True, 'domain': None, 'RE1': { 'status': 'OK', 'model': 'RE-EX8208', 'mastership_state': 'backup'}, 'ifd_style': 'SWITCH', 'version_RE1': '12.3R7.7', 'version_RE0': '12.3', 'serialnumber': 'XXXXXX', 'fqdn': 'XXXXXX', 'RE0': {'status': 'OK', 'model': 'RE-EX8208', 'mastership_state': 'master'}, 'switch_style': 'VLAN', 'version': '12.3R5-S3.1', 'master': 'RE0', 'hostname': 'XXXXXX', 'HOME': '/var/home/sn', 'vc_mode': 'Disabled', 'model': 'EX8208', 'vc_capable': True, 'personality': 'SWITCH'} sw = self.get_sw() sw.install(package='abc.tgz', no_copy=True) self.assertFalse(sw._multi_VC) calls = [call('/var/tmp/abc.tgz', dev_timeout=1800, re0=True), call('/var/tmp/abc.tgz', dev_timeout=1800, re1=True)] mock_pkgadd.assert_has_calls(calls) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_mixed_vc_with_copy(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._mixed_VC = True self.sw.put = MagicMock() self.sw.remote_checksum = MagicMock( return_value='d41d8cd98f00b204e9800998ecf8427e') self.sw._RE_list = ('version_RE0', 'version_RE1') with patch('jnpr.junos.utils.sw.SW.local_md5', MagicMock(return_value='d41d8cd98f00b204e9800998ecf8427e')): self.assertTrue( self.sw.install( pkg_set=[ 'install.tgz', 'install.tgz'], cleanfs=False)) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_mixed_vc_safe_copy_false(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._mixed_VC = True self.sw.safe_copy = MagicMock(return_value=False) self.sw.remote_checksum = MagicMock( return_value='d41d8cd98f00b204e9800998ecf8427e') self.sw._RE_list = ('version_RE0', 'version_RE1') with patch('jnpr.junos.utils.sw.SW.local_md5', MagicMock(return_value='d41d8cd98f00b204e9800998ecf8427e')): self.assertFalse( self.sw.install( pkg_set=[ 'install.tgz', 'install.tgz'], cleanfs=False)) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_mixed_vc_ValueError(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._mixed_VC = True self.sw.remote_checksum = MagicMock( return_value='d41d8cd98f00b204e9800998ecf8427e') self.sw._RE_list = ('version_RE0', 'version_RE1') with patch('jnpr.junos.utils.sw.SW.local_md5', MagicMock(return_value='d41d8cd98f00b204e9800998ecf8427e')): self.assertRaises( ValueError, self.sw.install, pkg_set='install.tgz', cleanfs=False) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_mixed_vc_TypeError(self, mock_pkgadd): self.assertRaises(TypeError, self.sw.install, cleanfs=False) @patch('jnpr.junos.Device.execute') def test_sw_install_kwargs_force_host(self, mock_execute): self.sw.install('file', no_copy=True, force_host=True) rpc = [ '<request-package-add><force-host/><no-validate/><re1/><package-name>/var/tmp/file</package-name></request-package-add>', '<request-package-add><package-name>/var/tmp/file</package-name><no-validate/><force-host/><re1/></request-package-add>', '<request-package-add><package-name>/var/tmp/file</package-name><no-validate/><re1/><force-host/></request-package-add>', '<request-package-add><force-host/><no-validate/><package-name>/var/tmp/file</package-name><re1/></request-package-add>', '<request-package-add><force-host/><re1/><no-validate/><package-name>/var/tmp/file</package-name></request-package-add>', '<request-package-add><no-validate/><re1/><package-name>/var/tmp/file</package-name><force-host/></request-package-add>', '<request-package-add><no-validate/><package-name>/var/tmp/file</package-name><force-host/><re1/></request-package-add>', '<request-package-add><force-host/><package-name>/var/tmp/file</package-name><no-validate/><re1/></request-package-add>', '<request-package-add><re1/><no-validate/><package-name>/var/tmp/file</package-name><force-host/></request-package-add>', '<request-package-add><re1/><force-host/><package-name>/var/tmp/file</package-name><no-validate/></request-package-add>', '<request-package-add><re1/><package-name>/var/tmp/file</package-name><force-host/><no-validate/></request-package-add>', '<request-package-add><re1/><force-host/><no-validate/><package-name>/var/tmp/file</package-name></request-package-add>', '<request-package-add><no-validate/><force-host/><re1/><package-name>/var/tmp/file</package-name></request-package-add>', '<request-package-add><package-name>/var/tmp/file</package-name><force-host/><no-validate/><re1/></request-package-add>', '<request-package-add><no-validate/><re1/><force-host/><package-name>/var/tmp/file</package-name></request-package-add>', '<request-package-add><package-name>/var/tmp/file</package-name><force-host/><re1/><no-validate/></request-package-add>', '<request-package-add><no-validate/><force-host/><package-name>/var/tmp/file</package-name><re1/></request-package-add>', '<request-package-add><force-host/><no-validate/><package-name>/var/tmp/file</package-name></request-package-add>', '<request-package-add><force-host/><package-name>/var/tmp/file</package-name><no-validate/></request-package-add>', '<request-package-add><package-name>/var/tmp/file</package-name><no-validate/><force-host/></request-package-add>', '<request-package-add><no-validate/><force-host/><package-name>/var/tmp/file</package-name></request-package-add>', '<request-package-add><no-validate/><package-name>/var/tmp/file</package-name><force-host/></request-package-add>', '<request-package-add><package-name>/var/tmp/file</package-name><force-host/><no-validate/></request-package-add>'] self.assertTrue(etree.tostring( mock_execute.call_args[0][0]).decode('utf-8') in rpc) @patch('jnpr.junos.Device.execute') def test_sw_rollback(self, mock_execute): rsp = '<rpc-reply><output>junos-vsrx-12.1X46-D30.2-domestic will become active at next reboot</output></rpc-reply>' mock_execute.side_effect = etree.XML(rsp) msg = 'junos-vsrx-12.1X46-D30.2-domestic will become active at next reboot' self.assertEqual(self.sw.rollback(), msg) @patch('jnpr.junos.Device.execute') def test_sw_rollback_multi(self, mock_execute): mock_execute.side_effect = self._mock_manager msg = {'fpc1': "Junos version 'D10.2' will become active at next reboot", 'fpc0': 'JUNOS version "D10.2" will become active at next reboot'} self.assertEqual(eval(self.sw.rollback()), msg) @patch('jnpr.junos.Device.execute') def test_sw_rollback_multi_exception(self, mock_execute): fname = 'request-package-rollback-multi-error.xml' mock_execute.side_effect = self._read_file(fname) self.assertRaises(SwRollbackError, self.sw.rollback) @patch('jnpr.junos.Device.execute') def test_sw_rollback_exception(self, mock_execute): rsp = '<rpc-reply><output>WARNING: Cannot rollback, /packages/junos.old is not valid</output></rpc-reply>' mock_execute.side_effect = etree.XML(rsp) self.assertRaises(SwRollbackError, self.sw.rollback) def test_sw_inventory(self): self.sw.dev.rpc.file_list = \ MagicMock(side_effect=self._mock_manager) self.assertEqual( self.sw.inventory, { 'current': None, 'rollback': None}) @patch('jnpr.junos.Device.execute') def test_sw_reboot(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_MX = True self.assertTrue('Shutdown NOW' in self.sw.reboot()) @patch('jnpr.junos.Device.execute') def test_sw_reboot_at(self, mock_execute): mock_execute.side_effect = self._mock_manager self.assertTrue('Shutdown at' in self.sw.reboot(at='201407091815')) @patch('jnpr.junos.Device.execute') def test_sw_reboot_multi_re_vc(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_RE = True self.sw._multi_VC = False self.assertTrue('Shutdown NOW' in self.sw.reboot()) @patch('jnpr.junos.Device.execute') def test_sw_reboot_mixed_vc(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._mixed_VC = True self.sw._multi_VC = True self.sw.reboot() self.assertTrue('all-members' in (etree.tostring(mock_execute.call_args[0][0]).decode('utf-8'))) @patch('jnpr.junos.Device.execute') def test_sw_reboot_exception(self, mock_execute): rsp = etree.XML('<rpc-reply><a>test</a></rpc-reply>') mock_execute.side_effect = RpcError(rsp=rsp) self.assertRaises(Exception, self.sw.reboot) @patch('jnpr.junos.Device.execute') def test_sw_reboot_exception_RpcTimeoutError(self, mock_execute): rsp = (self.dev, 'request-reboot', 60) mock_execute.side_effect = RpcTimeoutError(*rsp) self.assertRaises(Exception, self.sw.reboot) @patch('jnpr.junos.Device.execute') def test_sw_poweroff(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_MX = True self.assertTrue('Shutdown NOW' in self.sw.poweroff()) @patch('jnpr.junos.Device.execute') def test_sw_poweroff_exception(self, mock_execute): rsp = etree.XML('<rpc-reply><a>test</a></rpc-reply>') mock_execute.side_effect = RpcError(rsp=rsp) self.assertRaises(Exception, self.sw.poweroff) @patch('jnpr.junos.Device.execute') def test_sw_poweroff_multi_re_vc(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_RE = True self.sw._multi_VC = False self.assertTrue('Shutdown NOW' in self.sw.poweroff()) def _myprogress(self, dev, report): pass def _my_scp_progress(self, _path, _total, _xfrd): print (_path, _total, _xfrd) @contextmanager def capture(self, command, *args, **kwargs): out, sys.stdout = sys.stdout, StringIO() command(*args, **kwargs) sys.stdout.seek(0) yield sys.stdout.read() sys.stdout = out def _read_file(self, fname): from ncclient.xml_ import NCElement fpath = os.path.join(os.path.dirname(__file__), 'rpc-reply', fname) foo = open(fpath).read() rpc_reply = NCElement( foo, self.dev._conn._device_handler.transform_reply())._NCElement__doc[0] return rpc_reply def _mock_manager(self, *args, **kwargs): if kwargs: # Little hack for mocked execute if 'dev_timeout' in kwargs: return self._read_file(args[0].tag + '.xml') if 'path' in kwargs: if kwargs['path'] == '/packages': return self._read_file('file-list_dir.xml') device_params = kwargs['device_params'] device_handler = make_device_handler(device_params) session = SSHSession(device_handler) return Manager(session, device_handler) elif args: if args[0].find('at') is not None: return self._read_file('request-reboot-at.xml') else: return self._read_file(args[0].tag + '.xml')
def main(): dev = Device(host=hostname, user=junos_username, passwd=junos_password) # open a connection with the device and start a NETCONF session try: dev.open() except ConnectError as err: sys.exit("Unfortunately the target device is unreachable. Check connection parameters.") ###################################################################################### #######################CONFIG LOAD STARTS HERE######################################## ###################################################################################### dev.bind(cu=Config) # Lock the configuration, load configuration changes, and commit print ("Locking the configuration") try: dev.cu.lock() except LockError as err: print ("Unable to lock configuration: {0}".format(err)) dev.close() return print ("Loading configuration changes") try: dev.cu.load(path=conf_file, merge=True) except (ConfigLoadError, Exception) as err: print ("Unable to load configuration changes: {0}".format(err)) print ("Unlocking the configuration") try: dev.cu.unlock() except UnlockError: print ("Unable to unlock configuration: {0}".format(err)) dev.close() return print ("Committing the configuration") try: dev.cu.commit(comment='Loaded by example.') except CommitError as err: print ("Unable to commit configuration: {0}".format(err)) print ("Unlocking the configuration") try: dev.cu.unlock() except UnlockError as err: print ("Unable to unlock configuration: {0}".format(err)) dev.close() return print ("Unlocking the configuration") try: dev.cu.unlock() except UnlockError as err: print ("Unable to unlock configuration: {0}".format(err)) ###################################################################################### #######################UPGRADE PROCESS STARTS HERE#################################### ###################################################################################### type = (dev.facts["version"]) sw = SW(dev) if type == "18.4R3-S2": print("Looks like your device is already on the latest firmware!.") elif type != "18.4R3-S2": print("Not on latest Junos version. Copying/installing latest Junos image to device. Please be patient.") try: ok = sw.install(package=package_srx,remote_path=srx_local,validate=False,progress=update_progress) except Exception as err: ok = False print("Unable to install software.") if ok == True: print("Software installation complete. Rebooting!") rsp = sw.reboot() else: print("Unable to install software.") dev.close()
def update_process(type,host,package,threadIns): # verify package exists if type=='OS' or type=='Firmware': if not (os.path.isfile(package)): msg = 'Software package does not exist: {0}. '.format(package) logging.error(msg) print msg sys.exit() time.sleep(20) dev=None dev = Device(host=host,user=junos_username, passwd=junos_password) rebootTime=10 rebootOK=False while not rebootOK: try: time.sleep(10) rebootOK=True dev.open() except Exception as err: print threadIns.hostIP+threadIns.serialNumber+':wait device time='+str(rebootTime)+"Sec "+str(err) logging.info(threadIns.hostIP+threadIns.serialNumber+':wait device time='+str(rebootTime)+"Sec "+str(err)) rebootTime+=10 rebootOK=False if rebootTime>=rebootTimeout: logging.error('Cannot connect to device\n') print 'Cannot connect to device\n' return if type=='createLogFile': threadIns.status="createLog" dev.timeout = 100 create_log(dev) dev.close() return if type=='checkSerialNumber': threadIns.status="checkSN" threadIns.serialNumber=dev.facts['serialnumber'] dev.close() return if type=='Snapshot': threadIns.status="Snapshot" dev.timeout = 600 dev.rpc.request_snapshot(slice='alternate') dev.close() return if type=='setFixIP': threadIns.status="setFixIP" cu = Config(dev) cu.load('delete interfaces ge-0/0/0', format='set') cu.load('set interfaces ge-0/0/0 unit 0 family inet address '+threadIns.hostIP+'/'+str(dhcpNetmask), format='set') cu.pdiff() cu.commit() return # Create an instance of SW sw = SW(dev) threadIns.status="install"+type try: logging.info('Starting the software upgrade process: {0}'.format(package)) okOS = sw.install(package=package, remote_path=remote_path,progress=update_progress, validate=validate) #okOS=True except Exception as err: msg = 'Unable to install software, {0}'.format(err) logging.error(msg) okOS = False if type=="Firmware": #UPGRADED SUCCESSFULLY logging.info("!!!!!!!!!!!!!") logging.info(dev.cli("request system firmware upgrade pic pic-slot 0 fpc-slot 1")) threadIns.status="checkFirmware" okFirmware=False #okFirmware=True firmwareTime=0 while not okFirmware and okOS: xmlStr=etree.tostring(dev.rpc.get_system_firmware_information(), encoding='unicode') xmlRoot = ET.fromstring(xmlStr) for firmware_status in xmlRoot.iter('firmware-status'): #UPGRADED SUCCESSFULLY if firmware_status.text=='UPGRADED SUCCESSFULLY':okFirmware=True if firmware_status.text!='OK':print firmware_status.text print threadIns.hostIP+threadIns.serialNumber+":wate firmware upgrade "+str(firmwareTime)+" Sec" time.sleep(1) firmwareTime=firmwareTime+1 #print okFirmware elif type=="OS":okFirmware=True threadIns.status="reboot after install"+type if okOS is True and okFirmware is True: logging.info('Software installation complete. Rebooting') rsp = sw.reboot() logging.info('Upgrade pending reboot cycle, please be patient.') logging.info(rsp) else: msg = 'Unable to install software, {0}'.format(okOS) logging.error(msg) # End the NETCONF session and close the connection dev.close()
class TestSW(unittest.TestCase): @patch("ncclient.manager.connect") def setUp(self, mock_connect): mock_connect.side_effect = self._mock_manager self.dev = Device(host="1.1.1.1", user="******", password="******", gather_facts=False) self.dev.open() self.dev._facts = facts self.sw = self.get_sw() @patch("jnpr.junos.Device.execute") def get_sw(self, mock_execute): mock_execute.side_effect = self._mock_manager return SW(self.dev) @patch("ncclient.operations.session.CloseSession.request") def tearDown(self, mock_session): self.dev.close() def test_sw_hashfile(self): with patch("__builtin__.open", mock_open(), create=True): import jnpr.junos.utils.sw with open("foo") as h: h.read.side_effect = ("abc", "a", "") jnpr.junos.utils.sw._hashfile(h, MagicMock()) self.assertEqual(h.read.call_count, 3) @patch("jnpr.junos.Device.execute") def test_sw_constructor_multi_re(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw = SW(self.dev) self.assertFalse(self.sw._multi_RE) @patch("jnpr.junos.Device.execute") def test_sw_constructor_multi_vc(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw = SW(self.dev) self.assertFalse(self.sw._multi_VC) @patch("__builtin__.open") def test_sw_local_sha256(self, mock_built_open): package = "test.tgz" self.assertEqual( SW.local_sha256(package), "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934" "ca495991b7852b855" ) @patch("__builtin__.open") def test_sw_local_md5(self, mock_built_open): package = "test.tgz" self.assertEqual(self.sw.local_md5(package), "d41d8cd98f00b204e9800998ecf8427e") @patch("__builtin__.open") def test_sw_local_sha1(self, mock_built_open): package = "test.tgz" self.assertEqual(SW.local_sha1(package), "da39a3ee5e6b4b0d3255bfef95601890afd80709") def test_sw_progress(self): with self.capture(SW.progress, self.dev, "running") as output: self.assertEqual("1.1.1.1: running\n", output) @patch("paramiko.SSHClient") @patch("scp.SCPClient.put") def test_sw_put(self, mock_scp_put, mock_scp): # mock_scp_put.side_effect = self.mock_put package = "test.tgz" self.sw.put(package) self.assertTrue(call("test.tgz", "/var/tmp") in mock_scp_put.mock_calls) @patch("jnpr.junos.utils.scp.SCP.__exit__") @patch("jnpr.junos.utils.scp.SCP.__init__") @patch("jnpr.junos.utils.scp.SCP.__enter__") def test_sw_put_progress(self, mock_enter, mock_scp, mock_exit): package = "test.tgz" mock_scp.side_effect = self._fake_scp self.sw.put(package, progress=self._myprogress) self.assertEqual(mock_scp.call_args_list[0][1]["progress"].by10pct, 50) def _fake_scp(self, *args, **kwargs): progress = kwargs["progress"] progress("test.tgz", 100, 50) @patch("jnpr.junos.Device.execute") def test_sw_pkgadd(self, mock_execute): mock_execute.side_effect = self._mock_manager package = "test.tgz" self.assertTrue(self.sw.pkgadd(package)) @patch("jnpr.junos.Device.execute") def test_sw_pkgadd_pkg_set(self, mock_execute): mock_execute.side_effect = self._mock_manager pkg_set = ["abc.tgz", "pqr.tgz"] self.sw._mixed_VC = True self.sw.pkgadd(pkg_set) self.assertEqual([i.text for i in mock_execute.call_args[0][0].findall("set")], pkg_set) @patch("jnpr.junos.Device.execute") def test_sw_validate(self, mock_execute): mock_execute.side_effect = self._mock_manager package = "package.tgz" self.assertTrue(self.sw.validate(package)) @patch("jnpr.junos.Device.execute") def test_sw_remote_checksum_not_found(self, mock_execute): xml = """<rpc-error> <error-severity>error</error-severity> <error-message> md5: /var/tmp/123: No such file or directory </error-message> </rpc-error>""" mock_execute.side_effect = RpcError(rsp=etree.fromstring(xml)) package = "test.tgz" self.assertEqual(self.sw.remote_checksum(package), None) @patch("jnpr.junos.Device.execute") def test_sw_remote_checksum_not_rpc_error(self, mock_execute): xml = """<rpc-error> <error-severity>error</error-severity> <error-message> something else! </error-message> </rpc-error>""" mock_execute.side_effect = RpcError(rsp=etree.fromstring(xml)) package = "test.tgz" with self.assertRaises(RpcError): self.sw.remote_checksum(package) @patch("jnpr.junos.Device.execute") def test_sw_safe_copy(self, mock_execute): mock_execute.side_effect = self._mock_manager package = "safecopy.tgz" self.sw.put = MagicMock() with patch("jnpr.junos.utils.sw.SW.local_md5"): self.assertTrue( self.sw.safe_copy( package, progress=self._myprogress, cleanfs=True, checksum="96a35ab371e1ca10408c3caecdbd8a67" ) ) @patch("jnpr.junos.Device.execute") def test_sw_safe_copy_return_false(self, mock_execute): # not passing checksum value, will get random from magicmock mock_execute.side_effect = self._mock_manager package = "safecopy.tgz" self.sw.put = MagicMock() with patch("jnpr.junos.utils.sw.SW.local_md5"): self.assertFalse(self.sw.safe_copy(package, progress=self._myprogress, cleanfs=True)) @patch("jnpr.junos.Device.execute") def test_sw_safe_copy_checksum_none(self, mock_execute): mock_execute.side_effect = self._mock_manager package = "safecopy.tgz" self.sw.put = MagicMock() with patch("jnpr.junos.utils.sw.SW.local_md5", MagicMock(return_value="96a35ab371e1ca10408c3caecdbd8a67")): self.assertTrue(self.sw.safe_copy(package, progress=self._myprogress, cleanfs=True)) @patch("jnpr.junos.Device.execute") def test_sw_safe_install(self, mock_execute): mock_execute.side_effect = self._mock_manager package = "install.tgz" self.sw.put = MagicMock() with patch("jnpr.junos.utils.sw.SW.local_md5", MagicMock(return_value="96a35ab371e1ca10408c3caecdbd8a67")): self.assertTrue(self.sw.install(package, progress=self._myprogress, cleanfs=True)) @patch("jnpr.junos.utils.sw.SW.safe_copy") def test_sw_safe_install_copy_fail(self, mock_copy): mock_copy.return_value = False self.assertFalse(self.sw.install("file")) @patch("jnpr.junos.utils.sw.SW.validate") def test_sw_install_validate(self, mock_validate): mock_validate.return_value = False self.assertFalse(self.sw.install("file", validate=True, no_copy=True)) @patch("jnpr.junos.utils.sw.SW.pkgadd") def test_sw_install_multi_mx(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._multi_RE = True self.sw._multi_MX = True self.assertTrue(self.sw.install("file", no_copy=True)) @patch("jnpr.junos.utils.sw.SW.pkgadd") def test_sw_install_multi_vc(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._multi_RE = True self.sw._multi_VC = True self.sw._RE_list = ("version_RE0", "version_RE1") self.assertTrue(self.sw.install("file", no_copy=True)) @patch("jnpr.junos.utils.sw.SW.pkgadd") def test_sw_install_mixed_vc(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._mixed_VC = True self.sw._RE_list = ("version_RE0", "version_RE1") self.assertTrue(self.sw.install(pkg_set=["abc.tgz", "pqr.tgz"], no_copy=True)) @patch("jnpr.junos.utils.sw.SW.pkgadd") def test_sw_install_mixed_vc_with_copy(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._mixed_VC = True self.sw.put = MagicMock() self.sw.remote_checksum = MagicMock(return_value="d41d8cd98f00b204e9800998ecf8427e") self.sw._RE_list = ("version_RE0", "version_RE1") with patch("jnpr.junos.utils.sw.SW.local_md5", MagicMock(return_value="d41d8cd98f00b204e9800998ecf8427e")): self.assertTrue(self.sw.install(pkg_set=["install.tgz", "install.tgz"], cleanfs=False)) @patch("jnpr.junos.utils.sw.SW.pkgadd") def test_sw_install_mixed_vc_safe_copy_false(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._mixed_VC = True self.sw.safe_copy = MagicMock(return_value=False) self.sw.remote_checksum = MagicMock(return_value="d41d8cd98f00b204e9800998ecf8427e") self.sw._RE_list = ("version_RE0", "version_RE1") with patch("jnpr.junos.utils.sw.SW.local_md5", MagicMock(return_value="d41d8cd98f00b204e9800998ecf8427e")): self.assertFalse(self.sw.install(pkg_set=["install.tgz", "install.tgz"], cleanfs=False)) @patch("jnpr.junos.utils.sw.SW.pkgadd") def test_sw_install_mixed_vc_ValueError(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._mixed_VC = True self.sw.remote_checksum = MagicMock(return_value="d41d8cd98f00b204e9800998ecf8427e") self.sw._RE_list = ("version_RE0", "version_RE1") with patch("jnpr.junos.utils.sw.SW.local_md5", MagicMock(return_value="d41d8cd98f00b204e9800998ecf8427e")): self.assertRaises(ValueError, self.sw.install, pkg_set="install.tgz", cleanfs=False) @patch("jnpr.junos.utils.sw.SW.pkgadd") def test_sw_install_mixed_vc_TypeError(self, mock_pkgadd): self.assertRaises(TypeError, self.sw.install, cleanfs=False) @patch("jnpr.junos.Device.execute") def test_sw_install_kwargs_force_host(self, mock_execute): self.sw.install("file", no_copy=True, force_host=True) rpc = """<request-package-add><force-host/><no-validate/><package-name>/var/tmp/file</package-name></request-package-add>""" self.assertEqual(etree.tostring(mock_execute.call_args[0][0]), rpc) @patch("jnpr.junos.Device.execute") def test_sw_rollback(self, mock_execute): rsp = "<rpc-reply><output>junos-vsrx-12.1X46-D30.2-domestic will become active at next reboot</output></rpc-reply>" mock_execute.side_effect = etree.XML(rsp) msg = "junos-vsrx-12.1X46-D30.2-domestic will become active at next reboot" self.assertEqual(self.sw.rollback(), msg) @patch("jnpr.junos.Device.execute") def test_sw_rollback_multi(self, mock_execute): mock_execute.side_effect = self._mock_manager msg = "{'fpc1': \"Junos version 'D10.2' will become active at next reboot\", 'fpc0': 'JUNOS version \"D10.2\" will become active at next reboot'}" self.assertEqual(self.sw.rollback(), msg) @patch("jnpr.junos.Device.execute") def test_sw_rollback_multi_exception(self, mock_execute): fname = "request-package-rollback-multi-error.xml" mock_execute.side_effect = self._read_file(fname) self.assertRaises(SwRollbackError, self.sw.rollback) @patch("jnpr.junos.Device.execute") def test_sw_rollback_exception(self, mock_execute): rsp = "<rpc-reply><output>WARNING: Cannot rollback, /packages/junos.old is not valid</output></rpc-reply>" mock_execute.side_effect = etree.XML(rsp) self.assertRaises(SwRollbackError, self.sw.rollback) def test_sw_inventory(self): self.sw.dev.rpc.file_list = MagicMock(side_effect=self._mock_manager) self.assertEqual(self.sw.inventory, {"current": None, "rollback": None}) @patch("jnpr.junos.Device.execute") def test_sw_reboot(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_MX = True self.assertTrue("Shutdown NOW" in self.sw.reboot()) @patch("jnpr.junos.Device.execute") def test_sw_reboot_at(self, mock_execute): mock_execute.side_effect = self._mock_manager self.assertTrue("Shutdown at" in self.sw.reboot(at="201407091815")) @patch("jnpr.junos.Device.execute") def test_sw_reboot_multi_re_vc(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_RE = True self.sw._multi_VC = False self.assertTrue("Shutdown NOW" in self.sw.reboot()) @patch("jnpr.junos.Device.execute") def test_sw_reboot_mixed_vc(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._mixed_VC = True self.sw.reboot() self.assertTrue("all-members" in etree.tostring(mock_execute.call_args[0][0])) @patch("jnpr.junos.Device.execute") def test_sw_reboot_exception(self, mock_execute): rsp = etree.XML("<rpc-reply><a>test</a></rpc-reply>") mock_execute.side_effect = RpcError(rsp=rsp) self.assertRaises(Exception, self.sw.reboot) @patch("jnpr.junos.Device.execute") def test_sw_reboot_exception_RpcTimeoutError(self, mock_execute): rsp = (self.dev, "request-reboot", 60) mock_execute.side_effect = RpcTimeoutError(*rsp) self.assertRaises(Exception, self.sw.reboot) @patch("jnpr.junos.Device.execute") def test_sw_poweroff(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_MX = True self.assertTrue("Shutdown NOW" in self.sw.poweroff()) @patch("jnpr.junos.Device.execute") def test_sw_poweroff_exception(self, mock_execute): rsp = etree.XML("<rpc-reply><a>test</a></rpc-reply>") mock_execute.side_effect = RpcError(rsp=rsp) self.assertRaises(Exception, self.sw.poweroff) @patch("jnpr.junos.Device.execute") def test_sw_poweroff_multi_re_vc(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_RE = True self.sw._multi_VC = False self.assertTrue("Shutdown NOW" in self.sw.poweroff()) def _myprogress(self, dev, report): pass @contextmanager def capture(self, command, *args, **kwargs): out, sys.stdout = sys.stdout, StringIO() command(*args, **kwargs) sys.stdout.seek(0) yield sys.stdout.read() sys.stdout = out def _read_file(self, fname): from ncclient.xml_ import NCElement fpath = os.path.join(os.path.dirname(__file__), "rpc-reply", fname) foo = open(fpath).read() rpc_reply = NCElement(foo, self.dev._conn._device_handler.transform_reply())._NCElement__doc[0] return rpc_reply def _mock_manager(self, *args, **kwargs): if kwargs: # Little hack for mocked execute if "dev_timeout" in kwargs: return self._read_file(args[0].tag + ".xml") if "path" in kwargs: if kwargs["path"] == "/packages": return self._read_file("file-list_dir.xml") device_params = kwargs["device_params"] device_handler = make_device_handler(device_params) session = SSHSession(device_handler) return Manager(session, device_handler) elif args: if args[0].find("at") is not None: return self._read_file("request-reboot-at.xml") else: return self._read_file(args[0].tag + ".xml")
class TestSW(unittest.TestCase): @patch('ncclient.manager.connect') def setUp(self, mock_connect): mock_connect.side_effect = self._mock_manager self.dev = Device(host='1.1.1.1', user='******', password='******', gather_facts=False) self.dev.open() self.dev._facts = facts self.sw = self.get_sw() @patch('jnpr.junos.Device.execute') def get_sw(self, mock_execute): mock_execute.side_effect = self._mock_manager return SW(self.dev) @patch('ncclient.operations.session.CloseSession.request') def tearDown(self, mock_session): self.dev.close() def test_sw_hashfile(self): with patch('__builtin__.open', mock_open(), create=True): import jnpr.junos.utils.sw with open('foo') as h: h.read.side_effect = ('abc', 'a', '') jnpr.junos.utils.sw._hashfile(h, MagicMock()) self.assertEqual(h.read.call_count, 3) @patch('jnpr.junos.Device.execute') def test_sw_constructor_multi_re(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw = SW(self.dev) self.assertFalse(self.sw._multi_RE) @patch('jnpr.junos.Device.execute') def test_sw_constructor_multi_vc(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw = SW(self.dev) self.assertFalse(self.sw._multi_VC) @patch('__builtin__.open') def test_sw_local_sha256(self, mock_built_open): package = 'test.tgz' self.assertEqual( SW.local_sha256(package), 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934' 'ca495991b7852b855') @patch('__builtin__.open') def test_sw_local_md5(self, mock_built_open): package = 'test.tgz' self.assertEqual(SW.local_md5(package), 'd41d8cd98f00b204e9800998ecf8427e') @patch('__builtin__.open') def test_sw_local_sha1(self, mock_built_open): package = 'test.tgz' self.assertEqual(SW.local_sha1(package), 'da39a3ee5e6b4b0d3255bfef95601890afd80709') def test_sw_progress(self): with self.capture(SW.progress, self.dev, 'running') as output: self.assertEqual('1.1.1.1: running\n', output) @patch('paramiko.SSHClient') @patch('scp.SCPClient.put') def test_sw_put(self, mock_scp_put, mock_scp): # mock_scp_put.side_effect = self.mock_put package = 'test.tgz' self.sw.put(package) self.assertTrue( call('test.tgz', '/var/tmp') in mock_scp_put.mock_calls) @patch('jnpr.junos.utils.scp.SCP.__exit__') @patch('jnpr.junos.utils.scp.SCP.__init__') @patch('jnpr.junos.utils.scp.SCP.__enter__') def test_sw_put_progress(self, mock_enter, mock_scp, mock_exit): package = 'test.tgz' mock_scp.side_effect = self._fake_scp self.sw.put(package, progress=self._myprogress) self.assertEqual(mock_scp.call_args_list[0][1]['progress'].by10pct, 50) def _fake_scp(self, *args, **kwargs): progress = kwargs['progress'] progress('test.tgz', 100, 50) @patch('jnpr.junos.Device.execute') def test_sw_pkgadd(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'test.tgz' self.assertTrue(self.sw.pkgadd(package)) @patch('jnpr.junos.Device.execute') def test_sw_validate(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'package.tgz' self.assertTrue(self.sw.validate(package)) @patch('jnpr.junos.Device.execute') def test_sw_safe_copy(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'safecopy.tgz' self.sw.put = MagicMock() SW.local_md5 = MagicMock() self.assertTrue( self.sw.safe_copy(package, progress=self._myprogress, cleanfs=True, checksum='96a35ab371e1ca10408c3caecdbd8a67')) @patch('jnpr.junos.Device.execute') def test_sw_safe_copy_return_false(self, mock_execute): # not passing checksum value, will get random from magicmock mock_execute.side_effect = self._mock_manager package = 'safecopy.tgz' self.sw.put = MagicMock() SW.local_md5 = MagicMock() self.assertFalse( self.sw.safe_copy(package, progress=self._myprogress, cleanfs=True)) SW.local_md5.assert_called_with(package) @patch('jnpr.junos.Device.execute') def test_sw_safe_copy_checksum_none(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'safecopy.tgz' self.sw.put = MagicMock() SW.local_md5 = MagicMock( return_value='96a35ab371e1ca10408c3caecdbd8a67') self.assertTrue( self.sw.safe_copy(package, progress=self._myprogress, cleanfs=True)) @patch('jnpr.junos.Device.execute') def test_sw_safe_install(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'install.tgz' self.sw.put = MagicMock() SW.local_md5 = MagicMock( return_value='96a35ab371e1ca10408c3caecdbd8a67') self.assertTrue( self.sw.install(package, progress=self._myprogress, cleanfs=True)) @patch('jnpr.junos.utils.sw.SW.safe_copy') def test_sw_safe_install_copy_fail(self, mock_copy): mock_copy.return_value = False self.assertFalse(self.sw.install('file')) @patch('jnpr.junos.utils.sw.SW.validate') def test_sw_install_validate(self, mock_validate): mock_validate.return_value = False self.assertFalse(self.sw.install('file', validate=True, no_copy=True)) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_multi_mx(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._multi_RE = True self.sw._multi_MX = True self.assertTrue(self.sw.install('file', no_copy=True)) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_multi_vc(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._multi_RE = True self.sw._multi_VC = True self.sw._RE_list = ('version_RE0', 'version_RE1') self.assertTrue(self.sw.install('file', no_copy=True)) @patch('jnpr.junos.Device.execute') def test_sw_install_kwargs_force_host(self, mock_execute): self.sw.install('file', no_copy=True, force_host=True) rpc = """<request-package-add><force-host/><no-validate/><package-name>/var/tmp/file</package-name></request-package-add>""" self.assertEqual(etree.tostring(mock_execute.call_args[0][0]), rpc) @patch('jnpr.junos.Device.execute') def test_sw_rollback(self, mock_execute): rsp = '<rpc-reply><output>junos-vsrx-12.1X46-D30.2-domestic will become active at next reboot</output></rpc-reply>' mock_execute.side_effect = etree.XML(rsp) msg = 'junos-vsrx-12.1X46-D30.2-domestic will become active at next reboot' self.assertEqual(self.sw.rollback(), msg) @patch('jnpr.junos.Device.execute') def test_sw_rollback_multi(self, mock_execute): mock_execute.side_effect = self._mock_manager msg = '{\'fpc1\': "Junos version \'D10.2\' will become active at next reboot", \'fpc0\': \'JUNOS version "D10.2" will become active at next reboot\'}' self.assertEqual(self.sw.rollback(), msg) @patch('jnpr.junos.Device.execute') def test_sw_rollback_multi_exception(self, mock_execute): fname = 'request-package-rollback-multi-error.xml' mock_execute.side_effect = self._read_file(fname) self.assertRaises(SwRollbackError, self.sw.rollback) @patch('jnpr.junos.Device.execute') def test_sw_rollback_exception(self, mock_execute): rsp = '<rpc-reply><output>WARNING: Cannot rollback, /packages/junos.old is not valid</output></rpc-reply>' mock_execute.side_effect = etree.XML(rsp) self.assertRaises(SwRollbackError, self.sw.rollback) def test_sw_inventory(self): self.sw.dev.rpc.file_list = \ MagicMock(side_effect=self._mock_manager) self.assertEqual(self.sw.inventory, { 'current': None, 'rollback': None }) @patch('jnpr.junos.Device.execute') def test_sw_reboot(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_MX = True self.assertTrue('Shutdown NOW' in self.sw.reboot()) @patch('jnpr.junos.Device.execute') def test_sw_reboot_at(self, mock_execute): mock_execute.side_effect = self._mock_manager self.assertTrue('Shutdown at' in self.sw.reboot(at='201407091815')) @patch('jnpr.junos.Device.execute') def test_sw_reboot_multi_re_vc(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_RE = True self.sw._multi_VC = False self.assertTrue('Shutdown NOW' in self.sw.reboot()) @patch('jnpr.junos.Device.execute') def test_sw_reboot_exception(self, mock_execute): rsp = etree.XML('<rpc-reply><a>test</a></rpc-reply>') mock_execute.side_effect = RpcError(rsp=rsp) self.assertRaises(Exception, self.sw.reboot) @patch('jnpr.junos.Device.execute') def test_sw_poweroff(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_MX = True self.assertTrue('Shutdown NOW' in self.sw.poweroff()) @patch('jnpr.junos.Device.execute') def test_sw_poweroff_exception(self, mock_execute): rsp = etree.XML('<rpc-reply><a>test</a></rpc-reply>') mock_execute.side_effect = RpcError(rsp=rsp) self.assertRaises(Exception, self.sw.poweroff) @patch('jnpr.junos.Device.execute') def test_sw_poweroff_multi_re_vc(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_RE = True self.sw._multi_VC = False self.assertTrue('Shutdown NOW' in self.sw.poweroff()) def _myprogress(self, dev, report): pass @contextmanager def capture(self, command, *args, **kwargs): out, sys.stdout = sys.stdout, StringIO() command(*args, **kwargs) sys.stdout.seek(0) yield sys.stdout.read() sys.stdout = out def _read_file(self, fname): from ncclient.xml_ import NCElement fpath = os.path.join(os.path.dirname(__file__), 'rpc-reply', fname) foo = open(fpath).read() rpc_reply = NCElement(foo, self.dev._conn._device_handler.transform_reply() )._NCElement__doc[0] return rpc_reply def _mock_manager(self, *args, **kwargs): if kwargs: # Little hack for mocked execute if kwargs == {'dev_timeout': 1800}: return self._read_file(args[0].tag + '.xml') if 'path' in kwargs: if kwargs['path'] == '/packages': return self._read_file('file-list_dir.xml') device_params = kwargs['device_params'] device_handler = make_device_handler(device_params) session = SSHSession(device_handler) return Manager(session, device_handler) elif args: if args[0].find('at') is not None: return self._read_file('request-reboot-at.xml') else: return self._read_file(args[0].tag + '.xml')
class TestSW(unittest.TestCase): @patch("ncclient.manager.connect") def setUp(self, mock_connect): mock_connect.side_effect = self._mock_manager self.dev = Device(host="1.1.1.1", user="******", password="******", gather_facts=False) self.dev.open() self.dev.facts = facts self.sw = self.get_sw() @patch("jnpr.junos.Device.execute") def get_sw(self, mock_execute): mock_execute.side_effect = self._mock_manager return SW(self.dev) @patch("ncclient.operations.session.CloseSession.request") def tearDown(self, mock_session): self.dev.close() def test_sw_hashfile(self): with patch(builtin_string + ".open", mock_open(), create=True): import jnpr.junos.utils.sw with open("foo") as h: h.read.side_effect = ("abc", "a", "") jnpr.junos.utils.sw._hashfile(h, MagicMock()) self.assertEqual(h.read.call_count, 3) @patch("jnpr.junos.Device.execute") def test_sw_constructor_multi_re(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw = SW(self.dev) self.assertTrue(self.sw._multi_RE) @patch("jnpr.junos.Device.execute") def test_sw_constructor_multi_vc(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw = SW(self.dev) self.assertFalse(self.sw._multi_VC) @patch(builtin_string + ".open") def test_sw_local_sha256(self, mock_built_open): package = "test.tgz" self.assertEqual( SW.local_checksum(package, algorithm="sha256"), "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934" "ca495991b7852b855", ) @patch(builtin_string + ".open") def test_sw_local_md5(self, mock_built_open): package = "test.tgz" self.assertEqual( self.sw.local_checksum(package, algorithm="md5"), "d41d8cd98f00b204e9800998ecf8427e", ) @patch(builtin_string + ".open") def test_sw_local_sha1(self, mock_built_open): package = "test.tgz" self.assertEqual( SW.local_checksum(package, algorithm="sha1"), "da39a3ee5e6b4b0d3255bfef95601890afd80709", ) def test_sw_local_checksum_unknown_alg(self): self.assertRaises(ValueError, SW.local_checksum, "foo.tgz", algorithm="foo") def test_sw_progress(self): with self.capture(SW.progress, self.dev, "running") as output: self.assertEqual("1.1.1.1: running\n", output) @patch("jnpr.junos.Device.execute") @patch("paramiko.SSHClient") @patch("scp.SCPClient.put") def test_sw_progress_true(self, scp_put, mock_paramiko, mock_execute): mock_execute.side_effect = self._mock_manager with self.capture(SW.progress, self.dev, "testing") as output: self.sw.install("test.tgz", progress=True, checksum=345, cleanfs=False) self.assertEqual("1.1.1.1: testing\n", output) @patch("paramiko.SSHClient") @patch("scp.SCPClient.put") def test_sw_put(self, mock_scp_put, mock_scp): package = "test.tgz" self.sw.put(package) self.assertTrue( call("test.tgz", "/var/tmp") in mock_scp_put.mock_calls) @patch("jnpr.junos.utils.sw.FTP") def test_sw_put_ftp(self, mock_ftp_put): dev = Device( host="1.1.1.1", user="******", password="******", mode="telnet", port=23, gather_facts=False, ) dev.facts = facts sw = SW(dev) sw.put(package="test.tgz") self.assertTrue( call("test.tgz", "/var/tmp") in mock_ftp_put.mock_calls) @patch("jnpr.junos.utils.scp.SCP.__exit__") @patch("jnpr.junos.utils.scp.SCP.__init__") @patch("jnpr.junos.utils.scp.SCP.__enter__") def test_sw_put_progress(self, mock_enter, mock_scp, mock_exit): package = "test.tgz" mock_scp.side_effect = self._fake_scp with self.capture(self.sw.put, package, progress=self._my_scp_progress) as output: self.assertEqual("test.tgz 100 50\n", output) def _fake_scp(self, *args, **kwargs): progress = kwargs["progress"] progress("test.tgz", 100, 50) @patch("jnpr.junos.Device.execute") def test_sw_pkgadd(self, mock_execute): mock_execute.side_effect = self._mock_manager package = "test.tgz" self.assertTrue(self.sw.pkgadd(package)) @patch("jnpr.junos.Device.execute") @patch("jnpr.junos.utils.sw.SW.local_md5") def test_sw_install_url_in_pkg_set(self, mock_md5, mock_execute): mock_md5.return_value = "96a35ab371e1ca10408c3caecdbd8a67" mock_execute.side_effect = self._mock_manager self.sw.put = MagicMock() self.sw._mixed_VC = True self.assertTrue( self.sw.install(pkg_set=[ "safecopy.tgz", "safecopy.tgz", "ftp://server/path/test.tgz" ])) @patch("jnpr.junos.Device.execute") def test_sw_install_via_url(self, mock_execute): mock_execute.side_effect = self._mock_manager self.assertTrue(self.sw.install(package="ftp://server/path/test.tgz")) @patch("jnpr.junos.Device.execute") def test_sw_install_single_re_on_multi_re(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_RE = True self.assertTrue(self.sw.install("test.tgz", all_re=False, no_copy=True)) @patch("jnpr.junos.Device.execute") def test_sw_install_single_re(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_RE = False self.assertTrue(self.sw.install("test.tgz", no_copy=True)) @patch("jnpr.junos.Device.execute") def test_sw_install_srx_branch_cluster(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_RE = False self.sw._dev.facts["personality"] = "SRX_BRANCH" self.sw._dev.facts["srx_cluster"] = True self.assertTrue(self.sw.install("test.tgz", no_copy=True)) @patch("jnpr.junos.Device.execute") def test_sw_install_no_package_result(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_RE = False self.assertTrue(self.sw.install("test_no_result.tgz", no_copy=True)) @patch("jnpr.junos.Device.execute") def test_sw_install_issu(self, mock_execute): mock_execute.side_effect = self._mock_manager package = "test.tgz" self.assertTrue(self.sw.install(package, issu=True, no_copy=True)) @patch("jnpr.junos.Device.execute") def test_sw_install_nssu(self, mock_execute): mock_execute.side_effect = self._mock_manager package = "test.tgz" self.assertTrue(self.sw.install(package, nssu=True, no_copy=True)) @patch("jnpr.junos.Device.execute") def test_sw_install_issu_nssu_both_error(self, mock_execute): mock_execute.side_effect = self._mock_manager try: self.sw.install("test.tgz", issu=True, nssu=True) except TypeError as ex: self.assertEqual( str(ex), "install function can either take issu or nssu not both") @patch("jnpr.junos.Device.execute") def test_sw_install_issu_single_re_error(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_RE = False try: self.sw.install("test.tgz", issu=True) except TypeError as ex: self.assertEqual(str(ex), "ISSU/NSSU requires Multi RE setup") @patch("jnpr.junos.Device.execute") def test_sw_install_issu_nssu_single_re_error(self, mock_execute): mock_execute.side_effect = self._mock_manager package = "test.tgz" self.sw._multi_RE = False self.assertRaises(TypeError, self.sw.install, package, nssu=True, issu=True) @patch("jnpr.junos.Device.execute") def test_sw_pkgaddISSU(self, mock_execute): mock_execute.side_effect = self._mock_manager package = "test.tgz" self.assertTrue(self.sw.pkgaddISSU(package)) @patch("jnpr.junos.Device.execute") def test_sw_pkgaddNSSU(self, mock_execute): mock_execute.side_effect = self._mock_manager package = "test.tgz" self.assertTrue(self.sw.pkgaddNSSU(package)) @patch("jnpr.junos.Device.execute") def test_sw_pkgadd_pkg_set(self, mock_execute): mock_execute.side_effect = self._mock_manager pkg_set = ["abc.tgz", "pqr.tgz"] self.sw._mixed_VC = True self.sw.pkgadd(pkg_set) self.assertEqual( [i.text for i in mock_execute.call_args[0][0].findall("set")], pkg_set) @patch("jnpr.junos.Device.execute") def test_sw_validate(self, mock_execute): mock_execute.side_effect = self._mock_manager self.assertTrue(self.sw.validate("package.tgz")) @patch("jnpr.junos.Device.execute") def test_sw_validate_nssu(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw.log = MagicMock() # get_config returns false self.assertFalse(self.sw.validate("package.tgz", nssu=True)) self.sw.log.assert_called_with( "Requirement FAILED: GRES is not Enabled in configuration") @patch("jnpr.junos.Device.execute") def test_sw_validate_issu(self, mock_execute): mock_execute.side_effect = self._mock_manager self.dev.rpc.get_config = MagicMock() self.assertTrue(self.sw.validate("package.tgz", issu=True)) @patch("jnpr.junos.Device.execute") def test_sw_val_issu_request_shell_execute_gres_on(self, mock_execute): mock_execute.side_effect = self._mock_manager self.dev.rpc.get_config = MagicMock() self.dev.rpc.request_shell_execute = MagicMock() self.dev.rpc.request_shell_execute.return_value = etree.fromstring( """<rpc-reply> <output>Graceful switchover: On</output> </rpc-reply>""") self.assertTrue(self.sw.validate("package.tgz", issu=True)) @patch("jnpr.junos.Device.execute") def test_sw_validate_issu_2re_false(self, mock_execute): mock_execute.side_effect = self._mock_manager self.dev.facts["2RE"] = False self.assertFalse(self.sw.validate("package.tgz", issu=True)) self.dev.facts["2RE"] = True @patch("paramiko.SSHClient") @patch("jnpr.junos.utils.start_shell.StartShell.wait_for") def test_sw_validate_issu_request_shell_execute(self, mock_ss, mock_ssh): self._issu_test_helper() with patch("jnpr.junos.utils.start_shell.StartShell.run") as ss: ss.return_value = (True, "Graceful switchover: On") self.assertTrue(self.sw.validate("package.tgz", issu=True)) @patch("paramiko.SSHClient") @patch("jnpr.junos.utils.start_shell.StartShell.wait_for") def test_sw_validate_issu_ss_login_other_re_fail(self, mock_ss, mock_ssh): self._issu_test_helper() with patch("jnpr.junos.utils.start_shell.StartShell.run") as ss: ss.return_value = (False, "Graceful switchover: On") self.assertFalse(self.sw.validate("package.tgz", issu=True)) self.sw.log.assert_called_with( 'Requirement FAILED: Not able run "show system switchover"') @patch("paramiko.SSHClient") @patch("jnpr.junos.utils.start_shell.StartShell.wait_for") def test_sw_validate_issu_ss_graceful_off(self, mock_ss, mock_ssh): self._issu_test_helper() with patch("jnpr.junos.utils.start_shell.StartShell.run") as ss: ss.return_value = (True, "Graceful switchover: Off") self.assertFalse(self.sw.validate("package.tgz", issu=True)) self.sw.log.assert_called_with( "Requirement FAILED: Graceful switchover status is not On") def _issu_test_helper(self): self.sw.log = MagicMock() self.dev.rpc.request_shell_execute = MagicMock() self.dev.rpc = MagicMock() self.dev.rpc.get_routing_task_replication_state.return_value = self._read_file( "get-routing-task-replication-state.xml") self.dev.rpc.check_in_service_upgrade.return_value = self._read_file( "check-in-service-upgrade.xml") self.dev.rpc.request_shell_execute.side_effect = RpcError(rsp="not ok") @patch("jnpr.junos.Device.execute") def test_sw_validate_issu_stateful_replication_off(self, mock_execute): mock_execute.side_effect = self._mock_manager self.dev.rpc.get_config = MagicMock() self.dev.rpc.get_routing_task_replication_state = MagicMock() self.sw.log = MagicMock() self.assertFalse(self.sw.validate("package.tgz", issu=True)) self.sw.log.assert_called_with( "Requirement FAILED: Either Stateful Replication is not Enabled " "or RE mode\nis not Master") @patch("jnpr.junos.Device.execute") def test_sw_validate_issu_commit_sync_off(self, mock_execute): mock_execute.side_effect = self._mock_manager self.dev.rpc.get_config = MagicMock() self.dev.rpc.get_config.return_value = etree.fromstring(""" <configuration> <chassis> <redundancy> <graceful-switchover> </graceful-switchover> </redundancy> </chassis> </configuration>""") self.sw.log = MagicMock() self.assertFalse(self.sw.validate("package.tgz", issu=True)) self.sw.log.assert_called_with( "Requirement FAILED: commit synchronize is not Enabled " "in configuration") @patch("jnpr.junos.Device.execute") def test_sw_validate_issu_nonstop_routing_off(self, mock_execute): mock_execute.side_effect = self._mock_manager self.dev.rpc.get_config = MagicMock() self.dev.rpc.get_config.side_effect = iter([ etree.fromstring(""" <configuration> <chassis> <redundancy> <graceful-switchover> </graceful-switchover> </redundancy> </chassis> </configuration>"""), etree.fromstring(""" <configuration> <system> <commit> <synchronize/> </commit> </system> </configuration>"""), etree.fromstring("""<configuration> <routing-options></routing-options> </configuration>"""), ]) self.sw.log = MagicMock() self.assertFalse(self.sw.validate("package.tgz", issu=True)) self.sw.log.assert_called_with( "Requirement FAILED: NSR is not Enabled in configuration") @patch("jnpr.junos.Device.execute") def test_sw_validate_issu_validation_succeeded(self, mock_execute): rpc_reply = """<rpc-reply><output>mgd: commit complete Validation succeeded </output> <package-result>1</package-result> </rpc-reply>""" mock_execute.side_effect = etree.fromstring(rpc_reply) package = "package.tgz" self.assertFalse(self.sw.validate(package, issu=True)) @patch("jnpr.junos.Device.execute") def test_sw_remote_checksum_not_found(self, mock_execute): xml = """<rpc-error> <error-severity>error</error-severity> <error-message> md5: /var/tmp/123: No such file or directory </error-message> </rpc-error>""" mock_execute.side_effect = RpcError(rsp=etree.fromstring(xml)) package = "test.tgz" self.assertEqual(self.sw.remote_checksum(package), None) @patch("jnpr.junos.Device.execute") def test_sw_remote_checksum_not_rpc_error(self, mock_execute): xml = """<rpc-error> <error-severity>error</error-severity> <error-message> something else! </error-message> </rpc-error>""" mock_execute.side_effect = RpcError(rsp=etree.fromstring(xml)) package = "test.tgz" with self.assertRaises(RpcError): self.sw.remote_checksum(package) @patch("jnpr.junos.Device.execute") def test_sw_remote_checksum_md5(self, mock_execute): xml = """<rpc-reply> <checksum-information> <file-checksum> <computation-method>MD5</computation-method> <input-file>/var/tmp/foo.tgz</input-file> <checksum>8a04cfc475e21507be5145bc0e82ce09</checksum> </file-checksum> </checksum-information> </rpc-reply>""" mock_execute.side_effect = etree.fromstring(xml) package = "foo.tgz" self.assertEqual(self.sw.remote_checksum(package), "8a04cfc475e21507be5145bc0e82ce09") @patch("jnpr.junos.Device.execute") def test_sw_remote_checksum_sha1(self, mock_execute): xml = """ <rpc-reply> <checksum-information> <file-checksum> <computation-method>SHA1</computation-method> <input-file>/var/tmp/foo.tgz</input-file> <checksum>33c12913e81599452270ee849511e2e7578db00c</checksum> </file-checksum> </checksum-information> </rpc-reply>""" mock_execute.side_effect = etree.fromstring(xml) package = "foo.tgz" self.assertEqual( self.sw.remote_checksum(package, algorithm="sha1"), "33c12913e81599452270ee849511e2e7578db00c", ) @patch("jnpr.junos.Device.execute") def test_sw_remote_checksum_sha256(self, mock_execute): xml = """ <rpc-reply> <checksum-information> <file-checksum> <computation-method>SHA256</computation-method> <input-file>/var/tmp/foo.tgz</input-file> <checksum>27bccf64babe4ea6687d3461e6d724d165aa140933e77b582af615dad4f02170</checksum> </file-checksum> </checksum-information> </rpc-reply>""" mock_execute.side_effect = etree.fromstring(xml) package = "foo.tgz" self.assertEqual( self.sw.remote_checksum(package, algorithm="sha256"), "27bccf64babe4ea6687d3461e6d724d165aa140933e77b582af615dad4f02170", ) def test_sw_remote_checksum_unknown_alg(self): self.assertRaises(ValueError, self.sw.remote_checksum, "foo.tgz", algorithm="foo") @patch("jnpr.junos.Device.execute") def test_sw_safe_copy(self, mock_execute): mock_execute.side_effect = self._mock_manager package = "safecopy.tgz" self.sw.put = MagicMock() with patch("jnpr.junos.utils.sw.SW.local_md5"): self.assertTrue( self.sw.safe_copy( package, progress=self._myprogress, cleanfs=True, checksum="96a35ab371e1ca10408c3caecdbd8a67", )) @patch("jnpr.junos.Device.execute") @patch("jnpr.junos.utils.sw.SW.local_checksum") def test_sw_safe_copy_missing_local_file(self, mock_checksum, mock_execute): mock_execute.side_effect = self._mock_manager mock_checksum.side_effect = IOError() package = "foo.tgz" self.assertFalse( self.sw.safe_copy(package, progress=self._myprogress, cleanfs=True)) @patch("jnpr.junos.Device.execute") def test_sw_safe_copy_cleanfs_fail(self, mock_execute): mock_execute.side_effect = RpcError() package = "foo.tgz" self.assertFalse( self.sw.safe_copy( package, progress=self._myprogress, cleanfs=True, checksum="96a35ab371e1ca10408c3caecdbd8a67", )) @patch("jnpr.junos.Device.execute") def test_sw_safe_copy_return_false(self, mock_execute): # not passing checksum value, will get random from magicmock mock_execute.side_effect = self._mock_manager package = "safecopy.tgz" self.sw.put = MagicMock() with patch("jnpr.junos.utils.sw.SW.local_md5"): self.assertFalse( self.sw.safe_copy(package, progress=self._myprogress, cleanfs=True)) @patch("jnpr.junos.Device.execute") def test_sw_safe_copy_checksum_none(self, mock_execute): mock_execute.side_effect = self._mock_manager package = "safecopy.tgz" self.sw.put = MagicMock() with patch( "jnpr.junos.utils.sw.SW.local_md5", MagicMock(return_value="96a35ab371e1ca10408c3caecdbd8a67"), ): self.assertTrue( self.sw.safe_copy(package, progress=self._myprogress, cleanfs=True)) @patch("jnpr.junos.Device.execute") def test_sw_safe_install(self, mock_execute): mock_execute.side_effect = self._mock_manager package = "install.tgz" self.sw.put = MagicMock() with patch( "jnpr.junos.utils.sw.SW.local_md5", MagicMock(return_value="96a35ab371e1ca10408c3caecdbd8a67"), ): self.assertTrue( self.sw.install(package, progress=self._myprogress, cleanfs=True)) @patch("jnpr.junos.utils.sw.SW.safe_copy") def test_sw_safe_install_copy_fail(self, mock_copy): mock_copy.return_value = False self.assertFalse(self.sw.install("file")) @patch("jnpr.junos.utils.sw.SW.validate") def test_sw_install_validate(self, mock_validate): mock_validate.return_value = False self.assertFalse(self.sw.install("file", validate=True, no_copy=True)) @patch(builtin_string + ".print") @patch("jnpr.junos.utils.sw.SW.pkgadd") def test_sw_install_multi_mx(self, mock_pkgadd, mock_print): mock_pkgadd.return_value = True self.sw._multi_RE = True self.sw._multi_MX = True self.assertTrue(self.sw.install("file", no_copy=True, progress=True)) @patch("jnpr.junos.utils.sw.SW.pkgadd") def test_sw_install_multi_vc(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._multi_RE = True self.sw._multi_VC = True self.sw._RE_list = ("version_RE0", "version_RE1") self.assertTrue(self.sw.install("file", no_copy=True)) @patch("jnpr.junos.utils.sw.SW.pkgadd") def test_sw_install_mixed_vc(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._mixed_VC = True self.sw._RE_list = ("version_RE0", "version_RE1") self.assertTrue( self.sw.install(pkg_set=["abc.tgz", "pqr.tgz"], no_copy=True)) @patch("jnpr.junos.utils.sw.SW.pkgadd") def test_sw_install_multi_vc_mode_disabled(self, mock_pkgadd): mock_pkgadd.return_value = True self.dev._facts = { "2RE": True, "domain": None, "RE1": { "status": "OK", "model": "RE-EX8208", "mastership_state": "backup" }, "ifd_style": "SWITCH", "version_RE1": "12.3R7.7", "version_RE0": "12.3", "serialnumber": "XXXXXX", "fqdn": "XXXXXX", "RE0": { "status": "OK", "model": "RE-EX8208", "mastership_state": "master" }, "switch_style": "VLAN", "version": "12.3R5-S3.1", "master": "RE0", "hostname": "XXXXXX", "HOME": "/var/home/sn", "vc_mode": "Disabled", "model": "EX8208", "vc_capable": True, "personality": "SWITCH", } sw = self.get_sw() sw.install(package="abc.tgz", no_copy=True) self.assertFalse(sw._multi_VC) calls = [ call("/var/tmp/abc.tgz", dev_timeout=1800, vmhost=False, re0=True), call("/var/tmp/abc.tgz", dev_timeout=1800, re1=True, vmhost=False), ] mock_pkgadd.assert_has_calls(calls) @patch("jnpr.junos.utils.sw.SW.pkgadd") def test_sw_install_mixed_vc_with_copy(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._mixed_VC = True self.sw.put = MagicMock() self.sw.remote_checksum = MagicMock( return_value="d41d8cd98f00b204e9800998ecf8427e") self.sw._RE_list = ("version_RE0", "version_RE1") with patch( "jnpr.junos.utils.sw.SW.local_md5", MagicMock(return_value="d41d8cd98f00b204e9800998ecf8427e"), ): self.assertTrue( self.sw.install(pkg_set=["install.tgz", "install.tgz"], cleanfs=False)) @patch("jnpr.junos.utils.sw.SW.pkgadd") def test_sw_install_mixed_vc_safe_copy_false(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._mixed_VC = True self.sw.safe_copy = MagicMock(return_value=False) self.sw.remote_checksum = MagicMock( return_value="d41d8cd98f00b204e9800998ecf8427e") self.sw._RE_list = ("version_RE0", "version_RE1") with patch( "jnpr.junos.utils.sw.SW.local_md5", MagicMock(return_value="d41d8cd98f00b204e9800998ecf8427e"), ): self.assertFalse( self.sw.install(pkg_set=["install.tgz", "install.tgz"], cleanfs=False)) @patch("jnpr.junos.utils.sw.SW.pkgadd") def test_sw_install_mixed_vc_ValueError(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._mixed_VC = True self.sw.remote_checksum = MagicMock( return_value="d41d8cd98f00b204e9800998ecf8427e") self.sw._RE_list = ("version_RE0", "version_RE1") with patch( "jnpr.junos.utils.sw.SW.local_md5", MagicMock(return_value="d41d8cd98f00b204e9800998ecf8427e"), ): self.assertRaises(ValueError, self.sw.install, pkg_set="install.tgz", cleanfs=False) @patch("jnpr.junos.utils.sw.SW.pkgadd") def test_sw_install_mixed_vc_TypeError(self, mock_pkgadd): self.assertRaises(TypeError, self.sw.install, cleanfs=False) @patch("jnpr.junos.Device.execute") def test_sw_install_vmhost(self, mock_execute): mock_execute.side_effect = self._mock_manager package = "test.tgz" self.assertTrue(self.sw.install(package, no_copy=True, vmhost=True)) @patch("jnpr.junos.Device.execute") def test_sw_install_kwargs_force_host(self, mock_execute): self.sw.install("file", no_copy=True, force_host=True) rpc = [ "<request-package-add><force-host/><no-validate/><re1/><package-name>/var/tmp/file</package-name></request-package-add>", "<request-package-add><package-name>/var/tmp/file</package-name><no-validate/><force-host/><re1/></request-package-add>", "<request-package-add><package-name>/var/tmp/file</package-name><no-validate/><re1/><force-host/></request-package-add>", "<request-package-add><force-host/><no-validate/><package-name>/var/tmp/file</package-name><re1/></request-package-add>", "<request-package-add><force-host/><re1/><no-validate/><package-name>/var/tmp/file</package-name></request-package-add>", "<request-package-add><no-validate/><re1/><package-name>/var/tmp/file</package-name><force-host/></request-package-add>", "<request-package-add><no-validate/><package-name>/var/tmp/file</package-name><force-host/><re1/></request-package-add>", "<request-package-add><force-host/><package-name>/var/tmp/file</package-name><no-validate/><re1/></request-package-add>", "<request-package-add><re1/><no-validate/><package-name>/var/tmp/file</package-name><force-host/></request-package-add>", "<request-package-add><re1/><force-host/><package-name>/var/tmp/file</package-name><no-validate/></request-package-add>", "<request-package-add><re1/><package-name>/var/tmp/file</package-name><force-host/><no-validate/></request-package-add>", "<request-package-add><re1/><force-host/><no-validate/><package-name>/var/tmp/file</package-name></request-package-add>", "<request-package-add><no-validate/><force-host/><re1/><package-name>/var/tmp/file</package-name></request-package-add>", "<request-package-add><package-name>/var/tmp/file</package-name><force-host/><no-validate/><re1/></request-package-add>", "<request-package-add><no-validate/><re1/><force-host/><package-name>/var/tmp/file</package-name></request-package-add>", "<request-package-add><package-name>/var/tmp/file</package-name><force-host/><re1/><no-validate/></request-package-add>", "<request-package-add><no-validate/><force-host/><package-name>/var/tmp/file</package-name><re1/></request-package-add>", "<request-package-add><force-host/><no-validate/><package-name>/var/tmp/file</package-name></request-package-add>", "<request-package-add><force-host/><package-name>/var/tmp/file</package-name><no-validate/></request-package-add>", "<request-package-add><package-name>/var/tmp/file</package-name><no-validate/><force-host/></request-package-add>", "<request-package-add><no-validate/><force-host/><package-name>/var/tmp/file</package-name></request-package-add>", "<request-package-add><no-validate/><package-name>/var/tmp/file</package-name><force-host/></request-package-add>", "<request-package-add><package-name>/var/tmp/file</package-name><force-host/><no-validate/></request-package-add>", "<request-package-add><package-name>/var/tmp/file</package-name><re1/><no-validate/><force-host/></request-package-add>", "<request-package-add><package-name>/var/tmp/file</package-name><re1/><force-host/><no-validate/></request-package-add>", "<request-package-add><force-host/><package-name>/var/tmp/file</package-name><re1/><no-validate/></request-package-add>", "<request-package-add><re1/><package-name>/var/tmp/file</package-name><no-validate/><force-host/></request-package-add>", "<request-package-add><no-validate/><package-name>/var/tmp/file</package-name><re1/><force-host/></request-package-add>", "<request-package-add><re1/><no-validate/><force-host/><package-name>/var/tmp/file</package-name></request-package-add>", "<request-package-add><force-host/><re1/><package-name>/var/tmp/file</package-name><no-validate/></request-package-add>", ] self.assertTrue( etree.tostring(mock_execute.call_args[0][0]).decode("utf-8") in rpc) @patch("jnpr.junos.Device.execute") def test_sw_rollback(self, mock_execute): rsp = ("<rpc-reply><output>junos-vsrx-12.1X46-D30.2-domestic will " "become active at next reboot</output></rpc-reply>") mock_execute.side_effect = etree.XML(rsp) msg = "junos-vsrx-12.1X46-D30.2-domestic will become active " "at next reboot" self.assertEqual(self.sw.rollback(), msg) @patch("jnpr.junos.Device.execute") def test_sw_rollback_multi(self, mock_execute): mock_execute.side_effect = self._mock_manager msg = { "fpc1": "Junos version 'D10.2' will become active at next reboot", "fpc0": 'JUNOS version "D10.2" will become active at next reboot', } self.assertEqual(eval(self.sw.rollback()), msg) @patch("jnpr.junos.Device.execute") @unittest.skipIf(sys.platform == "win32", "will work for windows in coming days") def test_sw_rollback_multi_exception(self, mock_execute): fname = "request-package-rollback-multi-error.xml" mock_execute.side_effect = self._read_file(fname) self.assertRaises(SwRollbackError, self.sw.rollback) @patch("jnpr.junos.Device.execute") def test_sw_rollback_exception(self, mock_execute): rsp = ("<rpc-reply><output>WARNING: Cannot rollback, " "/packages/junos.old is not valid</output></rpc-reply>") mock_execute.side_effect = etree.XML(rsp) self.assertRaises(SwRollbackError, self.sw.rollback) def test_sw_inventory(self): self.sw.dev.rpc.file_list = MagicMock(side_effect=self._mock_manager) self.assertEqual(self.sw.inventory, { "current": None, "rollback": None }) @patch("jnpr.junos.Device.execute") def test_sw_reboot(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_MX = True self.assertTrue("Shutdown NOW" in self.sw.reboot()) @patch("jnpr.junos.Device.execute") def test_sw_reboot_at(self, mock_execute): mock_execute.side_effect = self._mock_manager self.assertTrue("Shutdown at" in self.sw.reboot(at="201407091815")) @patch("jnpr.junos.Device.execute") def test_sw_reboot_multi_re_vc(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_RE = True self.sw._multi_VC = False self.assertTrue("Shutdown NOW" in self.sw.reboot()) @patch("jnpr.junos.Device.execute") def test_sw_reboot_mixed_vc(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._mixed_VC = True self.sw._multi_VC = True self.sw.reboot() self.assertTrue("all-members" in ( etree.tostring(mock_execute.call_args[0][0]).decode("utf-8"))) @patch("jnpr.junos.Device.execute") def test_sw_reboot_mixed_vc_all_re_false(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._mixed_VC = True self.sw._multi_VC = True self.sw.reboot(all_re=False) self.assertTrue("all-members" not in ( etree.tostring(mock_execute.call_args[0][0]).decode("utf-8"))) @patch("jnpr.junos.Device.execute") def test_sw_reboot_exception(self, mock_execute): rsp = etree.XML("<rpc-reply><a>test</a></rpc-reply>") mock_execute.side_effect = RpcError(rsp=rsp) self.assertRaises(Exception, self.sw.reboot) @patch("jnpr.junos.Device.execute") def test_sw_reboot_exception_RpcTimeoutError(self, mock_execute): rsp = (self.dev, "request-reboot", 60) mock_execute.side_effect = RpcTimeoutError(*rsp) self.assertRaises(Exception, self.sw.reboot) @patch("jnpr.junos.Device.execute") def test_sw_poweroff(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_MX = True self.assertTrue("Shutdown NOW" in self.sw.poweroff()) @patch("jnpr.junos.Device.execute") def test_sw_poweroff_exception(self, mock_execute): rsp = etree.XML("<rpc-reply><a>test</a></rpc-reply>") mock_execute.side_effect = RpcError(rsp=rsp) self.assertRaises(Exception, self.sw.poweroff) @patch("jnpr.junos.Device.execute") def test_sw_poweroff_multi_re_vc(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_RE = True self.sw._multi_VC = False self.assertTrue("Shutdown NOW" in self.sw.poweroff()) @patch("jnpr.junos.Device.execute") def test_sw_check_pending_install(self, mock_execute): mock_execute.side_effect = self._mock_manager package = "test.tgz" self.assertFalse(self.sw.install(package)) @patch("jnpr.junos.utils.sw.SW.pkgadd") def test_sw_check_pending_install_RpcError_continue(self, mock_pkgadd): mock_pkgadd.return_value = True self.assertTrue(self.sw.install("test.tgz", no_copy=True)) def _myprogress(self, dev, report): pass def _my_scp_progress(self, _path, _total, _xfrd): print(_path, _total, _xfrd) @contextmanager def capture(self, command, *args, **kwargs): out, sys.stdout = sys.stdout, StringIO() command(*args, **kwargs) sys.stdout.seek(0) yield sys.stdout.read() sys.stdout = out def _read_file(self, fname): from ncclient.xml_ import NCElement fpath = os.path.join(os.path.dirname(__file__), "rpc-reply", fname) foo = open(fpath).read() rpc_reply = NCElement(foo, self.dev._conn._device_handler.transform_reply() )._NCElement__doc[0] return rpc_reply def _mock_manager(self, *args, **kwargs): if kwargs and "ignore_warning" not in kwargs: # Little hack for mocked execute if "dev_timeout" in kwargs: if (args and args[0].findtext("package-name") == "/var/tmp/test_no_result.tgz"): return self._read_file(args[0].tag + ".no_result.xml") else: return self._read_file(args[0].tag + ".xml") if "path" in kwargs: if kwargs["path"] == "/packages": return self._read_file("file-list_dir.xml") device_params = kwargs["device_params"] device_handler = make_device_handler(device_params) session = SSHSession(device_handler) return Manager(session, device_handler) elif args: if args[0].find("at") is not None: return self._read_file("request-reboot-at.xml") elif self._testMethodName == "test_sw_check_pending_install": if args[0].text == "request-package-check-pending-install": return self._read_file( "request-package-check-pending-install-error.xml") elif (self._testMethodName == "test_sw_check_pending_install_RpcError_continue"): if args[0].text == "request-package-check-pending-install": xml = """<rpc-error> <error-type>protocol</error-type> <error-tag>operation-failed</error-tag> <error-severity>error</error-severity> <error-message>syntax error</error-message> <error-info> <bad-element>request-package-check-pendings-install</bad-element> </error-info> </rpc-error>""" return RpcError(rsp=etree.fromstring(xml)) else: return self._read_file(args[0].tag + ".xml")
def main(): # initialize logging logging.basicConfig(filename=logfile, level=logging.INFO, format='%(asctime)s:%(name)s: %(message)s') logging.getLogger().name = host logging.getLogger().addHandler(logging.StreamHandler()) logging.info('Information logged in {0}'.format(logfile)) # verify package1 exists if not (os.path.isfile(package1)): msg = 'Software package1 does not exist: {0}. '.format(package1) logging.error(msg) sys.exit() dev = Device(host=host, user=user, passwd=passwd) try: dev.open() except ConnectError as err: logging.error('Cannot connect to device: {0}\n'.format(err)) return # Create an instance of SW sw = SW(dev) try: logging.info( 'Starting the software upgrade process: {0}'.format(package1)) ok = True #ok = sw.install(package=package1, remote_path=remote_path,progress=update_progress, validate=validate) except Exception as err: msg = 'Unable to install software, {0}'.format(err) logging.error(msg) ok = False if ok is True: logging.info('Software installation complete. Rebooting') rsp = sw.reboot() logging.info('Upgrade pending reboot cycle, please be patient.') logging.info(rsp) else: msg = 'Unable to install software, {0}'.format(ok) logging.error(msg) #dev=None #dev = Device(host=host, user=user, passwd=passwd) # End the NETCONF session and close the connection time.sleep(20) rebootOK = False while not rebootOK: try: print("try open") time.sleep(15) rebootOK = True dev.open() except ConnectError as err: print("Not open") rebootOK = False #"--------------firmware--------------" # verify package2 exists if not (os.path.isfile(package2)): msg = 'Software package2 does not exist: {0}. '.format(package2) logging.error(msg) sys.exit() # Create an instance of SW sw = SW(dev) try: logging.info( 'Starting the software upgrade process: {0}'.format(package2)) #ok = True ok = sw.install(package=package2, remote_path=remote_path, progress=update_progress, validate=validate) except Exception as err: msg = 'Unable to install software, {0}'.format(err) logging.error(msg) ok = False if ok is True: logging.info('Software installation complete.') dev.cli("request system firmware upgrade pic pic-slot 0 fpc-slot 1") else: msg = 'Unable to install software, {0}'.format(ok) logging.error(msg) time.sleep(20) rsp = sw.reboot() print("last reboot") time.sleep(20) rebootOK = False while not rebootOK: try: print("try open") time.sleep(15) rebootOK = True dev.open() except ConnectError as err: print("Not open") rebootOK = False #dev.timeout = 600 #dev.rpc.request_snapshot(slice='alternate') #dev.cli("request system snapshot slice alternate") print "close device" dev.close()
class TestSW(unittest.TestCase): @patch('ncclient.manager.connect') def setUp(self, mock_connect): mock_connect.side_effect = self._mock_manager self.dev = Device(host='1.1.1.1', user='******', password='******', gather_facts=False) self.dev.open() self.dev._facts = facts self.sw = self.get_sw() @patch('jnpr.junos.Device.execute') def get_sw(self, mock_execute): mock_execute.side_effect = self._mock_manager return SW(self.dev) @patch('ncclient.operations.session.CloseSession.request') def tearDown(self, mock_session): self.dev.close() def test_sw_hashfile(self): with patch('__builtin__.open', mock_open(), create=True): import jnpr.junos.utils.sw with open('foo') as h: h.read.side_effect = ('abc', 'a', '') jnpr.junos.utils.sw._hashfile(h, MagicMock()) self.assertEqual(h.read.call_count, 3) @patch('jnpr.junos.Device.execute') def test_sw_constructor_multi_re(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw = SW(self.dev) self.assertFalse(self.sw._multi_RE) @patch('jnpr.junos.Device.execute') def test_sw_constructor_multi_vc(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw = SW(self.dev) self.assertFalse(self.sw._multi_VC) @patch('__builtin__.open') def test_sw_local_sha256(self, mock_built_open): package = 'test.tgz' self.assertEqual(SW.local_sha256(package), 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934' 'ca495991b7852b855') @patch('__builtin__.open') def test_sw_local_md5(self, mock_built_open): package = 'test.tgz' self.assertEqual(self.sw.local_md5(package), 'd41d8cd98f00b204e9800998ecf8427e') @patch('__builtin__.open') def test_sw_local_sha1(self, mock_built_open): package = 'test.tgz' self.assertEqual(SW.local_sha1(package), 'da39a3ee5e6b4b0d3255bfef95601890afd80709') def test_sw_progress(self): with self.capture(SW.progress, self.dev, 'running') as output: self.assertEqual('1.1.1.1: running\n', output) @patch('paramiko.SSHClient') @patch('scp.SCPClient.put') def test_sw_put(self, mock_scp_put, mock_scp): # mock_scp_put.side_effect = self.mock_put package = 'test.tgz' self.sw.put(package) self.assertTrue( call( 'test.tgz', '/var/tmp') in mock_scp_put.mock_calls) @patch('jnpr.junos.utils.scp.SCP.__exit__') @patch('jnpr.junos.utils.scp.SCP.__init__') @patch('jnpr.junos.utils.scp.SCP.__enter__') def test_sw_put_progress(self, mock_enter, mock_scp, mock_exit): package = 'test.tgz' mock_scp.side_effect = self._fake_scp self.sw.put(package, progress=self._myprogress) self.assertEqual(mock_scp.call_args_list[0][1]['progress'].by10pct, 50) def _fake_scp(self, *args, **kwargs): progress = kwargs['progress'] progress('test.tgz', 100, 50) @patch('jnpr.junos.Device.execute') def test_sw_pkgadd(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'test.tgz' self.assertTrue(self.sw.pkgadd(package)) @patch('jnpr.junos.Device.execute') def test_sw_pkgadd_pkg_set(self, mock_execute): mock_execute.side_effect = self._mock_manager pkg_set = ['abc.tgz', 'pqr.tgz'] self.sw._mixed_VC = True self.sw.pkgadd(pkg_set) self.assertEqual([i.text for i in mock_execute.call_args[0][0].findall('set')], pkg_set) @patch('jnpr.junos.Device.execute') def test_sw_validate(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'package.tgz' self.assertTrue(self.sw.validate(package)) @patch('jnpr.junos.Device.execute') def test_sw_safe_copy(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'safecopy.tgz' self.sw.put = MagicMock() with patch('jnpr.junos.utils.sw.SW.local_md5'): self.assertTrue(self.sw.safe_copy(package, progress=self._myprogress, cleanfs=True, checksum='96a35ab371e1ca10408c3caecdbd8a67')) @patch('jnpr.junos.Device.execute') def test_sw_safe_copy_return_false(self, mock_execute): # not passing checksum value, will get random from magicmock mock_execute.side_effect = self._mock_manager package = 'safecopy.tgz' self.sw.put = MagicMock() with patch('jnpr.junos.utils.sw.SW.local_md5'): self.assertFalse(self.sw.safe_copy(package, progress=self._myprogress, cleanfs=True)) @patch('jnpr.junos.Device.execute') def test_sw_safe_copy_checksum_none(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'safecopy.tgz' self.sw.put = MagicMock() with patch('jnpr.junos.utils.sw.SW.local_md5', MagicMock(return_value='96a35ab371e1ca10408c3caecdbd8a67')): self.assertTrue(self.sw.safe_copy(package, progress=self._myprogress, cleanfs=True)) @patch('jnpr.junos.Device.execute') def test_sw_safe_install(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'install.tgz' self.sw.put = MagicMock() with patch('jnpr.junos.utils.sw.SW.local_md5', MagicMock(return_value='96a35ab371e1ca10408c3caecdbd8a67')): self.assertTrue( self.sw.install( package, progress=self._myprogress, cleanfs=True)) @patch('jnpr.junos.utils.sw.SW.safe_copy') def test_sw_safe_install_copy_fail(self, mock_copy): mock_copy.return_value = False self.assertFalse(self.sw.install('file')) @patch('jnpr.junos.utils.sw.SW.validate') def test_sw_install_validate(self, mock_validate): mock_validate.return_value = False self.assertFalse(self.sw.install('file', validate=True, no_copy=True)) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_multi_mx(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._multi_RE = True self.sw._multi_MX = True self.assertTrue(self.sw.install('file', no_copy=True)) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_multi_vc(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._multi_RE = True self.sw._multi_VC = True self.sw._RE_list = ('version_RE0', 'version_RE1') self.assertTrue(self.sw.install('file', no_copy=True)) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_mixed_vc(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._mixed_VC = True self.sw._RE_list = ('version_RE0', 'version_RE1') self.assertTrue(self.sw.install(pkg_set=['abc.tgz', 'pqr.tgz'], no_copy=True)) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_mixed_vc_with_copy(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._mixed_VC = True self.sw.put = MagicMock() self.sw.remote_checksum = MagicMock( return_value='d41d8cd98f00b204e9800998ecf8427e') self.sw._RE_list = ('version_RE0', 'version_RE1') with patch('jnpr.junos.utils.sw.SW.local_md5', MagicMock(return_value='d41d8cd98f00b204e9800998ecf8427e')): self.assertTrue( self.sw.install( pkg_set=[ 'install.tgz', 'install.tgz'], cleanfs=False)) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_mixed_vc_safe_copy_false(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._mixed_VC = True self.sw.safe_copy = MagicMock(return_value=False) self.sw.remote_checksum = MagicMock( return_value='d41d8cd98f00b204e9800998ecf8427e') self.sw._RE_list = ('version_RE0', 'version_RE1') with patch('jnpr.junos.utils.sw.SW.local_md5', MagicMock(return_value='d41d8cd98f00b204e9800998ecf8427e')): self.assertFalse( self.sw.install( pkg_set=[ 'install.tgz', 'install.tgz'], cleanfs=False)) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_mixed_vc_ValueError(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._mixed_VC = True self.sw.remote_checksum = MagicMock( return_value='d41d8cd98f00b204e9800998ecf8427e') self.sw._RE_list = ('version_RE0', 'version_RE1') with patch('jnpr.junos.utils.sw.SW.local_md5', MagicMock(return_value='d41d8cd98f00b204e9800998ecf8427e')): self.assertRaises( ValueError, self.sw.install, pkg_set='install.tgz', cleanfs=False) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_mixed_vc_TypeError(self, mock_pkgadd): self.assertRaises(TypeError, self.sw.install, cleanfs=False) @patch('jnpr.junos.Device.execute') def test_sw_install_kwargs_force_host(self, mock_execute): self.sw.install('file', no_copy=True, force_host=True) rpc = """<request-package-add><force-host/><no-validate/><package-name>/var/tmp/file</package-name></request-package-add>""" self.assertEqual(etree.tostring(mock_execute.call_args[0][0]), rpc) @patch('jnpr.junos.Device.execute') def test_sw_rollback(self, mock_execute): rsp = '<rpc-reply><output>junos-vsrx-12.1X46-D30.2-domestic will become active at next reboot</output></rpc-reply>' mock_execute.side_effect = etree.XML(rsp) msg = 'junos-vsrx-12.1X46-D30.2-domestic will become active at next reboot' self.assertEqual(self.sw.rollback(), msg) @patch('jnpr.junos.Device.execute') def test_sw_rollback_multi(self, mock_execute): mock_execute.side_effect = self._mock_manager msg = '{\'fpc1\': "Junos version \'D10.2\' will become active at next reboot", \'fpc0\': \'JUNOS version "D10.2" will become active at next reboot\'}' self.assertEqual(self.sw.rollback(), msg) @patch('jnpr.junos.Device.execute') def test_sw_rollback_multi_exception(self, mock_execute): fname = 'request-package-rollback-multi-error.xml' mock_execute.side_effect = self._read_file(fname) self.assertRaises(SwRollbackError, self.sw.rollback) @patch('jnpr.junos.Device.execute') def test_sw_rollback_exception(self, mock_execute): rsp = '<rpc-reply><output>WARNING: Cannot rollback, /packages/junos.old is not valid</output></rpc-reply>' mock_execute.side_effect = etree.XML(rsp) self.assertRaises(SwRollbackError, self.sw.rollback) def test_sw_inventory(self): self.sw.dev.rpc.file_list = \ MagicMock(side_effect=self._mock_manager) self.assertEqual( self.sw.inventory, { 'current': None, 'rollback': None}) @patch('jnpr.junos.Device.execute') def test_sw_reboot(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_MX = True self.assertTrue('Shutdown NOW' in self.sw.reboot()) @patch('jnpr.junos.Device.execute') def test_sw_reboot_at(self, mock_execute): mock_execute.side_effect = self._mock_manager self.assertTrue('Shutdown at' in self.sw.reboot(at='201407091815')) @patch('jnpr.junos.Device.execute') def test_sw_reboot_multi_re_vc(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_RE = True self.sw._multi_VC = False self.assertTrue('Shutdown NOW' in self.sw.reboot()) @patch('jnpr.junos.Device.execute') def test_sw_reboot_mixed_vc(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._mixed_VC = True self.sw.reboot() self.assertTrue('all-members' in etree.tostring(mock_execute.call_args[0][0])) @patch('jnpr.junos.Device.execute') def test_sw_reboot_exception(self, mock_execute): rsp = etree.XML('<rpc-reply><a>test</a></rpc-reply>') mock_execute.side_effect = RpcError(rsp=rsp) self.assertRaises(Exception, self.sw.reboot) @patch('jnpr.junos.Device.execute') def test_sw_reboot_exception_RpcTimeoutError(self, mock_execute): rsp = (self.dev, 'request-reboot', 60) mock_execute.side_effect = RpcTimeoutError(*rsp) self.assertRaises(Exception, self.sw.reboot) @patch('jnpr.junos.Device.execute') def test_sw_poweroff(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_MX = True self.assertTrue('Shutdown NOW' in self.sw.poweroff()) @patch('jnpr.junos.Device.execute') def test_sw_poweroff_exception(self, mock_execute): rsp = etree.XML('<rpc-reply><a>test</a></rpc-reply>') mock_execute.side_effect = RpcError(rsp=rsp) self.assertRaises(Exception, self.sw.poweroff) @patch('jnpr.junos.Device.execute') def test_sw_poweroff_multi_re_vc(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_RE = True self.sw._multi_VC = False self.assertTrue('Shutdown NOW' in self.sw.poweroff()) def _myprogress(self, dev, report): pass @contextmanager def capture(self, command, *args, **kwargs): out, sys.stdout = sys.stdout, StringIO() command(*args, **kwargs) sys.stdout.seek(0) yield sys.stdout.read() sys.stdout = out def _read_file(self, fname): from ncclient.xml_ import NCElement fpath = os.path.join(os.path.dirname(__file__), 'rpc-reply', fname) foo = open(fpath).read() rpc_reply = NCElement( foo, self.dev._conn._device_handler.transform_reply())._NCElement__doc[0] return rpc_reply def _mock_manager(self, *args, **kwargs): if kwargs: # Little hack for mocked execute if kwargs == {'dev_timeout': 1800}: return self._read_file(args[0].tag + '.xml') if 'path' in kwargs: if kwargs['path'] == '/packages': return self._read_file('file-list_dir.xml') device_params = kwargs['device_params'] device_handler = make_device_handler(device_params) session = SSHSession(device_handler) return Manager(session, device_handler) elif args: if args[0].find('at') is not None: return self._read_file('request-reboot-at.xml') else: return self._read_file(args[0].tag + '.xml')
def reboot_device(self, ip, hostname): # Reboots a device # Status dictionary for post-upgrade reporting statusDict = {} if Menu.upgrade_list == '': statusDict['Upgrade_List'] = 'Juniper-Upgrade_' + Menu.username else: statusDict['Upgrade_List'] = Menu.upgrade_list statusDict['Upgrade_Start'] = '' statusDict['Upgrade_Finish'] = '-' statusDict['IP'] = ip statusDict['Connected'] = 'N' statusDict['OS_installed'] = '-' statusDict['Rebooted'] = 'N' statusDict['IST_Confirm_Loaded'] = '-' statusDict['IST_Confirm_Rebooted'] = '' statusDict['Comments'] = '' # Start the logging now = datetime.datetime.now() date_time = now.strftime("%Y-%m-%d-%H%M") reboot_log = Menu.log_dir + "juniper-reboot-LOG_" + date_time + "_" + Menu.username + ".log" logging.basicConfig(filename=reboot_log, level=logging.INFO, format='%(asctime)s:%(name)s: %(message)s') logging.getLogger().name = ip print('Information logged in {0}'.format(reboot_log)) # Display basic information self.do_log("Device: {0} ({1})".format(hostname, ip)) now = datetime.datetime.now() formattime = now.strftime("%Y-%m-%d %H:%M") self.do_log("Timestamp: {0}".format(formattime)) # Verify package exists before starting upgrade process dev = Device(ip, user=Menu.username, password=Menu.password) # Try to open a connection to the device try: self.do_log('\n') self.do_log( '------------------------- Opening connection to: {0} -------------------------\n' .format(ip)) self.do_log('User: {0}'.format(Menu.username)) dev.open() # If there is an error when opening the connection, display error and exit upgrade process except Exception as err: sys.stderr.write('Cannot connect to device: {0}\n'.format(err)) else: # Record connection achieved statusDict['Connected'] = 'Y' # Increase the default RPC timeout to accommodate install operations dev.timeout = 600 # Create an instance of SW sw = SW(dev) # Logging now = datetime.datetime.now() statusDict['Upgrade_Start'] = now.strftime("%Y-%m-%d %H:%M") self.do_log('Timestamp: {0}'.format(statusDict['Upgrade_Start'])) self.do_log('Beginning reboot cycle, please be patient.') # Attempt to reboot try: rsp = sw.reboot() self.do_log(rsp) except Exception as err: msg = 'Unable to reboot system, {0}'.format(err) self.do_log(msg, level='error') else: # Record reboot statusDict['Rebooted'] = 'Y' # End the NETCONF session and close the connection dev.close() self.do_log('\n') self.do_log( '------------------------- Closed connection to: {0} -------------------------\n' .format(ip)) return statusDict
from jnpr.junos import Device from jnpr.junos.utils.sw import SW import sys dev = Device('host', user='******', password='******') try: dev.open() except Exception as err: print "Unable to connect to host:", err sys.exit(1) sft = SW(dev) print sft.reboot() #print sft.reboot(in_min=5) #print ("Before Shutdown\n") #print sft.poweroff() #print ("After Shutdown\n")
class JunosDevice(BaseDevice): def __init__(self, host, username, password, *args, **kwargs): super(JunosDevice, self).__init__(host, username, password, *args, vendor='juniper', device_type=JNPR_DEVICE_TYPE, **kwargs) self.native = JunosNativeDevice(*args, host=host, user=username, passwd=password, **kwargs) self.connected = False self.open() self.cu = JunosNativeConfig(self.native) self.fs = JunosNativeFS(self.native) self.sw = JunosNativdSW(self.native) def open(self): if not self.connected: self.native.open() self.connected = True def close(self): if self.connected: self.native.close() self.connected = False def show(self, command, raw_text=True): if not raw_text: raise ValueError('Juniper only supports raw text output. \ Append " | display xml" to your commands for a structured string.') if not command.startswith('show'): raise CommandError(command, 'Juniper "show" commands must begin with "show".') return self.native.cli(command, warning=False) def show_list(self, commands, raw_text=True): responses = [] for command in commands: responses.append(self.show(command, raw_text=raw_text)) return responses def backup_running_config(self, filename): with open(filename, 'w') as f: f.write(self.running_config) def config(self, command, format='set'): try: self.cu.load(command, format=format) self.cu.commit() except ConfigLoadError as e: raise CommandError(command, e.message) def config_list(self, commands, format='set'): try: for command in commands: self.cu.load(command, format=format) self.cu.commit() except ConfigLoadError as e: raise CommandListError(commands, command, e.message) def _uptime_components(self, uptime_full_string): match_days = re.search(r'(\d+) days?', uptime_full_string) match_hours = re.search(r'(\d+) hours?', uptime_full_string) match_minutes = re.search(r'(\d+) minutes?', uptime_full_string) match_seconds = re.search(r'(\d+) seconds?', uptime_full_string) days = int(match_days.group(1)) if match_days else 0 hours = int(match_hours.group(1)) if match_hours else 0 minutes = int(match_minutes.group(1)) if match_minutes else 0 seconds = int(match_seconds.group(1)) if match_seconds else 0 return days, hours, minutes, seconds def _uptime_to_string(self, uptime_full_string): days, hours, minutes, seconds = self._uptime_components(uptime_full_string) return '%02d:%02d:%02d:%02d' % (days, hours, minutes, seconds) def _uptime_to_seconds(self, uptime_full_string): days, hours, minutes, seconds = self._uptime_components(uptime_full_string) seconds += days * 24 * 60 * 60 seconds += hours * 60 * 60 seconds += minutes * 60 return seconds def _get_interfaces(self): eth_ifaces = EthPortTable(self.native) eth_ifaces.get() loop_ifaces = LoopbackTable(self.native) loop_ifaces.get() ifaces = eth_ifaces.keys() ifaces.extend(loop_ifaces.keys()) return ifaces def checkpoint(self, filename): self.save(filename) def rollback(self, filename): self.native.timeout = 60 temp_file = NamedTemporaryFile() with SCP(self.native) as scp: scp.get(filename, local_path=temp_file.name) self.cu.load(path=temp_file.name, format='text', overwrite=True) self.cu.commit() temp_file.close() self.native.timeout = 30 @property def facts(self): if hasattr(self, '_facts'): return self._facts native_facts = self.native.facts facts = {} facts['hostname'] = native_facts['hostname'] facts['fqdn'] = native_facts['fqdn'] facts['model'] = native_facts['model'] native_uptime_string = native_facts['RE0']['up_time'] facts['uptime'] = self._uptime_to_seconds(native_uptime_string) facts['uptime_string'] = self._uptime_to_string(native_uptime_string) facts['serial_number'] = native_facts['serialnumber'] facts['interfaces'] = self._get_interfaces() for fact_key in native_facts: if fact_key.startswith('version') and fact_key != 'version_info': facts['os_version'] = native_facts[fact_key] break facts['vendor'] = self.vendor self._facts = facts return self._facts def _file_copy_local_file_exists(self, filepath): return os.path.isfile(filepath) def _file_copy_local_md5(self, filepath, blocksize=2**20): if self._file_copy_local_file_exists(filepath): m = hashlib.md5() with open(filepath, "rb") as f: buf = f.read(blocksize) while buf: m.update(buf) buf = f.read(blocksize) return m.hexdigest() def _file_copy_remote_md5(self, filename): return self.fs.checksum(filename) def file_copy_remote_exists(self, src, dest=None): if dest is None: dest = os.path.basename(src) local_hash = self._file_copy_local_md5(src) remote_hash = self._file_copy_remote_md5(dest) if local_hash is not None: if local_hash == remote_hash: return True return False def file_copy(self, src, dest=None): if dest is None: dest = os.path.basename(src) with SCP(self.native) as scp: scp.put(src, remote_path=dest) def get_boot_options(self): return self.facts['os_version'] def set_boot_options(self, sys): raise NotImplementedError def reboot(self, timer=0, confirm=False): if confirm: self.sw.reboot(in_min=timer) else: print('Need to confirm reboot with confirm=True') @property def running_config(self): return self.show('show config') def save(self, filename=None): if filename is None: self.cu.commit() return temp_file = NamedTemporaryFile() temp_file.write(self.show('show config')) temp_file.flush() with SCP(self.native) as scp: scp.put(temp_file.name, remote_path=filename) temp_file.close() return True @property def startup_config(self): return self.show('show config')
from jnpr.junos import Device from jnpr.junos.utils.sw import SW import sys dev = Device('host', user='******', password='******') try: dev.open() except Exception as err: print "Unable to connect to host:", err sys.exit(1) sft= SW(dev) print sft.reboot() #print sft.reboot(in_min=5) #print ("Before Shutdown\n") #print sft.poweroff() #print ("After Shutdown\n")
def do_junos_upgrade(router, cleanfsflag, device_address, device_username, device_password, junos_version_for_upgrade, current_re_only, copy_only): router.open() facts = dict((router.facts)) router.close() current_re_model = None if str(facts['version']) == str(junos_version_for_upgrade): print(device_address, "already is running on junos version", junos_version_for_upgrade) return 0 if 're0' in list(facts['current_re']): if dict(facts['RE0'])['model']: current_re_model = dict(facts['RE0'])['model'] else: print("Script could not fetch Model of RE0 from", device_address, "which is the current RE. Script will not upgrade", device_address, "\n") return 1 if not current_re_only: if facts['RE1']: if (str(facts['RE1']['model']) != str(current_re_model)): current_re_only = True print( "Script is logged in to RE0 of", device_address, "Either the script could not fetch the RE type of RE1 or the RE type of RE0 does not match RE1. Script will only upgrade RE0 on", device_address, "\n") if (not current_re_only) and (str(facts['RE1']['status']) != 'OK'): current_re_only = True print( "Script is logged in to RE0 of", device_address, "Status of RE1 is not \'OK\'. Script will only upgrade RE0 on", device_address, "\n") if (not current_re_only) and facts['version_RE1']: if str(facts['version_RE1']) == junos_version_for_upgrade: current_re_only = True print("Script is logged in to RE0 of", device_address, "RE1 is already running junos version", junos_version_for_upgrade, "Script will only upgrade RE0 on", device_address, "\n") else: current_re_only = True print( "Script is logged in to RE0 of", device_address, "Script could not fetch version info from RE1. Script will only upgrade RE0 on", device_address, "\n") else: current_re_only = True print( "Script is logged in to RE0 of", device_address, "Script could not fetch RE1 info. Script will only upgrade RE0 on", device_address, "\n") elif 're1' in list(facts['current_re']): if dict(facts['RE1'])['model']: current_re_model = dict(facts['RE1'])['model'] else: print("Script could not fetch Model of RE1 from", device_address, "which is the current RE. Script will not upgrade", device_address, "\n") return 1 if not current_re_only: if facts['RE0']: if (str(facts['RE0']['model']) != str(current_re_model)): current_re_only = True print( "Script is logged in to RE1 of", device_address, "Either the script could not fetch the RE type of RE0 or the RE type of RE0 does not match RE1. Script will only upgrade RE1 on", device_address, "\n") if (not current_re_only) and (str(facts['RE0']['status']) != 'OK'): current_re_only = True print( "Script is logged in to RE1 of", device_address, "Status of RE0 is not \'OK\'. Script will only upgrade RE1 on", device_address, "\n") if (not current_re_only) and facts['version_RE0']: if str(facts['version_RE0']) == junos_version_for_upgrade: current_re_only = True print("Script is logged in to RE1 of", device_address, "RE0 is already running junos version", junos_version_for_upgrade, "Script will only upgrade RE1 on", device_address, "\n") else: if (not current_re_only): current_re_only = True print( "Script is logged in to RE1 of", device_address, "Script could not fetch version info from RE0. Script will only upgrade RE1 on", device_address, "\n") else: current_re_only = True print( "Script is logged in to RE1 of", device_address, "Script could not fetch RE0 info. Script will only upgrade RE1 on", device_address, "\n") else: print( "Script could not identify current RE Model. Script will not upgrade", device_address, "\n") return 1 if not current_re_model: print( "Script could not identify current RE Model. Script will not upgrade", device_address, "\n") return 1 version_year = re.search('^(\d*)\..*$', junos_version_for_upgrade).group(1) major_version = re.search('^(\d*\.\d).*$', junos_version_for_upgrade).group(1) junos_name_format_type = None junos_name_format = None junos_image_name = None junos_image_location_format = None junos_image_path = None found_valid_image = False for format_map_key in junos_image_name_format_selector.keys(): if (junos_image_name_format_selector[format_map_key]['from'] <= int(version_year) <= junos_image_name_format_selector[format_map_key]['to']): junos_name_format_type = format_map_key if junos_name_format_type is None: print("Couldn't fetch Junos name format type. Script will not upgrade", device_address) return 1 put_version_in_format = re.compile('^(.*)(VERSION_NUMBER)(.*)$') put_version_in_image_location = re.compile( '^(.*)(MAJOR_VERSION_NUMBER)(.*)(VERSION_NUMBER)(.*)$') daily_image_format = re.compile('^(\d*\.\d)I\-(\d{8})\.(\d)\.(\d{4})$') junos_version_in_directory_path = junos_version_for_upgrade if daily_image_format.match(junos_version_for_upgrade): # for daily image junos_version_in_directory_path = daily_image_format.search( junos_version_for_upgrade).group(2) + daily_image_format.search( junos_version_for_upgrade).group( 4) + '.' + daily_image_format.search( junos_version_for_upgrade).group(3) print("Model of current RE in", device_address, "is:", current_re_model) try: junos_name_format = str( junos_image_name_format_map[junos_name_format_type] [current_re_model]) junos_image_name = put_version_in_format.sub( r"\g<1>" + str(junos_version_for_upgrade) + r"\g<3>", junos_name_format) junos_image_location_format = junos_image_location_map[ current_re_model] try: for image_path in list(junos_image_location_format): junos_image_path = put_version_in_image_location.sub( r"\g<1>" + str(major_version) + r"\g<3>" + str(junos_version_in_directory_path) + r"\g<5>", image_path) + str(junos_image_name) if (Path(junos_image_path).is_file()): print("Junos image for upgrading current RE in", device_address, "is at: ", junos_image_path) found_valid_image = True break except: print( "Error in fetching image file location for,", device_address, "from image location format configuration. Please check if correct image location format is available in script configuration file for RE Type: ", current_re_model) return 1 except: print( "Error in fetching image name for", device_address, "based on image name format configuration. Please check if correct image name format is available in script configuration file for RE Type: ", current_re_model) return 1 if not found_valid_image or not junos_image_path: print("Error in finding suitable junos image to upgrade", device_address, "Script will not upgrade", device_address) return 1 router.open() sw = SW(router) file_copy_status = 1 is_vmhost_image = False local_checksum_string = None remote_checksum_string = None checksum_matches = False if ('vmhost' in junos_image_path): is_vmhost_image = True print("Checking whether the device", device_address, "already have the junos image file", junos_image_name, "in /var/tmp/ directory") if Path(junos_image_path + '.md5').is_file(): remote_checksum_string = sw.remote_checksum('/var/tmp/' + junos_image_name, algorithm='md5') if remote_checksum_string: with open(junos_image_path + '.md5') as checksum_data: local_checksum_string = str( checksum_data.readline()).split()[0].rstrip() if remote_checksum_string == local_checksum_string: checksum_matches = True elif Path(junos_image_path + '.sha1').is_file(): remote_checksum_string = sw.remote_checksum('/var/tmp/' + junos_image_name, algorithm='sha1') if remote_checksum_string: with open(junos_image_path + '.sha1') as checksum_data: local_checksum_string = str( checksum_data.readline()).split()[0].rstrip() if remote_checksum_string == local_checksum_string: checksum_matches = True elif Path(junos_image_path + '.sha256').is_file(): remote_checksum_string = sw.remote_checksum('/var/tmp/' + junos_image_name, algorithm='sha256') if remote_checksum_string: with open(junos_image_path + '.sha256') as checksum_data: local_checksum_string = str( checksum_data.readline()).split()[0].rstrip() if remote_checksum_string == local_checksum_string: checksum_matches = True else: remote_checksum_string = sw.remote_checksum('/var/tmp/' + junos_image_name) if remote_checksum_string: local_checksum_string = sw.local_checksum(junos_image_path) if remote_checksum_string == local_checksum_string: checksum_matches = True if checksum_matches: print("Device already have the junos image file", junos_image_name, "in /var/tmp/ directory of", device_address, "Script will use this file to perform the upgrade.") file_copy_status = 0 else: print( "The device", device_address, "do not have the junos image file", junos_image_name, "in /var/tmp/ directory. Script will copy the required junos image." ) if Path(str(split_copy_path)).is_file(): print("Script will now attempt to use splitcopy.py script to copy", junos_image_path, "to", device_address) print("running command:", str(split_copy_path), junos_image_path, device_username + "@" + device_address + ":/var/tmp/", "--pwd", device_password) try: file_copy_status = subprocess.call([ str(split_copy_path), junos_image_path, device_username + "@" + device_address + ":/var/tmp/", "--pwd", device_password ], stdout=sys.stdout, stderr=subprocess.DEVNULL, timeout=900) except Exception as e: file_copy_status = 1 print("Attempt to copy the image to", device_address, "using splitcopy utility failed.") print(str(e)) if file_copy_status != 0: print( "splitcopy couldn't copy the image to", device_address, "\nScript will use junos pyEZ jnpr.junos.utls.sw.put() to copy image to device. This process will be slower." ) try: sw.put(junos_image_path, progress=True) file_copy_status = 0 except Exception as e: print(str(e)) else: print( "Scipt couldnt locate splitcopy utility. Script will use junos pyEZ jnpr.junos.utls.sw.put() to copy image to device. This process will be slower." ) try: sw.put(junos_image_path, progress=True) file_copy_status = 0 except Exception as e: print(str(e)) if file_copy_status != 0: print( "Script could not copy the required junos image file to current RE of", device_address, "Upgrade will not be performed on", device_address) router.close() return 1 if copy_only: print("Script successfully copied", junos_image_name, "to /var/tmp/ directory of", device_address) router.close() return 0 try: installation_status = sw.install(package="/var/tmp/" + junos_image_name, no_copy=True, progress=True, vmhost=is_vmhost_image, cleanfs=cleanfsflag, all_re=not (current_re_only)) if installation_status: print("Rebooting", device_address, "after junos upgrade") try: sw.reboot(all_re=not (current_re_only), vmhost=is_vmhost_image) except: pass ## Pyez throws an exception after rebooting vmhost devices. This can be removed after it is fixed. router.close() wait_for_router_online(router, 300, device_address) router.open() if str(dict(router.facts)['version']) == str( junos_version_for_upgrade): print(device_address, "was successfully upgraded to", junos_version_for_upgrade) return 0 else: print( "Script attempted upgrading", device_address, "to", junos_version_for_upgrade, "and rebooted the device. But current version is still not the target version." ) return 1 else: print( "Script could not complete installation of new junos image in ", device_address) router.close() return 1 except Exception as e: print("Script could not complete installation of new junos image in ", device_address) print(str(e)) router.close() return 1
class TestSW(unittest.TestCase): @patch('ncclient.manager.connect') def setUp(self, mock_connect): mock_connect.side_effect = self._mock_manager self.dev = Device(host='1.1.1.1', user='******', password='******', gather_facts=False) self.dev.open() self.dev._facts = facts self.sw = self.get_sw() @patch('jnpr.junos.Device.execute') def get_sw(self, mock_execute): mock_execute.side_effect = self._mock_manager return SW(self.dev) @patch('ncclient.operations.session.CloseSession.request') def tearDown(self, mock_session): self.dev.close() def test_sw_hashfile(self): with patch('__builtin__.open', mock_open(), create=True): import jnpr.junos.utils.sw with open('foo') as h: h.read.side_effect = ('abc', 'a', '') jnpr.junos.utils.sw._hashfile(h, MagicMock()) self.assertEqual(h.read.call_count, 3) @patch('jnpr.junos.Device.execute') def test_sw_constructor_multi_re(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw = SW(self.dev) self.assertFalse(self.sw._multi_RE) @patch('jnpr.junos.Device.execute') def test_sw_constructor_multi_vc(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw = SW(self.dev) self.assertFalse(self.sw._multi_VC) @patch('__builtin__.open') def test_sw_local_sha256(self, mock_built_open): package = 'test.tgz' self.assertEqual( SW.local_sha256(package), 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934' 'ca495991b7852b855') @patch('__builtin__.open') def test_sw_local_md5(self, mock_built_open): package = 'test.tgz' self.assertEqual(self.sw.local_md5(package), 'd41d8cd98f00b204e9800998ecf8427e') @patch('__builtin__.open') def test_sw_local_sha1(self, mock_built_open): package = 'test.tgz' self.assertEqual(SW.local_sha1(package), 'da39a3ee5e6b4b0d3255bfef95601890afd80709') def test_sw_progress(self): with self.capture(SW.progress, self.dev, 'running') as output: self.assertEqual('1.1.1.1: running\n', output) @patch('paramiko.SSHClient') @patch('scp.SCPClient.put') def test_sw_put(self, mock_scp_put, mock_scp): # mock_scp_put.side_effect = self.mock_put package = 'test.tgz' self.sw.put(package) self.assertTrue( call('test.tgz', '/var/tmp') in mock_scp_put.mock_calls) @patch('jnpr.junos.utils.scp.SCP.__exit__') @patch('jnpr.junos.utils.scp.SCP.__init__') @patch('jnpr.junos.utils.scp.SCP.__enter__') def test_sw_put_progress(self, mock_enter, mock_scp, mock_exit): package = 'test.tgz' mock_scp.side_effect = self._fake_scp with self.capture(self.sw.put, package, progress=self._my_scp_progress) as output: self.assertEqual('test.tgz 100 50\n', output) def _fake_scp(self, *args, **kwargs): progress = kwargs['progress'] progress('test.tgz', 100, 50) @patch('jnpr.junos.Device.execute') def test_sw_pkgadd(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'test.tgz' self.assertTrue(self.sw.pkgadd(package)) @patch('jnpr.junos.Device.execute') def test_sw_pkgadd_pkg_set(self, mock_execute): mock_execute.side_effect = self._mock_manager pkg_set = ['abc.tgz', 'pqr.tgz'] self.sw._mixed_VC = True self.sw.pkgadd(pkg_set) self.assertEqual( [i.text for i in mock_execute.call_args[0][0].findall('set')], pkg_set) @patch('jnpr.junos.Device.execute') def test_sw_validate(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'package.tgz' self.assertTrue(self.sw.validate(package)) @patch('jnpr.junos.Device.execute') def test_sw_remote_checksum_not_found(self, mock_execute): xml = '''<rpc-error> <error-severity>error</error-severity> <error-message> md5: /var/tmp/123: No such file or directory </error-message> </rpc-error>''' mock_execute.side_effect = RpcError(rsp=etree.fromstring(xml)) package = 'test.tgz' self.assertEqual(self.sw.remote_checksum(package), None) @patch('jnpr.junos.Device.execute') def test_sw_remote_checksum_not_rpc_error(self, mock_execute): xml = '''<rpc-error> <error-severity>error</error-severity> <error-message> something else! </error-message> </rpc-error>''' mock_execute.side_effect = RpcError(rsp=etree.fromstring(xml)) package = 'test.tgz' with self.assertRaises(RpcError): self.sw.remote_checksum(package) @patch('jnpr.junos.Device.execute') def test_sw_safe_copy(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'safecopy.tgz' self.sw.put = MagicMock() with patch('jnpr.junos.utils.sw.SW.local_md5'): self.assertTrue( self.sw.safe_copy(package, progress=self._myprogress, cleanfs=True, checksum='96a35ab371e1ca10408c3caecdbd8a67')) @patch('jnpr.junos.Device.execute') def test_sw_safe_copy_return_false(self, mock_execute): # not passing checksum value, will get random from magicmock mock_execute.side_effect = self._mock_manager package = 'safecopy.tgz' self.sw.put = MagicMock() with patch('jnpr.junos.utils.sw.SW.local_md5'): self.assertFalse( self.sw.safe_copy(package, progress=self._myprogress, cleanfs=True)) @patch('jnpr.junos.Device.execute') def test_sw_safe_copy_checksum_none(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'safecopy.tgz' self.sw.put = MagicMock() with patch('jnpr.junos.utils.sw.SW.local_md5', MagicMock(return_value='96a35ab371e1ca10408c3caecdbd8a67')): self.assertTrue( self.sw.safe_copy(package, progress=self._myprogress, cleanfs=True)) @patch('jnpr.junos.Device.execute') def test_sw_safe_install(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'install.tgz' self.sw.put = MagicMock() with patch('jnpr.junos.utils.sw.SW.local_md5', MagicMock(return_value='96a35ab371e1ca10408c3caecdbd8a67')): self.assertTrue( self.sw.install(package, progress=self._myprogress, cleanfs=True)) @patch('jnpr.junos.utils.sw.SW.safe_copy') def test_sw_safe_install_copy_fail(self, mock_copy): mock_copy.return_value = False self.assertFalse(self.sw.install('file')) @patch('jnpr.junos.utils.sw.SW.validate') def test_sw_install_validate(self, mock_validate): mock_validate.return_value = False self.assertFalse(self.sw.install('file', validate=True, no_copy=True)) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_multi_mx(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._multi_RE = True self.sw._multi_MX = True self.assertTrue(self.sw.install('file', no_copy=True)) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_multi_vc(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._multi_RE = True self.sw._multi_VC = True self.sw._RE_list = ('version_RE0', 'version_RE1') self.assertTrue(self.sw.install('file', no_copy=True)) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_mixed_vc(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._mixed_VC = True self.sw._RE_list = ('version_RE0', 'version_RE1') self.assertTrue( self.sw.install(pkg_set=['abc.tgz', 'pqr.tgz'], no_copy=True)) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_multi_vc_mode_disabled(self, mock_pkgadd): mock_pkgadd.return_value = True self.dev._facts = { 'domain': None, 'RE1': { 'status': 'OK', 'model': 'RE-EX8208', 'mastership_state': 'backup' }, 'ifd_style': 'SWITCH', 'version_RE1': '12.3R7.7', 'version_RE0': '12.3', '2RE': True, 'serialnumber': 'XXXXXX', 'fqdn': 'XXXXXX', 'RE0': { 'status': 'OK', 'model': 'RE-EX8208', 'mastership_state': 'master' }, 'switch_style': 'VLAN', 'version': '12.3R5-S3.1', 'master': 'RE0', 'hostname': 'XXXXXX', 'HOME': '/var/home/sn', 'vc_mode': 'Disabled', 'model': 'EX8208', 'vc_capable': True, 'personality': 'SWITCH' } sw = self.get_sw() sw.install(package='abc.tgz', no_copy=True) self.assertFalse(sw._multi_VC) calls = [ call('/var/tmp/abc.tgz', dev_timeout=1800, re0=True), call('/var/tmp/abc.tgz', dev_timeout=1800, re1=True) ] mock_pkgadd.assert_has_calls(calls) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_mixed_vc_with_copy(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._mixed_VC = True self.sw.put = MagicMock() self.sw.remote_checksum = MagicMock( return_value='d41d8cd98f00b204e9800998ecf8427e') self.sw._RE_list = ('version_RE0', 'version_RE1') with patch('jnpr.junos.utils.sw.SW.local_md5', MagicMock(return_value='d41d8cd98f00b204e9800998ecf8427e')): self.assertTrue( self.sw.install(pkg_set=['install.tgz', 'install.tgz'], cleanfs=False)) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_mixed_vc_safe_copy_false(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._mixed_VC = True self.sw.safe_copy = MagicMock(return_value=False) self.sw.remote_checksum = MagicMock( return_value='d41d8cd98f00b204e9800998ecf8427e') self.sw._RE_list = ('version_RE0', 'version_RE1') with patch('jnpr.junos.utils.sw.SW.local_md5', MagicMock(return_value='d41d8cd98f00b204e9800998ecf8427e')): self.assertFalse( self.sw.install(pkg_set=['install.tgz', 'install.tgz'], cleanfs=False)) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_mixed_vc_ValueError(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._mixed_VC = True self.sw.remote_checksum = MagicMock( return_value='d41d8cd98f00b204e9800998ecf8427e') self.sw._RE_list = ('version_RE0', 'version_RE1') with patch('jnpr.junos.utils.sw.SW.local_md5', MagicMock(return_value='d41d8cd98f00b204e9800998ecf8427e')): self.assertRaises(ValueError, self.sw.install, pkg_set='install.tgz', cleanfs=False) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_mixed_vc_TypeError(self, mock_pkgadd): self.assertRaises(TypeError, self.sw.install, cleanfs=False) @patch('jnpr.junos.Device.execute') def test_sw_install_kwargs_force_host(self, mock_execute): self.sw.install('file', no_copy=True, force_host=True) rpc = """<request-package-add><force-host/><no-validate/><package-name>/var/tmp/file</package-name></request-package-add>""" self.assertEqual(etree.tostring(mock_execute.call_args[0][0]), rpc) @patch('jnpr.junos.Device.execute') def test_sw_rollback(self, mock_execute): rsp = '<rpc-reply><output>junos-vsrx-12.1X46-D30.2-domestic will become active at next reboot</output></rpc-reply>' mock_execute.side_effect = etree.XML(rsp) msg = 'junos-vsrx-12.1X46-D30.2-domestic will become active at next reboot' self.assertEqual(self.sw.rollback(), msg) @patch('jnpr.junos.Device.execute') def test_sw_rollback_multi(self, mock_execute): mock_execute.side_effect = self._mock_manager msg = '{\'fpc1\': "Junos version \'D10.2\' will become active at next reboot", \'fpc0\': \'JUNOS version "D10.2" will become active at next reboot\'}' self.assertEqual(self.sw.rollback(), msg) @patch('jnpr.junos.Device.execute') def test_sw_rollback_multi_exception(self, mock_execute): fname = 'request-package-rollback-multi-error.xml' mock_execute.side_effect = self._read_file(fname) self.assertRaises(SwRollbackError, self.sw.rollback) @patch('jnpr.junos.Device.execute') def test_sw_rollback_exception(self, mock_execute): rsp = '<rpc-reply><output>WARNING: Cannot rollback, /packages/junos.old is not valid</output></rpc-reply>' mock_execute.side_effect = etree.XML(rsp) self.assertRaises(SwRollbackError, self.sw.rollback) def test_sw_inventory(self): self.sw.dev.rpc.file_list = \ MagicMock(side_effect=self._mock_manager) self.assertEqual(self.sw.inventory, { 'current': None, 'rollback': None }) @patch('jnpr.junos.Device.execute') def test_sw_reboot(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_MX = True self.assertTrue('Shutdown NOW' in self.sw.reboot()) @patch('jnpr.junos.Device.execute') def test_sw_reboot_at(self, mock_execute): mock_execute.side_effect = self._mock_manager self.assertTrue('Shutdown at' in self.sw.reboot(at='201407091815')) @patch('jnpr.junos.Device.execute') def test_sw_reboot_multi_re_vc(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_RE = True self.sw._multi_VC = False self.assertTrue('Shutdown NOW' in self.sw.reboot()) @patch('jnpr.junos.Device.execute') def test_sw_reboot_mixed_vc(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._mixed_VC = True self.sw.reboot() self.assertTrue( 'all-members' in etree.tostring(mock_execute.call_args[0][0])) @patch('jnpr.junos.Device.execute') def test_sw_reboot_exception(self, mock_execute): rsp = etree.XML('<rpc-reply><a>test</a></rpc-reply>') mock_execute.side_effect = RpcError(rsp=rsp) self.assertRaises(Exception, self.sw.reboot) @patch('jnpr.junos.Device.execute') def test_sw_reboot_exception_RpcTimeoutError(self, mock_execute): rsp = (self.dev, 'request-reboot', 60) mock_execute.side_effect = RpcTimeoutError(*rsp) self.assertRaises(Exception, self.sw.reboot) @patch('jnpr.junos.Device.execute') def test_sw_poweroff(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_MX = True self.assertTrue('Shutdown NOW' in self.sw.poweroff()) @patch('jnpr.junos.Device.execute') def test_sw_poweroff_exception(self, mock_execute): rsp = etree.XML('<rpc-reply><a>test</a></rpc-reply>') mock_execute.side_effect = RpcError(rsp=rsp) self.assertRaises(Exception, self.sw.poweroff) @patch('jnpr.junos.Device.execute') def test_sw_poweroff_multi_re_vc(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_RE = True self.sw._multi_VC = False self.assertTrue('Shutdown NOW' in self.sw.poweroff()) def _myprogress(self, dev, report): pass def _my_scp_progress(self, _path, _total, _xfrd): print _path, _total, _xfrd @contextmanager def capture(self, command, *args, **kwargs): out, sys.stdout = sys.stdout, StringIO() command(*args, **kwargs) sys.stdout.seek(0) yield sys.stdout.read() sys.stdout = out def _read_file(self, fname): from ncclient.xml_ import NCElement fpath = os.path.join(os.path.dirname(__file__), 'rpc-reply', fname) foo = open(fpath).read() rpc_reply = NCElement(foo, self.dev._conn._device_handler.transform_reply() )._NCElement__doc[0] return rpc_reply def _mock_manager(self, *args, **kwargs): if kwargs: # Little hack for mocked execute if 'dev_timeout' in kwargs: return self._read_file(args[0].tag + '.xml') if 'path' in kwargs: if kwargs['path'] == '/packages': return self._read_file('file-list_dir.xml') device_params = kwargs['device_params'] device_handler = make_device_handler(device_params) session = SSHSession(device_handler) return Manager(session, device_handler) elif args: if args[0].find('at') is not None: return self._read_file('request-reboot-at.xml') else: return self._read_file(args[0].tag + '.xml')
class TestSW(unittest.TestCase): @patch('ncclient.manager.connect') def setUp(self, mock_connect): mock_connect.side_effect = self._mock_manager self.dev = Device(host='1.1.1.1', user='******', password='******', gather_facts=False) self.dev.open() self.dev._facts = facts self.sw = self.get_sw() @patch('jnpr.junos.Device.execute') def get_sw(self, mock_execute): mock_execute.side_effect = self._mock_manager return SW(self.dev) @patch('ncclient.operations.session.CloseSession.request') def tearDown(self, mock_session): self.dev.close() def test_sw_hashfile(self): with patch('__builtin__.open', mock_open(), create=True): import jnpr.junos.utils.sw with open('foo') as h: h.read.side_effect = ('abc', 'a', '') jnpr.junos.utils.sw._hashfile(h, MagicMock()) self.assertEqual(h.read.call_count, 3) @patch('jnpr.junos.Device.execute') def test_sw_constructor_multi_re(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw = SW(self.dev) self.assertFalse(self.sw._multi_RE) @patch('jnpr.junos.Device.execute') def test_sw_constructor_multi_vc(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw = SW(self.dev) self.assertFalse(self.sw._multi_VC) @patch('__builtin__.open') def test_sw_local_sha256(self, mock_built_open): package = 'test.tgz' self.assertEqual(SW.local_sha256(package), 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934' 'ca495991b7852b855') @patch('__builtin__.open') def test_sw_local_md5(self, mock_built_open): package = 'test.tgz' self.assertEqual(SW.local_md5(package), 'd41d8cd98f00b204e9800998ecf8427e') @patch('__builtin__.open') def test_sw_local_sha1(self, mock_built_open): package = 'test.tgz' self.assertEqual(SW.local_sha1(package), 'da39a3ee5e6b4b0d3255bfef95601890afd80709') def test_sw_progress(self): with self.capture(SW.progress, self.dev, 'running') as output: self.assertEqual('1.1.1.1: running\n', output) @patch('paramiko.SSHClient') @patch('scp.SCPClient.put') def test_sw_put(self, mock_scp_put, mock_scp): # mock_scp_put.side_effect = self.mock_put package = 'test.tgz' self.sw.put(package) self.assertTrue(call('test.tgz', '/var/tmp') in mock_scp_put.mock_calls) @patch('jnpr.junos.utils.scp.SCP.__exit__') @patch('jnpr.junos.utils.scp.SCP.__init__') @patch('jnpr.junos.utils.scp.SCP.__enter__') def test_sw_put_progress(self, mock_enter, mock_scp, mock_exit): package = 'test.tgz' mock_scp.side_effect = self._fake_scp self.sw.put(package, progress=self._myprogress) self.assertEqual(mock_scp.call_args_list[0][1]['progress'].by10pct, 50) def _fake_scp(self, *args, **kwargs): progress = kwargs['progress'] progress('test.tgz', 100, 50) @patch('jnpr.junos.Device.execute') def test_sw_pkgadd(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'test.tgz' self.assertTrue(self.sw.pkgadd(package)) @patch('jnpr.junos.Device.execute') def test_sw_validate(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'package.tgz' self.assertTrue(self.sw.validate(package)) @patch('jnpr.junos.Device.execute') def test_sw_safe_copy(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'safecopy.tgz' self.sw.put = MagicMock() SW.local_md5 = MagicMock() self.assertTrue(self.sw.safe_copy(package, progress=self._myprogress, cleanfs=True, checksum='96a35ab371e1ca10408c3caecdbd8a67')) @patch('jnpr.junos.Device.execute') def test_sw_safe_copy_return_false(self, mock_execute): # not passing checksum value, will get random from magicmock mock_execute.side_effect = self._mock_manager package = 'safecopy.tgz' self.sw.put = MagicMock() SW.local_md5 = MagicMock() self.assertFalse(self.sw.safe_copy(package, progress=self._myprogress, cleanfs=True)) SW.local_md5.assert_called_with(package) @patch('jnpr.junos.Device.execute') def test_sw_safe_copy_checksum_none(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'safecopy.tgz' self.sw.put = MagicMock() SW.local_md5 = MagicMock(return_value='96a35ab371e1ca10408c3caecdbd8a67') self.assertTrue(self.sw.safe_copy(package, progress=self._myprogress, cleanfs=True)) @patch('jnpr.junos.Device.execute') def test_sw_safe_install(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'install.tgz' self.sw.put = MagicMock() SW.local_md5 = MagicMock(return_value='96a35ab371e1ca10408c3caecdbd8a67') self.assertTrue(self.sw.install(package, progress=self._myprogress, cleanfs=True)) @patch('jnpr.junos.utils.sw.SW.safe_copy') def test_sw_safe_install_copy_fail(self, mock_copy): mock_copy.return_value = False self.assertFalse(self.sw.install('file')) @patch('jnpr.junos.utils.sw.SW.validate') def test_sw_install_validate(self, mock_validate): mock_validate.return_value = False self.assertFalse(self.sw.install('file', validate=True, no_copy=True)) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_multi_mx(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._multi_RE = True self.sw._multi_MX = True self.assertTrue(self.sw.install('file', no_copy=True)) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_multi_vc(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._multi_RE = True self.sw._multi_VC = True self.sw._RE_list = ('version_RE0', 'version_RE1') self.assertTrue(self.sw.install('file', no_copy=True)) @patch('jnpr.junos.Device.execute') def test_sw_rollback(self, mock_execute): # we need proper xml for this test case, update request-package-roll # back.xml mock_execute.side_effect = self._mock_manager self.assertEqual(self.sw.rollback(), '') def test_sw_inventory(self): self.sw.dev.rpc.file_list = \ MagicMock(side_effect=self._mock_manager) self.assertEqual(self.sw.inventory, {'current': None, 'rollback': None}) @patch('jnpr.junos.Device.execute') def test_sw_reboot(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_MX = True self.assertTrue('Shutdown NOW' in self.sw.reboot()) @patch('jnpr.junos.Device.execute') def test_sw_reboot_multi_re_vc(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_RE = True self.sw._multi_VC = False self.assertTrue('Shutdown NOW' in self.sw.reboot()) @patch('jnpr.junos.Device.execute') def test_sw_reboot_exception(self, mock_execute): rsp = etree.XML('<rpc-reply><a>test</a></rpc-reply>') mock_execute.side_effect = RpcError(rsp=rsp) self.assertRaises(Exception, self.sw.reboot) @patch('jnpr.junos.Device.execute') def test_sw_poweroff(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_MX = True self.assertTrue('Shutdown NOW' in self.sw.poweroff()) @patch('jnpr.junos.Device.execute') def test_sw_poweroff_exception(self, mock_execute): rsp = etree.XML('<rpc-reply><a>test</a></rpc-reply>') mock_execute.side_effect = RpcError(rsp=rsp) self.assertRaises(Exception, self.sw.poweroff) @patch('jnpr.junos.Device.execute') def test_sw_poweroff_multi_re_vc(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_RE = True self.sw._multi_VC = False self.assertTrue('Shutdown NOW' in self.sw.poweroff()) def _myprogress(self, dev, report): pass @contextmanager def capture(self, command, *args, **kwargs): out, sys.stdout = sys.stdout, StringIO() command(*args, **kwargs) sys.stdout.seek(0) yield sys.stdout.read() sys.stdout = out def _read_file(self, fname): from ncclient.xml_ import NCElement fpath = os.path.join(os.path.dirname(__file__), 'rpc-reply', fname) foo = open(fpath).read() rpc_reply = NCElement(foo, self.dev._conn._device_handler.transform_reply())._NCElement__doc[0] return rpc_reply def _mock_manager(self, *args, **kwargs): if kwargs: if 'path' in kwargs: if kwargs['path'] == '/packages': return self._read_file('file-list_dir.xml') device_params = kwargs['device_params'] device_handler = make_device_handler(device_params) session = SSHSession(device_handler) return Manager(session, device_handler) elif args: return self._read_file(args[0].tag + '.xml')
class TestSW(unittest.TestCase): @patch('ncclient.manager.connect') def setUp(self, mock_connect): mock_connect.side_effect = self._mock_manager self.dev = Device(host='1.1.1.1', user='******', password='******', gather_facts=False) self.dev.open() self.dev.facts = facts self.sw = self.get_sw() @patch('jnpr.junos.Device.execute') def get_sw(self, mock_execute): mock_execute.side_effect = self._mock_manager return SW(self.dev) @patch('ncclient.operations.session.CloseSession.request') def tearDown(self, mock_session): self.dev.close() def test_sw_hashfile(self): with patch(builtin_string + '.open', mock_open(), create=True): import jnpr.junos.utils.sw with open('foo') as h: h.read.side_effect = ('abc', 'a', '') jnpr.junos.utils.sw._hashfile(h, MagicMock()) self.assertEqual(h.read.call_count, 3) @patch('jnpr.junos.Device.execute') def test_sw_constructor_multi_re(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw = SW(self.dev) self.assertTrue(self.sw._multi_RE) @patch('jnpr.junos.Device.execute') def test_sw_constructor_multi_vc(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw = SW(self.dev) self.assertFalse(self.sw._multi_VC) @patch(builtin_string + '.open') def test_sw_local_sha256(self, mock_built_open): package = 'test.tgz' self.assertEqual( SW.local_sha256(package), 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934' 'ca495991b7852b855') @patch(builtin_string + '.open') def test_sw_local_md5(self, mock_built_open): package = 'test.tgz' self.assertEqual(self.sw.local_md5(package), 'd41d8cd98f00b204e9800998ecf8427e') @patch(builtin_string + '.open') def test_sw_local_sha1(self, mock_built_open): package = 'test.tgz' self.assertEqual(SW.local_sha1(package), 'da39a3ee5e6b4b0d3255bfef95601890afd80709') def test_sw_progress(self): with self.capture(SW.progress, self.dev, 'running') as output: self.assertEqual('1.1.1.1: running\n', output) @patch('jnpr.junos.Device.execute') @patch('paramiko.SSHClient') @patch('scp.SCPClient.put') def test_sw_progress_true(self, scp_put, mock_paramiko, mock_execute): mock_execute.side_effect = self._mock_manager with self.capture(SW.progress, self.dev, 'testing') as output: self.sw.install('test.tgz', progress=True, checksum=345, cleanfs=False) self.assertEqual('1.1.1.1: testing\n', output) @patch('paramiko.SSHClient') @patch('scp.SCPClient.put') def test_sw_put(self, mock_scp_put, mock_scp): package = 'test.tgz' self.sw.put(package) self.assertTrue( call('test.tgz', '/var/tmp') in mock_scp_put.mock_calls) @patch('jnpr.junos.utils.sw.FTP') def test_sw_put_ftp(self, mock_ftp_put): dev = Device(host='1.1.1.1', user='******', password='******', mode='telnet', port=23, gather_facts=False) sw = SW(dev) sw.put(package='test.tgz') self.assertTrue( call('test.tgz', '/var/tmp') in mock_ftp_put.mock_calls) @patch('jnpr.junos.utils.scp.SCP.__exit__') @patch('jnpr.junos.utils.scp.SCP.__init__') @patch('jnpr.junos.utils.scp.SCP.__enter__') def test_sw_put_progress(self, mock_enter, mock_scp, mock_exit): package = 'test.tgz' mock_scp.side_effect = self._fake_scp with self.capture(self.sw.put, package, progress=self._my_scp_progress) as output: self.assertEqual('test.tgz 100 50\n', output) def _fake_scp(self, *args, **kwargs): progress = kwargs['progress'] progress('test.tgz', 100, 50) @patch('jnpr.junos.Device.execute') def test_sw_pkgadd(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'test.tgz' self.assertTrue(self.sw.pkgadd(package)) @patch('jnpr.junos.Device.execute') def test_sw_install_single_re(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_RE = False self.assertTrue(self.sw.install('test.tgz', no_copy=True)) @patch('jnpr.junos.Device.execute') def test_sw_install_issu(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'test.tgz' self.assertTrue(self.sw.install(package, issu=True, no_copy=True)) @patch('jnpr.junos.Device.execute') def test_sw_install_nssu(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'test.tgz' self.assertTrue(self.sw.install(package, nssu=True, no_copy=True)) @patch('jnpr.junos.Device.execute') def test_sw_install_issu_nssu_both_error(self, mock_execute): mock_execute.side_effect = self._mock_manager try: self.sw.install('test.tgz', issu=True, nssu=True) except TypeError as ex: self.assertEqual( str(ex), 'install function can either take issu or nssu not both') @patch('jnpr.junos.Device.execute') def test_sw_install_issu_single_re_error(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_RE = False try: self.sw.install('test.tgz', issu=True) except TypeError as ex: self.assertEqual(str(ex), 'ISSU/NSSU requires Multi RE setup') @patch('jnpr.junos.Device.execute') def test_sw_install_issu_nssu_single_re_error(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'test.tgz' self.sw._multi_RE = False self.assertRaises(TypeError, self.sw.install, package, nssu=True, issu=True) @patch('jnpr.junos.Device.execute') def test_sw_pkgaddISSU(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'test.tgz' self.assertTrue(self.sw.pkgaddISSU(package)) @patch('jnpr.junos.Device.execute') def test_sw_pkgaddNSSU(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'test.tgz' self.assertTrue(self.sw.pkgaddNSSU(package)) @patch('jnpr.junos.Device.execute') def test_sw_pkgadd_pkg_set(self, mock_execute): mock_execute.side_effect = self._mock_manager pkg_set = ['abc.tgz', 'pqr.tgz'] self.sw._mixed_VC = True self.sw.pkgadd(pkg_set) self.assertEqual( [i.text for i in mock_execute.call_args[0][0].findall('set')], pkg_set) @patch('jnpr.junos.Device.execute') def test_sw_validate(self, mock_execute): mock_execute.side_effect = self._mock_manager self.assertTrue(self.sw.validate('package.tgz')) @patch('jnpr.junos.Device.execute') def test_sw_validate_nssu(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw.log = MagicMock() # get_config returns false self.assertFalse(self.sw.validate('package.tgz', nssu=True)) self.sw.log.assert_called_with( 'Requirement FAILED: GRES is not Enabled in configuration') @patch('jnpr.junos.Device.execute') def test_sw_validate_issu(self, mock_execute): mock_execute.side_effect = self._mock_manager self.dev.rpc.get_config = MagicMock() self.assertTrue(self.sw.validate('package.tgz', issu=True)) @patch('jnpr.junos.Device.execute') def test_sw_val_issu_request_shell_execute_gres_on(self, mock_execute): mock_execute.side_effect = self._mock_manager self.dev.rpc.get_config = MagicMock() self.dev.rpc.request_shell_execute = MagicMock() self.dev.rpc.request_shell_execute.return_value = etree.fromstring( """<rpc-reply> <output>Graceful switchover: On</output> </rpc-reply>""") self.assertTrue(self.sw.validate('package.tgz', issu=True)) @patch('jnpr.junos.Device.execute') def test_sw_validate_issu_2re_false(self, mock_execute): mock_execute.side_effect = self._mock_manager self.dev.facts['2RE'] = False self.assertFalse(self.sw.validate('package.tgz', issu=True)) self.dev.facts['2RE'] = True @patch('paramiko.SSHClient') @patch('jnpr.junos.utils.start_shell.StartShell.wait_for') def test_sw_validate_issu_request_shell_execute(self, mock_ss, mock_ssh): self._issu_test_helper() with patch('jnpr.junos.utils.start_shell.StartShell.run') as ss: ss.return_value = (True, 'Graceful switchover: On') self.assertTrue(self.sw.validate('package.tgz', issu=True)) @patch('paramiko.SSHClient') @patch('jnpr.junos.utils.start_shell.StartShell.wait_for') def test_sw_validate_issu_ss_login_other_re_fail(self, mock_ss, mock_ssh): self._issu_test_helper() with patch('jnpr.junos.utils.start_shell.StartShell.run') as ss: ss.return_value = (False, 'Graceful switchover: On') self.assertFalse(self.sw.validate('package.tgz', issu=True)) self.sw.log.assert_called_with( 'Requirement FAILED: Not able run "show system switchover"') @patch('paramiko.SSHClient') @patch('jnpr.junos.utils.start_shell.StartShell.wait_for') def test_sw_validate_issu_ss_graceful_off(self, mock_ss, mock_ssh): self._issu_test_helper() with patch('jnpr.junos.utils.start_shell.StartShell.run') as ss: ss.return_value = (True, 'Graceful switchover: Off') self.assertFalse(self.sw.validate('package.tgz', issu=True)) self.sw.log.assert_called_with( 'Requirement FAILED: Graceful switchover status is not On') def _issu_test_helper(self): self.sw.log = MagicMock() self.dev.rpc.request_shell_execute = MagicMock() self.dev.rpc = MagicMock() self.dev.rpc.get_routing_task_replication_state.return_value = \ self._read_file('get-routing-task-replication-state.xml') self.dev.rpc.check_in_service_upgrade.return_value = \ self._read_file('check-in-service-upgrade.xml') self.dev.rpc.request_shell_execute.side_effect = \ RpcError(rsp='not ok') @patch('jnpr.junos.Device.execute') def test_sw_validate_issu_stateful_replication_off(self, mock_execute): mock_execute.side_effect = self._mock_manager self.dev.rpc.get_config = MagicMock() self.dev.rpc.get_routing_task_replication_state = MagicMock() self.sw.log = MagicMock() self.assertFalse(self.sw.validate('package.tgz', issu=True)) self.sw.log.assert_called_with( 'Requirement FAILED: Either Stateful Replication is not Enabled or RE mode\nis not Master' ) @patch('jnpr.junos.Device.execute') def test_sw_validate_issu_commit_sync_off(self, mock_execute): mock_execute.side_effect = self._mock_manager self.dev.rpc.get_config = MagicMock() self.dev.rpc.get_config.return_value = etree.fromstring(""" <configuration> <chassis> <redundancy> <graceful-switchover> </graceful-switchover> </redundancy> </chassis> </configuration>""") self.sw.log = MagicMock() self.assertFalse(self.sw.validate('package.tgz', issu=True)) self.sw.log.assert_called_with( 'Requirement FAILED: commit synchronize is not Enabled in configuration' ) @patch('jnpr.junos.Device.execute') def test_sw_validate_issu_nonstop_routing_off(self, mock_execute): mock_execute.side_effect = self._mock_manager self.dev.rpc.get_config = MagicMock() self.dev.rpc.get_config.side_effect = iter([ etree.fromstring(""" <configuration> <chassis> <redundancy> <graceful-switchover> </graceful-switchover> </redundancy> </chassis> </configuration>"""), etree.fromstring(""" <configuration> <system> <commit> <synchronize/> </commit> </system> </configuration>"""), etree.fromstring("""<configuration> <routing-options></routing-options> </configuration>""") ]) self.sw.log = MagicMock() self.assertFalse(self.sw.validate('package.tgz', issu=True)) self.sw.log.assert_called_with( 'Requirement FAILED: NSR is not Enabled in configuration') @patch('jnpr.junos.Device.execute') def test_sw_validate_issu_validation_succeeded(self, mock_execute): rpc_reply = """<rpc-reply><output>mgd: commit complete Validation succeeded </output> <package-result>1</package-result> </rpc-reply>""" mock_execute.side_effect = etree.fromstring(rpc_reply) package = 'package.tgz' self.assertFalse(self.sw.validate(package, issu=True)) @patch('jnpr.junos.Device.execute') def test_sw_remote_checksum_not_found(self, mock_execute): xml = '''<rpc-error> <error-severity>error</error-severity> <error-message> md5: /var/tmp/123: No such file or directory </error-message> </rpc-error>''' mock_execute.side_effect = RpcError(rsp=etree.fromstring(xml)) package = 'test.tgz' self.assertEqual(self.sw.remote_checksum(package), None) @patch('jnpr.junos.Device.execute') def test_sw_remote_checksum_not_rpc_error(self, mock_execute): xml = '''<rpc-error> <error-severity>error</error-severity> <error-message> something else! </error-message> </rpc-error>''' mock_execute.side_effect = RpcError(rsp=etree.fromstring(xml)) package = 'test.tgz' with self.assertRaises(RpcError): self.sw.remote_checksum(package) @patch('jnpr.junos.Device.execute') def test_sw_safe_copy(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'safecopy.tgz' self.sw.put = MagicMock() with patch('jnpr.junos.utils.sw.SW.local_md5'): self.assertTrue( self.sw.safe_copy(package, progress=self._myprogress, cleanfs=True, checksum='96a35ab371e1ca10408c3caecdbd8a67')) @patch('jnpr.junos.Device.execute') def test_sw_safe_copy_return_false(self, mock_execute): # not passing checksum value, will get random from magicmock mock_execute.side_effect = self._mock_manager package = 'safecopy.tgz' self.sw.put = MagicMock() with patch('jnpr.junos.utils.sw.SW.local_md5'): self.assertFalse( self.sw.safe_copy(package, progress=self._myprogress, cleanfs=True)) @patch('jnpr.junos.Device.execute') def test_sw_safe_copy_checksum_none(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'safecopy.tgz' self.sw.put = MagicMock() with patch('jnpr.junos.utils.sw.SW.local_md5', MagicMock(return_value='96a35ab371e1ca10408c3caecdbd8a67')): self.assertTrue( self.sw.safe_copy(package, progress=self._myprogress, cleanfs=True)) @patch('jnpr.junos.Device.execute') def test_sw_safe_install(self, mock_execute): mock_execute.side_effect = self._mock_manager package = 'install.tgz' self.sw.put = MagicMock() with patch('jnpr.junos.utils.sw.SW.local_md5', MagicMock(return_value='96a35ab371e1ca10408c3caecdbd8a67')): self.assertTrue( self.sw.install(package, progress=self._myprogress, cleanfs=True)) @patch('jnpr.junos.utils.sw.SW.safe_copy') def test_sw_safe_install_copy_fail(self, mock_copy): mock_copy.return_value = False self.assertFalse(self.sw.install('file')) @patch('jnpr.junos.utils.sw.SW.validate') def test_sw_install_validate(self, mock_validate): mock_validate.return_value = False self.assertFalse(self.sw.install('file', validate=True, no_copy=True)) @patch(builtin_string + '.print') @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_multi_mx(self, mock_pkgadd, mock_print): mock_pkgadd.return_value = True self.sw._multi_RE = True self.sw._multi_MX = True self.assertTrue(self.sw.install('file', no_copy=True, progress=True)) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_multi_vc(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._multi_RE = True self.sw._multi_VC = True self.sw._RE_list = ('version_RE0', 'version_RE1') self.assertTrue(self.sw.install('file', no_copy=True)) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_mixed_vc(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._mixed_VC = True self.sw._RE_list = ('version_RE0', 'version_RE1') self.assertTrue( self.sw.install(pkg_set=['abc.tgz', 'pqr.tgz'], no_copy=True)) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_multi_vc_mode_disabled(self, mock_pkgadd): mock_pkgadd.return_value = True self.dev._facts = { '2RE': True, 'domain': None, 'RE1': { 'status': 'OK', 'model': 'RE-EX8208', 'mastership_state': 'backup' }, 'ifd_style': 'SWITCH', 'version_RE1': '12.3R7.7', 'version_RE0': '12.3', 'serialnumber': 'XXXXXX', 'fqdn': 'XXXXXX', 'RE0': { 'status': 'OK', 'model': 'RE-EX8208', 'mastership_state': 'master' }, 'switch_style': 'VLAN', 'version': '12.3R5-S3.1', 'master': 'RE0', 'hostname': 'XXXXXX', 'HOME': '/var/home/sn', 'vc_mode': 'Disabled', 'model': 'EX8208', 'vc_capable': True, 'personality': 'SWITCH' } sw = self.get_sw() sw.install(package='abc.tgz', no_copy=True) self.assertFalse(sw._multi_VC) calls = [ call('/var/tmp/abc.tgz', dev_timeout=1800, re0=True), call('/var/tmp/abc.tgz', dev_timeout=1800, re1=True) ] mock_pkgadd.assert_has_calls(calls) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_mixed_vc_with_copy(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._mixed_VC = True self.sw.put = MagicMock() self.sw.remote_checksum = MagicMock( return_value='d41d8cd98f00b204e9800998ecf8427e') self.sw._RE_list = ('version_RE0', 'version_RE1') with patch('jnpr.junos.utils.sw.SW.local_md5', MagicMock(return_value='d41d8cd98f00b204e9800998ecf8427e')): self.assertTrue( self.sw.install(pkg_set=['install.tgz', 'install.tgz'], cleanfs=False)) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_mixed_vc_safe_copy_false(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._mixed_VC = True self.sw.safe_copy = MagicMock(return_value=False) self.sw.remote_checksum = MagicMock( return_value='d41d8cd98f00b204e9800998ecf8427e') self.sw._RE_list = ('version_RE0', 'version_RE1') with patch('jnpr.junos.utils.sw.SW.local_md5', MagicMock(return_value='d41d8cd98f00b204e9800998ecf8427e')): self.assertFalse( self.sw.install(pkg_set=['install.tgz', 'install.tgz'], cleanfs=False)) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_mixed_vc_ValueError(self, mock_pkgadd): mock_pkgadd.return_value = True self.sw._mixed_VC = True self.sw.remote_checksum = MagicMock( return_value='d41d8cd98f00b204e9800998ecf8427e') self.sw._RE_list = ('version_RE0', 'version_RE1') with patch('jnpr.junos.utils.sw.SW.local_md5', MagicMock(return_value='d41d8cd98f00b204e9800998ecf8427e')): self.assertRaises(ValueError, self.sw.install, pkg_set='install.tgz', cleanfs=False) @patch('jnpr.junos.utils.sw.SW.pkgadd') def test_sw_install_mixed_vc_TypeError(self, mock_pkgadd): self.assertRaises(TypeError, self.sw.install, cleanfs=False) @patch('jnpr.junos.Device.execute') def test_sw_install_kwargs_force_host(self, mock_execute): self.sw.install('file', no_copy=True, force_host=True) rpc = [ '<request-package-add><force-host/><no-validate/><re1/><package-name>/var/tmp/file</package-name></request-package-add>', '<request-package-add><package-name>/var/tmp/file</package-name><no-validate/><force-host/><re1/></request-package-add>', '<request-package-add><package-name>/var/tmp/file</package-name><no-validate/><re1/><force-host/></request-package-add>', '<request-package-add><force-host/><no-validate/><package-name>/var/tmp/file</package-name><re1/></request-package-add>', '<request-package-add><force-host/><re1/><no-validate/><package-name>/var/tmp/file</package-name></request-package-add>', '<request-package-add><no-validate/><re1/><package-name>/var/tmp/file</package-name><force-host/></request-package-add>', '<request-package-add><no-validate/><package-name>/var/tmp/file</package-name><force-host/><re1/></request-package-add>', '<request-package-add><force-host/><package-name>/var/tmp/file</package-name><no-validate/><re1/></request-package-add>', '<request-package-add><re1/><no-validate/><package-name>/var/tmp/file</package-name><force-host/></request-package-add>', '<request-package-add><re1/><force-host/><package-name>/var/tmp/file</package-name><no-validate/></request-package-add>', '<request-package-add><re1/><package-name>/var/tmp/file</package-name><force-host/><no-validate/></request-package-add>', '<request-package-add><re1/><force-host/><no-validate/><package-name>/var/tmp/file</package-name></request-package-add>', '<request-package-add><no-validate/><force-host/><re1/><package-name>/var/tmp/file</package-name></request-package-add>', '<request-package-add><package-name>/var/tmp/file</package-name><force-host/><no-validate/><re1/></request-package-add>', '<request-package-add><no-validate/><re1/><force-host/><package-name>/var/tmp/file</package-name></request-package-add>', '<request-package-add><package-name>/var/tmp/file</package-name><force-host/><re1/><no-validate/></request-package-add>', '<request-package-add><no-validate/><force-host/><package-name>/var/tmp/file</package-name><re1/></request-package-add>', '<request-package-add><force-host/><no-validate/><package-name>/var/tmp/file</package-name></request-package-add>', '<request-package-add><force-host/><package-name>/var/tmp/file</package-name><no-validate/></request-package-add>', '<request-package-add><package-name>/var/tmp/file</package-name><no-validate/><force-host/></request-package-add>', '<request-package-add><no-validate/><force-host/><package-name>/var/tmp/file</package-name></request-package-add>', '<request-package-add><no-validate/><package-name>/var/tmp/file</package-name><force-host/></request-package-add>', '<request-package-add><package-name>/var/tmp/file</package-name><force-host/><no-validate/></request-package-add>', '<request-package-add><package-name>/var/tmp/file</package-name><re1/><no-validate/><force-host/></request-package-add>', '<request-package-add><package-name>/var/tmp/file</package-name><re1/><force-host/><no-validate/></request-package-add>', '<request-package-add><force-host/><package-name>/var/tmp/file</package-name><re1/><no-validate/></request-package-add>', '<request-package-add><re1/><package-name>/var/tmp/file</package-name><no-validate/><force-host/></request-package-add>', '<request-package-add><no-validate/><package-name>/var/tmp/file</package-name><re1/><force-host/></request-package-add>', '<request-package-add><re1/><no-validate/><force-host/><package-name>/var/tmp/file</package-name></request-package-add>', '<request-package-add><force-host/><re1/><package-name>/var/tmp/file</package-name><no-validate/></request-package-add>' ] self.assertTrue( etree.tostring(mock_execute.call_args[0][0]).decode('utf-8') in rpc) @patch('jnpr.junos.Device.execute') def test_sw_rollback(self, mock_execute): rsp = '<rpc-reply><output>junos-vsrx-12.1X46-D30.2-domestic will become active at next reboot</output></rpc-reply>' mock_execute.side_effect = etree.XML(rsp) msg = 'junos-vsrx-12.1X46-D30.2-domestic will become active at next reboot' self.assertEqual(self.sw.rollback(), msg) @patch('jnpr.junos.Device.execute') def test_sw_rollback_multi(self, mock_execute): mock_execute.side_effect = self._mock_manager msg = { 'fpc1': "Junos version 'D10.2' will become active at next reboot", 'fpc0': 'JUNOS version "D10.2" will become active at next reboot' } self.assertEqual(eval(self.sw.rollback()), msg) @patch('jnpr.junos.Device.execute') def test_sw_rollback_multi_exception(self, mock_execute): fname = 'request-package-rollback-multi-error.xml' mock_execute.side_effect = self._read_file(fname) self.assertRaises(SwRollbackError, self.sw.rollback) @patch('jnpr.junos.Device.execute') def test_sw_rollback_exception(self, mock_execute): rsp = '<rpc-reply><output>WARNING: Cannot rollback, /packages/junos.old is not valid</output></rpc-reply>' mock_execute.side_effect = etree.XML(rsp) self.assertRaises(SwRollbackError, self.sw.rollback) def test_sw_inventory(self): self.sw.dev.rpc.file_list = \ MagicMock(side_effect=self._mock_manager) self.assertEqual(self.sw.inventory, { 'current': None, 'rollback': None }) @patch('jnpr.junos.Device.execute') def test_sw_reboot(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_MX = True self.assertTrue('Shutdown NOW' in self.sw.reboot()) @patch('jnpr.junos.Device.execute') def test_sw_reboot_at(self, mock_execute): mock_execute.side_effect = self._mock_manager self.assertTrue('Shutdown at' in self.sw.reboot(at='201407091815')) @patch('jnpr.junos.Device.execute') def test_sw_reboot_multi_re_vc(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_RE = True self.sw._multi_VC = False self.assertTrue('Shutdown NOW' in self.sw.reboot()) @patch('jnpr.junos.Device.execute') def test_sw_reboot_mixed_vc(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._mixed_VC = True self.sw._multi_VC = True self.sw.reboot() self.assertTrue('all-members' in ( etree.tostring(mock_execute.call_args[0][0]).decode('utf-8'))) @patch('jnpr.junos.Device.execute') def test_sw_reboot_mixed_vc_all_re_false(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._mixed_VC = True self.sw._multi_VC = True self.sw.reboot(all_re=False) self.assertTrue('all-members' not in ( etree.tostring(mock_execute.call_args[0][0]).decode('utf-8'))) @patch('jnpr.junos.Device.execute') def test_sw_reboot_exception(self, mock_execute): rsp = etree.XML('<rpc-reply><a>test</a></rpc-reply>') mock_execute.side_effect = RpcError(rsp=rsp) self.assertRaises(Exception, self.sw.reboot) @patch('jnpr.junos.Device.execute') def test_sw_reboot_exception_RpcTimeoutError(self, mock_execute): rsp = (self.dev, 'request-reboot', 60) mock_execute.side_effect = RpcTimeoutError(*rsp) self.assertRaises(Exception, self.sw.reboot) @patch('jnpr.junos.Device.execute') def test_sw_poweroff(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_MX = True self.assertTrue('Shutdown NOW' in self.sw.poweroff()) @patch('jnpr.junos.Device.execute') def test_sw_poweroff_exception(self, mock_execute): rsp = etree.XML('<rpc-reply><a>test</a></rpc-reply>') mock_execute.side_effect = RpcError(rsp=rsp) self.assertRaises(Exception, self.sw.poweroff) @patch('jnpr.junos.Device.execute') def test_sw_poweroff_multi_re_vc(self, mock_execute): mock_execute.side_effect = self._mock_manager self.sw._multi_RE = True self.sw._multi_VC = False self.assertTrue('Shutdown NOW' in self.sw.poweroff()) def _myprogress(self, dev, report): pass def _my_scp_progress(self, _path, _total, _xfrd): print(_path, _total, _xfrd) @contextmanager def capture(self, command, *args, **kwargs): out, sys.stdout = sys.stdout, StringIO() command(*args, **kwargs) sys.stdout.seek(0) yield sys.stdout.read() sys.stdout = out def _read_file(self, fname): from ncclient.xml_ import NCElement fpath = os.path.join(os.path.dirname(__file__), 'rpc-reply', fname) foo = open(fpath).read() rpc_reply = NCElement(foo, self.dev._conn._device_handler.transform_reply() )._NCElement__doc[0] return rpc_reply def _mock_manager(self, *args, **kwargs): if kwargs: # Little hack for mocked execute if 'dev_timeout' in kwargs: return self._read_file(args[0].tag + '.xml') if 'path' in kwargs: if kwargs['path'] == '/packages': return self._read_file('file-list_dir.xml') device_params = kwargs['device_params'] device_handler = make_device_handler(device_params) session = SSHSession(device_handler) return Manager(session, device_handler) elif args: if args[0].find('at') is not None: return self._read_file('request-reboot-at.xml') else: return self._read_file(args[0].tag + '.xml')
class JunosDevice(BaseDevice): def __init__(self, host, username, password, *args, **kwargs): super(JunosDevice, self).__init__(host, username, password, *args, vendor='juniper', device_type=JNPR_DEVICE_TYPE, **kwargs) self.native = JunosNativeDevice(*args, host=host, user=username, passwd=password, **kwargs) self.open() self.cu = JunosNativeConfig(self.native) self.fs = JunosNativeFS(self.native) self.sw = JunosNativdSW(self.native) @property def connected(self): return self.native.connected def open(self): if not self.connected: self.native.open() def close(self): if self.connected: self.native.close() def show(self, command, raw_text=True): if not raw_text: raise ValueError('Juniper only supports raw text output. \ Append " | display xml" to your commands for a structured string.') if not command.startswith('show'): raise CommandError(command, 'Juniper "show" commands must begin with "show".') return self.native.cli(command, warning=False) def show_list(self, commands, raw_text=True): responses = [] for command in commands: responses.append(self.show(command, raw_text=raw_text)) return responses def backup_running_config(self, filename): with open(filename, 'w') as f: f.write(self.running_config) def config(self, command, format='set'): try: self.cu.load(command, format=format) self.cu.commit() except ConfigLoadError as e: raise CommandError(command, e.message) def config_list(self, commands, format='set'): try: for command in commands: self.cu.load(command, format=format) self.cu.commit() except ConfigLoadError as e: raise CommandListError(commands, command, e.message) def _uptime_components(self, uptime_full_string): match_days = re.search(r'(\d+) days?', uptime_full_string) match_hours = re.search(r'(\d+) hours?', uptime_full_string) match_minutes = re.search(r'(\d+) minutes?', uptime_full_string) match_seconds = re.search(r'(\d+) seconds?', uptime_full_string) days = int(match_days.group(1)) if match_days else 0 hours = int(match_hours.group(1)) if match_hours else 0 minutes = int(match_minutes.group(1)) if match_minutes else 0 seconds = int(match_seconds.group(1)) if match_seconds else 0 return days, hours, minutes, seconds def _uptime_to_string(self, uptime_full_string): days, hours, minutes, seconds = self._uptime_components(uptime_full_string) return '%02d:%02d:%02d:%02d' % (days, hours, minutes, seconds) def _uptime_to_seconds(self, uptime_full_string): days, hours, minutes, seconds = self._uptime_components(uptime_full_string) seconds += days * 24 * 60 * 60 seconds += hours * 60 * 60 seconds += minutes * 60 return seconds def _get_interfaces(self): eth_ifaces = EthPortTable(self.native) eth_ifaces.get() loop_ifaces = LoopbackTable(self.native) loop_ifaces.get() ifaces = eth_ifaces.keys() ifaces.extend(loop_ifaces.keys()) return ifaces def checkpoint(self, filename): self.save(filename) def rollback(self, filename): self.native.timeout = 60 temp_file = NamedTemporaryFile() with SCP(self.native) as scp: scp.get(filename, local_path=temp_file.name) self.cu.load(path=temp_file.name, format='text', overwrite=True) self.cu.commit() temp_file.close() self.native.timeout = 30 @property def facts(self): if hasattr(self, '_facts'): return self._facts native_facts = self.native.facts facts = {} facts['hostname'] = native_facts['hostname'] facts['fqdn'] = native_facts['fqdn'] facts['model'] = native_facts['model'] native_uptime_string = native_facts['RE0']['up_time'] facts['uptime'] = self._uptime_to_seconds(native_uptime_string) facts['uptime_string'] = self._uptime_to_string(native_uptime_string) facts['serial_number'] = native_facts['serialnumber'] facts['interfaces'] = self._get_interfaces() for fact_key in native_facts: if fact_key.startswith('version') and fact_key != 'version_info': facts['os_version'] = native_facts[fact_key] break facts['vendor'] = self.vendor self._facts = facts return self._facts def _file_copy_local_file_exists(self, filepath): return os.path.isfile(filepath) def _file_copy_local_md5(self, filepath, blocksize=2**20): if self._file_copy_local_file_exists(filepath): m = hashlib.md5() with open(filepath, "rb") as f: buf = f.read(blocksize) while buf: m.update(buf) buf = f.read(blocksize) return m.hexdigest() def _file_copy_remote_md5(self, filename): return self.fs.checksum(filename) def file_copy_remote_exists(self, src, dest=None, **kwargs): if dest is None: dest = os.path.basename(src) local_hash = self._file_copy_local_md5(src) remote_hash = self._file_copy_remote_md5(dest) if local_hash is not None: if local_hash == remote_hash: return True return False def file_copy(self, src, dest=None, **kwargs): if dest is None: dest = os.path.basename(src) with SCP(self.native) as scp: scp.put(src, remote_path=dest) def get_boot_options(self): return self.facts['os_version'] def set_boot_options(self, sys): raise NotImplementedError def reboot(self, timer=0, confirm=False): if confirm: self.sw.reboot(in_min=timer) else: print('Need to confirm reboot with confirm=True') @property def running_config(self): return self.show('show config') def save(self, filename=None): if filename is None: self.cu.commit() return temp_file = NamedTemporaryFile() temp_file.write(self.show('show config')) temp_file.flush() with SCP(self.native) as scp: scp.put(temp_file.name, remote_path=filename) temp_file.close() return True @property def startup_config(self): return self.show('show config')