OverHaul the Snapshot Workflow
[pharos-tools.git] / dashboard / src / workflow / models.py
index 6a8eca1..4e79546 100644 (file)
@@ -10,6 +10,8 @@
 
 from django.shortcuts import render
 from django.contrib import messages
+from django.http import HttpResponse
+from django.utils import timezone
 
 import yaml
 import requests
@@ -26,13 +28,11 @@ from booking.models import Booking
 class BookingAuthManager():
     LFN_PROJECTS = ["opnfv"]  # TODO
 
-    def parse_url(self, info_url):
-        """
-        will return the PTL in the INFO file on success, or None
-        """
+    def parse_github_url(self, url):
+        project_leads = []
         try:
-            parts = info_url.split("/")
-            if parts[0].find("http") > -1:  # the url include http(s)://
+            parts = url.split("/")
+            if "http" in parts[0]:  # the url include http(s)://
                 parts = parts[2:]
             if parts[-1] != "INFO.yaml":
                 return None
@@ -47,13 +47,84 @@ class BookingAuthManager():
             info_file = requests.get(url, timeout=15).text
             info_parsed = yaml.load(info_file)
             ptl = info_parsed.get('project_lead')
-            if not ptl:
+            if ptl:
+                project_leads.append(ptl)
+            sub_ptl = info_parsed.get("subproject_lead")
+            if sub_ptl:
+                project_leads.append(sub_ptl)
+
+        except Exception:
+            pass
+
+        return project_leads
+
+    def parse_gerrit_url(self, url):
+        project_leads = []
+        try:
+            parts = url.split("/")
+            if "http" in parts[0]:  # the url include http(s)://
+                parts = parts[2:]
+            if "f=INFO.yaml" not in parts[-1].split(";"):
+                return None
+            if "gerrit.opnfv.org" not in parts[0]:
                 return None
-            return ptl
+            # now to download and parse file
+            url = "https://" + "/".join(parts)
+            info_file = requests.get(url, timeout=15).text
+            info_parsed = yaml.load(info_file)
+            ptl = info_parsed.get('project_lead')
+            if ptl:
+                project_leads.append(ptl)
+            sub_ptl = info_parsed.get("subproject_lead")
+            if sub_ptl:
+                project_leads.append(sub_ptl)
 
         except Exception:
             return None
 
