Add Quick-Booking Workflow
[pharos-tools.git] / dashboard / src / resource_inventory / resource_manager.py
1 ##############################################################################
2 # Copyright (c) 2018 Parker Berberian, Sawyer Bergeron, and others.
3 #
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
8 ##############################################################################
9
10
11 from django.template.loader import render_to_string
12
13 import booking
14 from dashboard.exceptions import (
15     ResourceExistenceException,
16     ResourceAvailabilityException,
17     ResourceProvisioningException,
18     ModelValidationException,
19 )
20 from resource_inventory.models import Host, HostConfiguration, ResourceBundle, HostProfile
21
22
23 class ResourceManager:
24
25     instance = None
26
27     def __init__(self):
28         pass
29
30     @staticmethod
31     def getInstance():
32         if ResourceManager.instance is None:
33             ResourceManager.instance = ResourceManager()
34         return ResourceManager.instance
35
36     def getAvailableHostTypes(self, lab):
37         hostset = Host.objects.filter(lab=lab).filter(booked=False).filter(working=True)
38         hostprofileset = HostProfile.objects.filter(host__in=hostset, labs=lab)
39         return set(hostprofileset)
40
41     # public interface
42     def deleteResourceBundle(self, resourceBundle):
43         for host in Host.objects.filter(bundle=resourceBundle):
44             self.releaseHost(host)
45         resourceBundle.delete()
46
47     def convertResourceBundle(self, genericResourceBundle, lab=None, config=None):
48         """
49         Takes in a GenericResourceBundle and 'converts' it into a ResourceBundle
50         """
51         resource_bundle = ResourceBundle()
52         resource_bundle.template = genericResourceBundle
53         resource_bundle.save()
54
55         hosts = genericResourceBundle.getHosts()
56
57         # current supported case: user creating new booking
58         # currently unsupported: editing existing booking
59
60         physical_hosts = []
61
62         for host in hosts:
63             host_config = None
64             if config:
65                 host_config = HostConfiguration.objects.get(bundle=config, host=host)
66             try:
67                 physical_host = self.acquireHost(host, genericResourceBundle.lab.name)
68             except ResourceAvailabilityException:
69                 self.fail_acquire(physical_hosts)
70                 raise ResourceAvailabilityException("Could not provision hosts, not enough available")
71             try:
72                 physical_host.bundle = resource_bundle
73                 physical_host.template = host
74                 physical_host.config = host_config
75                 physical_hosts.append(physical_host)
76
77                 self.configureNetworking(physical_host)
78             except Exception:
79                 self.fail_acquire(physical_hosts)
80                 raise ResourceProvisioningException("Network configuration failed.")
81             try:
82                 physical_host.save()
83             except Exception:
84                 self.fail_acquire(physical_hosts)
85                 raise ModelValidationException("Saving hosts failed")
86
87         return resource_bundle
88
89     def configureNetworking(self, host):
90         generic_interfaces = list(host.template.generic_interfaces.all())
91         for int_num, physical_interface in enumerate(host.interfaces.all()):
92             generic_interface = generic_interfaces[int_num]
93             physical_interface.config.clear()
94             for vlan in generic_interface.vlans.all():
95                 physical_interface.config.add(vlan)
96
97     # private interface
98     def acquireHost(self, genericHost, labName):
99         host_full_set = Host.objects.filter(lab__name__exact=labName, profile=genericHost.profile)
100         if not host_full_set.first():
101             raise ResourceExistenceException("No matching servers found")
102         host_set = host_full_set.filter(booked=False)
103         if not host_set.first():
104             raise ResourceAvailabilityException("No unbooked hosts match requested hosts")
105         host = host_set.first()
106         host.booked = True
107         host.template = genericHost
108         host.save()
109         return host
110
111     def releaseHost(self, host):
112         host.template = None
113         host.bundle = None
114         host.booked = False
115         host.save()
116
117     def fail_acquire(self, hosts):
118         for host in hosts:
119             self.releaseHost(host)
120
121     def makePDF(self, resource):
122         """
123         fills the pod descriptor file template with info about the resource
124         """
125         template = "dashboard/pdf.yaml"
126         info = {}
127         info['details'] = self.get_pdf_details(resource)
128         info['jumphost'] = self.get_pdf_jumphost(resource)
129         info['nodes'] = self.get_pdf_nodes(resource)
130
131         return render_to_string(template, context=info)
132
133     def get_pdf_details(self, resource):
134         details = {}
135         owner = "Anon"
136         email = "email@mail.com"
137         resource_lab = resource.template.lab
138         lab = resource_lab.name
139         location = resource_lab.location
140         pod_type = "development"
141         link = "https://wiki.opnfv.org/display/INF/Pharos+Laas"
142
143         try:
144             # try to get more specific info that may fail, we dont care if it does
145             booking_owner = booking.models.Booking.objects.get(resource=resource).owner
146             owner = booking_owner.username
147             email = booking_owner.userprofile.email_addr
148         except Exception:
149             pass
150
151         details['owner'] = owner
152         details['email'] = email
153         details['lab'] = lab
154         details['location'] = location
155         details['type'] = pod_type
156         details['link'] = link
157
158         return details
159
160     def get_pdf_jumphost(self, resource):
161         jumphost = Host.objects.get(bundle=resource, config__opnfvRole__name__iexact="jumphost")
162         return self.get_pdf_host(jumphost)
163
164     def get_pdf_nodes(self, resource):
165         pdf_nodes = []
166         nodes = Host.objects.filter(bundle=resource).exclude(config__opnfvRole__name__iexact="jumphost")
167         for node in nodes:
168             pdf_nodes.append(self.get_pdf_host(node))
169
170         return pdf_nodes
171
172     def get_pdf_host(self, host):
173         host_info = {}
174         host_info['name'] = host.template.resource.name
175         host_info['node'] = {}
176         host_info['node']['type'] = "baremetal"
177         host_info['node']['vendor'] = host.vendor
178         host_info['node']['model'] = host.model
179         host_info['node']['arch'] = host.profile.cpuprofile.first().architecture
180         host_info['node']['cpus'] = host.profile.cpuprofile.first().cpus
181         host_info['node']['cores'] = host.profile.cpuprofile.first().cores
182         cflags = host.profile.cpuprofile.first().cflags
183         if cflags and cflags.strip():
184             host_info['node']['cpu_cflags'] = cflags
185         host_info['node']['memory'] = str(host.profile.ramprofile.first().amount) + "G"
186         host_info['disks'] = []
187         for disk in host.profile.storageprofile.all():
188             disk_info = {}
189             disk_info['name'] = disk.name
190             disk_info['capacity'] = str(disk.size) + "G"
191             disk_info['type'] = disk.media_type
192             disk_info['interface'] = disk.interface
193             disk_info['rotation'] = disk.rotation
194             host_info['disks'].append(disk_info)
195
196         host_info['interfaces'] = []
197         for interface in host.interfaces.all():
198             iface_info = {}
199             iface_info['name'] = interface.name
200             iface_info['address'] = "unknown"
201             iface_info['mac_address'] = interface.mac_address
202             vlans = "|".join([str(vlan.vlan_id) for vlan in interface.config.all()])
203             iface_info['vlans'] = vlans
204             host_info['interfaces'].append(iface_info)
205
206         return host_info