Statistics
| Branch: | Tag: | Revision:

root / api / handlers.py @ 166bf271

History | View | Annotate | Download (10.8 kB)

1
# vim: ts=4 sts=4 et ai sw=4 fileencoding=utf-8
2
#
3
# Copyright © 2010 Greek Research and Technology Network
4
#
5

    
6
from django.conf import settings
7
from piston.handler import BaseHandler, AnonymousBaseHandler
8
from synnefo.api.faults import fault, noContent, accepted, created
9
from synnefo.api.helpers import instance_to_server, paginator
10
from synnefo.util.rapi import GanetiRapiClient, GanetiApiError
11
from synnefo.db.models import VirtualMachine, Flavor, Image, User, id_from_instance_name
12
from util.rapi import GanetiRapiClient
13

    
14

    
15
if settings.GANETI_CLUSTER_INFO:
16
    rapi = GanetiRapiClient(*settings.GANETI_CLUSTER_INFO)
17
else:
18
    rapi = None
19

    
20
ganeti_prefix_id = settings.GANETI_PREFIX_ID
21

    
22
VERSIONS = [
23
    {
24
        "status": "CURRENT",
25
        "id": "v1.0",
26
        "docURL" : "http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20090714.pdf ",
27
        "wadl" : "http://docs.rackspacecloud.com/servers/api/v1.0/application.wadl"
28
    },
29
]
30

    
31

    
32
class VersionHandler(AnonymousBaseHandler):
33
    allowed_methods = ('GET',)
34

    
35
    def read(self, request, number=None):
36
        if number is None:
37
            versions = map(lambda v: {
38
                        "status": v["status"],
39
                        "id": v["id"],
40
                    }, VERSIONS)
41
            return { "versions": versions }
42
        else:
43
            for version in VERSIONS:
44
                if version["id"] == number:
45
                    return { "version": version }
46
            raise fault.itemNotFound
47

    
48

    
49
class ServerHandler(BaseHandler):
50
    allowed_methods = ('GET', 'POST', 'PUT', 'DELETE')
51

    
52
    def read(self, request, id=None):
53
        from time import sleep
54
        sleep(1)
55
        #TODO: delete the sleep once the mock objects are removed
56
        if id is None:
57
            return self.read_all(request)
58
        elif id == "detail":
59
            return self.read_all(request, detail=True)
60
        else:
61
            return self.read_one(request, id)
62

    
63
    def read_one(self, request, id):
64
        if not rapi: # No ganeti backend. Return mock objects
65
            servers = VirtualMachine.objects.filter(owner=User.objects.all()[0])
66
            return { "server": servers[0] }
67
        try:
68
            instance = rapi.GetInstance(id)
69
            return { "server": instance_to_server(instance) }
70
        except GanetiApiError:
71
            raise fault.itemNotFound
72

    
73
    @paginator
74
    def read_all(self, request, detail=False):
75
        if not rapi: # No ganeti backend. Return mock objects
76
            if detail:
77
                virtual_servers = VirtualMachine.objects.filter(owner=User.objects.all()[0])
78
                #get the first user, since we don't have any user data yet
79
                virtual_servers_list = [{'status': server.state, 'flavorId': server.flavor, \
80
                    'name': server.name, 'id': server.id, 'imageId': server.imageid, 
81
                    'metadata': {'Server_Label': server.server_label, \
82
                    'Image_Version': server.image_version}, \
83
                    'hostId': '9e107d9d372bb6826bd81d3542a419d6',  \
84
                    'addresses': {'public': ['67.23.10.133'], 'private': ['10.176.42.17']}} \
85
                        for server in virtual_servers]
86
                #pass some fake data regarding ip, since we don't have any such data
87
                return { "servers":  virtual_servers_list }                
88
            else:
89
                virtual_servers = VirtualMachine.objects.filter(owner=User.objects.all()[0])
90
                return { "servers": [ { "id": s.id, "name": s.name } for s in virtual_servers ] }
91

    
92
        if not detail:
93
            instances = rapi.GetInstances(bulk=False)
94
            servers = [ { "id": id, "name": id } for id in instances ]
