diff options
-rw-r--r-- | src/api/migrations/0007_auto_20190417_1511.py | 25 | ||||
-rw-r--r-- | src/api/migrations/0008_auto_20190419_1414.py | 28 | ||||
-rw-r--r-- | src/api/migrations/0009_merge_20190508_1317.py | 14 | ||||
-rw-r--r-- | src/api/models.py | 92 | ||||
-rw-r--r-- | src/api/urls.py | 4 | ||||
-rw-r--r-- | src/api/views.py | 14 | ||||
-rw-r--r-- | src/resource_inventory/idf_templater.py | 15 |
7 files changed, 180 insertions, 12 deletions
diff --git a/src/api/migrations/0007_auto_20190417_1511.py b/src/api/migrations/0007_auto_20190417_1511.py new file mode 100644 index 0000000..e7d2c59 --- /dev/null +++ b/src/api/migrations/0007_auto_20190417_1511.py @@ -0,0 +1,25 @@ +# Generated by Django 2.1 on 2019-04-17 15:11 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0006_auto_20190313_1729'), + ] + + operations = [ + migrations.AddField( + model_name='opnfvapiconfig', + name='idf', + field=models.CharField(default='', max_length=100), + preserve_default=False, + ), + migrations.AddField( + model_name='opnfvapiconfig', + name='pdf', + field=models.CharField(default='', max_length=100), + preserve_default=False, + ), + ] diff --git a/src/api/migrations/0008_auto_20190419_1414.py b/src/api/migrations/0008_auto_20190419_1414.py new file mode 100644 index 0000000..03c3865 --- /dev/null +++ b/src/api/migrations/0008_auto_20190419_1414.py @@ -0,0 +1,28 @@ +# Generated by Django 2.1 on 2019-04-19 14:14 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('resource_inventory', '0009_auto_20190315_1757'), + ('api', '0007_auto_20190417_1511'), + ] + + operations = [ + migrations.CreateModel( + name='BridgeConfig', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('interfaces', models.ManyToManyField(to='resource_inventory.Interface')), + ('opnfv_config', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='resource_inventory.OPNFVConfig')), + ], + ), + migrations.AddField( + model_name='opnfvapiconfig', + name='bridge_config', + field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to='api.BridgeConfig'), + ), + ] diff --git a/src/api/migrations/0009_merge_20190508_1317.py b/src/api/migrations/0009_merge_20190508_1317.py new file mode 100644 index 0000000..1a34380 --- /dev/null +++ b/src/api/migrations/0009_merge_20190508_1317.py @@ -0,0 +1,14 @@ +# Generated by Django 2.1 on 2019-05-08 13:17 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0008_auto_20190419_1414'), + ('api', '0007_opnfvapiconfig_opnfv_config'), + ] + + operations = [ + ] diff --git a/src/api/models.py b/src/api/models.py index c165454..1f708ae 100644 --- a/src/api/models.py +++ b/src/api/models.py @@ -12,6 +12,7 @@ from django.contrib.auth.models import User from django.db import models from django.core.exceptions import PermissionDenied from django.shortcuts import get_object_or_404 +from django.urls import reverse import json import uuid @@ -23,6 +24,7 @@ from resource_inventory.models import ( Host, Image, Interface, + HostOPNFVConfig, RemoteInfo, OPNFVConfig ) @@ -98,6 +100,14 @@ class LabManager(object): booking.idf = IDFTemplater().makeIDF(booking) booking.save() + def get_pdf(self, booking_id): + booking = get_object_or_404(Booking, pk=booking_id, lab=self.lab) + return booking.pdf + + def get_idf(self, booking_id): + booking = get_object_or_404(Booking, pk=booking_id, lab=self.lab) + return booking.idf + def get_profile(self): prof = {} prof['name'] = self.lab.name @@ -351,11 +361,44 @@ class TaskConfig(models.Model): self.delta = '{}' +class BridgeConfig(models.Model): + """ + Displays mapping between jumphost interfaces and + bridges + """ + interfaces = models.ManyToManyField(Interface) + opnfv_config = models.ForeignKey(OPNFVConfig, on_delete=models.CASCADE) + + def to_dict(self): + d = {} + hid = self.interfaces.first().host.labid + d[hid] = {} + for interface in self.interfaces.all(): + d[hid][interface.mac_address] = [] + for vlan in interface.config.all(): + network_role = self.opnfv_model.networks().filter(network=vlan.network) + bridge = IDFTemplater.bridge_names[network_role.name] + br_config = { + "vlan_id": vlan.vlan_id, + "tagged": vlan.tagged, + "bridge": bridge + } + d[hid][interface.mac_address].append(br_config) + return d + + def to_json(self): + return json.dumps(self.to_dict()) + + class OpnfvApiConfig(models.Model): installer = models.CharField(max_length=200) scenario = models.CharField(max_length=300) roles = models.ManyToManyField(Host) + # pdf and idf are url endpoints, not the actual file + pdf = models.CharField(max_length=100) + idf = models.CharField(max_length=100) + bridge_config = models.OneToOneField(BridgeConfig, on_delete=models.CASCADE, null=True) delta = models.TextField() opnfv_config = models.ForeignKey(OPNFVConfig, null=True, on_delete=models.SET_NULL) @@ -367,6 +410,12 @@ class OpnfvApiConfig(models.Model): d['installer'] = self.installer if self.scenario: d['scenario'] = self.scenario + if self.pdf: + d['pdf'] = self.pdf + if self.idf: + d['idf'] = self.idf + if self.bridge_config: + d['bridged_interfaces'] = self.bridge_config.to_dict() hosts = self.roles.all() if hosts.exists(): @@ -395,6 +444,16 @@ class OpnfvApiConfig(models.Model): d['scenario'] = scenario self.delta = json.dumps(d) + def set_xdf(self, booking, update_delta=True): + kwargs = {'lab_name': booking.lab.name, 'booking_id': booking.id} + self.pdf = reverse('get-pdf', kwargs=kwargs) + self.idf = reverse('get-idf', kwargs=kwargs) + if update_delta: + d = json.loads(self.delta) + d['pdf'] = self.pdf + d['idf'] = self.idf + self.delta = json.dumps(d) + def add_role(self, host): self.roles.add(host) d = json.loads(self.delta) @@ -632,6 +691,7 @@ class SnapshotConfig(TaskConfig): if not self.delta: self.delta = self.to_json() self.save() + d = json.loads(self.delta) return d @@ -823,7 +883,6 @@ class JobFactory(object): job=job ) cls.makeSoftware( - hosts=hosts, booking=booking, job=job ) @@ -915,18 +974,41 @@ class JobFactory(object): network_config.save() @classmethod - def makeSoftware(cls, hosts=[], booking=None, job=Job()): + def make_bridge_config(cls, booking): + if booking.resource.hosts.count() < 2: + return None + try: + jumphost_config = HostOPNFVConfig.objects.filter( + role__name__iexact="jumphost" + ) + jumphost = Host.objects.get( + bundle=booking.resource, + config=jumphost_config.host_config + ) + except Exception: + return None + br_config = BridgeConfig.objects.create(opnfv_config=booking.opnfv_config) + for iface in jumphost.interfaces.all(): + br_config.interfaces.add(iface) + return br_config + + @classmethod + def makeSoftware(cls, booking=None, job=Job()): if not booking.opnfv_config: return None opnfv_api_config = OpnfvApiConfig.objects.create( opnfv_config=booking.opnfv_config, - installer=booking.opnfv_config.installer, - scenario=booking.opnfv_config.scenario, + installer=booking.opnfv_config.installer.name, + scenario=booking.opnfv_config.scenario.name, + bridge_config=cls.make_bridge_config(booking) ) - for host in hosts: + opnfv_api_config.set_xdf(booking, False) + opnfv_api_config.save() + + for host in booking.resource.hosts.all(): opnfv_api_config.roles.add(host) software_config = SoftwareConfig.objects.create(opnfv=opnfv_api_config) software_relation = SoftwareRelation.objects.create(job=job, config=software_config) diff --git a/src/api/urls.py b/src/api/urls.py index d18a04d..d1f772a 100644 --- a/src/api/urls.py +++ b/src/api/urls.py @@ -41,6 +41,8 @@ from api.views import ( done_jobs, update_host_bmc, lab_host, + get_pdf, + get_idf, GenerateTokenView ) @@ -55,6 +57,8 @@ urlpatterns = [ path('labs/<slug:lab_name>/inventory', lab_inventory), path('labs/<slug:lab_name>/hosts/<slug:host_id>', lab_host), path('labs/<slug:lab_name>/hosts/<slug:host_id>/bmc', update_host_bmc), + path('labs/<slug:lab_name>/booking/<slug:booking_id>/pdf', get_pdf, name="get-pdf"), + path('labs/<slug:lab_name>/booking/<slug:booking_id>/idf', get_idf, name="get-idf"), path('labs/<slug:lab_name>/jobs/<int:job_id>', specific_job), path('labs/<slug:lab_name>/jobs/<int:job_id>/<slug:task_id>', specific_task), path('labs/<slug:lab_name>/jobs/new', new_jobs), diff --git a/src/api/views.py b/src/api/views.py index 2ae1ac5..fb28958 100644 --- a/src/api/views.py +++ b/src/api/views.py @@ -13,7 +13,7 @@ from django.contrib.auth.decorators import login_required from django.shortcuts import redirect from django.utils.decorators import method_decorator from django.views import View -from django.http.response import JsonResponse +from django.http.response import JsonResponse, HttpResponse from rest_framework import viewsets from rest_framework.authtoken.models import Token from django.views.decorators.csrf import csrf_exempt @@ -64,6 +64,18 @@ def lab_host(request, lab_name="", host_id=""): return JsonResponse(lab_manager.update_host(host_id, request.POST), safe=False) +def get_pdf(request, lab_name="", booking_id=""): + lab_token = request.META.get('HTTP_AUTH_TOKEN') + lab_manager = LabManagerTracker.get(lab_name, lab_token) + return HttpResponse(lab_manager.get_pdf(booking_id), content_type="text/plain") + + +def get_idf(request, lab_name="", booking_id=""): + lab_token = request.META.get('HTTP_AUTH_TOKEN') + lab_manager = LabManagerTracker.get(lab_name, lab_token) + return HttpResponse(lab_manager.get_idf(booking_id), content_type="text/plain") + + def lab_status(request, lab_name=""): lab_token = request.META.get('HTTP_AUTH_TOKEN') lab_manager = LabManagerTracker.get(lab_name, lab_token) diff --git a/src/resource_inventory/idf_templater.py b/src/resource_inventory/idf_templater.py index 26307e3..bf6eda0 100644 --- a/src/resource_inventory/idf_templater.py +++ b/src/resource_inventory/idf_templater.py @@ -19,8 +19,15 @@ class IDFTemplater: """ Utility class to create a full IDF yaml file """ + net_names = ["admin", "mgmt", "private", "public"] + bridge_names = { + "admin": "br-admin", + "mgmt": "br-mgmt", + "private": "br-private", + "public": "br-public" + } + def __init__(self): - self.net_names = ["admin", "mgmt", "private", "public"] self.networks = {} for i, name in enumerate(self.net_names): self.networks[name] = { @@ -117,11 +124,7 @@ class IDFTemplater: return fuel def get_fuel_bridges(self): - bridges = {} - for net in self.net_names: - bridges[net] = "br-" + net - - return bridges + return self.bridge_names def get_fuel_nodes(self, booking): jumphost = booking.opnfv_config.host_opnfv_config.get( |