def setUp(self): self.client = Client() site = Site(name='Site 1', slug='site-1') site.save() manufacturer = Manufacturer(name='Manufacturer 1', slug='manufacturer-1') manufacturer.save() devicetype = DeviceType(model='Device Type 1', manufacturer=manufacturer) devicetype.save() devicerole = DeviceRole(name='Device Role 1', slug='device-role-1') devicerole.save() device1 = Device(name='Device 1', site=site, device_type=devicetype, device_role=devicerole) device1.save() device2 = Device(name='Device 2', site=site, device_type=devicetype, device_role=devicerole) device2.save() iface1 = Interface(device=device1, name='Interface 1', form_factor=IFACE_FF_1GE_FIXED) iface1.save() iface2 = Interface(device=device1, name='Interface 2', form_factor=IFACE_FF_1GE_FIXED) iface2.save() iface3 = Interface(device=device1, name='Interface 3', form_factor=IFACE_FF_1GE_FIXED) iface3.save() iface4 = Interface(device=device2, name='Interface 1', form_factor=IFACE_FF_1GE_FIXED) iface4.save() iface5 = Interface(device=device2, name='Interface 2', form_factor=IFACE_FF_1GE_FIXED) iface5.save() iface6 = Interface(device=device2, name='Interface 3', form_factor=IFACE_FF_1GE_FIXED) iface6.save() Cable(termination_a=iface1, termination_b=iface4, type=CABLE_TYPE_CAT6).save() Cable(termination_a=iface2, termination_b=iface5, type=CABLE_TYPE_CAT6).save() Cable(termination_a=iface3, termination_b=iface6, type=CABLE_TYPE_CAT6).save()
def test_trace(self): device = create_test_device('Device 1') circuittermination = CircuitTermination.objects.first() interface = Interface.objects.create(device=device, name='Interface 1') Cable(termination_a=circuittermination, termination_b=interface).save() response = self.client.get( reverse('circuits:circuittermination_trace', kwargs={'pk': circuittermination.pk})) self.assertHttpStatus(response, 200)
def create_and_connect_surges(self, site, rack, pp, pole_setup): # surge_config will be of format <pole no>:<num surges>[ <pole no>:<num surges> [...]] # So first split by spaces to get a single pole config and then iterate of surge at this pole. # The RearPort of the 1st surge protector of the 1st pole will be connected to PP port 1 then # continuing upwards. surge_type = DeviceType.objects.get(manufacturer__name='Ubnt', model='Surge Protector') pp_port = 1 for pole_config in pole_setup.split(): pole_no, num_surges = pole_config.split(':') for n in range(1, int(num_surges) + 1): # Create surge surge_name = "sp-%s-mast%s-%s" % (site.slug.lower(), pole_no, n) surge = Device( device_type=surge_type, device_role=DeviceRole.objects.get(name='Surge Protector'), name=surge_name, status=DeviceStatusChoices.STATUS_PLANNED, site=site) surge.save() # Link RearPort of SP to next free panel port cable = Cable(termination_a=RearPort.objects.get( device=pp, name=str(pp_port)), termination_b=RearPort.objects.get(device=surge, name=str(1)), status=CableStatusChoices.STATUS_PLANNED) cable.save() self.log_success( "Created surge protector %s and linked it to patch panel port %s." % (surge, pp_port)) pp_port += 1
def setUpTestData(cls): sites = ( Site(name='Site 1', slug='site-1'), Site(name='Site 2', slug='site-2'), Site(name='Site 3', slug='site-3'), ) Site.objects.bulk_create(sites) circuit_types = ( CircuitType(name='Circuit Type 1', slug='circuit-type-1'), ) CircuitType.objects.bulk_create(circuit_types) providers = ( Provider(name='Provider 1', slug='provider-1'), ) Provider.objects.bulk_create(providers) provider_networks = ( ProviderNetwork(name='Provider Network 1', provider=providers[0]), ProviderNetwork(name='Provider Network 2', provider=providers[0]), ProviderNetwork(name='Provider Network 3', provider=providers[0]), ) ProviderNetwork.objects.bulk_create(provider_networks) circuits = ( Circuit(provider=providers[0], type=circuit_types[0], cid='Circuit 1'), Circuit(provider=providers[0], type=circuit_types[0], cid='Circuit 2'), Circuit(provider=providers[0], type=circuit_types[0], cid='Circuit 3'), Circuit(provider=providers[0], type=circuit_types[0], cid='Circuit 4'), Circuit(provider=providers[0], type=circuit_types[0], cid='Circuit 5'), Circuit(provider=providers[0], type=circuit_types[0], cid='Circuit 6'), ) Circuit.objects.bulk_create(circuits) circuit_terminations = (( CircuitTermination(circuit=circuits[0], site=sites[0], term_side='A', port_speed=1000, upstream_speed=1000, xconnect_id='ABC'), CircuitTermination(circuit=circuits[0], site=sites[1], term_side='Z', port_speed=1000, upstream_speed=1000, xconnect_id='DEF'), CircuitTermination(circuit=circuits[1], site=sites[1], term_side='A', port_speed=2000, upstream_speed=2000, xconnect_id='GHI'), CircuitTermination(circuit=circuits[1], site=sites[2], term_side='Z', port_speed=2000, upstream_speed=2000, xconnect_id='JKL'), CircuitTermination(circuit=circuits[2], site=sites[2], term_side='A', port_speed=3000, upstream_speed=3000, xconnect_id='MNO'), CircuitTermination(circuit=circuits[2], site=sites[0], term_side='Z', port_speed=3000, upstream_speed=3000, xconnect_id='PQR'), CircuitTermination(circuit=circuits[3], provider_network=provider_networks[0], term_side='A'), CircuitTermination(circuit=circuits[4], provider_network=provider_networks[1], term_side='A'), CircuitTermination(circuit=circuits[5], provider_network=provider_networks[2], term_side='A'), )) CircuitTermination.objects.bulk_create(circuit_terminations) Cable(termination_a=circuit_terminations[0], termination_b=circuit_terminations[1]).save()
def run(self, data, commit): device_a = data["device_a"] device_b = data["device_b"] ports_a = getattr(device_a, data["termination_type_a"]).all() ports_b = getattr(device_b, data["termination_type_b"]).all() terms_a = expand_pattern(data["termination_name_a"]) terms_b = expand_pattern(data["termination_name_b"]) if len(terms_a) != len(terms_b): return self.log_failure( f'Mismatched number of ports: {len(terms_a)} (A) versus {len(terms_b)} (B)' ) labels = expand_pattern(data["cable_label"]) if len(labels) == 1: labels = [labels[0] for i in range(len(terms_a))] elif len(labels) != len(terms_a): return self.log_failure( f'Mismatched number of labels: {len(labels)} labels versus {len(terms_a)} ports' ) for i in range(len(terms_a)): term_a = [x for x in ports_a if x.name == terms_a[i]] if len(term_a) != 1: self.log_failure( f'Unable to find "{terms_a[i]}" in {data["termination_type_a"]} on device A ({device_a.name})' ) continue term_b = [x for x in ports_b if x.name == terms_b[i]] if len(term_b) != 1: self.log_failure( f'Unable to find "{terms_b[i]}" in {data["termination_type_b"]} on device B ({device_b.name})' ) continue cable = Cable( termination_a=term_a[0], termination_b=term_b[0], type=data["cable_type"], status=data["cable_status"], tenant=data["cable_tenant"], label=labels[i], color=data["cable_color"], length=data["cable_length"], length_unit=data["cable_length_unit"], ) try: with transaction.atomic(): cable.full_clean() cable.save() cable.tags.set(data["cable_tags"]) except Exception as e: self.log_failure( f'Unable to connect {device_a.name}:{terms_a[i]} to {device_b.name}:{terms_b[i]}: {e}' ) continue self.log_success( f'Created cable from {device_a.name}:{terms_a[i]} to {device_b.name}:{terms_b[i]}' )
def _connect_interface(interface): ''' Get iface connection from iface description Description should be like "server|port" ''' desc_regex = "^(.*)+\|(.*)+" desc_regex = re.compile(desc_regex) iface_descr = interface.description if desc_regex.match(iface_descr): asset_tag, server_port = iface_descr.split('|') server = Device.objects.filter(asset_tag=asset_tag) if server: server = server[0] server_name = server.name # Find and compare ports for iface in server.interfaces.all(): if _compare_interfaces(iface.name, server_port): port = iface else: port = None port = server.interfaces.filter(name=server_port) if port: cable = Cable() cable.termination_a = interface cable.termination_b = port[0] try: cable.save() except Exception as e: logger.error( "Cannot do a connection {} to {} on {} - error is {}". format(interface.name, server_name, server_port, e)) return logger.info( "Successfully connected interface {} to server {} on port {}" .format(interface.name, server_name, server_port)) else: logger.warning("Cannot found interface {} on server {}".format( server_port, server_name)) else: logger.warning( "Cannot find server by AssetTag {}".format(asset_tag)) else: logger.info( "Incorrect or None description on interface {} - cannot connect anything" .format(interface.name))
def setUp(self): user = create_test_user(permissions=['dcim.view_cable']) self.client = Client() self.client.force_login(user) site = Site(name='Site 1', slug='site-1') site.save() manufacturer = Manufacturer(name='Manufacturer 1', slug='manufacturer-1') manufacturer.save() devicetype = DeviceType(model='Device Type 1', manufacturer=manufacturer) devicetype.save() devicerole = DeviceRole(name='Device Role 1', slug='device-role-1') devicerole.save() device1 = Device(name='Device 1', site=site, device_type=devicetype, device_role=devicerole) device1.save() device2 = Device(name='Device 2', site=site, device_type=devicetype, device_role=devicerole) device2.save() iface1 = Interface(device=device1, name='Interface 1', type=IFACE_TYPE_1GE_FIXED) iface1.save() iface2 = Interface(device=device1, name='Interface 2', type=IFACE_TYPE_1GE_FIXED) iface2.save() iface3 = Interface(device=device1, name='Interface 3', type=IFACE_TYPE_1GE_FIXED) iface3.save() iface4 = Interface(device=device2, name='Interface 1', type=IFACE_TYPE_1GE_FIXED) iface4.save() iface5 = Interface(device=device2, name='Interface 2', type=IFACE_TYPE_1GE_FIXED) iface5.save() iface6 = Interface(device=device2, name='Interface 3', type=IFACE_TYPE_1GE_FIXED) iface6.save() Cable(termination_a=iface1, termination_b=iface4, type=CABLE_TYPE_CAT6).save() Cable(termination_a=iface2, termination_b=iface5, type=CABLE_TYPE_CAT6).save() Cable(termination_a=iface3, termination_b=iface6, type=CABLE_TYPE_CAT6).save()
def run(self, data, commit): # Create the device device = Device(name=data['business_name'], device_role_id=self.DEVICE_ROLE_ID, device_type_id=data["hardware_choice"], platform_id=self.PLATFORM_ID, site_id=self.SITE_ID) device.save() interfaces = Interface.objects.filter(device_id=device.id) enabled_interfaces = [] mgmt_intf = interfaces.get(name="b107") enabled_interfaces.append(mgmt_intf) uplk_intf = interfaces.get(name="ether10") enabled_interfaces.append(uplk_intf) uplk_intf.mode = "tagged" uplk_intf.tagged_vlans.set([self.INET_VLAN, self.MGMT_VLAN]) uplk_intf.description = "Uplink" uplk_intf.save() inet_intf = interfaces.get(name="ether1") enabled_interfaces.append(inet_intf) inet_intf.description = "Internet" inet_intf.mode = "access" inet_intf.untagged_vlan = self.INET_VLAN inet_intf.save() mgmt_intf.save() for intf in interfaces: intf.enabled = False intf.save() for intf in enabled_interfaces: intf.enabled = True intf.mtu = 1500 intf.save() available_ip = Prefix.objects.get( vlan=self.MGMT_VLAN).get_first_available_ip() ip = IPAddress( address=available_ip, assigned_object_type=ContentType.objects.get_for_model(Interface), assigned_object_id=mgmt_intf.id) ip.save() device.primary_ip4_id = ip.id device.primary_ip_id = ip.id device.comments = data['comments'] device.save() # ############ if (not data["skip_zabbix"] and commit): # Post to Zabbix API to create host in mikrotik group and ICMP # template try: hostid = self.ZAPI.host.create( host=data["business_name"], interfaces=dict(type=2, main=1, useip=1, ip=available_ip.replace("/24", ""), port=161, dns="", details=dict( version="1", bulk="0", community=self.SNMP_COMMUNITY)), groups=dict(groupid=15), templates=dict(templateid=10186)) self.log_info("zabbix configured successfully") except Exception as e: self.log_info("failed to configure zabbix {0}".format(e)) if (not data["skip_uplink_port"] and commit): try: agg_switches = Device.objects.filter( site=data["uplink_site"], device_role_id=self.AGG_ROLE_ID, status="active") selected_interface = "" for agg_switch in agg_switches: interfaces = Interface.objects.filter( device_id=agg_switch.id) for interface in interfaces: if (interface.connection_status is not True and interface.enabled is True and interface.description == '' and interface.type == '1000base-x-sfp'): selected_interface = interface break if selected_interface != "": selected_interface.enabled = True selected_interface.description = device.name selected_interface.mode = "tagged" selected_interface.tagged_vlans.set( [self.INET_VLAN, self.MGMT_VLAN]) selected_interface.save() cable = Cable( termination_a=uplk_intf, termination_b=selected_interface, ) cable.save() self.log_info( "uplink switch chosen. Port {0} on {1}".format( selected_interface.name, agg_switch.name)) break if selected_interface == "": self.log_failure("No available aggregate port found. \ No aggregate port assigned.") except BaseException: self.log("failed to document uplink switch") self.log_success("Created {0}".format(device.name))
def setup_bbr(self, site, rack, vlan, site_no, node_id, asset_tag, sw): bbr_name = "bbr-%s.in.ffho.net" % site.slug try: bbr = Device.objects.get(name=bbr_name) self.log_info("Backbone router %s already present, carrying on." % bbr_name) return bbr except Device.DoesNotExist: pass bbr_type = DeviceType.objects.get(manufacturer__name='PCEngines', model='APU2c4-19"') bbr = Device( device_type=bbr_type, device_role=DeviceRole.objects.get(name='Backbone router'), platform=Platform.objects.get(name='Linux'), name=bbr_name, asset_tag=asset_tag, status=DeviceStatusChoices.STATUS_PLANNED, site=site, rack=rack, position=rack.u_height - 4, face=DeviceFaceChoices.FACE_FRONT, ) bbr.save() self.log_success("Created backbone router %s" % bbr) # Set bond0 mode to tagged-all, bundle enp<n>s0 into it and connect enp<n>s0 to switchport 10 + n bbr_bond0 = Interface.objects.get(device=bbr, name="bond0") bbr_bond0.mode = InterfaceModeChoices.MODE_TAGGED_ALL bbr_bond0.save() # Link enp1s0 and enp2s0 to switch port 10 and 11 respectivly for n in [1, 2]: bbr_port = Interface.objects.get(device=bbr, name="enp%ds0" % n) sw_port = Interface.objects.get(device=sw, name=str(10 + n)) cable = Cable(termination_a=sw_port, termination_b=bbr_port, status=CableStatusChoices.STATUS_PLANNED) cable.save() bbr_port.lag = bbr_bond0 bbr_port.save() self.log_success("Linked %s to %s" % (bbr, sw)) # Disable enp3s0 enp3s0 = Interface.objects.get(device=bbr, name="enp3s0") enp3s0.enabled = False enp3s0.save() # Set up Mgmt vlan interface + IP bbr_mgmt_iface = Interface( device=bbr, name="vlan%d" % vlan.vid, type=InterfaceTypeChoices.TYPE_VIRTUAL, ) bbr_mgmt_iface.save() bbr_mgmt_ip = IPAddress(address="172.30.%d.1/24" % site_no, interface=bbr_mgmt_iface) bbr_mgmt_ip.save() self.log_success("Configured %s on interface %s of %s" % (bbr_mgmt_ip, bbr_mgmt_iface, bbr)) # Set up loopback IPs bbr_lo_iface = Interface.objects.get(device=bbr, name="lo") ipv4 = IPAddress(address="10.132.255.%s/32" % node_id, interface=bbr_lo_iface) ipv4.save() ipv6 = IPAddress(address="2a03:2260:2342:ffff::%s/128" % node_id, interface=bbr_lo_iface) ipv6.save() bbr.primary_ip4 = ipv4 bbr.primary_ip6 = ipv6 bbr.save() self.log_success("Configured %s + %s on lo interface of %s" % (ipv4, ipv6, bbr))
def setup_swtich(self, site, rack, pp, panel_ports, vlan, site_no, asset_tag): sw_name = "sw-%s-01.in.ffho.net" % site.slug try: sw = Device.objects.get(name=sw_name) self.log_info("Switch %s already present, carrying on." % sw_name) return sw except Device.DoesNotExist: pass sw_type = DeviceType.objects.get(manufacturer__name='Netonix', model='WS-12-250-AC') sw = Device(device_type=sw_type, device_role=DeviceRole.objects.get(name='Switch'), platform=Platform.objects.get(name='Netonix'), name=sw_name, asset_tag=asset_tag, status=DeviceStatusChoices.STATUS_PLANNED, site=site, rack=rack, position=rack.u_height - 2, face=DeviceFaceChoices.FACE_FRONT) sw.save() self.log_success("Created switch %s" % sw) # Link switch ports for panel ports for n in range(1, int(panel_ports) + 1): cable = Cable(termination_a=Interface.objects.get(device=sw, name=str(n)), termination_b=FrontPort.objects.get(device=pp, name=str(n)), status=CableStatusChoices.STATUS_PLANNED) cable.save() # Disable interfaces which aren't connected unused_ifaces = [13, 14] if panel_ports < 10: unused_ifaces.extend(list(range(int(panel_ports + 1), 10))) unused_ifaces = [str(x) for x in sorted(unused_ifaces)] for n in unused_ifaces: iface = Interface.objects.get(device=sw, name=n) iface.enabled = False iface.save() self.log_success("Disabled switch unsued ports %s" % ",".join(unused_ifaces)) # Set up Mgmt port sw_mgmt_port = Interface.objects.get(device=sw, name="10") sw_mgmt_port.mode = InterfaceModeChoices.MODE_ACCESS sw_mgmt_port.untagged_vlan = vlan sw_mgmt_port.description = "Mgmt" sw_mgmt_port.save() self.log_success("Set mgmt interface 10 to untagged VLAN %s" % vlan) # Set po1 tagged-all and bundle ports 11 + 12 into it sw_po1 = Interface.objects.get(device=sw, name='po1') sw_po1.mode = InterfaceModeChoices.MODE_TAGGED_ALL sw_po1.save() for n in [11, 12]: sw_port = Interface.objects.get(device=sw, name=str(n)) sw_port.lag = sw_po1 sw_port.save() self.log_success("Linked first %s ports of %s to %s" % (panel_ports, sw, pp)) # Set up Mgmt vlan interface + IP sw_mgmt_iface = Interface( device=sw, name="vlan%d" % vlan.vid, type=InterfaceTypeChoices.TYPE_VIRTUAL, ) sw_mgmt_iface.save() sw_mgmt_ip = IPAddress(address="172.30.%d.10/24" % site_no, interface=sw_mgmt_iface) sw_mgmt_ip.save() sw.primary_ip4 = sw_mgmt_ip sw.save() self.log_success("Configured %s on interface %s of %s" % (sw_mgmt_ip, sw_mgmt_iface, sw)) return sw
def run(self, data, commit: bool): """The main method of the script that will be run when pressing the Run Script button 1. Grabs the data from Netbox about devices containing the devices by regex input by the user 2. Loops through the devices, and makes a NAPALM `get_lldp_neighbors` call to gather local and their remote interfaces 3. Loops through all LLDP provided local interfaces. 4. If a mac_address is any kind of empty or null, it makes sure to set it to python None 5. Makes sure the local interface can be found in Netbox 6. If a cable is found, it moves to the next iteration and if the remote interface is correct, goes to next iteration 7. If a cable is found but the remote interface is not the same, makes sure to mark the cable for deletion (Netbox only allows 1 to 1 cable connections) 8. Makes sure the remote device and interface can be found in Netbox 9. Deletes the cable if one was found 10. Creates a new cable using the local and remote interface pair 11. Calls function to remove cables no longer found in LLDP Args: data (dict): a dict that has the variables for user input. Defined using class variables commit (bool): a bool that determines to commit or not to commit the changes to database (since Netbox automatically reverts database changes on commit = False, we don't use it) Returns: str: output for the Output tab """ output = "" devices = Device.objects.filter(name__regex=data["device_name"]) for device in devices: napalm_lldp_neighbors = napalm_call("get_lldp_neighbors", device.id, self.request) lldp_interface_names = [] for local_interface_name, remote_interface in napalm_lldp_neighbors.items( ): remote_device_name = remote_interface[0]["hostname"] remote_interface_name = remote_interface[0]["port"] lldp_interface_names.append(local_interface_name) try: netbox_local_interface = Interface.objects.get( device=device.id, name=local_interface_name) except Interface.DoesNotExist: if data["non_existent"]: self.log_warning( f"""`[{device.name}]` Local interface **({local_interface_name})** for device **({device.name})** could not be found in Netbox. Please run the interface update script to have all the interfaces for a device generated""" ) continue delete_cable = False if netbox_local_interface.cable is not None: if (netbox_local_interface._cable_peer.name == remote_interface_name and netbox_local_interface._cable_peer.device.name == remote_device_name): # Cable already exists so we continue on continue else: # A Netbox cable is connected but not to the interface the device is reporting delete_cable = True # Don't delete the cable immediately as the remote interface might not be there try: remote_device = Device.objects.get(name=remote_device_name) netbox_remote_interface = Interface.objects.get( device=remote_device.id, name=remote_interface_name) except Device.DoesNotExist: if data["non_existent"]: self.log_info( f"""`[{device.name}]` Remote device **({remote_device_name})** could not be found in Netbox Create the device in Netbox and add the **({remote_interface_name})** interface for a cable to be connected""" ) continue except Interface.DoesNotExist: if data["non_existent"]: self.log_info( f"""`[{device.name}]` Remote Interface **({remote_interface_name})** for device **({remote_device_name})** could not be found in Netbox Create the interface in Netbox for a cable to be connected""" ) continue if delete_cable: # Delete a cable that doesn't exist netbox_local_interface.cable.delete() self.log_success( f"`[{device.name}]` Deleting a no longer existing cable: " f"**{netbox_local_interface.name}** " f"({netbox_local_interface.device.name})" " <-> " f"**{netbox_local_interface._cable_peer.name}** " f"({netbox_local_interface._cable_peer.device.name})") # Create a new cable dcim_interface_type = ContentType.objects.get( app_label="dcim", model="interface") new_cable = Cable( termination_a_type=dcim_interface_type, termination_a_id=netbox_local_interface.id, termination_b_type=dcim_interface_type, termination_b_id=netbox_remote_interface.id, ) new_cable.save() self.log_success(f"`[{device.name}]` Creating a new cable: " f"**{netbox_local_interface.name}** " f"({netbox_local_interface.device.name})" " <-> " f"**{netbox_remote_interface.name}** " f"({netbox_remote_interface.device.name})") self.remove_old_cables(device, lldp_interface_names) return output