ask the PI to click save
[plstackapi.git] / planetstack / core / dashboard / views / tenant.py
index 9066a2b..5a45033 100644 (file)
@@ -1,7 +1,58 @@
 from view_common import *
+from core.models import *
 import functools
+from django.contrib.auth.models import BaseUserManager
+from django.core import serializers
+from django.core.mail import EmailMultiAlternatives
+import json
 
-BLESSED_SITES = ["Stanford", "Washington", "Princeton", "GeorgiaTech", "MaxPlanck"]
+BLESSED_DEPLOYMENTS = ["US-MaxPlanck", "US-GeorgiaTech", "US-Princeton", "US-Washington", "US-Stanford"]
+
+class RequestAccessView(View):
+    def post(self, request, *args, **kwargs):
+       email = request.POST.get("email", "0")
+       firstname = request.POST.get("firstname", "0")
+       lastname = request.POST.get("lastname", "0")
+       site = request.POST.get("site","0")
+        # see if it already exists
+        user=User.objects.filter(email=BaseUserManager.normalize_email(email))
+        if (user):
+             user = user[0]
+             if user.is_active:
+                 # force a new email to be sent
+                 user.is_registering=True
+                 user.save()
+                 return HttpResponse(json.dumps({"error": "already_approved"}), content_type='application/javascript')
+             else:
+                 return HttpResponse(json.dumps({"error": "already_pending"}), content_type='application/javascript')
+
+        user=User.deleted_objects.filter(email=BaseUserManager.normalize_email(email))
+        if (user):
+            return HttpResponse(json.dumps({"error": "is_deleted"}), content_type='application/javascript')
+
+       user = User(
+            email=BaseUserManager.normalize_email(email),
+            firstname=firstname,
+            lastname=lastname,
+           is_active=False,
+            is_admin=False,
+            is_registering=True
+        )
+        user.save()
+       user.site=Site.objects.get(name=site)
+       user.save(update_fields=['site'])
+       sitePriv = SitePrivilege.objects.filter(site=user.site)
+       userId = user.id
+       userUrl = "http://"+request.get_host()+"/admin/core/user/"+str(userId)
+       for sp in sitePriv:
+               subject, from_email, to = 'Authorize OpenCloud User Account', 'support@opencloud.us', str(sp.user)
+               text_content = 'This is an important message.'
+               html_content = """<p>Please authorize the following user on site """+site+""": <br><br>User: """+firstname+""" """+lastname+"""<br>Email: """+email+"""<br><br>
+Check the checkbox next to Is Active property at <a href="""+userUrl+"""> this link</a> to authorize the user, and then click the Save button. If you do not recognize this individual, or otherwise do not want to approve this account, please ignore this email. If you do not approve this request in 48 hours, the account will automatically be deleted.</p>"""
+               msg = EmailMultiAlternatives(subject,text_content, from_email, [to])
+               msg.attach_alternative(html_content, "text/html")
+               msg.send()
+        return HttpResponse(serializers.serialize("json",[user,]), content_type='application/javascript')
 
 class TenantCreateSlice(View):
     def post(self, request, *args, **kwargs):
@@ -15,11 +66,12 @@ class TenantCreateSlice(View):
         networkPorts = request.POST.get("network","0")
         mountDataSets = request.POST.get("mountDataSets","0")
         privateVolume = request.POST.get("privateVolume","0")
+        userEmail = request.POST.get("userEmail","0")
         if (actionToDo == "add"):
            serviceClass = ServiceClass.objects.get(name=serviceClass)
            site = request.user.site
            image = Image.objects.get(name=imageName)
-           newSlice = Slice(name=sliceName,serviceClass=serviceClass,site=site,imagePreference=image,mountDataSets=mountDataSets)
+           newSlice = Slice(name=sliceName,serviceClass=serviceClass,site=site,image_preference=image,mount_data_sets=mountDataSets)
            newSlice.save()
           privateTemplate="Private"
           publicTemplate="Public shared IPv4"\r
