Example #1
0
    def setUp(self, mock_node):
        self.device = EOSDevice('host', 'user', 'pass')
        self.maxDiff = None

        mock_node.enable.side_effect = enable
        mock_node.config.side_effect = config
        self.device.native = mock_node
Example #2
0
    def setUp(self, mock_node):
        self.device = EOSDevice("host", "user", "pass")
        self.maxDiff = None

        mock_node.enable.side_effect = enable
        mock_node.config.side_effect = config
        self.device.native = mock_node
Example #3
0
    def setup_test_file_copy_remote_exists(self, test_file_copy_remote_exists, mock_ssh, mock_node):
        self.device = EOSDevice("host", "user", "pass")
        self.maxDiff = None

        mock_node.enable.side_effect = enable
        mock_node.config.side_effect = config
        self.device.native = mock_node
        mock_ssh.send_command_timing.side_effect = send_command
        mock_ssh.send_command_expect.side_effect = send_command_expect
        self.device.native_ssh = mock_ssh
Example #4
0
    def setUp(self, mock_node):
        self.device = EOSDevice('host', 'user', 'pass')
        self.maxDiff = None

        mock_node.enable.side_effect = enable
        mock_node.config.side_effect = config
        self.device.native = mock_node
Example #5
0
def test_init_pass_timeout(mock_eos_connect):
    EOSDevice("host", "username", "password", timeout=30)
    mock_eos_connect.assert_called_with(host="host",
                                        username="******",
                                        password="******",
                                        transport="http",
                                        timeout=30)
Example #6
0
class TestEOSDevice(unittest.TestCase):

    @mock.patch('pyeapi.client.Node', autospec=True)
    def setUp(self, mock_node):
        self.device = EOSDevice('host', 'user', 'pass')
        self.maxDiff = None

        mock_node.enable.side_effect = enable
        mock_node.config.side_effect = config
        self.device.native = mock_node

    def test_config(self):
        command = 'interface Eth1'
        result = self.device.config(command)

        self.assertIsNone(result)
        self.device.native.config.assert_called_with([command])

    def test_bad_config(self):
        command = 'asdf poknw'

        with self.assertRaisesRegexp(CommandError, command):
            self.device.config(command)

    def test_config_list(self):
        commands = ['interface Eth1', 'no shutdown']
        result = self.device.config_list(commands)

        self.assertIsNone(result)
        self.device.native.config.assert_called_with(commands)

    def test_bad_config_list(self):
        commands = ['interface Eth1', 'apons']

        with self.assertRaisesRegexp(CommandListError, commands[1]):
            self.device.config_list(commands)

    def test_show(self):
        command = 'show ip arp'
        result = self.device.show(command)

        self.assertIsInstance(result, dict)
        self.assertNotIn('command', result)
        self.assertIn('dynamicEntries', result)

        self.device.native.enable.assert_called_with(
            [command], encoding='json')

    def test_bad_show(self):
        command = 'show microsoft'
        with self.assertRaises(CommandError):
            self.device.show(command)

    def test_show_raw_text(self):
        command = 'show hostname'
        result = self.device.show(command, raw_text=True)

        self.assertIsInstance(result, str)
        self.assertEqual(result,
                          'Hostname: spine1\nFQDN:     spine1.ntc.com\n')
        self.device.native.enable.assert_called_with([command], encoding='text')

    def test_show_list(self):
        commands = ['show hostname', 'show clock']

        result = self.device.show_list(commands)
        self.assertIsInstance(result, list)

        self.assertIn('hostname', result[0])
        self.assertIn('fqdn', result[0])
        self.assertIn('output', result[1])

        self.device.native.enable.assert_called_with(commands, encoding='json')

    def test_bad_show_list(self):
        commands = ['show badcommand', 'show clock']
        with self.assertRaisesRegexp(CommandListError, 'show badcommand'):
            self.device.show_list(commands)

    def test_save(self):
        result = self.device.save()
        self.assertTrue(result)
        self.device.native.enable.assert_called_with(['copy running-config startup-config'], encoding='json')

    @mock.patch.object(EOSFileCopy, 'remote_file_exists', autospec=True)
    def test_file_copy_remote_exists(self, mock_fc):
        mock_fc.return_value = True
        result = self.device.file_copy_remote_exists('source_file')

        self.assertTrue(result)

    @mock.patch.object(EOSFileCopy, 'remote_file_exists', autospec=True)
    def test_file_copy_remote_exists_failure(self, mock_fc):
        mock_fc.return_value = False
        result = self.device.file_copy_remote_exists('source_file')

        self.assertFalse(result)

    @mock.patch('pyntc.devices.eos_device.EOSFileCopy', autospec=True)
    def test_file_copy(self, mock_fc):
        instance = mock_fc.return_value
        self.device.file_copy('source_file')

        instance.send.assert_called_with()

    def test_reboot(self):
        self.device.reboot(confirm=True)
        self.device.native.enable.assert_called_with(['reload now'], encoding='json')

    def test_reboot_no_confirm(self):
        self.device.reboot()
        assert not self.device.native.enable.called

    def test_reboot_with_timer(self):
        with self.assertRaises(RebootTimerError):
            self.device.reboot(confirm=True, timer=3)

    def test_get_boot_options(self):
        boot_options = self.device.get_boot_options()
        self.assertEqual(boot_options, {'sys': 'EOS.swi'})

    def test_set_boot_options(self):
        self.device.set_boot_options('new_image.swi')
        self.device.native.enable.assert_called_with(['install source new_image.swi'], encoding='json')

    def test_backup_running_config(self):
        filename = 'local_running_config'
        self.device.backup_running_config(filename)

        with open(filename, 'r') as f:
            contents = f.read()

        self.assertEqual(contents, self.device.running_config)
        os.remove(filename)

    def test_rollback(self):
        self.device.rollback('good_checkpoint')
        self.device.native.enable.assert_called_with(['configure replace good_checkpoint force'], encoding='json')

    def test_bad_rollback(self):
        with self.assertRaises(RollbackError):
            self.device.rollback('bad_checkpoint')

    def test_checkpiont(self):
        self.device.checkpoint('good_checkpoint')
        self.device.native.enable.assert_called_with(['copy running-config good_checkpoint'], encoding='json')

    @mock.patch.object(EOSVlans, 'get_list', autospec=True)
    def test_facts(self, mock_vlan_list):
        mock_vlan_list.return_value = ['1', '2', '10']
        facts = self.device.facts
        self.assertIsInstance(facts['uptime'], int)
        self.assertIsInstance(facts['uptime_string'], str)

        del facts['uptime']
        del facts['uptime_string']

        expected = {
            'vendor': 'arista',
            'os_version': '4.14.7M-2384414.4147M',
            'interfaces': [
                'Ethernet1',
                'Ethernet2',
                'Ethernet3',
                'Ethernet4',
                'Ethernet5',
                'Ethernet6',
                'Ethernet7',
                'Ethernet8',
                'Management1',
            ],
            'hostname': 'eos-spine1',
            'fqdn': 'eos-spine1.ntc.com',
            'serial_number': '',
            'model': 'vEOS',
            'vlans': ['1', '2', '10']
        }
        self.assertEqual(facts, expected)

        self.device.native.enable.reset_mock()
        facts = self.device.facts
        self.assertEqual(facts, expected)
        self.device.native.enable.assert_not_called()

    def test_running_config(self):
        expected = self.device.show('show running-config', raw_text=True)
        self.assertEqual(self.device.running_config, expected)

    def test_starting_config(self):
        expected = self.device.show('show startup-config', raw_text=True)
        self.assertEqual(self.device.startup_config, expected)
