Statistics
| Branch: | Tag: | Revision:

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