From f5cdab1569b26df0c7ffc3df1529f095116fd13a Mon Sep 17 00:00:00 2001 From: Parker Berberian Date: Thu, 6 Feb 2020 12:59:51 -0500 Subject: Modifies Resource Models for ongoing refactor Change-Id: Ice88f53135f57aca8e2de4d69274e7d490f981a4 Signed-off-by: Parker Berberian --- src/dashboard/utils.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/dashboard/utils.py (limited to 'src/dashboard') diff --git a/src/dashboard/utils.py b/src/dashboard/utils.py new file mode 100644 index 0000000..af2461e --- /dev/null +++ b/src/dashboard/utils.py @@ -0,0 +1,24 @@ + +class AbstractModelQuery(): + """ + This is a class made for querying abstract models. + + This class is itself abstract. create subclasses to + query your own abstract models. + """ + + model_list = [] + + @classmethod + def filter(cls, *args, **kwargs): + """ + Query all concrete model classes. + + Iterates over the model list and returns a list of all + matching models from the classes given. + Filter queries are given here as normal and are passed into the Django ORM + for each concrete model + """ + result = [] + for model in cls.model_list: + result += list(model.objects.filter(*args, **kwargs)) -- cgit 1.2.3-korg From 8c012f8a9bc64add11920688abcd6981278cb0ea Mon Sep 17 00:00:00 2001 From: Parker Berberian Date: Thu, 13 Feb 2020 14:25:24 -0500 Subject: Fix Imports Fixes stale import statements. The dashboard can now come up and we can run our unit tests Change-Id: I7189afb2cd37aaa2492de065c236b6aa9a35de5b Signed-off-by: Parker Berberian --- src/account/views.py | 10 +++---- src/api/serializers/booking_serializer.py | 4 +-- src/booking/quick_deployer.py | 20 ++++++------- src/booking/views.py | 6 ++-- src/dashboard/utils.py | 18 ++++++++++++ src/dashboard/views.py | 4 +-- src/resource_inventory/admin.py | 47 ++++++++++++++++--------------- src/resource_inventory/models.py | 1 + src/resource_inventory/views.py | 6 ++-- src/workflow/booking_workflow.py | 7 ++--- src/workflow/models.py | 4 +-- src/workflow/opnfv_workflow.py | 4 +-- src/workflow/resource_bundle_workflow.py | 30 +++++++++----------- src/workflow/snapshot_workflow.py | 4 +-- src/workflow/sw_bundle_workflow.py | 12 ++++---- src/workflow/workflow_manager.py | 13 ++++----- 16 files changed, 104 insertions(+), 86 deletions(-) (limited to 'src/dashboard') diff --git a/src/account/views.py b/src/account/views.py index ccc4c8d..a8bb02b 100644 --- a/src/account/views.py +++ b/src/account/views.py @@ -33,7 +33,7 @@ from account.forms import AccountSettingsForm from account.jira_util import SignatureMethod_RSA_SHA1 from account.models import UserProfile from booking.models import Booking -from resource_inventory.models import GenericResourceBundle, ConfigBundle, Image +from resource_inventory.models import ResourceTemplate, Image @method_decorator(login_required, name='dispatch') @@ -177,7 +177,7 @@ def account_resource_view(request): if not request.user.is_authenticated: return render(request, "dashboard/login.html", {'title': 'Authentication Required'}) template = "account/resource_list.html" - resources = GenericResourceBundle.objects.filter( + resources = ResourceTemplate.objects.filter( owner=request.user).prefetch_related("configbundle_set") mapping = {} resource_list = [] @@ -218,7 +218,7 @@ def account_configuration_view(request): if not request.user.is_authenticated: return render(request, "dashboard/login.html", {'title': 'Authentication Required'}) template = "account/configuration_list.html" - configs = list(ConfigBundle.objects.filter(owner=request.user)) + configs = list(ResourceTemplate.objects.filter(owner=request.user)) context = {"title": "Configuration List", "configurations": configs} return render(request, template, context=context) @@ -245,7 +245,7 @@ def account_images_view(request): def resource_delete_view(request, resource_id=None): if not request.user.is_authenticated: return HttpResponse('no') # 403? - grb = get_object_or_404(GenericResourceBundle, pk=resource_id) + grb = get_object_or_404(ResourceTemplate, pk=resource_id) if not request.user.id == grb.owner.id: return HttpResponse('no') # 403? if Booking.objects.filter(resource__template=grb, end__gt=timezone.now()).exists(): @@ -257,7 +257,7 @@ def resource_delete_view(request, resource_id=None): def configuration_delete_view(request, config_id=None): if not request.user.is_authenticated: return HttpResponse('no') # 403? - config = get_object_or_404(ConfigBundle, pk=config_id) + config = get_object_or_404(ResourceTemplate, pk=config_id) if not request.user.id == config.owner.id: return HttpResponse('no') # 403? if Booking.objects.filter(config_bundle=config, end__gt=timezone.now()).exists(): diff --git a/src/api/serializers/booking_serializer.py b/src/api/serializers/booking_serializer.py index 46a2348..993eb22 100644 --- a/src/api/serializers/booking_serializer.py +++ b/src/api/serializers/booking_serializer.py @@ -11,7 +11,7 @@ from rest_framework import serializers from resource_inventory.models import ( - HostConfiguration, + ResourceConfiguration, CpuProfile, DiskProfile, InterfaceProfile, @@ -35,7 +35,7 @@ class BookingField(serializers.Field): host_configs = {} # mapping hostname -> config networks = {} # mapping vlan id -> network_hosts for host in booking.resource.hosts.all(): - host_configs[host.name] = HostConfiguration.objects.get(host=host.template) + host_configs[host.name] = ResourceConfiguration.objects.get(host=host.template) if "jumphost" not in ser and host_configs[host.name].opnfvRole.name.lower() == "jumphost": ser['jumphost'] = host.name # host is a Host model diff --git a/src/booking/quick_deployer.py b/src/booking/quick_deployer.py index 94ad14d..917f578 100644 --- a/src/booking/quick_deployer.py +++ b/src/booking/quick_deployer.py @@ -12,7 +12,7 @@ import json from django.db.models import Q from datetime import timedelta from django.utils import timezone -from django.form import ValidationException +from django.core.exceptions import ValidationError from account.models import Lab from resource_inventory.models import ( @@ -21,7 +21,7 @@ from resource_inventory.models import ( Image, OPNFVRole, OPNFVConfig, - HostOPNFVConfig, + ResourceOPNFVConfig, ) from resource_inventory.resource_manager import ResourceManager from resource_inventory.pdf_templater import PDFTemplater @@ -49,9 +49,9 @@ def parse_resource_field(resource_json): template = ResourceTemplate.objects.get(pk=resource_info['id']) if lab is None: - raise ValidationException("No lab was selected") + raise ValidationError("No lab was selected") if template is None: - raise ValidationException("No Host was selected") + raise ValidationError("No Host was selected") return lab, template @@ -82,7 +82,7 @@ def generate_hostopnfv(hostconfig, opnfvconfig): name="Jumphost", description="Single server jumphost role" ) - return HostOPNFVConfig.objects.create( + return ResourceOPNFVConfig.objects.create( role=role, host_config=hostconfig, opnfv_config=opnfvconfig @@ -107,15 +107,15 @@ def check_invariants(request, **kwargs): if installer in image.os.sup_installers.all(): # if installer not here, we can omit that and not check for scenario if not scenario: - raise ValidationException("An OPNFV Installer needs a scenario to be chosen to work properly") + raise ValidationError("An OPNFV Installer needs a scenario to be chosen to work properly") if scenario not in installer.sup_scenarios.all(): - raise ValidationException("The chosen installer does not support the chosen scenario") + raise ValidationError("The chosen installer does not support the chosen scenario") if image.from_lab != lab: - raise ValidationException("The chosen image is not available at the chosen hosting lab") + raise ValidationError("The chosen image is not available at the chosen hosting lab") if image.host_type != host_profile: - raise ValidationException("The chosen image is not available for the chosen host type") + raise ValidationError("The chosen image is not available for the chosen host type") if not image.public and image.owner != request.user: - raise ValidationException("You are not the owner of the chosen private image") + raise ValidationError("You are not the owner of the chosen private image") if length < 1 or length > 21: raise BookingLengthException("Booking must be between 1 and 21 days long") diff --git a/src/booking/views.py b/src/booking/views.py index 8e25952..39b24a7 100644 --- a/src/booking/views.py +++ b/src/booking/views.py @@ -18,7 +18,7 @@ from django.shortcuts import redirect, render from django.db.models import Q from django.urls import reverse -from resource_inventory.models import ResourceBundle, HostProfile, Image, Host +from resource_inventory.models import ResourceBundle, ResourceProfile, Image, ResourceQuery from resource_inventory.resource_manager import ResourceManager from account.models import Lab, Downtime from booking.models import Booking @@ -130,7 +130,7 @@ class ResourceBookingsJSON(View): def build_image_mapping(lab, user): mapping = {} - for profile in HostProfile.objects.filter(labs=lab): + for profile in ResourceProfile.objects.filter(labs=lab): images = Image.objects.filter( from_lab=lab, host_type=profile @@ -178,7 +178,7 @@ def booking_modify_image(request, booking_id): if timezone.now() > booking.end: return HttpResponse("unauthorized") new_image = Image.objects.get(id=form.cleaned_data['image_id']) - host = Host.objects.get(id=form.cleaned_data['host_id']) + host = ResourceQuery.get(labid=form.cleaned_data['host_id']) host.config.image = new_image host.config.save() JobFactory.reimageHost(new_image, booking, host) diff --git a/src/dashboard/utils.py b/src/dashboard/utils.py index af2461e..3d63366 100644 --- a/src/dashboard/utils.py +++ b/src/dashboard/utils.py @@ -1,3 +1,14 @@ +############################################################################## +# Copyright (c) 2020 Parker Berberian and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +from django.core.exceptions import ObjectDoesNotExist + class AbstractModelQuery(): """ @@ -22,3 +33,10 @@ class AbstractModelQuery(): result = [] for model in cls.model_list: result += list(model.objects.filter(*args, **kwargs)) + + @classmethod + def get(cls, *args, **kwargs): + try: + return cls.filter(*args, **kwargs)[0] + except IndexError: + raise ObjectDoesNotExist() diff --git a/src/dashboard/views.py b/src/dashboard/views.py index 2f37774..498bd9d 100644 --- a/src/dashboard/views.py +++ b/src/dashboard/views.py @@ -15,7 +15,7 @@ from django.shortcuts import render from account.models import Lab -from resource_inventory.models import Image, HostProfile +from resource_inventory.models import Image, ResourceProfile from workflow.workflow_manager import ManagerTracker @@ -80,7 +80,7 @@ class LandingView(TemplateView): hosts = [] - for host_profile in HostProfile.objects.all(): + for host_profile in ResourceProfile.objects.all(): name = host_profile.name description = host_profile.description in_labs = host_profile.labs diff --git a/src/resource_inventory/admin.py b/src/resource_inventory/admin.py index ab21dd1..13afd99 100644 --- a/src/resource_inventory/admin.py +++ b/src/resource_inventory/admin.py @@ -16,11 +16,10 @@ from resource_inventory.models import ( DiskProfile, CpuProfile, RamProfile, - GenericResourceBundle, - GenericResource, - GenericHost, - GenericInterface, - Host, + ResourceTemplate, + ResourceConfiguration, + InterfaceConfiguration, + Server, Interface, Network, Vlan, @@ -28,26 +27,30 @@ from resource_inventory.models import ( Scenario, Installer, Opsys, - ConfigBundle, OPNFVConfig, OPNFVRole, Image, - ResourceConfiguration, RemoteInfo ) -profiles = [HostProfile, InterfaceProfile, DiskProfile, CpuProfile, RamProfile] - -admin.site.register(profiles) - -generics = [GenericResourceBundle, GenericResource, GenericHost, GenericInterface] - -admin.site.register(generics) - -physical = [Host, Interface, Network, Vlan, ResourceBundle] - -admin.site.register(physical) - -config = [Scenario, Installer, Opsys, ConfigBundle, OPNFVConfig, OPNFVRole, Image, HostConfiguration, RemoteInfo] - -admin.site.register(config) +admin.site.register([ + ResourceProfile, + InterfaceProfile, + DiskProfile, + CpuProfile, + RamProfile, + ResourceTemplate, + ResourceConfiguration, + InterfaceConfiguration, + Server, + Interface, + Network, + Vlan, + ResourceBundle, + Scenario, + Installer, + Opsys, + OPNFVConfig, + OPNFVRole, + Image, + RemoteInfo]) diff --git a/src/resource_inventory/models.py b/src/resource_inventory/models.py index 20e080b..eec009a 100644 --- a/src/resource_inventory/models.py +++ b/src/resource_inventory/models.py @@ -200,6 +200,7 @@ class ResourceConfiguration(models.Model): image = models.ForeignKey("Image", on_delete=models.PROTECT) template = models.ForeignKey(ResourceTemplate, related_name="resourceConfigurations", null=True, on_delete=models.CASCADE) is_head_node = models.BooleanField(default=False) + # name? def __str__(self): return "config with " + str(self.template) + " and image " + str(self.image) diff --git a/src/resource_inventory/views.py b/src/resource_inventory/views.py index 8c3d899..52f8c75 100644 --- a/src/resource_inventory/views.py +++ b/src/resource_inventory/views.py @@ -12,7 +12,7 @@ from django.views.generic import TemplateView from django.shortcuts import get_object_or_404 from django.shortcuts import render -from resource_inventory.models import HostProfile, Host +from resource_inventory.models import ResourceProfile, ResourceQuery class HostView(TemplateView): @@ -20,13 +20,13 @@ class HostView(TemplateView): def get_context_data(self, **kwargs): context = super(HostView, self).get_context_data(**kwargs) - hosts = Host.objects.filter(working=True) + hosts = ResourceQuery.filter(working=True) context.update({'hosts': hosts, 'title': "Hardware Resources"}) return context def hostprofile_detail_view(request, hostprofile_id): - hostprofile = get_object_or_404(HostProfile, id=hostprofile_id) + hostprofile = get_object_or_404(ResourceProfile, id=hostprofile_id) return render( request, diff --git a/src/workflow/booking_workflow.py b/src/workflow/booking_workflow.py index c96e1b9..00fa0f9 100644 --- a/src/workflow/booking_workflow.py +++ b/src/workflow/booking_workflow.py @@ -14,7 +14,7 @@ from datetime import timedelta from booking.models import Booking from workflow.models import WorkflowStep, AbstractSelectOrCreate from workflow.forms import ResourceSelectorForm, SWConfigSelectorForm, BookingMetaForm, OPNFVSelectForm -from resource_inventory.models import GenericResourceBundle, ConfigBundle, OPNFVConfig +from resource_inventory.models import OPNFVConfig, ResourceTemplate from django.db.models import Q @@ -44,8 +44,7 @@ class Abstract_Resource_Select(AbstractSelectOrCreate): def get_form_queryset(self): user = self.repo_get(self.repo.SESSION_USER) - qs = GenericResourceBundle.objects.filter(Q(hidden=False) & (Q(owner=user) | Q(public=True))) - return qs + return ResourceTemplate.objects.filter(Q(hidden=False) & (Q(owner=user) | Q(public=True))) def get_page_context(self): return { @@ -83,7 +82,7 @@ class SWConfig_Select(AbstractSelectOrCreate): def get_form_queryset(self): user = self.repo_get(self.repo.SESSION_USER) grb = self.repo_get(self.repo.SELECTED_GRESOURCE_BUNDLE) - qs = ConfigBundle.objects.filter(Q(hidden=False) & (Q(owner=user) | Q(public=True))).filter(bundle=grb) + qs = ResourceTemplate.objects.filter(Q(hidden=False) & (Q(owner=user) | Q(public=True))).filter(bundle=grb) return qs def put_confirm_info(self, bundle): diff --git a/src/workflow/models.py b/src/workflow/models.py index 4d32869..df00d21 100644 --- a/src/workflow/models.py +++ b/src/workflow/models.py @@ -18,7 +18,7 @@ import requests from workflow.forms import ConfirmationForm from api.models import JobFactory from dashboard.exceptions import ResourceAvailabilityException, ModelValidationException -from resource_inventory.models import Image, InterfaceProfile, OPNFVConfig, ResourceOPNFVConfig, NetworkRole +from resource_inventory.models import Image, InterfaceConfiguration, OPNFVConfig, ResourceOPNFVConfig, NetworkRole from resource_inventory.resource_manager import ResourceManager from resource_inventory.pdf_templater import PDFTemplater from notifier.manager import NotificationHandler @@ -725,7 +725,7 @@ class Repository(): config = config_bundle.hostConfigurations.get( host__resource__name=host_role['host_name'] ) - HostOPNFVConfig.objects.create( + ResourceOPNFVConfig.objects.create( role=host_role['role'], host_config=config, opnfv_config=opnfv_config diff --git a/src/workflow/opnfv_workflow.py b/src/workflow/opnfv_workflow.py index 0cac48e..6ffc91d 100644 --- a/src/workflow/opnfv_workflow.py +++ b/src/workflow/opnfv_workflow.py @@ -11,7 +11,7 @@ from django.forms import formset_factory from workflow.models import WorkflowStep, AbstractSelectOrCreate -from resource_inventory.models import ConfigBundle, OPNFV_SETTINGS +from resource_inventory.models import ResourceTemplate, OPNFV_SETTINGS from workflow.forms import OPNFVSelectionForm, OPNFVNetworkRoleForm, OPNFVHostRoleForm, SWConfigSelectorForm, BasicMetaForm @@ -27,7 +27,7 @@ class OPNFV_Resource_Select(AbstractSelectOrCreate): def get_form_queryset(self): user = self.repo_get(self.repo.SESSION_USER) - qs = ConfigBundle.objects.filter(owner=user) + qs = ResourceTemplate.objects.filter(owner=user) return qs def put_confirm_info(self, bundle): diff --git a/src/workflow/resource_bundle_workflow.py b/src/workflow/resource_bundle_workflow.py index f57476b..89baae7 100644 --- a/src/workflow/resource_bundle_workflow.py +++ b/src/workflow/resource_bundle_workflow.py @@ -22,11 +22,10 @@ from workflow.forms import ( ResourceMetaForm, ) from resource_inventory.models import ( - GenericResourceBundle, - GenericInterface, - GenericHost, - GenericResource, - HostProfile, + ResourceProfile, + ResourceTemplate, + ResourceConfiguration, + InterfaceConfiguration, Network, NetworkConnection ) @@ -64,12 +63,12 @@ class Define_Hardware(WorkflowStep): models['hosts'] = [] # This will always clear existing data when this step changes models['interfaces'] = {} if "bundle" not in models: - models['bundle'] = GenericResourceBundle(owner=self.repo_get(self.repo.SESSION_USER)) + models['bundle'] = ResourceTemplate(owner=self.repo_get(self.repo.SESSION_USER)) host_data = data['host'] names = {} for host_profile_dict in host_data.values(): id = host_profile_dict['id'] - profile = HostProfile.objects.get(id=id) + profile = ResourceProfile.objects.get(id=id) # instantiate genericHost and store in repo for name in host_profile_dict['values'].values(): if not re.match(r"(?=^.{1,253}$)(^([A-Za-z0-9-_]{1,62}\.)*[A-Za-z0-9-_]{1,63})", name): @@ -77,14 +76,13 @@ class Define_Hardware(WorkflowStep): if name in names: raise NonUniqueHostnameException("All hosts must have unique names") names[name] = True - genericResource = GenericResource(bundle=models['bundle'], name=name) - genericHost = GenericHost(profile=profile, resource=genericResource) - models['hosts'].append(genericHost) + resourceConfig = ResourceConfiguration(profile=profile, template=models['bundle']) + models['hosts'].append(resourceConfig) for interface_profile in profile.interfaceprofile.all(): - genericInterface = GenericInterface(profile=interface_profile, host=genericHost) - if genericHost.resource.name not in models['interfaces']: - models['interfaces'][genericHost.resource.name] = [] - models['interfaces'][genericHost.resource.name].append(genericInterface) + genericInterface = InterfaceConfiguration(profile=interface_profile, resource_config=resourceConfig) + if resourceConfig.name not in models['interfaces']: + models['interfaces'][resourceConfig.name] = [] + models['interfaces'][resourceConfig.name].append(genericInterface) # add selected lab to models for lab_dict in data['lab'].values(): @@ -226,7 +224,7 @@ class Define_Nets(WorkflowStep): for host in existing_host_list: existing_hosts[host.resource.name] = host - bundle = models.get("bundle", GenericResourceBundle(owner=self.repo_get(self.repo.SESSION_USER))) + bundle = models.get("bundle", ResourceTemplate(owner=self.repo_get(self.repo.SESSION_USER))) for net_id, net in networks.items(): network = Network() @@ -381,7 +379,7 @@ class Resource_Meta_Info(WorkflowStep): models = self.repo_get(self.repo.GRESOURCE_BUNDLE_MODELS, {}) name = form.cleaned_data['bundle_name'] desc = form.cleaned_data['bundle_description'] - bundle = models.get("bundle", GenericResourceBundle(owner=self.repo_get(self.repo.SESSION_USER))) + bundle = models.get("bundle", ResourceTemplate(owner=self.repo_get(self.repo.SESSION_USER))) bundle.name = name bundle.description = desc models['bundle'] = bundle diff --git a/src/workflow/snapshot_workflow.py b/src/workflow/snapshot_workflow.py index c2f4cd6..c0e2052 100644 --- a/src/workflow/snapshot_workflow.py +++ b/src/workflow/snapshot_workflow.py @@ -12,7 +12,7 @@ from django.utils import timezone import json from booking.models import Booking -from resource_inventory.models import Host, Image +from resource_inventory.models import ResourceQuery, Image from workflow.models import WorkflowStep from workflow.forms import BasicMetaForm, SnapshotHostSelectForm @@ -61,7 +61,7 @@ class Select_Host_Step(WorkflowStep): name = host['name'] booking_id = host['booking'] booking = Booking.objects.get(pk=booking_id) - host = Host.objects.get(bundle=booking.resource, template__resource__name=name) + host = ResourceQuery.get(bundle=booking.resource, template__resource__name=name) models = self.repo_get(self.repo.SNAPSHOT_MODELS, {}) if "host" not in models: models['host'] = host diff --git a/src/workflow/sw_bundle_workflow.py b/src/workflow/sw_bundle_workflow.py index ebd8c86..686f46f 100644 --- a/src/workflow/sw_bundle_workflow.py +++ b/src/workflow/sw_bundle_workflow.py @@ -13,7 +13,7 @@ from django.forms import formset_factory from workflow.models import WorkflowStep from workflow.forms import BasicMetaForm, HostSoftwareDefinitionForm from workflow.booking_workflow import Abstract_Resource_Select -from resource_inventory.models import Image, GenericHost, ConfigBundle, HostConfiguration +from resource_inventory.models import Image, ResourceConfiguration, ResourceTemplate class SWConf_Resource_Select(Abstract_Resource_Select): @@ -38,7 +38,7 @@ class Define_Software(WorkflowStep): user = self.repo_get(self.repo.SESSION_USER) lab = self.repo_get(self.repo.SELECTED_GRESOURCE_BUNDLE).lab for i, host_data in enumerate(hosts_data): - host = GenericHost.objects.get(pk=host_data['host_id']) + host = ResourceConfiguration.objects.get(pk=host_data['host_id']) wrong_owner = Image.objects.exclude(owner=user).exclude(public=True) wrong_host = Image.objects.exclude(host_type=host.profile) wrong_lab = Image.objects.exclude(from_lab=lab) @@ -86,7 +86,7 @@ class Define_Software(WorkflowStep): if not grb: return [] if grb.id: - return GenericHost.objects.filter(resource__bundle=grb) + return ResourceConfiguration.objects.filter(resource__bundle=grb) generic_hosts = self.repo_get(self.repo.GRESOURCE_BUNDLE_MODELS, {}).get("hosts", []) return generic_hosts @@ -109,7 +109,7 @@ class Define_Software(WorkflowStep): def post(self, post_data, user): models = self.repo_get(self.repo.CONFIG_MODELS, {}) if "bundle" not in models: - models['bundle'] = ConfigBundle(owner=self.repo_get(self.repo.SESSION_USER)) + models['bundle'] = ResourceTemplate(owner=self.repo_get(self.repo.SESSION_USER)) confirm = self.repo_get(self.repo.CONFIRMATION, {}) @@ -127,7 +127,7 @@ class Define_Software(WorkflowStep): if headnode: has_headnode = True bundle = models['bundle'] - hostConfig = HostConfiguration( + hostConfig = ResourceConfiguration( host=host, image=image, bundle=bundle, @@ -175,7 +175,7 @@ class Config_Software(WorkflowStep): def post(self, post_data, user): models = self.repo_get(self.repo.CONFIG_MODELS, {}) if "bundle" not in models: - models['bundle'] = ConfigBundle(owner=self.repo_get(self.repo.SESSION_USER)) + models['bundle'] = ResourceTemplate(owner=self.repo_get(self.repo.SESSION_USER)) confirm = self.repo_get(self.repo.CONFIRMATION, {}) if "configuration" not in confirm: diff --git a/src/workflow/workflow_manager.py b/src/workflow/workflow_manager.py index fda105e..e31e14c 100644 --- a/src/workflow/workflow_manager.py +++ b/src/workflow/workflow_manager.py @@ -16,9 +16,8 @@ from booking.models import Booking from workflow.workflow_factory import WorkflowFactory from workflow.models import Repository from resource_inventory.models import ( - GenericResourceBundle, - ConfigBundle, - HostConfiguration, + ResourceTemplate, + ResourceConfiguration, OPNFVConfig ) from workflow.forms import ManagerForm @@ -154,10 +153,10 @@ class SessionManager(): edit_object = Booking.objects.get(pk=target_id) self.prefill_booking(edit_object) elif workflow_type == 1: - edit_object = GenericResourceBundle.objects.get(pk=target_id) + edit_object = ResourceTemplate.objects.get(pk=target_id) self.prefill_resource(edit_object) elif workflow_type == 2: - edit_object = ConfigBundle.objects.get(pk=target_id) + edit_object = ResourceTemplate.objects.get(pk=target_id) self.prefill_config(edit_object) def prefill_booking(self, booking): @@ -213,7 +212,7 @@ class SessionManager(): models = self.active_workflow().repository.el.get(self.active_workflow().repository.CONFIG_MODELS, {}) models['bundle'] = config models['host_configs'] = [] - for host_conf in HostConfiguration.objects.filter(bundle=config): + for host_conf in ResourceConfiguration.objects.filter(bundle=config): models['host_configs'].append(host_conf) models['opnfv'] = OPNFVConfig.objects.filter(bundle=config).last() return models @@ -227,7 +226,7 @@ class SessionManager(): opnfv = OPNFVConfig.objects.filter(bundle=config).last() confirm['configuration']['installer'] = opnfv.installer.name confirm['configuration']['scenario'] = opnfv.scenario.name - for host_conf in HostConfiguration.objects.filter(bundle=config): + for host_conf in ResourceConfiguration.objects.filter(bundle=config): h = {"name": host_conf.host.resource.name, "image": host_conf.image.name, "role": host_conf.opnfvRole.name} confirm['configuration']['hosts'].append(h) return confirm -- cgit 1.2.3-korg From b360e0e417f787e0266268596d630b87e88283d1 Mon Sep 17 00:00:00 2001 From: Parker Berberian Date: Tue, 3 Mar 2020 12:30:36 -0500 Subject: Fixing and adding tests for the new resource models. Change-Id: I4dd0569411b415a3e8a8de43d4b99e927e5b7821 Signed-off-by: Parker Berberian --- src/booking/views.py | 6 +- src/dashboard/testing_utils.py | 209 ++++++++--------------------- src/dashboard/tests/test_views.py | 30 +++++ src/resource_inventory/resource_manager.py | 7 + 4 files changed, 98 insertions(+), 154 deletions(-) create mode 100644 src/dashboard/tests/test_views.py (limited to 'src/dashboard') diff --git a/src/booking/views.py b/src/booking/views.py index 39b24a7..daaf026 100644 --- a/src/booking/views.py +++ b/src/booking/views.py @@ -42,11 +42,11 @@ def quick_create(request): context = {} r_manager = ResourceManager.getInstance() - profiles = {} + templates = {} for lab in Lab.objects.all(): - profiles[str(lab)] = r_manager.getAvailableHostTypes(lab) + templates[str(lab)] = r_manager.getAvailableResourceTemplates(lab, request.user) - context['lab_profile_map'] = profiles + context['lab_profile_map'] = templates context['form'] = QuickBookingForm(default_user=request.user.username, user=request.user) diff --git a/src/dashboard/testing_utils.py b/src/dashboard/testing_utils.py index 0f52daa..01bb9c2 100644 --- a/src/dashboard/testing_utils.py +++ b/src/dashboard/testing_utils.py @@ -12,16 +12,17 @@ from django.core.files.base import ContentFile from django.utils import timezone import json -import re from datetime import timedelta -from dashboard.exceptions import InvalidHostnameException from booking.models import Booking from account.models import UserProfile, Lab, LabStatus, VlanManager, PublicNetwork from resource_inventory.models import ( - Host, - HostProfile, + ResourceTemplate, + ResourceProfile, + ResourceConfiguration, InterfaceProfile, + InterfaceConfiguration, + Server, DiskProfile, CpuProfile, Opsys, @@ -31,15 +32,6 @@ from resource_inventory.models import ( OPNFVRole, RamProfile, Network, - GenericResourceBundle, - GenericResource, - GenericHost, - ConfigBundle, - GenericInterface, - HostConfiguration, - OPNFVConfig, - NetworkConnection, - HostOPNFVConfig ) from resource_inventory.resource_manager import ResourceManager @@ -79,59 +71,22 @@ def make_booking(owner=None, start=timezone.now(), project="my_project", collaborators=[], topology={}, installer=None, scenario=None): - grb, host_set = make_grb(topology, owner, lab) - config_bundle, opnfv_bundle = make_config_bundle(grb, owner, topology, host_set, installer, scenario) - resource = ResourceManager.getInstance().convertResourceBundle(grb, config=config_bundle) + resource_template = make_resource_template() + resource = ResourceManager.getInstance().convertResourceBundle(resource_template) if not resource: raise Exception("Resource not created") return Booking.objects.create( resource=resource, - config_bundle=config_bundle, start=start, end=end, owner=owner, purpose=purpose, project=project, lab=lab, - opnfv_config=opnfv_bundle ) -def make_config_bundle(grb, owner, topology={}, host_set={}, - installer=None, scenario=None): - cb = ConfigBundle.objects.create( - owner=owner, - name="config bundle " + str(ConfigBundle.objects.count()), - description="cb generated by make_config_bundle() method", - bundle=grb - ) - - scen = scenario or Scenario.objects.first() or make_scenario() - inst = installer or Installer.objects.first() or make_installer([scen]) - - opnfv_config = OPNFVConfig.objects.create( - installer=inst, - scenario=scen, - bundle=cb - ) - - # generate host configurations based on topology and host set - for hostname, host_info in topology.items(): - host_config = HostConfiguration.objects.create( - host=host_set[hostname], - image=host_info["image"], - bundle=cb, - is_head_node=host_info['role'].name.lower() == "jumphost" - ) - HostOPNFVConfig.objects.create( - role=host_info["role"], - host_config=host_config, - opnfv_config=opnfv_config - ) - return cb, opnfv_config - - def make_network(name, lab, grb, public): network = Network(name=name, bundle=grb, is_public=public) if public: @@ -151,49 +106,33 @@ def make_network(name, lab, grb, public): return network -def make_grb(topology, owner, lab): - - grb = GenericResourceBundle.objects.create( - owner=owner, - lab=lab, - name="Generic ResourceBundle " + str(GenericResourceBundle.objects.count()), - description="grb generated by make_grb() method" - ) - - networks = {} - host_set = {} - - for hostname, info in topology.items(): - host_profile = info["type"] +def make_resource_template(owner=None, lab=None, name="Test Template"): + if owner is None: + owner = make_user(username="template_owner") + if lab is None: + lab = make_lab(name="template_lab") + rt = ResourceTemplate.objects.create(name=name, owner=owner, lab=lab, public=True) + config = make_resource_config(rt) + make_interface_config(config) + return rt - # need to construct host from hostname and type - generic_host = make_generic_host(grb, host_profile, hostname) - host_set[hostname] = generic_host - # set up networks - nets = info["nets"] - for interface_index, interface_profile in enumerate(host_profile.interfaceprofile.all()): - generic_interface = GenericInterface.objects.create(host=generic_host, profile=interface_profile) - netconfig = nets[interface_index] - for network_info in netconfig: - network_name = network_info["name"] - if network_name not in networks: - networks[network_name] = make_network(network_name, lab, grb, network_info['public']) +def make_resource_config(template, profile=None, image=None): + if profile is None: + profile = make_resource_profile(lab=template.lab) - generic_interface.connections.add(NetworkConnection.objects.create( - network=networks[network_name], - vlan_is_tagged=network_info["tagged"] - )) + if image is None: + image = make_image(profile) - return grb, host_set + return ResourceConfiguration.objects.create(profile=profile, image=image, template=template) -def make_generic_host(grb, host_profile, hostname): - if not re.match(r"(?=^.{1,253}$)(^([A-Za-z0-9-_]{1,62}\.)*[A-Za-z0-9-_]{1,63})$", hostname): - raise InvalidHostnameException("Hostname must comply to RFC 952 and all extensions") - gresource = GenericResource.objects.create(bundle=grb, name=hostname) +def make_interface_config(resource_config): + # lets just grab one of the iface profiles from the related host + iface_profile = resource_config.profile.interfaceprofile.all()[0] - return GenericHost.objects.create(resource=gresource, profile=host_profile) + # not adding any connections here + return InterfaceConfiguration.objects.create(profile=iface_profile, resource_config=resource_config) def make_user(is_superuser=False, username="testuser", @@ -267,80 +206,48 @@ resource_inventory instantiation section for permanent resources """ -def make_complete_host_profile(lab, name="test_hostprofile"): - host_profile = make_host_profile(lab, name=name) - make_disk_profile(host_profile, 500, name=name) - make_cpu_profile(host_profile) - make_interface_profile(host_profile, name=name) - make_ram_profile(host_profile) - - return host_profile - - -def make_host_profile(lab, host_type=0, name="test hostprofile"): - host_profile = HostProfile.objects.create( - host_type=host_type, +def make_resource_profile(lab, name="test_hostprofile"): + resource_profile = ResourceProfile.objects.create( name=name, - description='test hostprofile instance' + description='test resourceprofile instance' ) - host_profile.labs.add(lab) - - return host_profile - - -def make_ram_profile(host, channels=4, amount=256): - return RamProfile.objects.create( - host=host, - amount=amount, - channels=channels + resource_profile.labs.add(lab) + + RamProfile.objects.create(host=resource_profile, amount=8, channels=2) + CpuProfile.objects.create(cores=4, architecture="x86_64", cpus=1, host=resource_profile) + DiskProfile.objects.create( + name="test disk profile", + size=256, + media_type="SSD", + host=resource_profile ) - -def make_disk_profile(hostprofile, size=0, media_type="SSD", - name="test diskprofile", rotation=0, - interface="sata"): - return DiskProfile.objects.create( - name=name, - size=size, - media_type=media_type, - host=hostprofile, - rotation=rotation, - interface=interface + InterfaceProfile.objects.create( + host=resource_profile, + name="test interface profile", + speed=1000, + nic_type="pcie" ) + return resource_profile -def make_cpu_profile(hostprofile, - cores=4, - architecture="x86_64", - cpus=4,): - return CpuProfile.objects.create( - cores=cores, - architecture=architecture, - cpus=cpus, - host=hostprofile, - cflags='' - ) +def make_image(resource_profile, lab=None, lab_id="4", owner=None, os=None, + public=True, name="default image", description="default image"): + if lab is None: + lab = make_lab() -def make_interface_profile(hostprofile, - speed=1000, - name="test interface profile", - nic_type="pcie"): - return InterfaceProfile.objects.create( - host=hostprofile, - name=name, - speed=speed, - nic_type=nic_type - ) + if owner is None: + owner = make_user() + if os is None: + os = make_os() -def make_image(lab, lab_id, owner, os, host_profile, - public=True, name="default image", description="default image"): return Image.objects.create( from_lab=lab, lab_id=lab_id, os=os, - host_type=host_profile, + host_type=resource_profile, public=public, name=name, description=description @@ -369,10 +276,10 @@ def make_os(installers=None, name="test OS"): return os -def make_host(host_profile, lab, labid="test_host", name="test_host", - booked=False, working=True, config=None, template=None, - bundle=None, model="Model 1", vendor="ACME"): - return Host.objects.create( +def make_server(host_profile, lab, labid="test_host", name="test_host", + booked=False, working=True, config=None, template=None, + bundle=None, model="Model 1", vendor="ACME"): + return Server.objects.create( lab=lab, profile=host_profile, name=name, diff --git a/src/dashboard/tests/test_views.py b/src/dashboard/tests/test_views.py new file mode 100644 index 0000000..f2d5490 --- /dev/null +++ b/src/dashboard/tests/test_views.py @@ -0,0 +1,30 @@ +############################################################################## +# Copyright (c) 2020 Parker Berberian, Sawyer Bergeron, and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +from django.test import TestCase, Client +from dashboard.testing_utils import make_lab + + +class DashboardViewTestCase(TestCase): + @classmethod + def setUpTestData(cls): + make_lab(name="TestLab") + cls.client = Client() + + def test_landing_view_anon(self): + response = self.client.get('/') + self.assertEqual(response.status_code, 200) + + def test_lab_list_view(self): + response = self.client.get('/lab/') + self.assertEqual(response.status_code, 200) + + def test_lab_detail_view(self): + response = self.client.get('/lab/TestLab/') + self.assertEqual(response.status_code, 200) diff --git a/src/resource_inventory/resource_manager.py b/src/resource_inventory/resource_manager.py index e14218b..c8b2b05 100644 --- a/src/resource_inventory/resource_manager.py +++ b/src/resource_inventory/resource_manager.py @@ -7,11 +7,13 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## import re +from django.db.models import Q from dashboard.exceptions import ResourceAvailabilityException from resource_inventory.models import ( ResourceBundle, + ResourceTemplate, Network, Vlan, PhysicalNetwork, @@ -31,6 +33,11 @@ class ResourceManager: ResourceManager.instance = ResourceManager() return ResourceManager.instance + def getAvailableResourceTemplates(self, lab, user): + templates = ResourceTemplate.objects.filter(lab=lab) + templates.filter(Q(owner=user) | Q(public=True)) + return templates + def templateIsReservable(self, resource_template): """ Check if the required resources to reserve this template is available. -- cgit 1.2.3-korg From 064f145f218385a6401fa6be2ccbbc462e915c26 Mon Sep 17 00:00:00 2001 From: Adam Hassick Date: Mon, 16 Mar 2020 11:20:03 -0400 Subject: Test resource templates now use the same lab as the image generated alongside it. Signed-off-by: Adam Hassick Change-Id: I22ce80b4d162dd31dc3bd2ff2bd7ee30d474a0dd --- src/dashboard/testing_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/dashboard') diff --git a/src/dashboard/testing_utils.py b/src/dashboard/testing_utils.py index 01bb9c2..506e998 100644 --- a/src/dashboard/testing_utils.py +++ b/src/dashboard/testing_utils.py @@ -122,7 +122,7 @@ def make_resource_config(template, profile=None, image=None): profile = make_resource_profile(lab=template.lab) if image is None: - image = make_image(profile) + image = make_image(profile, lab=template.lab) return ResourceConfiguration.objects.create(profile=profile, image=image, template=template) -- cgit 1.2.3-korg