Skip to content

Instantly share code, notes, and snippets.

@chonty
Created November 7, 2019 22:27
Show Gist options
  • Save chonty/b7f333587a9a23c2f7820411affe881d to your computer and use it in GitHub Desktop.
Save chonty/b7f333587a9a23c2f7820411affe881d to your computer and use it in GitHub Desktop.
from django.utils.text import slugify
from dcim.constants import *
from dcim.models import Device, DeviceRole, DeviceType, Site, Interface
from circuits.models import Circuit
from ipam.models import VLAN, VLANGroup, Role, Prefix, IPAddress
from extras.models import Tag
from extras.scripts import *
class NewELineService(Script):
class Meta:
name = "New AAPT E-Line Service"
description = "Provision a new AAPT E-Line service"
fields = ['fnn', 'state', 'speed', 'trunk']
field_order = ['fnn', 'state', 'speed', 'trunk']
commit_default = False
netbox_url = 'http://netbox.lab'
fnn = StringVar(
label = 'FNN',
min_length = 8,
max_length = 8,
regex = '\d+$',
description="The FNN of the service"
)
# TODO: Dropdown with custom selection
state = StringVar(
max_length = 3,
regex = '^(?:NSW|VIC|QLD|WA|TAS|ACT)$',
description = 'Service state: NSW/VIC/QLD/WA/TAS/ACT'
)
speed = IntegerVar(
min_value = 1,
max_value = 100,
description = 'The provisioned service speed in Mbps'
)
trunk = ObjectVar(
queryset = Interface.tags.filter(name__contains='aapt')
.exclude(name__regex='-[AZ]')
)
def Diff(self, li1, li2):
return (list(set(li1) - set(li2)))
def url(self, obj, x=''):
return x + self.netbox_url + obj.get_absolute_url()
def abort(self):
self.log_failure('!!! ABORTING !!!')
self.log_info('Nothing written to database.')
raise Exception
def run(self, data):
# vlans = VLAN.objects.filter(
# group__name='AAPT-SY1'
# )
vlans = VLAN.objects.filter(
site__name='Equinix SY1'
)
vid_list = list(vlans.values_list('vid', flat=True))
next_vid = self.next_available_vid(vid_list)
site = Site.objects.get(
name='Equinix SY1'
)
role = Role.objects.get(
name='AAPT'
)
cid = data['trunk']
fnn = data['fnn']
state = data['state']
# TODO: don't allowed duplicate FNNs
name = 'aapt-' + fnn
self.log_info('===CREATE VLAN===')
vlan = self.create_vlan(next_vid, name, site, role)
self.log_info('===UPDATE TRUNKS===')
trunk_ports = self.get_trunk_ports(vlan, cid)
role = Role.objects.get(
name = 'AAPT E-Line NSW'
)
self.log_info('===CREATE PREFIX===')
prefix = self.get_next_prefix(state, fnn, role, vlan)
vlan.save()
for port in trunk_ports:
port.tagged_vlans.add(vlan)
port.save()
prefix.vlan = vlan
prefix.save()
self.log_info('===CREATE L3 INTERFACE===')
interface = self.create_router_interface(vlan, fnn, data['speed'], prefix)
# A bit of a dirty workaround for the lack of VLAN group
# allowed VLAN ranges
def next_available_vid(self, vids):
# start_ and end_vid for allowed VLAN range
start_vid = 1400
end_vid = 1600
vids.append(start_vid - 1)
vids.append(end_vid + 1)
vids.sort()
original_list = [x for x in range(vids[0], vids[-1] + 1)]
vids = set(vids)
return (min(list(vids ^ set(original_list))))
def create_vlan(self, vid, name, site, role):
vlan = VLAN(
name=name,
vid=vid,
site=site,
role=role
)
# vlan.save()
self.log_success(vlan)
return vlan
def get_trunk_ports(self, vlan, cid):
trunk_ports = Interface.objects.filter(tags__name=cid)
tagged_ports = trunk_ports.filter(mode=200) # 200 = 'Tagged'
diff = self.Diff(trunk_ports, tagged_ports)
if len(diff) > 0:
self.log_failure('Interfaces not configured as tagged ports:')
for d in diff:
self.log_failure(d.name + ' on ' + d.device.name + self.url(d, ' '))
self.abort()
self.log_info('Interfaces with CID ' + cid.name + ' :')
for port in trunk_ports:
self.log_info(port.device.name + ' / ' + port.name)
return trunk_ports
def get_next_prefix(self, state, fnn, role, vlan):
prefix = None
containers = Prefix.objects.filter(
role = role,
status=0 # 0 = Container
)
created = False
# Loop through containers in case there are more than 1
# and they are full
for container in containers:
for cidr in container.get_available_prefixes().iter_cidrs():
try:
c = next(cidr.subnet(30, 1)) # Get the next /30
except:
continue
prefix = Prefix(
prefix = c,
role = role,
vlan = vlan,
description = fnn
)
self.log_success('Created prefix ' + str(prefix))
created = True
break
if created: break
self.log_info('No available /30 in ' + str(container))
if not created:
self.log_failure('No available /30.')
self.abort()
return prefix
def create_router_interface(self, vlan, fnn, speed, prefix):
z = Interface.objects.get(tags__name='aapt1234-Z')
d = z.device
i = Interface.objects.create(
name = z.name + '.' + str(vlan.vid),
description = fnn + ' ' + str(speed) + 'Mbps',
type = 1000 # Virtual
)
a = str(prefix.prefix[1]) + '/30'
IPAddress.objects.create(address=a, status=1, family=4, interface=i)
self.log_success('Created interface ' + i.name + ' on ' + d.name + ' with IP ' + a)
d.interfaces.add(i)
i.save()
d.save()
return i
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment