aboutsummaryrefslogtreecommitdiffstats
path: root/src/resource_inventory
diff options
context:
space:
mode:
Diffstat (limited to 'src/resource_inventory')
-rw-r--r--src/resource_inventory/migrations/0012_auto_20200103_1850.py76
-rw-r--r--src/resource_inventory/models.py90
-rw-r--r--src/resource_inventory/resource_manager.py14
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):