Пример #1
0
    def __init__(self, switch_descriptor, shell_factory):
        super(Dell, self).__init__(switch_descriptor)
        self.shell = None
        self.shell_factory = shell_factory

        self.page_reader = PageReader(read_while="--More-- or (q)uit",
                                      and_press="m",
                                      unless_prompt="#")
Пример #2
0
class PageReaderTest(unittest.TestCase):

    def setUp(self):
        self.reader = PageReader(
            read_while="--More-- or (q)uit",
            and_press="m",
            unless_prompt="#")

        self.shell_mock = flexmock()

    def tearDown(self):
        flexmock_teardown()

    def test_reads_without_pagination(self):
        self.shell_mock.should_receive("do").with_args("command", wait_for=("--More-- or (q)uit", "#"), include_last_line=True).once().ordered().and_return([
            "line1",
            "line2",
            "prompt#"
        ])

        result = self.reader.do(self.shell_mock, "command")

        assert_that(result, is_([
            "line1",
            "line2"
        ]))

    def test_reads_2_pages_and_removes_page_indicators_and_prompt(self):
        self.shell_mock.should_receive("do").with_args("command", wait_for=("--More-- or (q)uit", "#"), include_last_line=True).once().ordered().and_return([
            "line1",
            "line2",
            "--More-- or (q)uit"
        ])

        self.shell_mock.should_receive("send_key").with_args("m", wait_for=("--More-- or (q)uit", "#"), include_last_line=True).once().ordered().and_return([
            "line3",
            "line4",
            "--More-- or (q)uit"
        ])

        self.shell_mock.should_receive("send_key").with_args("m", wait_for=("--More-- or (q)uit", "#"), include_last_line=True).once().ordered().and_return([
            "line5",
            "line6",
            "prompt#"
        ])

        result = self.reader.do(self.shell_mock, "command")

        assert_that(result, is_([
            "line1",
            "line2",
            "line3",
            "line4",
            "line5",
            "line6"
        ]))
Пример #3
0
    def setUp(self):
        self.reader = PageReader(
            read_while="--More-- or (q)uit",
            and_press="m",
            unless_prompt="#")

        self.shell_mock = flexmock()
Пример #4
0
class PageReaderTest(unittest.TestCase):
    def setUp(self):
        self.reader = PageReader(read_while="--More-- or (q)uit",
                                 and_press="m",
                                 unless_prompt="#")

        self.shell_mock = flexmock()

    def tearDown(self):
        flexmock_teardown()

    def test_reads_without_pagination(self):
        self.shell_mock.should_receive("do").with_args(
            "command",
            wait_for=("--More-- or (q)uit", "#"),
            include_last_line=True).once().ordered().and_return(
                ["line1", "line2", "prompt#"])

        result = self.reader.do(self.shell_mock, "command")

        assert_that(result, is_(["line1", "line2"]))

    def test_reads_2_pages_and_removes_page_indicators_and_prompt(self):
        self.shell_mock.should_receive("do").with_args(
            "command",
            wait_for=("--More-- or (q)uit", "#"),
            include_last_line=True).once().ordered().and_return(
                ["line1", "line2", "--More-- or (q)uit"])

        self.shell_mock.should_receive("send_key").with_args(
            "m", wait_for=("--More-- or (q)uit", "#"),
            include_last_line=True).once().ordered().and_return(
                ["line3", "line4", "--More-- or (q)uit"])

        self.shell_mock.should_receive("send_key").with_args(
            "m", wait_for=("--More-- or (q)uit", "#"),
            include_last_line=True).once().ordered().and_return(
                ["line5", "line6", "prompt#"])

        result = self.reader.do(self.shell_mock, "command")

        assert_that(
            result, is_(["line1", "line2", "line3", "line4", "line5",
                         "line6"]))
