Merge "Removes log button in deployment"
[pharos-tools.git] / dashboard / src / workflow / sw_bundle_workflow.py
1 ##############################################################################
2 # Copyright (c) 2018 Sawyer Bergeron, Parker Berberian, 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
13 from workflow.models import WorkflowStep
14 from workflow.forms import SoftwareConfigurationForm, HostSoftwareDefinitionForm
15 from workflow.booking_workflow import Resource_Select
16 from resource_inventory.models import Image, GenericHost, ConfigBundle, HostConfiguration, Installer, OPNFVConfig
17
18
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"
25
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)
33         return response
34
35
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"
41
42     def create_hostformset(self, hostlist):
43         hosts_initial = []
44         host_configs = self.repo_get(self.repo.CONFIG_MODELS, {}).get("host_configs", False)
45         if host_configs:
46             for config in host_configs:
47                 host_initial = {'host_id': config.host.id, 'host_name': config.host.resource.name}
48                 host_initial['role'] = config.opnfvRole
49                 host_initial['image'] = config.image
50                 hosts_initial.append(host_initial)
51
52         else:
53             for host in hostlist:
54                 host_initial = {'host_id': host.id, 'host_name': host.resource.name}
55
56                 hosts_initial.append(host_initial)
57
58         HostFormset = formset_factory(HostSoftwareDefinitionForm, extra=0)
59         host_formset = HostFormset(initial=hosts_initial)
60
61         filter_data = {}
62         user = self.repo_get(self.repo.SESSION_USER)
63         i = 0
64         for host_data in hosts_initial:
65             host_profile = None
66             try:
67                 host = GenericHost.objects.get(pk=host_data['host_id'])
68                 host_profile = host.profile
69             except Exception:
70                 for host in hostlist:
71                     if host.resource.name == host_data['host_name']:
72                         host_profile = host.profile
73                         break
74             excluded_images = Image.objects.exclude(owner=user).exclude(public=True)
75             excluded_images = excluded_images | Image.objects.exclude(host_type=host.profile)
76             lab = self.repo_get(self.repo.SELECTED_GRESOURCE_BUNDLE).lab
77             excluded_images = excluded_images | Image.objects.exclude(from_lab=lab)
78             filter_data["id_form-" + str(i) + "-image"] = []
79             for image in excluded_images:
80                 filter_data["id_form-" + str(i) + "-image"].append(image.name)
81             i += 1
82
83         return host_formset, filter_data
84
85     def get_host_list(self, grb=None):
86         if grb is None:
87             grb = self.repo_get(self.repo.SELECTED_GRESOURCE_BUNDLE, False)
88             if not grb:
89                 return []
90         if grb.id:
91             return GenericHost.objects.filter(resource__bundle=grb)
92         generic_hosts = self.repo_get(self.repo.GRESOURCE_BUNDLE_MODELS, {}).get("hosts", [])
93         return generic_hosts
94
95     def get_context(self):
96         context = super(Define_Software, self).get_context()
97
98         grb = self.repo_get(self.repo.SELECTED_GRESOURCE_BUNDLE, False)
99
100         if grb:
101             context["grb"] = grb
102             formset, filter_data = self.create_hostformset(self.get_host_list(grb))
103             context["formset"] = formset
104             context["filter_data"] = filter_data
105         else:
106             context["error"] = "Please select a resource first"
107             self.metastep.set_invalid("Step requires information that is not yet provided by previous step")
108
109         return context
110
111     def post_render(self, request):
112         models = self.repo_get(self.repo.CONFIG_MODELS, {})
113         if "bundle" not in models:
114             models['bundle'] = ConfigBundle(owner=self.repo_get(self.repo.SESSION_USER))
115
116         confirm = self.repo_get(self.repo.CONFIRMATION, {})
117
118         HostFormset = formset_factory(HostSoftwareDefinitionForm, extra=0)
119         formset = HostFormset(request.POST)
120         hosts = self.get_host_list()
121         has_jumphost = False
122         if formset.is_valid():
123             models['host_configs'] = []
124             i = 0
125             confirm_hosts = []
126             for form in formset:
127                 host = hosts[i]
128                 i += 1
129                 image = form.cleaned_data['image']
130                 # checks image compatability
131                 grb = self.repo_get(self.repo.SELECTED_GRESOURCE_BUNDLE)
132                 lab = None
133                 if grb:
134                     lab = grb.lab
135                 try:
136                     owner = self.repo_get(self.repo.SESSION_USER)
137                     q = Image.objects.filter(owner=owner) | Image.objects.filter(public=True)
138                     q.filter(host_type=host.profile)
139                     q.filter(from_lab=lab)
140                     q.get(id=image.id)  # will throw exception if image is not in q
141                 except:
142                     self.metastep.set_invalid("Image " + image.name + " is not compatible with host " + host.resource.name)
143                 role = form.cleaned_data['role']
144                 if "jumphost" in role.name.lower():
145                     has_jumphost = True
146                 bundle = models['bundle']
147                 hostConfig = HostConfiguration(
148                     host=host,
149                     image=image,
150                     bundle=bundle,
151                     opnfvRole=role
152                 )
153                 models['host_configs'].append(hostConfig)
154                 confirm_host = {"name": host.resource.name, "image": image.name, "role": role.name}
155                 confirm_hosts.append(confirm_host)
156
157             if not has_jumphost:
158                 self.metastep.set_invalid('Must have at least one "Jumphost" per POD')
159                 return self.render(request)
160
161             self.repo_put(self.repo.CONFIG_MODELS, models)
162             if "configuration" not in confirm:
163                 confirm['configuration'] = {}
164             confirm['configuration']['hosts'] = confirm_hosts
165             self.repo_put(self.repo.CONFIRMATION, confirm)
166             self.metastep.set_valid("Completed")
167         else:
168             self.metastep.set_invalid("Please complete all fields")
169
170         return self.render(request)
171
172
173 class Config_Software(WorkflowStep):
174     template = 'config_bundle/steps/config_software.html'
175     form = SoftwareConfigurationForm
176     context = {'workspace_form': form}
177     title = "Other Info"
178     description = "Give your software config a name, description, and other stuff"
179     short_title = "config info"
180
181     def get_context(self):
182         context = super(Config_Software, self).get_context()
183
184         initial = {}
185         models = self.repo_get(self.repo.CONFIG_MODELS, {})
186         bundle = models.get("bundle", False)
187         if bundle:
188             initial['name'] = bundle.name
189             initial['description'] = bundle.description
190         opnfv = models.get("opnfv", False)
191         if opnfv:
192             initial['installer'] = opnfv.installer
193             initial['scenario'] = opnfv.scenario
194         else:
195             initial['opnfv'] = False
196         supported = {}
197         for installer in Installer.objects.all():
198             supported[str(installer)] = []
199             for scenario in installer.sup_scenarios.all():
200                 supported[str(installer)].append(str(scenario))
201
202         context["form"] = SoftwareConfigurationForm(initial=initial)
203         context['supported'] = supported
204
205         return context
206
207     def post_render(self, request):
208         try:
209             models = self.repo_get(self.repo.CONFIG_MODELS, {})
210             if "bundle" not in models:
211                 models['bundle'] = ConfigBundle(owner=self.repo_get(self.repo.SESSION_USER))
212
213             confirm = self.repo_get(self.repo.CONFIRMATION, {})
214             if "configuration" not in confirm:
215                 confirm['configuration'] = {}
216
217             form = self.form(request.POST)
218             if form.is_valid():
219                 models['bundle'].name = form.cleaned_data['name']
220                 models['bundle'].description = form.cleaned_data['description']
221                 if form.cleaned_data['opnfv']:
222                     installer = form.cleaned_data['installer']
223                     scenario = form.cleaned_data['scenario']
224                     opnfv = OPNFVConfig(
225                         bundle=models['bundle'],
226                         installer=installer,
227                         scenario=scenario
228                     )
229                     models['opnfv'] = opnfv
230                     confirm['configuration']['installer'] = form.cleaned_data['installer'].name
231                     confirm['configuration']['scenario'] = form.cleaned_data['scenario'].name
232
233                 confirm['configuration']['name'] = form.cleaned_data['name']
234                 confirm['configuration']['description'] = form.cleaned_data['description']
235                 self.metastep.set_valid("Complete")
236             else:
237                 self.metastep.set_invalid("Please correct the errors shown below")
238
239             self.repo_put(self.repo.CONFIG_MODELS, models)
240             self.repo_put(self.repo.CONFIRMATION, confirm)
241
242         except Exception:
243             pass
244         return self.render(request)