def test_get_device_sendline(mock_pxssh, mock_nxos_device, mock_paramiko): mock_pxssh.return_value.expect.side_effect = [2, 0] get_device(target=dev_info['target'], user=dev_info['user'], passwd=dev_info['passwd']) calls = [call('show version'), call('cat /proc/version')] mock_pxssh.return_value.sendline.assert_has_calls(calls)
def test_get_device_paramiko_authentication_exception(mock_paramiko): mock_paramiko.return_value.connect.side_effect = AuthenticationException with pytest.raises(TargetError) as e: get_device(target=dev_info['target'], user=dev_info['user'], passwd=dev_info['passwd']) assert e.value.message == ('Authentication error: %s' % dev_info['target'])
def test_get_device_paramiko_ssh_exception(mock_paramiko): mock_paramiko.return_value.connect.side_effect = SSHException with pytest.raises(TargetError) as e: get_device(target=dev_info['target'], user=dev_info['user'], passwd=dev_info['passwd']) assert e.value.message == ('Error logging in: %s' % dev_info['target'])
def test_get_device_socket_error(mock_paramiko): mock_paramiko.return_value.connect.side_effect = socket.error with pytest.raises(TargetError) as e: get_device(target=dev_info['target'], user=dev_info['user'], passwd=dev_info['passwd']) assert e.value.message == ('Device unreachable: %s' % dev_info['target'])
def test_get_device_login(mock_pxssh, mock_nxos_device, mock_paramiko): mock_pxssh.return_value.expect.return_value = 0 get_device(target=dev_info['target'], user=dev_info['user'], passwd=dev_info['passwd']) mock_paramiko.return_value.connect.assert_called_with( dev_info['target'], username=dev_info['user'], timeout=5, password=dev_info['passwd']) mock_pxssh.return_value.login.assert_called_with( dev_info['target'], dev_info['user'], auto_prompt_reset=False, login_timeout=10, password=dev_info['passwd'])
def test_get_device_cumulus(mock_pxssh, mock_cumulus_device, mock_paramiko): device_name = 'cumulus_device' mock_pxssh.return_value.expect.side_effect = [2, 0] mock_cumulus_device.return_value = device_name dev = get_device(target=dev_info['target'], user=dev_info['user'], passwd=dev_info['passwd']) assert dev == device_name
def test_get_device_eos(mock_pxssh, mock_eos_device, mock_paramiko): device_name = 'eos_device' mock_pxssh.return_value.expect.return_value = 1 mock_eos_device.return_value = device_name dev = get_device(target=dev_info['target'], user=dev_info['user'], passwd=dev_info['passwd']) assert dev == device_name
def test_get_device_target_error(mock_pxssh, mock_ssh): mock_pxssh.return_value.expect.side_effect = [2, 4] with pytest.raises(TargetError) as e: dev = get_device(target=dev_info['target'], user=dev_info['user'], passwd=dev_info['passwd']) assert e.value.message == 'Unable to determine device type for %s' % dev_info[ 'target']
def test_get_device_nos_only(mock_pxssh, mock_nxos_device, mock_paramiko): device_name = 'nxos' mock_pxssh.return_value.expect.return_value = 0 mock_nxos_device.return_value = device_name dev = get_device(target=dev_info['target'], user=dev_info['user'], passwd=dev_info['passwd'], nos_only=True) assert dev == device_name
def test_get_device_exception(mock_pxssh, mock_ssh): exception_msg = 'Test Exception Message' mock_pxssh.return_value.login.side_effect = ExceptionPxssh(exception_msg) with pytest.raises(TargetError) as e: dev = get_device(target=dev_info['target'], user=dev_info['user'], passwd=dev_info['passwd']) assert e.value.message == 'Error logging in to {target} : {error}'.format( target=dev_info['target'], error=exception_msg)
def retry_ztp(target, nos=None, user='******', password='******'): log = setup_logging(logname='aeon-retry', target=target) cumulus_lease_file = '/var/lib/dhcp/dhclient.eth0.leases' server = "{}:{}".format(get_server_ipaddr(target), _AEON_PORT) dev_table = { 'eos': { 'dev_obj': EosDevice, 'cmds': ['write erase now', 'reload now'] }, 'cumulus': { 'dev_obj': CumulusDevice, 'cmds': [ "sudo sed -i '/vrf mgmt/d' /etc/network/interfaces", 'sudo ztp -R', 'sudo reboot' ], 'virt_cmds': [ "sudo ztp -v -r $(cat %s | grep 'cumulus-provision-url'| tail -1 | cut -f2 -d \\\")" % cumulus_lease_file ] }, 'nxos': { 'dev_obj': NxosDevice, 'cmds': 'terminal dont-ask ; write erase ; reload' }, 'ubuntu': { 'dev_obj': UbuntuDevice, 'cmds': [ 'curl "http://{}/api/register/ubuntu"'.format( get_server_ipaddr(target)) ] }, 'centos': { 'dev_obj': CentosDevice, 'cmds': [ 'curl "http://{}/api/register/centos"'.format( get_server_ipaddr(target)) ] } } def post_success(): message = 'Retry successfully initiated' log.info(message) post_device_status(server=server, target=target, state='RETRY', message=message) try: if not nos: log.info('Determining device OS type') dev = get_device(target=target, user=user, passwd=password) dev.gather_facts() nos = dev.facts['os_name'].lower() else: nos = nos.lower() log.info('Device OS type: %s' % nos) if not any(nos in x for x in dev_table): error_msg = 'Retry not supported for device type %s' % nos log.error(error_msg) post_device_status(server=server, target=target, state='ERROR', message=error_msg) return False, error_msg dev = dev_table[nos]['dev_obj'](target, user=user, passwd=password) except (ProbeError, TargetError) as e: error_msg = 'Error accessing device: %s' % str(e) log.error(error_msg) post_device_status(server=server, target=target, state='ERROR', message=error_msg) log.handlers.pop() return False, error_msg try: # CumulusVX doesn't always boot into ZTP mode without network errors # Use different retry commands for CVX if dev.facts['os_name'] == 'cumulus' and dev.facts['virtual']: log.info('Running retry commands: %s' % dev_table[nos]['virt_cmds']) ok, output = dev.api.execute(dev_table[nos]['virt_cmds']) post_success() return ok, output # aeon-venos NxosDevice doesn't use execute for some reason elif dev.facts['os_name'] == 'nxos': # Ignore timeout after reload try: log.info('Running retry commands. %s' % dev_table[nos]['cmds']) output = (dev.api.exec_config(dev_table[nos]['cmds'], timeout=10)) except TimeoutError: post_success() output = True ok = True else: log.info('Running retry commands: %s' % dev_table[nos]['cmds']) ok, output = dev.api.execute(dev_table[nos]['cmds']) post_success() return ok, output except (CommandError, NxosCommandError) as e: # IncompleteRead error raised when reloading EOS. This is normal. if 'IncompleteRead' in str(e.exc): post_success() return True, None error_msg = 'Unable to initiate ZTP retry: %s' % str(e) log.error(error_msg) post_device_status(server=server, target=target, state='ERROR', message=error_msg) return False, e except TimeoutError: error_msg = 'Device %s unreachable' % target log.error('Unable to initiate ZTP retry: Device %s unreachable' % target) post_device_status(server=server, target=target, state='ERROR', message=error_msg) return False, error_msg except LoginNotReadyError as e: error_msg = 'Unable to login to device: %s' % str(e) log.error(error_msg) post_device_status(server=server, target=target, state='ERROR', message=error_msg) finally: log.handlers.pop() return ok, output