Пример #5
0
class Dell(SwitchBase):
    def __init__(self, switch_descriptor, shell_factory):
        super(Dell, self).__init__(switch_descriptor)
        self.shell = None
        self.shell_factory = shell_factory

        self.page_reader = PageReader(read_while="--More-- or (q)uit",
                                      and_press="m",
                                      unless_prompt="#")

    def _connect(self):
        params = dict(
            host=self.switch_descriptor.hostname,
            username=self.switch_descriptor.username,
            password=self.switch_descriptor.password,
        )

        if self.switch_descriptor.port:
            params["port"] = self.switch_descriptor.port

        self.shell = self.shell_factory(**params)

        self.shell.do("enable", wait_for=":")
        password_return = self.shell.do(self.switch_descriptor.password)
        if any(["Incorrect Password" in line for line in password_return]):
            raise PrivilegedAccessRefused(password_return)

    def _disconnect(self):
        self.shell.quit("quit")
        self.logger.info(self.shell.full_log)

    def _start_transaction(self):
        pass

    def _end_transaction(self):
        pass

    def rollback_transaction(self):
        pass

    def commit_transaction(self):
        self.shell.do("copy running-config startup-config",
                      wait_for="? (y/n) ")
        self.shell.send_key("y")

    def set_interface_state(self, interface_id, state):
        with self.config(), self.interface(interface_id):
            self.shell.do('shutdown' if state is OFF else 'no shutdown')

    def get_vlans(self):
        result = self.page_reader.do(self.shell, "show vlan")
        vlans = parse_vlan_list(result)
        return vlans

    def get_vlan(self, vlan_number):
        result = self.page_reader.do(self.shell,
                                     "show vlan id {}".format(vlan_number))

        if regex.match(".*\^.*", result[0]):
            raise BadVlanNumber()
        elif regex.match("^ERROR", result[0]):
            raise UnknownVlan(vlan_number)
        vlan = parse_vlan_list(result)[0]
        return vlan

    def get_vlan_interfaces(self, vlan_number):
        result = self.page_reader.do(self.shell,
                                     "show vlan id {}".format(vlan_number))

        if regex.match(".*\^.*", result[0]):
            raise BadVlanNumber()
        elif regex.match("^ERROR", result[0]):
            raise UnknownVlan(vlan_number)

        return self.parse_interface_from_vlan_list(vlan_number, result)

    def get_interface(self, interface_id):
        return self.read_interface(interface_id)

    def get_interfaces(self):
        result = self.page_reader.do(self.shell, 'show interfaces status')

        return [
            self.read_interface(name)
            for name in self.parse_interface_names(result)
        ]

    def add_vlan(self, number, name=None):
        result = self.page_reader.do(self.shell,
                                     "show vlan id {}".format(number))
        if regex.match(".*\^.*", result[0]):
            raise BadVlanNumber()
        elif regex.match("^VLAN", result[0]):
            raise VlanAlreadyExist(number)

        with self.config():
            with self.vlan_database():
                self.set('vlan {}', number)

            if name is not None:
                with self.interface("vlan {}".format(number)):
                    self.set('name {}', name).on_any_result(BadVlanName)

    def remove_vlan(self, number, name=None):
        with self.config():
            with self.vlan_database():
                self.set('no vlan {}', number).on_result_matching(
                    ".*These VLANs do not exist:.*", UnknownVlan, number)

    def set_interface_description(self, interface_id, description):
        with self.config(), self.interface(interface_id):
            self.set('description "{}"',
                     description).on_any_result(BadInterfaceDescription,
                                                description)

    def set_access_mode(self, interface_id):
        with self.config(), self.interface(interface_id):
            self.shell.do("switchport mode access")

    def set_trunk_mode(self, interface_id):
        interface_data = self.get_interface_data(interface_id)
        actual_port_mode = resolve_port_mode(interface_data)

        if actual_port_mode in ("access", None):
            with self.config(), self.interface(interface_id):
                self.shell.do("switchport mode trunk")

    def set_access_vlan(self, interface_id, vlan):
        with self.config(), self.interface(interface_id):
            self.set("switchport access vlan {}", vlan)\
                .on_result_matching(".*VLAN ID not found.*", UnknownVlan, vlan)\
                .on_result_matching(".*Interface not in Access Mode.*", InterfaceInWrongPortMode, "trunk")

    def set_interface_mtu(self, interface_id, size):
        with self.config(), self.interface(interface_id):
            self.set("mtu {}", size)\
                .on_result_matching(".*Value is out of range.*", InvalidMtuSize, size)

    def unset_interface_mtu(self, interface_id):
        with self.config(), self.interface(interface_id):
            self.set("no mtu")

    def set_bond_mtu(self, number, size):
        with NamedBond(number) as bond:
            self.set_interface_mtu(bond.name, size)

    def unset_bond_mtu(self, number):
        with NamedBond(number) as bond:
            self.unset_interface_mtu(bond.name)

    def unset_interface_access_vlan(self, interface_id):
        with self.config(), self.interface(interface_id):
            self.shell.do("no switchport access vlan")

    def set_interface_native_vlan(self, interface_id, vlan):
        interface_data = self.get_interface_data(interface_id)

        actual_port_mode = resolve_port_mode(interface_data)
        if actual_port_mode == "access":
            raise InterfaceInWrongPortMode("access")

        with self.config(), self.interface(interface_id):
            if actual_port_mode != "general":
                self.set("switchport mode general")
            if actual_port_mode == "trunk":
                self.copy_vlans(interface_data, "trunk", "general")

            self.set("switchport general pvid {}",
                     vlan).on_any_result(UnknownVlan, vlan)

    def unset_interface_native_vlan(self, interface_id):
        interface_data = self.get_interface_data(interface_id)
        assert_native_vlan_is_set(interface_id, interface_data)

        with self.config(), self.interface(interface_id):
            self.set("switchport mode trunk")
            self.copy_vlans(interface_data, "general", "trunk")

    def add_trunk_vlan(self, interface_id, vlan):
        interface_data = self.get_interface_data(interface_id)

        actual_port_mode = resolve_port_mode(interface_data)
        if actual_port_mode == "access":
            raise InterfaceInWrongPortMode("access")

        with self.config(), self.interface(interface_id):
            if actual_port_mode is None:
                self.set("switchport mode trunk")
                actual_port_mode = "trunk"

            self.set("switchport {} allowed vlan add {}", actual_port_mode, vlan)\
                .on_result_matching(".*VLAN does not exist.*", UnknownVlan, vlan)

    def remove_trunk_vlan(self, interface_id, vlan):
        interface_data = self.get_interface_data(interface_id)
        trunk_vlans = resolve_trunk_vlans(interface_data)

        if vlan not in trunk_vlans:
            raise TrunkVlanNotSet(interface_id)

        actual_port_mode = resolve_port_mode(interface_data)
        with self.config(), self.interface(interface_id):
            self.set("switchport {} allowed vlan remove {}", actual_port_mode,
                     vlan)

    def edit_interface_spanning_tree(self, interface_id, edge=None):
        commands = []
        if edge is not None:
            commands.append(
                "{}spanning-tree portfast".format("" if edge else "no "))

        if commands:
            with self.config(), self.interface(interface_id):
                [self.shell.do(cmd) for cmd in commands]

    def set_interface_lldp_state(self, interface_id, enabled):
        with self.config(), self.interface(interface_id):
            self.set("{}lldp transmit", "" if enabled else "no ")
            self.set("{}lldp receive", "" if enabled else "no ")
            self.set("{}lldp med transmit-tlv capabilities",
                     "" if enabled else "no ")
            self.set("{}lldp med transmit-tlv network-policy",
                     "" if enabled else "no ")

    def set_bond_description(self, number, description):
        with NamedBond(number) as bond:
            return self.set_interface_description(bond.name, description)

    def set_bond_trunk_mode(self, number):
        with NamedBond(number) as bond:
            return self.set_trunk_mode(bond.name)

    def set_bond_access_mode(self, number):
        with NamedBond(number) as bond:
            return self.set_access_mode(bond.name)

    def add_bond_trunk_vlan(self, number, vlan):
        with NamedBond(number) as bond:
            return self.add_trunk_vlan(bond.name, vlan)

    def remove_bond_trunk_vlan(self, number, vlan):
        with NamedBond(number) as bond:
            return self.remove_trunk_vlan(bond.name, vlan)

    def set_bond_native_vlan(self, number, vlan):
        with NamedBond(number) as bond:
            return self.set_interface_native_vlan(bond.name, vlan)

    def unset_bond_native_vlan(self, number):
        with NamedBond(number) as bond:
            return self.unset_interface_native_vlan(bond.name)

    def config(self):
        return SubShell(self.shell, enter="configure", exit_cmd='exit')

    def vlan_database(self):
        return SubShell(self.shell, enter="vlan database", exit_cmd='exit')

    def interface(self, interface_id):
        return SubShell(self.shell,
                        enter="interface {}".format(interface_id),
                        exit_cmd='exit',
                        validate=no_output(UnknownInterface, interface_id))

    def set(self, command, *arguments):
        result = self.shell.do(command.format(*arguments))

        return ResultChecker(result)

    def get_interface_data(self, interface_id):
        interface_data = self.page_reader.do(
            self.shell,
            "show running-config interface {}".format(interface_id))
        if any([
                "Invalid input" in line or regex.match("ERROR.*", line)
                for line in interface_data
        ]):
            raise UnknownInterface(interface_id)
        return interface_data

    def copy_vlans(self, data, from_mode, to_mode):
        for line in data:
            if regex.match("switchport {} allowed vlan.*".format(from_mode),
                           line):
                self.shell.do(line.replace(from_mode, to_mode))

    def parse_interface_names(self, status_list):
        interfaces = []
        for line in status_list:
            if regex.match("(\d\S+).*", line):
                interfaces.append("ethernet {}".format(regex[0]))
            elif regex.match("ch(\d+).*", line):
                interfaces.append("port-channel {}".format(regex[0]))

        return interfaces

    def read_interface(self, interface_name):
        data = self.get_interface_data(interface_name)

        interface = Interface(name=interface_name,
                              port_mode=ACCESS,
                              shutdown=False)
        for line in data:
            if regex.match("switchport mode \S+", line):
                interface.port_mode = TRUNK
            if regex.match("shutdown", line):
                interface.shutdown = True
            if regex.match("switchport access vlan (\d+)", line):
                interface.access_vlan = int(regex[0])
            if regex.match("switchport general pvid (\d+)", line):
                interface.trunk_native_vlan = int(regex[0])
            if regex.match("switchport \S+ allowed vlan add (\S+)", line):
                interface.trunk_vlans += parse_vlan_ranges(regex[0])
            if regex.match("mtu (\d+)", line):
                interface.mtu = int(regex[0])

        return interface

    def reset_interface(self, interface_id):
        with self.config(), self.interface(interface_id):
            self.shell.do("no switchport access vlan")
            self.shell.do("no switchport mode")
            self.shell.do("no mtu")
        data = "\n".join(self.get_interface_data(interface_id))
        if len(data) > 0:
            raise InterfaceResetIncomplete("{}".format(data))

    def parse_interface_from_vlan_list(self, vlan_number, result):
        vlan_interfaces = []
        number = None
        for line in result:
            if regex.match('^(\d+)(.*)', line):
                number, leftover = regex
                if int(number) == vlan_number:
                    if regex.match('^\s{1,6}\S*\s+([a-zA-Z0-9-,/]+).*',
                                   leftover):
                        vlan_interfaces.extend(
                            self.parse_interface_port_list(regex[0]))

            elif regex.match('^\s+([a-zA-Z0-9-,/]+).*',
                             line) and int(number) == vlan_number:
                vlan_interfaces.extend(self.parse_interface_port_list(
                    regex[0]))

        return vlan_interfaces

    def parse_interface_port_list(self, ports):
        port_list = filter(None, ports.split(','))
        interface_list = []
        for port in port_list:
            if regex.match('^ch(\d+)-(\d+)', port):
                start, end = regex
                for i in range(int(start), int(end) + 1):
                    interface_list.append("port-channel {}".format(i))
            elif regex.match('^ch(\d+)', port):
                start = regex[0]
                interface_list.append("port-channel {}".format(start))
            elif regex.match('^(\d/[a-z]+)(\d+)-\d/[a-z]+(\d+)', port):
                debut, start, end = regex
                for i in range(int(start), int(end) + 1):
                    interface_list.append("ethernet {0}{1}".format(debut, i))
            elif regex.match('^(\d/[a-z]+)(\d+)', port):
                debut, start = regex
                interface_list.append("ethernet {0}{1}".format(debut, start))
        return interface_list