@@ -31,7 +83,20 @@ class TenantCreateSlice(View):
           addOrModifyPorts(networkPorts,sliceName)\r
           if privateVolume=="true":\r
                privateVolForSlice(request.user,sliceName)
-        return HttpResponse(json.dumps("Slice created"), mimetype='application/javascript')
+          slicePrivs=SlicePrivilege(user=User.objects.get(email=userEmail),slice=Slice.objects.get(name=sliceName),role=SliceRole.objects.get(role="admin"))
+           slicePrivs.save()
+        return HttpResponse(json.dumps("Slice created"), content_type='application/javascript')
+
+class TenantAddUser(View):
+    def post(self, request, *args, **kwargs):
+        if request.user.isReadOnlyUser():
+            return HttpResponseForbidden("User is in read-only mode")
+
+        sliceName = request.POST.get("sliceName", "0")
+        userEmail = request.POST.get("userEmail","0")
+        slicePrivs=SlicePrivilege(user=User.objects.get(email=userEmail),slice=Slice.objects.get(name=sliceName),role=SliceRole.objects.get(role="admin"))
+        slicePrivs.save()
+        return HttpResponse(json.dumps("Slice created"), content_type='application/javascript')
 
 def privateVolForSlice(user,sliceName):
        if not hasPrivateVolume(sliceName):\r
@@ -57,14 +122,14 @@ class TenantUpdateSlice(View):
                 if(entry.name==sliceName):\r
                          if (actionToDo == "update"):\r
                                 setattr(entry,'serviceClass',serviceClass)\r
-                                setattr(entry,'imagePreference',imageName)\r
-                                setattr(entry,'mountDataSets',dataSet)\r
+                                setattr(entry,'image_preference',imageName)\r
+                                setattr(entry,'mount_data_sets',dataSet)\r
                                 entry.save()\r
                                 break\r
        addOrModifyPorts(networkPorts,sliceName)\r
        if privateVolume=="true":\r
                 privateVolForSlice(request.user,sliceName)\r
-        return HttpResponse(json.dumps("Slice updated"), mimetype='application/javascript')\r
+        return HttpResponse(json.dumps("Slice updated"), content_type='application/javascript')\r
 \r
 def addNetwork(name,template,sliceName):\r
        networkTemplate=NetworkTemplate.objects.get(name=template)\r
@@ -103,41 +168,61 @@ def getTenantSliceInfo(user, tableFormat = False):
     tenantSliceDetails['sliceServiceClass']=userSliceTableFormatter(tenantServiceClassData)
     tenantSliceDetails['image']=userSliceTableFormatter(getImageInfo(user))
     tenantSliceDetails['deploymentSites']=userSliceTableFormatter(getDeploymentSites())
-    tenantSliceDetails['sites'] = userSliceTableFormatter(getTenantSitesInfo())
+    #tenantSliceDetails['sites'] = userSliceTableFormatter(getTenantSitesInfo())
     tenantSliceDetails['mountDataSets'] = userSliceTableFormatter(getMountDataSets())
     tenantSliceDetails['publicKey'] = getPublicKey(user)
+    tenantSliceDetails['availableSites']=userSliceTableFormatter(getAvailableSites())
+    tenantSliceDetails['role']=getUserRole(user)
+    tenantSliceDetails['siteUsers']=getSiteUsers(user)
     return tenantSliceDetails
 
+def getSiteUsers(user):
+       users = User.objects.filter(site=user.site)
+       siteUsers=[]
+        for entry in users:
+               siteUsers.append(str(entry))
+       return siteUsers
+
+
+def getUserRole(user):
+       sp=SitePrivilege.objects.filter(user=user)
+       for entry in sp:
+               return str(entry.role)
+
+
 def getTenantInfo(user):
     slices =Slice.objects.all()
     userSliceInfo = []
     for entry in slices:
