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