Пример #6
0
    def setUp(self):
        self.reader = PageReader(read_while="--More-- or (q)uit",
                                 and_press="m",
                                 unless_prompt="#")

        self.shell_mock = flexmock()
Пример #7
0
    def __init__(self, switch_descriptor, shell_factory):
        super(Dell, self).__init__(switch_descriptor)
        self.shell = None
        self.shell_factory = shell_factory

        self.page_reader = PageReader(read_while="--More-- or (q)uit", and_press="m", unless_prompt="#")
Пример #8
0
class Dell(SwitchBase):
    def __init__(self, switch_descriptor, shell_factory):
        super(Dell, self).__init__(switch_descriptor)
        self.shell = None
        self.shell_factory = shell_factory

        self.page_reader = PageReader(read_while="--More-- or (q)uit", and_press="m", unless_prompt="#")

    def _connect(self):
        params = dict(
            host=self.switch_descriptor.hostname,
            username=self.switch_descriptor.username,
            password=self.switch_descriptor.password,
        )

        if self.switch_descriptor.port:
            params["port"] = self.switch_descriptor.port

        self.shell = self.shell_factory(**params)

        self.shell.do("enable", wait_for=":")
        self.shell.do(self.switch_descriptor.password)

    def _disconnect(self):
        self.shell.quit("quit")
        self.logger.info(self.shell.full_log)

    def _start_transaction(self):
        pass

    def _end_transaction(self):
        pass

    def rollback_transaction(self):
        pass

    def commit_transaction(self):
        self.shell.do("copy running-config startup-config", wait_for="? (y/n) ")
        self.shell.send_key("y")

    def set_interface_state(self, interface_id, state):
        with self.config(), self.interface(interface_id):
            self.shell.do("shutdown" if state is OFF else "no shutdown")

    def get_vlans(self):
        result = self.page_reader.do(self.shell, "show vlan")
        vlans = parse_vlan_list(result)
        return vlans

    def get_vlan(self, vlan_number):
        result = self.page_reader.do(self.shell, "show vlan id {}".format(vlan_number))

        if regex.match(".*\^.*", result[0]):
            raise BadVlanNumber()
        elif regex.match("^ERROR", result[0]):
            raise UnknownVlan(vlan_number)
        vlan = parse_vlan_list(result)[0]
        return vlan

    def get_vlan_interfaces(self, vlan_number):
        result = self.page_reader.do(self.shell, "show vlan id {}".format(vlan_number))

        if regex.match(".*\^.*", result[0]):
            raise BadVlanNumber()
        elif regex.match("^ERROR", result[0]):
            raise UnknownVlan(vlan_number)

        return self.parse_interface_from_vlan_list(vlan_number, result)

    def get_interface(self, interface_id):
        return self.read_interface(interface_id)

    def get_interfaces(self):
        result = self.page_reader.do(self.shell, "show interfaces status")

        return [self.read_interface(name) for name in self.parse_interface_names(result)]

    def add_vlan(self, number, name=None):
        result = self.page_reader.do(self.shell, "show vlan id {}".format(number))
        if regex.match(".*\^.*", result[0]):
            raise BadVlanNumber()
        elif regex.match("^VLAN", result[0]):
            raise VlanAlreadyExist(number)

        with self.config():
            with self.vlan_database():
                self.set("vlan {}", number)

            if name is not None:
                with self.interface("vlan {}".format(number)):
                    self.set("name {}", name).on_any_result(BadVlanName)

    def remove_vlan(self, number, name=None):
        with self.config():
            with self.vlan_database():
                self.set("no vlan {}", number).on_result_matching(".*These VLANs do not exist:.*", UnknownVlan, number)

    def set_interface_description(self, interface_id, description):
        with self.config(), self.interface(interface_id):
            self.set('description "{}"', description).on_any_result(BadInterfaceDescription, description)

    def set_access_mode(self, interface_id):
        with self.config(), self.interface(interface_id):
            self.shell.do("switchport mode access")

    def set_trunk_mode(self, interface_id):
        interface_data = self.get_interface_data(interface_id)
        actual_port_mode = resolve_port_mode(interface_data)

        if actual_port_mode in ("access", None):
            with self.config(), self.interface(interface_id):
                self.shell.do("switchport mode trunk")

    def set_access_vlan(self, interface_id, vlan):
        with self.config(), self.interface(interface_id):
            self.set("switchport access vlan {}", vlan).on_result_matching(
                ".*VLAN ID not found.*", UnknownVlan, vlan
            ).on_result_matching(".*Interface not in Access Mode.*", InterfaceInWrongPortMode, "trunk")

    def set_interface_mtu(self, interface_id, size):
        with self.config(), self.interface(interface_id):
            self.set("mtu {}", size).on_result_matching(".*Value is out of range.*", InvalidMtuSize, size)

    def unset_interface_mtu(self, interface_id):
        with self.config(), self.interface(interface_id):
            self.set("no mtu")

    def set_bond_mtu(self, number, size):
        with NamedBond(number) as bond:
            self.set_interface_mtu(bond.name, size)

    def unset_bond_mtu(self, number):
        with NamedBond(number) as bond:
            self.unset_interface_mtu(bond.name)

    def unset_interface_access_vlan(self, interface_id):
        with self.config(), self.interface(interface_id):
            self.shell.do("no switchport access vlan")

    def set_interface_native_vlan(self, interface_id, vlan):
        interface_data = self.get_interface_data(interface_id)

        actual_port_mode = resolve_port_mode(interface_data)
        if actual_port_mode == "access":
            raise InterfaceInWrongPortMode("access")

        with self.config(), self.interface(interface_id):
            if actual_port_mode != "general":
                self.set("switchport mode general")
            if actual_port_mode == "trunk":
                self.copy_vlans(interface_data, "trunk", "general")

            self.set("switchport general pvid {}", vlan).on_any_result(UnknownVlan, vlan)

    def unset_interface_native_vlan(self, interface_id):
        interface_data = self.get_interface_data(interface_id)
        assert_native_vlan_is_set(interface_id, interface_data)

        with self.config(), self.interface(interface_id):
            self.set("switchport mode trunk")
            self.copy_vlans(interface_data, "general", "trunk")

    def add_trunk_vlan(self, interface_id, vlan):
        interface_data = self.get_interface_data(interface_id)

        actual_port_mode = resolve_port_mode(interface_data)
        if actual_port_mode == "access":
            raise InterfaceInWrongPortMode("access")

        with self.config(), self.interface(interface_id):
            if actual_port_mode is None:
                self.set("switchport mode trunk")
                actual_port_mode = "trunk"

            self.set("switchport {} allowed vlan add {}", actual_port_mode, vlan).on_result_matching(
                ".*VLAN does not exist.*", UnknownVlan, vlan
            )

    def remove_trunk_vlan(self, interface_id, vlan):
        interface_data = self.get_interface_data(interface_id)
        trunk_vlans = resolve_trunk_vlans(interface_data)

        if vlan not in trunk_vlans:
            raise TrunkVlanNotSet(interface_id)

        actual_port_mode = resolve_port_mode(interface_data)
        with self.config(), self.interface(interface_id):
            self.set("switchport {} allowed vlan remove {}", actual_port_mode, vlan)

    def edit_interface_spanning_tree(self, interface_id, edge=None):
        commands = []
        if edge is not None:
            commands.append("{}spanning-tree portfast".format("" if edge else "no "))

        if commands:
            with self.config(), self.interface(interface_id):
                [self.shell.do(cmd) for cmd in commands]

    def set_interface_lldp_state(self, interface_id, enabled):
        with self.config(), self.interface(interface_id):
            self.set("{}lldp transmit", "" if enabled else "no ")
            self.set("{}lldp receive", "" if enabled else "no ")
            self.set("{}lldp med transmit-tlv capabilities", "" if enabled else "no ")
            self.set("{}lldp med transmit-tlv network-policy", "" if enabled else "no ")

    def set_bond_description(self, number, description):
        with NamedBond(number) as bond:
            return self.set_interface_description(bond.name, description)

    def set_bond_trunk_mode(self, number):
        with NamedBond(number) as bond:
            return self.set_trunk_mode(bond.name)

    def set_bond_access_mode(self, number):
        with NamedBond(number) as bond:
            return self.set_access_mode(bond.name)

    def add_bond_trunk_vlan(self, number, vlan):
        with NamedBond(number) as bond:
            return self.add_trunk_vlan(bond.name, vlan)

    def remove_bond_trunk_vlan(self, number, vlan):
        with NamedBond(number) as bond:
            return self.remove_trunk_vlan(bond.name, vlan)

    def set_bond_native_vlan(self, number, vlan):
        with NamedBond(number) as bond:
            return self.set_interface_native_vlan(bond.name, vlan)

    def unset_bond_native_vlan(self, number):
        with NamedBond(number) as bond:
            return self.unset_interface_native_vlan(bond.name)

    def config(self):
        return SubShell(self.shell, enter="configure", exit_cmd="exit")

    def vlan_database(self):
        return SubShell(self.shell, enter="vlan database", exit_cmd="exit")

    def interface(self, interface_id):
        return SubShell(
            self.shell,
            enter="interface {}".format(interface_id),
            exit_cmd="exit",
            validate=no_output(UnknownInterface, interface_id),
        )

    def set(self, command, *arguments):
        result = self.shell.do(command.format(*arguments))

        return ResultChecker(result)

    def get_interface_data(self, interface_id):
        interface_data = self.page_reader.do(self.shell, "show running-config interface {}".format(interface_id))
        if any(["Invalid input" in line or regex.match("ERROR.*", line) for line in interface_data]):
            raise UnknownInterface(interface_id)
        return interface_data

    def copy_vlans(self, data, from_mode, to_mode):
        for line in data:
            if regex.match("switchport {} allowed vlan.*".format(from_mode), line):
                self.shell.do(line.replace(from_mode, to_mode))

    def parse_interface_names(self, status_list):
        interfaces = []
        for line in status_list:
            if regex.match("(\d\S+).*", line):
                interfaces.append("ethernet {}".format(regex[0]))
            elif regex.match("ch(\d+).*", line):
                interfaces.append("port-channel {}".format(regex[0]))

        return interfaces

    def read_interface(self, interface_name):
        data = self.get_interface_data(interface_name)

        interface = Interface(name=interface_name, port_mode=ACCESS, shutdown=False)
        for line in data:
            if regex.match("switchport mode \S+", line):
                interface.port_mode = TRUNK
            if regex.match("shutdown", line):
                interface.shutdown = True
            if regex.match("switchport access vlan (\d+)", line):
                interface.access_vlan = int(regex[0])
            if regex.match("switchport general pvid (\d+)", line):
                interface.trunk_native_vlan = int(regex[0])
            if regex.match("switchport \S+ allowed vlan add (\S+)", line):
                interface.trunk_vlans += parse_vlan_ranges(regex[0])
            if regex.match("mtu (\d+)", line):
                interface.mtu = int(regex[0])

        return interface

    def reset_interface(self, interface_id):
        with self.config(), self.interface(interface_id):
            self.shell.do("no switchport access vlan")
            self.shell.do("no switchport mode")
            self.shell.do("no mtu")
        data = "\n".join(self.get_interface_data(interface_id))
        if len(data) > 0:
            raise InterfaceResetIncomplete("{}".format(data))

    def parse_interface_from_vlan_list(self, vlan_number, result):
        vlan_interfaces = []
        number = None
        for line in result:
            if regex.match("^(\d+)(.*)", line):
                number, leftover = regex
                if int(number) == vlan_number:
                    if regex.match("^\s{1,6}\S*\s+([a-zA-Z0-9-,/]+).*", leftover):
                        vlan_interfaces.extend(self.parse_interface_port_list(regex[0]))

            elif regex.match("^\s+([a-zA-Z0-9-,/]+).*", line) and int(number) == vlan_number:
                vlan_interfaces.extend(self.parse_interface_port_list(regex[0]))

        return vlan_interfaces

    def parse_interface_port_list(self, ports):
        port_list = filter(None, ports.split(","))
        interface_list = []
        for port in port_list:
            if regex.match("^ch(\d+)-(\d+)", port):
                start, end = regex
                for i in range(int(start), int(end) + 1):
                    interface_list.append("port-channel {}".format(i))
            elif regex.match("^ch(\d+)", port):
                start = regex[0]
                interface_list.append("port-channel {}".format(start))
            elif regex.match("^(\d/[a-z]+)(\d+)-\d/[a-z]+(\d+)", port):
                debut, start, end = regex
                for i in range(int(start), int(end) + 1):
                    interface_list.append("ethernet {0}{1}".format(debut, i))
            elif regex.match("^(\d/[a-z]+)(\d+)", port):
                debut, start = regex
                interface_list.append("ethernet {0}{1}".format(debut, start))
        return interface_list