-       sliceName = Slice.objects.get(id=entry.id).name
-       slice = Slice.objects.get(name=Slice.objects.get(id=entry.id).name)
-       sliceServiceClass = entry.serviceClass.name
-       preferredImage =  entry.imagePreference
-       #sliceDataSet = entry.mountDataSets
-       sliceNetwork = {}
-       numSliver = 0
-       sliceImage=""
-       sliceSite = {}
-       sliceNode = {}
-       sliceInstance= {}
-       #createPrivateVolume(user,sliceName)
-       for sliver in slice.slivers.all():
-           if sliver.node.site.name in BLESSED_SITES:
-                sliceSite[sliver.node.site.name] = sliceSite.get(sliver.node.site.name,0) + 1
-                sliceImage = sliver.image.name
-                sliceNode[str(sliver)] = sliver.node.name
-       numSliver = sum(sliceSite.values())
-       numSites = len(sliceSite)
-       userSliceInfo.append({'sliceName': sliceName,'sliceServiceClass': sliceServiceClass,'preferredImage':preferredImage,'numOfSites':numSites, 'sliceSite':sliceSite,'sliceImage':sliceImage,'numOfSlivers':numSliver,'instanceNodePair':sliceNode})
+       if (entry.site == user.site):
+           sliceName = Slice.objects.get(id=entry.id).name
+           slice = Slice.objects.get(name=Slice.objects.get(id=entry.id).name)
+           sliceServiceClass = entry.serviceClass.name
+           preferredImage =  entry.image_preference
+           #sliceDataSet = entry.mount_data_sets
+           sliceNetwork = {}
+           numSliver = 0
+           sliceImage=""
+           sliceSite = {}
+           sliceNode = {}
+           sliceInstance= {}
+           #createPrivateVolume(user,sliceName)
+           available_sites = getAvailableSites()
+           for sliver in slice.slivers.all():
+                if sliver.node.site.name in available_sites:
+                    sliceSite[sliver.node.site.name] = sliceSite.get(sliver.node.site.name,0) + 1
+                    sliceImage = sliver.image.name
+                    sliceNode[str(sliver)] = sliver.node.name
+           numSliver = sum(sliceSite.values())
+           numSites = len(sliceSite)
+           userSliceInfo.append({'sliceName': sliceName,'sliceServiceClass': sliceServiceClass,'preferredImage':preferredImage,'numOfSites':numSites, 'sliceSite':sliceSite,'sliceImage':sliceImage,'numOfSlivers':numSliver,'instanceNodePair':sliceNode})
     return userSliceInfo
 
 def getTenantSitesInfo():
+        availableSites=getAvailableSites()
        tenantSiteInfo=[]
         for entry in Site.objects.all():
-            if entry.name in BLESSED_SITES:
+            if entry.name in availableSites:
                 tenantSiteInfo.append({'siteName':entry.name})
        return tenantSiteInfo
 
@@ -156,12 +241,23 @@ def getServiceClassInfo(user):
     return sliceInfo
 
 def getImageInfo(user):
-    imageList = Image.objects.all()
-    #imageList = ['Fedora 16 LXC rev 1.3','Hadoop','MPI']
+    #imageList = Image.objects.all()
+    #imageInfo = []
+    #for imageEntry in imageList:
+          #imageInfo.append({'Image':imageEntry.name})
     imageInfo = []
-    for imageEntry in imageList:
-          imageInfo.append({'Image':imageEntry.name})
-          #imageInfo.append({'Image':imageEntry})
+    tempImageInfo = []
+    length = len(BLESSED_DEPLOYMENTS)
+    for deployment in Deployment.objects.all():
+        if deployment.name in BLESSED_DEPLOYMENTS:
+            for x in deployment.imagedeployments.all():
+                tempImageInfo.append(x.image.name)
+    temp = {}
+    for i in set(tempImageInfo):
+       temp[i] = tempImageInfo.count(i)
+    for key in temp:
+       if temp[key]>1:
+               imageInfo.append(key)
     return imageInfo
 
 def createPrivateVolume(user, sliceName):
