class DemoScript(Script): name = "Script Demo" description = "A quick demonstration of the available field types" my_string1 = StringVar( description="Input a string between 3 and 10 characters", min_length=3, max_length=10) my_string2 = StringVar( description= "This field enforces a regex: three letters followed by three numbers", regex=r'[a-z]{3}\d{3}') my_number = IntegerVar( description="Pick a number between 1 and 255 (inclusive)", min_value=1, max_value=255) my_boolean = BooleanVar( description="Use the checkbox to toggle true/false") my_object = ObjectVar(description="Select a NetBox site", queryset=Site.objects.all()) def run(self, data): self.log_info("Your string was {}".format(data['my_string1'])) self.log_info("Your second string was {}".format(data['my_string2'])) self.log_info("Your number was {}".format(data['my_number'])) if data['my_boolean']: self.log_info("You ticked the checkbox") else: self.log_info("You did not tick the checkbox") self.log_info("You chose the sites {}".format(data['my_object'])) return "Here's some output"
class SiteGeoAll(Script): class Meta: name = 'All sites for a region' description = 'Retrieve list of all sites and populate the latitude/longitude fields based on their physical address.' commit_default = True region = ObjectVar(model=Region, display_field=name) overwrite = BooleanVar( default=False, label='Override existing value', description='If location already exists, update the value.') def run(self, data, commit): for site in get_sites_for_region(data['region']): update_site(self, site)
class SiteGeoOne(Script): class Meta: name = 'Specific site' description = 'Populate the latitude/longitude fields for a specific site based on its physical address.' commit_default = True location = ObjectVar(model=Site, display_field=name) overwrite = BooleanVar( default=False, label='Override existing value', description='If location already exists, update the value.') def run(self, data, commit): site = data['location'] update_site(self, site, data['overwrite'])
class NewVM(Script): class Meta: name = "New VM" description = "Create a new VM" field_order = [ 'vm_name', 'dns_name', 'primary_ip4', 'primary_ip6', #'vrf', 'role', 'status', 'cluster', #'tenant', 'platform', 'interface_name', 'mac_address', 'vcpus', 'memory', 'disk', 'comments' ] vm_name = StringVar(label="VM name") dns_name = StringVar(label="DNS name", required=False) primary_ip4 = IPAddressWithMaskVar(label="IPv4 address") primary_ip6 = IPAddressWithMaskVar(label="IPv6 address", required=False) #vrf = ObjectVar(VRF.objects, required=False) role = ObjectVar(DeviceRole.objects.filter(vm_role=True), required=False) status = ChoiceVar(VirtualMachineStatusChoices, default=VirtualMachineStatusChoices.STATUS_ACTIVE) cluster = ObjectVar(Cluster.objects) #tenant = ObjectVar(Tenant.objects, required=False) platform = ObjectVar(Platform.objects, required=False) interface_name = StringVar(default="eth0") mac_address = StringVar(label="MAC address", required=False) vcpus = IntegerVar(label="VCPUs", required=False) memory = IntegerVar(label="Memory (MB)", required=False) disk = IntegerVar(label="Disk (GB)", required=False) comments = TextVar(label="Comments", required=False) def run(self, data): vm = VirtualMachine( name=data["vm_name"], role=data["role"], status=data["status"], cluster=data["cluster"], platform=data["platform"], vcpus=data["vcpus"], memory=data["memory"], disk=data["disk"], comments=data["comments"], tenant=data.get("tenant"), ) vm.save() interface = Interface( name=data["interface_name"], type=InterfaceTypeChoices.TYPE_VIRTUAL, mac_address=data["mac_address"], virtual_machine=vm, ) interface.save() def add_addr(addr, expect_family): if not addr: return if addr.version != expect_family: raise RuntimeError("Wrong family for %r" % a) try: a = IPAddress.objects.get( address=addr, vrf=data.get("vrf"), ) result = "Assigned" except ObjectDoesNotExist: a = IPAddress( address=addr, vrf=data.get("vrf"), ) result = "Created" a.status = IPAddressStatusChoices.STATUS_ACTIVE a.dns_name = data["dns_name"] if a.interface: raise RuntimeError("Address %s is already assigned" % addr) a.interface = interface a.tenant = data.get("tenant") a.save() self.log_info("%s IP address %s %s" % (result, a.address, a.vrf or "")) setattr(vm, "primary_ip%d" % a.family, a) add_addr(data["primary_ip4"], 4) add_addr(data["primary_ip6"], 6) vm.save() self.log_success("Created VM %s" % vm.name)
class New(Script): class Meta: name = "Create FTTB CPE w/ automatic uplink selection and monitoring" description = "Generate standard CPE router configuration \ and configure uplink switch and linkage" field_order = [ 'business_name', 'asset_tag', 'uplink_site', 'skip_zabbix', 'skip_uplink_port', 'confirmation_email', 'comments', 'rack_mount' ] # ##################Check to make sure you have these defined############## RACK_MOUNT_ID = DeviceType.objects.get(model="RB2011-RM").id WALL_MOUNT_ID = DeviceType.objects.get(model="RB2011").id SITE_ID = Site.objects.get(name="Customer Premise").id DEVICE_ROLE_ID = DeviceRole.objects.get(name="CPE").id AGG_ROLE_ID = DeviceRole.objects.get(name="Aggregation").id PLATFORM_ID = Platform.objects.get(name="RouterOS").id CHOICES = ((RACK_MOUNT_ID, "Rack Mount"), (WALL_MOUNT_ID, "Wall Mount")) INET_VLAN = VLAN.objects.get(vid=900) MGMT_VLAN = VLAN.objects.get(vid=107) #SITES = Site.objects.filter(region_id=1) REGION = 1 ZAPI = ZabbixAPI( url='http://zabbix-web-apache-mysql:8080/api_jsonrpc.php/', user='******', password='******') SNMP_COMMUNITY = "got" # ##################END################### rack_mount = ChoiceVar(choices=((True, "Rack Mount"), (False, "Wall Mount"))) business_name = StringVar(label="Business Name") asset_tag = StringVar(label="Asset Tag", required=False) hardware_choice = ChoiceVar(choices=CHOICES) comments = TextVar(label="Comments", required=False) uplink_site = ObjectVar(model=Site, query_params={'region_id': REGION}) skip_zabbix = BooleanVar(label="Disable Zabbix configuration") skip_uplink_port = BooleanVar(label="Disable upstream port selection") confirmation_email = BooleanVar(label="Send Confirmation Email") 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))
class MultiConnect(Script): class Meta: name = "Multi Connect" description = "Add multiple connections from one device to another" device_a = ObjectVar(model=Device, label="Device A") termination_type_a = ChoiceVar(choices=TERM_CHOICES, label="Device A port type") termination_name_a = StringVar(label="Device A port name pattern", description="Example: ge-0/0/[5,7,12-23]") device_b = ObjectVar(model=Device, label="Device B") termination_type_b = ChoiceVar(choices=TERM_CHOICES, label="Device B port type") termination_name_b = StringVar(label="Device B port name pattern", description="Example: ge-0/0/[5,7,12-23]") cable_status = ChoiceVar(choices=LinkStatusChoices.CHOICES, default=LinkStatusChoices.STATUS_CONNECTED, label="Cable Status") cable_type = ChoiceVar(choices=NO_CHOICE + CableTypeChoices.CHOICES, required=False, label="Cable Type") cable_tenant = ObjectVar(model=Tenant, required=False, label="Cable Tenant") cable_label = StringVar(label="Cable Label pattern", required=False) cable_color = ChoiceVar(choices=NO_CHOICE + ColorChoices.CHOICES, required=False, label="Cable Color") cable_length = IntegerVar( required=False, label="Cable Length") # unfortunately there is no DecimalVar cable_length_unit = ChoiceVar(choices=NO_CHOICE + CableLengthUnitChoices.CHOICES, required=False, label="Cable Length Unit") cable_tags = MultiObjectVar(model=Tag, required=False, label="Cable Tags") 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]}' )
class CreateManagementInterface(Script): class Meta: name = "Create Management Interface" description = "Create a management interface for a specified device and assign an IP address." device = ObjectVar( description="The Device to add management interface to", queryset=Device.objects.filter(device_role__slug="server"), ) add_ip = BooleanVar( description= "Automatically add IP address from appropriate management network at site.", default=True) def _add_ip_to_interface(self, device, interface): # determine prefix appropriate to site of device try: prefix = Prefix.objects.get(site=device.site, role__slug="management", tenant=device.tenant) except ObjectDoesNotExist: message = "Can't find prefix for site {} on device {}".format( device.site.slug, device.name) self.log_failure(message) return message self.log_info("Selecting address from network {}".format( prefix.prefix)) available_ips = iter(prefix.get_available_ips()) # disable 0net skipping on frack if device.tenant and device.tenant.slug == 'fr-tech': zeroth_net = None else: # skip the first /24 net as this is reserved for network devices zeroth_net = list( ipaddress.ip_network(prefix.prefix).subnets(new_prefix=24))[0] ip = None for ip in available_ips: address = ipaddress.ip_address(ip) if zeroth_net is None or address not in zeroth_net: break else: ip = None if ip: # create IP address as child of appropriate prefix newip = IPAddress( address="{}/{}".format(ip, prefix.prefix.prefixlen), status=IPADDRESS_STATUS_ACTIVE, family=prefix.family, ) # save ASAP newip.save() newip.vrf = prefix.vrf.pk if prefix.vrf else None # assign ip to interface newip.interface = interface newip.tenant = device.tenant newip.save() message = "Created ip {} for mgmt on device {}".format( newip, device.name) self.log_success(message) return message # fall through to failure message = "Not enough IPs to allocate one on prefix {}".format( prefix.prefix) self.log_failure(message) return message def run(self, data): """Create a 'mgmt' interface, and, if requested, allocate an appropriate IP address.""" device = data['device'] try: mgmt = device.interfaces.get(name='mgmt') self.log_info("mgmt already exists for device {}".format( device.name)) except ObjectDoesNotExist: # create interface of name mgmt, is_mgmt flag set of type 1G Ethernet mgmt = Interface(name="mgmt", mgmt_only=True, device=device, type=IFACE_TYPE_1GE_FIXED) mgmt.save() if data['add_ip']: return self._add_ip_to_interface(device, mgmt) else: message = "Created mgmt on device {}".format(device.name) self.log_success(message) return message
class NewVM(Script): class Meta: name = "New VM" description = "Create a new VM" field_order = [ 'vm_name', 'dns_name', 'primary_ip4', 'primary_ip6', #'vrf', 'role', 'status', 'cluster', #'tenant', 'platform', 'interface_name', 'mac_address', 'vcpus', 'memory', 'disk', 'comments', 'pve_host' ] vm_name = StringVar(label="VM name") dns_name = StringVar(label="DNS name", required=False) primary_ip4 = IPAddressWithMaskVar(label="IPv4 address") # primary_ip6 = IPAddressWithMaskVar(label="IPv6 address", required=False) # vrf = ObjectVar(VRF.objects, required=False) role = ObjectVar(DeviceRole.objects.filter(vm_role=True), required=False, default=8) status = ChoiceVar(VirtualMachineStatusChoices, default=VirtualMachineStatusChoices.STATUS_ACTIVE) # cluster = ObjectVar(Cluster.objects) # tenant = ObjectVar(Tenant.objects, required=False) # platform = ObjectVar(Platform.objects, required=False) interface_name = StringVar(default="eth0") # mac_address = StringVar(label="MAC address", required=False) vcpus = IntegerVar(label="VCPUs", required=True) memory = IntegerVar(label="Memory (MB)", required=True) disk = IntegerVar(label="Disk (GB)", required=True) comments = TextVar(label="Comments", required=False) # pve_host = ObjectVar(Device.objects.filter(cluster__name='Newtelco Cluster'), label="Proxmox Host", required=True) PVE_DEVICES = (('nt-pve', 'nt-pve'), ('nt-pve2', 'nt-pve2'), ('nt-pve5', 'nt-pve5'), ('nt-pve6', 'nt-pve6')) pve_host = ChoiceVar(choices=PVE_DEVICES) # pve_host_ip=Device.objects.filter(name=pve_host) def run(self, data, commit): pve_host = Device.objects.filter(name=data["pve_host"]) vm = VirtualMachine( name=data["vm_name"], role=data["role"], status=data["status"], vcpus=data["vcpus"], memory=data["memory"], disk=data["disk"], comments=data["comments"], ) if commit: vm.save() interface = Interface( name=data["interface_name"], type=InterfaceTypeChoices.TYPE_VIRTUAL, virtual_machine=vm, ) if commit: interface.save() def add_addr(addr, expect_family): if not addr: return if addr.version != expect_family: raise RuntimeError("Wrong family for %r" % a) try: a = IPAddress.objects.get( address=addr, family=addr.version, vrf=data.get("vrf"), ) result = "Assigned" except ObjectDoesNotExist: a = IPAddress( address=addr, family=addr.version, vrf=data.get("vrf"), ) result = "Created" a.status = IPAddressStatusChoices.STATUS_ACTIVE a.dns_name = data["dns_name"] if a.interface: raise RuntimeError("Address %s is already assigned" % addr) a.interface = interface a.tenant = data.get("tenant") a.save() self.log_info("%s IP address %s %s" % (result, a.address, a.vrf or "")) setattr(vm, "primary_ip%d" % a.family, a) def connect_pve(addr): self.log_info(addr) proxmox = ProxmoxAPI( addr, user='******', token_name='nb1', token_value='0cf6ab07-ff7e-41a3-80e4-e09e7fea6c7d', verify_ssl=False) self.log_success(proxmox.nodes.get()) # self.log_info(data["pve_host"]) pve_ip = str(pve_host.get().primary_ip4)[:-3] self.log_info(pve_ip) connect_pve(pve_ip) if commit: add_addr(data["primary_ip4"], 4) # add_addr(data["primary_ip6"], 6) vm.save() self.log_success("Created VM %s" % vm.name) else: self.log_success("Dry-run Success - Created VM %s" % vm.name)
class NewVM(Script): class Meta: name = "New VM" description = "Create a new VM" vm_name = StringVar(label="VM name") dns_name = StringVar(label="DNS name", required=False) vm_tags = MultiObjectVar(model=Tag, label="VM tags", required=False) primary_ip4 = IPAddressWithMaskVar(label="IPv4 address") #primary_ip4_tags = MultiObjectVar(model=Tag, label="IPv4 tags", required=False) primary_ip6 = IPAddressWithMaskVar(label="IPv6 address", required=False) #primary_ip6_tags = MultiObjectVar(model=Tag, label="IPv6 tags", required=False) #vrf = ObjectVar(model=VRF, required=False) role = ObjectVar(model=DeviceRole, query_params=dict(vm_role=True), required=False) status = ChoiceVar(VirtualMachineStatusChoices, default=VirtualMachineStatusChoices.STATUS_ACTIVE) cluster = ObjectVar(model=Cluster) tenant = ObjectVar(model=Tenant, required=False) platform = ObjectVar(model=Platform, required=False) interface_name = StringVar(default="eth0") mac_address = StringVar(label="MAC address", required=False) vcpus = IntegerVar(label="VCPUs", required=False) memory = IntegerVar(label="Memory (MB)", required=False) disk = IntegerVar(label="Disk (GB)", required=False) comments = TextVar(label="Comments", required=False) def run(self, data, commit): vm = VirtualMachine( name=data["vm_name"], role=data["role"], status=data["status"], cluster=data["cluster"], platform=data["platform"], vcpus=data["vcpus"], memory=data["memory"], disk=data["disk"], comments=data["comments"], tenant=data.get("tenant"), ) vm.full_clean() vm.save() vm.tags.set(data["vm_tags"]) vminterface = VMInterface( name=data["interface_name"], mac_address=data["mac_address"], virtual_machine=vm, ) vminterface.full_clean() vminterface.save() def add_addr(addr, family): if not addr: return if addr.version != family: raise RuntimeError(f"Wrong family for {a}") try: a = IPAddress.objects.get( address=addr, vrf=data.get("vrf"), ) result = "Assigned" except ObjectDoesNotExist: a = IPAddress( address=addr, vrf=data.get("vrf"), ) result = "Created" a.status = IPAddressStatusChoices.STATUS_ACTIVE a.dns_name = data["dns_name"] if a.assigned_object: raise RuntimeError(f"Address {addr} is already assigned") a.assigned_object = vminterface a.tenant = data.get("tenant") a.full_clean() a.save() #a.tags.set(data[f"primary_ip{family}_tags"]) self.log_info(f"{result} IP address {a.address} {a.vrf or ''}") setattr(vm, f"primary_ip{family}", a) add_addr(data["primary_ip4"], 4) add_addr(data["primary_ip6"], 6) vm.full_clean() vm.save() self.log_success( f"Created VM [{vm.name}](/virtualization/virtual-machines/{vm.id}/)" )