Merge "Fixes a typo"
[pharos-tools.git] / dashboard / src / workflow / workflow_manager.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.http import JsonResponse
12
13 from booking.models import Booking
14 from workflow.workflow_factory import WorkflowFactory
15 from workflow.models import Repository
16 from resource_inventory.models import (
17     GenericResourceBundle,
18     ConfigBundle,
19     HostConfiguration,
20     OPNFVConfig
21 )
22
23 import logging
24 logger = logging.getLogger(__name__)
25
26
27 class SessionManager():
28     def active_workflow(self):
29         return self.workflows[-1]
30
31     def __init__(self, request=None):
32         self.workflows = []
33
34         self.owner = request.user
35
36         self.factory = WorkflowFactory()
37
38     def set_step_statuses(self, superclass_type, desired_enabled=True):
39         workflow = self.active_workflow()
40         steps = workflow.steps
41         for step in steps:
42             if isinstance(step, superclass_type):
43                 if desired_enabled:
44                     step.enable()
45                 else:
46                     step.disable()
47
48     def add_workflow(self, workflow_type=None, target_id=None, **kwargs):
49         if target_id is not None:
50             self.prefill_repo(target_id, workflow_type)
51
52         repo = Repository()
53         if(len(self.workflows) >= 1):
54             defaults = self.workflows[-1].repository.get_child_defaults()
55             repo.set_defaults(defaults)
56             repo.el[repo.HAS_RESULT] = False
57         repo.el[repo.SESSION_USER] = self.owner
58         repo.el[repo.SESSION_MANAGER] = self
59         self.workflows.append(
60             self.factory.create_workflow(
61                 workflow_type=workflow_type,
62                 repo=repo
63             )
64         )
65
66     def pop_workflow(self):
67         multiple_wfs = len(self.workflows) > 1
68         if multiple_wfs:
69             if self.workflows[-1].repository.el[Repository.RESULT]:  # move result
70                 key = self.workflows[-1].repository.el[Repository.RESULT_KEY]
71                 result = self.workflows[-1].repository.el[Repository.RESULT]
72                 self.workflows[-2].repository.el[key] = result
73             self.workflows.pop()
74         current_repo = self.workflows[-1].repository
75         return (multiple_wfs, current_repo.el[current_repo.RESULT])
76
77     def status(self, request):
78         try:
79             meta_json = []
80             for step in self.active_workflow().steps:
81                 meta_json.append(step.to_json())
82             responsejson = {}
83             responsejson["steps"] = meta_json
84             responsejson["active"] = self.active_workflow().repository.el['active_step']
85             responsejson["workflow_count"] = len(self.workflows)
86             return JsonResponse(responsejson, safe=False)
87         except Exception:
88             pass
89
90     def render(self, request, **kwargs):
91         # filter out when a step needs to handle post/form data
92         # if 'workflow' in post data, this post request was meant for me, not step
93         if request.method == 'POST' and request.POST.get('workflow', None) is None:
94             return self.active_workflow().steps[self.active_workflow().active_index].post_render(request)
95         return self.active_workflow().steps[self.active_workflow().active_index].render(request)
96
97     def post_render(self, request):
98         return self.active_workflow().steps[self.active_workflow().active_index].post_render(request)
99
100     def get_active_step(self):
101         return self.active_workflow().steps[self.active_workflow().active_index]
102
103     def go_next(self, **kwargs):
104         # need to verify current step is valid to allow this
105         if self.get_active_step().valid < 200:
106             return
107         next_step = self.active_workflow().active_index + 1
108         if next_step >= len(self.active_workflow().steps):
109             raise Exception("Out of bounds request for step")
110         while not self.active_workflow().steps[next_step].enabled:
111             next_step += 1
112         self.active_workflow().repository.el['active_step'] = next_step
113         self.active_workflow().active_index = next_step
114
115     def go_prev(self, **kwargs):
116         prev_step = self.active_workflow().active_index - 1
117         if prev_step < 0:
118             raise Exception("Out of bounds request for step")
119         while not self.active_workflow().steps[prev_step].enabled:
120             prev_step -= 1
121         self.active_workflow().repository.el['active_step'] = prev_step
122         self.active_workflow().active_index = prev_step
123
124     def prefill_repo(self, target_id, workflow_type):
125         self.repository.el[self.repository.EDIT] = True
126         edit_object = None
127         if workflow_type == 0:
128             edit_object = Booking.objects.get(pk=target_id)
129             self.prefill_booking(edit_object)
130         elif workflow_type == 1:
131             edit_object = GenericResourceBundle.objects.get(pk=target_id)
132             self.prefill_resource(edit_object)
133         elif workflow_type == 2:
134             edit_object = ConfigBundle.objects.get(pk=target_id)
135             self.prefill_config(edit_object)
136
137     def prefill_booking(self, booking):
138         models = self.make_booking_models(booking)
139         confirmation = self.make_booking_confirm(booking)
140         self.active_workflow().repository.el[self.active_workflow().repository.BOOKING_MODELS] = models
141         self.active_workflow().repository.el[self.active_workflow().repository.CONFIRMATION] = confirmation
142         self.active_workflow().repository.el[self.active_workflow().repository.GRESOURCE_BUNDLE_MODELS] = self.make_grb_models(booking.resource.template)
143         self.active_workflow().repository.el[self.active_workflow().repository.SELECTED_GRESOURCE_BUNDLE] = self.make_grb_models(booking.resource.template)['bundle']
144         self.active_workflow().repository.el[self.active_workflow().repository.CONFIG_MODELS] = self.make_config_models(booking.config_bundle)
145
146     def prefill_resource(self, resource):
147         models = self.make_grb_models(resource)
148         confirm = self.make_grb_confirm(resource)
149         self.active_workflow().repository.el[self.active_workflow().repository.GRESOURCE_BUNDLE_MODELS] = models
150         self.active_workflow().repository.el[self.active_workflow().repository.CONFIRMATION] = confirm
151
152     def prefill_config(self, config):
153         models = self.make_config_models(config)
154         confirm = self.make_config_confirm(config)
155         self.active_workflow().repository.el[self.active_workflow().repository.CONFIG_MODELS] = models
156         self.active_workflow().repository.el[self.active_workflow().repository.CONFIRMATION] = confirm
157         grb_models = self.make_grb_models(config.bundle)
158         self.active_workflow().repository.el[self.active_workflow().repository.GRESOURCE_BUNDLE_MODELS] = grb_models
159
160     def make_grb_models(self, resource):
161         models = self.active_workflow().repository.el.get(self.active_workflow().repository.GRESOURCE_BUNDLE_MODELS, {})
162         models['hosts'] = []
163         models['bundle'] = resource
164         models['interfaces'] = {}
165         models['vlans'] = {}
166         for host in resource.getHosts():
167             models['hosts'].append(host)
168             models['interfaces'][host.resource.name] = []
169             models['vlans'][host.resource.name] = {}
170             for interface in host.generic_interfaces.all():
171                 models['interfaces'][host.resource.name].append(interface)
172                 models['vlans'][host.resource.name][interface.profile.name] = []
173                 for vlan in interface.vlans.all():
174                     models['vlans'][host.resource.name][interface.profile.name].append(vlan)
175         return models
176
177     def make_grb_confirm(self, resource):
178         confirm = self.active_workflow().repository.el.get(self.active_workflow().repository.CONFIRMATION, {})
179         confirm['resource'] = {}
180         confirm['resource']['hosts'] = []
181         confirm['resource']['lab'] = resource.lab.lab_user.username
182         for host in resource.getHosts():
183             confirm['resource']['hosts'].append({"name": host.resource.name, "profile": host.profile.name})
184         return confirm
185
186     def make_config_models(self, config):
187         models = self.active_workflow().repository.el.get(self.active_workflow().repository.CONFIG_MODELS, {})
188         models['bundle'] = config
189         models['host_configs'] = []
190         for host_conf in HostConfiguration.objects.filter(bundle=config):
191             models['host_configs'].append(host_conf)
192         models['opnfv'] = OPNFVConfig.objects.filter(bundle=config).last()
193         return models
194
195     def make_config_confirm(self, config):
196         confirm = self.active_workflow().repository.el.get(self.active_workflow().repository.CONFIRMATION, {})
197         confirm['configuration'] = {}
198         confirm['configuration']['hosts'] = []
199         confirm['configuration']['name'] = config.name
200         confirm['configuration']['description'] = config.description
201         opnfv = OPNFVConfig.objects.filter(bundle=config).last()
202         confirm['configuration']['installer'] = opnfv.installer.name
203         confirm['configuration']['scenario'] = opnfv.scenario.name
204         for host_conf in HostConfiguration.objects.filter(bundle=config):
205             h = {"name": host_conf.host.resource.name, "image": host_conf.image.name, "role": host_conf.opnfvRole.name}
206             confirm['configuration']['hosts'].append(h)
207         return confirm
208
209     def make_booking_models(self, booking):
210         models = self.active_workflow().repository.el.get(self.active_workflow().repository.BOOKING_MODELS, {})
211         models['booking'] = booking
212         models['collaborators'] = []
213         for user in booking.collaborators.all():
214             models['collaborators'].append(user)
215         return models
216
217     def make_booking_confirm(self, booking):
218         confirm = self.active_workflow().repository.el.get(self.active_workflow().repository.CONFIRMATION, {})
219         confirm['booking'] = {}
220         confirm['booking']['length'] = (booking.end - booking.start).days
221         confirm['booking']['project'] = booking.project
222         confirm['booking']['purpose'] = booking.purpose
223         confirm['booking']['resource name'] = booking.resource.template.name
224         confirm['booking']['configuration name'] = booking.config_bundle.name
225         confirm['booking']['collaborators'] = []
226         for user in booking.collaborators.all():
227             confirm['booking']['collaborators'].append(user.username)
228         return confirm
229
230
231 class ManagerTracker():
232     instance = None
233
234     managers = {}
235
236     def __init__(self):
237         pass
238
239     @staticmethod
240     def getInstance():
241         if ManagerTracker.instance is None:
242             ManagerTracker.instance = ManagerTracker()
243         return ManagerTracker.instance