From f446907704b9cc0fee83cf4b4633cbfda03d2430 Mon Sep 17 00:00:00 2001 From: Parker Berberian Date: Thu, 14 Mar 2019 15:51:19 -0400 Subject: Fixing Network Models Change-Id: Ia2cdf069e90c8091e8d984c368e47f375aed02ea Signed-off-by: Parker Berberian --- .../migrations/0009_auto_20190315_1757.py | 73 ++++++++++++++++++++ src/resource_inventory/models.py | 57 +++++++++------- src/resource_inventory/resource_manager.py | 78 ++++++++++++++++------ 3 files changed, 162 insertions(+), 46 deletions(-) create mode 100644 src/resource_inventory/migrations/0009_auto_20190315_1757.py (limited to 'src/resource_inventory') diff --git a/src/resource_inventory/migrations/0009_auto_20190315_1757.py b/src/resource_inventory/migrations/0009_auto_20190315_1757.py new file mode 100644 index 0000000..92ed0e9 --- /dev/null +++ b/src/resource_inventory/migrations/0009_auto_20190315_1757.py @@ -0,0 +1,73 @@ +# Generated by Django 2.1 on 2019-03-15 17:57 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('resource_inventory', '0008_host_remote_management'), + ] + + operations = [ + migrations.CreateModel( + name='NetworkConnection', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('vlan_is_tagged', models.BooleanField()), + ], + ), + migrations.CreateModel( + name='NetworkRole', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=100)), + ], + ), + migrations.RemoveField( + model_name='genericinterface', + name='vlans', + ), + migrations.RemoveField( + model_name='network', + name='vlan_id', + ), + migrations.AddField( + model_name='network', + name='bundle', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, related_name='networks', to='resource_inventory.GenericResourceBundle'), + preserve_default=False, + ), + migrations.AddField( + model_name='network', + name='is_public', + field=models.BooleanField(default=False), + preserve_default=False, + ), + migrations.AddField( + model_name='vlan', + name='network', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='resource_inventory.Network'), + ), + migrations.AddField( + model_name='networkrole', + name='network', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='resource_inventory.Network'), + ), + migrations.AddField( + model_name='networkconnection', + name='network', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='resource_inventory.Network'), + ), + migrations.AddField( + model_name='genericinterface', + name='connections', + field=models.ManyToManyField(to='resource_inventory.NetworkConnection'), + ), + migrations.AddField( + model_name='opnfvconfig', + name='networks', + field=models.ManyToManyField(to='resource_inventory.NetworkRole'), + ), + ] diff --git a/src/resource_inventory/models.py b/src/resource_inventory/models.py index 4e3974e..0b7b24c 100644 --- a/src/resource_inventory/models.py +++ b/src/resource_inventory/models.py @@ -105,26 +105,6 @@ class RamProfile(models.Model): return str(self.amount) + "G for " + str(self.host) -# Networking -- located here due to import order requirements -class Network(models.Model): - id = models.AutoField(primary_key=True) - vlan_id = models.IntegerField() - name = models.CharField(max_length=100) - - def __str__(self): - return self.name - - -class Vlan(models.Model): - id = models.AutoField(primary_key=True) - vlan_id = models.IntegerField() - tagged = models.BooleanField() - public = models.BooleanField(default=False) - - def __str__(self): - return str(self.vlan_id) + ("_T" if self.tagged else "") - - # Generic resource templates class GenericResourceBundle(models.Model): id = models.AutoField(primary_key=True) @@ -145,6 +125,32 @@ class GenericResourceBundle(models.Model): return self.name +class Network(models.Model): + id = models.AutoField(primary_key=True) + name = models.CharField(max_length=100) + bundle = models.ForeignKey(GenericResourceBundle, on_delete=models.CASCADE, related_name="networks") + is_public = models.BooleanField() + + def __str__(self): + return self.name + + +class NetworkConnection(models.Model): + network = models.ForeignKey(Network, on_delete=models.CASCADE) + vlan_is_tagged = models.BooleanField() + + +class Vlan(models.Model): + id = models.AutoField(primary_key=True) + vlan_id = models.IntegerField() + tagged = models.BooleanField() + public = models.BooleanField(default=False) + network = models.ForeignKey(Network, on_delete=models.DO_NOTHING, null=True) + + def __str__(self): + return str(self.vlan_id) + ("_T" if self.tagged else "") + + 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 (_)") @@ -185,14 +191,11 @@ class ResourceBundle(models.Model): return "instance of " + str(self.template) -# Networking - - class GenericInterface(models.Model): id = models.AutoField(primary_key=True) - vlans = models.ManyToManyField(Vlan) profile = models.ForeignKey(InterfaceProfile, on_delete=models.CASCADE) host = models.ForeignKey(GenericHost, on_delete=models.CASCADE, related_name='generic_interfaces') + connections = models.ManyToManyField(NetworkConnection) def __str__(self): return "type " + str(self.profile) + " on host " + str(self.host) @@ -224,6 +227,11 @@ class Opsys(models.Model): return self.name +class NetworkRole(models.Model): + name = models.CharField(max_length=100) + network = models.ForeignKey(Network, on_delete=models.CASCADE) + + class ConfigBundle(models.Model): id = models.AutoField(primary_key=True) owner = models.ForeignKey(User, on_delete=models.CASCADE) @@ -240,6 +248,7 @@ class OPNFVConfig(models.Model): installer = models.ForeignKey(Installer, on_delete=models.CASCADE) scenario = models.ForeignKey(Scenario, on_delete=models.CASCADE) bundle = models.ForeignKey(ConfigBundle, related_name="opnfv_config", on_delete=models.CASCADE) + networks = models.ManyToManyField(NetworkRole) def __str__(self): return "OPNFV job with " + str(self.installer) + " and " + str(self.scenario) diff --git a/src/resource_inventory/resource_manager.py b/src/resource_inventory/resource_manager.py index 52b0055..d3d3ed4 100644 --- a/src/resource_inventory/resource_manager.py +++ b/src/resource_inventory/resource_manager.py @@ -14,7 +14,14 @@ from dashboard.exceptions import ( ResourceProvisioningException, ModelValidationException, ) -from resource_inventory.models import Host, HostConfiguration, ResourceBundle, HostProfile +from resource_inventory.models import ( + Host, + HostConfiguration, + ResourceBundle, + HostProfile, + Network, + Vlan +) class ResourceManager: @@ -66,39 +73,48 @@ class ResourceManager: self.releaseHost(host) resourceBundle.delete() - def convertResourceBundle(self, genericResourceBundle, lab=None, config=None): + def get_vlans(self, genericResourceBundle): + networks = {} + vlan_manager = genericResourceBundle.lab.vlan_manager + for network in genericResourceBundle.networks.all(): + if network.is_public: + public_net = vlan_manager.get_public_vlan() + vlan_manager.reserve_public_vlan(public_net.vlan) + networks[network.name] = public_net.vlan + else: + vlan = vlan_manager.get_vlan() + vlan_manager.reserve_vlans(vlan) + networks[network.name] = vlan + return networks + + def convertResourceBundle(self, genericResourceBundle, config=None): """ Takes in a GenericResourceBundle and 'converts' it into a ResourceBundle """ - resource_bundle = ResourceBundle() - resource_bundle.template = genericResourceBundle - resource_bundle.save() - - hosts = genericResourceBundle.getHosts() - - # current supported case: user creating new booking - # currently unsupported: editing existing booking - + resource_bundle = ResourceBundle.objects.create(template=genericResourceBundle) + generic_hosts = genericResourceBundle.getHosts() physical_hosts = [] - for host in hosts: + vlan_map = self.get_vlans(genericResourceBundle) + + for generic_host in generic_hosts: host_config = None if config: - host_config = HostConfiguration.objects.get(bundle=config, host=host) + host_config = HostConfiguration.objects.get(bundle=config, host=generic_host) try: - physical_host = self.acquireHost(host, genericResourceBundle.lab.name) + physical_host = self.acquireHost(generic_host, genericResourceBundle.lab.name) except ResourceAvailabilityException: - self.fail_acquire(physical_hosts) + self.fail_acquire(physical_hosts, vlan_map) raise ResourceAvailabilityException("Could not provision hosts, not enough available") try: physical_host.bundle = resource_bundle - physical_host.template = host + physical_host.template = generic_host physical_host.config = host_config physical_hosts.append(physical_host) - self.configureNetworking(physical_host) + self.configureNetworking(physical_host, vlan_map) except Exception: - self.fail_acquire(physical_hosts) + self.fail_acquire(physical_hosts, vlan_map) raise ResourceProvisioningException("Network configuration failed.") try: physical_host.save() @@ -108,13 +124,20 @@ class ResourceManager: return resource_bundle - def configureNetworking(self, host): + def configureNetworking(self, host, vlan_map): generic_interfaces = list(host.template.generic_interfaces.all()) for int_num, physical_interface in enumerate(host.interfaces.all()): generic_interface = generic_interfaces[int_num] physical_interface.config.clear() - for vlan in generic_interface.vlans.all(): - physical_interface.config.add(vlan) + for connection in generic_interface.connections.all(): + 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=connection.network + ) + ) # private interface def acquireHost(self, genericHost, labName): @@ -136,6 +159,17 @@ class ResourceManager: host.booked = False host.save() - def fail_acquire(self, hosts): + def releaseNetworks(self, grb, vlan_manager, vlans): + for net_name, vlan_id in vlans.items(): + net = Network.objects.get(name=net_name, bundle=grb) + if(net.is_public): + vlan_manager.release_public_vlan(vlan_id) + else: + vlan_manager.release_vlans(vlan_id) + + def fail_acquire(self, hosts, vlans): + grb = hosts[0].template.resource.bundle + vlan_manager = hosts[0].lab.vlan_manager + self.releaseNetworks(grb, vlan_manager, vlans) for host in hosts: self.releaseHost(host) -- cgit 1.2.3-korg