summaryrefslogtreecommitdiffstats
path: root/dashboard/src/workflow
diff options
context:
space:
mode:
authorSawyer Bergeron <sbergeron@iol.unh.edu>2019-04-09 16:30:57 -0400
committerParker Berberian <pberberian@iol.unh.edu>2019-05-03 11:48:22 -0400
commit8864dae63b9512835862aabbe7f288fbe3c661e0 (patch)
tree9a85c3f2759e2e6e6dd375b7a17c7d2e8331f05c /dashboard/src/workflow
parentd26781393ba3827b698e89573ace06ace4240f95 (diff)
Implement OPNFV workflow
This is a counterpart to an update to network models, and allows for configuring baremetal OPNFV and Openstack deploys Change-Id: I0185dbfa6c9105d7e63a7e7d7dd1f5cf228a8877 Signed-off-by: Sawyer Bergeron <sbergeron@iol.unh.edu> Signed-off-by: Parker Berberian <pberberian@iol.unh.edu>
Diffstat (limited to 'dashboard/src/workflow')
-rw-r--r--dashboard/src/workflow/forms.py53
-rw-r--r--dashboard/src/workflow/models.py61
-rw-r--r--dashboard/src/workflow/opnfv_workflow.py327
-rw-r--r--dashboard/src/workflow/snapshot_workflow.py8
-rw-r--r--dashboard/src/workflow/sw_bundle_workflow.py193
-rw-r--r--dashboard/src/workflow/workflow_factory.py15
6 files changed, 522 insertions, 135 deletions
diff --git a/dashboard/src/workflow/forms.py b/dashboard/src/workflow/forms.py
index b40713f..6d26b5c 100644
--- a/dashboard/src/workflow/forms.py
+++ b/dashboard/src/workflow/forms.py
@@ -20,9 +20,8 @@ from resource_inventory.models import (
GenericResourceBundle,
ConfigBundle,
OPNFVRole,
- Image,
Installer,
- Scenario
+ Scenario,
)
@@ -125,6 +124,7 @@ class SWConfigSelectorForm(forms.Form):
bundle = None
edit = False
resource = None
+ user = None
if "chosen_software" in kwargs:
chosen_software = kwargs.pop("chosen_software")
@@ -134,18 +134,25 @@ class SWConfigSelectorForm(forms.Form):
edit = kwargs.pop("edit")
if "resource" in kwargs:
resource = kwargs.pop("resource")
+ if "user" in kwargs:
+ user = kwargs.pop("user")
super(SWConfigSelectorForm, self).__init__(*args, **kwargs)
- attrs = self.build_search_widget_attrs(chosen_software, bundle, edit, resource)
+ attrs = self.build_search_widget_attrs(chosen_software, bundle, edit, resource, user)
self.fields['software_bundle'] = forms.CharField(
widget=SearchableSelectMultipleWidget(attrs=attrs)
)
- def build_search_widget_attrs(self, chosen, bundle, edit, resource):
+ def build_search_widget_attrs(self, chosen, bundle, edit, resource, user):
configs = {}
queryset = ConfigBundle.objects.select_related('owner').all()
if resource:
+ if user is None:
+ user = resource.owner
queryset = queryset.filter(bundle=resource)
+ if user:
+ queryset = queryset.filter(owner=user)
+
for config in queryset:
displayable = {}
displayable['small_name'] = config.name
@@ -424,20 +431,14 @@ class NetworkConfigurationForm(forms.Form):
class HostSoftwareDefinitionForm(forms.Form):
- fields = ["host_name", "role", "image"]
host_name = forms.CharField(max_length=200, disabled=True, required=False)
- role = forms.ModelChoiceField(queryset=OPNFVRole.objects.all())
- image = forms.ModelChoiceField(queryset=Image.objects.all())
-
+ headnode = forms.BooleanField(required=False, widget=forms.HiddenInput)
-class SoftwareConfigurationForm(forms.Form):
-
- name = forms.CharField(max_length=200)
- description = forms.CharField(widget=forms.Textarea)
- opnfv = forms.BooleanField(disabled=True, required=False)
- installer = forms.ModelChoiceField(queryset=Installer.objects.all(), disabled=True, required=False)
- scenario = forms.ModelChoiceField(queryset=Scenario.objects.all(), disabled=True, required=False)
+ def __init__(self, *args, **kwargs):
+ imageQS = kwargs.pop("imageQS")
+ super(HostSoftwareDefinitionForm, self).__init__(*args, **kwargs)
+ self.fields['image'] = forms.ModelChoiceField(queryset=imageQS)
class WorkflowSelectionForm(forms.Form):
@@ -461,7 +462,7 @@ class SnapshotHostSelectForm(forms.Form):
host = forms.CharField()
-class SnapshotMetaForm(forms.Form):
+class BasicMetaForm(forms.Form):
name = forms.CharField()
description = forms.CharField(widget=forms.Textarea)
@@ -475,3 +476,23 @@ class ConfirmationForm(forms.Form):
(False, "Cancel")
)
)
+
+
+class OPNFVSelectionForm(forms.Form):
+ installer = forms.ModelChoiceField(queryset=Installer.objects.all(), required=True)
+ scenario = forms.ModelChoiceField(queryset=Scenario.objects.all(), required=True)
+
+
+class OPNFVNetworkRoleForm(forms.Form):
+ role = forms.CharField(max_length=200, disabled=True, required=False)
+
+ def __init__(self, *args, config_bundle, **kwargs):
+ super(OPNFVNetworkRoleForm, self).__init__(*args, **kwargs)
+ self.fields['network'] = forms.ModelChoiceField(
+ queryset=config_bundle.bundle.networks.all()
+ )
+
+
+class OPNFVHostRoleForm(forms.Form):
+ host_name = forms.CharField(max_length=200, disabled=True, required=False)
+ role = forms.ModelChoiceField(queryset=OPNFVRole.objects.all().order_by("name").distinct("name"))
diff --git a/dashboard/src/workflow/models.py b/dashboard/src/workflow/models.py
index 4ebb042..bf5751d 100644
--- a/dashboard/src/workflow/models.py
+++ b/dashboard/src/workflow/models.py
@@ -19,7 +19,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, GenericInterface
+from resource_inventory.models import Image, GenericInterface, OPNFVConfig, HostOPNFVConfig, NetworkRole
from resource_inventory.resource_manager import ResourceManager
from resource_inventory.pdf_templater import PDFTemplater
from notifier.manager import NotificationHandler
@@ -259,6 +259,7 @@ class Repository():
CONFIRMATION = "confirmation"
SELECTED_GRESOURCE_BUNDLE = "selected generic bundle pk"
SELECTED_CONFIG_BUNDLE = "selected config bundle pk"
+ SELECTED_OPNFV_CONFIG = "selected opnfv deployment config"
GRESOURCE_BUNDLE_MODELS = "generic_resource_bundle_models"
GRESOURCE_BUNDLE_INFO = "generic_resource_bundle_info"
BOOKING = "booking"
@@ -268,6 +269,7 @@ class Repository():
SWCONF_HOSTS = "swconf_hosts"
BOOKING_MODELS = "booking models"
CONFIG_MODELS = "configuration bundle models"
+ OPNFV_MODELS = "opnfv configuration models"
SESSION_USER = "session owner user account"
VALIDATED_MODEL_GRB = "valid grb config model instance in db"
VALIDATED_MODEL_CONFIG = "valid config model instance in db"
@@ -339,6 +341,14 @@ class Repository():
self.el[self.RESULT_KEY] = self.SELECTED_CONFIG_BUNDLE
return
+ if self.OPNFV_MODELS in self.el:
+ errors = self.make_opnfv_config()
+ if errors:
+ return errors
+ else:
+ self.el[self.HAS_RESULT] = True
+ self.el[self.RESULT_KEY] = self.SELECTED_OPNFV_CONFIG
+
if self.BOOKING_MODELS in self.el:
errors = self.make_booking()
if errors:
@@ -536,7 +546,7 @@ class Repository():
booking.collaborators.add(collaborator)
try:
- booking.pdf = PDFTemplater.makePDF(booking.resource)
+ booking.pdf = PDFTemplater.makePDF(booking)
booking.save()
except Exception as e:
return "BOOK, failed to create Pod Desriptor File: " + str(e)
@@ -551,6 +561,53 @@ class Repository():
except Exception as e:
return "BOOK, saving booking generated exception: " + str(e) + " CODE:0x0016"
+ def make_opnfv_config(self):
+ opnfv_models = self.el[self.OPNFV_MODELS]
+ config_bundle = opnfv_models['configbundle']
+ if not config_bundle:
+ return "No Configuration bundle selected"
+ info = opnfv_models.get("meta", {})
+ name = info.get("name", False)
+ desc = info.get("description", False)
+ if not (name and desc):
+ return "No name or description given"
+ installer = opnfv_models['installer_chosen']
+ if not installer:
+ return "No OPNFV Installer chosen"
+ scenario = opnfv_models['scenario_chosen']
+ if not scenario:
+ return "No OPNFV Scenario chosen"
+
+ opnfv_config = OPNFVConfig.objects.create(
+ bundle=config_bundle,
+ name=name,
+ description=desc,
+ installer=installer,
+ scenario=scenario
+ )
+
+ network_roles = opnfv_models['network_roles']
+ for net_role in network_roles:
+ opnfv_config.networks.add(
+ NetworkRole.objects.create(
+ name=net_role['role'],
+ network=net_role['network']
+ )
+ )
+
+ host_roles = opnfv_models['host_roles']
+ for host_role in host_roles:
+ config = config_bundle.hostConfigurations.get(
+ host__resource__name=host_role['host_name']
+ )
+ HostOPNFVConfig.objects.create(
+ role=host_role['role'],
+ host_config=config,
+ opnfv_config=opnfv_config
+ )
+
+ self.el[self.RESULT] = opnfv_config
+
def __init__(self):
self.el = {}
self.el[self.CONFIRMATION] = {}
diff --git a/dashboard/src/workflow/opnfv_workflow.py b/dashboard/src/workflow/opnfv_workflow.py
new file mode 100644
index 0000000..26e1d7c
--- /dev/null
+++ b/dashboard/src/workflow/opnfv_workflow.py
@@ -0,0 +1,327 @@
+##############################################################################
+# Copyright (c) 2018 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.forms import formset_factory
+from django.contrib import messages
+
+import json
+
+from workflow.models import WorkflowStep
+from resource_inventory.models import ConfigBundle, OPNFV_SETTINGS
+from workflow.forms import OPNFVSelectionForm, OPNFVNetworkRoleForm, OPNFVHostRoleForm, SWConfigSelectorForm, BasicMetaForm
+
+
+class OPNFV_Resource_Select(WorkflowStep):
+ template = 'booking/steps/swconfig_select.html'
+ title = "Select Software Configuration"
+ description = "Choose the software and related configurations you want to use to configure OPNFV"
+ short_title = "software configuration"
+ modified_key = "configbundle_step"
+
+ def update_confirmation(self):
+ confirm = self.repo_get(self.repo.CONFIRMATION, {})
+ config_bundle = self.repo_get(self.repo.OPNFV_MODELS, {}).get("configbundle")
+ if not config_bundle:
+ return
+ confirm['software bundle'] = config_bundle.name
+ confirm['hardware POD'] = config_bundle.bundle.name
+ self.repo_put(self.repo.CONFIRMATION, confirm)
+
+ def post_render(self, request):
+ models = self.repo_get(self.repo.OPNFV_MODELS, {})
+ form = SWConfigSelectorForm(request.POST)
+ if form.is_valid():
+ bundle_json = form.cleaned_data['software_bundle']
+ bundle_json = bundle_json[2:-2] # Stupid django string bug
+ if not bundle_json:
+ self.metastep.set_invalid("Please select a valid config")
+ return self.render(request)
+ bundle_json = json.loads(bundle_json)
+ if len(bundle_json) < 1:
+ self.metastep.set_invalid("Please select a valid config")
+ return self.render(request)
+ bundle = None
+ id = int(bundle_json[0]['id'])
+ bundle = ConfigBundle.objects.get(id=id)
+
+ models['configbundle'] = bundle
+ self.repo_put(self.repo.OPNFV_MODELS, models)
+ self.metastep.set_valid("Step Completed")
+ messages.add_message(request, messages.SUCCESS, 'Form Validated Successfully', fail_silently=True)
+ self.update_confirmation()
+ else:
+ self.metastep.set_invalid("Please select or create a valid config")
+ messages.add_message(request, messages.ERROR, "Form Didn't Validate", fail_silently=True)
+
+ return self.render(request)
+
+ def get_context(self):
+ context = super(OPNFV_Resource_Select, self).get_context()
+ default = []
+ user = self.repo_get(self.repo.SESSION_USER)
+
+ context['form'] = SWConfigSelectorForm(chosen_software=default, bundle=None, edit=True, resource=None, user=user)
+ return context
+
+
+class Pick_Installer(WorkflowStep):
+ template = 'config_bundle/steps/pick_installer.html'
+ title = 'Pick OPNFV Installer'
+ description = 'Choose which OPNFV installer to use'
+ short_title = "opnfv installer"
+ modified_key = "installer_step"
+
+ def update_confirmation(self):
+ confirm = self.repo_get(self.repo.CONFIRMATION, {})
+ models = self.repo_get(self.repo.OPNFV_MODELS, {})
+ installer = models.get("installer_chosen")
+ scenario = models.get("scenario_chosen")
+ if not (installer and scenario):
+ return
+ confirm['installer'] = installer.name
+ confirm['scenario'] = scenario.name
+ self.repo_put(self.repo.CONFIRMATION, confirm)
+
+ def get_context(self):
+ context = super(Pick_Installer, self).get_context()
+
+ models = self.repo_get(self.repo.OPNFV_MODELS, None)
+ initial = {
+ "installer": models.get("installer_chosen"),
+ "scenario": models.get("scenario_chosen")
+ }
+
+ context["form"] = OPNFVSelectionForm(initial=initial)
+ return context
+
+ def post_render(self, request):
+ form = OPNFVSelectionForm(request.POST)
+ if form.is_valid():
+ installer = form.cleaned_data['installer']
+ scenario = form.cleaned_data['scenario']
+ models = self.repo_get(self.repo.OPNFV_MODELS, {})
+ models['installer_chosen'] = installer
+ models['scenario_chosen'] = scenario
+ self.repo_put(self.repo.OPNFV_MODELS, models)
+ self.update_confirmation()
+ self.metastep.set_valid("Step Completed")
+ else:
+ self.metastep.set_invalid("Please select an Installer and Scenario")
+
+ return self.render(request)
+
+
+class Assign_Network_Roles(WorkflowStep):
+ template = 'config_bundle/steps/assign_network_roles.html'
+ title = 'Pick Network Roles'
+ description = 'Choose what role each network should get'
+ short_title = "network roles"
+ modified_key = "net_roles_step"
+
+ """
+ to do initial filling, repo should have a "network_roles" array with the following structure for each element:
+ {
+ "role": <NetworkRole object ref>,
+ "network": <Network object ref>
+ }
+ """
+ def create_netformset(self, roles, config_bundle, data=None):
+ roles_initial = []
+ set_roles = self.repo_get(self.repo.OPNFV_MODELS, {}).get("network_roles")
+ if set_roles:
+ roles_initial = set_roles
+ else:
+ for role in OPNFV_SETTINGS.NETWORK_ROLES:
+ roles_initial.append({"role": role})
+
+ Formset = formset_factory(OPNFVNetworkRoleForm, extra=0)
+ kwargs = {
+ "initial": roles_initial,
+ "form_kwargs": {"config_bundle": config_bundle}
+ }
+ formset = None
+ if data:
+ formset = Formset(data, **kwargs)
+ else:
+ formset = Formset(**kwargs)
+ return formset
+
+ def get_context(self):
+ context = super(Assign_Network_Roles, self).get_context()
+ config_bundle = self.repo_get(self.repo.OPNFV_MODELS, {}).get("configbundle")
+ if config_bundle is None:
+ context["unavailable"] = True
+ return context
+
+ roles = OPNFV_SETTINGS.NETWORK_ROLES
+ formset = self.create_netformset(roles, config_bundle)
+ context['formset'] = formset
+
+ return context
+
+ def update_confirmation(self):
+ confirm = self.repo_get(self.repo.CONFIRMATION, {})
+ models = self.repo_get(self.repo.OPNFV_MODELS, {})
+ roles = models.get("network_roles")
+ if not roles:
+ return
+ confirm['network roles'] = {}
+ for role in roles:
+ confirm['network roles'][role['role']] = role['network'].name
+ self.repo_put(self.repo.CONFIRMATION, confirm)
+
+ def post_render(self, request):
+ models = self.repo_get(self.repo.OPNFV_MODELS, {})
+ config_bundle = models.get("configbundle")
+ roles = OPNFV_SETTINGS.NETWORK_ROLES
+ net_role_formset = self.create_netformset(roles, config_bundle, data=request.POST)
+ if net_role_formset.is_valid():
+ results = []
+ for form in net_role_formset:
+ results.append({
+ "role": form.cleaned_data['role'],
+ "network": form.cleaned_data['network']
+ })
+ models['network_roles'] = results
+ self.metastep.set_valid("Completed")
+ self.repo_put(self.repo.OPNFV_MODELS, models)
+ self.update_confirmation()
+ else:
+ self.metastep.set_invalid("Please complete all fields")
+ return self.render(request)
+
+
+class Assign_Host_Roles(WorkflowStep): # taken verbatim from Define_Software in sw workflow, merge the two?
+ template = 'config_bundle/steps/assign_host_roles.html'
+ title = 'Pick Host Roles'
+ description = "Choose the role each machine will have in your OPNFV pod"
+ short_title = "host roles"
+ modified_key = "host_roles_step"
+
+ def create_host_role_formset(self, hostlist=[], data=None):
+ models = self.repo_get(self.repo.OPNFV_MODELS, {})
+ host_roles = models.get("host_roles", [])
+ if not host_roles:
+ for host in hostlist:
+ initial = {"host_name": host.resource.name}
+ host_roles.append(initial)
+ models['host_roles'] = host_roles
+ self.repo_put(self.repo.OPNFV_MODELS, models)
+
+ HostFormset = formset_factory(OPNFVHostRoleForm, extra=0)
+
+ kwargs = {"initial": host_roles}
+ formset = None
+ if data:
+ formset = HostFormset(data, **kwargs)
+ else:
+ formset = HostFormset(**kwargs)
+
+ return formset
+
+ def get_context(self):
+ context = super(Assign_Host_Roles, self).get_context()
+ models = self.repo_get(self.repo.OPNFV_MODELS, {})
+ config = models.get("configbundle")
+ if config is None:
+ context['error'] = "Please select a Configuration on the first step"
+
+ formset = self.create_host_role_formset(hostlist=config.bundle.getHosts())
+ context['formset'] = formset
+
+ return context
+
+ def get_host_role_mapping(self, host_roles, hostname):
+ for obj in host_roles:
+ if hostname == obj['host_name']:
+ return obj
+ return None
+
+ def update_confirmation(self):
+ confirm = self.repo_get(self.repo.CONFIRMATION, {})
+ models = self.repo_get(self.repo.OPNFV_MODELS, {})
+ roles = models.get("host_roles")
+ if not roles:
+ return
+ confirm['host roles'] = {}
+ for role in roles:
+ confirm['host roles'][role['host_name']] = role['role'].name
+ self.repo_put(self.repo.CONFIRMATION, confirm)
+
+ def post_render(self, request):
+ formset = self.create_host_role_formset(data=request.POST)
+
+ models = self.repo_get(self.repo.OPNFV_MODELS, {})
+ host_roles = models.get("host_roles", [])
+
+ has_jumphost = False
+ if formset.is_valid():
+ for form in formset:
+ hostname = form.cleaned_data['host_name']
+ role = form.cleaned_data['role']
+ mapping = self.get_host_role_mapping(host_roles, hostname)
+ mapping['role'] = role
+ if "jumphost" in role.name.lower():
+ has_jumphost = True
+
+ models['host_roles'] = host_roles
+ self.repo_put(self.repo.OPNFV_MODELS, models)
+ self.update_confirmation()
+
+ if not has_jumphost:
+ self.metastep.set_invalid('Must have at least one "Jumphost" per POD')
+ else:
+ self.metastep.set_valid("Completed")
+ else:
+ self.metastep.set_invalid("Please complete all fields")
+
+ return self.render(request)
+
+
+class MetaInfo(WorkflowStep):
+ template = 'config_bundle/steps/config_software.html'
+ title = "Other Info"
+ description = "Give your software config a name, description, and other stuff"
+ short_title = "config info"
+
+ def get_context(self):
+ context = super(MetaInfo, self).get_context()
+
+ initial = self.repo_get(self.repo.OPNFV_MODELS, {}).get("meta", {})
+ context["form"] = BasicMetaForm(initial=initial)
+ return context
+
+ def update_confirmation(self):
+ confirm = self.repo_get(self.repo.CONFIRMATION, {})
+ models = self.repo_get(self.repo.OPNFV_MODELS, {})
+ meta = models.get("meta")
+ if not meta:
+ return
+ confirm['name'] = meta['name']
+ confirm['description'] = meta['description']
+ self.repo_put(self.repo.CONFIRMATION, confirm)
+
+ def post_render(self, request):
+ models = self.repo_get(self.repo.OPNFV_MODELS, {})
+ info = models.get("meta", {})
+
+ form = BasicMetaForm(request.POST)
+ if form.is_valid():
+ info['name'] = form.cleaned_data['name']
+ info['description'] = form.cleaned_data['description']
+ models['meta'] = info
+ self.repo_put(self.repo.OPNFV_MODELS, models)
+ self.update_confirmation()
+ self.metastep.set_valid("Complete")
+ else:
+ self.metastep.set_invalid("Please correct the errors shown below")
+
+ self.repo_put(self.repo.OPNFV_MODELS, models)
+ return self.render(request)
diff --git a/dashboard/src/workflow/snapshot_workflow.py b/dashboard/src/workflow/snapshot_workflow.py
index 002aee5..34ac3a5 100644
--- a/dashboard/src/workflow/snapshot_workflow.py
+++ b/dashboard/src/workflow/snapshot_workflow.py
@@ -14,7 +14,7 @@ import json
from booking.models import Booking
from resource_inventory.models import Host, Image
from workflow.models import WorkflowStep
-from workflow.forms import SnapshotMetaForm, SnapshotHostSelectForm
+from workflow.forms import BasicMetaForm, SnapshotHostSelectForm
class Select_Host_Step(WorkflowStep):
@@ -91,14 +91,14 @@ class Image_Meta_Step(WorkflowStep):
desc = self.repo_get(self.repo.SNAPSHOT_DESC, False)
form = None
if name and desc:
- form = SnapshotMetaForm(initial={"name": name, "description": desc})
+ form = BasicMetaForm(initial={"name": name, "description": desc})
else:
- form = SnapshotMetaForm()
+ form = BasicMetaForm()
context['form'] = form
return context
def post_render(self, request):
- form = SnapshotMetaForm(request.POST)
+ form = BasicMetaForm(request.POST)
if form.is_valid():
name = form.cleaned_data['name']
self.repo_put(self.repo.SNAPSHOT_NAME, name)
diff --git a/dashboard/src/workflow/sw_bundle_workflow.py b/dashboard/src/workflow/sw_bundle_workflow.py
index fd41018..a6a7464 100644
--- a/dashboard/src/workflow/sw_bundle_workflow.py
+++ b/dashboard/src/workflow/sw_bundle_workflow.py
@@ -11,9 +11,9 @@
from django.forms import formset_factory
from workflow.models import WorkflowStep
-from workflow.forms import SoftwareConfigurationForm, HostSoftwareDefinitionForm
+from workflow.forms import BasicMetaForm, HostSoftwareDefinitionForm
from workflow.booking_workflow import Resource_Select
-from resource_inventory.models import Image, GenericHost, ConfigBundle, HostConfiguration, Installer, OPNFVConfig
+from resource_inventory.models import Image, GenericHost, ConfigBundle, HostConfiguration
# resource selection step is reused from Booking workflow
@@ -39,48 +39,57 @@ class Define_Software(WorkflowStep):
description = "Choose the opnfv and image of your machines"
short_title = "host config"
- def create_hostformset(self, hostlist):
+ def build_filter_data(self, hosts_data):
+ """
+ returns a 2D array of images to exclude
+ based on the ordering of the passed
+ hosts_data
+ """
+ filter_data = []
+ 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'])
+ 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)
+ excluded_images = wrong_owner | wrong_host | wrong_lab
+ filter_data.append([])
+ for image in excluded_images:
+ filter_data[i].append(image.pk)
+ return filter_data
+
+ def create_hostformset(self, hostlist, data=None):
hosts_initial = []
host_configs = self.repo_get(self.repo.CONFIG_MODELS, {}).get("host_configs", False)
if host_configs:
for config in host_configs:
- host_initial = {'host_id': config.host.id, 'host_name': config.host.resource.name}
- host_initial['role'] = config.opnfvRole
- host_initial['image'] = config.image
- hosts_initial.append(host_initial)
-
+ hosts_initial.append({
+ 'host_id': config.host.id,
+ 'host_name': config.host.resource.name,
+ 'headnode': config.is_head_node,
+ 'image': config.image
+ })
else:
for host in hostlist:
- host_initial = {'host_id': host.id, 'host_name': host.resource.name}
-
- hosts_initial.append(host_initial)
+ hosts_initial.append({
+ 'host_id': host.id,
+ 'host_name': host.resource.name
+ })
HostFormset = formset_factory(HostSoftwareDefinitionForm, extra=0)
- host_formset = HostFormset(initial=hosts_initial)
+ filter_data = self.build_filter_data(hosts_initial)
- filter_data = {}
- user = self.repo_get(self.repo.SESSION_USER)
- i = 0
- for host_data in hosts_initial:
- host_profile = None
- try:
- host = GenericHost.objects.get(pk=host_data['host_id'])
- host_profile = host.profile
- except Exception:
- for host in hostlist:
- if host.resource.name == host_data['host_name']:
- host_profile = host.profile
- break
- excluded_images = Image.objects.exclude(owner=user).exclude(public=True)
- excluded_images = excluded_images | Image.objects.exclude(host_type=host_profile)
- lab = self.repo_get(self.repo.SELECTED_GRESOURCE_BUNDLE).lab
- excluded_images = excluded_images | Image.objects.exclude(from_lab=lab)
- filter_data["id_form-" + str(i) + "-image"] = []
- for image in excluded_images:
- filter_data["id_form-" + str(i) + "-image"].append(image.name)
- i += 1
+ class SpecialHostFormset(HostFormset):
+ def get_form_kwargs(self, index):
+ kwargs = super(SpecialHostFormset, self).get_form_kwargs(index)
+ if index is not None:
+ kwargs['imageQS'] = Image.objects.exclude(pk__in=filter_data[index])
+ return kwargs
- return host_formset, filter_data
+ if data:
+ return SpecialHostFormset(data, initial=hosts_initial)
+ return SpecialHostFormset(initial=hosts_initial)
def get_host_list(self, grb=None):
if grb is None:
@@ -99,9 +108,9 @@ class Define_Software(WorkflowStep):
if grb:
context["grb"] = grb
- formset, filter_data = self.create_hostformset(self.get_host_list(grb))
+ formset = self.create_hostformset(self.get_host_list(grb))
context["formset"] = formset
- context["filter_data"] = filter_data
+ context['headnode'] = self.repo_get(self.repo.CONFIG_MODELS, {}).get("headnode_index", 1)
else:
context["error"] = "Please select a resource first"
self.metastep.set_invalid("Step requires information that is not yet provided by previous step")
@@ -115,47 +124,35 @@ class Define_Software(WorkflowStep):
confirm = self.repo_get(self.repo.CONFIRMATION, {})
- HostFormset = formset_factory(HostSoftwareDefinitionForm, extra=0)
- formset = HostFormset(request.POST)
hosts = self.get_host_list()
- has_jumphost = False
+ models['headnode_index'] = request.POST.get("headnode", 1)
+ formset = self.create_hostformset(hosts, data=request.POST)
+ has_headnode = False
if formset.is_valid():
models['host_configs'] = []
- i = 0
confirm_hosts = []
- for form in formset:
+ for i, form in enumerate(formset):
host = hosts[i]
- i += 1
image = form.cleaned_data['image']
- # checks image compatability
- grb = self.repo_get(self.repo.SELECTED_GRESOURCE_BUNDLE)
- lab = None
- if grb:
- lab = grb.lab
- try:
- owner = self.repo_get(self.repo.SESSION_USER)
- q = Image.objects.filter(owner=owner) | Image.objects.filter(public=True)
- q.filter(host_type=host.profile)
- q.filter(from_lab=lab)
- q.get(id=image.id) # will throw exception if image is not in q
- except Exception:
- self.metastep.set_invalid("Image " + image.name + " is not compatible with host " + host.resource.name)
- role = form.cleaned_data['role']
- if "jumphost" in role.name.lower():
- has_jumphost = True
+ headnode = form.cleaned_data['headnode']
+ if headnode:
+ has_headnode = True
bundle = models['bundle']
hostConfig = HostConfiguration(
host=host,
image=image,
bundle=bundle,
- opnfvRole=role
+ is_head_node=headnode
)
models['host_configs'].append(hostConfig)
- confirm_host = {"name": host.resource.name, "image": image.name, "role": role.name}
- confirm_hosts.append(confirm_host)
-
- if not has_jumphost:
- self.metastep.set_invalid('Must have at least one "Jumphost" per POD')
+ confirm_hosts.append({
+ "name": host.resource.name,
+ "image": image.name,
+ "headnode": headnode
+ })
+
+ if not has_headnode:
+ self.metastep.set_invalid('Must have one "Headnode" per POD')
return self.render(request)
self.repo_put(self.repo.CONFIG_MODELS, models)
@@ -172,8 +169,6 @@ class Define_Software(WorkflowStep):
class Config_Software(WorkflowStep):
template = 'config_bundle/steps/config_software.html'
- form = SoftwareConfigurationForm
- context = {'workspace_form': form}
title = "Other Info"
description = "Give your software config a name, description, and other stuff"
short_title = "config info"
@@ -187,58 +182,30 @@ class Config_Software(WorkflowStep):
if bundle:
initial['name'] = bundle.name
initial['description'] = bundle.description
- opnfv = models.get("opnfv", False)
- if opnfv:
- initial['installer'] = opnfv.installer
- initial['scenario'] = opnfv.scenario
- else:
- initial['opnfv'] = False
- supported = {}
- for installer in Installer.objects.all():
- supported[str(installer)] = []
- for scenario in installer.sup_scenarios.all():
- supported[str(installer)].append(str(scenario))
-
- context["form"] = SoftwareConfigurationForm(initial=initial)
- context['supported'] = supported
-
+ context["form"] = BasicMetaForm(initial=initial)
return context
def post_render(self, request):
- try:
- 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 = self.repo_get(self.repo.CONFIG_MODELS, {})
+ if "bundle" not in models:
+ models['bundle'] = ConfigBundle(owner=self.repo_get(self.repo.SESSION_USER))
- confirm = self.repo_get(self.repo.CONFIRMATION, {})
- if "configuration" not in confirm:
- confirm['configuration'] = {}
+ confirm = self.repo_get(self.repo.CONFIRMATION, {})
+ if "configuration" not in confirm:
+ confirm['configuration'] = {}
- form = self.form(request.POST)
- if form.is_valid():
- models['bundle'].name = form.cleaned_data['name']
- models['bundle'].description = form.cleaned_data['description']
- if form.cleaned_data['opnfv']:
- installer = form.cleaned_data['installer']
- scenario = form.cleaned_data['scenario']
- opnfv = OPNFVConfig(
- bundle=models['bundle'],
- installer=installer,
- scenario=scenario
- )
- models['opnfv'] = opnfv
- confirm['configuration']['installer'] = form.cleaned_data['installer'].name
- confirm['configuration']['scenario'] = form.cleaned_data['scenario'].name
-
- confirm['configuration']['name'] = form.cleaned_data['name']
- confirm['configuration']['description'] = form.cleaned_data['description']
- self.metastep.set_valid("Complete")
- else:
- self.metastep.set_invalid("Please correct the errors shown below")
+ form = BasicMetaForm(request.POST)
+ if form.is_valid():
+ models['bundle'].name = form.cleaned_data['name']
+ models['bundle'].description = form.cleaned_data['description']
- self.repo_put(self.repo.CONFIG_MODELS, models)
- self.repo_put(self.repo.CONFIRMATION, confirm)
+ confirm['configuration']['name'] = form.cleaned_data['name']
+ confirm['configuration']['description'] = form.cleaned_data['description']
+ self.metastep.set_valid("Complete")
+ else:
+ self.metastep.set_invalid("Please correct the errors shown below")
+
+ self.repo_put(self.repo.CONFIG_MODELS, models)
+ self.repo_put(self.repo.CONFIRMATION, confirm)
- except Exception:
- pass
return self.render(request)
diff --git a/dashboard/src/workflow/workflow_factory.py b/dashboard/src/workflow/workflow_factory.py
index f5e2ad1..db2bba1 100644
--- a/dashboard/src/workflow/workflow_factory.py
+++ b/dashboard/src/workflow/workflow_factory.py
@@ -12,6 +12,7 @@ from workflow.booking_workflow import Booking_Resource_Select, SWConfig_Select,
from workflow.resource_bundle_workflow import Define_Hardware, Define_Nets, Resource_Meta_Info
from workflow.sw_bundle_workflow import Config_Software, Define_Software, SWConf_Resource_Select
from workflow.snapshot_workflow import Select_Host_Step, Image_Meta_Step
+from workflow.opnfv_workflow import Pick_Installer, Assign_Network_Roles, Assign_Host_Roles, OPNFV_Resource_Select, MetaInfo
from workflow.models import Confirmation_Step
import uuid
@@ -36,6 +37,11 @@ class ConfigMetaWorkflow(object):
color = "#00ffcc"
+class OPNFVMetaWorkflow(object):
+ workflow_type = 3
+ color = "000000"
+
+
class MetaStep(object):
UNTOUCHED = 0
@@ -110,12 +116,21 @@ class WorkflowFactory():
Image_Meta_Step,
]
+ opnfv_steps = [
+ OPNFV_Resource_Select,
+ Pick_Installer,
+ Assign_Network_Roles,
+ Assign_Host_Roles,
+ MetaInfo
+ ]
+
def conjure(self, workflow_type=None, repo=None):
workflow_types = [
self.booking_steps,
self.resource_steps,
self.config_steps,
self.snapshot_steps,
+ self.opnfv_steps,
]
steps = self.make_steps(workflow_types[workflow_type], repository=repo)