Rewrite Notification subsystem
[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.db import models
12 from django.contrib.auth.models import User
13 from django.core import serializers
14 from django.http import HttpResponse, JsonResponse
15
16 import json
17 import uuid
18 import random
19
20 from resource_inventory.models import *
21 from booking.models import Booking
22 from workflow.workflow_factory import WorkflowFactory, MetaStep, MetaRelation
23 from workflow.models import Repository, Confirmation_Step
24
25 import logging
26 logger = logging.getLogger(__name__)
27
28 class SessionManager():
29
30     def __init__(self, request=None):
31         self.repository = Repository()
32         self.repository.el[self.repository.SESSION_USER] = request.user
33         self.repository.el['active_step'] = 0
34         self.steps = []
35         self.factory = WorkflowFactory()
36         c_step = WorkflowFactory().make_step(Confirmation_Step, self.repository)
37         self.steps.append(c_step)
38         metaconfirm = MetaStep()
39         metaconfirm.index = 0
40         metaconfirm.short_title = "confirm"
41         self.repository.el['steps'] = 1;
42         self.metaworkflow = None
43         self.metaworkflows = []
44         self.metarelations = []
45         self.relationreverselookup = {}
46         self.initialized = False
47         self.active_index = 0
48         self.step_meta = [metaconfirm]
49         self.relation_depth = 0
50
51     def add_workflow(self, workflow_type=None, target_id=None, **kwargs):
52         if target_id is not None:
53             self.prefill_repo(target_id, workflow_type)
54         factory_steps, meta_info = self.factory.conjure(workflow_type=workflow_type, repo=self.repository)
55         offset = len(meta_info)
56         for relation in self.metarelations:
57             if relation.depth > self.relation_depth:
58                 self.relation_depth = relation.depth
59             if relation.parent >= self.repository.el['active_step']:
60                 relation.parent += offset
61                 for i in range(0, len(relation.children)):
62                     if relation.children[i] >= self.repository.el['active_step']:
63                         relation.children[i] += offset
64         self.step_meta[self.active_index:self.active_index] = meta_info
65         self.steps[self.active_index:self.active_index] = factory_steps
66
67         if self.initialized:
68             relation = MetaRelation()
69             relation.parent = self.repository.el['active_step'] + offset
70             relation.depth = self.relationreverselookup[self.step_meta[relation.parent]].depth + 1
71             if relation.depth > self.relation_depth:
72                 self.relation_depth = relation.depth
73             for i in range(self.repository.el['active_step'], offset + self.repository.el['active_step']):
74                 relation.children.append(i)
75                 self.relationreverselookup[self.step_meta[i]] = relation
76             relation.color = "#%06x" % random.randint(0, 0xFFFFFF)
77             self.metarelations.append(relation)
78         else:
79             relation = MetaRelation()
80             relation.depth = 0
81             relation.parent = 500000000000
82             for i in range(0, len(self.step_meta)):
83                 relation.children.append(i)
84                 self.relationreverselookup[self.step_meta[i]] = relation
85             self.metarelations.append(relation)
86             self.initialized = True
87
88
89     def status(self, request):
90         try:
91             workflows = []
92             steps = []
93             for step in self.step_meta:
94                 steps.append(step.to_json())
95             parents = {}
96             children = {}
97             responsejson = {}
98             responsejson["steps"] = steps
99             responsejson["active"] = self.repository.el['active_step']
100             responsejson["relations"] = []
101             i = 0
102             for relation in self.metarelations:
103                 responsejson["relations"].append(relation.to_json())
104                 children[relation.parent] = i
105                 for child in relation.children:
106                     parents[child] = i
107                 i += 1
108             responsejson['max_depth'] = self.relation_depth
109             responsejson['parents'] = parents
110             responsejson['children'] = children
111             return JsonResponse(responsejson, safe=False)
112         except Exception as e:
113             pass
114
115     def render(self, request, **kwargs):
116         #filter out when a step needs to handle post/form data
117         # if 'workflow' in post data, this post request was meant for me, not step
118         if request.method == 'POST' and request.POST.get('workflow', None) is None:
119             return self.steps[self.active_index].post_render(request)
120         return self.steps[self.active_index].render(request)
121
122     def post_render(self, request):
123         return self.steps[self.active_index].post_render(request)
124
125     def goto(self, num, **kwargs):
126         self.repository.el['active_step'] = int(num)
127         self.active_index = int(num)
128         #TODO: change to include some checking
129
130     def prefill_repo(self, target_id, workflow_type):
131         self.repository.el[self.repository.EDIT] = True
132         edit_object = None
133         if workflow_type == 0:
134             edit_object = Booking.objects.get(pk=target_id)
135             self.prefill_booking(edit_object)
136         elif workflow_type == 1:
137             edit_object = GenericResourceBundle.objects.get(pk=target_id)
138             self.prefill_resource(edit_object)
139         elif workflow_type == 2:
140             edit_object = ConfigBundle.objects.get(pk=target_id)
141             self.prefill_config(edit_object)
142
143
144     def prefill_booking(self, booking):
145         models = self.make_booking_models(booking)
146         confirmation = self.make_booking_confirm(booking)
147         self.repository.el[self.repository.BOOKING_MODELS] = models
148         self.repository.el[self.repository.CONFIRMATION] = confirmation
149         self.repository.el[self.repository.GRESOURCE_BUNDLE_MODELS] = self.make_grb_models(booking.resource.template)
150         self.repository.el[self.repository.BOOKING_SELECTED_GRB] = self.make_grb_models(booking.resource.template)['bundle']
151         self.repository.el[self.repository.CONFIG_MODELS] = self.make_config_models(booking.config_bundle)
152
153     def prefill_resource(self, resource):
154         models = self.make_grb_models(resource)
155         confirm = self.make_grb_confirm(resource)
156         self.repository.el[self.repository.GRESOURCE_BUNDLE_MODELS] = models
157         self.repository.el[self.repository.CONFIRMATION] = confirm
158
159     def prefill_config(self, config):
160         models = self.make_config_models(config)
161         confirm = self.make_config_confirm(config)
162         self.repository.el[self.repository.CONFIG_MODELS] = models
163         self.repository.el[self.repository.CONFIRMATION] = confirm
164         grb_models = self.make_grb_models(config.bundle)
165         self.repository.el[self.repository.GRESOURCE_BUNDLE_MODELS] = grb_models
166         self.repository.el[self.repository.SWCONF_SELECTED_GRB] = config.bundle
167
168     def make_grb_models(self, resource):
169         models = self.repository.el.get(self.repository.GRESOURCE_BUNDLE_MODELS, {})
170         models['hosts'] = []
171         models['bundle'] = resource
172         models['interfaces'] = {}
173         models['vlans'] = {}
174         for host in resource.getHosts():
175             models['hosts'].append(host)
176             models['interfaces'][host.resource.name] = []
177             models['vlans'][host.resource.name] = {}
178             for interface in host.generic_interfaces.all():
179                 models['interfaces'][host.resource.name].append(interface)
180                 models['vlans'][host.resource.name][interface.profile.name] = []
181                 for vlan in interface.vlans.all():
182                     models['vlans'][host.resource.name][interface.profile.name].append(vlan)
183         return models
184
185     def make_grb_confirm(self, resource):
186         confirm = self.repository.el.get(self.repository.CONFIRMATION, {})
187         confirm['resource'] = {}
188         confirm['resource']['hosts'] = []
189         confirm['resource']['lab'] = resource.lab.lab_user.username
190         for host in resource.getHosts():
191             confirm['resource']['hosts'].append({"name": host.resource.name, "profile": host.profile.name})
192         return confirm
193
194     def make_config_models(self, config):
195         models = self.repository.el.get(self.repository.CONFIG_MODELS, {})
196         models['bundle'] = config
197         models['host_configs'] = []
198         for host_conf in HostConfiguration.objects.filter(bundle=config):
199             models['host_configs'].append(host_conf)
200         models['opnfv'] = OPNFVConfig.objects.filter(bundle=config).last()
201         return models
202
203     def make_config_confirm(self, config):
204         confirm = self.repository.el.get(self.repository.CONFIRMATION, {})
205         confirm['configuration'] = {}
206         confirm['configuration']['hosts'] = []
207         confirm['configuration']['name'] = config.name
208         confirm['configuration']['description'] = config.description
209         opnfv = OPNFVConfig.objects.filter(bundle=config).last()
210         confirm['configuration']['installer'] = opnfv.installer.name
211         confirm['configuration']['scenario'] = opnfv.scenario.name
212         for host_conf in HostConfiguration.objects.filter(bundle=config):
213             h = {"name": host_conf.host.resource.name, "image": host_conf.image.name, "role": host_conf.opnfvRole.name}
214             confirm['configuration']['hosts'].append(h)
215         return confirm
216
217     def make_booking_models(self, booking):
218         models = self.repository.el.get(self.repository.BOOKING_MODELS, {})
219         models['booking'] = booking
220         models['collaborators'] = []
221         for user in booking.collaborators.all():
222             models['collaborators'].append(user)
223         return models
224
225     def make_booking_confirm(self, booking):
226         confirm = self.repository.el.get(self.repository.CONFIRMATION, {})
227         confirm['booking'] = {}
228         confirm['booking']['length'] = (booking.end - booking.start).days
229         confirm['booking']['project'] = booking.project
230         confirm['booking']['purpose'] = booking.purpose
231         confirm['booking']['resource name'] = booking.resource.template.name
232         confirm['booking']['configuration name'] = booking.config_bundle.name
233         confirm['booking']['collaborators'] = []
234         for user in booking.collaborators.all():
235             confirm['booking']['collaborators'].append(user.username)
236         return confirm
237
238
239 class ManagerTracker():
240     instance = None
241
242     managers = {}
243
244     def __init__(self):
245         pass
246
247     @staticmethod
248     def getInstance():
249         if ManagerTracker.instance is None:
250             ManagerTracker.instance = ManagerTracker()
251         return ManagerTracker.instance