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