def testValues_insert_after_atomic_factory_01(self):
        """Ensure that comments which are added, assert is_comment"""
        with patch('__main__.IOSCfgLine') as mock:
            # the mock pretends to be an IOSCfgLine so we can test against it
            result_correct01 = mock
            result_correct01.linenum = 16
            result_correct01.text = ' ! TODO: some note to self'
            result_correct01.classname = 'IOSCfgLine'
            result_correct01.is_comment = True

        result_correct02 = [
            'interface GigabitEthernet4/1', 
            ' ! TODO: some note to self',
            ' switchport', 
            ' switchport access vlan 100', 
            ' switchport voice vlan 150', 
            ' power inline static max 7000',
            ]
        linespec = 'interface GigabitEthernet4/1'
        cfg = CiscoConfParse(self.c01, factory=True)
        cfg.insert_after(linespec, ' ! TODO: some note to self', 
            exactmatch=True, atomic=True)

        test_result01 = cfg.find_objects('TODO')[0]
        self.assertEqual(result_correct01.linenum, test_result01.linenum)
        self.assertEqual(result_correct01.text, test_result01.text)
        self.assertEqual(result_correct01.classname, test_result01.classname)
        self.assertEqual(result_correct01.is_comment, test_result01.is_comment)

        # FIXME: this fails... maybe because I don't parse comments as children correctly???
        test_result02 = cfg.find_children(linespec)
        self.assertEqual(result_correct02, test_result02)
def Modify_Conf():
    parse = CiscoConfParse('cat.txt')

    #特定のI/FのVLAN番号を変更する
    #例:10、12番ポートのVLAN番号を変更する
    for i in range(25):
        if (i == 10):
            for intf in parse.find_objects(r'^interface GigabitEthernet0/' +
                                           str(i)):
                if (intf.has_child_with(r' switchport access vlan')):
                    intf.delete_children_matching(r' switchport access vlan')
                    parse.insert_after(r'^interface GigabitEthernet0/' +
                                       str(i),
                                       insertstr=' switchport access vlan 999',
                                       exactmatch=False,
                                       ignore_ws=False,
                                       atomic=False)
                    parse.commit()

        elif (i == 12):
            for intf in parse.find_objects(r'^interface GigabitEthernet0/' +
                                           str(i)):
                if (intf.has_child_with(r' switchport access vlan')):
                    intf.delete_children_matching(r' switchport access vlan')
                    parse.insert_after(r'^interface GigabitEthernet0/' +
                                       str(i),
                                       insertstr=' switchport access vlan 999',
                                       exactmatch=False,
                                       ignore_ws=False,
                                       atomic=False)
                    parse.commit()

    #新規ファイルに書き込み
    parse.save_as('cat2.txt')
    def testValues_insert_after_nonatomic_02(self):
        """Negative test.  We expect insert_after(atomic=False) to miss any children added like this at some point in the future I might fix insert_after so it knows how to correctly parse children"""
        result_correct = ['interface GigabitEthernet4/1', 
            #' shutdown',   <--- Intentionally commented out
            ' switchport', 
            ' switchport access vlan 100', 
            ' switchport voice vlan 150', 
            ' power inline static max 7000',
            ]
        linespec = 'interface GigabitEthernet4/1'
        cfg = CiscoConfParse(self.c01, factory=False)
        cfg.insert_after(linespec, ' shutdown', exactmatch=True, atomic=False)
        test_result = cfg.find_children(linespec)

        self.assertEqual(result_correct, test_result)
    def testValues_insert_after_atomic_01(self):
        """We expect insert_after(atomic=True) to correctly parse children"""
        ## See also -> testValues_insert_after_nonatomic_02()
        result_correct = [
            'interface GigabitEthernet4/1', 
            ' shutdown',
            ' switchport', 
            ' switchport access vlan 100', 
            ' switchport voice vlan 150', 
            ' power inline static max 7000',
            ]
        linespec = 'interface GigabitEthernet4/1'
        cfg = CiscoConfParse(self.c01, factory=False)
        cfg.insert_after(linespec, ' shutdown', exactmatch=True, atomic=True)
        test_result = cfg.find_children(linespec)

        self.assertEqual(result_correct, test_result)
 def testValues_insert_after_nonatomic_01(self):
     inputs = ['interface GigabitEthernet4/1',
         'interface GigabitEthernet4/2',
         'interface GigabitEthernet4/3',
         'interface GigabitEthernet4/4',
         'interface GigabitEthernet4/5',
         'interface GigabitEthernet4/6',
         'interface GigabitEthernet4/7',
         'interface GigabitEthernet4/8',
         ]
     cfg = CiscoConfParse(self.c01, factory=False)
     for idx, linespec in enumerate(inputs):
         test_result = cfg.insert_after(linespec, ' shutdown',
             exactmatch=True, atomic=False)
         result_correct = [inputs[idx]]
         self.assertEqual(result_correct, test_result)