@@ -228,6 +324,15 @@ def getDeploymentSites():
         deploymentInfo.append({'DeploymentSite':entry.name})
     return deploymentInfo
 
+def getAvailableSites():
+    available_sites = []
+    for deployment in Deployment.objects.all():
+        if deployment.name in BLESSED_DEPLOYMENTS:
+            for x in deployment.sitedeployments.all():
+               if x.site.nodes.all():
+                       available_sites.append(x.site.name)
+    return list(set(available_sites))
+
 class TenantDeleteSliceView(View):
         def post(self,request):\r
                 if request.user.isReadOnlyUser():\r
@@ -237,7 +342,7 @@ class TenantDeleteSliceView(View):
                 #print slice, slice.id\r
                 sliceToDel=Slice(name=sliceName, id=slice.id)\r
                 sliceToDel.delete()
-                return HttpResponse(json.dumps("Slice deleted"), mimetype='application/javascript')
+                return HttpResponse(json.dumps("Slice deleted"), content_type='application/javascript')
 
 class TenantAddOrRemoveSliverView(View):
     """ Add or remove slivers from a Slice
@@ -260,12 +365,14 @@ class TenantAddOrRemoveSliverView(View):
         actionToDo = request.POST.get("actionToDo", None)
         count = int(request.POST.get("count","0"))
        sliceName = request.POST.get("slice", None)
+       imageName = request.POST.get("image",None)
         noAct = request.POST.get("noAct", False)
 
         if not sliceName:
             return HttpResponseServerError("No slice name given")
 
         slice = Slice.objects.get(name=sliceName)
+       image = Image.objects.get(name=imageName)
 
         if siteName:
             siteList = [Site.objects.get(name=siteName)]
@@ -277,13 +384,13 @@ class TenantAddOrRemoveSliverView(View):
             if (siteList is None):
                 siteList = tenant_pick_sites(user, user_ip, slice, count)
 
-            sitesChanged = slice_increase_slivers(request.user, user_ip, siteList, slice, count, noAct)
+            sitesChanged = slice_increase_slivers(request.user, user_ip, siteList, slice, image, count, noAct)
         elif (actionToDo == "rem"):
             sitesChanged = slice_decrease_slivers(request.user, siteList, slice, count, noAct)
         else:
             return HttpResponseServerError("Unknown actionToDo %s" % actionToDo)
 
-        return HttpResponse(json.dumps(sitesChanged), mimetype='application/javascript')
+        return HttpResponse(json.dumps(sitesChanged), content_type='application/javascript')
 
     def get(self, request, *args, **kwargs):
         request.POST = request.GET
@@ -300,7 +407,7 @@ class TenantPickSitesView(View):
         ip = request.GET.get("ip", get_ip(request))
         sites = tenant_pick_sites(request.user, user_ip=ip, count=0, slice=slice)
         sites = [x.name for x in sites]
-        return HttpResponse(json.dumps(sites), mimetype='application/javascript')
+        return HttpResponse(json.dumps(sites), content_type='application/javascript')
 
 def siteSortKey(site, slice=None, count=None, lat=None, lon=None):
     # try to pick a site we're already using
@@ -328,12 +435,17 @@ def tenant_pick_sites(user, user_ip=None, slice=None, count=None):
         print "exception in geo code"
         traceback.print_exc()
 
+    available_sites = getAvailableSites()
     sites = Site.objects.all()
-    sites = [x for x in sites if x.name in BLESSED_SITES]
+    sites = [x for x in sites if x.name in available_sites]
     sites = sorted(sites, key=functools.partial(siteSortKey, slice=slice, count=count, lat=lat, lon=lon))
 
     return sites
 
 class TenantViewData(View):
     def get(self, request, **kwargs):
-        return HttpResponse(json.dumps(getTenantSliceInfo(request.user, True)), mimetype='application/javascript')
+        return HttpResponse(json.dumps(getTenantSliceInfo(request.user, True)), content_type='application/javascript')
+
+class RequestAccountView(View):
+    def get(self, request, **kwargs):
+        return HttpResponse()