Statistics
| Branch: | Tag: | Revision:

root / api / handlers.py @ 2cc9d3a5

History | View | Annotate | Download (10.6 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, 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 = [
194
          {
195
            "id" : 1,
196
            "name" : "256 MB Server",
197
            "ram" : 256,
198
            "disk" : 10
199
          },
200
          {
201
            "id" : 2,
202
            "name" : "512 MB Server",
203
            "ram" : 512,
204
            "disk" : 20
205
          }
206
        ]
207

    
208
    def read(self, request, id=None):
209
        """
210
        List flavors or retrieve one
211

212
        Returns: OK
213
        Faults: cloudServersFault, serviceUnavailable, unauthorized,
214
                badRequest, itemNotFound
215
        """
216
        if id is None:
217
            simple = map(lambda v: {
218
                        "id": v["id"],
219
                        "name": v["name"],
220
                    }, self.flavors)
221
            return { "flavors": simple }
222
        elif id == "detail":
223
            return { "flavors": self.flavors }
224
        else:
225
            for flavor in self.flavors:
226
                if str(flavor["id"]) == id:
227
                    return { "flavor": flavor }
228
            raise fault.itemNotFound
229

    
230

    
231
class ImageHandler(BaseHandler):
232
    allowed_methods = ('GET', 'POST')
233

    
234
    def read(self, request, id=None):
235
        """
236
        List images or retrieve one
237

238
        Returns: OK
239
        Faults: cloudServersFault, serviceUnavailable, unauthorized,
240
                badRequest, itemNotFound
241
        """
242
        images = Image.objects.all()
243
        if not rapi: # No ganeti backend. Return mock objects
244
            if id == "detail":
245
                return { "images": images }
246
            elif id is None:
247
                return { "images": [ { "id": s.id, "name": s.name } for s in images ] }
248
            else:
249
                return { "image": images[0] }
250
        if id is None:
251
            return {}
252
        elif id == "detail":
253
            return {}
254
        else:
255
            raise fault.itemNotFound
256

    
257
    def create(self, request):
258
        """Create a new image"""
259
        return accepted
260

    
261

    
262
class SharedIPGroupHandler(BaseHandler):
263
    allowed_methods = ('GET', 'POST', 'DELETE')
264

    
265
    def read(self, request, id=None):
266
        """List Shared IP Groups"""
267
        if id is None:
268
            return {}
269
        elif id == "detail":
270
            return {}
271
        else:
272
            raise fault.itemNotFound
273

    
274
    def create(self, request, id):
275
        """Creates a new Shared IP Group"""
276
        return created
277

    
278
    def delete(self, request, id):
279
        """Deletes a Shared IP Group"""
280
        return noContent
281

    
282

    
283
class LimitHandler(BaseHandler):
284
    allowed_methods = ('GET',)
285

    
286
    # XXX: hookup with @throttle
287

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

    
336
    absolute = {
337
        "maxTotalRAMSize" : 51200,
338
        "maxIPGroups" : 50,
339
        "maxIPGroupMembers" : 25
340
    }
341

    
342
    def read(self, request):
343
        return { "limits": {
344
                "rate": self.rate,
345
                "absolute": self.absolute,
346
               }
347
            }