Example #7
0
class TestEOSDevice(unittest.TestCase):
    @mock.patch("pyeapi.client.Node", autospec=True)
    def setUp(self, mock_node):
        self.device = EOSDevice("host", "user", "pass")
        self.maxDiff = None

        mock_node.enable.side_effect = enable
        mock_node.config.side_effect = config
        self.device.native = mock_node

    def tearDown(self):
        # Reset the mock so we don't have transient test effects
        self.device.native.reset_mock()

    def test_config(self):
        command = "interface Eth1"
        result = self.device.config(command)

        self.assertIsNone(result)
        self.device.native.config.assert_called_with([command])

    def test_bad_config(self):
        command = "asdf poknw"

        with self.assertRaisesRegex(CommandError, command):
            self.device.config(command)

    def test_config_list(self):
        commands = ["interface Eth1", "no shutdown"]
        result = self.device.config_list(commands)

        self.assertIsNone(result)
        self.device.native.config.assert_called_with(commands)

    def test_bad_config_list(self):
        commands = ["interface Eth1", "apons"]

        with self.assertRaisesRegex(CommandListError, commands[1]):
            self.device.config_list(commands)

    def test_show(self):
        command = "show ip arp"
        result = self.device.show(command)

        self.assertIsInstance(result, dict)
        self.assertNotIn("command", result)
        self.assertIn("dynamicEntries", result)

        self.device.native.enable.assert_called_with([command], encoding="json")

    def test_bad_show(self):
        command = "show microsoft"
        with self.assertRaises(CommandError):
            self.device.show(command)

    def test_show_raw_text(self):
        command = "show hostname"
        result = self.device.show(command, raw_text=True)

        self.assertIsInstance(result, str)
        self.assertEqual(result, "Hostname: spine1\nFQDN:     spine1.ntc.com\n")
        self.device.native.enable.assert_called_with([command], encoding="text")

    def test_show_list(self):
        commands = ["show hostname", "show clock"]

        result = self.device.show_list(commands)
        self.assertIsInstance(result, list)

        self.assertIn("hostname", result[0])
        self.assertIn("fqdn", result[0])
        self.assertIn("output", result[1])

        self.device.native.enable.assert_called_with(commands, encoding="json")

    def test_bad_show_list(self):
        commands = ["show badcommand", "show clock"]
        with self.assertRaisesRegex(CommandListError, "show badcommand"):
            self.device.show_list(commands)

    def test_save(self):
        result = self.device.save()
        self.assertTrue(result)
        self.device.native.enable.assert_called_with(["copy running-config startup-config"], encoding="json")

    @mock.patch("pyeapi.client.Node", autospec=True)
    @mock.patch("netmiko.arista.arista.AristaSSH", autospec=True)
    def setup_test_file_copy_remote_exists(self, test_file_copy_remote_exists, mock_ssh, mock_node):
        self.device = EOSDevice("host", "user", "pass")
        self.maxDiff = None

        mock_node.enable.side_effect = enable
        mock_node.config.side_effect = config
        self.device.native = mock_node
        mock_ssh.send_command_timing.side_effect = send_command
        mock_ssh.send_command_expect.side_effect = send_command_expect
        self.device.native_ssh = mock_ssh

    def teardown_test_file_copy_remote_exists(self, test_file_copy_remote_exists):
        self.device.native.reset_mock()
        self.device.native_ssh.reset_mock()

    @mock.patch("pyntc.devices.eos_device.FileTransfer", autospec=True)
    @mock.patch.object(EOSDevice, "open")
    @mock.patch.object(EOSDevice, "close")
    @mock.patch("netmiko.arista.arista.AristaSSH", autospec=True)
    def test_file_copy_remote_exists(self, mock_open, mock_close, mock_ssh, mock_ft):
        self.device.native_ssh = mock_open
        self.device.native_ssh.send_command_timing.side_effect = None
        self.device.native_ssh.send_command_timing.return_value = "flash: /dev/null"
        mock_ft_instance = mock_ft.return_value
        mock_ft_instance.check_file_exists.return_value = True
        mock_ft_instance.compare_md5.return_value = True

        result = self.device.file_copy_remote_exists("source_file")

        self.assertTrue(result)

    @mock.patch("pyntc.devices.eos_device.FileTransfer", autospec=True)
    @mock.patch.object(EOSDevice, "open")
    @mock.patch.object(EOSDevice, "close")
    @mock.patch("netmiko.arista.arista.AristaSSH", autospec=True)
    def test_file_copy_remote_exists_bad_md5(self, mock_open, mock_close, mock_ssh, mock_ft):
        self.device.native_ssh = mock_open
        self.device.native_ssh.send_command_timing.side_effect = None
        self.device.native_ssh.send_command_timing.return_value = "flash: /dev/null"
        mock_ft_instance = mock_ft.return_value
        mock_ft_instance.check_file_exists.return_value = True
        mock_ft_instance.compare_md5.return_value = False

        result = self.device.file_copy_remote_exists("source_file")

        self.assertFalse(result)

    @mock.patch("pyntc.devices.eos_device.FileTransfer", autospec=True)
    @mock.patch.object(EOSDevice, "open")
    @mock.patch.object(EOSDevice, "close")
    @mock.patch("netmiko.arista.arista.AristaSSH", autospec=True)
    def test_file_copy_remote_not_exist(self, mock_open, mock_close, mock_ssh, mock_ft):

        self.device.native_ssh = mock_open
        self.device.native_ssh.send_command_timing.side_effect = None
        self.device.native_ssh.send_command_timing.return_value = "flash: /dev/null"

        mock_ft_instance = mock_ft.return_value
        mock_ft_instance.check_file_exists.return_value = False
        mock_ft_instance.compare_md5.return_value = True

        result = self.device.file_copy_remote_exists("source_file")

        self.assertFalse(result)

    @mock.patch("pyntc.devices.eos_device.FileTransfer", autospec=True)
    @mock.patch.object(EOSDevice, "open")
    @mock.patch.object(EOSDevice, "close")
    @mock.patch("netmiko.arista.arista.AristaSSH", autospec=True)
    def test_file_copy(self, mock_open, mock_close, mock_ssh, mock_ft):
        self.device.native_ssh = mock_open
        self.device.native_ssh.send_command_timing.side_effect = None
        self.device.native_ssh.send_command_timing.return_value = "flash: /dev/null"

        mock_ft_instance = mock_ft.return_value
        mock_ft_instance.check_file_exists.side_effect = [False, True]
        self.device.file_copy("path/to/source_file")

        mock_ft.assert_called_with(self.device.native_ssh, "path/to/source_file", "source_file", file_system="flash:")
        mock_ft_instance.enable_scp.assert_any_call()
        mock_ft_instance.establish_scp_conn.assert_any_call()
        mock_ft_instance.transfer_file.assert_any_call()

    @mock.patch("pyntc.devices.eos_device.FileTransfer", autospec=True)
    @mock.patch.object(EOSDevice, "open")
    @mock.patch.object(EOSDevice, "close")
    @mock.patch("netmiko.arista.arista.AristaSSH", autospec=True)
    def test_file_copy_different_dest(self, mock_open, mock_close, mock_ssh, mock_ft):
        self.device.native_ssh = mock_open
        self.device.native_ssh.send_command_timing.side_effect = None
        self.device.native_ssh.send_command_timing.return_value = "flash: /dev/null"

        mock_ft_instance = mock_ft.return_value
        mock_ft_instance.check_file_exists.side_effect = [False, True]
        self.device.file_copy("source_file", "dest_file")

        mock_ft.assert_called_with(self.device.native_ssh, "source_file", "dest_file", file_system="flash:")
        mock_ft_instance.enable_scp.assert_any_call()
        mock_ft_instance.establish_scp_conn.assert_any_call()
        mock_ft_instance.transfer_file.assert_any_call()

    @mock.patch("pyntc.devices.eos_device.FileTransfer", autospec=True)
    @mock.patch.object(EOSDevice, "open")
    @mock.patch.object(EOSDevice, "close")
    @mock.patch("netmiko.arista.arista.AristaSSH", autospec=True)
    def test_file_copy_fail(self, mock_open, mock_close, mock_ssh, mock_ft):
        self.device.native_ssh = mock_open
        self.device.native_ssh.send_command_timing.side_effect = None
        self.device.native_ssh.send_command_timing.return_value = "flash: /dev/null"

        mock_ft_instance = mock_ft.return_value
        mock_ft_instance.transfer_file.side_effect = Exception
        mock_ft_instance.check_file_exists.return_value = False

        with self.assertRaises(FileTransferError):
            self.device.file_copy("source_file")

    def test_reboot(self):
        self.device.reboot(confirm=True)
        self.device.native.enable.assert_called_with(["reload now"], encoding="json")

    def test_reboot_no_confirm(self):
        self.device.reboot()
        assert not self.device.native.enable.called

    def test_reboot_with_timer(self):
        with self.assertRaises(RebootTimerError):
            self.device.reboot(confirm=True, timer=3)

    def test_boot_options(self):
        boot_options = self.device.boot_options
        self.assertEqual(boot_options, {"sys": "EOS.swi"})

    def test_set_boot_options(self):
        results = [
            [{"result": {"output": "flash:"}}],
            [{"result": {"output": "new_image.swi"}}],
            [{"result": {}}],
            [{"result": {"softwareImage": "flash:new_image.swi"}}],
        ]
        calls = [
            mock.call(["dir"], encoding="text"),
            mock.call(["dir flash:"], encoding="text"),
            mock.call(["install source flash:new_image.swi"], encoding="json"),
            mock.call(["show boot-config"], encoding="json"),
        ]
        self.device.native.enable.side_effect = results
        self.device.set_boot_options("new_image.swi")
        self.device.native.enable.assert_has_calls(calls)

    def test_backup_running_config(self):
        filename = "local_running_config"
        self.device.backup_running_config(filename)

        with open(filename, "r") as f:
            contents = f.read()

        self.assertEqual(contents, self.device.running_config)
        os.remove(filename)

    def test_rollback(self):
        self.device.rollback("good_checkpoint")
        self.device.native.enable.assert_called_with(["configure replace good_checkpoint force"], encoding="json")

    def test_bad_rollback(self):
        with self.assertRaises(RollbackError):
            self.device.rollback("bad_checkpoint")

    def test_checkpoint(self):
        self.device.checkpoint("good_checkpoint")
        self.device.native.enable.assert_called_with(["copy running-config good_checkpoint"], encoding="json")

    def test_uptime(self):
        sh_version_output = self.device.show("show version")
        expected = int(time.time() - sh_version_output["bootupTimestamp"])
        uptime = self.device.uptime
        self.assertIsInstance(uptime, int)
        self.assertEqual(uptime, expected)

    @mock.patch.object(EOSDevice, "_uptime_to_string", autospec=True)
    def test_uptime_string(self, mock_upt_str):
        mock_upt_str.return_value = "02:00:03:38"
        uptime_string = self.device.uptime_string
        self.assertIsInstance(uptime_string, str)
        self.assertEqual(uptime_string, "02:00:03:38")

    def test_vendor(self):
        vendor = self.device.vendor
        self.assertEqual(vendor, "arista")

    def test_os_version(self):
        os_version = self.device.os_version
        self.assertEqual(os_version, "4.14.7M-2384414.4147M")

    def test_interfaces(self):
        interfaces = self.device.interfaces
        expected = [
            "Ethernet1",
            "Ethernet2",
            "Ethernet3",
            "Ethernet4",
            "Ethernet5",
            "Ethernet6",
            "Ethernet7",
            "Ethernet8",
            "Management1",
        ]
        self.assertEqual(interfaces, expected)

    def test_hostname(self):
        hostname = self.device.hostname
        self.assertEqual(hostname, "eos-spine1")

    def test_fqdn(self):
        fqdn = self.device.fqdn
        self.assertEqual(fqdn, "eos-spine1.ntc.com")

    def test_serial_number(self):
        serial_number = self.device.serial_number
        self.assertEqual(serial_number, "")

    def test_model(self):
        model = self.device.model
        self.assertEqual(model, "vEOS")

    @mock.patch.object(EOSVlans, "get_list", autospec=True)
    def test_vlans(self, mock_vlan_list):
        mock_vlan_list.return_value = ["1", "2", "10"]
        expected = ["1", "2", "10"]
        vlans = self.device.vlans

        self.assertEqual(vlans, expected)

    def test_running_config(self):
        expected = self.device.show("show running-config", raw_text=True)
        self.assertEqual(self.device.running_config, expected)

    def test_starting_config(self):
        expected = self.device.show("show startup-config", raw_text=True)
        self.assertEqual(self.device.startup_config, expected)
