1 ##############################################################################
2 # Copyright (c) 2018 Sawyer Bergeron, Parker Berberian, and others.
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
8 ##############################################################################
11 from django.forms import formset_factory
13 from workflow.models import WorkflowStep
14 from workflow.forms import BasicMetaForm, HostSoftwareDefinitionForm
15 from workflow.booking_workflow import Resource_Select
16 from resource_inventory.models import Image, GenericHost, ConfigBundle, HostConfiguration
19 # resource selection step is reused from Booking workflow
20 class SWConf_Resource_Select(Resource_Select):
21 def __init__(self, *args, **kwargs):
22 super(SWConf_Resource_Select, self).__init__(*args, **kwargs)
23 self.repo_key = self.repo.SELECTED_GRESOURCE_BUNDLE
24 self.confirm_key = "configuration"
26 def post_render(self, request):
27 response = super(SWConf_Resource_Select, self).post_render(request)
28 models = self.repo_get(self.repo.CONFIG_MODELS, {})
29 bundle = models.get("bundle", ConfigBundle(owner=self.repo_get(self.repo.SESSION_USER)))
30 bundle.bundle = self.repo_get(self.repo_key) # super put grb here
31 models['bundle'] = bundle
32 self.repo_put(self.repo.CONFIG_MODELS, models)
36 class Define_Software(WorkflowStep):
37 template = 'config_bundle/steps/define_software.html'
38 title = "Pick Software"
39 description = "Choose the opnfv and image of your machines"
40 short_title = "host config"
42 def build_filter_data(self, hosts_data):
44 returns a 2D array of images to exclude
45 based on the ordering of the passed
49 user = self.repo_get(self.repo.SESSION_USER)
50 lab = self.repo_get(self.repo.SELECTED_GRESOURCE_BUNDLE).lab
51 for i, host_data in enumerate(hosts_data):
52 host = GenericHost.objects.get(pk=host_data['host_id'])
53 wrong_owner = Image.objects.exclude(owner=user).exclude(public=True)
54 wrong_host = Image.objects.exclude(host_type=host.profile)
55 wrong_lab = Image.objects.exclude(from_lab=lab)
56 excluded_images = wrong_owner | wrong_host | wrong_lab
57 filter_data.append([])
58 for image in excluded_images:
59 filter_data[i].append(image.pk)
62 def create_hostformset(self, hostlist, data=None):
64 host_configs = self.repo_get(self.repo.CONFIG_MODELS, {}).get("host_configs", False)
66 for config in host_configs:
67 hosts_initial.append({
68 'host_id': config.host.id,
69 'host_name': config.host.resource.name,
70 'headnode': config.is_head_node,
75 hosts_initial.append({
77 'host_name': host.resource.name
80 HostFormset = formset_factory(HostSoftwareDefinitionForm, extra=0)
81 filter_data = self.build_filter_data(hosts_initial)
83 class SpecialHostFormset(HostFormset):
84 def get_form_kwargs(self, index):
85 kwargs = super(SpecialHostFormset, self).get_form_kwargs(index)
87 kwargs['imageQS'] = Image.objects.exclude(pk__in=filter_data[index])
91 return SpecialHostFormset(data, initial=hosts_initial)
92 return SpecialHostFormset(initial=hosts_initial)
94 def get_host_list(self, grb=None):
96 grb = self.repo_get(self.repo.SELECTED_GRESOURCE_BUNDLE, False)
100 return GenericHost.objects.filter(resource__bundle=grb)
101 generic_hosts = self.repo_get(self.repo.GRESOURCE_BUNDLE_MODELS, {}).get("hosts", [])
104 def get_context(self):
105 context = super(Define_Software, self).get_context()
107 grb = self.repo_get(self.repo.SELECTED_GRESOURCE_BUNDLE, False)
111 formset = self.create_hostformset(self.get_host_list(grb))
112 context["formset"] = formset
113 context['headnode'] = self.repo_get(self.repo.CONFIG_MODELS, {}).get("headnode_index", 1)
115 context["error"] = "Please select a resource first"
116 self.set_invalid("Step requires information that is not yet provided by previous step")
120 def post_render(self, request):
121 models = self.repo_get(self.repo.CONFIG_MODELS, {})
122 if "bundle" not in models:
123 models['bundle'] = ConfigBundle(owner=self.repo_get(self.repo.SESSION_USER))
125 confirm = self.repo_get(self.repo.CONFIRMATION, {})
127 hosts = self.get_host_list()
128 models['headnode_index'] = request.POST.get("headnode", 1)
129 formset = self.create_hostformset(hosts, data=request.POST)
131 if formset.is_valid():
132 models['host_configs'] = []
134 for i, form in enumerate(formset):
136 image = form.cleaned_data['image']
137 headnode = form.cleaned_data['headnode']
140 bundle = models['bundle']
141 hostConfig = HostConfiguration(
145 is_head_node=headnode
147 models['host_configs'].append(hostConfig)
148 confirm_hosts.append({
149 "name": host.resource.name,
155 self.set_invalid('Must have one "Headnode" per POD')
156 return self.render(request)
158 self.repo_put(self.repo.CONFIG_MODELS, models)
159 if "configuration" not in confirm:
160 confirm['configuration'] = {}
161 confirm['configuration']['hosts'] = confirm_hosts
162 self.repo_put(self.repo.CONFIRMATION, confirm)
163 self.set_valid("Completed")
165 self.set_invalid("Please complete all fields")
167 return self.render(request)
170 class Config_Software(WorkflowStep):
171 template = 'config_bundle/steps/config_software.html'
173 description = "Give your software config a name, description, and other stuff"
174 short_title = "config info"
176 def get_context(self):
177 context = super(Config_Software, self).get_context()
180 models = self.repo_get(self.repo.CONFIG_MODELS, {})
181 bundle = models.get("bundle", False)
183 initial['name'] = bundle.name
184 initial['description'] = bundle.description
185 context["form"] = BasicMetaForm(initial=initial)
188 def post_render(self, request):
189 models = self.repo_get(self.repo.CONFIG_MODELS, {})
190 if "bundle" not in models:
191 models['bundle'] = ConfigBundle(owner=self.repo_get(self.repo.SESSION_USER))
193 confirm = self.repo_get(self.repo.CONFIRMATION, {})
194 if "configuration" not in confirm:
195 confirm['configuration'] = {}
197 form = BasicMetaForm(request.POST)
199 models['bundle'].name = form.cleaned_data['name']
200 models['bundle'].description = form.cleaned_data['description']
202 confirm['configuration']['name'] = form.cleaned_data['name']
203 confirm['configuration']['description'] = form.cleaned_data['description']
204 self.set_valid("Complete")
206 self.set_invalid("Please correct the errors shown below")
208 self.repo_put(self.repo.CONFIG_MODELS, models)
209 self.repo_put(self.repo.CONFIRMATION, confirm)
211 return self.render(request)