+        return project_leads
+
+    def parse_opnfv_git_url(self, url):
+        project_leads = []
+        try:
+            parts = url.split("/")
+            if "http" in parts[0]:  # the url include http(s)://
+                parts = parts[2:]
+            if "INFO.yaml" not in parts[-1]:
+                return None
+            if "git.opnfv.org" not in parts[0]:
+                return None
+            if parts[-2] == "tree":
+                parts[-2] = "plain"
+            # now to download and parse file
+            url = "https://" + "/".join(parts)
+            info_file = requests.get(url, timeout=15).text
+            info_parsed = yaml.load(info_file)
+            ptl = info_parsed.get('project_lead')
+            if ptl:
+                project_leads.append(ptl)
+            sub_ptl = info_parsed.get("subproject_lead")
+            if sub_ptl:
+                project_leads.append(sub_ptl)
+
+        except Exception:
+            return None
+
+        return project_leads
+
+    def parse_url(self, info_url):
+        """
+        will return the PTL in the INFO file on success, or None
+        """
+        if "github" in info_url:
+            return self.parse_github_url(info_url)
+
+        if "gerrit.opnfv.org" in info_url:
+            return self.parse_gerrit_url(info_url)
+
+        if "git.opnfv.org" in info_url:
+            return self.parse_opnfv_git_url(info_url)
+
     def booking_allowed(self, booking, repo):
         """
         This is the method that will have to change whenever the booking policy changes in the Infra
@@ -72,7 +143,6 @@ class BookingAuthManager():
 
 
 class WorkflowStep(object):
-
     template = 'bad_request.html'
     title = "Generic Step"
     description = "You were led here by mistake"
@@ -120,9 +190,11 @@ class Confirmation_Step(WorkflowStep):
     description = "Does this all look right?"
 
     def get_vlan_warning(self):
-        grb = self.repo_get(self.repo.BOOKING_SELECTED_GRB, False)
+        grb = self.repo_get(self.repo.SELECTED_GRESOURCE_BUNDLE, False)
         if not grb:
             return 0
+        if self.repo.BOOKING_MODELS not in self.repo.el:
+            return 0
         vlan_manager = grb.lab.vlan_manager
         if vlan_manager is None:
             return 0
@@ -164,9 +236,10 @@ class Confirmation_Step(WorkflowStep):
                 errors = self.flush_to_db()
                 if errors:
                     messages.add_message(request, messages.ERROR, "ERROR OCCURRED: " + errors)
-                    return render(request, self.template, context)
-                messages.add_message(request, messages.SUCCESS, "Confirmed")
-                return render(request, self.template, context)
+                else:
+                    messages.add_message(request, messages.SUCCESS, "Confirmed")
+
+                return HttpResponse('')
             elif data == "False":
                 context["bypassed"] = "true"
                 messages.add_message(request, messages.SUCCESS, "Canceled")
@@ -182,7 +255,7 @@ class Confirmation_Step(WorkflowStep):
             pass
 
     def translate_vlans(self):
-        grb = self.repo_get(self.repo.BOOKING_SELECTED_GRB, False)
+        grb = self.repo_get(self.repo.SELECTED_GRESOURCE_BUNDLE, False)
         if not grb:
             return 0
         vlan_manager = grb.lab.vlan_manager
@@ -216,6 +289,7 @@ class Repository():
     RESOURCE_SELECT = "resource_select"
     CONFIRMATION = "confirmation"
     SELECTED_GRESOURCE_BUNDLE = "selected generic bundle pk"
+    SELECTED_CONFIG_BUNDLE = "selected config bundle pk"
     GRESOURCE_BUNDLE_MODELS = "generic_resource_bundle_models"
     GRESOURCE_BUNDLE_INFO = "generic_resource_bundle_info"
     BOOKING = "booking"
@@ -223,8 +297,6 @@ class Repository():
     GRB_LAST_HOSTLIST = "grb_network_previous_hostlist"
     BOOKING_FORMS = "booking_forms"
     SWCONF_HOSTS = "swconf_hosts"
-    SWCONF_SELECTED_GRB = "swconf_selected_grb_pk"
-    BOOKING_SELECTED_GRB = "booking_selected_grb_pk"
     BOOKING_MODELS = "booking models"
     CONFIG_MODELS = "configuration bundle models"
     SESSION_USER = "session owner user account"
@@ -238,6 +310,22 @@ class Repository():
     SNAPSHOT_DESC = "description of the snapshot"
     BOOKING_INFO_FILE = "the INFO.yaml file for this user's booking"
 
+    #migratory elements of segmented workflow
+    #each of these is the end result of a different workflow.
+    HAS_RESULT = "whether or not workflow has a result"
+    RESULT_KEY = "key for target index that result will be put into in parent"
+    RESULT = "result object from workflow"
+
+    def get_child_defaults(self):
+        return_tuples = []
+        for key in [self.SELECTED_GRESOURCE_BUNDLE, self.SESSION_USER]:
+            return_tuples.append((key, self.el.get(key)))
+        return return_tuples
+
+    def set_defaults(self, defaults):
+        for key, value in defaults:
+            self.el[key] = value
+
     def get(self, key, default, id):
         self.add_get_history(key, id)
         return self.el.get(key, default)
@@ -268,11 +356,19 @@ class Repository():
             errors = self.make_generic_resource_bundle()
             if errors:
                 return errors
+            else:
+                self.el[self.HAS_RESULT] = True
+                self.el[self.RESULT_KEY] = self.SELECTED_GRESOURCE_BUNDLE
+                return
 
         if self.CONFIG_MODELS in self.el:
             errors = self.make_software_config_bundle()
             if errors:
                 return errors
+            else:
+                self.el[self.HAS_RESULT] = True
+                self.el[self.RESULT_KEY] = self.SELECTED_CONFIG_BUNDLE
+                return
 
         if self.BOOKING_MODELS in self.el:
             errors = self.make_booking()
@@ -290,6 +386,8 @@ class Repository():
         if not booking_id:
             return "SNAP, No booking ID provided"
         booking = Booking.objects.get(pk=booking_id)
+        if booking.start > timezone.now() or booking.end < timezone.now():
+            return "Booking is not active"
         name = self.el.get(self.SNAPSHOT_NAME)
         if not name:
             return "SNAP, no name provided"
@@ -305,6 +403,13 @@ class Repository():
         image.owner = owner
         image.host_type = host.profile
         image.save()
+        try:
+            current_image = host.config.image
+            image.os = current_image.os
+            image.save()
+        except Exception:
+            pass
+        JobFactory.makeSnapshotTask(image, booking, host)
 
     def make_generic_resource_bundle(self):
         owner = self.el[self.SESSION_USER]
@@ -365,7 +470,7 @@ class Repository():
         else:
             return "GRB no models given. CODE:0x0001"
 
-        self.el[self.VALIDATED_MODEL_GRB] = bundle
+        self.el[self.RESULT] = bundle
         return False
 
     def make_software_config_bundle(self):
@@ -403,15 +508,15 @@ class Repository():
         else:
             pass
 
-        self.el[self.VALIDATED_MODEL_CONFIG] = bundle
+        self.el[self.RESULT] = bundle
         return False
 
     def make_booking(self):
         models = self.el[self.BOOKING_MODELS]
         owner = self.el[self.SESSION_USER]
 
-        if self.BOOKING_SELECTED_GRB in self.el:
-            selected_grb = self.el[self.BOOKING_SELECTED_GRB]
+        if self.SELECTED_GRESOURCE_BUNDLE in self.el:
+            selected_grb = self.el[self.SELECTED_GRESOURCE_BUNDLE]
         else:
             return "BOOK, no selected resource. CODE:0x000e"
 
@@ -501,5 +606,6 @@ class Repository():
     def __init__(self):
         self.el = {}
         self.el[self.CONFIRMATION] = {}
+        self.el["active_step"] = 0
         self.get_history = {}
         self.put_history = {}