95
        else:
96
            instances = rapi.GetInstances(bulk=True)
97
            servers = []
98
            for instance in instances:
99
                servers.append(instance_to_server(instance))
100
        return { "servers": servers }
101

    
102
    def create(self, request):
103
        print 'create machine was called'
104
        rapi.CreateInstance('create', 'machine-unwebXYZ', 'plain', [{"size": 5120}], [{}], os='debootstrap+default', ip_check=False, name_check=False,pnode="store68", beparams={'auto_balance': True, 'vcpus': 2, 'memory': 1024})
105
        #TODO: replace with real data from request.POST
106
        return accepted
107

    
108
    def update(self, request, id):
109
        return noContent
110

    
111
    def delete(self, request, id):
112
        machine = 'machine-XXX' #VirtualMachine.objects.get(id=id_from_instance_name(id))
113
        print 'deleting machine %s' % machine
114
        rapi.DeleteInstance(machine.name)
115
        return accepted
116

    
117

    
118
class ServerAddressHandler(BaseHandler):
119
    allowed_methods = ('GET', 'PUT', 'DELETE')
120

    
121
    def read(self, request, id, type=None):
122
        """List IP addresses for a server"""
123

    
124
        if type is None:
125
            pass
126
        elif type == "private":
127
            pass
128
        elif type == "public":
129
            pass
130
        return {}
131

    
132
    def update(self, request, id, address):
133
        """Share an IP address to another in the group"""
134
        return accepted
135

    
136
    def delete(self, request, id, address):
137
        """Unshare an IP address"""
138
        return accepted
139

    
140

    
141
class ServerActionHandler(BaseHandler):
142
    allowed_methods = ('POST', 'DELETE', 'GET', 'PUT')
143
#TODO: remove GET/PUT
144
    
145
    def read(self, request, id):
146
        return accepted
147

    
148
    def create(self, request, id):
149
        """Reboot, rebuild, resize, confirm resized, revert resized"""
150
        machine = 'machine-XXX' #VirtualMachine.objects.get(id=id_from_instance_name(id))
151
        reboot_request = request.POST.get('reboot', None)
152
        shutdown_request = request.POST.get('shutdown', None)
153
        if reboot_request:
154
            print 'reboot was asked, with options: %s' % reboot_request   
155
            rapi.RebootInstance(machine)
156
        elif shutdown_request:
157
            print 'shutdown was asked, with options: %s' % shutdown_request               
158
            rapi.ShutdownInstance(machine)
159
        return accepted
160

    
161

    
162
    def delete(self, request, id):
163
        """Delete an Instance"""
164
        return accepted
165

    
166
    def update(self, request, id):
167
        return noContent
168

    
169

    
170

    
171
#read is called on GET requests
172
#create is called on POST, and creates new objects, and should return them (or rc.CREATED.)
173
#update is called on PUT, and should update an existing product and return them (or rc.ALL_OK.)
174
#delete is called on DELETE, and should delete an existing object. Should not return anything, just rc.DELETED.'''
175

    
176

    
177
class ServerBackupHandler(BaseHandler):
178
    """ Backup Schedules are not implemented yet, return notImplemented """
179
    allowed_methods = ('GET', 'POST', 'DELETE')
180

    
181
    def read(self, request, id):
182
        raise fault.notImplemented
183

    
184
    def create(self, request, id):
185
        raise fault.notImplemented
186

    
187
    def delete(self, request, id):
188
        raise fault.notImplemented
189

    
190

    
191
class FlavorHandler(BaseHandler):
192
    allowed_methods = ('GET',)
193
    flavors = Flavor.objects.all()
194
    flavors = [ {'id': flavor.id, 'name': flavor.name, 'ram': flavor.ram, \
195
             'disk': flavor.disk} for flavor in flavors]
196

    
197
    def read(self, request, id=None):
198
        """
199
        List flavors or retrieve one
200

201
        Returns: OK
202
        Faults: cloudServersFault, serviceUnavailable, unauthorized,
203
                badRequest, itemNotFound
204
        """
205
        if id is None:
206
            simple = map(lambda v: {
207
                        "id": v['id'],
208
                        "name": v['name'],
209
                    }, self.flavors)
210
            return { "flavors": simple }
211
        elif id == "detail":
212
            return { "flavors": self.flavors }
213
        else:
214
            for flavor in self.flavors:
215
                if str(flavor['id']) == id:
216
                    return { "flavor": flavor }
217
            raise fault.itemNotFound
218

    
219

    
220
class ImageHandler(BaseHandler):
221
    allowed_methods = ('GET', 'POST')
222

    
223
    def read(self, request, id=None):
224
        """
225
        List images or retrieve one
226

227
        Returns: OK
228
        Faults: cloudServersFault, serviceUnavailable, unauthorized,
229
                badRequest, itemNotFound
230
        """
231
        images = Image.objects.all()
232
        images = [ {'created': image.created.isoformat(), 'id': image.id, \
233
              'name': image.name, 'updated': image.updated.isoformat(), \
234
               'description': image.description, 'state': image.state, 'serverid': image.serverid, \
235
               'vm_id': image.vm_id} for image in images]
236

    
237
        if not rapi: # No ganeti backend. Return mock objects
238
            if id == "detail":
239
                return { "images": images }
240
            elif id is None:
241
                return { "images": [ { "id": s['id'], "name": s['name'] } for s in images ] }
242
            else:
243
                return { "image": images[0] }
244
        if id is None:
245
            return {}
246
        elif id == "detail":
247
            return {}
248
        else:
249
            raise fault.itemNotFound
250

    
251
    def create(self, request):
252
        """Create a new image"""
253
        return accepted
254

    
255

    
256
class SharedIPGroupHandler(BaseHandler):
257
    allowed_methods = ('GET', 'POST', 'DELETE')
258

    
259
    def read(self, request, id=None):
260
        """List Shared IP Groups"""
261
        if id is None:
262
            return {}
263
        elif id == "detail":
264
            return {}
265
        else:
266
            raise fault.itemNotFound
267

    
268
    def create(self, request, id):
269
        """Creates a new Shared IP Group"""
270
        return created
271

    
272
    def delete(self, request, id):
273
        """Deletes a Shared IP Group"""
274
        return noContent
275

    
276

    
277
class LimitHandler(BaseHandler):
278
    allowed_methods = ('GET',)
279

    
280
    # XXX: hookup with @throttle
281

    
282
    rate = [
283
        {
284
           "verb" : "POST",
285
           "URI" : "*",
286
           "regex" : ".*",
287
           "value" : 10,
288
           "remaining" : 2,
289
           "unit" : "MINUTE",
290
           "resetTime" : 1244425439
291
        },
292
        {
293
           "verb" : "POST",
294
           "URI" : "*/servers",
295
           "regex" : "^/servers",
296
           "value" : 25,
297
           "remaining" : 24,
298
           "unit" : "DAY",
299
           "resetTime" : 1244511839
300
        },
301
        {
302
           "verb" : "PUT",
303
           "URI" : "*",
304
           "regex" : ".*",
305
           "value" : 10,
306
           "remaining" : 2,
307
           "unit" : "MINUTE",
308
           "resetTime" : 1244425439
309
        },
310
        {
311
           "verb" : "GET",
312
           "URI" : "*",
313
           "regex" : ".*",
314
           "value" : 3,
315
           "remaining" : 3,
316
           "unit" : "MINUTE",
317
           "resetTime" : 1244425439
318
        },
319
        {
320
           "verb" : "DELETE",
321
           "URI" : "*",
322
           "regex" : ".*",
323
           "value" : 100,
324
           "remaining" : 100,
325
           "unit" : "MINUTE",
326
           "resetTime" : 1244425439
327
        }
328
    ]
329

    
330
    absolute = {
331
        "maxTotalRAMSize" : 51200,
332
        "maxIPGroups" : 50,
333
        "maxIPGroupMembers" : 25
334
    }
335

    
336
    def read(self, request):
337
        return { "limits": {
338
                "rate": self.rate,
339
                "absolute": self.absolute,
340
               }
341
            }