def standardize_configs(ip, chan):

    print "Downloading running configuration"
    output = send_command("enable", "!Tmgmt", "skip", "sh run", read=True, chan=chan)

    # Captures running config
    capture = re.findall(r"!\r\nver.*end", output, re.S).pop()

    # Parses running config
    print "Parsing configuraion"
    output = CiscoConfParse(capture.splitlines())

    # Corrects DNS Setting
    dns = output.find_lines(r"ip dns server-address.*")
    output.replace_lines(r"ip dns server-address.*", r"ip dns server-address 10.210.1.214 10.220.1.200")
    print ("Correcting dns entry")
    send_command(
        "no {0}".format(dns.pop()), "ip dns server-address 10.210.1.214 10.220.1.200", configure=True, chan=chan
    )

    # Enables IGMP Snooping globally
    output.insert_after(r"hostname", r"ip multicast active")
    print ('Enabling "ip multicast"')
    send_command("ip multicast active", configure=True, chan=chan)

    # print 'Searching for interfaces with dhcp helper'
    # virtual_interfaces = output.find_objects_w_child(r'interface ve.*', r'\s+ip\s+helper.*',)
    # for intf in virtual_interfaces:
    #     interface = intf.text
    #     print interface
    #     has_dhcp_helper = intf.has_child_with(r'ip helper.*')
    #     for line in intf.all_children:
    #         if 'ip address' in line.text:
    #             address = line.text
    #             print address
    #         if 'helper-address' in line.text:
    #             dhcp = line.text
    #             print dhcp
    #     if has_dhcp_helper:
    #         writer.writerow((ip, interface, address, dhcp))
    #
    # Iterates through interfaces and cleans up misconfigurations
    for interface in output.find_objects(r"^interface.+"):
        has_loop_detection = interface.has_child_with(r"loop-detection")
        has_bpdu_guard = interface.has_child_with(r"stp-bpdu-guard")
        has_root_protection = interface.has_child_with(r"spanning-tree\sroot-protect")
        has_no_flow_control = interface.has_child_with(r"no\sflow-control")
        is_layer3_intf = (interface.has_child_with(r"ip\s+add")) or ("interface ve.*" in interface.text)

        # Temporarily disabled

        # Remove loop-detection misconfiguration
        if has_loop_detection and has_bpdu_guard:
            interface.delete_children_matching("loop-detection")
            print ('Removing "loop-detection" from {0}'.format(interface.text))
            send_command(interface.text, "no loop-detection", configure=True)

        # Remove spanning-tree root-protect misconfiguration
        if has_root_protection:
            interface.delete_children_matching(r"spanning-tree\sroot-protect")
            print ('Removing "spanning-tree root-protect" from {0}'.format(interface.text))
            send_command(interface.text, "no spanning-tree root", configure=True)

        # Adds IGMP snooping and QoS to Layer 3 interfaces
        if is_layer3_intf and not ("loopback" in interface.text or "management" in interface.text):
            interface.append_to_family(r" trust dscp")
            print ('Adding "trust dscp" to {0}'.format(interface.text))
            send_command(interface.text, "trust dscp", configure=True, chan=chan)
            interface.append_to_family(r" ip igmp version 2")
            print ('Adding "ip igmp version 2" to {0}'.format(interface.text))
            send_command(interface.text, "ip igmp version 2", configure=True, chan=chan)

        # enables flow-control
        if has_no_flow_control:
            interface.delete_children_matching(r"no\sflow-control.+")
            print ('Enabling "flow-control" on {0}'.format(interface.text))
            send_command(interface.text, "flow-control", configure=True, chan=chan)
    return output
def convert_cfg_file(config, device_type, out_path, conversion_matrix):
    """Convert cfg file to other cfg file"""

    import os
    import re
    from ciscoconfparse import CiscoConfParse

    # Check if device type exist in conversion matrix
    if device_type in conversion_matrix:
        # Determine new filename
        new_filename = os.path.join(out_path, os.path.basename(config))
        if os.path.isfile(new_filename):  # Remove CFG if it exist
            os.remove(new_filename)

        # Parse cisco configuration with Ciscoconfparse
        parse = CiscoConfParse(config)

        # DELETE
        for item in conversion_matrix[device_type]["delete"]:
            if item[1] == None:  # Check required fields
                continue
            elif item[0] != None:  # Parent cmd is mentionned
                parent_object = parse.find_objects(item[0])
                for parent in parent_object:
                    # Delete child object in parent object
                    parent.delete_children_matching(item[1])
            else:  # parent cmd is not mentionned
                cli_objects = parse.find_objects(item[1])
                for cli_object in cli_objects:
                    # Delete object and all child objects if exist
                    cli_object.delete()

        # ADD
        for item in conversion_matrix[device_type]["add"]:
            if item[2] == None:  # Check required fields
                continue
            elif item[0] != None:  # parent cmd is mentionned
                parent_object = parse.find_objects(item[0])
                parent_object_done = list(
                )  # This is to avoid duplicate added entries
                for parent in parent_object:
                    parent_re = re.compile(parent.text)
                    if parent.has_children == True:  # Add space to child if they are child
                        if parent.text not in parent_object_done:  # Avoid duplicates entries
                            nb_space = len(parent.text) - len(
                                parent.text.lstrip()) + 1
                            parse.insert_after(parent_re,
                                               insertstr=" " * nb_space +
                                               item[2])
                            parent_object_done.append(parent.text)
                    else:  # Entry is at the root of cfg, no space added
                        parse.insert_after(parent_re, insertstr=item[2])
            else:  # parent cmd is not mentionned
                parse.append_line(item[2])  # Write line at the end of the file

        # REPLACE
        for item in conversion_matrix[device_type]["replace"]:
            if item[1] == None or item[2] == None:  # Check required fields
                continue
            if item[0] != None:  # parent cmd is mentionned
                initial_cmd = re.compile(item[1])
                parse.replace_children(item[0], initial_cmd, item[2])
            else:  # parent cmd is not mentionned
                initial_cmd = re.compile(item[1])
                parse.replace_lines(initial_cmd, item[2])

        # Write output to out_file
        parse.save_as(new_filename)
    else:
        new_filename = "Skipped (model unknown)"

    return new_filename