1 from view_common import *
4 BLESSED_SITES = ["Stanford", "Washington", "Princeton", "GeorgiaTech", "MaxPlanck"]
6 class TenantCreateSlice(View):
7 def post(self, request, *args, **kwargs):
8 if request.user.isReadOnlyUser():
9 return HttpResponseForbidden("User is in read-only mode")
11 sliceName = request.POST.get("sliceName", "0")
12 serviceClass = request.POST.get("serviceClass", "0")
13 imageName = request.POST.get("imageName", "0")
14 actionToDo = request.POST.get("actionToDo", "0")
15 networkPorts = request.POST.get("network","0")
16 mountDataSets = request.POST.get("mountDataSets","0")
17 privateVolume = request.POST.get("privateVolume","0")
18 if (actionToDo == "add"):
19 serviceClass = ServiceClass.objects.get(name=serviceClass)
20 site = request.user.site
21 image = Image.objects.get(name=imageName)
22 newSlice = Slice(name=sliceName,serviceClass=serviceClass,site=site,imagePreference=image,mountDataSets=mountDataSets)
24 privateTemplate="Private"
25 publicTemplate="Public shared IPv4"
\r
26 privateNetworkName = sliceName+"-"+privateTemplate
\r
27 publicNetworkName = sliceName+"-"+publicTemplate
\r
28 slice=Slice.objects.get(name=sliceName)
\r
29 addNetwork(privateNetworkName,privateTemplate,slice)
\r
30 addNetwork(publicNetworkName,publicTemplate,slice)
\r
31 addOrModifyPorts(networkPorts,sliceName)
\r
32 if privateVolume=="true":
\r
33 privateVolForSlice(request.user,sliceName)
34 return HttpResponse(json.dumps("Slice created"), content_type='application/javascript')
36 def privateVolForSlice(user,sliceName):
37 if not hasPrivateVolume(sliceName):
\r
38 volumeName=createPrivateVolume(user,sliceName)
\r
40 mountVolume(sliceName,volumeName,readWrite)
42 class TenantUpdateSlice(View):
43 def post(self, request, *args, **kwargs):
\r
44 if request.user.isReadOnlyUser():
\r
45 return HttpResponseForbidden("User is in read-only mode")
\r
47 sliceName = request.POST.get("sliceName", "0")
\r
48 serviceClass = request.POST.get("serviceClass", "0")
\r
49 imageName = request.POST.get("imageName", "0")
\r
50 actionToDo = request.POST.get("actionToDo", "0")
\r
51 networkPorts = request.POST.get("networkPorts","0")
\r
52 dataSet = request.POST.get("dataSet","0")
\r
53 privateVolume = request.POST.get("privateVolume","0")
\r
54 slice = Slice.objects.all()
\r
56 serviceClass = ServiceClass.objects.get(name=serviceClass)
\r
57 if(entry.name==sliceName):
\r
58 if (actionToDo == "update"):
\r
59 setattr(entry,'serviceClass',serviceClass)
\r
60 setattr(entry,'imagePreference',imageName)
\r
61 setattr(entry,'mountDataSets',dataSet)
\r
64 addOrModifyPorts(networkPorts,sliceName)
\r
65 if privateVolume=="true":
\r
66 privateVolForSlice(request.user,sliceName)
\r
67 return HttpResponse(json.dumps("Slice updated"), content_type='application/javascript')
\r
69 def addNetwork(name,template,sliceName):
\r
70 networkTemplate=NetworkTemplate.objects.get(name=template)
\r
71 newNetwork = Network(name = name,
\r
72 template = networkTemplate,
\r
75 addNetworkSlice(newNetwork,sliceName)
\r
77 def addNetworkSlice(networkSlice,sliceName):
\r
78 newNetworkSlice=NetworkSlice(network =networkSlice,
\r
80 newNetworkSlice.save()
\r
82 def addOrModifyPorts(networkPorts,sliceName):
\r
83 networkList = Network.objects.all()
\r
86 for networkEntry in networkList:
\r
87 networkSlices = networkEntry.slices.all()
\r
88 for slice in networkSlices:
\r
89 if slice.name==sliceName:
\r
90 if networkEntry.template.name=="Public shared IPv4":
\r
91 setattr(networkEntry,'ports',networkPorts)
\r
94 def getTenantSliceInfo(user, tableFormat = False):
95 tenantSliceDetails = {}
96 tenantSliceData = getTenantInfo(user)
97 tenantServiceClassData = getServiceClassInfo(user)
99 tenantSliceDetails['userSliceInfo'] = userSliceTableFormatter(tenantSliceData)
100 tenantSliceDetails['sliceServiceClass']=userSliceTableFormatter(tenantServiceClassData)
102 tenantSliceDetails['userSliceInfo'] = tenantSliceData
103 tenantSliceDetails['sliceServiceClass']=userSliceTableFormatter(tenantServiceClassData)
104 tenantSliceDetails['image']=userSliceTableFormatter(getImageInfo(user))
105 tenantSliceDetails['deploymentSites']=userSliceTableFormatter(getDeploymentSites())
106 tenantSliceDetails['sites'] = userSliceTableFormatter(getTenantSitesInfo())
107 tenantSliceDetails['mountDataSets'] = userSliceTableFormatter(getMountDataSets())
108 tenantSliceDetails['publicKey'] = getPublicKey(user)
109 return tenantSliceDetails
111 def getTenantInfo(user):
112 slices =Slice.objects.all()
115 sliceName = Slice.objects.get(id=entry.id).name
116 slice = Slice.objects.get(name=Slice.objects.get(id=entry.id).name)
117 sliceServiceClass = entry.serviceClass.name
118 preferredImage = entry.imagePreference
119 #sliceDataSet = entry.mountDataSets
126 #createPrivateVolume(user,sliceName)
127 for sliver in slice.slivers.all():
128 if sliver.node.site.name in BLESSED_SITES:
129 sliceSite[sliver.node.site.name] = sliceSite.get(sliver.node.site.name,0) + 1
130 sliceImage = sliver.image.name
131 sliceNode[str(sliver)] = sliver.node.name
132 numSliver = sum(sliceSite.values())
133 numSites = len(sliceSite)
134 userSliceInfo.append({'sliceName': sliceName,'sliceServiceClass': sliceServiceClass,'preferredImage':preferredImage,'numOfSites':numSites, 'sliceSite':sliceSite,'sliceImage':sliceImage,'numOfSlivers':numSliver,'instanceNodePair':sliceNode})
137 def getTenantSitesInfo():
139 for entry in Site.objects.all():
140 if entry.name in BLESSED_SITES:
141 tenantSiteInfo.append({'siteName':entry.name})
142 return tenantSiteInfo
144 def getPublicKey(user):
145 users=User.objects.all()
\r
147 if (str(key.email)==str(user)):
\r
148 sshKey = key.public_key
\r
151 def getServiceClassInfo(user):
152 serviceClassList = ServiceClass.objects.all()
154 for entry in serviceClassList:
155 sliceInfo.append({'serviceClass':entry.name})
158 def getImageInfo(user):
159 imageList = Image.objects.all()
160 #imageList = ['Fedora 16 LXC rev 1.3','Hadoop','MPI']
162 for imageEntry in imageList:
163 imageInfo.append({'Image':imageEntry.name})
164 #imageInfo.append({'Image':imageEntry})
167 def createPrivateVolume(user, sliceName):
168 caps = Volume.CAP_READ_DATA | Volume.CAP_WRITE_DATA | Volume.CAP_HOST_DATA
169 getattr(Volume.default_gateway_caps,"read data") | \
170 getattr(Volume.default_gateway_caps,"write data") | \
171 getattr(Volume.default_gateway_caps,"host files")
172 v = Volume(name="private_" + sliceName, owner_id=user, description="private volume for %s" % sliceName, blocksize=61440, private=True, archive=False, default_gateway_caps = caps)
176 SYNDICATE_REPLICATE_PORTNUM = 1025
180 inuse[SYNDICATE_REPLICATE_PORTNUM] = True
181 for vs in VolumeSlice.objects.all():
182 inuse[vs.peer_portnum]=True
183 inuse[vs.replicate_portnum]=True
184 for network in Network.objects.all():
185 if not network.ports:
187 network_ports = [x.strip() for x in network.ports.split(",")]
188 for network_port in network_ports:
190 inuse[int(network_port)] = True
192 # in case someone has put a malformed port number in the list
194 for i in range(1025, 65535):
195 if not inuse.get(i,False):
199 def mountVolume(sliceName, volumeName, readWrite):
200 slice = Slice.objects.get(name=sliceName)
201 volume = Volume.objects.get(name=volumeName)
202 # choose some unused port numbers
203 flags = Volume.CAP_READ_DATA
205 flags = flags | Volume.CAP_WRITE_DATA
206 vs = VolumeSlice(volume_id = volume, slice_id = slice, gateway_caps=flags, peer_portnum = get_free_port(), replicate_portnum = SYNDICATE_REPLICATE_PORTNUM)
209 def hasPrivateVolume(sliceName):
210 slice = Slice.objects.get(name=sliceName)
211 for vs in VolumeSlice.objects.filter(slice_id=slice):
212 if vs.volume_id.private:
216 def getMountDataSets():
218 for volume in Volume.objects.all():
\r
219 if not volume.private:
\r
220 dataSetInfo.append({'DataSet': volume.name})
\r
224 def getDeploymentSites():
225 deploymentList = Deployment.objects.all()
227 for entry in deploymentList:
228 deploymentInfo.append({'DeploymentSite':entry.name})
229 return deploymentInfo
231 class TenantDeleteSliceView(View):
232 def post(self,request):
\r
233 if request.user.isReadOnlyUser():
\r
234 return HttpResponseForbidden("User is in read-only mode")
\r
235 sliceName = request.POST.get("sliceName",None)
\r
236 slice = Slice.objects.get(name=sliceName)
\r
237 #print slice, slice.id
\r
238 sliceToDel=Slice(name=sliceName, id=slice.id)
\r
240 return HttpResponse(json.dumps("Slice deleted"), content_type='application/javascript')
242 class TenantAddOrRemoveSliverView(View):
243 """ Add or remove slivers from a Slice
246 siteName - name of site. If not specified, PlanetStack will pick the
248 actionToDo - [add | rem]
249 count - number of slivers to add or remove
250 sliceName - name of slice
251 noAct - if set, no changes will be made to db, but result will still
252 show which sites would have been modified.
255 Dictionary of sites that were modified, and the count of nodes
256 that were added or removed at each site.
258 def post(self, request, *args, **kwargs):
259 siteName = request.POST.get("siteName", None)
260 actionToDo = request.POST.get("actionToDo", None)
261 count = int(request.POST.get("count","0"))
262 sliceName = request.POST.get("slice", None)
263 noAct = request.POST.get("noAct", False)
266 return HttpResponseServerError("No slice name given")
268 slice = Slice.objects.get(name=sliceName)
271 siteList = [Site.objects.get(name=siteName)]
275 if (actionToDo == "add"):
276 user_ip = request.GET.get("ip", get_ip(request))
277 if (siteList is None):
278 siteList = tenant_pick_sites(user, user_ip, slice, count)
280 sitesChanged = slice_increase_slivers(request.user, user_ip, siteList, slice, count, noAct)
281 elif (actionToDo == "rem"):
282 sitesChanged = slice_decrease_slivers(request.user, siteList, slice, count, noAct)
284 return HttpResponseServerError("Unknown actionToDo %s" % actionToDo)
286 return HttpResponse(json.dumps(sitesChanged), content_type='application/javascript')
288 def get(self, request, *args, **kwargs):
289 request.POST = request.GET
290 return self.post(request, *args, **kwargs) # for testing REST in browser
291 #return HttpResponseServerError("GET is not supported")
293 class TenantPickSitesView(View):
294 """ primarily just for testing purposes """
295 def get(self, request, *args, **kwargs):
296 count = request.GET.get("count","0")
297 slice = request.GET.get("slice",None)
299 slice = Slice.objects.get(name=slice)
300 ip = request.GET.get("ip", get_ip(request))
301 sites = tenant_pick_sites(request.user, user_ip=ip, count=0, slice=slice)
302 sites = [x.name for x in sites]
303 return HttpResponse(json.dumps(sites), content_type='application/javascript')
305 def siteSortKey(site, slice=None, count=None, lat=None, lon=None):
306 # try to pick a site we're already using
307 has_slivers_here=False
309 for sliver in slice.slivers.all():
310 if sliver.node.site.name == site.name:
311 has_slivers_here=True
314 d = haversine(site.location.latitude, site.location.longitude, lat, lon)
316 return (-has_slivers_here, d)
318 def tenant_pick_sites(user, user_ip=None, slice=None, count=None):
319 """ Returns list of sites, sorted from most favorable to least favorable """
323 client_geo = GeoIP().city(user_ip)
325 lat=float(client_geo["latitude"])
326 lon=float(client_geo["longitude"])
328 print "exception in geo code"
329 traceback.print_exc()
331 sites = Site.objects.all()
332 sites = [x for x in sites if x.name in BLESSED_SITES]
333 sites = sorted(sites, key=functools.partial(siteSortKey, slice=slice, count=count, lat=lat, lon=lon))
337 class TenantViewData(View):
338 def get(self, request, **kwargs):
339 return HttpResponse(json.dumps(getTenantSliceInfo(request.user, True)), content_type='application/javascript')