root / api / handlers.py @ 038383b1
History | View | Annotate | Download (39.7 kB)
1 | 00b4f1be | Faidon Liambotis | # vim: ts=4 sts=4 et ai sw=4 fileencoding=utf-8
|
---|---|---|---|
2 | 00b4f1be | Faidon Liambotis | #
|
3 | e9134601 | Constantinos Venetsanopoulos | # Copyright © 2010 Greek Research and Technology Network
|
4 | 8b78d1a5 | Markos Gogoulos | |
5 | a237869d | Faidon Liambotis | from django.utils import simplejson as json |
6 | 285a1fa8 | Dimitris Moraitis | from django.http import HttpResponse |
7 | 00b4f1be | Faidon Liambotis | from piston.handler import BaseHandler, AnonymousBaseHandler |
8 | 1a49199e | Dimitris Moraitis | from synnefo.api.faults import fault, noContent, accepted, created, notModified |
9 | 5fb55fba | Georgios Gousios | from synnefo.api.helpers import instance_to_server, paginator, authenticate |
10 | e646ebe5 | Dimitris Moraitis | from synnefo.util.rapi import GanetiRapiClient, GanetiApiError |
11 | e646ebe5 | Dimitris Moraitis | from synnefo.util.rapi import CertificateError |
12 | a31ff6cb | Markos Gogoulos | from synnefo.db.models import * |
13 | 01199e0b | Markos Gogoulos | import random |
14 | 01199e0b | Markos Gogoulos | import string |
15 | 285a1fa8 | Dimitris Moraitis | import logging |
16 | 54f8cd6d | Markos Gogoulos | from datetime import datetime, timedelta |
17 | 038383b1 | Dimitris Moraitis | import iso8601 |
18 | 5abebfaa | Vassilios Karakoidas | from logic import backend, utils |
19 | 5abebfaa | Vassilios Karakoidas | |
20 | 285a1fa8 | Dimitris Moraitis | log = logging.getLogger('synnefo.api.handlers')
|
21 | 253f0c82 | Faidon Liambotis | |
22 | c5e38339 | Markos Gogoulos | try:
|
23 | ec06b07c | Dimitris Moraitis | rapi = GanetiRapiClient(*settings.GANETI_CLUSTER_INFO) |
24 | c5e38339 | Markos Gogoulos | rapi.GetVersion() |
25 | c18611c8 | Markos Gogoulos | except Exception, e: |
26 | 6b83d46b | Markos Gogoulos | log.exception('Unexpected error: %s' % e)
|
27 | c5e38339 | Markos Gogoulos | raise fault.serviceUnavailable
|
28 | c5e38339 | Markos Gogoulos | #If we can't connect to the rapi successfully, don't do anything
|
29 | 00b4f1be | Faidon Liambotis | |
30 | 00b4f1be | Faidon Liambotis | VERSIONS = [ |
31 | 00b4f1be | Faidon Liambotis | { |
32 | 00b4f1be | Faidon Liambotis | "status": "CURRENT", |
33 | 00b4f1be | Faidon Liambotis | "id": "v1.0", |
34 | e646ebe5 | Dimitris Moraitis | "docURL":
|
35 | e646ebe5 | Dimitris Moraitis | "http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf",
|
36 | e646ebe5 | Dimitris Moraitis | "wadl":
|
37 | e646ebe5 | Dimitris Moraitis | "http://docs.rackspacecloud.com/servers/api/v1.0/application.wadl"
|
38 | 00b4f1be | Faidon Liambotis | }, |
39 | 9071888e | Constantinos Venetsanopoulos | { |
40 | 9071888e | Constantinos Venetsanopoulos | "status": "CURRENT", |
41 | 60023e66 | Constantinos Venetsanopoulos | "id": "v1.1", |
42 | e646ebe5 | Dimitris Moraitis | "docURL":
|
43 | e646ebe5 | Dimitris Moraitis | "http://docs.openstack.org/openstack-compute/developer/content/",
|
44 | e646ebe5 | Dimitris Moraitis | "wadl": "None yet" |
45 | 60023e66 | Constantinos Venetsanopoulos | }, |
46 | 60023e66 | Constantinos Venetsanopoulos | { |
47 | 60023e66 | Constantinos Venetsanopoulos | "status": "CURRENT", |
48 | 9071888e | Constantinos Venetsanopoulos | "id": "v1.0grnet1", |
49 | e646ebe5 | Dimitris Moraitis | "docURL": "None yet", |
50 | e646ebe5 | Dimitris Moraitis | "wad1": "None yet" |
51 | 9071888e | Constantinos Venetsanopoulos | } |
52 | 00b4f1be | Faidon Liambotis | ] |
53 | 00b4f1be | Faidon Liambotis | |
54 | f5ea24a9 | Markos Gogoulos | #read is called on GET requests
|
55 | f5ea24a9 | Markos Gogoulos | #create is called on POST, and creates new objects
|
56 | f5ea24a9 | Markos Gogoulos | #update is called on PUT, and should update an existing product
|
57 | f5ea24a9 | Markos Gogoulos | #delete is called on DELETE, and should delete an existing object
|
58 | f5ea24a9 | Markos Gogoulos | |
59 | ccbd9f9b | Markos Gogoulos | |
60 | 00b4f1be | Faidon Liambotis | class VersionHandler(AnonymousBaseHandler): |
61 | 00b4f1be | Faidon Liambotis | allowed_methods = ('GET',)
|
62 | 00b4f1be | Faidon Liambotis | |
63 | 00b4f1be | Faidon Liambotis | def read(self, request, number=None): |
64 | ffffd5fe | Markos Gogoulos | try:
|
65 | ffffd5fe | Markos Gogoulos | if number is None: |
66 | ffffd5fe | Markos Gogoulos | versions = map(lambda v: { |
67 | ffffd5fe | Markos Gogoulos | "status": v["status"], |
68 | ffffd5fe | Markos Gogoulos | "id": v["id"], |
69 | ffffd5fe | Markos Gogoulos | }, VERSIONS) |
70 | e646ebe5 | Dimitris Moraitis | return {"versions": versions} |
71 | ffffd5fe | Markos Gogoulos | else:
|
72 | ffffd5fe | Markos Gogoulos | for version in VERSIONS: |
73 | ffffd5fe | Markos Gogoulos | if version["id"] == number: |
74 | e646ebe5 | Dimitris Moraitis | return {"version": version} |
75 | ffffd5fe | Markos Gogoulos | raise fault.itemNotFound
|
76 | ffffd5fe | Markos Gogoulos | except Exception, e: |
77 | 6b83d46b | Markos Gogoulos | log.exception('Unexpected error: %s' % e)
|
78 | ffffd5fe | Markos Gogoulos | raise fault.serviceUnavailable
|
79 | 00b4f1be | Faidon Liambotis | |
80 | 00b4f1be | Faidon Liambotis | |
81 | 00b4f1be | Faidon Liambotis | class ServerHandler(BaseHandler): |
82 | f5ea24a9 | Markos Gogoulos | """Handler responsible for the Servers
|
83 | f5ea24a9 | Markos Gogoulos |
|
84 | f5ea24a9 | Markos Gogoulos | handles the listing of Virtual Machines, Creates and Destroys VM's
|
85 | f5ea24a9 | Markos Gogoulos |
|
86 | f5ea24a9 | Markos Gogoulos | @HTTP methods: POST, DELETE, PUT, GET
|
87 | f5ea24a9 | Markos Gogoulos | @Parameters: POST data with the create data (cpu, ram, etc)
|
88 | e646ebe5 | Dimitris Moraitis | @Responses: HTTP 200 if successfully call rapi, 304 if not modified,
|
89 | e646ebe5 | Dimitris Moraitis | itemNotFound or serviceUnavailable otherwise
|
90 | f5ea24a9 | Markos Gogoulos |
|
91 | f5ea24a9 | Markos Gogoulos | """
|
92 | fd4828ce | Faidon Liambotis | allowed_methods = ('GET', 'POST', 'PUT', 'DELETE') |
93 | fd4828ce | Faidon Liambotis | |
94 | 5fb55fba | Georgios Gousios | #@authenticate
|
95 | 00b4f1be | Faidon Liambotis | def read(self, request, id=None): |
96 | 38e2c5ed | Christodoulos Psaltis | from time import sleep |
97 | dc8b976e | Markos Gogoulos | sleep(0.5)
|
98 | ccbd9f9b | Markos Gogoulos | #TODO: delete the sleep once the mock objects are removed
|
99 | 00b4f1be | Faidon Liambotis | if id is None: |
100 | 00b4f1be | Faidon Liambotis | return self.read_all(request) |
101 | 253f0c82 | Faidon Liambotis | elif id == "detail": |
102 | 00b4f1be | Faidon Liambotis | return self.read_all(request, detail=True) |
103 | 00b4f1be | Faidon Liambotis | else:
|
104 | 00b4f1be | Faidon Liambotis | return self.read_one(request, id) |
105 | 00b4f1be | Faidon Liambotis | |
106 | 00b4f1be | Faidon Liambotis | def read_one(self, request, id): |
107 | 909f415b | Faidon Liambotis | try:
|
108 | 37a57502 | Markos Gogoulos | server = VirtualMachine.objects.get(id=id)
|
109 | 5abebfaa | Vassilios Karakoidas | server = {'status': utils.get_rsapi_state(server),
|
110 | e646ebe5 | Dimitris Moraitis | 'flavorRef': server.flavor.id,
|
111 | e646ebe5 | Dimitris Moraitis | 'name': server.name,
|
112 | e646ebe5 | Dimitris Moraitis | 'id': server.id,
|
113 | b335768e | Markos Gogoulos | 'imageRef': server.sourceimage.id,
|
114 | e646ebe5 | Dimitris Moraitis | 'created': server.created,
|
115 | 1a49199e | Dimitris Moraitis | 'updated': server.updated,
|
116 | e646ebe5 | Dimitris Moraitis | 'hostId': server.hostid,
|
117 | 5abebfaa | Vassilios Karakoidas | 'progress': utils.get_rsapi_state(server) == 'ACTIVE' and 100 or 0, |
118 | ffffd5fe | Markos Gogoulos | #'metadata': {'Server_Label': server.description },
|
119 | e646ebe5 | Dimitris Moraitis | 'metadata': [{'meta': { |
120 | e646ebe5 | Dimitris Moraitis | 'key': {
|
121 | e646ebe5 | Dimitris Moraitis | metadata.meta_key: metadata.meta_value |
122 | e646ebe5 | Dimitris Moraitis | } |
123 | e646ebe5 | Dimitris Moraitis | } |
124 | e646ebe5 | Dimitris Moraitis | } |
125 | e646ebe5 | Dimitris Moraitis | for metadata in |
126 | e646ebe5 | Dimitris Moraitis | server.virtualmachinemetadata_set.all()], |
127 | e646ebe5 | Dimitris Moraitis | 'addresses': {'public': { |
128 | e646ebe5 | Dimitris Moraitis | 'ip': {'addr': server.ipfour}, |
129 | e646ebe5 | Dimitris Moraitis | 'ip6': {'addr': server.ipsix}}, |
130 | e646ebe5 | Dimitris Moraitis | 'private': ''}, |
131 | ffffd5fe | Markos Gogoulos | } |
132 | e646ebe5 | Dimitris Moraitis | return {"server": server} |
133 | c18611c8 | Markos Gogoulos | except VirtualMachine.DoesNotExist:
|
134 | 909f415b | Faidon Liambotis | raise fault.itemNotFound
|
135 | c18611c8 | Markos Gogoulos | except VirtualMachine.MultipleObjectsReturned:
|
136 | c18611c8 | Markos Gogoulos | raise fault.serviceUnavailable
|
137 | c18611c8 | Markos Gogoulos | except Exception, e: |
138 | 6b83d46b | Markos Gogoulos | log.exception('Unexpected error: %s' % e)
|
139 | c18611c8 | Markos Gogoulos | raise fault.serviceUnavailable
|
140 | 37a57502 | Markos Gogoulos | |
141 | 2c089b77 | Faidon Liambotis | @paginator
|
142 | 00b4f1be | Faidon Liambotis | def read_all(self, request, detail=False): |
143 | c5a032c4 | Markos Gogoulos | #changes_since should be on ISO 8601 format
|
144 | ffffd5fe | Markos Gogoulos | try:
|
145 | ab5282e4 | Dimitris Moraitis | changes_since = request.GET.get("changes-since", 0) |
146 | d19719cd | Markos Gogoulos | if changes_since:
|
147 | 038383b1 | Dimitris Moraitis | last_update = iso8601.parse_date(changes_since) |
148 | 54f8cd6d | Markos Gogoulos | #return a badRequest if the changes_since is older than a limit
|
149 | 038383b1 | Dimitris Moraitis | if (datetime.now(last_update.tzinfo) - last_update >
|
150 | e646ebe5 | Dimitris Moraitis | timedelta(seconds=settings.POLL_LIMIT)): |
151 | e646ebe5 | Dimitris Moraitis | raise fault.badRequest
|
152 | e646ebe5 | Dimitris Moraitis | virtual_servers = VirtualMachine.objects.filter( |
153 | e646ebe5 | Dimitris Moraitis | updated__gt=last_update) |
154 | 1a49199e | Dimitris Moraitis | if not len(virtual_servers): |
155 | 1a49199e | Dimitris Moraitis | return notModified
|
156 | d19719cd | Markos Gogoulos | else:
|
157 | d19719cd | Markos Gogoulos | virtual_servers = VirtualMachine.objects.filter(deleted=False)
|
158 | e646ebe5 | Dimitris Moraitis | # get all VM's for now, FIX it to take the user's VMs only yet.
|
159 | e646ebe5 | Dimitris Moraitis | # also don't get deleted VM's
|
160 | a3808aa8 | Markos Gogoulos | except Exception, e: |
161 | e646ebe5 | Dimitris Moraitis | raise fault.badRequest
|
162 | a3808aa8 | Markos Gogoulos | try:
|
163 | ffffd5fe | Markos Gogoulos | if not detail: |
164 | e646ebe5 | Dimitris Moraitis | return {"servers": [{ |
165 | e646ebe5 | Dimitris Moraitis | "id": s.id, "name": s.name} for s in virtual_servers]} |
166 | ffffd5fe | Markos Gogoulos | else:
|
167 | e646ebe5 | Dimitris Moraitis | virtual_servers_list = [ |
168 | 8a88551c | Vassilios Karakoidas | {'status': utils.get_rsapi_state(server),
|
169 | e646ebe5 | Dimitris Moraitis | 'flavorRef': server.flavor.id,
|
170 | e646ebe5 | Dimitris Moraitis | 'name': server.name,
|
171 | e646ebe5 | Dimitris Moraitis | 'id': server.id,
|
172 | e646ebe5 | Dimitris Moraitis | 'created': server.created,
|
173 | e646ebe5 | Dimitris Moraitis | 'updated': server.updated,
|
174 | e646ebe5 | Dimitris Moraitis | 'imageRef': server.sourceimage.id,
|
175 | e646ebe5 | Dimitris Moraitis | 'hostId': server.hostid,
|
176 | 8a88551c | Vassilios Karakoidas | 'progress': (utils.get_rsapi_state(server) == 'ACTIVE' and 100 or 0), |
177 | e646ebe5 | Dimitris Moraitis | #'metadata': {'Server_Label': server.description },
|
178 | e646ebe5 | Dimitris Moraitis | 'metadata':[
|
179 | e646ebe5 | Dimitris Moraitis | {'meta':
|
180 | e646ebe5 | Dimitris Moraitis | {'key': {metadata.meta_key: metadata.meta_value}}}
|
181 | e646ebe5 | Dimitris Moraitis | for metadata in |
182 | e646ebe5 | Dimitris Moraitis | server.virtualmachinemetadata_set.all() |
183 | e646ebe5 | Dimitris Moraitis | ], |
184 | e646ebe5 | Dimitris Moraitis | 'addresses': {
|
185 | e646ebe5 | Dimitris Moraitis | 'public': {
|
186 | e646ebe5 | Dimitris Moraitis | 'ip': {'addr': server.ipfour}, |
187 | e646ebe5 | Dimitris Moraitis | 'ip6': {'addr': server.ipsix} |
188 | e646ebe5 | Dimitris Moraitis | }, |
189 | e646ebe5 | Dimitris Moraitis | 'private': ''}, |
190 | e646ebe5 | Dimitris Moraitis | } for server in virtual_servers] |
191 | e646ebe5 | Dimitris Moraitis | #pass fake data regarding ip, since we don't have it yet
|
192 | e646ebe5 | Dimitris Moraitis | return {"servers": virtual_servers_list} |
193 | ffffd5fe | Markos Gogoulos | except Exception, e: |
194 | 6b83d46b | Markos Gogoulos | log.exception('Unexpected error: %s' % e)
|
195 | ffffd5fe | Markos Gogoulos | raise fault.serviceUnavailable
|
196 | e107ee57 | Markos Gogoulos | |
197 | 00b4f1be | Faidon Liambotis | def create(self, request): |
198 | 5ad45fcc | Dimitris Moraitis | """ Parse RackSpace API create request to generate rapi create request
|
199 | 285a1fa8 | Dimitris Moraitis | TODO: auto generate and set password
|
200 | 285a1fa8 | Dimitris Moraitis | """
|
201 | e646ebe5 | Dimitris Moraitis | # Check if we have all the necessary data in the JSON request
|
202 | debeeec9 | Markos Gogoulos | try:
|
203 | 285a1fa8 | Dimitris Moraitis | server = json.loads(request.raw_post_data)['server']
|
204 | 8714499d | Markos Gogoulos | name = server['name']
|
205 | b335768e | Markos Gogoulos | flavorRef = server['flavorRef']
|
206 | b335768e | Markos Gogoulos | flavor = Flavor.objects.get(id=flavorRef) |
207 | b335768e | Markos Gogoulos | imageRef = server['imageRef']
|
208 | b335768e | Markos Gogoulos | image = Image.objects.get(id=imageRef) |
209 | 285a1fa8 | Dimitris Moraitis | metadata = server['metadata']
|
210 | 285a1fa8 | Dimitris Moraitis | personality = server.get('personality', None) |
211 | 2baac7ca | Markos Gogoulos | except (Flavor.DoesNotExist, Image.DoesNotExist):
|
212 | 2baac7ca | Markos Gogoulos | raise fault.itemNotFound
|
213 | 2baac7ca | Markos Gogoulos | except (Flavor.MultipleObjectsReturned, Image.MultipleObjectsReturned):
|
214 | 2baac7ca | Markos Gogoulos | raise fault.serviceUnavailable
|
215 | 285a1fa8 | Dimitris Moraitis | except Exception as e: |
216 | e646ebe5 | Dimitris Moraitis | log.exception('Malformed create request: %s - %s' %
|
217 | e646ebe5 | Dimitris Moraitis | (e, request.raw_post_data)) |
218 | 71008c92 | Markos Gogoulos | raise fault.badRequest
|
219 | c18611c8 | Markos Gogoulos | |
220 | 34a619ae | Vangelis Koukis | # TODO: Proper Authn, Authz
|
221 | 34a619ae | Vangelis Koukis | # Everything belongs to a single SynnefoUser for now.
|
222 | e646ebe5 | Dimitris Moraitis | try:
|
223 | 34a619ae | Vangelis Koukis | owner = SynnefoUser.objects.all()[0]
|
224 | 34a619ae | Vangelis Koukis | except Exception as e: |
225 | e646ebe5 | Dimitris Moraitis | log.exception('Cannot find a single SynnefoUser in the DB: %s' %
|
226 | e646ebe5 | Dimitris Moraitis | (e)) |
227 | 34a619ae | Vangelis Koukis | raise fault.unauthorized
|
228 | 34a619ae | Vangelis Koukis | |
229 | 285a1fa8 | Dimitris Moraitis | # add the new VM to the local db
|
230 | a43b7f70 | Dimitris Moraitis | try:
|
231 | e646ebe5 | Dimitris Moraitis | vm = VirtualMachine.objects.create(sourceimage=image, |
232 | e646ebe5 | Dimitris Moraitis | ipfour='0.0.0.0',
|
233 | e646ebe5 | Dimitris Moraitis | ipsix='::1',
|
234 | e646ebe5 | Dimitris Moraitis | flavor=flavor, |
235 | e646ebe5 | Dimitris Moraitis | owner=owner) |
236 | a43b7f70 | Dimitris Moraitis | except Exception as e: |
237 | 6b83d46b | Markos Gogoulos | log.exception("Can't save vm: %s" % e)
|
238 | a43b7f70 | Dimitris Moraitis | raise fault.serviceUnavailable
|
239 | a43b7f70 | Dimitris Moraitis | |
240 | c18611c8 | Markos Gogoulos | try:
|
241 | 8714499d | Markos Gogoulos | vm.name = name |
242 | 8714499d | Markos Gogoulos | #vm.description = descr
|
243 | e646ebe5 | Dimitris Moraitis | vm.save() |
244 | 285a1fa8 | Dimitris Moraitis | jobId = rapi.CreateInstance( |
245 | 285a1fa8 | Dimitris Moraitis | 'create',
|
246 | e646ebe5 | Dimitris Moraitis | (request.META['SERVER_NAME'] == 'testserver' and |
247 | e646ebe5 | Dimitris Moraitis | 'test-server' or vm.backend_id), |
248 | 285a1fa8 | Dimitris Moraitis | 'plain',
|
249 | e646ebe5 | Dimitris Moraitis | # disk field of Flavor object is in GB,
|
250 | e646ebe5 | Dimitris Moraitis | # value specified here is in MB
|
251 | e646ebe5 | Dimitris Moraitis | # FIXME: Always ask for a 2GB disk,
|
252 | e646ebe5 | Dimitris Moraitis | # current LVM physical groups are too small:
|
253 | 9a6600f3 | Vangelis Koukis | # [{"size": flavor.disk * 1000}],
|
254 | 9a6600f3 | Vangelis Koukis | [{"size": 2000}], |
255 | 285a1fa8 | Dimitris Moraitis | [{}], |
256 | b335768e | Markos Gogoulos | #TODO: select OS from imageRef
|
257 | 285a1fa8 | Dimitris Moraitis | os='debootstrap+default',
|
258 | 285a1fa8 | Dimitris Moraitis | ip_check=False,
|
259 | 285a1fa8 | Dimitris Moraitis | name_check=False,
|
260 | 285a1fa8 | Dimitris Moraitis | #TODO: verify if this is necessary
|
261 | e646ebe5 | Dimitris Moraitis | pnode=rapi.GetNodes()[0],
|
262 | 285a1fa8 | Dimitris Moraitis | # Dry run when called by unit tests
|
263 | e646ebe5 | Dimitris Moraitis | dry_run=request.META['SERVER_NAME'] == 'testserver', |
264 | 285a1fa8 | Dimitris Moraitis | beparams={ |
265 | 285a1fa8 | Dimitris Moraitis | 'auto_balance': True, |
266 | 285a1fa8 | Dimitris Moraitis | 'vcpus': flavor.cpu,
|
267 | 285a1fa8 | Dimitris Moraitis | 'memory': flavor.ram,
|
268 | 285a1fa8 | Dimitris Moraitis | }, |
269 | 285a1fa8 | Dimitris Moraitis | ) |
270 | e646ebe5 | Dimitris Moraitis | log.info('created vm with %s cpus, %s ram and %s storage' %
|
271 | e646ebe5 | Dimitris Moraitis | (flavor.cpu, flavor.ram, flavor.disk)) |
272 | a43b7f70 | Dimitris Moraitis | except (GanetiApiError, CertificateError) as e: |
273 | 6b83d46b | Markos Gogoulos | log.exception('CreateInstance failed: %s' % e)
|
274 | 5abebfaa | Vassilios Karakoidas | # FIX: if the instance creation have failed, why it is saved in the db?
|
275 | 285a1fa8 | Dimitris Moraitis | vm.deleted = True
|
276 | 285a1fa8 | Dimitris Moraitis | vm.save() |
277 | c18611c8 | Markos Gogoulos | raise fault.serviceUnavailable
|
278 | a43b7f70 | Dimitris Moraitis | except Exception as e: |
279 | 6b83d46b | Markos Gogoulos | log.exception('Unexpected error: %s' % e)
|
280 | a43b7f70 | Dimitris Moraitis | vm.deleted = True
|
281 | a43b7f70 | Dimitris Moraitis | vm.save() |
282 | e646ebe5 | Dimitris Moraitis | raise fault.serviceUnavailable
|
283 | 285a1fa8 | Dimitris Moraitis | |
284 | 01199e0b | Markos Gogoulos | ret = {'server': {
|
285 | e646ebe5 | Dimitris Moraitis | 'id': vm.id,
|
286 | e646ebe5 | Dimitris Moraitis | 'name': vm.name,
|
287 | e646ebe5 | Dimitris Moraitis | "imageRef": imageRef,
|
288 | e646ebe5 | Dimitris Moraitis | "flavorRef": flavorRef,
|
289 | e646ebe5 | Dimitris Moraitis | "hostId": vm.hostid,
|
290 | e646ebe5 | Dimitris Moraitis | "progress": 0, |
291 | e646ebe5 | Dimitris Moraitis | "status": 'BUILD', |
292 | e646ebe5 | Dimitris Moraitis | "adminPass": self.random_password(), |
293 | e646ebe5 | Dimitris Moraitis | "metadata": {"My Server Name": vm.name}, |
294 | e646ebe5 | Dimitris Moraitis | "addresses": {
|
295 | e646ebe5 | Dimitris Moraitis | "public": [],
|
296 | e646ebe5 | Dimitris Moraitis | "private": [],
|
297 | 285a1fa8 | Dimitris Moraitis | }, |
298 | 01199e0b | Markos Gogoulos | }, |
299 | 01199e0b | Markos Gogoulos | } |
300 | e646ebe5 | Dimitris Moraitis | return HttpResponse(json.dumps(ret),
|
301 | e646ebe5 | Dimitris Moraitis | mimetype="application/json", status=202) |
302 | 01199e0b | Markos Gogoulos | |
303 | 01199e0b | Markos Gogoulos | def random_password(self): |
304 | 01199e0b | Markos Gogoulos | "return random password"
|
305 | 01199e0b | Markos Gogoulos | number_of_chars = 8
|
306 | e646ebe5 | Dimitris Moraitis | possible_chars = string.ascii_uppercase + string.ascii_lowercase + \ |
307 | e646ebe5 | Dimitris Moraitis | string.digits |
308 | e646ebe5 | Dimitris Moraitis | return ''.join(random.choice(possible_chars) \ |
309 | e646ebe5 | Dimitris Moraitis | for x in range(number_of_chars)) |
310 | 00b4f1be | Faidon Liambotis | |
311 | 00b4f1be | Faidon Liambotis | def update(self, request, id): |
312 | e646ebe5 | Dimitris Moraitis | """Sets and updates Virtual Machine Metadata.
|
313 | e646ebe5 | Dimitris Moraitis |
|
314 | 73469364 | Markos Gogoulos | """
|
315 | 73469364 | Markos Gogoulos | try:
|
316 | 73469364 | Markos Gogoulos | metadata_request = json.loads(request.raw_post_data)['metadata']
|
317 | 73469364 | Markos Gogoulos | metadata_key = metadata_request.get('metadata_key')
|
318 | 73469364 | Markos Gogoulos | metadata_value = metadata_request.get('metadata_value')
|
319 | e646ebe5 | Dimitris Moraitis | |
320 | 73469364 | Markos Gogoulos | vm = VirtualMachine.objects.get(id=id)
|
321 | 73469364 | Markos Gogoulos | #we only update virtual machine's name atm
|
322 | 73469364 | Markos Gogoulos | if metadata_key == 'name': |
323 | 73469364 | Markos Gogoulos | vm.name = metadata_value |
324 | 73469364 | Markos Gogoulos | vm.save() |
325 | 73469364 | Markos Gogoulos | return accepted
|
326 | 73469364 | Markos Gogoulos | except VirtualMachine.DoesNotExist:
|
327 | 73469364 | Markos Gogoulos | raise fault.itemNotFound
|
328 | 73469364 | Markos Gogoulos | except VirtualMachine.MultipleObjectsReturned:
|
329 | 73469364 | Markos Gogoulos | raise fault.serviceUnavailable
|
330 | 73469364 | Markos Gogoulos | except Exception, e: |
331 | 6b83d46b | Markos Gogoulos | log.exception('Unexpected error: %s' % e)
|
332 | 73469364 | Markos Gogoulos | raise fault.serviceUnavailable
|
333 | 73469364 | Markos Gogoulos | |
334 | f0858246 | Markos Gogoulos | raise fault.itemNotFound
|
335 | 00b4f1be | Faidon Liambotis | |
336 | 00b4f1be | Faidon Liambotis | def delete(self, request, id): |
337 | 9eef701d | Markos Gogoulos | try:
|
338 | c18611c8 | Markos Gogoulos | vm = VirtualMachine.objects.get(id=id)
|
339 | ffffd5fe | Markos Gogoulos | #TODO: set the status to DESTROYED
|
340 | 5abebfaa | Vassilios Karakoidas | backend.start_action(vm, 'DESTROY')
|
341 | ffffd5fe | Markos Gogoulos | rapi.DeleteInstance(vm.backend_id) |
342 | e646ebe5 | Dimitris Moraitis | return accepted
|
343 | c18611c8 | Markos Gogoulos | except VirtualMachine.DoesNotExist:
|
344 | 9eef701d | Markos Gogoulos | raise fault.itemNotFound
|
345 | c18611c8 | Markos Gogoulos | except VirtualMachine.MultipleObjectsReturned:
|
346 | c18611c8 | Markos Gogoulos | raise fault.serviceUnavailable
|
347 | c18611c8 | Markos Gogoulos | except GanetiApiError, CertificateError:
|
348 | c18611c8 | Markos Gogoulos | raise fault.serviceUnavailable
|
349 | c18611c8 | Markos Gogoulos | except Exception, e: |
350 | 6b83d46b | Markos Gogoulos | log.exception('Unexpected error: %s' % e)
|
351 | c18611c8 | Markos Gogoulos | raise fault.serviceUnavailable
|
352 | 00b4f1be | Faidon Liambotis | |
353 | ffffd5fe | Markos Gogoulos | |
354 | 00b4f1be | Faidon Liambotis | class ServerAddressHandler(BaseHandler): |
355 | d73d59e4 | Markos Gogoulos | """Handler responsible for Server Addresses
|
356 | d73d59e4 | Markos Gogoulos |
|
357 | e646ebe5 | Dimitris Moraitis | handles Reboot, Shutdown and Start actions.
|
358 | d73d59e4 | Markos Gogoulos |
|
359 | d73d59e4 | Markos Gogoulos | @HTTP methods: GET
|
360 | d73d59e4 | Markos Gogoulos | @Parameters: Id of server and networkID (eg public, private)
|
361 | e646ebe5 | Dimitris Moraitis | @Responses: HTTP 200 if successfully call rapi, itemNotFound,
|
362 | e646ebe5 | Dimitris Moraitis | serviceUnavailable otherwise
|
363 | d73d59e4 | Markos Gogoulos |
|
364 | d73d59e4 | Markos Gogoulos | """
|
365 | d73d59e4 | Markos Gogoulos | allowed_methods = ('GET',)
|
366 | 00b4f1be | Faidon Liambotis | |
367 | 76c8e33d | Markos Gogoulos | def read(self, request, id, networkID=None): |
368 | 00b4f1be | Faidon Liambotis | """List IP addresses for a server"""
|
369 | ccbd9f9b | Markos Gogoulos | |
370 | d73d59e4 | Markos Gogoulos | try:
|
371 | d73d59e4 | Markos Gogoulos | server = VirtualMachine.objects.get(id=id)
|
372 | e646ebe5 | Dimitris Moraitis | address = {'public': {'ip': {'addr': server.ipfour}, \ |
373 | e646ebe5 | Dimitris Moraitis | 'ip6': {'addr': server.ipsix}}, 'private': ''} |
374 | d73d59e4 | Markos Gogoulos | except VirtualMachine.DoesNotExist:
|
375 | d73d59e4 | Markos Gogoulos | raise fault.itemNotFound
|
376 | d73d59e4 | Markos Gogoulos | except VirtualMachine.MultipleObjectsReturned:
|
377 | d73d59e4 | Markos Gogoulos | raise fault.serviceUnavailable
|
378 | d73d59e4 | Markos Gogoulos | except Exception, e: |
379 | d73d59e4 | Markos Gogoulos | log.exception('Unexpected error: %s' % e)
|
380 | d73d59e4 | Markos Gogoulos | raise fault.serviceUnavailable
|
381 | 00b4f1be | Faidon Liambotis | |
382 | d73d59e4 | Markos Gogoulos | if networkID == "public": |
383 | e646ebe5 | Dimitris Moraitis | address = {'public': {'ip': {'addr': server.ipfour}, \ |
384 | e646ebe5 | Dimitris Moraitis | 'ip6': {'addr': server.ipsix}}} |
385 | d73d59e4 | Markos Gogoulos | elif networkID == "private": |
386 | e646ebe5 | Dimitris Moraitis | address = {'private': ''} |
387 | 964185dd | Markos Gogoulos | elif networkID != None: |
388 | 964185dd | Markos Gogoulos | raise fault.badRequest
|
389 | e646ebe5 | Dimitris Moraitis | return {"addresses": address} |
390 | 00b4f1be | Faidon Liambotis | |
391 | 00b4f1be | Faidon Liambotis | |
392 | 00b4f1be | Faidon Liambotis | class ServerActionHandler(BaseHandler): |
393 | f5ea24a9 | Markos Gogoulos | """Handler responsible for Server Actions
|
394 | f5ea24a9 | Markos Gogoulos |
|
395 | e646ebe5 | Dimitris Moraitis | handles Reboot, Shutdown and Start actions.
|
396 | f5ea24a9 | Markos Gogoulos |
|
397 | f5ea24a9 | Markos Gogoulos | @HTTP methods: POST, DELETE, PUT
|
398 | f5ea24a9 | Markos Gogoulos | @Parameters: POST data with the action (reboot, shutdown, start)
|
399 | e646ebe5 | Dimitris Moraitis | @Responses: HTTP 202 if successfully call rapi, itemNotFound,
|
400 | e646ebe5 | Dimitris Moraitis | serviceUnavailable otherwise
|
401 | f5ea24a9 | Markos Gogoulos |
|
402 | f5ea24a9 | Markos Gogoulos | """
|
403 | f5ea24a9 | Markos Gogoulos | |
404 | f5ea24a9 | Markos Gogoulos | allowed_methods = ('POST', 'DELETE', 'PUT') |
405 | 00b4f1be | Faidon Liambotis | |
406 | 00b4f1be | Faidon Liambotis | def create(self, request, id): |
407 | f5ea24a9 | Markos Gogoulos | """Reboot, Shutdown, Start virtual machine"""
|
408 | e646ebe5 | Dimitris Moraitis | |
409 | c18611c8 | Markos Gogoulos | try:
|
410 | ffffd5fe | Markos Gogoulos | requested_action = json.loads(request.raw_post_data) |
411 | ffffd5fe | Markos Gogoulos | reboot_request = requested_action.get('reboot', None) |
412 | ffffd5fe | Markos Gogoulos | shutdown_request = requested_action.get('shutdown', None) |
413 | ffffd5fe | Markos Gogoulos | start_request = requested_action.get('start', None) |
414 | ffffd5fe | Markos Gogoulos | #action not implemented
|
415 | e646ebe5 | Dimitris Moraitis | action = reboot_request and 'REBOOT' or shutdown_request \ |
416 | e646ebe5 | Dimitris Moraitis | and 'STOP' or start_request and 'START' |
417 | ffffd5fe | Markos Gogoulos | |
418 | ffffd5fe | Markos Gogoulos | if not action: |
419 | e646ebe5 | Dimitris Moraitis | raise fault.notImplemented
|
420 | ffffd5fe | Markos Gogoulos | #test if we can get the vm
|
421 | c18611c8 | Markos Gogoulos | vm = VirtualMachine.objects.get(id=id)
|
422 | 5abebfaa | Vassilios Karakoidas | backend.start_action(vm, action) |
423 | c18611c8 | Markos Gogoulos | |
424 | c18611c8 | Markos Gogoulos | if reboot_request:
|
425 | c18611c8 | Markos Gogoulos | rapi.RebootInstance(vm.backend_id) |
426 | c18611c8 | Markos Gogoulos | elif shutdown_request:
|
427 | c18611c8 | Markos Gogoulos | rapi.ShutdownInstance(vm.backend_id) |
428 | c18611c8 | Markos Gogoulos | elif start_request:
|
429 | c18611c8 | Markos Gogoulos | rapi.StartupInstance(vm.backend_id) |
430 | c18611c8 | Markos Gogoulos | return accepted
|
431 | ffffd5fe | Markos Gogoulos | except VirtualMachine.DoesNotExist:
|
432 | ffffd5fe | Markos Gogoulos | raise fault.itemNotFound
|
433 | ffffd5fe | Markos Gogoulos | except VirtualMachine.MultipleObjectsReturned:
|
434 | ffffd5fe | Markos Gogoulos | raise fault.serviceUnavailable
|
435 | c18611c8 | Markos Gogoulos | except GanetiApiError, CertificateError:
|
436 | c18611c8 | Markos Gogoulos | raise fault.serviceUnavailable
|
437 | c18611c8 | Markos Gogoulos | except Exception, e: |
438 | 6b83d46b | Markos Gogoulos | log.exception('Unexpected error: %s' % e)
|
439 | c18611c8 | Markos Gogoulos | raise fault.serviceUnavailable
|
440 | c18611c8 | Markos Gogoulos | |
441 | ccbd9f9b | Markos Gogoulos | def delete(self, request, id): |
442 | ccbd9f9b | Markos Gogoulos | """Delete an Instance"""
|
443 | ccbd9f9b | Markos Gogoulos | return accepted
|
444 | ccbd9f9b | Markos Gogoulos | |
445 | ccbd9f9b | Markos Gogoulos | def update(self, request, id): |
446 | f0858246 | Markos Gogoulos | raise fault.itemNotFound
|
447 | ccbd9f9b | Markos Gogoulos | |
448 | ccbd9f9b | Markos Gogoulos | |
449 | c99adc90 | Faidon Liambotis | class ServerBackupHandler(BaseHandler): |
450 | c99adc90 | Faidon Liambotis | """ Backup Schedules are not implemented yet, return notImplemented """
|
451 | c99adc90 | Faidon Liambotis | allowed_methods = ('GET', 'POST', 'DELETE') |
452 | c99adc90 | Faidon Liambotis | |
453 | c99adc90 | Faidon Liambotis | def read(self, request, id): |
454 | 635cfd6e | Faidon Liambotis | raise fault.notImplemented
|
455 | c99adc90 | Faidon Liambotis | |
456 | c99adc90 | Faidon Liambotis | def create(self, request, id): |
457 | 635cfd6e | Faidon Liambotis | raise fault.notImplemented
|
458 | c99adc90 | Faidon Liambotis | |
459 | c99adc90 | Faidon Liambotis | def delete(self, request, id): |
460 | 635cfd6e | Faidon Liambotis | raise fault.notImplemented
|
461 | c99adc90 | Faidon Liambotis | |
462 | c99adc90 | Faidon Liambotis | |
463 | 60023e66 | Constantinos Venetsanopoulos | class ServerMetadataHandler(BaseHandler): |
464 | 60023e66 | Constantinos Venetsanopoulos | """Handles Metadata of a specific Server
|
465 | 60023e66 | Constantinos Venetsanopoulos |
|
466 | 60023e66 | Constantinos Venetsanopoulos | the handler Lists, Creates, Updates and Deletes Metadata values
|
467 | 60023e66 | Constantinos Venetsanopoulos |
|
468 | 60023e66 | Constantinos Venetsanopoulos | @HTTP methods: POST, DELETE, PUT, GET
|
469 | 60023e66 | Constantinos Venetsanopoulos | @Parameters: POST data with key value pairs
|
470 | 60023e66 | Constantinos Venetsanopoulos |
|
471 | 60023e66 | Constantinos Venetsanopoulos | """
|
472 | 60023e66 | Constantinos Venetsanopoulos | allowed_methods = ('GET', 'POST', 'PUT', 'DELETE') |
473 | 60023e66 | Constantinos Venetsanopoulos | |
474 | 60023e66 | Constantinos Venetsanopoulos | def read(self, request, id, key=None): |
475 | 60023e66 | Constantinos Venetsanopoulos | """List metadata of the specific server"""
|
476 | 60023e66 | Constantinos Venetsanopoulos | if key is None: |
477 | 60023e66 | Constantinos Venetsanopoulos | return self.read_allkeys(request, id) |
478 | 60023e66 | Constantinos Venetsanopoulos | else:
|
479 | 60023e66 | Constantinos Venetsanopoulos | return self.read_onekey(request, id, key) |
480 | 60023e66 | Constantinos Venetsanopoulos | |
481 | 60023e66 | Constantinos Venetsanopoulos | def read_allkeys(self, request, id): |
482 | 60023e66 | Constantinos Venetsanopoulos | """Returns all the key value pairs of the specified server"""
|
483 | 60023e66 | Constantinos Venetsanopoulos | try:
|
484 | 60023e66 | Constantinos Venetsanopoulos | server = VirtualMachine.objects.get(pk=id)
|
485 | 60023e66 | Constantinos Venetsanopoulos | return {
|
486 | 60023e66 | Constantinos Venetsanopoulos | "metadata": {
|
487 | 60023e66 | Constantinos Venetsanopoulos | "values": [
|
488 | e646ebe5 | Dimitris Moraitis | {m.meta_key: m.meta_value} \ |
489 | e646ebe5 | Dimitris Moraitis | for m in server.virtualmachinemetadata_set.all() |
490 | 60023e66 | Constantinos Venetsanopoulos | ] |
491 | 60023e66 | Constantinos Venetsanopoulos | } |
492 | 60023e66 | Constantinos Venetsanopoulos | } |
493 | 60023e66 | Constantinos Venetsanopoulos | except VirtualMachine.DoesNotExist:
|
494 | 60023e66 | Constantinos Venetsanopoulos | raise fault.itemNotFound
|
495 | 60023e66 | Constantinos Venetsanopoulos | except VirtualMachine.MultipleObjectsReturned:
|
496 | 60023e66 | Constantinos Venetsanopoulos | raise fault.serviceUnavailable
|
497 | 60023e66 | Constantinos Venetsanopoulos | except Exception, e: |
498 | 60023e66 | Constantinos Venetsanopoulos | log.exception('Unexpected error: %s' % e)
|
499 | 60023e66 | Constantinos Venetsanopoulos | raise fault.serviceUnavailable
|
500 | e646ebe5 | Dimitris Moraitis | |
501 | 60023e66 | Constantinos Venetsanopoulos | def read_onekey(self, request, id, key): |
502 | 60023e66 | Constantinos Venetsanopoulos | """Returns the specified metadata key of the specified server"""
|
503 | 60023e66 | Constantinos Venetsanopoulos | try:
|
504 | 60023e66 | Constantinos Venetsanopoulos | server = VirtualMachine.objects.get(pk=id)
|
505 | 60023e66 | Constantinos Venetsanopoulos | return {
|
506 | 60023e66 | Constantinos Venetsanopoulos | "metadata": {
|
507 | 60023e66 | Constantinos Venetsanopoulos | "values": [
|
508 | e646ebe5 | Dimitris Moraitis | {m.meta_key: m.meta_value} for m in |
509 | e646ebe5 | Dimitris Moraitis | server.virtualmachinemetadata_set.filter(meta_key=key) |
510 | 60023e66 | Constantinos Venetsanopoulos | ] |
511 | 60023e66 | Constantinos Venetsanopoulos | } |
512 | 60023e66 | Constantinos Venetsanopoulos | } |
513 | 60023e66 | Constantinos Venetsanopoulos | except VirtualMachineMetadata.DoesNotExist:
|
514 | e646ebe5 | Dimitris Moraitis | raise fault.itemNotFound
|
515 | 60023e66 | Constantinos Venetsanopoulos | except VirtualMachine.DoesNotExist:
|
516 | 60023e66 | Constantinos Venetsanopoulos | raise fault.itemNotFound
|
517 | 60023e66 | Constantinos Venetsanopoulos | except VirtualMachine.MultipleObjectsReturned:
|
518 | 60023e66 | Constantinos Venetsanopoulos | raise fault.serviceUnavailable
|
519 | 60023e66 | Constantinos Venetsanopoulos | except Exception, e: |
520 | 60023e66 | Constantinos Venetsanopoulos | log.exception('Unexpected error: %s' % e)
|
521 | 60023e66 | Constantinos Venetsanopoulos | raise fault.serviceUnavailable
|
522 | 60023e66 | Constantinos Venetsanopoulos | |
523 | 13b4c540 | Constantinos Venetsanopoulos | def create(self, request, id, key=None): |
524 | 13b4c540 | Constantinos Venetsanopoulos | """Create or Update all metadata for the specified VM"""
|
525 | 13b4c540 | Constantinos Venetsanopoulos | if key is not None: |
526 | 13b4c540 | Constantinos Venetsanopoulos | log.exception('The POST request should not pass a key in the URL')
|
527 | 13b4c540 | Constantinos Venetsanopoulos | raise fault.badRequest
|
528 | 13b4c540 | Constantinos Venetsanopoulos | try:
|
529 | 13b4c540 | Constantinos Venetsanopoulos | metadata = json.loads(request.raw_post_data)['metadata']
|
530 | 13b4c540 | Constantinos Venetsanopoulos | except Exception as e: |
531 | e646ebe5 | Dimitris Moraitis | log.exception('Malformed create request: %s - %s' \
|
532 | e646ebe5 | Dimitris Moraitis | % (e, request.raw_post_data)) |
533 | 13b4c540 | Constantinos Venetsanopoulos | raise fault.badRequest
|
534 | 13b4c540 | Constantinos Venetsanopoulos | |
535 | 13b4c540 | Constantinos Venetsanopoulos | try:
|
536 | 13b4c540 | Constantinos Venetsanopoulos | vm = VirtualMachine.objects.get(pk=id)
|
537 | 13b4c540 | Constantinos Venetsanopoulos | for x in metadata.keys(): |
538 | e646ebe5 | Dimitris Moraitis | vm_meta, created = (vm.virtualmachinemetadata_set. |
539 | e646ebe5 | Dimitris Moraitis | get_or_create(meta_key=x)) |
540 | e646ebe5 | Dimitris Moraitis | vm_meta.meta_value = metadata[x] |
541 | 13b4c540 | Constantinos Venetsanopoulos | vm_meta.save() |
542 | 13b4c540 | Constantinos Venetsanopoulos | return {
|
543 | 13b4c540 | Constantinos Venetsanopoulos | "metadata": [{
|
544 | e646ebe5 | Dimitris Moraitis | "meta": {
|
545 | e646ebe5 | Dimitris Moraitis | "key": {m.meta_key: m.meta_value}}} \
|
546 | e646ebe5 | Dimitris Moraitis | for m in vm.virtualmachinemetadata_set.all()] |
547 | e646ebe5 | Dimitris Moraitis | } |
548 | 13b4c540 | Constantinos Venetsanopoulos | except VirtualMachine.DoesNotExist:
|
549 | 13b4c540 | Constantinos Venetsanopoulos | raise fault.itemNotFound
|
550 | 13b4c540 | Constantinos Venetsanopoulos | except VirtualMachine.MultipleObjectsReturned:
|
551 | 13b4c540 | Constantinos Venetsanopoulos | raise fault.serviceUnavailable
|
552 | 13b4c540 | Constantinos Venetsanopoulos | except VirtualMachineMetadata.DoesNotExist:
|
553 | 13b4c540 | Constantinos Venetsanopoulos | raise fault.itemNotFound
|
554 | 13b4c540 | Constantinos Venetsanopoulos | except VirtualMachineMetadata.MultipleObjectsReturned:
|
555 | 13b4c540 | Constantinos Venetsanopoulos | raise fault.serviceUnavailable
|
556 | 13b4c540 | Constantinos Venetsanopoulos | except Exception, e: |
557 | 13b4c540 | Constantinos Venetsanopoulos | log.exception('Unexpected error: %s' % e)
|
558 | 13b4c540 | Constantinos Venetsanopoulos | raise fault.serviceUnavailable
|
559 | 60023e66 | Constantinos Venetsanopoulos | |
560 | 13b4c540 | Constantinos Venetsanopoulos | def update(self, request, id, key=None): |
561 | 7abdaf78 | Constantinos Venetsanopoulos | """Update or Create the specified metadata key for the specified VM"""
|
562 | 13b4c540 | Constantinos Venetsanopoulos | if key is None: |
563 | 13b4c540 | Constantinos Venetsanopoulos | log.exception('No metadata key specified in URL')
|
564 | 13b4c540 | Constantinos Venetsanopoulos | raise fault.badRequest
|
565 | 7abdaf78 | Constantinos Venetsanopoulos | try:
|
566 | 7abdaf78 | Constantinos Venetsanopoulos | metadata = json.loads(request.raw_post_data)['meta']
|
567 | 7abdaf78 | Constantinos Venetsanopoulos | metadata_value = metadata[key] |
568 | 7abdaf78 | Constantinos Venetsanopoulos | except Exception as e: |
569 | e646ebe5 | Dimitris Moraitis | log.exception('Malformed create request: %s - %s' \
|
570 | e646ebe5 | Dimitris Moraitis | % (e, request.raw_post_data)) |
571 | 7abdaf78 | Constantinos Venetsanopoulos | raise fault.badRequest
|
572 | 7abdaf78 | Constantinos Venetsanopoulos | |
573 | 7abdaf78 | Constantinos Venetsanopoulos | try:
|
574 | 7abdaf78 | Constantinos Venetsanopoulos | server = VirtualMachine.objects.get(pk=id)
|
575 | e646ebe5 | Dimitris Moraitis | vm_meta, created = (server.virtualmachinemetadata_set. |
576 | e646ebe5 | Dimitris Moraitis | get_or_create(meta_key=key)) |
577 | e646ebe5 | Dimitris Moraitis | vm_meta.meta_value = metadata_value |
578 | 7abdaf78 | Constantinos Venetsanopoulos | vm_meta.save() |
579 | 7abdaf78 | Constantinos Venetsanopoulos | return {"meta": {vm_meta.meta_key: vm_meta.meta_value}} |
580 | e646ebe5 | Dimitris Moraitis | |
581 | 7abdaf78 | Constantinos Venetsanopoulos | except VirtualMachine.DoesNotExist:
|
582 | 7abdaf78 | Constantinos Venetsanopoulos | raise fault.itemNotFound
|
583 | 7abdaf78 | Constantinos Venetsanopoulos | except VirtualMachine.MultipleObjectsReturned:
|
584 | 7abdaf78 | Constantinos Venetsanopoulos | raise fault.serviceUnavailable
|
585 | 7abdaf78 | Constantinos Venetsanopoulos | except VirtualMachineMetadata.DoesNotExist:
|
586 | 7abdaf78 | Constantinos Venetsanopoulos | raise fault.itemNotFound
|
587 | 7abdaf78 | Constantinos Venetsanopoulos | except VirtualMachineMetadata.MultipleObjectsReturned:
|
588 | 7abdaf78 | Constantinos Venetsanopoulos | raise fault.serviceUnavailable
|
589 | 7abdaf78 | Constantinos Venetsanopoulos | except Exception, e: |
590 | 7abdaf78 | Constantinos Venetsanopoulos | log.exception('Unexpected error: %s' % e)
|
591 | 7abdaf78 | Constantinos Venetsanopoulos | raise fault.serviceUnavailable
|
592 | 60023e66 | Constantinos Venetsanopoulos | |
593 | 13b4c540 | Constantinos Venetsanopoulos | def delete(self, request, id, key=None): |
594 | 13b4c540 | Constantinos Venetsanopoulos | """Delete the specified metadata key"""
|
595 | 13b4c540 | Constantinos Venetsanopoulos | if key is None: |
596 | 13b4c540 | Constantinos Venetsanopoulos | log.exception('No metadata key specified in URL')
|
597 | 13b4c540 | Constantinos Venetsanopoulos | raise fault.badRequest
|
598 | e9134601 | Constantinos Venetsanopoulos | try:
|
599 | e9134601 | Constantinos Venetsanopoulos | server = VirtualMachine.objects.get(pk=id)
|
600 | 36d0df36 | Constantinos Venetsanopoulos | server.virtualmachinemetadata_set.get(meta_key=key).delete() |
601 | e9134601 | Constantinos Venetsanopoulos | except VirtualMachineMetadata.DoesNotExist:
|
602 | e9134601 | Constantinos Venetsanopoulos | raise fault.itemNotFound
|
603 | e9134601 | Constantinos Venetsanopoulos | except VirtualMachine.DoesNotExist:
|
604 | e9134601 | Constantinos Venetsanopoulos | raise fault.itemNotFound
|
605 | 36d0df36 | Constantinos Venetsanopoulos | except VirtualMachineMetadata.MultipleObjectsReturned:
|
606 | 36d0df36 | Constantinos Venetsanopoulos | raise fault.serviceUnavailable
|
607 | e9134601 | Constantinos Venetsanopoulos | except VirtualMachine.MultipleObjectsReturned:
|
608 | e9134601 | Constantinos Venetsanopoulos | raise fault.serviceUnavailable
|
609 | e9134601 | Constantinos Venetsanopoulos | except Exception, e: |
610 | e9134601 | Constantinos Venetsanopoulos | log.exception('Unexpected error: %s' % e)
|
611 | e9134601 | Constantinos Venetsanopoulos | raise fault.serviceUnavailable
|
612 | 60023e66 | Constantinos Venetsanopoulos | |
613 | 60023e66 | Constantinos Venetsanopoulos | |
614 | 427a9220 | Faidon Liambotis | class FlavorHandler(BaseHandler): |
615 | ffffd5fe | Markos Gogoulos | """Handler responsible for Flavors
|
616 | ffffd5fe | Markos Gogoulos |
|
617 | ffffd5fe | Markos Gogoulos | """
|
618 | 427a9220 | Faidon Liambotis | allowed_methods = ('GET',)
|
619 | 427a9220 | Faidon Liambotis | |
620 | 427a9220 | Faidon Liambotis | def read(self, request, id=None): |
621 | dcc6a862 | Faidon Liambotis | """
|
622 | dcc6a862 | Faidon Liambotis | List flavors or retrieve one
|
623 | 427a9220 | Faidon Liambotis |
|
624 | 427a9220 | Faidon Liambotis | Returns: OK
|
625 | dcc6a862 | Faidon Liambotis | Faults: cloudServersFault, serviceUnavailable, unauthorized,
|
626 | dcc6a862 | Faidon Liambotis | badRequest, itemNotFound
|
627 | 427a9220 | Faidon Liambotis | """
|
628 | ffffd5fe | Markos Gogoulos | try:
|
629 | ffffd5fe | Markos Gogoulos | flavors = Flavor.objects.all() |
630 | e646ebe5 | Dimitris Moraitis | flavors = [{'id': flavor.id,
|
631 | e646ebe5 | Dimitris Moraitis | 'name': flavor.name,
|
632 | e646ebe5 | Dimitris Moraitis | 'ram': flavor.ram,
|
633 | e646ebe5 | Dimitris Moraitis | 'disk': flavor.disk,
|
634 | e646ebe5 | Dimitris Moraitis | 'cpu': flavor.cpu}
|
635 | e646ebe5 | Dimitris Moraitis | for flavor in flavors] |
636 | ffffd5fe | Markos Gogoulos | |
637 | ffffd5fe | Markos Gogoulos | if id is None: |
638 | ffffd5fe | Markos Gogoulos | simple = map(lambda v: { |
639 | ffffd5fe | Markos Gogoulos | "id": v['id'], |
640 | ffffd5fe | Markos Gogoulos | "name": v['name'], |
641 | ffffd5fe | Markos Gogoulos | }, flavors) |
642 | e646ebe5 | Dimitris Moraitis | return {"flavors": simple} |
643 | ffffd5fe | Markos Gogoulos | elif id == "detail": |
644 | e646ebe5 | Dimitris Moraitis | return {"flavors": flavors} |
645 | ffffd5fe | Markos Gogoulos | else:
|
646 | ffffd5fe | Markos Gogoulos | flavor = Flavor.objects.get(id=id)
|
647 | e646ebe5 | Dimitris Moraitis | return {"flavor": { |
648 | ffffd5fe | Markos Gogoulos | 'id': flavor.id,
|
649 | ffffd5fe | Markos Gogoulos | 'name': flavor.name,
|
650 | ffffd5fe | Markos Gogoulos | 'ram': flavor.ram,
|
651 | e646ebe5 | Dimitris Moraitis | 'disk': flavor.disk,
|
652 | e646ebe5 | Dimitris Moraitis | 'cpu': flavor.cpu,
|
653 | e646ebe5 | Dimitris Moraitis | }} |
654 | ffffd5fe | Markos Gogoulos | |
655 | ffffd5fe | Markos Gogoulos | except Flavor.DoesNotExist:
|
656 | 635cfd6e | Faidon Liambotis | raise fault.itemNotFound
|
657 | ffffd5fe | Markos Gogoulos | except Flavor.MultipleObjectsReturned:
|
658 | ffffd5fe | Markos Gogoulos | raise fault.serviceUnavailable
|
659 | ffffd5fe | Markos Gogoulos | except Exception, e: |
660 | 6b83d46b | Markos Gogoulos | log.exception('Unexpected error: %s' % e)
|
661 | ffffd5fe | Markos Gogoulos | raise fault.serviceUnavailable
|
662 | dcc6a862 | Faidon Liambotis | |
663 | dcc6a862 | Faidon Liambotis | |
664 | dcc6a862 | Faidon Liambotis | class ImageHandler(BaseHandler): |
665 | f5ea24a9 | Markos Gogoulos | """Handler responsible for Images
|
666 | f5ea24a9 | Markos Gogoulos |
|
667 | e646ebe5 | Dimitris Moraitis | handles the listing, creation and delete of Images.
|
668 | f5ea24a9 | Markos Gogoulos |
|
669 | f5ea24a9 | Markos Gogoulos | @HTTP methods: GET, POST
|
670 | e646ebe5 | Dimitris Moraitis | @Parameters: POST data
|
671 | e646ebe5 | Dimitris Moraitis | @Responses: HTTP 202 if successfully create Image or get the Images list,
|
672 | e646ebe5 | Dimitris Moraitis | itemNotFound, serviceUnavailable otherwise
|
673 | f5ea24a9 | Markos Gogoulos |
|
674 | f5ea24a9 | Markos Gogoulos | """
|
675 | f5ea24a9 | Markos Gogoulos | |
676 | dcc6a862 | Faidon Liambotis | allowed_methods = ('GET', 'POST') |
677 | dcc6a862 | Faidon Liambotis | |
678 | dcc6a862 | Faidon Liambotis | def read(self, request, id=None): |
679 | dcc6a862 | Faidon Liambotis | """
|
680 | dcc6a862 | Faidon Liambotis | List images or retrieve one
|
681 | dcc6a862 | Faidon Liambotis |
|
682 | dcc6a862 | Faidon Liambotis | Returns: OK
|
683 | dcc6a862 | Faidon Liambotis | Faults: cloudServersFault, serviceUnavailable, unauthorized,
|
684 | dcc6a862 | Faidon Liambotis | badRequest, itemNotFound
|
685 | dcc6a862 | Faidon Liambotis | """
|
686 | c5a032c4 | Markos Gogoulos | |
687 | c5a032c4 | Markos Gogoulos | #changes_since should be on ISO 8601 format
|
688 | c5a032c4 | Markos Gogoulos | try:
|
689 | c5a032c4 | Markos Gogoulos | changes_since = request.GET.get("changes-since", 0) |
690 | c5a032c4 | Markos Gogoulos | if changes_since:
|
691 | e646ebe5 | Dimitris Moraitis | last_update = datetime.strptime(changes_since, |
692 | e646ebe5 | Dimitris Moraitis | "%Y-%m-%dT%H:%M:%S")
|
693 | 54f8cd6d | Markos Gogoulos | #return a badRequest if the changes_since is older than a limit
|
694 | e646ebe5 | Dimitris Moraitis | if datetime.now() - last_update > timedelta(
|
695 | e646ebe5 | Dimitris Moraitis | seconds=settings.POLL_LIMIT): |
696 | e646ebe5 | Dimitris Moraitis | raise fault.badRequest
|
697 | c5a032c4 | Markos Gogoulos | images = Image.objects.filter(updated__gt=last_update) |
698 | c5a032c4 | Markos Gogoulos | if not len(images): |
699 | c5a032c4 | Markos Gogoulos | return notModified
|
700 | c5a032c4 | Markos Gogoulos | else:
|
701 | c5a032c4 | Markos Gogoulos | images = Image.objects.all() |
702 | c5a032c4 | Markos Gogoulos | except Exception, e: |
703 | e646ebe5 | Dimitris Moraitis | raise fault.badRequest
|
704 | ffffd5fe | Markos Gogoulos | try:
|
705 | e646ebe5 | Dimitris Moraitis | images_list = [{'created': image.created.isoformat(),
|
706 | ffffd5fe | Markos Gogoulos | 'id': image.id,
|
707 | ffffd5fe | Markos Gogoulos | 'name': image.name,
|
708 | e646ebe5 | Dimitris Moraitis | 'updated': image.updated.isoformat(),
|
709 | e646ebe5 | Dimitris Moraitis | 'status': image.state,
|
710 | e646ebe5 | Dimitris Moraitis | 'progress': image.state == 'ACTIVE' and 100 or 0, |
711 | e646ebe5 | Dimitris Moraitis | 'size': image.size,
|
712 | 4e6f9904 | Markos Gogoulos | 'serverId': image.sourcevm and image.sourcevm.id or "", |
713 | e646ebe5 | Dimitris Moraitis | #'metadata':[{'meta':
|
714 | e646ebe5 | Dimitris Moraitis | #{ 'key': {metadata.meta_key: metadata.meta_value}}}
|
715 | e646ebe5 | Dimitris Moraitis | #for metadata in image.imagemetadata_set.all()]
|
716 | e646ebe5 | Dimitris Moraitis | 'metadata':{'meta': |
717 | e646ebe5 | Dimitris Moraitis | {'key': {'description': image.description}}}, |
718 | ffffd5fe | Markos Gogoulos | } for image in images] |
719 | ffffd5fe | Markos Gogoulos | # Images info is stored in the DB. Ganeti is not aware of this
|
720 | ffffd5fe | Markos Gogoulos | if id == "detail": |
721 | e646ebe5 | Dimitris Moraitis | return {"images": images_list} |
722 | ffffd5fe | Markos Gogoulos | elif id is None: |
723 | e646ebe5 | Dimitris Moraitis | return {"images": [{"id": s['id'], "name": s['name']} \ |
724 | e646ebe5 | Dimitris Moraitis | for s in images_list]} |
725 | e646ebe5 | Dimitris Moraitis | else:
|
726 | ffffd5fe | Markos Gogoulos | image = images.get(id=id)
|
727 | e646ebe5 | Dimitris Moraitis | return {"image": {'created': image.created.isoformat(), |
728 | 12827073 | Markos Gogoulos | 'id': image.id,
|
729 | 12827073 | Markos Gogoulos | 'name': image.name,
|
730 | e646ebe5 | Dimitris Moraitis | 'updated': image.updated.isoformat(),
|
731 | e646ebe5 | Dimitris Moraitis | 'description': image.description,
|
732 | e646ebe5 | Dimitris Moraitis | 'status': image.state,
|
733 | e646ebe5 | Dimitris Moraitis | 'progress': image.state == 'ACTIVE' and 100 or 0, |
734 | e646ebe5 | Dimitris Moraitis | 'size': image.size,
|
735 | 4e6f9904 | Markos Gogoulos | 'serverId': image.sourcevm and image.sourcevm.id or "", |
736 | e646ebe5 | Dimitris Moraitis | #'metadata':[{'meta': { 'key':
|
737 | e646ebe5 | Dimitris Moraitis | #{metadata.meta_key: metadata.meta_value}}}
|
738 | e646ebe5 | Dimitris Moraitis | #for metadata in image.imagemetadata_set.all()]
|
739 | e646ebe5 | Dimitris Moraitis | 'metadata': {
|
740 | e646ebe5 | Dimitris Moraitis | 'meta': {'key': {'description': image.description}}}, |
741 | e646ebe5 | Dimitris Moraitis | }} |
742 | ffffd5fe | Markos Gogoulos | except Image.DoesNotExist:
|
743 | ffffd5fe | Markos Gogoulos | raise fault.itemNotFound
|
744 | ffffd5fe | Markos Gogoulos | except Image.MultipleObjectsReturned:
|
745 | ffffd5fe | Markos Gogoulos | raise fault.serviceUnavailable
|
746 | ffffd5fe | Markos Gogoulos | except Exception, e: |
747 | 6b83d46b | Markos Gogoulos | log.exception('Unexpected error: %s' % e)
|
748 | ffffd5fe | Markos Gogoulos | raise fault.serviceUnavailable
|
749 | dcc6a862 | Faidon Liambotis | |
750 | dcc6a862 | Faidon Liambotis | def create(self, request): |
751 | dcc6a862 | Faidon Liambotis | """Create a new image"""
|
752 | dcc6a862 | Faidon Liambotis | return accepted
|
753 | ed66d976 | Faidon Liambotis | |
754 | ed66d976 | Faidon Liambotis | |
755 | 60023e66 | Constantinos Venetsanopoulos | class ImageMetadataHandler(BaseHandler): |
756 | 60023e66 | Constantinos Venetsanopoulos | """Handles Metadata of a specific Image
|
757 | 60023e66 | Constantinos Venetsanopoulos |
|
758 | 60023e66 | Constantinos Venetsanopoulos | the handler Lists, Creates, Updates and Deletes Metadata values
|
759 | 60023e66 | Constantinos Venetsanopoulos |
|
760 | 60023e66 | Constantinos Venetsanopoulos | @HTTP methods: POST, DELETE, PUT, GET
|
761 | 60023e66 | Constantinos Venetsanopoulos | @Parameters: POST data with key value pairs
|
762 | 60023e66 | Constantinos Venetsanopoulos |
|
763 | 60023e66 | Constantinos Venetsanopoulos | """
|
764 | 60023e66 | Constantinos Venetsanopoulos | allowed_methods = ('GET', 'POST', 'PUT', 'DELETE') |
765 | 60023e66 | Constantinos Venetsanopoulos | |
766 | 60023e66 | Constantinos Venetsanopoulos | def read(self, request, id, key=None): |
767 | 60023e66 | Constantinos Venetsanopoulos | """List metadata of the specific server"""
|
768 | 60023e66 | Constantinos Venetsanopoulos | if key is None: |
769 | 60023e66 | Constantinos Venetsanopoulos | return self.read_allkeys(request, id) |
770 | 60023e66 | Constantinos Venetsanopoulos | else:
|
771 | 60023e66 | Constantinos Venetsanopoulos | return self.read_onekey(request, id, key) |
772 | 60023e66 | Constantinos Venetsanopoulos | |
773 | 60023e66 | Constantinos Venetsanopoulos | def read_allkeys(self, request, id): |
774 | 60023e66 | Constantinos Venetsanopoulos | """Returns all the key value pairs of the specified server"""
|
775 | 60023e66 | Constantinos Venetsanopoulos | try:
|
776 | e9134601 | Constantinos Venetsanopoulos | image = Image.objects.get(pk=id)
|
777 | 60023e66 | Constantinos Venetsanopoulos | return {
|
778 | 60023e66 | Constantinos Venetsanopoulos | "metadata": [{
|
779 | e646ebe5 | Dimitris Moraitis | "meta": {
|
780 | e646ebe5 | Dimitris Moraitis | "key": {m.meta_key: m.meta_value}}} \
|
781 | e646ebe5 | Dimitris Moraitis | for m in image.imagemetadata_set.all()] |
782 | 60023e66 | Constantinos Venetsanopoulos | } |
783 | 60023e66 | Constantinos Venetsanopoulos | except Image.DoesNotExist:
|
784 | 60023e66 | Constantinos Venetsanopoulos | raise fault.itemNotFound
|
785 | 60023e66 | Constantinos Venetsanopoulos | except Image.MultipleObjectsReturned:
|
786 | 60023e66 | Constantinos Venetsanopoulos | raise fault.serviceUnavailable
|
787 | 60023e66 | Constantinos Venetsanopoulos | except Exception, e: |
788 | 60023e66 | Constantinos Venetsanopoulos | log.exception('Unexpected error: %s' % e)
|
789 | 60023e66 | Constantinos Venetsanopoulos | raise fault.serviceUnavailable
|
790 | e646ebe5 | Dimitris Moraitis | |
791 | 60023e66 | Constantinos Venetsanopoulos | def read_onekey(self, request, id, key): |
792 | 60023e66 | Constantinos Venetsanopoulos | """Returns the specified metadata key of the specified server"""
|
793 | 60023e66 | Constantinos Venetsanopoulos | try:
|
794 | 60023e66 | Constantinos Venetsanopoulos | image = Image.objects.get(pk=id)
|
795 | 60023e66 | Constantinos Venetsanopoulos | return {
|
796 | 60023e66 | Constantinos Venetsanopoulos | "metadata": {
|
797 | 60023e66 | Constantinos Venetsanopoulos | "values": [
|
798 | e646ebe5 | Dimitris Moraitis | {m.meta_key: m.meta_value} \ |
799 | e646ebe5 | Dimitris Moraitis | for m in image.imagemetadata_set.filter(meta_key=key) |
800 | 60023e66 | Constantinos Venetsanopoulos | ] |
801 | 60023e66 | Constantinos Venetsanopoulos | } |
802 | 60023e66 | Constantinos Venetsanopoulos | } |
803 | 60023e66 | Constantinos Venetsanopoulos | except ImageMetadata.DoesNotExist:
|
804 | e646ebe5 | Dimitris Moraitis | raise fault.itemNotFound
|
805 | 60023e66 | Constantinos Venetsanopoulos | except Image.DoesNotExist:
|
806 | 60023e66 | Constantinos Venetsanopoulos | raise fault.itemNotFound
|
807 | 60023e66 | Constantinos Venetsanopoulos | except Image.MultipleObjectsReturned:
|
808 | 60023e66 | Constantinos Venetsanopoulos | raise fault.serviceUnavailable
|
809 | 60023e66 | Constantinos Venetsanopoulos | except Exception, e: |
810 | 60023e66 | Constantinos Venetsanopoulos | log.exception('Unexpected error: %s' % e)
|
811 | 60023e66 | Constantinos Venetsanopoulos | raise fault.serviceUnavailable
|
812 | 60023e66 | Constantinos Venetsanopoulos | |
813 | 13b4c540 | Constantinos Venetsanopoulos | def create(self, request, id, key=None): |
814 | 13b4c540 | Constantinos Venetsanopoulos | """Create or Update all metadata for the specified Image"""
|
815 | 13b4c540 | Constantinos Venetsanopoulos | if key is not None: |
816 | 13b4c540 | Constantinos Venetsanopoulos | log.exception('The POST request should not pass a key in the URL')
|
817 | 13b4c540 | Constantinos Venetsanopoulos | raise fault.badRequest
|
818 | 13b4c540 | Constantinos Venetsanopoulos | try:
|
819 | 13b4c540 | Constantinos Venetsanopoulos | metadata = json.loads(request.raw_post_data)['metadata']
|
820 | 13b4c540 | Constantinos Venetsanopoulos | except Exception as e: |
821 | e646ebe5 | Dimitris Moraitis | log.exception('Malformed create request: %s - %s' \
|
822 | e646ebe5 | Dimitris Moraitis | % (e, request.raw_post_data)) |
823 | 13b4c540 | Constantinos Venetsanopoulos | raise fault.badRequest
|
824 | 13b4c540 | Constantinos Venetsanopoulos | |
825 | 13b4c540 | Constantinos Venetsanopoulos | try:
|
826 | 13b4c540 | Constantinos Venetsanopoulos | image = Image.objects.get(pk=id)
|
827 | 13b4c540 | Constantinos Venetsanopoulos | for x in metadata.keys(): |
828 | e646ebe5 | Dimitris Moraitis | img_meta, created = (image.imagemetadata_set. |
829 | e646ebe5 | Dimitris Moraitis | get_or_create(meta_key=x)) |
830 | e646ebe5 | Dimitris Moraitis | img_meta.meta_value = metadata[x] |
831 | 13b4c540 | Constantinos Venetsanopoulos | img_meta.save() |
832 | 13b4c540 | Constantinos Venetsanopoulos | return {
|
833 | 13b4c540 | Constantinos Venetsanopoulos | "metadata": [{
|
834 | e646ebe5 | Dimitris Moraitis | "meta": {
|
835 | e646ebe5 | Dimitris Moraitis | "key": {m.meta_key: m.meta_value}}} \
|
836 | e646ebe5 | Dimitris Moraitis | for m in image.imagemetadata_set.all()] |
837 | e646ebe5 | Dimitris Moraitis | } |
838 | 13b4c540 | Constantinos Venetsanopoulos | except Image.DoesNotExist:
|
839 | 13b4c540 | Constantinos Venetsanopoulos | raise fault.itemNotFound
|
840 | 13b4c540 | Constantinos Venetsanopoulos | except Image.MultipleObjectsReturned:
|
841 | 13b4c540 | Constantinos Venetsanopoulos | raise fault.serviceUnavailable
|
842 | 13b4c540 | Constantinos Venetsanopoulos | except ImageMetadata.DoesNotExist:
|
843 | 13b4c540 | Constantinos Venetsanopoulos | raise fault.itemNotFound
|
844 | 13b4c540 | Constantinos Venetsanopoulos | except ImageMetadata.MultipleObjectsReturned:
|
845 | 13b4c540 | Constantinos Venetsanopoulos | raise fault.serviceUnavailable
|
846 | 13b4c540 | Constantinos Venetsanopoulos | except Exception, e: |
847 | 13b4c540 | Constantinos Venetsanopoulos | log.exception('Unexpected error: %s' % e)
|
848 | 13b4c540 | Constantinos Venetsanopoulos | raise fault.serviceUnavailable
|
849 | 60023e66 | Constantinos Venetsanopoulos | |
850 | 13b4c540 | Constantinos Venetsanopoulos | def update(self, request, id, key=None): |
851 | e646ebe5 | Dimitris Moraitis | """Update or Create the specified metadata key for the
|
852 | e646ebe5 | Dimitris Moraitis | specified Image"""
|
853 | 13b4c540 | Constantinos Venetsanopoulos | if key is None: |
854 | 13b4c540 | Constantinos Venetsanopoulos | log.exception('No metadata key specified in URL')
|
855 | 13b4c540 | Constantinos Venetsanopoulos | raise fault.badRequest
|
856 | 7abdaf78 | Constantinos Venetsanopoulos | try:
|
857 | 7abdaf78 | Constantinos Venetsanopoulos | metadata = json.loads(request.raw_post_data)['meta']
|
858 | 7abdaf78 | Constantinos Venetsanopoulos | metadata_value = metadata[key] |
859 | 7abdaf78 | Constantinos Venetsanopoulos | except Exception as e: |
860 | e646ebe5 | Dimitris Moraitis | log.exception('Malformed create request: %s - %s' \
|
861 | e646ebe5 | Dimitris Moraitis | % (e, request.raw_post_data)) |
862 | 7abdaf78 | Constantinos Venetsanopoulos | raise fault.badRequest
|
863 | 7abdaf78 | Constantinos Venetsanopoulos | |
864 | 7abdaf78 | Constantinos Venetsanopoulos | try:
|
865 | 7abdaf78 | Constantinos Venetsanopoulos | image = Image.objects.get(pk=id)
|
866 | e646ebe5 | Dimitris Moraitis | img_meta, created = (image.imagemetadata_set. |
867 | e646ebe5 | Dimitris Moraitis | get_or_create(meta_key=key)) |
868 | e646ebe5 | Dimitris Moraitis | img_meta.meta_value = metadata_value |
869 | 7abdaf78 | Constantinos Venetsanopoulos | img_meta.save() |
870 | 7abdaf78 | Constantinos Venetsanopoulos | return {"meta": {img_meta.meta_key: img_meta.meta_value}} |
871 | e646ebe5 | Dimitris Moraitis | |
872 | 7abdaf78 | Constantinos Venetsanopoulos | except Image.DoesNotExist:
|
873 | 7abdaf78 | Constantinos Venetsanopoulos | raise fault.itemNotFound
|
874 | 7abdaf78 | Constantinos Venetsanopoulos | except Image.MultipleObjectsReturned:
|
875 | 7abdaf78 | Constantinos Venetsanopoulos | raise fault.serviceUnavailable
|
876 | 7abdaf78 | Constantinos Venetsanopoulos | except ImageMetadata.DoesNotExist:
|
877 | 7abdaf78 | Constantinos Venetsanopoulos | raise fault.itemNotFound
|
878 | 7abdaf78 | Constantinos Venetsanopoulos | except ImageMetadata.MultipleObjectsReturned:
|
879 | 7abdaf78 | Constantinos Venetsanopoulos | raise fault.serviceUnavailable
|
880 | 7abdaf78 | Constantinos Venetsanopoulos | except Exception, e: |
881 | 7abdaf78 | Constantinos Venetsanopoulos | log.exception('Unexpected error: %s' % e)
|
882 | 7abdaf78 | Constantinos Venetsanopoulos | raise fault.serviceUnavailable
|
883 | 60023e66 | Constantinos Venetsanopoulos | |
884 | 13b4c540 | Constantinos Venetsanopoulos | def delete(self, request, id, key=None): |
885 | 13b4c540 | Constantinos Venetsanopoulos | """Delete the specified metadata key"""
|
886 | 13b4c540 | Constantinos Venetsanopoulos | if key is None: |
887 | 13b4c540 | Constantinos Venetsanopoulos | log.exception('No metadata key specified in URL')
|
888 | 13b4c540 | Constantinos Venetsanopoulos | raise fault.badRequest
|
889 | e9134601 | Constantinos Venetsanopoulos | try:
|
890 | e9134601 | Constantinos Venetsanopoulos | image = Image.objects.get(pk=id)
|
891 | 36d0df36 | Constantinos Venetsanopoulos | image.imagemetadata_set.get(meta_key=key).delete() |
892 | e9134601 | Constantinos Venetsanopoulos | except ImageMetadata.DoesNotExist:
|
893 | e9134601 | Constantinos Venetsanopoulos | raise fault.itemNotFound
|
894 | e9134601 | Constantinos Venetsanopoulos | except Image.DoesNotExist:
|
895 | e9134601 | Constantinos Venetsanopoulos | raise fault.itemNotFound
|
896 | 36d0df36 | Constantinos Venetsanopoulos | except ImageMetadata.MultipleObjectsReturned:
|
897 | 36d0df36 | Constantinos Venetsanopoulos | raise fault.serviceUnavailable
|
898 | e9134601 | Constantinos Venetsanopoulos | except Image.MultipleObjectsReturned:
|
899 | e9134601 | Constantinos Venetsanopoulos | raise fault.serviceUnavailable
|
900 | e9134601 | Constantinos Venetsanopoulos | except Exception, e: |
901 | e9134601 | Constantinos Venetsanopoulos | log.exception('Unexpected error: %s' % e)
|
902 | e9134601 | Constantinos Venetsanopoulos | raise fault.serviceUnavailable
|
903 | 60023e66 | Constantinos Venetsanopoulos | |
904 | 60023e66 | Constantinos Venetsanopoulos | |
905 | ed66d976 | Faidon Liambotis | class SharedIPGroupHandler(BaseHandler): |
906 | ed66d976 | Faidon Liambotis | allowed_methods = ('GET', 'POST', 'DELETE') |
907 | ed66d976 | Faidon Liambotis | |
908 | ed66d976 | Faidon Liambotis | def read(self, request, id=None): |
909 | ed66d976 | Faidon Liambotis | """List Shared IP Groups"""
|
910 | ed66d976 | Faidon Liambotis | if id is None: |
911 | ed66d976 | Faidon Liambotis | return {}
|
912 | ed66d976 | Faidon Liambotis | elif id == "detail": |
913 | ed66d976 | Faidon Liambotis | return {}
|
914 | ed66d976 | Faidon Liambotis | else:
|
915 | 635cfd6e | Faidon Liambotis | raise fault.itemNotFound
|
916 | ed66d976 | Faidon Liambotis | |
917 | ed66d976 | Faidon Liambotis | def create(self, request, id): |
918 | ed66d976 | Faidon Liambotis | """Creates a new Shared IP Group"""
|
919 | ed66d976 | Faidon Liambotis | return created
|
920 | ed66d976 | Faidon Liambotis | |
921 | ed66d976 | Faidon Liambotis | def delete(self, request, id): |
922 | ed66d976 | Faidon Liambotis | """Deletes a Shared IP Group"""
|
923 | f0858246 | Markos Gogoulos | raise fault.itemNotFound
|
924 | beb79c95 | Faidon Liambotis | |
925 | beb79c95 | Faidon Liambotis | |
926 | a31ff6cb | Markos Gogoulos | class VirtualMachineGroupHandler(BaseHandler): |
927 | 59cee068 | Markos Gogoulos | """Handler responsible for Virtual Machine Groups
|
928 | 59cee068 | Markos Gogoulos |
|
929 | 59cee068 | Markos Gogoulos | creates, lists, deletes virtual machine groups
|
930 | 59cee068 | Markos Gogoulos |
|
931 | 59cee068 | Markos Gogoulos | @HTTP methods: GET, POST, DELETE
|
932 | e646ebe5 | Dimitris Moraitis | @Parameters: POST data
|
933 | e646ebe5 | Dimitris Moraitis | @Responses: HTTP 202 if successfully get the Groups list,
|
934 | e646ebe5 | Dimitris Moraitis | itemNotFound, serviceUnavailable otherwise
|
935 | 59cee068 | Markos Gogoulos |
|
936 | 59cee068 | Markos Gogoulos | """
|
937 | 59cee068 | Markos Gogoulos | |
938 | a31ff6cb | Markos Gogoulos | allowed_methods = ('GET', 'POST', 'DELETE') |
939 | a31ff6cb | Markos Gogoulos | |
940 | a31ff6cb | Markos Gogoulos | def read(self, request, id=None): |
941 | a31ff6cb | Markos Gogoulos | """List Groups"""
|
942 | ffffd5fe | Markos Gogoulos | try:
|
943 | e646ebe5 | Dimitris Moraitis | vmgroups = VirtualMachineGroup.objects.all() |
944 | e646ebe5 | Dimitris Moraitis | vmgroups_list = [{'id': vmgroup.id, \
|
945 | ffffd5fe | Markos Gogoulos | 'name': vmgroup.name, \
|
946 | e646ebe5 | Dimitris Moraitis | 'server_id':
|
947 | e646ebe5 | Dimitris Moraitis | [machine.id for machine in vmgroup.machines.all()] |
948 | ffffd5fe | Markos Gogoulos | } for vmgroup in vmgroups] |
949 | ffffd5fe | Markos Gogoulos | # Group info is stored in the DB. Ganeti is not aware of this
|
950 | ffffd5fe | Markos Gogoulos | if id == "detail": |
951 | e646ebe5 | Dimitris Moraitis | return {"groups": vmgroups_list} |
952 | ffffd5fe | Markos Gogoulos | elif id is None: |
953 | e646ebe5 | Dimitris Moraitis | return {"groups": [{"id": s['id'], |
954 | e646ebe5 | Dimitris Moraitis | "name": s['name']} for s in vmgroups_list]} |
955 | ffffd5fe | Markos Gogoulos | else:
|
956 | a8acbbac | Markos Gogoulos | vmgroup = vmgroups.get(id=id)
|
957 | 59cee068 | Markos Gogoulos | |
958 | e646ebe5 | Dimitris Moraitis | return {"group": {'id': vmgroup.id, |
959 | e646ebe5 | Dimitris Moraitis | 'name': vmgroup.name,
|
960 | e646ebe5 | Dimitris Moraitis | 'server_id':
|
961 | e646ebe5 | Dimitris Moraitis | [machine.id for machine in vmgroup.machines.all()] |
962 | e646ebe5 | Dimitris Moraitis | }} |
963 | 59cee068 | Markos Gogoulos | |
964 | 59cee068 | Markos Gogoulos | except VirtualMachineGroup.DoesNotExist:
|
965 | 59cee068 | Markos Gogoulos | raise fault.itemNotFound
|
966 | 59cee068 | Markos Gogoulos | except VirtualMachineGroup.MultipleObjectsReturned:
|
967 | 59cee068 | Markos Gogoulos | raise fault.serviceUnavailable
|
968 | ffffd5fe | Markos Gogoulos | except Exception, e: |
969 | 6b83d46b | Markos Gogoulos | log.exception('Unexpected error: %s' % e)
|
970 | ffffd5fe | Markos Gogoulos | raise fault.serviceUnavailable
|
971 | a31ff6cb | Markos Gogoulos | |
972 | a31ff6cb | Markos Gogoulos | def create(self, request, id): |
973 | a31ff6cb | Markos Gogoulos | """Creates a Group"""
|
974 | a31ff6cb | Markos Gogoulos | return created
|
975 | a31ff6cb | Markos Gogoulos | |
976 | a31ff6cb | Markos Gogoulos | def delete(self, request, id): |
977 | a31ff6cb | Markos Gogoulos | """Deletes a Group"""
|
978 | f0858246 | Markos Gogoulos | raise fault.itemNotFound
|
979 | a31ff6cb | Markos Gogoulos | |
980 | a31ff6cb | Markos Gogoulos | |
981 | beb79c95 | Faidon Liambotis | class LimitHandler(BaseHandler): |
982 | beb79c95 | Faidon Liambotis | allowed_methods = ('GET',)
|
983 | beb79c95 | Faidon Liambotis | |
984 | beb79c95 | Faidon Liambotis | # XXX: hookup with @throttle
|
985 | beb79c95 | Faidon Liambotis | |
986 | beb79c95 | Faidon Liambotis | rate = [ |
987 | beb79c95 | Faidon Liambotis | { |
988 | e646ebe5 | Dimitris Moraitis | "verb": "POST", |
989 | e646ebe5 | Dimitris Moraitis | "URI": "*", |
990 | e646ebe5 | Dimitris Moraitis | "regex": ".*", |
991 | e646ebe5 | Dimitris Moraitis | "value": 10, |
992 | e646ebe5 | Dimitris Moraitis | "remaining": 2, |
993 | e646ebe5 | Dimitris Moraitis | "unit": "MINUTE", |
994 | e646ebe5 | Dimitris Moraitis | "resetTime": 1244425439 |
995 | beb79c95 | Faidon Liambotis | }, |
996 | beb79c95 | Faidon Liambotis | { |
997 | e646ebe5 | Dimitris Moraitis | "verb": "POST", |
998 | e646ebe5 | Dimitris Moraitis | "URI": "*/servers", |
999 | e646ebe5 | Dimitris Moraitis | "regex": "^/servers", |
1000 | e646ebe5 | Dimitris Moraitis | "value": 25, |
1001 | e646ebe5 | Dimitris Moraitis | "remaining": 24, |
1002 | e646ebe5 | Dimitris Moraitis | "unit": "DAY", |
1003 | e646ebe5 | Dimitris Moraitis | "resetTime": 1244511839 |
1004 | beb79c95 | Faidon Liambotis | }, |
1005 | beb79c95 | Faidon Liambotis | { |
1006 | e646ebe5 | Dimitris Moraitis | "verb": "PUT", |
1007 | e646ebe5 | Dimitris Moraitis | "URI": "*", |
1008 | e646ebe5 | Dimitris Moraitis | "regex": ".*", |
1009 | e646ebe5 | Dimitris Moraitis | "value": 10, |
1010 | e646ebe5 | Dimitris Moraitis | "remaining": 2, |
1011 | e646ebe5 | Dimitris Moraitis | "unit": "MINUTE", |
1012 | e646ebe5 | Dimitris Moraitis | "resetTime": 1244425439 |
1013 | beb79c95 | Faidon Liambotis | }, |
1014 | beb79c95 | Faidon Liambotis | { |
1015 | e646ebe5 | Dimitris Moraitis | "verb": "GET", |
1016 | e646ebe5 | Dimitris Moraitis | "URI": "*", |
1017 | e646ebe5 | Dimitris Moraitis | "regex": ".*", |
1018 | e646ebe5 | Dimitris Moraitis | "value": 3, |
1019 | e646ebe5 | Dimitris Moraitis | "remaining": 3, |
1020 | e646ebe5 | Dimitris Moraitis | "unit": "MINUTE", |
1021 | e646ebe5 | Dimitris Moraitis | "resetTime": 1244425439 |
1022 | beb79c95 | Faidon Liambotis | }, |
1023 | beb79c95 | Faidon Liambotis | { |
1024 | e646ebe5 | Dimitris Moraitis | "verb": "DELETE", |
1025 | e646ebe5 | Dimitris Moraitis | "URI": "*", |
1026 | e646ebe5 | Dimitris Moraitis | "regex": ".*", |
1027 | e646ebe5 | Dimitris Moraitis | "value": 100, |
1028 | e646ebe5 | Dimitris Moraitis | "remaining": 100, |
1029 | e646ebe5 | Dimitris Moraitis | "unit": "MINUTE", |
1030 | e646ebe5 | Dimitris Moraitis | "resetTime": 1244425439 |
1031 | beb79c95 | Faidon Liambotis | } |
1032 | beb79c95 | Faidon Liambotis | ] |
1033 | beb79c95 | Faidon Liambotis | |
1034 | beb79c95 | Faidon Liambotis | absolute = { |
1035 | e646ebe5 | Dimitris Moraitis | "maxTotalRAMSize": 51200, |
1036 | e646ebe5 | Dimitris Moraitis | "maxIPGroups": 50, |
1037 | e646ebe5 | Dimitris Moraitis | "maxIPGroupMembers": 25 |
1038 | beb79c95 | Faidon Liambotis | } |
1039 | beb79c95 | Faidon Liambotis | |
1040 | beb79c95 | Faidon Liambotis | def read(self, request): |
1041 | e646ebe5 | Dimitris Moraitis | return {"limits": { |
1042 | beb79c95 | Faidon Liambotis | "rate": self.rate, |
1043 | beb79c95 | Faidon Liambotis | "absolute": self.absolute, |
1044 | beb79c95 | Faidon Liambotis | } |
1045 | beb79c95 | Faidon Liambotis | } |
1046 | 9071888e | Constantinos Venetsanopoulos | |
1047 | 9071888e | Constantinos Venetsanopoulos | |
1048 | 9071888e | Constantinos Venetsanopoulos | class DiskHandler(BaseHandler): |
1049 | 9071888e | Constantinos Venetsanopoulos | allowed_methods = ('GET', 'POST', 'PUT', 'DELETE') |
1050 | 9071888e | Constantinos Venetsanopoulos | |
1051 | 9071888e | Constantinos Venetsanopoulos | def read(self, request, id=None): |
1052 | 9071888e | Constantinos Venetsanopoulos | """List Disks"""
|
1053 | 9071888e | Constantinos Venetsanopoulos | if id is None: |
1054 | 9071888e | Constantinos Venetsanopoulos | return self.read_all(request) |
1055 | 9071888e | Constantinos Venetsanopoulos | elif id == "detail": |
1056 | 9071888e | Constantinos Venetsanopoulos | return self.read_all(request, detail=True) |
1057 | 9071888e | Constantinos Venetsanopoulos | else:
|
1058 | 9071888e | Constantinos Venetsanopoulos | return self.read_one(request, id) |
1059 | 9071888e | Constantinos Venetsanopoulos | |
1060 | 9071888e | Constantinos Venetsanopoulos | def read_one(self, request, id): |
1061 | 9071888e | Constantinos Venetsanopoulos | """List one Disk with the specified id with all details"""
|
1062 | e646ebe5 | Dimitris Moraitis | # FIXME Get detailed info from the DB
|
1063 | 9071888e | Constantinos Venetsanopoulos | # for the Disk with the specified id
|
1064 | 9071888e | Constantinos Venetsanopoulos | try:
|
1065 | 9071888e | Constantinos Venetsanopoulos | disk = Disk.objects.get(pk=id)
|
1066 | 9071888e | Constantinos Venetsanopoulos | disk_details = { |
1067 | e646ebe5 | Dimitris Moraitis | "id": disk.id,
|
1068 | e646ebe5 | Dimitris Moraitis | "name": disk.name,
|
1069 | e646ebe5 | Dimitris Moraitis | "size": disk.size,
|
1070 | e646ebe5 | Dimitris Moraitis | "created": disk.created,
|
1071 | e646ebe5 | Dimitris Moraitis | "serverId": disk.vm.id
|
1072 | 9071888e | Constantinos Venetsanopoulos | } |
1073 | e646ebe5 | Dimitris Moraitis | return {"disks": disk_details} |
1074 | 9071888e | Constantinos Venetsanopoulos | except:
|
1075 | 9071888e | Constantinos Venetsanopoulos | raise fault.itemNotFound
|
1076 | 9071888e | Constantinos Venetsanopoulos | |
1077 | 9071888e | Constantinos Venetsanopoulos | @paginator
|
1078 | 9071888e | Constantinos Venetsanopoulos | def read_all(self, request, detail=False): |
1079 | 9071888e | Constantinos Venetsanopoulos | """List all Disks. If -detail- is set list them with all details"""
|
1080 | 9071888e | Constantinos Venetsanopoulos | if not detail: |
1081 | 9071888e | Constantinos Venetsanopoulos | disks = Disk.objects.filter(owner=SynnefoUser.objects.all()[0])
|
1082 | e646ebe5 | Dimitris Moraitis | return {"disks": [{"id": disk.id, "name": disk.name} \ |
1083 | e646ebe5 | Dimitris Moraitis | for disk in disks]} |
1084 | 9071888e | Constantinos Venetsanopoulos | else:
|
1085 | 9071888e | Constantinos Venetsanopoulos | disks = Disk.objects.filter(owner=SynnefoUser.objects.all()[0])
|
1086 | e646ebe5 | Dimitris Moraitis | disks_details = [{ |
1087 | e646ebe5 | Dimitris Moraitis | "id": disk.id,
|
1088 | e646ebe5 | Dimitris Moraitis | "name": disk.name,
|
1089 | e646ebe5 | Dimitris Moraitis | "size": disk.size,
|
1090 | e646ebe5 | Dimitris Moraitis | "created": disk.created,
|
1091 | e646ebe5 | Dimitris Moraitis | "serverId": disk.vm.id,
|
1092 | e646ebe5 | Dimitris Moraitis | } for disk in disks] |
1093 | e646ebe5 | Dimitris Moraitis | return {"disks": disks_details} |
1094 | 9071888e | Constantinos Venetsanopoulos | |
1095 | 9071888e | Constantinos Venetsanopoulos | def create(self, request): |
1096 | 9071888e | Constantinos Venetsanopoulos | """Create a new Disk"""
|
1097 | e646ebe5 | Dimitris Moraitis | # FIXME Create a partial DB entry,
|
1098 | 9071888e | Constantinos Venetsanopoulos | # then call the backend for actual creation
|
1099 | 9071888e | Constantinos Venetsanopoulos | pass
|
1100 | 9071888e | Constantinos Venetsanopoulos | |
1101 | 9071888e | Constantinos Venetsanopoulos | def update(self, request, id): |
1102 | 9071888e | Constantinos Venetsanopoulos | """Rename the Disk with the specified id"""
|
1103 | 9071888e | Constantinos Venetsanopoulos | # FIXME Change the Disk's name in the DB
|
1104 | 9071888e | Constantinos Venetsanopoulos | pass
|
1105 | 9071888e | Constantinos Venetsanopoulos | |
1106 | 9071888e | Constantinos Venetsanopoulos | def delete(self, request, id): |
1107 | 9071888e | Constantinos Venetsanopoulos | """Destroy the Disk with the specified id"""
|
1108 | 9071888e | Constantinos Venetsanopoulos | # Call the backend for actual destruction
|
1109 | 9071888e | Constantinos Venetsanopoulos | pass |