root / api / handlers.py @ 6f6bd1a2
History | View | Annotate | Download (8.8 kB)
1 |
# vim: ts=4 sts=4 et ai sw=4 fileencoding=utf-8
|
---|---|
2 |
#
|
3 |
# Copyright © 2010 Greek Research and Technology Network
|
4 |
#
|
5 |
|
6 |
from django.conf import settings |
7 |
from piston.handler import BaseHandler, AnonymousBaseHandler |
8 |
from synnefo.api.faults import fault, noContent, accepted, created |
9 |
from synnefo.api.helpers import instance_to_server, paginator |
10 |
from synnefo.util.rapi import GanetiRapiClient, GanetiApiError |
11 |
from synnefo.vocabs import MOCK_SERVERS, MOCK_IMAGES |
12 |
from synnefo.db.models import VirtualMachine, User |
13 |
|
14 |
|
15 |
if settings.GANETI_CLUSTER_INFO:
|
16 |
rapi = GanetiRapiClient(*settings.GANETI_CLUSTER_INFO) |
17 |
else:
|
18 |
rapi = None
|
19 |
|
20 |
VERSIONS = [ |
21 |
{ |
22 |
"status": "CURRENT", |
23 |
"id": "v1.0", |
24 |
"docURL" : "http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20090714.pdf ", |
25 |
"wadl" : "http://docs.rackspacecloud.com/servers/api/v1.0/application.wadl" |
26 |
}, |
27 |
] |
28 |
|
29 |
class VersionHandler(AnonymousBaseHandler): |
30 |
allowed_methods = ('GET',)
|
31 |
|
32 |
def read(self, request, number=None): |
33 |
if number is None: |
34 |
versions = map(lambda v: { |
35 |
"status": v["status"], |
36 |
"id": v["id"], |
37 |
}, VERSIONS) |
38 |
return { "versions": versions } |
39 |
else:
|
40 |
for version in VERSIONS: |
41 |
if version["id"] == number: |
42 |
return { "version": version } |
43 |
raise fault.itemNotFound
|
44 |
|
45 |
|
46 |
class ServerHandler(BaseHandler): |
47 |
allowed_methods = ('GET', 'POST', 'PUT', 'DELETE') |
48 |
|
49 |
def read(self, request, id=None): |
50 |
from time import sleep |
51 |
sleep(1)
|
52 |
if id is None: |
53 |
return self.read_all(request) |
54 |
elif id == "detail": |
55 |
return self.read_all(request, detail=True) |
56 |
else:
|
57 |
return self.read_one(request, id) |
58 |
|
59 |
def read_one(self, request, id): |
60 |
if not rapi: # No ganeti backend. Return mock objects |
61 |
return { "server": MOCK_SERVERS[0] } |
62 |
try:
|
63 |
instance = rapi.GetInstance(id)
|
64 |
return { "server": instance_to_server(instance) } |
65 |
except GanetiApiError:
|
66 |
raise fault.itemNotFound
|
67 |
|
68 |
@paginator
|
69 |
def read_all(self, request, detail=False): |
70 |
if not rapi: # No ganeti backend. Return mock objects |
71 |
if detail:
|
72 |
return { "servers": MOCK_SERVERS } |
73 |
virtual_servers = VirtualMachine.objects.filter(owner=User.objects.all()[0])
|
74 |
#get the first user, since we don't have any user data yet
|
75 |
virtual_servers_list = [{'status': server.state, 'flavorId': server.flavor, \ |
76 |
'name': server.name, 'id': server.id, 'imageId': server.imageid, |
77 |
'metadata': {'Server_Label': server.server_label, \ |
78 |
'Image_Version': server.image_version}, \
|
79 |
'hostId': '9e107d9d372bb6826bd81d3542a419d6', \ |
80 |
'addresses': {'public': ['67.23.10.133'], 'private': ['10.176.42.17']}} \ |
81 |
for server in virtual_servers] |
82 |
#pass some fake data regarding ip, since we don't have any such data
|
83 |
return { "servers": virtual_servers_list } |
84 |
else:
|
85 |
return { "servers": [ { "id": s['id'], "name": s['name'] } for s in MOCK_SERVERS ] } |
86 |
|
87 |
if not detail: |
88 |
instances = rapi.GetInstances(bulk=False)
|
89 |
servers = [ { "id": id, "name": id } for id in instances ] |
90 |
else:
|
91 |
instances = rapi.GetInstances(bulk=True)
|
92 |
servers = [] |
93 |
for instance in instances: |
94 |
servers.append(instance_to_server(instance)) |
95 |
return { "servers": servers } |
96 |
|
97 |
def create(self, request): |
98 |
return accepted
|
99 |
|
100 |
def update(self, request, id): |
101 |
return noContent
|
102 |
|
103 |
def delete(self, request, id): |
104 |
return accepted
|
105 |
|
106 |
|
107 |
class ServerAddressHandler(BaseHandler): |
108 |
allowed_methods = ('GET', 'PUT', 'DELETE') |
109 |
|
110 |
def read(self, request, id, type=None): |
111 |
"""List IP addresses for a server"""
|
112 |
if type is None: |
113 |
pass
|
114 |
elif type == "private": |
115 |
pass
|
116 |
elif type == "public": |
117 |
pass
|
118 |
return {}
|
119 |
|
120 |
def update(self, request, id, address): |
121 |
"""Share an IP address to another in the group"""
|
122 |
return accepted
|
123 |
|
124 |
def delete(self, request, id, address): |
125 |
"""Unshare an IP address"""
|
126 |
return accepted
|
127 |
|
128 |
|
129 |
class ServerActionHandler(BaseHandler): |
130 |
allowed_methods = ('POST',)
|
131 |
|
132 |
def create(self, request, id): |
133 |
"""Reboot, rebuild, resize, confirm resized, revert resized"""
|
134 |
print ("server action %s" % id) |
135 |
return accepted
|
136 |
|
137 |
|
138 |
class ServerBackupHandler(BaseHandler): |
139 |
""" Backup Schedules are not implemented yet, return notImplemented """
|
140 |
allowed_methods = ('GET', 'POST', 'DELETE') |
141 |
|
142 |
def read(self, request, id): |
143 |
raise fault.notImplemented
|
144 |
|
145 |
def create(self, request, id): |
146 |
raise fault.notImplemented
|
147 |
|
148 |
def delete(self, request, id): |
149 |
raise fault.notImplemented
|
150 |
|
151 |
|
152 |
class FlavorHandler(BaseHandler): |
153 |
allowed_methods = ('GET',)
|
154 |
flavors = [ |
155 |
{ |
156 |
"id" : 1, |
157 |
"name" : "256 MB Server", |
158 |
"ram" : 256, |
159 |
"disk" : 10 |
160 |
}, |
161 |
{ |
162 |
"id" : 2, |
163 |
"name" : "512 MB Server", |
164 |
"ram" : 512, |
165 |
"disk" : 20 |
166 |
} |
167 |
] |
168 |
|
169 |
def read(self, request, id=None): |
170 |
"""
|
171 |
List flavors or retrieve one
|
172 |
|
173 |
Returns: OK
|
174 |
Faults: cloudServersFault, serviceUnavailable, unauthorized,
|
175 |
badRequest, itemNotFound
|
176 |
"""
|
177 |
if id is None: |
178 |
simple = map(lambda v: { |
179 |
"id": v["id"], |
180 |
"name": v["name"], |
181 |
}, self.flavors)
|
182 |
return { "flavors": simple } |
183 |
elif id == "detail": |
184 |
return { "flavors": self.flavors } |
185 |
else:
|
186 |
for flavor in self.flavors: |
187 |
if str(flavor["id"]) == id: |
188 |
return { "flavor": flavor } |
189 |
raise fault.itemNotFound
|
190 |
|
191 |
|
192 |
class ImageHandler(BaseHandler): |
193 |
allowed_methods = ('GET', 'POST') |
194 |
|
195 |
def read(self, request, id=None): |
196 |
"""
|
197 |
List images or retrieve one
|
198 |
|
199 |
Returns: OK
|
200 |
Faults: cloudServersFault, serviceUnavailable, unauthorized,
|
201 |
badRequest, itemNotFound
|
202 |
"""
|
203 |
if not rapi: # No ganeti backend. Return mock objects |
204 |
if id == "detail": |
205 |
return { "images": MOCK_IMAGES } |
206 |
elif id is None: |
207 |
return { "images": [ { "id": s['id'], "name": s['name'] } for s in MOCK_IMAGES ] } |
208 |
else:
|
209 |
return { "image": MOCK_IMAGES[0] } |
210 |
if id is None: |
211 |
return {}
|
212 |
elif id == "detail": |
213 |
return {}
|
214 |
else:
|
215 |
raise fault.itemNotFound
|
216 |
|
217 |
def create(self, request): |
218 |
"""Create a new image"""
|
219 |
return accepted
|
220 |
|
221 |
|
222 |
class SharedIPGroupHandler(BaseHandler): |
223 |
allowed_methods = ('GET', 'POST', 'DELETE') |
224 |
|
225 |
def read(self, request, id=None): |
226 |
"""List Shared IP Groups"""
|
227 |
if id is None: |
228 |
return {}
|
229 |
elif id == "detail": |
230 |
return {}
|
231 |
else:
|
232 |
raise fault.itemNotFound
|
233 |
|
234 |
def create(self, request, id): |
235 |
"""Creates a new Shared IP Group"""
|
236 |
return created
|
237 |
|
238 |
def delete(self, request, id): |
239 |
"""Deletes a Shared IP Group"""
|
240 |
return noContent
|
241 |
|
242 |
|
243 |
class LimitHandler(BaseHandler): |
244 |
allowed_methods = ('GET',)
|
245 |
|
246 |
# XXX: hookup with @throttle
|
247 |
|
248 |
rate = [ |
249 |
{ |
250 |
"verb" : "POST", |
251 |
"URI" : "*", |
252 |
"regex" : ".*", |
253 |
"value" : 10, |
254 |
"remaining" : 2, |
255 |
"unit" : "MINUTE", |
256 |
"resetTime" : 1244425439 |
257 |
}, |
258 |
{ |
259 |
"verb" : "POST", |
260 |
"URI" : "*/servers", |
261 |
"regex" : "^/servers", |
262 |
"value" : 25, |
263 |
"remaining" : 24, |
264 |
"unit" : "DAY", |
265 |
"resetTime" : 1244511839 |
266 |
}, |
267 |
{ |
268 |
"verb" : "PUT", |
269 |
"URI" : "*", |
270 |
"regex" : ".*", |
271 |
"value" : 10, |
272 |
"remaining" : 2, |
273 |
"unit" : "MINUTE", |
274 |
"resetTime" : 1244425439 |
275 |
}, |
276 |
{ |
277 |
"verb" : "GET", |
278 |
"URI" : "*", |
279 |
"regex" : ".*", |
280 |
"value" : 3, |
281 |
"remaining" : 3, |
282 |
"unit" : "MINUTE", |
283 |
"resetTime" : 1244425439 |
284 |
}, |
285 |
{ |
286 |
"verb" : "DELETE", |
287 |
"URI" : "*", |
288 |
"regex" : ".*", |
289 |
"value" : 100, |
290 |
"remaining" : 100, |
291 |
"unit" : "MINUTE", |
292 |
"resetTime" : 1244425439 |
293 |
} |
294 |
] |
295 |
|
296 |
absolute = { |
297 |
"maxTotalRAMSize" : 51200, |
298 |
"maxIPGroups" : 50, |
299 |
"maxIPGroupMembers" : 25 |
300 |
} |
301 |
|
302 |
def read(self, request): |
303 |
return { "limits": { |
304 |
"rate": self.rate, |
305 |
"absolute": self.absolute, |
306 |
} |
307 |
} |