diff options
Diffstat (limited to 'src/resource_inventory')
-rw-r--r-- | src/resource_inventory/migrations/0012_auto_20200103_1850.py | 76 | ||||
-rw-r--r-- | src/resource_inventory/models.py | 90 | ||||
-rw-r--r-- | src/resource_inventory/resource_manager.py | 14 |
3 files changed, 160 insertions, 20 deletions
diff --git a/src/resource_inventory/migrations/0012_auto_20200103_1850.py b/src/resource_inventory/migrations/0012_auto_20200103_1850.py new file mode 100644 index 0000000..2bb203e --- /dev/null +++ b/src/resource_inventory/migrations/0012_auto_20200103_1850.py @@ -0,0 +1,76 @@ +# Generated by Django 2.2 on 2020-01-03 18:50 + +from django.db import migrations, models +import django.db.models.deletion + + +def genTempVlanNetwork(apps, editor): + Vlan = apps.get_model("resource_inventory", "Vlan") + Network = apps.get_model("resource_inventory", "Network") + tempVlanNetwork = apps.get_model("resource_inventory", "tempVlanNetwork") + for vlan in Vlan.objects.filter(network__isnull=False): + tempVlanNetwork.objects.create(network=vlan.network, vlan=vlan) + +def deleteTempVlanNetworks(apps, editor): + tempVlanNetwork = apps.get_model("resource_inventory", "tempVlanNetwork") + tempVlanNetwork.objects.all().delete() + + +def pairVlanPhysicalNetworks(apps, editor): + PhysicalNetwork = apps.get_model("resource_inventory", "PhysicalNetwork") + tempVlanPair = apps.get_model("resource_inventory", "tempVlanNetwork") + for pair in tempVlanPair.objects.all(): + physicalNetwork = PhysicalNetwork.objects.create(vlan_id=vlan.vlan_id, + generic_network=pair.network) + pair.vlan.network = physicalNetwork + +def deletePhysicalNetworks(apps, editor): + PhysicalNetwork = apps.get_model("resource_inventory", "PhysicalNetwork") + PhysicalNetwork.objects.all().delete() + +class Migration(migrations.Migration): + + dependencies = [ + ('resource_inventory', '0011_auto_20191106_2024'), + ] + + operations = [ + migrations.CreateModel( + name='PhysicalNetwork', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('vlan_id', models.IntegerField()), + ('generic_network', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='resource_inventory.Network')), + ], + options={ + 'abstract': False, + }, + ), + migrations.AlterField( + model_name='host', + name='id', + field=models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), + ), + migrations.AlterField( + model_name='resourcebundle', + name='id', + field=models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), + ), + migrations.CreateModel( + name='tempVlanNetwork', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('vlan', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='resource_inventory.vlan')), + ('network', models.ForeignKey(null=True, to='resource_inventory.network', on_delete=django.db.models.deletion.CASCADE)), + ] + ), + migrations.RunPython(genTempVlanNetwork, deleteTempVlanNetworks), + migrations.AlterField( + model_name='vlan', + name='network', + field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, + to='resource_inventory.PhysicalNetwork', null=True), + ), + migrations.RunPython(pairVlanPhysicalNetworks, deletePhysicalNetworks), + migrations.DeleteModel("tempVlanNetwork") + ] diff --git a/src/resource_inventory/models.py b/src/resource_inventory/models.py index 031ccce..d152698 100644 --- a/src/resource_inventory/models.py +++ b/src/resource_inventory/models.py @@ -105,6 +105,33 @@ class RamProfile(models.Model): return str(self.amount) + "G for " + str(self.host) +class Resource(models.Model): + class Meta: + abstract = True + + def get_configuration(self, state): + """ + Returns the desired configuration for this host as a + JSON object as defined in the rest api spec. + state is a ConfigState + TODO: single method, or different methods for hw, network, snapshot, etc? + """ + raise NotImplementedError("Must implement in concrete Resource classes") + + def reserve(self): + """ + Reserves this resource for its currently + assigned booking. + """ + raise NotImplementedError("Must implement in concrete Resource classes") + + def release(self): + """ + Makes this resource available again for new boookings + """ + raise NotImplementedError("Must implement in concrete Resource classes") + + # Generic resource templates class GenericResourceBundle(models.Model): id = models.AutoField(primary_key=True) @@ -116,12 +143,12 @@ class GenericResourceBundle(models.Model): public = models.BooleanField(default=False) hidden = models.BooleanField(default=False) - def getHosts(self): - return_hosts = [] + def getResources(self): + my_resources = [] for genericResource in self.generic_resources.all(): - return_hosts.append(genericResource.getHost()) + my_resources.append(genericResource.getResource()) - return return_hosts + return my_resources def __str__(self): return self.name @@ -137,6 +164,29 @@ class Network(models.Model): return self.name +class PhysicalNetwork(Resource): + vlan_id = models.IntegerField() + generic_network = models.ForeignKey(Network, on_delete=models.CASCADE) + + def get_configuration(self, state): + """ + Returns the network configuration + Collects info about each attached network interface and vlan, etc + """ + return {} + + def reserve(self): + """ + Reserves vlan(s) associated with this network + """ + # vlan_manager = self.bundle.lab.vlan_manager + return False + + def release(self): + # vlan_manager = self.bundle.lab.vlan_manager + return False + + class NetworkConnection(models.Model): network = models.ForeignKey(Network, on_delete=models.CASCADE) vlan_is_tagged = models.BooleanField() @@ -147,18 +197,25 @@ class Vlan(models.Model): vlan_id = models.IntegerField() tagged = models.BooleanField() public = models.BooleanField(default=False) - network = models.ForeignKey(Network, on_delete=models.DO_NOTHING, null=True) + network = models.ForeignKey(PhysicalNetwork, on_delete=models.DO_NOTHING, null=True) def __str__(self): return str(self.vlan_id) + ("_T" if self.tagged else "") +class ConfigState: + NEW = 0 + RESET = 100 + CLEAN = 200 + + class GenericResource(models.Model): 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]) - def getHost(self): + def getResource(self): + # TODO: This will have to be dealt with return self.generic_host def __str__(self): @@ -183,8 +240,7 @@ class GenericHost(models.Model): # Physical, actual resources -class ResourceBundle(models.Model): - id = models.AutoField(primary_key=True) +class ResourceBundle(Resource): template = models.ForeignKey(GenericResourceBundle, on_delete=models.SET_NULL, null=True) def __str__(self): @@ -289,6 +345,9 @@ class Image(models.Model): def __str__(self): return self.name + def in_use(self): + return Host.objects.filter(booked=True, config__image=self).exists() + def get_sentinal_opnfv_role(): return OPNFVRole.objects.get_or_create(name="deleted", description="Role was deleted.") @@ -336,8 +395,7 @@ def get_default_remote_info(): # Concrete host, actual machine in a lab -class Host(models.Model): - id = models.AutoField(primary_key=True) +class Host(Resource): template = models.ForeignKey(GenericHost, on_delete=models.SET_NULL, null=True) booked = models.BooleanField(default=False) name = models.CharField(max_length=200, unique=True) @@ -354,6 +412,18 @@ class Host(models.Model): def __str__(self): return self.name + def get_configuration(self, state): + ipmi = state == ConfigState.NEW + power = "off" if state == ConfigState.CLEAN else "on" + + return { + "id": self.labid, + "image": self.config.image.lab_id, + "hostname": self.template.resource.name, + "power": power, + "ipmi_create": str(ipmi) + } + class Interface(models.Model): id = models.AutoField(primary_key=True) diff --git a/src/resource_inventory/resource_manager.py b/src/resource_inventory/resource_manager.py index e94b4ec..7df4263 100644 --- a/src/resource_inventory/resource_manager.py +++ b/src/resource_inventory/resource_manager.py @@ -50,7 +50,7 @@ class ResourceManager: # count up hosts profile_count = {} - for host in grb.getHosts(): + for host in grb.getResources(): if host.profile not in profile_count: profile_count[host.profile] = 0 profile_count[host.profile] += 1 @@ -71,7 +71,7 @@ class ResourceManager: # public interface def deleteResourceBundle(self, resourceBundle): for host in Host.objects.filter(bundle=resourceBundle): - self.releaseHost(host) + host.release() resourceBundle.delete() def get_vlans(self, genericResourceBundle): @@ -93,7 +93,7 @@ class ResourceManager: Takes in a GenericResourceBundle and 'converts' it into a ResourceBundle """ resource_bundle = ResourceBundle.objects.create(template=genericResourceBundle) - generic_hosts = genericResourceBundle.getHosts() + generic_hosts = genericResourceBundle.getResources() physical_hosts = [] vlan_map = self.get_vlans(genericResourceBundle) @@ -154,12 +154,6 @@ class ResourceManager: host.save() return host - def releaseHost(self, host): - host.template = None - host.bundle = None - host.booked = False - host.save() - def releaseNetworks(self, grb, vlan_manager, vlans): for net_name, vlan_id in vlans.items(): net = Network.objects.get(name=net_name, bundle=grb) @@ -172,7 +166,7 @@ class ResourceManager: vlan_manager = grb.lab.vlan_manager self.releaseNetworks(grb, vlan_manager, vlans) for host in hosts: - self.releaseHost(host) + host.release() class HostNameValidator(object): |