Scott Baker | c7325a4 | 2014-05-30 16:06:46 -0700 | [diff] [blame] | 1 | from view_common import * |
Scott Baker | 866c5b3 | 2014-08-29 11:34:00 -0700 | [diff] [blame] | 2 | from core.models import * |
Scott Baker | c7325a4 | 2014-05-30 16:06:46 -0700 | [diff] [blame] | 3 | import functools |
Scott Baker | 866c5b3 | 2014-08-29 11:34:00 -0700 | [diff] [blame] | 4 | from django.contrib.auth.models import BaseUserManager |
| 5 | from django.core import serializers |
| 6 | from django.core.mail import EmailMultiAlternatives |
Scott Baker | 3dfb6cb | 2015-01-28 16:03:40 -0800 | [diff] [blame] | 7 | import json |
Scott Baker | c7325a4 | 2014-05-30 16:06:46 -0700 | [diff] [blame] | 8 | |
Scott Baker | 866c5b3 | 2014-08-29 11:34:00 -0700 | [diff] [blame] | 9 | BLESSED_DEPLOYMENTS = ["US-MaxPlanck", "US-GeorgiaTech", "US-Princeton", "US-Washington", "US-Stanford"] |
| 10 | |
| 11 | class RequestAccessView(View): |
| 12 | def post(self, request, *args, **kwargs): |
| 13 | email = request.POST.get("email", "0") |
| 14 | firstname = request.POST.get("firstname", "0") |
| 15 | lastname = request.POST.get("lastname", "0") |
| 16 | site = request.POST.get("site","0") |
Scott Baker | 3dfb6cb | 2015-01-28 16:03:40 -0800 | [diff] [blame] | 17 | # see if it already exists |
| 18 | user=User.objects.filter(email=BaseUserManager.normalize_email(email)) |
| 19 | if (user): |
| 20 | user = user[0] |
| 21 | if user.is_active: |
| 22 | # force a new email to be sent |
| 23 | user.is_registering=True |
| 24 | user.save() |
| 25 | return HttpResponse(json.dumps({"error": "already_approved"}), content_type='application/javascript') |
| 26 | else: |
| 27 | return HttpResponse(json.dumps({"error": "already_pending"}), content_type='application/javascript') |
| 28 | |
Scott Baker | 361a0bd | 2015-01-28 16:11:35 -0800 | [diff] [blame] | 29 | user=User.deleted_objects.filter(email=BaseUserManager.normalize_email(email)) |
| 30 | if (user): |
| 31 | return HttpResponse(json.dumps({"error": "is_deleted"}), content_type='application/javascript') |
| 32 | |
Scott Baker | 866c5b3 | 2014-08-29 11:34:00 -0700 | [diff] [blame] | 33 | user = User( |
| 34 | email=BaseUserManager.normalize_email(email), |
| 35 | firstname=firstname, |
| 36 | lastname=lastname, |
Scott Baker | 73244b6 | 2015-01-27 23:07:51 -0800 | [diff] [blame] | 37 | is_active=False, |
Scott Baker | 3dfb6cb | 2015-01-28 16:03:40 -0800 | [diff] [blame] | 38 | is_admin=False, |
| 39 | is_registering=True |
Scott Baker | 866c5b3 | 2014-08-29 11:34:00 -0700 | [diff] [blame] | 40 | ) |
| 41 | user.save() |
| 42 | user.site=Site.objects.get(name=site) |
| 43 | user.save(update_fields=['site']) |
| 44 | sitePriv = SitePrivilege.objects.filter(site=user.site) |
| 45 | userId = user.id |
| 46 | userUrl = "http://"+request.get_host()+"/admin/core/user/"+str(userId) |
| 47 | for sp in sitePriv: |
| 48 | subject, from_email, to = 'Authorize OpenCloud User Account', 'support@opencloud.us', str(sp.user) |
| 49 | text_content = 'This is an important message.' |
| 50 | html_content = """<p>Please authorize the following user on site """+site+""": <br><br>User: """+firstname+""" """+lastname+"""<br>Email: """+email+"""<br><br> |
Scott Baker | baf0026 | 2015-01-28 16:38:05 -0800 | [diff] [blame] | 51 | 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>""" |
Scott Baker | 866c5b3 | 2014-08-29 11:34:00 -0700 | [diff] [blame] | 52 | msg = EmailMultiAlternatives(subject,text_content, from_email, [to]) |
| 53 | msg.attach_alternative(html_content, "text/html") |
| 54 | msg.send() |
| 55 | return HttpResponse(serializers.serialize("json",[user,]), content_type='application/javascript') |
Scott Baker | c7325a4 | 2014-05-30 16:06:46 -0700 | [diff] [blame] | 56 | |
| 57 | class TenantCreateSlice(View): |
| 58 | def post(self, request, *args, **kwargs): |
| 59 | if request.user.isReadOnlyUser(): |
| 60 | return HttpResponseForbidden("User is in read-only mode") |
| 61 | |
| 62 | sliceName = request.POST.get("sliceName", "0") |
| 63 | serviceClass = request.POST.get("serviceClass", "0") |
| 64 | imageName = request.POST.get("imageName", "0") |
| 65 | actionToDo = request.POST.get("actionToDo", "0") |
| 66 | networkPorts = request.POST.get("network","0") |
| 67 | mountDataSets = request.POST.get("mountDataSets","0") |
| 68 | privateVolume = request.POST.get("privateVolume","0") |
Scott Baker | 866c5b3 | 2014-08-29 11:34:00 -0700 | [diff] [blame] | 69 | userEmail = request.POST.get("userEmail","0") |
Scott Baker | c7325a4 | 2014-05-30 16:06:46 -0700 | [diff] [blame] | 70 | if (actionToDo == "add"): |
| 71 | serviceClass = ServiceClass.objects.get(name=serviceClass) |
| 72 | site = request.user.site |
| 73 | image = Image.objects.get(name=imageName) |
Scott Baker | ffce785 | 2015-01-03 16:26:38 -0800 | [diff] [blame] | 74 | newSlice = Slice(name=sliceName,serviceClass=serviceClass,site=site,image_preference=image,mount_data_sets=mountDataSets) |
Scott Baker | c7325a4 | 2014-05-30 16:06:46 -0700 | [diff] [blame] | 75 | newSlice.save() |
| 76 | privateTemplate="Private" |
| 77 | publicTemplate="Public shared IPv4"
|
| 78 | privateNetworkName = sliceName+"-"+privateTemplate
|
| 79 | publicNetworkName = sliceName+"-"+publicTemplate
|
| 80 | slice=Slice.objects.get(name=sliceName)
|
| 81 | addNetwork(privateNetworkName,privateTemplate,slice)
|
| 82 | addNetwork(publicNetworkName,publicTemplate,slice)
|
| 83 | addOrModifyPorts(networkPorts,sliceName)
|
| 84 | if privateVolume=="true":
|
| 85 | privateVolForSlice(request.user,sliceName) |
Scott Baker | 866c5b3 | 2014-08-29 11:34:00 -0700 | [diff] [blame] | 86 | slicePrivs=SlicePrivilege(user=User.objects.get(email=userEmail),slice=Slice.objects.get(name=sliceName),role=SliceRole.objects.get(role="admin")) |
| 87 | slicePrivs.save() |
| 88 | return HttpResponse(json.dumps("Slice created"), content_type='application/javascript') |
| 89 | |
| 90 | class TenantAddUser(View): |
| 91 | def post(self, request, *args, **kwargs): |
| 92 | if request.user.isReadOnlyUser(): |
| 93 | return HttpResponseForbidden("User is in read-only mode") |
| 94 | |
| 95 | sliceName = request.POST.get("sliceName", "0") |
| 96 | userEmail = request.POST.get("userEmail","0") |
| 97 | slicePrivs=SlicePrivilege(user=User.objects.get(email=userEmail),slice=Slice.objects.get(name=sliceName),role=SliceRole.objects.get(role="admin")) |
| 98 | slicePrivs.save() |
Scott Baker | 823b721 | 2014-06-16 10:25:39 -0700 | [diff] [blame] | 99 | return HttpResponse(json.dumps("Slice created"), content_type='application/javascript') |
Scott Baker | c7325a4 | 2014-05-30 16:06:46 -0700 | [diff] [blame] | 100 | |
| 101 | def privateVolForSlice(user,sliceName): |
| 102 | if not hasPrivateVolume(sliceName):
|
| 103 | volumeName=createPrivateVolume(user,sliceName)
|
| 104 | readWrite="true"
|
| 105 | mountVolume(sliceName,volumeName,readWrite) |
| 106 | |
| 107 | class TenantUpdateSlice(View): |
| 108 | def post(self, request, *args, **kwargs):
|
| 109 | if request.user.isReadOnlyUser():
|
| 110 | return HttpResponseForbidden("User is in read-only mode")
|
| 111 |
|
| 112 | sliceName = request.POST.get("sliceName", "0")
|
| 113 | serviceClass = request.POST.get("serviceClass", "0")
|
| 114 | imageName = request.POST.get("imageName", "0")
|
| 115 | actionToDo = request.POST.get("actionToDo", "0")
|
| 116 | networkPorts = request.POST.get("networkPorts","0")
|
| 117 | dataSet = request.POST.get("dataSet","0")
|
| 118 | privateVolume = request.POST.get("privateVolume","0")
|
| 119 | slice = Slice.objects.all()
|
| 120 | for entry in slice:
|
| 121 | serviceClass = ServiceClass.objects.get(name=serviceClass)
|
| 122 | if(entry.name==sliceName):
|
| 123 | if (actionToDo == "update"):
|
| 124 | setattr(entry,'serviceClass',serviceClass)
|
Scott Baker | ffce785 | 2015-01-03 16:26:38 -0800 | [diff] [blame] | 125 | setattr(entry,'image_preference',imageName)
|
| 126 | setattr(entry,'mount_data_sets',dataSet)
|
Scott Baker | c7325a4 | 2014-05-30 16:06:46 -0700 | [diff] [blame] | 127 | entry.save()
|
| 128 | break
|
| 129 | addOrModifyPorts(networkPorts,sliceName)
|
| 130 | if privateVolume=="true":
|
| 131 | privateVolForSlice(request.user,sliceName)
|
Scott Baker | 823b721 | 2014-06-16 10:25:39 -0700 | [diff] [blame] | 132 | return HttpResponse(json.dumps("Slice updated"), content_type='application/javascript')
|
Scott Baker | c7325a4 | 2014-05-30 16:06:46 -0700 | [diff] [blame] | 133 |
|
| 134 | def addNetwork(name,template,sliceName):
|
| 135 | networkTemplate=NetworkTemplate.objects.get(name=template)
|
| 136 | newNetwork = Network(name = name,
|
| 137 | template = networkTemplate,
|
| 138 | owner = sliceName)
|
| 139 | newNetwork.save()
|
| 140 | addNetworkSlice(newNetwork,sliceName)
|
| 141 |
|
| 142 | def addNetworkSlice(networkSlice,sliceName):
|
| 143 | newNetworkSlice=NetworkSlice(network =networkSlice,
|
| 144 | slice=sliceName)
|
| 145 | newNetworkSlice.save()
|
| 146 |
|
| 147 | def addOrModifyPorts(networkPorts,sliceName):
|
| 148 | networkList = Network.objects.all()
|
| 149 | networkInfo = []
|
| 150 | if networkPorts:
|
| 151 | for networkEntry in networkList:
|
| 152 | networkSlices = networkEntry.slices.all()
|
| 153 | for slice in networkSlices:
|
| 154 | if slice.name==sliceName:
|
| 155 | if networkEntry.template.name=="Public shared IPv4":
|
| 156 | setattr(networkEntry,'ports',networkPorts)
|
| 157 | networkEntry.save()
|
| 158 |
|
| 159 | def getTenantSliceInfo(user, tableFormat = False): |
| 160 | tenantSliceDetails = {} |
| 161 | tenantSliceData = getTenantInfo(user) |
| 162 | tenantServiceClassData = getServiceClassInfo(user) |
| 163 | if (tableFormat): |
| 164 | tenantSliceDetails['userSliceInfo'] = userSliceTableFormatter(tenantSliceData) |
| 165 | tenantSliceDetails['sliceServiceClass']=userSliceTableFormatter(tenantServiceClassData) |
| 166 | else: |
| 167 | tenantSliceDetails['userSliceInfo'] = tenantSliceData |
| 168 | tenantSliceDetails['sliceServiceClass']=userSliceTableFormatter(tenantServiceClassData) |
| 169 | tenantSliceDetails['image']=userSliceTableFormatter(getImageInfo(user)) |
| 170 | tenantSliceDetails['deploymentSites']=userSliceTableFormatter(getDeploymentSites()) |
Scott Baker | 866c5b3 | 2014-08-29 11:34:00 -0700 | [diff] [blame] | 171 | #tenantSliceDetails['sites'] = userSliceTableFormatter(getTenantSitesInfo()) |
Scott Baker | c7325a4 | 2014-05-30 16:06:46 -0700 | [diff] [blame] | 172 | tenantSliceDetails['mountDataSets'] = userSliceTableFormatter(getMountDataSets()) |
| 173 | tenantSliceDetails['publicKey'] = getPublicKey(user) |
Scott Baker | 866c5b3 | 2014-08-29 11:34:00 -0700 | [diff] [blame] | 174 | tenantSliceDetails['availableSites']=userSliceTableFormatter(getAvailableSites()) |
| 175 | tenantSliceDetails['role']=getUserRole(user) |
| 176 | tenantSliceDetails['siteUsers']=getSiteUsers(user) |
Scott Baker | c7325a4 | 2014-05-30 16:06:46 -0700 | [diff] [blame] | 177 | return tenantSliceDetails |
| 178 | |
Scott Baker | 866c5b3 | 2014-08-29 11:34:00 -0700 | [diff] [blame] | 179 | def getSiteUsers(user): |
| 180 | users = User.objects.filter(site=user.site) |
| 181 | siteUsers=[] |
| 182 | for entry in users: |
| 183 | siteUsers.append(str(entry)) |
| 184 | return siteUsers |
| 185 | |
| 186 | |
| 187 | def getUserRole(user): |
| 188 | sp=SitePrivilege.objects.filter(user=user) |
| 189 | for entry in sp: |
| 190 | return str(entry.role) |
| 191 | |
| 192 | |
Scott Baker | c7325a4 | 2014-05-30 16:06:46 -0700 | [diff] [blame] | 193 | def getTenantInfo(user): |
| 194 | slices =Slice.objects.all() |
| 195 | userSliceInfo = [] |
| 196 | for entry in slices: |
Scott Baker | 866c5b3 | 2014-08-29 11:34:00 -0700 | [diff] [blame] | 197 | if (entry.site == user.site): |
| 198 | sliceName = Slice.objects.get(id=entry.id).name |
| 199 | slice = Slice.objects.get(name=Slice.objects.get(id=entry.id).name) |
| 200 | sliceServiceClass = entry.serviceClass.name |
Scott Baker | ffce785 | 2015-01-03 16:26:38 -0800 | [diff] [blame] | 201 | preferredImage = entry.image_preference |
| 202 | #sliceDataSet = entry.mount_data_sets |
Scott Baker | 866c5b3 | 2014-08-29 11:34:00 -0700 | [diff] [blame] | 203 | sliceNetwork = {} |
| 204 | numSliver = 0 |
| 205 | sliceImage="" |
| 206 | sliceSite = {} |
| 207 | sliceNode = {} |
| 208 | sliceInstance= {} |
| 209 | #createPrivateVolume(user,sliceName) |
Scott Baker | 01ef649 | 2014-08-29 12:19:09 -0700 | [diff] [blame] | 210 | available_sites = getAvailableSites() |
Scott Baker | 866c5b3 | 2014-08-29 11:34:00 -0700 | [diff] [blame] | 211 | for sliver in slice.slivers.all(): |
| 212 | if sliver.node.site.name in available_sites: |
| 213 | sliceSite[sliver.node.site.name] = sliceSite.get(sliver.node.site.name,0) + 1 |
| 214 | sliceImage = sliver.image.name |
| 215 | sliceNode[str(sliver)] = sliver.node.name |
| 216 | numSliver = sum(sliceSite.values()) |
| 217 | numSites = len(sliceSite) |
| 218 | userSliceInfo.append({'sliceName': sliceName,'sliceServiceClass': sliceServiceClass,'preferredImage':preferredImage,'numOfSites':numSites, 'sliceSite':sliceSite,'sliceImage':sliceImage,'numOfSlivers':numSliver,'instanceNodePair':sliceNode}) |
Scott Baker | c7325a4 | 2014-05-30 16:06:46 -0700 | [diff] [blame] | 219 | return userSliceInfo |
| 220 | |
| 221 | def getTenantSitesInfo(): |
Scott Baker | 866c5b3 | 2014-08-29 11:34:00 -0700 | [diff] [blame] | 222 | availableSites=getAvailableSites() |
Scott Baker | c7325a4 | 2014-05-30 16:06:46 -0700 | [diff] [blame] | 223 | tenantSiteInfo=[] |
| 224 | for entry in Site.objects.all(): |
Scott Baker | 866c5b3 | 2014-08-29 11:34:00 -0700 | [diff] [blame] | 225 | if entry.name in availableSites: |
Scott Baker | c7325a4 | 2014-05-30 16:06:46 -0700 | [diff] [blame] | 226 | tenantSiteInfo.append({'siteName':entry.name}) |
| 227 | return tenantSiteInfo |
| 228 | |
| 229 | def getPublicKey(user): |
| 230 | users=User.objects.all()
|
| 231 | for key in users:
|
| 232 | if (str(key.email)==str(user)):
|
| 233 | sshKey = key.public_key
|
| 234 | return sshKey |
| 235 | |
| 236 | def getServiceClassInfo(user): |
| 237 | serviceClassList = ServiceClass.objects.all() |
| 238 | sliceInfo = [] |
| 239 | for entry in serviceClassList: |
| 240 | sliceInfo.append({'serviceClass':entry.name}) |
| 241 | return sliceInfo |
| 242 | |
| 243 | def getImageInfo(user): |
Scott Baker | 866c5b3 | 2014-08-29 11:34:00 -0700 | [diff] [blame] | 244 | #imageList = Image.objects.all() |
| 245 | #imageInfo = [] |
| 246 | #for imageEntry in imageList: |
| 247 | #imageInfo.append({'Image':imageEntry.name}) |
Scott Baker | c7325a4 | 2014-05-30 16:06:46 -0700 | [diff] [blame] | 248 | imageInfo = [] |
Scott Baker | 866c5b3 | 2014-08-29 11:34:00 -0700 | [diff] [blame] | 249 | tempImageInfo = [] |
| 250 | length = len(BLESSED_DEPLOYMENTS) |
| 251 | for deployment in Deployment.objects.all(): |
| 252 | if deployment.name in BLESSED_DEPLOYMENTS: |
Sapan Bhatia | a0beef8 | 2014-11-20 15:08:18 -0500 | [diff] [blame] | 253 | for x in deployment.imagedeployments.all(): |
Scott Baker | 866c5b3 | 2014-08-29 11:34:00 -0700 | [diff] [blame] | 254 | tempImageInfo.append(x.image.name) |
| 255 | temp = {} |
| 256 | for i in set(tempImageInfo): |
| 257 | temp[i] = tempImageInfo.count(i) |
| 258 | for key in temp: |
| 259 | if temp[key]>1: |
| 260 | imageInfo.append(key) |
Scott Baker | c7325a4 | 2014-05-30 16:06:46 -0700 | [diff] [blame] | 261 | return imageInfo |
| 262 | |
| 263 | def createPrivateVolume(user, sliceName): |
| 264 | caps = Volume.CAP_READ_DATA | Volume.CAP_WRITE_DATA | Volume.CAP_HOST_DATA |
| 265 | getattr(Volume.default_gateway_caps,"read data") | \ |
| 266 | getattr(Volume.default_gateway_caps,"write data") | \ |
| 267 | getattr(Volume.default_gateway_caps,"host files") |
| 268 | v = Volume(name="private_" + sliceName, owner_id=user, description="private volume for %s" % sliceName, blocksize=61440, private=True, archive=False, default_gateway_caps = caps) |
| 269 | v.save() |
| 270 | return v |
| 271 | |
| 272 | SYNDICATE_REPLICATE_PORTNUM = 1025 |
| 273 | |
| 274 | def get_free_port(): |
| 275 | inuse={} |
| 276 | inuse[SYNDICATE_REPLICATE_PORTNUM] = True |
| 277 | for vs in VolumeSlice.objects.all(): |
| 278 | inuse[vs.peer_portnum]=True |
| 279 | inuse[vs.replicate_portnum]=True |
| 280 | for network in Network.objects.all(): |
| 281 | if not network.ports: |
| 282 | continue |
| 283 | network_ports = [x.strip() for x in network.ports.split(",")] |
| 284 | for network_port in network_ports: |
| 285 | try: |
| 286 | inuse[int(network_port)] = True |
| 287 | except: |
| 288 | # in case someone has put a malformed port number in the list |
| 289 | pass |
| 290 | for i in range(1025, 65535): |
| 291 | if not inuse.get(i,False): |
| 292 | return i |
| 293 | return False |
| 294 | |
| 295 | def mountVolume(sliceName, volumeName, readWrite): |
| 296 | slice = Slice.objects.get(name=sliceName) |
| 297 | volume = Volume.objects.get(name=volumeName) |
| 298 | # choose some unused port numbers |
| 299 | flags = Volume.CAP_READ_DATA |
| 300 | if readWrite: |
| 301 | flags = flags | Volume.CAP_WRITE_DATA |
| 302 | vs = VolumeSlice(volume_id = volume, slice_id = slice, gateway_caps=flags, peer_portnum = get_free_port(), replicate_portnum = SYNDICATE_REPLICATE_PORTNUM) |
| 303 | vs.save() |
| 304 | |
| 305 | def hasPrivateVolume(sliceName): |
| 306 | slice = Slice.objects.get(name=sliceName) |
| 307 | for vs in VolumeSlice.objects.filter(slice_id=slice): |
| 308 | if vs.volume_id.private: |
| 309 | return True |
| 310 | return False |
| 311 | |
| 312 | def getMountDataSets(): |
| 313 | dataSetInfo=[]
|
| 314 | for volume in Volume.objects.all():
|
| 315 | if not volume.private:
|
| 316 | dataSetInfo.append({'DataSet': volume.name})
|
| 317 |
|
| 318 | return dataSetInfo |
| 319 | |
| 320 | def getDeploymentSites(): |
| 321 | deploymentList = Deployment.objects.all() |
| 322 | deploymentInfo = [] |
| 323 | for entry in deploymentList: |
| 324 | deploymentInfo.append({'DeploymentSite':entry.name}) |
| 325 | return deploymentInfo |
| 326 | |
Scott Baker | 866c5b3 | 2014-08-29 11:34:00 -0700 | [diff] [blame] | 327 | def getAvailableSites(): |
| 328 | available_sites = [] |
| 329 | for deployment in Deployment.objects.all(): |
| 330 | if deployment.name in BLESSED_DEPLOYMENTS: |
Sapan Bhatia | a0beef8 | 2014-11-20 15:08:18 -0500 | [diff] [blame] | 331 | for x in deployment.sitedeployments.all(): |
Scott Baker | 866c5b3 | 2014-08-29 11:34:00 -0700 | [diff] [blame] | 332 | if x.site.nodes.all(): |
| 333 | available_sites.append(x.site.name) |
| 334 | return list(set(available_sites)) |
| 335 | |
Scott Baker | c7325a4 | 2014-05-30 16:06:46 -0700 | [diff] [blame] | 336 | class TenantDeleteSliceView(View): |
| 337 | def post(self,request):
|
| 338 | if request.user.isReadOnlyUser():
|
| 339 | return HttpResponseForbidden("User is in read-only mode")
|
| 340 | sliceName = request.POST.get("sliceName",None)
|
| 341 | slice = Slice.objects.get(name=sliceName)
|
| 342 | #print slice, slice.id
|
| 343 | sliceToDel=Slice(name=sliceName, id=slice.id)
|
| 344 | sliceToDel.delete() |
Scott Baker | 823b721 | 2014-06-16 10:25:39 -0700 | [diff] [blame] | 345 | return HttpResponse(json.dumps("Slice deleted"), content_type='application/javascript') |
Scott Baker | c7325a4 | 2014-05-30 16:06:46 -0700 | [diff] [blame] | 346 | |
| 347 | class TenantAddOrRemoveSliverView(View): |
| 348 | """ Add or remove slivers from a Slice |
| 349 | |
| 350 | Arguments: |
| 351 | siteName - name of site. If not specified, PlanetStack will pick the |
| 352 | best site., |
| 353 | actionToDo - [add | rem] |
| 354 | count - number of slivers to add or remove |
| 355 | sliceName - name of slice |
| 356 | noAct - if set, no changes will be made to db, but result will still |
| 357 | show which sites would have been modified. |
| 358 | |
| 359 | Returns: |
| 360 | Dictionary of sites that were modified, and the count of nodes |
| 361 | that were added or removed at each site. |
| 362 | """ |
| 363 | def post(self, request, *args, **kwargs): |
| 364 | siteName = request.POST.get("siteName", None) |
| 365 | actionToDo = request.POST.get("actionToDo", None) |
| 366 | count = int(request.POST.get("count","0")) |
| 367 | sliceName = request.POST.get("slice", None) |
Scott Baker | 866c5b3 | 2014-08-29 11:34:00 -0700 | [diff] [blame] | 368 | imageName = request.POST.get("image",None) |
Scott Baker | c7325a4 | 2014-05-30 16:06:46 -0700 | [diff] [blame] | 369 | noAct = request.POST.get("noAct", False) |
| 370 | |
| 371 | if not sliceName: |
| 372 | return HttpResponseServerError("No slice name given") |
| 373 | |
| 374 | slice = Slice.objects.get(name=sliceName) |
Scott Baker | 866c5b3 | 2014-08-29 11:34:00 -0700 | [diff] [blame] | 375 | image = Image.objects.get(name=imageName) |
Scott Baker | c7325a4 | 2014-05-30 16:06:46 -0700 | [diff] [blame] | 376 | |
| 377 | if siteName: |
| 378 | siteList = [Site.objects.get(name=siteName)] |
| 379 | else: |
| 380 | siteList = None |
| 381 | |
| 382 | if (actionToDo == "add"): |
| 383 | user_ip = request.GET.get("ip", get_ip(request)) |
| 384 | if (siteList is None): |
| 385 | siteList = tenant_pick_sites(user, user_ip, slice, count) |
| 386 | |
Scott Baker | 866c5b3 | 2014-08-29 11:34:00 -0700 | [diff] [blame] | 387 | sitesChanged = slice_increase_slivers(request.user, user_ip, siteList, slice, image, count, noAct) |
Scott Baker | c7325a4 | 2014-05-30 16:06:46 -0700 | [diff] [blame] | 388 | elif (actionToDo == "rem"): |
| 389 | sitesChanged = slice_decrease_slivers(request.user, siteList, slice, count, noAct) |
| 390 | else: |
| 391 | return HttpResponseServerError("Unknown actionToDo %s" % actionToDo) |
| 392 | |
Scott Baker | 823b721 | 2014-06-16 10:25:39 -0700 | [diff] [blame] | 393 | return HttpResponse(json.dumps(sitesChanged), content_type='application/javascript') |
Scott Baker | c7325a4 | 2014-05-30 16:06:46 -0700 | [diff] [blame] | 394 | |
| 395 | def get(self, request, *args, **kwargs): |
| 396 | request.POST = request.GET |
| 397 | return self.post(request, *args, **kwargs) # for testing REST in browser |
| 398 | #return HttpResponseServerError("GET is not supported") |
| 399 | |
| 400 | class TenantPickSitesView(View): |
| 401 | """ primarily just for testing purposes """ |
| 402 | def get(self, request, *args, **kwargs): |
| 403 | count = request.GET.get("count","0") |
| 404 | slice = request.GET.get("slice",None) |
| 405 | if slice: |
| 406 | slice = Slice.objects.get(name=slice) |
| 407 | ip = request.GET.get("ip", get_ip(request)) |
| 408 | sites = tenant_pick_sites(request.user, user_ip=ip, count=0, slice=slice) |
| 409 | sites = [x.name for x in sites] |
Scott Baker | 823b721 | 2014-06-16 10:25:39 -0700 | [diff] [blame] | 410 | return HttpResponse(json.dumps(sites), content_type='application/javascript') |
Scott Baker | c7325a4 | 2014-05-30 16:06:46 -0700 | [diff] [blame] | 411 | |
| 412 | def siteSortKey(site, slice=None, count=None, lat=None, lon=None): |
| 413 | # try to pick a site we're already using |
| 414 | has_slivers_here=False |
| 415 | if slice: |
| 416 | for sliver in slice.slivers.all(): |
| 417 | if sliver.node.site.name == site.name: |
| 418 | has_slivers_here=True |
| 419 | |
| 420 | # Haversine method |
| 421 | d = haversine(site.location.latitude, site.location.longitude, lat, lon) |
| 422 | |
| 423 | return (-has_slivers_here, d) |
| 424 | |
| 425 | def tenant_pick_sites(user, user_ip=None, slice=None, count=None): |
| 426 | """ Returns list of sites, sorted from most favorable to least favorable """ |
| 427 | lat=None |
| 428 | lon=None |
| 429 | try: |
| 430 | client_geo = GeoIP().city(user_ip) |
| 431 | if client_geo: |
| 432 | lat=float(client_geo["latitude"]) |
| 433 | lon=float(client_geo["longitude"]) |
| 434 | except: |
| 435 | print "exception in geo code" |
| 436 | traceback.print_exc() |
| 437 | |
Scott Baker | 01ef649 | 2014-08-29 12:19:09 -0700 | [diff] [blame] | 438 | available_sites = getAvailableSites() |
Scott Baker | c7325a4 | 2014-05-30 16:06:46 -0700 | [diff] [blame] | 439 | sites = Site.objects.all() |
Scott Baker | 866c5b3 | 2014-08-29 11:34:00 -0700 | [diff] [blame] | 440 | sites = [x for x in sites if x.name in available_sites] |
Scott Baker | c7325a4 | 2014-05-30 16:06:46 -0700 | [diff] [blame] | 441 | sites = sorted(sites, key=functools.partial(siteSortKey, slice=slice, count=count, lat=lat, lon=lon)) |
| 442 | |
| 443 | return sites |
| 444 | |
| 445 | class TenantViewData(View): |
| 446 | def get(self, request, **kwargs): |
Scott Baker | 823b721 | 2014-06-16 10:25:39 -0700 | [diff] [blame] | 447 | return HttpResponse(json.dumps(getTenantSliceInfo(request.user, True)), content_type='application/javascript') |
Scott Baker | 866c5b3 | 2014-08-29 11:34:00 -0700 | [diff] [blame] | 448 | |
| 449 | class RequestAccountView(View): |
| 450 | def get(self, request, **kwargs): |
| 451 | return HttpResponse() |