1 from resource_inventory.models import (
11 InterfaceConfiguration,
21 from django.contrib.auth.models import User
23 from account.models import Lab
25 from resource_inventory.resource_manager import ResourceManager
26 from resource_inventory.pdf_templater import PDFTemplater
28 from booking.quick_deployer import update_template
30 from datetime import timedelta
32 from django.utils import timezone
34 from booking.models import Booking
35 from notifier.manager import NotificationHandler
36 from api.models import JobFactory
38 from api.models import JobStatus
42 print("====================================================================")
45 def book_host(owner_username, host_labid, lab_username, hostname, image_id, template_name, length_days=21, collaborator_usernames=[], purpose="internal", project="LaaS"):
47 creates a quick booking using the given host
49 lab = Lab.objects.get(lab_user__username=lab_username)
50 host = Server.objects.filter(lab=lab).get(labid=host_labid)
52 print("Can't book host, already marked as booked")
58 template = ResourceTemplate.objects.filter(public=True).get(name=template_name)
59 image = Image.objects.get(id=image_id)
61 owner = User.objects.get(username=owner_username)
63 new_template = update_template(template, image, hostname, owner)
65 rmanager = ResourceManager.getInstance()
67 vlan_map = rmanager.get_vlans(new_template)
69 # only a single host so can reuse var for iter here
70 resource_bundle = ResourceBundle.objects.create(template=new_template)
71 res_configs = new_template.getConfigs()
73 for config in res_configs:
75 host.bundle = resource_bundle
77 rmanager.configureNetworking(resource_bundle, host, vlan_map)
82 print("Failed to book host due to error configuring it")
87 booking = Booking.objects.create(
93 end=timezone.now() + timedelta(days=int(length_days)),
94 resource=resource_bundle,
98 booking.pdf = PDFTemplater.makePDF(booking)
102 for collaborator_username in collaborator_usernames:
104 user = User.objects.get(username=collaborator_username)
105 booking.collaborators.add(user)
107 print("couldn't add user with username ", collaborator_username)
111 JobFactory.makeCompleteJob(booking)
112 NotificationHandler.notify_new_booking(booking)
115 def mark_working(host_labid, lab_username, working=True):
116 lab = Lab.objects.get(lab_user__username=lab_username)
117 server = Server.objects.filter(lab=lab).get(labid=host_labid)
118 print("changing server working status from ", server.working, "to", working)
119 server.working = working
123 def mark_booked(host_labid, lab_username, booked=True):
124 lab = Lab.objects.get(lab_user__username=lab_username)
125 server = Server.objects.filter(lab=lab).get(labid=host_labid)
126 print("changing server booked status from ", server.booked, "to", booked)
127 server.booked = booked
131 # returns host filtered by lab and then unique id within lab
132 def get_host(host_labid, lab_username):
133 lab = Lab.objects.get(lab_user__username=lab_username)
134 return Server.objects.filter(lab=lab).get(labid=host_labid)
137 def get_info(host_labid, lab_username):
139 host = get_host(host_labid, lab_username)
140 info['host_labid'] = host_labid
141 info['booked'] = host.booked
142 info['working'] = host.working
143 info['profile'] = str(host.profile)
146 info['bundle'] = binfo
149 info['config'] = cinfo
154 def map_cntt_interfaces(labid: str):
156 Use this during cntt migrations, call it with a host labid and it will change profiles for this host
157 as well as mapping its interfaces across. interface ens1f2 should have the mac address of interface eno50
158 as an invariant before calling this function
160 host = get_host(labid, "unh_iol")
161 host.profile = ResourceProfile.objects.get(name="HPE x86 CNTT")
163 host = get_host(labid, "unh_iol")
165 for iface in host.interfaces.all():
167 if iface.profile.name == "ens1f2":
168 new_ifprofile = InterfaceProfile.objects.get(host=host.profile, name="eno50")
170 new_ifprofile = InterfaceProfile.objects.get(host=host.profile, name=iface.profile.name)
172 iface.profile = new_ifprofile
177 def detect_leaked_hosts(labid="unh_iol"):
179 Use this to try to detect leaked hosts.
180 These hosts may still be in the process of unprovisioning,
181 but if they are not (or unprovisioning is frozen) then
182 these hosts are instead leaked
184 working_servers = Server.objects.filter(working=True, lab__lab_user__username=labid)
185 booked = working_servers.filter(booked=True)
189 for booking in Booking.objects.filter(end__gte=timezone.now()):
190 res_for_booking = booking.resource.get_resources()
191 print(res_for_booking)
192 for resource in res_for_booking:
193 filtered = filtered.exclude(id=resource.id)
195 print("Possibly leaked:")
196 for host in filtered:
202 def booking_for_host(host_labid: str, labid="unh_iol"):
203 server = Server.objects.get(lab__lab_user__username=labid, labid=host_labid)
204 booking = server.bundle.booking_set.first()
207 print("id:", booking.id)
208 print("owner:", booking.owner)
209 print("job (id):", booking.job, "(" + str(booking.job.id) + ")")
214 def force_release_booking(booking_id):
215 booking = Booking.objects.get(id=booking_id)
217 tasks = job.get_tasklist()
219 task.status = JobStatus.DONE
223 def get_network_metadata(booking_id: int):
224 booking = Booking.objects.get(id=booking_id)
225 bundle = booking.resource
226 pnets = PhysicalNetwork.objects.filter(bundle=bundle).all()
229 net = pnet.generic_network
230 mdata = {"vlan_id": pnet.vlan_id, "netname": net.name, "public": net.is_public}
231 metadata[net.name] = mdata
235 def print_dict_pretty(a_dict):
236 print(json.dumps(a_dict, sort_keys=True, indent=4))
250 media_type: str ("SSD" or "HDD")
251 interface: str ("sata", "sas", "ssd", "nvme", "scsi", or "iscsi")
257 "nic_type": str ("onboard" or "pcie")
258 "order": int (compared to the other interfaces, indicates the "order" that the ports are laid out)
262 cores: int (hardware threads count)
263 architecture: str (x86_64" or "aarch64")
264 cpus: int (number of sockets)
275 def add_profile(data):
276 base_profile = ResourceProfile.objects.create(name=data['name'], description=data['description'])
279 for lab_username in data['labs']:
280 lab = Lab.objects.get(lab_user__username=lab_username)
282 base_profile.labs.add(lab)
285 for diskname in data['disks'].keys():
286 disk = data['disks'][diskname]
288 disk_profile = DiskProfile.objects.create(name=diskname, size=disk['capacity'], media_type=disk['media_type'], interface=disk['interface'], host=base_profile)
291 for ifacename in data['interfaces'].keys():
292 iface = data['interfaces'][ifacename]
294 iface_profile = InterfaceProfile.objects.create(name=ifacename, speed=iface['speed'], nic_type=iface['nic_type'], order=iface['order'], host=base_profile)
298 cpu_prof = CpuProfile.objects.create(cores=cpu['cores'], architecture=cpu['architecture'], cpus=cpu['cpus'], cflags=cpu['cflags'], host=base_profile)
301 ram_prof = RamProfile.objects.create(amount=data['ram']['amount'], channels=data['ram']['channels'], host=base_profile)
305 def make_default_template(resource_profile, image_id=None, template_name=None, connected_interface_names=None, interfaces_tagged=False, connected_interface_tagged=False, owner_username="root", lab_username="unh_iol", public=True, temporary=False, description=""):
307 if not resource_profile:
308 raise Exception("No viable continuation from none resource_profile")
310 if not template_name:
311 template_name = resource_profile.name
313 if not connected_interface_names:
314 connected_interface_names = [InterfaceProfile.objects.filter(host=resource_profile).first().name]
315 print("setting connected interface names to", connected_interface_names)
318 image_id = Image.objects.filter(host_type=resource_profile).first().id
320 image = Image.objects.get(id=image_id)
322 base = ResourceTemplate.objects.create(
325 owner=User.objects.get(username=owner_username),
326 lab=Lab.objects.get(lab_user__username=lab_username), description=description,
327 public=public, temporary=temporary, copy_of=None)
329 rconf = ResourceConfiguration.objects.create(profile=resource_profile, image=image, template=base, is_head_node=True, name="opnfv_host")
332 connected_interfaces = []
334 for iface_prof in InterfaceProfile.objects.filter(host=resource_profile).all():
335 iface_conf = InterfaceConfiguration.objects.create(profile=iface_prof, resource_config=rconf)
337 if iface_prof.name in connected_interface_names:
338 connected_interfaces.append(iface_conf)
340 network = Network.objects.create(name="public", bundle=base, is_public=True)
342 for iface in connected_interfaces:
343 connection = NetworkConnection.objects.create(network=network, vlan_is_tagged=interfaces_tagged)
346 iface.connections.add(connection)
347 print("adding connection to iface ", iface)
353 Note: interfaces should be dict from interface name (eg ens1f0) to dict of schema:
355 mac_address: <mac addr>,
356 bus_addr: <bus addr>, //this field is optional, "" is default
361 def add_server(profile, uname, interfaces, lab_username="unh_iol", vendor="unknown", model="unknown"):
362 server = Server.objects.create(
370 lab=Lab.objects.get(lab_user__username=lab_username),
374 for iface_prof in InterfaceProfile.objects.filter(host=profile).all():
375 mac_addr = interfaces[iface_prof.name]["mac_address"]
377 if "bus_addr" in interfaces[iface_prof.name].keys():
378 bus_addr = interfaces[iface_prof.name]["bus_addr"]
380 iface = Interface.objects.create(acts_as=None, profile=iface_prof, mac_address=mac_addr, bus_address=bus_addr)
383 server.interfaces.add(iface)