Example #8
0
class TestEOSDevice(unittest.TestCase):
    @mock.patch('pyeapi.client.Node', autospec=True)
    def setUp(self, mock_node):
        self.device = EOSDevice('host', 'user', 'pass')
        self.maxDiff = None

        mock_node.enable.side_effect = enable
        mock_node.config.side_effect = config
        self.device.native = mock_node

    def test_config(self):
        command = 'interface Eth1'
        result = self.device.config(command)

        self.assertIsNone(result)
        self.device.native.config.assert_called_with([command])

    def test_bad_config(self):
        command = 'asdf poknw'

        with self.assertRaisesRegexp(CommandError, command):
            self.device.config(command)

    def test_config_list(self):
        commands = ['interface Eth1', 'no shutdown']
        result = self.device.config_list(commands)

        self.assertIsNone(result)
        self.device.native.config.assert_called_with(commands)

    def test_bad_config_list(self):
        commands = ['interface Eth1', 'apons']

        with self.assertRaisesRegexp(CommandListError, commands[1]):
            self.device.config_list(commands)

    def test_show(self):
        command = 'show ip arp'
        result = self.device.show(command)

        self.assertIsInstance(result, dict)
        self.assertNotIn('command', result)
        self.assertIn('dynamicEntries', result)

        self.device.native.enable.assert_called_with([command],
                                                     encoding='json')

    def test_bad_show(self):
        command = 'show microsoft'
        with self.assertRaises(CommandError):
            self.device.show(command)

    def test_show_raw_text(self):
        command = 'show hostname'
        result = self.device.show(command, raw_text=True)

        self.assertIsInstance(result, str)
        self.assertEqual(result,
                         'Hostname: spine1\nFQDN:     spine1.ntc.com\n')
        self.device.native.enable.assert_called_with([command],
                                                     encoding='text')

    def test_show_list(self):
        commands = ['show hostname', 'show clock']

        result = self.device.show_list(commands)
        self.assertIsInstance(result, list)

        self.assertIn('hostname', result[0])
        self.assertIn('fqdn', result[0])
        self.assertIn('output', result[1])

        self.device.native.enable.assert_called_with(commands, encoding='json')

    def test_bad_show_list(self):
        commands = ['show badcommand', 'show clock']
        with self.assertRaisesRegexp(CommandListError, 'show badcommand'):
            self.device.show_list(commands)

    def test_save(self):
        result = self.device.save()
        self.assertTrue(result)
        self.device.native.enable.assert_called_with(
            ['copy running-config startup-config'], encoding='json')

    @mock.patch.object(EOSFileCopy, 'remote_file_exists', autospec=True)
    def test_file_copy_remote_exists(self, mock_fc):
        mock_fc.return_value = True
        result = self.device.file_copy_remote_exists('source_file')

        self.assertTrue(result)

    @mock.patch.object(EOSFileCopy, 'remote_file_exists', autospec=True)
    def test_file_copy_remote_exists_failure(self, mock_fc):
        mock_fc.return_value = False
        result = self.device.file_copy_remote_exists('source_file')

        self.assertFalse(result)

    @mock.patch('pyntc.devices.eos_device.EOSFileCopy', autospec=True)
    def test_file_copy(self, mock_fc):
        instance = mock_fc.return_value
        self.device.file_copy('source_file')

        instance.send.assert_called_with()

    def test_reboot(self):
        self.device.reboot(confirm=True)
        self.device.native.enable.assert_called_with(['reload now'],
                                                     encoding='json')

    def test_reboot_no_confirm(self):
        self.device.reboot()
        assert not self.device.native.enable.called

    def test_reboot_with_timer(self):
        with self.assertRaises(RebootTimerError):
            self.device.reboot(confirm=True, timer=3)

    def test_get_boot_options(self):
        boot_options = self.device.get_boot_options()
        self.assertEqual(boot_options, {'sys': 'EOS.swi'})

    def test_set_boot_options(self):
        self.device.set_boot_options('new_image.swi')
        self.device.native.enable.assert_called_with(
            ['install source new_image.swi'], encoding='json')

    def test_backup_running_config(self):
        filename = 'local_running_config'
        self.device.backup_running_config(filename)

        with open(filename, 'r') as f:
            contents = f.read()

        self.assertEqual(contents, self.device.running_config)
        os.remove(filename)

    def test_rollback(self):
        self.device.rollback('good_checkpoint')
        self.device.native.enable.assert_called_with(
            ['configure replace good_checkpoint force'], encoding='json')

    def test_bad_rollback(self):
        with self.assertRaises(RollbackError):
            self.device.rollback('bad_checkpoint')

    def test_checkpiont(self):
        self.device.checkpoint('good_checkpoint')
        self.device.native.enable.assert_called_with(
            ['copy running-config good_checkpoint'], encoding='json')

    @mock.patch.object(EOSVlans, 'get_list', autospec=True)
    def test_facts(self, mock_vlan_list):
        mock_vlan_list.return_value = ['1', '2', '10']
        facts = self.device.facts
        self.assertIsInstance(facts['uptime'], int)
        self.assertIsInstance(facts['uptime_string'], str)

        del facts['uptime']
        del facts['uptime_string']

        expected = {
            'vendor':
            'arista',
            'os_version':
            '4.14.7M-2384414.4147M',
            'interfaces': [
                'Ethernet1',
                'Ethernet2',
                'Ethernet3',
                'Ethernet4',
                'Ethernet5',
                'Ethernet6',
                'Ethernet7',
                'Ethernet8',
                'Management1',
            ],
            'hostname':
            'eos-spine1',
            'fqdn':
            'eos-spine1.ntc.com',
            'serial_number':
            '',
            'model':
            'vEOS',
            'vlans': ['1', '2', '10']
        }
        self.assertEqual(facts, expected)

        self.device.native.enable.reset_mock()
        facts = self.device.facts
        self.assertEqual(facts, expected)
        self.device.native.enable.assert_not_called()

    def test_running_config(self):
        expected = self.device.show('show running-config', raw_text=True)
        self.assertEqual(self.device.running_config, expected)

    def test_starting_config(self):
        expected = self.device.show('show startup-config', raw_text=True)
        self.assertEqual(self.device.startup_config, expected)
Example #9
0
class TestEOSDevice(unittest.TestCase):
    @mock.patch("pyeapi.client.Node", autospec=True)
    def setUp(self, mock_node):
        self.device = EOSDevice("host", "user", "pass")
        self.maxDiff = None

        mock_node.enable.side_effect = enable
        mock_node.config.side_effect = config
        self.device.native = mock_node

    def tearDown(self):
        # Reset the mock so we don't have transient test effects
        self.device.native.reset_mock()

    def test_config_pass_string(self):
        command = "interface Eth1"
        result = self.device.config(command)

        self.assertIsNone(result)
        self.device.native.config.assert_called_with(command)

    def test_config_pass_list(self):
        commands = ["interface Eth1", "no shutdown"]
        result = self.device.config(commands)

        self.assertIsNone(result)
        self.device.native.config.assert_called_with(commands)

    @mock.patch.object(EOSDevice, "config")
    def test_config_list(self, mock_config):
        commands = ["interface Eth1", "no shutdown"]
        self.device.config_list(commands)
        self.device.config.assert_called_with(commands)

    def test_bad_config_pass_string(self):
        command = "asdf poknw"
        response = "Error [1002]: asdf_poknw failed [None]"

        with pytest.raises(CommandError) as err:
            self.device.config(command)
        assert err.value.command == command
        assert err.value.cli_error_msg == response

    def test_bad_config_pass_list(self):
        commands = ["interface Eth1", "apons"]
        response = [
            "Valid",
            "\nCommand apons failed with message: Error [1002]: apons failed [None]\nCommand List: \n\tinterface Eth1\n\tapons\n",
        ]

        with pytest.raises(CommandListError) as err:
            self.device.config(commands)
        assert err.value.command == commands[1]
        assert err.value.message == response[1]

    @mock.patch.object(EOSDevice, "_parse_response")
    def test_show_pass_string(self, mock_parse):
        command = "show ip arp"
        return_value = [{
            "command": "show ip arp",
            "result": {
                "ipV4Neighbors": [{
                    "hwAddress": "2cc2.60ff.0011",
                    "interface": "Management1",
                    "age": 0,
                    "address": "10.0.0.2"
                }],
                "notLearnedEntries":
                0,
                "totalEntries":
                1,
                "dynamicEntries":
                1,
                "staticEntries":
                0,
            },
            "encoding": "json",
        }]
        mock_parse.return_value = return_value
        result = self.device.show(command)
        assert result == return_value[0]
        self.device._parse_response.assert_called_with([result],
                                                       raw_text=False)
        self.device.native.enable.assert_called_with([command],
                                                     encoding="json")

    @mock.patch.object(EOSDevice, "_parse_response")
    def test_show_pass_list(self, mock_parse):
        commands = ["show hostname", "show clock"]
        return_value = [
            {
                "command": "show hostname",
                "result": {
                    "hostname": "eos-spine1",
                    "fqdn": "eos-spine1.ntc.com"
                },
                "encoding": "json",
            },
            {
                "command": "show clock",
                "result": {
                    "output":
                    "Fri Jan 22 23:29:21 2016\nTimezone: UTC\nClock source: local\n"
                },
                "encoding": "text",
            },
        ]
        mock_parse.return_value = return_value
        result = self.device.show(commands)
        assert result == return_value
        self.device._parse_response.assert_called_with(result, raw_text=False)
        self.device.native.enable.assert_called_with(commands, encoding="json")

    def test_bad_show_pass_string(self):
        command = "show microsoft"
        response = "Error [1002]: show_microsoft failed [None]"
        with pytest.raises(CommandError) as err:
            self.device.show(command)
        assert err.value.command[0] == "show_microsoft"
        assert err.value.cli_error_msg == response

    def test_bad_show_pass_list(self):
        commands = ["show badcommand", "show clock"]
        response = [
            "\nCommand show_badcommand failed with message: Error [1002]: show_badcommand failed [None]\nCommand List: \n\tshow badcommand\n\tshow clock\n",
            "Valid",
        ]
        with pytest.raises(CommandListError) as err:
            self.device.show(commands)
        assert err.value.command == "show_badcommand"
        assert err.value.message == response[0]

    @mock.patch.object(EOSDevice, "_parse_response")
    def test_show_raw_text(self, mock_parse):
        command = "show hostname"
        mock_parse.return_value = [{
            "command": "show hostname",
            "result": {
                "output": "Hostname: spine1\nFQDN:     spine1.ntc.com\n"
            },
            "encoding": "text",
        }]
        result = self.device.show(command, raw_text=True)
        self.device._parse_response.assert_called_with([result], raw_text=True)
        self.device.native.enable.assert_called_with([command],
                                                     encoding="text")

    @mock.patch.object(EOSDevice, "show")
    def test_show_list(self, mock_config):
        commands = ["show hostname", "show clock"]
        self.device.show_list(commands)
        self.device.show.assert_called_with(commands)

    def test_save(self):
        result = self.device.save()
        self.assertTrue(result)
        self.device.native.enable.assert_called_with(
            ["copy running-config startup-config"], encoding="json")

    @mock.patch("pyeapi.client.Node", autospec=True)
    @mock.patch("netmiko.arista.arista.AristaSSH", autospec=True)
    def setup_test_file_copy_remote_exists(self, test_file_copy_remote_exists,
                                           mock_ssh, mock_node):
        self.device = EOSDevice("host", "user", "pass")
        self.maxDiff = None

        mock_node.enable.side_effect = enable
        mock_node.config.side_effect = config
        self.device.native = mock_node
        mock_ssh.send_command_timing.side_effect = send_command
        mock_ssh.send_command_expect.side_effect = send_command_expect
        self.device.native_ssh = mock_ssh

    def teardown_test_file_copy_remote_exists(self,
                                              test_file_copy_remote_exists):
        self.device.native.reset_mock()
        self.device.native_ssh.reset_mock()

    @mock.patch("pyntc.devices.eos_device.FileTransfer", autospec=True)
    @mock.patch.object(EOSDevice, "open")
    @mock.patch.object(EOSDevice, "close")
    @mock.patch("netmiko.arista.arista.AristaSSH", autospec=True)
    def test_file_copy_remote_exists(self, mock_open, mock_close, mock_ssh,
                                     mock_ft):
        self.device.native_ssh = mock_open
        self.device.native_ssh.send_command_timing.side_effect = None
        self.device.native_ssh.send_command_timing.return_value = "flash: /dev/null"
        mock_ft_instance = mock_ft.return_value
        mock_ft_instance.check_file_exists.return_value = True
        mock_ft_instance.compare_md5.return_value = True

        result = self.device.file_copy_remote_exists("source_file")

        self.assertTrue(result)

    @mock.patch("pyntc.devices.eos_device.FileTransfer", autospec=True)
    @mock.patch.object(EOSDevice, "open")
    @mock.patch.object(EOSDevice, "close")
    @mock.patch("netmiko.arista.arista.AristaSSH", autospec=True)
    def test_file_copy_remote_exists_bad_md5(self, mock_open, mock_close,
                                             mock_ssh, mock_ft):
        self.device.native_ssh = mock_open
        self.device.native_ssh.send_command_timing.side_effect = None
        self.device.native_ssh.send_command_timing.return_value = "flash: /dev/null"
        mock_ft_instance = mock_ft.return_value
        mock_ft_instance.check_file_exists.return_value = True
        mock_ft_instance.compare_md5.return_value = False

        result = self.device.file_copy_remote_exists("source_file")

        self.assertFalse(result)

    @mock.patch("pyntc.devices.eos_device.FileTransfer", autospec=True)
    @mock.patch.object(EOSDevice, "open")
    @mock.patch.object(EOSDevice, "close")
    @mock.patch("netmiko.arista.arista.AristaSSH", autospec=True)
    def test_file_copy_remote_not_exist(self, mock_open, mock_close, mock_ssh,
                                        mock_ft):

        self.device.native_ssh = mock_open
        self.device.native_ssh.send_command_timing.side_effect = None
        self.device.native_ssh.send_command_timing.return_value = "flash: /dev/null"

        mock_ft_instance = mock_ft.return_value
        mock_ft_instance.check_file_exists.return_value = False
        mock_ft_instance.compare_md5.return_value = True

        result = self.device.file_copy_remote_exists("source_file")

        self.assertFalse(result)

    @mock.patch("pyntc.devices.eos_device.FileTransfer", autospec=True)
    @mock.patch.object(EOSDevice, "open")
    @mock.patch.object(EOSDevice, "close")
    @mock.patch("netmiko.arista.arista.AristaSSH", autospec=True)
    def test_file_copy(self, mock_open, mock_close, mock_ssh, mock_ft):
        self.device.native_ssh = mock_open
        self.device.native_ssh.send_command_timing.side_effect = None
        self.device.native_ssh.send_command_timing.return_value = "flash: /dev/null"

        mock_ft_instance = mock_ft.return_value
        mock_ft_instance.check_file_exists.side_effect = [False, True]
        self.device.file_copy("path/to/source_file")

        mock_ft.assert_called_with(self.device.native_ssh,
                                   "path/to/source_file",
                                   "source_file",
                                   file_system="flash:")
        mock_ft_instance.enable_scp.assert_any_call()
        mock_ft_instance.establish_scp_conn.assert_any_call()
        mock_ft_instance.transfer_file.assert_any_call()

    @mock.patch("pyntc.devices.eos_device.FileTransfer", autospec=True)
    @mock.patch.object(EOSDevice, "open")
    @mock.patch.object(EOSDevice, "close")
    @mock.patch("netmiko.arista.arista.AristaSSH", autospec=True)
    def test_file_copy_different_dest(self, mock_open, mock_close, mock_ssh,
                                      mock_ft):
        self.device.native_ssh = mock_open
        self.device.native_ssh.send_command_timing.side_effect = None
        self.device.native_ssh.send_command_timing.return_value = "flash: /dev/null"

        mock_ft_instance = mock_ft.return_value
        mock_ft_instance.check_file_exists.side_effect = [False, True]
        self.device.file_copy("source_file", "dest_file")

        mock_ft.assert_called_with(self.device.native_ssh,
                                   "source_file",
                                   "dest_file",
                                   file_system="flash:")
        mock_ft_instance.enable_scp.assert_any_call()
        mock_ft_instance.establish_scp_conn.assert_any_call()
        mock_ft_instance.transfer_file.assert_any_call()

    @mock.patch("pyntc.devices.eos_device.FileTransfer", autospec=True)
    @mock.patch.object(EOSDevice, "open")
    @mock.patch.object(EOSDevice, "close")
    @mock.patch("netmiko.arista.arista.AristaSSH", autospec=True)
    def test_file_copy_fail(self, mock_open, mock_close, mock_ssh, mock_ft):
        self.device.native_ssh = mock_open
        self.device.native_ssh.send_command_timing.side_effect = None
        self.device.native_ssh.send_command_timing.return_value = "flash: /dev/null"

        mock_ft_instance = mock_ft.return_value
        mock_ft_instance.transfer_file.side_effect = Exception
        mock_ft_instance.check_file_exists.return_value = False

        with self.assertRaises(FileTransferError):
            self.device.file_copy("source_file")

    def test_reboot(self):
        self.device.reboot()
        self.device.native.enable.assert_called_with(["reload now"],
                                                     encoding="json")

    def test_reboot_with_timer(self):
        with self.assertRaises(RebootTimerError):
            self.device.reboot(timer=3)

    def test_boot_options(self):
        boot_options = self.device.boot_options
        self.assertEqual(boot_options, {"sys": "EOS.swi"})

    def test_set_boot_options(self):
        results = [
            [{
                "result": {
                    "output": "flash:"
                }
            }],
            [{
                "result": {
                    "output": "new_image.swi"
                }
            }],
            [{
                "result": {}
            }],
            [{
                "result": {
                    "softwareImage": "flash:new_image.swi"
                }
            }],
        ]
        calls = [
            mock.call(["dir"], encoding="text"),
            mock.call(["dir flash:"], encoding="text"),
            mock.call(["install source flash:new_image.swi"], encoding="json"),
            mock.call(["show boot-config"], encoding="json"),
        ]
        self.device.native.enable.side_effect = results
        self.device.set_boot_options("new_image.swi")
        self.device.native.enable.assert_has_calls(calls)

    def test_backup_running_config(self):
        filename = "local_running_config"
        self.device.backup_running_config(filename)

        with open(filename, "r") as f:
            contents = f.read()

        self.assertEqual(contents, self.device.running_config)
        os.remove(filename)

    def test_rollback(self):
        self.device.rollback("good_checkpoint")
        self.device.native.enable.assert_called_with(
            ["configure replace good_checkpoint force"], encoding="json")

    def test_bad_rollback(self):
        with self.assertRaises(RollbackError):
            self.device.rollback("bad_checkpoint")

    def test_checkpoint(self):
        self.device.checkpoint("good_checkpoint")
        self.device.native.enable.assert_called_with(
            ["copy running-config good_checkpoint"], encoding="json")

    def test_uptime(self):
        sh_version_output = self.device.show("show version")
        expected = int(time.time() - sh_version_output["bootupTimestamp"])
        uptime = self.device.uptime
        self.assertIsInstance(uptime, int)
        self.assertEqual(uptime, expected)

    @mock.patch.object(EOSDevice, "_uptime_to_string", autospec=True)
    def test_uptime_string(self, mock_upt_str):
        mock_upt_str.return_value = "02:00:03:38"
        uptime_string = self.device.uptime_string
        self.assertIsInstance(uptime_string, str)
        self.assertEqual(uptime_string, "02:00:03:38")

    def test_vendor(self):
        vendor = self.device.vendor
        self.assertEqual(vendor, "arista")

    def test_os_version(self):
        os_version = self.device.os_version
        self.assertEqual(os_version, "4.14.7M-2384414.4147M")

    def test_interfaces(self):
        interfaces = self.device.interfaces
        expected = [
            "Ethernet1",
            "Ethernet2",
            "Ethernet3",
            "Ethernet4",
            "Ethernet5",
            "Ethernet6",
            "Ethernet7",
            "Ethernet8",
            "Management1",
        ]
        self.assertEqual(interfaces, expected)

    def test_hostname(self):
        hostname = self.device.hostname
        self.assertEqual(hostname, "eos-spine1")

    def test_fqdn(self):
        fqdn = self.device.fqdn
        self.assertEqual(fqdn, "eos-spine1.ntc.com")

    def test_serial_number(self):
        serial_number = self.device.serial_number
        self.assertEqual(serial_number, "")

    def test_model(self):
        model = self.device.model
        self.assertEqual(model, "vEOS")

    @mock.patch.object(EOSVlans, "get_list", autospec=True)
    def test_vlans(self, mock_vlan_list):
        mock_vlan_list.return_value = ["1", "2", "10"]
        expected = ["1", "2", "10"]
        vlans = self.device.vlans

        self.assertEqual(vlans, expected)

    def test_running_config(self):
        expected = self.device.show("show running-config", raw_text=True)
        self.assertEqual(self.device.running_config, expected)

    def test_starting_config(self):
        expected = self.device.show("show startup-config", raw_text=True)
        self.assertEqual(self.device.startup_config, expected)