diff options
Diffstat (limited to 'src/resource_inventory/models.py')
-rw-r--r-- | src/resource_inventory/models.py | 131 |
1 files changed, 125 insertions, 6 deletions
diff --git a/src/resource_inventory/models.py b/src/resource_inventory/models.py index 7fe479a..aefd5ce 100644 --- a/src/resource_inventory/models.py +++ b/src/resource_inventory/models.py @@ -9,10 +9,12 @@ ############################################################################## from django.contrib.auth.models import User + from django.core.exceptions import ValidationError from django.db import models from django.db.models import Q import traceback +import json import re from collections import Counter @@ -20,7 +22,6 @@ from collections import Counter from account.models import Lab from dashboard.utils import AbstractModelQuery - """ Profiles of resources hosted by labs. @@ -33,6 +34,10 @@ Profile models (e.g. an x86 server profile and armv8 server profile. class ResourceProfile(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=200, unique=True) + architecture = models.CharField(max_length=50, choices=[ + ("x86_64", "x86_64"), + ("aarch64", "aarch64") + ]) description = models.TextField() labs = models.ManyToManyField(Lab, related_name="resourceprofiles") @@ -147,6 +152,24 @@ with varying degrees of abstraction. """ +class CloudInitFile(models.Model): + text = models.TextField() + + # higher priority is applied later, so "on top" of existing files + priority = models.IntegerField() + + @classmethod + def merge_strategy(cls): + return [ + {'name': 'list', 'settings': ['append']}, + {'name': 'dict', 'settings': ['recurse_list', 'replace']}, + ] + + @classmethod + def create(cls, text="", priority=0): + return CloudInitFile.objects.create(priority=priority, text=text) + + class ResourceTemplate(models.Model): """ Models a "template" of a complete, configured collection of resources that can be booked. @@ -167,6 +190,24 @@ class ResourceTemplate(models.Model): temporary = models.BooleanField(default=False) copy_of = models.ForeignKey("ResourceTemplate", blank=True, null=True, on_delete=models.SET_NULL) + # if these fields are empty ("") then they are implicitly "every vlan", + # otherwise we filter any allocations we try to instantiate against this list + # they should be represented as a json list of integers + private_vlan_pool = models.TextField(default="") + public_vlan_pool = models.TextField(default="") + + def private_vlan_pool_set(self): + if self.private_vlan_pool != "": + return set(json.loads(self.private_vlan_pool)) + else: + return None + + def public_vlan_pool_set(self): + if self.private_vlan_pool != "": + return set(json.loads(self.public_vlan_pool)) + else: + return None + def getConfigs(self): configs = self.resourceConfigurations.all() return list(configs) @@ -235,9 +276,14 @@ class ResourceConfiguration(models.Model): is_head_node = models.BooleanField(default=False) name = models.CharField(max_length=3000, default="opnfv_host") + cloud_init_files = models.ManyToManyField(CloudInitFile, blank=True) + def __str__(self): return str(self.name) + def ci_file_list(self): + return list(self.cloud_init_files.order_by("priority").all()) + def get_default_remote_info(): return RemoteInfo.objects.get_or_create( @@ -369,10 +415,43 @@ class Server(Resource): return isinstance(other, Server) and other.name == self.name +def is_serializable(data): + try: + json.dumps(data) + return True + except Exception: + return False + + class Opsys(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=100) - sup_installers = models.ManyToManyField("Installer", blank=True) + lab_id = models.CharField(max_length=100) + obsolete = models.BooleanField(default=False) + available = models.BooleanField(default=True) # marked true by Cobbler if it exists there + from_lab = models.ForeignKey(Lab, on_delete=models.CASCADE) + + indexes = [ + models.Index(fields=['cobbler_id']) + ] + + def new_from_data(data): + opsys = Opsys() + opsys.update(data) + return opsys + + def serialize(self): + d = {} + for field in vars(self): + attr = getattr(self, field) + if is_serializable(attr): + d[field] = attr + return d + + def update(self, data): + for field in vars(self): + if field in data: + setattr(self, field, data[field] if data[field] else getattr(self, field)) def __str__(self): return self.name @@ -382,18 +461,51 @@ class Image(models.Model): """Model for representing OS images / snapshots of hosts.""" id = models.AutoField(primary_key=True) - lab_id = models.IntegerField() # ID the lab who holds this image knows from_lab = models.ForeignKey(Lab, on_delete=models.CASCADE) - name = models.CharField(max_length=200) + architecture = models.CharField(max_length=50, choices=[ + ("x86_64", "x86_64"), + ("aarch64", "aarch64"), + ("unknown", "unknown"), + ]) + lab_id = models.CharField(max_length=100) + name = models.CharField(max_length=100) owner = models.ForeignKey(User, null=True, on_delete=models.SET_NULL) public = models.BooleanField(default=True) - host_type = models.ForeignKey(ResourceProfile, on_delete=models.CASCADE) description = models.TextField() os = models.ForeignKey(Opsys, null=True, on_delete=models.CASCADE) + available = models.BooleanField(default=True) # marked True by cobbler if it exists there + obsolete = models.BooleanField(default=False) + + indexes = [ + models.Index(fields=['architecture']), + models.Index(fields=['cobbler_id']) + ] + def __str__(self): return self.name + def is_obsolete(self): + return self.obsolete or self.os.obsolete + + def serialize(self): + d = {} + for field in vars(self): + attr = getattr(self, field) + if is_serializable(attr): + d[field] = attr + return d + + def update(self, data): + for field in vars(self): + if field in data: + setattr(self, field, data[field] if data[field] else getattr(self, field)) + + def new_from_data(data): + img = Image() + img.update(data) + return img + def in_use(self): for resource in ResourceQuery.filter(config__image=self): if resource.is_reserved(): @@ -409,7 +521,7 @@ Networking configuration models class Network(models.Model): id = models.AutoField(primary_key=True) - name = models.CharField(max_length=100) + name = models.CharField(max_length=200) bundle = models.ForeignKey(ResourceTemplate, on_delete=models.CASCADE, related_name="networks") is_public = models.BooleanField() @@ -507,6 +619,13 @@ class NetworkRole(models.Model): network = models.ForeignKey(Network, on_delete=models.CASCADE) +def create_resource_ref_string(for_hosts: [str]) -> str: + # need to sort the list, then do dump + for_hosts.sort() + + return json.dumps(for_hosts) + + class OPNFVConfig(models.Model): id = models.AutoField(primary_key=True) installer = models.ForeignKey(Installer, on_delete=models.CASCADE) |