Enhance PDF/IDF Support
[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 dashboard.exceptions import (
12     ResourceExistenceException,
13     ResourceAvailabilityException,
14     ResourceProvisioningException,
15     ModelValidationException,
16 )
17 from resource_inventory.models import Host, HostConfiguration, ResourceBundle, HostProfile
18
19
20 class ResourceManager:
21
22     instance = None
23
24     def __init__(self):
25         pass
26
27     @staticmethod
28     def getInstance():
29         if ResourceManager.instance is None:
30             ResourceManager.instance = ResourceManager()
31         return ResourceManager.instance
32
33     def getAvailableHostTypes(self, lab):
34         hostset = Host.objects.filter(lab=lab).filter(booked=False).filter(working=True)
35         hostprofileset = HostProfile.objects.filter(host__in=hostset, labs=lab)
36         return set(hostprofileset)
37
38     def hostsAvailable(self, grb):
39         """
40         This method will check if the given GenericResourceBundle
41         is available. No changes to the database
42         """
43
44         # count up hosts
45         profile_count = {}
46         for host in grb.getHosts():
47             if host.profile not in profile_count:
48                 profile_count[host.profile] = 0
49             profile_count[host.profile] += 1
50
51         # check that all required hosts are available
52         for profile in profile_count.keys():
53             available = Host.objects.filter(
54                 booked=False,
55                 lab=grb.lab,
56                 profile=profile
57             ).count()
58             needed = profile_count[profile]
59             if available < needed:
60                 return False
61         return True
62
63     # public interface
64     def deleteResourceBundle(self, resourceBundle):
65         for host in Host.objects.filter(bundle=resourceBundle):
66             self.releaseHost(host)
67         resourceBundle.delete()
68
69     def convertResourceBundle(self, genericResourceBundle, lab=None, config=None):
70         """
71         Takes in a GenericResourceBundle and 'converts' it into a ResourceBundle
72         """
73         resource_bundle = ResourceBundle()
74         resource_bundle.template = genericResourceBundle
75         resource_bundle.save()
76
77         hosts = genericResourceBundle.getHosts()
78
79         # current supported case: user creating new booking
80         # currently unsupported: editing existing booking
81
82         physical_hosts = []
83
84         for host in hosts:
85             host_config = None
86             if config:
87                 host_config = HostConfiguration.objects.get(bundle=config, host=host)
88             try:
89                 physical_host = self.acquireHost(host, genericResourceBundle.lab.name)
90             except ResourceAvailabilityException:
91                 self.fail_acquire(physical_hosts)
92                 raise ResourceAvailabilityException("Could not provision hosts, not enough available")
93             try:
94                 physical_host.bundle = resource_bundle
95                 physical_host.template = host
96                 physical_host.config = host_config
97                 physical_hosts.append(physical_host)
98
99                 self.configureNetworking(physical_host)
100             except Exception:
101                 self.fail_acquire(physical_hosts)
102                 raise ResourceProvisioningException("Network configuration failed.")
103             try:
104                 physical_host.save()
105             except Exception:
106                 self.fail_acquire(physical_hosts)
107                 raise ModelValidationException("Saving hosts failed")
108
109         return resource_bundle
110
111     def configureNetworking(self, host):
112         generic_interfaces = list(host.template.generic_interfaces.all())
113         for int_num, physical_interface in enumerate(host.interfaces.all()):
114             generic_interface = generic_interfaces[int_num]
115             physical_interface.config.clear()
116             for vlan in generic_interface.vlans.all():
117                 physical_interface.config.add(vlan)
118
119     # private interface
120     def acquireHost(self, genericHost, labName):
121         host_full_set = Host.objects.filter(lab__name__exact=labName, profile=genericHost.profile)
122         if not host_full_set.first():
123             raise ResourceExistenceException("No matching servers found")
124         host_set = host_full_set.filter(booked=False)
125         if not host_set.first():
126             raise ResourceAvailabilityException("No unbooked hosts match requested hosts")
127         host = host_set.first()
128         host.booked = True
129         host.template = genericHost
130         host.save()
131         return host
132
133     def releaseHost(self, host):
134         host.template = None
135         host.bundle = None
136         host.booked = False
137         host.save()
138
139     def fail_acquire(self, hosts):
140         for host in hosts:
141             self.releaseHost(host)