Merge "Add ability to clean up hosts and vlans"
[pharos-tools.git] / dashboard / src / resource_inventory / models.py
index 5b07077..bdc1f5d 100644 (file)
@@ -39,7 +39,7 @@ class InterfaceProfile(models.Model):
     id = models.AutoField(primary_key=True)
     speed = models.IntegerField()
     name = models.CharField(max_length=100)
-    host = models.ForeignKey(HostProfile, on_delete=models.DO_NOTHING, related_name='interfaceprofile')
+    host = models.ForeignKey(HostProfile, on_delete=models.CASCADE, related_name='interfaceprofile')
     nic_type = models.CharField(
         max_length=50,
         choices=[
@@ -61,7 +61,7 @@ class DiskProfile(models.Model):
         ("HDD", "HDD")
     ])
     name = models.CharField(max_length=50)
-    host = models.ForeignKey(HostProfile, on_delete=models.DO_NOTHING, related_name='storageprofile')
+    host = models.ForeignKey(HostProfile, on_delete=models.CASCADE, related_name='storageprofile')
     rotation = models.IntegerField(default=0)
     interface = models.CharField(
         max_length=50,
@@ -88,7 +88,7 @@ class CpuProfile(models.Model):
         ("aarch64", "aarch64")
     ])
     cpus = models.IntegerField()
-    host = models.ForeignKey(HostProfile, on_delete=models.DO_NOTHING, related_name='cpuprofile')
+    host = models.ForeignKey(HostProfile, on_delete=models.CASCADE, related_name='cpuprofile')
     cflags = models.TextField(null=True)
 
     def __str__(self):
@@ -99,7 +99,7 @@ class RamProfile(models.Model):
     id = models.AutoField(primary_key=True)
     amount = models.IntegerField()
     channels = models.IntegerField()
-    host = models.ForeignKey(HostProfile, on_delete=models.DO_NOTHING, related_name='ramprofile')
+    host = models.ForeignKey(HostProfile, on_delete=models.CASCADE, related_name='ramprofile')
 
     def __str__(self):
         return str(self.amount) + "G for " + str(self.host)
@@ -130,8 +130,8 @@ class GenericResourceBundle(models.Model):
     id = models.AutoField(primary_key=True)
     name = models.CharField(max_length=300, unique=True)
     xml = models.TextField()
-    owner = models.ForeignKey(User, null=True, on_delete=models.DO_NOTHING)
-    lab = models.ForeignKey(Lab, null=True, on_delete=models.DO_NOTHING)
+    owner = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
+    lab = models.ForeignKey(Lab, null=True, on_delete=models.SET_NULL)
     description = models.CharField(max_length=1000, default="")
 
     def getHosts(self):
@@ -146,7 +146,7 @@ class GenericResourceBundle(models.Model):
 
 
 class GenericResource(models.Model):
-    bundle = models.ForeignKey(GenericResourceBundle, related_name='generic_resources', on_delete=models.DO_NOTHING)
+    bundle = models.ForeignKey(GenericResourceBundle, related_name='generic_resources', on_delete=models.CASCADE)
     hostname_validchars = RegexValidator(regex=r'(?=^.{1,253}$)(?=(^([A-Za-z0-9\-\_]{1,62}\.)*[A-Za-z0-9\-\_]{1,63}$))', message="Enter a valid hostname. Full domain name may be 1-253 characters, each hostname 1-63 characters (including suffixed dot), and valid characters for hostnames are A-Z, a-z, 0-9, hyphen (-), and underscore (_)")
     name = models.CharField(max_length=200, validators=[hostname_validchars])
 
@@ -167,8 +167,8 @@ class GenericResource(models.Model):
 # Host template
 class GenericHost(models.Model):
     id = models.AutoField(primary_key=True)
-    profile = models.ForeignKey(HostProfile, on_delete=models.DO_NOTHING)
-    resource = models.OneToOneField(GenericResource, related_name='generic_host', on_delete=models.DO_NOTHING)
+    profile = models.ForeignKey(HostProfile, on_delete=models.CASCADE)
+    resource = models.OneToOneField(GenericResource, related_name='generic_host', on_delete=models.CASCADE)
 
     def __str__(self):
         return self.resource.name
@@ -177,11 +177,16 @@ class GenericHost(models.Model):
 # Physical, actual resources
 class ResourceBundle(models.Model):
     id = models.AutoField(primary_key=True)
