490d2f0db6695d852a2aa445eb51eff8bbc27439
[laas.git] / src / workflow / opnfv_workflow.py
1 ##############################################################################
2 # Copyright (c) 2018 Parker Berberian, Sawyer Bergeron, and others.
3 #
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 ##############################################################################
9
10
11 from django.forms import formset_factory
12 from django.contrib import messages
13
14 import json
15
16 from workflow.models import WorkflowStep
17 from resource_inventory.models import ConfigBundle, OPNFV_SETTINGS
18 from workflow.forms import OPNFVSelectionForm, OPNFVNetworkRoleForm, OPNFVHostRoleForm, SWConfigSelectorForm, BasicMetaForm
19
20
21 class OPNFV_Resource_Select(WorkflowStep):
22     template = 'booking/steps/swconfig_select.html'
23     title = "Select Software Configuration"
24     description = "Choose the software and related configurations you want to use to configure OPNFV"
25     short_title = "software configuration"
26     modified_key = "configbundle_step"
27
28     def update_confirmation(self):
29         confirm = self.repo_get(self.repo.CONFIRMATION, {})
30         config_bundle = self.repo_get(self.repo.OPNFV_MODELS, {}).get("configbundle")
31         if not config_bundle:
32             return
33         confirm['software bundle'] = config_bundle.name
34         confirm['hardware POD'] = config_bundle.bundle.name
35         self.repo_put(self.repo.CONFIRMATION, confirm)
36
37     def post_render(self, request):
38         models = self.repo_get(self.repo.OPNFV_MODELS, {})
39         form = SWConfigSelectorForm(request.POST)
40         if form.is_valid():
41             bundle_json = form.cleaned_data['software_bundle']
42             bundle_json = bundle_json[2:-2]  # Stupid django string bug
43             if not bundle_json:
44                 self.set_invalid("Please select a valid config")
45                 return self.render(request)
46             bundle_json = json.loads(bundle_json)
47             if len(bundle_json) < 1:
48                 self.set_invalid("Please select a valid config")
49                 return self.render(request)
50             bundle = None
51             id = int(bundle_json[0]['id'])
52             bundle = ConfigBundle.objects.get(id=id)
53
54             models['configbundle'] = bundle
55             self.repo_put(self.repo.OPNFV_MODELS, models)
56             self.set_valid("Step Completed")
57             messages.add_message(request, messages.SUCCESS, 'Form Validated Successfully', fail_silently=True)
58             self.update_confirmation()
59         else:
60             self.set_invalid("Please select or create a valid config")
61             messages.add_message(request, messages.ERROR, "Form Didn't Validate", fail_silently=True)
62
63         return self.render(request)
64
65     def get_context(self):
66         context = super(OPNFV_Resource_Select, self).get_context()
67         default = []
68         user = self.repo_get(self.repo.SESSION_USER)
69
70         context['form'] = SWConfigSelectorForm(chosen_software=default, bundle=None, edit=True, resource=None, user=user)
71         return context
72
73
74 class Pick_Installer(WorkflowStep):
75     template = 'config_bundle/steps/pick_installer.html'
76     title = 'Pick OPNFV Installer'
77     description = 'Choose which OPNFV installer to use'
78     short_title = "opnfv installer"
79     modified_key = "installer_step"
80
81     def update_confirmation(self):
82         confirm = self.repo_get(self.repo.CONFIRMATION, {})
83         models = self.repo_get(self.repo.OPNFV_MODELS, {})
84         installer = models.get("installer_chosen")
85         scenario = models.get("scenario_chosen")
86         if not (installer and scenario):
87             return
88         confirm['installer'] = installer.name
89         confirm['scenario'] = scenario.name
90         self.repo_put(self.repo.CONFIRMATION, confirm)
91
92     def get_context(self):
93         context = super(Pick_Installer, self).get_context()
94
95         models = self.repo_get(self.repo.OPNFV_MODELS, None)
96         initial = {
97             "installer": models.get("installer_chosen"),
98             "scenario": models.get("scenario_chosen")
99         }
100
101         context["form"] = OPNFVSelectionForm(initial=initial)
102         return context
103
104     def post_render(self, request):
105         form = OPNFVSelectionForm(request.POST)
106         if form.is_valid():
107             installer = form.cleaned_data['installer']
108             scenario = form.cleaned_data['scenario']
109             models = self.repo_get(self.repo.OPNFV_MODELS, {})
110             models['installer_chosen'] = installer
111             models['scenario_chosen'] = scenario
112             self.repo_put(self.repo.OPNFV_MODELS, models)
113             self.update_confirmation()
114             self.set_valid("Step Completed")
115         else:
116             self.set_invalid("Please select an Installer and Scenario")
117
118         return self.render(request)
119
120
121 class Assign_Network_Roles(WorkflowStep):
122     template = 'config_bundle/steps/assign_network_roles.html'
123     title = 'Pick Network Roles'
124     description = 'Choose what role each network should get'
125     short_title = "network roles"
126     modified_key = "net_roles_step"
127
128     """
129     to do initial filling, repo should have a "network_roles" array with the following structure for each element:
130     {
131         "role": <NetworkRole object ref>,
132         "network": <Network object ref>
133     }
134     """
135     def create_netformset(self, roles, config_bundle, data=None):
136         roles_initial = []
137         set_roles = self.repo_get(self.repo.OPNFV_MODELS, {}).get("network_roles")
138         if set_roles:
139             roles_initial = set_roles
140         else:
141             for role in OPNFV_SETTINGS.NETWORK_ROLES:
142                 roles_initial.append({"role": role})
143
144         Formset = formset_factory(OPNFVNetworkRoleForm, extra=0)
145         kwargs = {
146             "initial": roles_initial,
147             "form_kwargs": {"config_bundle": config_bundle}
148         }
149         formset = None
150         if data:
151             formset = Formset(data, **kwargs)
152         else:
153             formset = Formset(**kwargs)
154         return formset
155
156     def get_context(self):
157         context = super(Assign_Network_Roles, self).get_context()
158         config_bundle = self.repo_get(self.repo.OPNFV_MODELS, {}).get("configbundle")
159         if config_bundle is None:
160             context["unavailable"] = True
161             return context
162
163         roles = OPNFV_SETTINGS.NETWORK_ROLES
164         formset = self.create_netformset(roles, config_bundle)
165         context['formset'] = formset
166
167         return context
168
169     def update_confirmation(self):
170         confirm = self.repo_get(self.repo.CONFIRMATION, {})
171         models = self.repo_get(self.repo.OPNFV_MODELS, {})
172         roles = models.get("network_roles")
173         if not roles:
174             return
175         confirm['network roles'] = {}
176         for role in roles:
177             confirm['network roles'][role['role']] = role['network'].name
178         self.repo_put(self.repo.CONFIRMATION, confirm)
179
180     def post_render(self, request):
181         models = self.repo_get(self.repo.OPNFV_MODELS, {})
182         config_bundle = models.get("configbundle")
183         roles = OPNFV_SETTINGS.NETWORK_ROLES
184         net_role_formset = self.create_netformset(roles, config_bundle, data=request.POST)
185         if net_role_formset.is_valid():
186             results = []
187             for form in net_role_formset:
188                 results.append({
189                     "role": form.cleaned_data['role'],
190                     "network": form.cleaned_data['network']
191                 })
192             models['network_roles'] = results
193             self.set_valid("Completed")
194             self.repo_put(self.repo.OPNFV_MODELS, models)
195             self.update_confirmation()
196         else:
197             self.set_invalid("Please complete all fields")
198         return self.render(request)
199
200
201 class Assign_Host_Roles(WorkflowStep):  # taken verbatim from Define_Software in sw workflow, merge the two?
202     template = 'config_bundle/steps/assign_host_roles.html'
203     title = 'Pick Host Roles'
204     description = "Choose the role each machine will have in your OPNFV pod"
205     short_title = "host roles"
206     modified_key = "host_roles_step"
207
208     def create_host_role_formset(self, hostlist=[], data=None):
209         models = self.repo_get(self.repo.OPNFV_MODELS, {})
210         host_roles = models.get("host_roles", [])
211         if not host_roles:
212             for host in hostlist:
213                 initial = {"host_name": host.resource.name}
214                 host_roles.append(initial)
215         models['host_roles'] = host_roles
216         self.repo_put(self.repo.OPNFV_MODELS, models)
217
218         HostFormset = formset_factory(OPNFVHostRoleForm, extra=0)
219
220         kwargs = {"initial": host_roles}
221         formset = None
222         if data:
223             formset = HostFormset(data, **kwargs)
224         else:
225             formset = HostFormset(**kwargs)
226
227         return formset
228
229     def get_context(self):
230         context = super(Assign_Host_Roles, self).get_context()
231         models = self.repo_get(self.repo.OPNFV_MODELS, {})
232         config = models.get("configbundle")
233         if config is None:
234             context['error'] = "Please select a Configuration on the first step"
235
236         formset = self.create_host_role_formset(hostlist=config.bundle.getHosts())
237         context['formset'] = formset
238
239         return context
240
241     def get_host_role_mapping(self, host_roles, hostname):
242         for obj in host_roles:
243             if hostname == obj['host_name']:
244                 return obj
245         return None
246
247     def update_confirmation(self):
248         confirm = self.repo_get(self.repo.CONFIRMATION, {})
249         models = self.repo_get(self.repo.OPNFV_MODELS, {})
250         roles = models.get("host_roles")
251         if not roles:
252             return
253         confirm['host roles'] = {}
254         for role in roles:
255             confirm['host roles'][role['host_name']] = role['role'].name
256         self.repo_put(self.repo.CONFIRMATION, confirm)
257
258     def post_render(self, request):
259         formset = self.create_host_role_formset(data=request.POST)
260
261         models = self.repo_get(self.repo.OPNFV_MODELS, {})
262         host_roles = models.get("host_roles", [])
263
264         has_jumphost = False
265         if formset.is_valid():
266             for form in formset:
267                 hostname = form.cleaned_data['host_name']
268                 role = form.cleaned_data['role']
269                 mapping = self.get_host_role_mapping(host_roles, hostname)
270                 mapping['role'] = role
271                 if "jumphost" in role.name.lower():
272                     has_jumphost = True
273
274             models['host_roles'] = host_roles
275             self.repo_put(self.repo.OPNFV_MODELS, models)
276             self.update_confirmation()
277
278             if not has_jumphost:
279                 self.set_invalid('Must have at least one "Jumphost" per POD')
280             else:
281                 self.set_valid("Completed")
282         else:
283             self.set_invalid("Please complete all fields")
284
285         return self.render(request)
286
287
288 class MetaInfo(WorkflowStep):
289     template = 'config_bundle/steps/config_software.html'
290     title = "Other Info"
291     description = "Give your software config a name, description, and other stuff"
292     short_title = "config info"
293
294     def get_context(self):
295         context = super(MetaInfo, self).get_context()
296
297         initial = self.repo_get(self.repo.OPNFV_MODELS, {}).get("meta", {})
298         context["form"] = BasicMetaForm(initial=initial)
299         return context
300
301     def update_confirmation(self):
302         confirm = self.repo_get(self.repo.CONFIRMATION, {})
303         models = self.repo_get(self.repo.OPNFV_MODELS, {})
304         meta = models.get("meta")
305         if not meta:
306             return
307         confirm['name'] = meta['name']
308         confirm['description'] = meta['description']
309         self.repo_put(self.repo.CONFIRMATION, confirm)
310
311     def post_render(self, request):
312         models = self.repo_get(self.repo.OPNFV_MODELS, {})
313         info = models.get("meta", {})
314
315         form = BasicMetaForm(request.POST)
316         if form.is_valid():
317             info['name'] = form.cleaned_data['name']
318             info['description'] = form.cleaned_data['description']
319             models['meta'] = info
320             self.repo_put(self.repo.OPNFV_MODELS, models)
321             self.update_confirmation()
322             self.set_valid("Complete")
323         else:
324             self.set_invalid("Please correct the errors shown below")
325
326         self.repo_put(self.repo.OPNFV_MODELS, models)
327         return self.render(request)