diff options
Diffstat (limited to 'src/resource_inventory/resource_manager.py')
-rw-r--r-- | src/resource_inventory/resource_manager.py | 197 |
1 files changed, 0 insertions, 197 deletions
diff --git a/src/resource_inventory/resource_manager.py b/src/resource_inventory/resource_manager.py deleted file mode 100644 index 16c106e..0000000 --- a/src/resource_inventory/resource_manager.py +++ /dev/null @@ -1,197 +0,0 @@ -############################################################################## -# Copyright (c) 2018 Parker Berberian, Sawyer Bergeron, and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## - -from __future__ import annotations # noqa: F407 - -import re -from typing import Optional -from django.db.models import Q - -from dashboard.exceptions import ResourceAvailabilityException - -from resource_inventory.models import ( - Resource, - ResourceBundle, - ResourceTemplate, - ResourceConfiguration, - Network, - Vlan, - PhysicalNetwork, - InterfaceConfiguration, -) - -from account.models import Lab -from django.contrib.auth.models import User - - -class ResourceManager: - - instance = None - - def __init__(self): - pass - - @staticmethod - def getInstance() -> ResourceManager: - if ResourceManager.instance is None: - ResourceManager.instance = ResourceManager() - return ResourceManager.instance - - def getAvailableResourceTemplates(self, lab: Lab, user: Optional[User] = None) -> list[ResourceTemplate]: - filter = Q(public=True) - if user: - filter = filter | Q(owner=user) - filter = filter & Q(temporary=False) & Q(lab=lab) - return ResourceTemplate.objects.filter(filter) - - def templateIsReservable(self, resource_template: ResourceTemplate): - """ - Check if the required resources to reserve this template is available. - - No changes to the database - """ - # count up hosts - profile_count = {} - for config in resource_template.getConfigs(): - if config.profile not in profile_count: - profile_count[config.profile] = 0 - profile_count[config.profile] += 1 - - # check that all required hosts are available - for profile in profile_count.keys(): - available = len(profile.get_resources(lab=resource_template.lab, unreserved=True)) - needed = profile_count[profile] - if available < needed: - return False - return True - - # public interface - def deleteResourceBundle(self, resourceBundle: ResourceBundle): - raise NotImplementedError("Resource Bundle Deletion Not Implemented") - - def releaseResourceBundle(self, resourceBundle: ResourceBundle): - resourceBundle.release() - - def get_vlans(self, resourceTemplate: ResourceTemplate) -> dict[str, int]: - """ - returns: dict from network name to the associated vlan number (backend vlan id) - """ - networks = {} - vlan_manager = resourceTemplate.lab.vlan_manager - for network in resourceTemplate.networks.all(): - if network.is_public: - # already throws if can't get requested count, so can always expect public_net to be Some - public_net = vlan_manager.get_public_vlan(within=resourceTemplate.public_vlan_pool_set()) - vlan_manager.reserve_public_vlan(public_net.vlan) - networks[network.name] = public_net.vlan - else: - # already throws if can't get requested count, so can always index in @ 0 - vlans = vlan_manager.get_vlans(count=1, within=resourceTemplate.private_vlan_pool_set()) - vlan_manager.reserve_vlans(vlans[0]) - networks[network.name] = vlans[0] - return networks - - def instantiateTemplate(self, resource_template: ResourceTemplate): - """ - Convert a ResourceTemplate into a ResourceBundle. - - Takes in a ResourceTemplate and reserves all the - Resources needed and returns a completed ResourceBundle. - """ - resource_bundle = ResourceBundle.objects.create(template=resource_template) - res_configs = resource_template.getConfigs() - resources = [] - - vlan_map = self.get_vlans(resource_template) - - for config in res_configs: - try: - phys_res = self.acquireHost(config) - phys_res.bundle = resource_bundle - phys_res.config = config - resources.append(phys_res) - - self.configureNetworking(resource_bundle, phys_res, vlan_map) - phys_res.save() - - except Exception as e: - self.fail_acquire(resources, vlan_map, resource_template) - raise e - - return resource_bundle - - def configureNetworking(self, resource_bundle: ResourceBundle, resource: Resource, vlan_map: dict[str, int]): - """ - @vlan_map: dict from network name to the associated vlan number (backend vlan id) - """ - for physical_interface in resource.interfaces.all(): - - # assign interface configs - iface_config = InterfaceConfiguration.objects.get( - profile=physical_interface.profile, - resource_config=resource.config - ) - - physical_interface.acts_as = iface_config - physical_interface.acts_as.save() - - physical_interface.config.clear() - for connection in iface_config.connections.all(): - physicalNetwork = PhysicalNetwork.objects.create( - vlan_id=vlan_map[connection.network.name], - generic_network=connection.network, - bundle=resource_bundle, - ) - physical_interface.config.add( - Vlan.objects.create( - vlan_id=vlan_map[connection.network.name], - tagged=connection.vlan_is_tagged, - public=connection.network.is_public, - network=physicalNetwork - ) - ) - - # private interface - def acquireHost(self, resource_config: ResourceConfiguration) -> Resource: - resources = resource_config.profile.get_resources( - lab=resource_config.template.lab, - unreserved=True - ) - - try: - resource = resources[0] # TODO: should we randomize and 'load balance' the servers? - resource.config = resource_config - resource.reserve() - return resource - except IndexError: - raise ResourceAvailabilityException("No available resources of requested type") - - def releaseNetworks(self, template, vlans): - vlan_manager = template.lab.vlan_manager - for net_name, vlan_id in vlans.items(): - net = Network.objects.get(name=net_name, bundle=template) - if (net.is_public): - vlan_manager.release_public_vlan(vlan_id) - else: - vlan_manager.release_vlans(vlan_id) - - def fail_acquire(self, hosts, vlans, template): - self.releaseNetworks(template, vlans) - for host in hosts: - host.release() - - -class HostNameValidator(object): - regex = r'^[A-Za-z0-9][A-Za-z0-9-]*$' - message = "Hostnames can only contain alphanumeric characters and hyphens (-). Hostnames must start with a letter" - pattern = re.compile(regex) - - @classmethod - def is_valid_hostname(cls, hostname): - return len(hostname) < 65 and cls.pattern.fullmatch(hostname) is not None |