-    template = models.ForeignKey(GenericResourceBundle, on_delete=models.DO_NOTHING)
+    template = models.ForeignKey(GenericResourceBundle, on_delete=models.SET_NULL, null=True)
 
     def __str__(self):
+        if self.template is None:
+            return "Resource bundle " + str(self.id) + " with no template"
         return "instance of " + str(self.template)
 
+    def get_host(self, role="Jumphost"):
+        return Host.objects.filter(bundle=self, config__opnfvRole__name=role).first()
+
 
 # Networking
 
@@ -189,8 +194,8 @@ class ResourceBundle(models.Model):
 class GenericInterface(models.Model):
     id = models.AutoField(primary_key=True)
     vlans = models.ManyToManyField(Vlan)
-    profile = models.ForeignKey(InterfaceProfile, on_delete=models.DO_NOTHING)
-    host = models.ForeignKey(GenericHost, on_delete=models.DO_NOTHING, related_name='generic_interfaces')
+    profile = models.ForeignKey(InterfaceProfile, on_delete=models.CASCADE)
+    host = models.ForeignKey(GenericHost, on_delete=models.CASCADE, related_name='generic_interfaces')
 
     def __str__(self):
         return "type " + str(self.profile) + " on host " + str(self.host)
@@ -224,7 +229,7 @@ class Opsys(models.Model):
 
 class ConfigBundle(models.Model):
     id = models.AutoField(primary_key=True)
-    owner = models.ForeignKey(User, on_delete=models.CASCADE)  # consider setting to root user?
+    owner = models.ForeignKey(User, on_delete=models.CASCADE)
     name = models.CharField(max_length=200, unique=True)
     description = models.CharField(max_length=1000, default="")
     bundle = models.ForeignKey(GenericResourceBundle, null=True, on_delete=models.CASCADE)
@@ -262,7 +267,6 @@ class Image(models.Model):
     name = models.CharField(max_length=200)
     owner = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
     public = models.BooleanField(default=True)
-    # may need to change host_type.on_delete to models.SET() once images are transferrable between compatible host types
     host_type = models.ForeignKey(HostProfile, on_delete=models.CASCADE)
     description = models.TextField()
     os = models.ForeignKey(Opsys, null=True, on_delete=models.CASCADE)
@@ -271,6 +275,10 @@ class Image(models.Model):
         return self.name
 
 
+def get_sentinal_opnfv_role():
+    return OPNFVRole.objects.get_or_create(name="deleted", description="Role was deleted.")
+
+
 class HostConfiguration(models.Model):
     """
     model to represent a complete configuration for a single
@@ -280,12 +288,32 @@ class HostConfiguration(models.Model):
     host = models.ForeignKey(GenericHost, related_name="configuration", on_delete=models.CASCADE)
     image = models.ForeignKey(Image, on_delete=models.PROTECT)
     bundle = models.ForeignKey(ConfigBundle, related_name="hostConfigurations", null=True, on_delete=models.CASCADE)
-    opnfvRole = models.ForeignKey(OPNFVRole, on_delete=models.PROTECT)
+    opnfvRole = models.ForeignKey(OPNFVRole, on_delete=models.SET(get_sentinal_opnfv_role))
 
     def __str__(self):
         return "config with " + str(self.host) + " and image " + str(self.image)
 
 
+class RemoteInfo(models.Model):
+    address = models.CharField(max_length=15)
+    mac_address = models.CharField(max_length=17)
+    password = models.CharField(max_length=100)
+    user = models.CharField(max_length=100)
+    management_type = models.CharField(max_length=50, default="ipmi")
+    versions = models.CharField(max_length=100)  # json serialized list of floats
+
+
+def get_default_remote_info():
+    return RemoteInfo.objects.get_or_create(
+        address="default",
+        mac_address="default",
+        password="default",
+        user="default",
+        management_type="default",
+        versions="[default]"
+    )[0].pk
+
+
 # Concrete host, actual machine in a lab
 class Host(models.Model):
     id = models.AutoField(primary_key=True)
@@ -300,6 +328,7 @@ class Host(models.Model):
     working = models.BooleanField(default=True)
     vendor = models.CharField(max_length=100, default="unknown")
     model = models.CharField(max_length=150, default="unknown")
+    remote_management = models.ForeignKey(RemoteInfo, default=get_default_remote_info, on_delete=models.SET(get_default_remote_info))
 
     def __str__(self):
         return self.name