Statistics
| Branch: | Tag: | Revision:

root / api / servers.py @ 09471611

History | View | Annotate | Download (10.1 kB)

1
#
2
# Copyright (c) 2010 Greek Research and Technology Network
3
#
4

    
5
from logging import getLogger
6

    
7
from django.conf import settings
8
from django.conf.urls.defaults import *
9
from django.http import HttpResponse
10
from django.template.loader import render_to_string
11
from django.utils import simplejson as json
12

    
13
from synnefo.api.actions import server_actions
14
from synnefo.api.errors import *
15
from synnefo.api.util import *
16
from synnefo.db.models import *
17
from synnefo.util.rapi import GanetiRapiClient
18
from synnefo.logic import backend, utils
19

    
20
log = getLogger('synnefo.api.servers')
21
rapi = GanetiRapiClient(*settings.GANETI_CLUSTER_INFO)
22

    
23
urlpatterns = patterns('synnefo.api.servers',
24
    (r'^(?:/|.json|.xml)?$', 'demux'),
25
    (r'^/detail(?:.json|.xml)?$', 'list_servers', {'detail': True}),
26
    (r'^/(\d+)(?:.json|.xml)?$', 'server_demux'),
27
    (r'^/(\d+)/action(?:.json|.xml)?$', 'server_action'),
28
    (r'^/(\d+)/ips(?:.json|.xml)?$', 'list_addresses'),
29
    (r'^/(\d+)/ips/(.+?)(?:.json|.xml)?$', 'list_addresses_by_network'),
30
)
31

    
32

    
33
def demux(request):
34
    if request.method == 'GET':
35
        return list_servers(request)
36
    elif request.method == 'POST':
37
        return create_server(request)
38
    else:
39
        fault = BadRequest()
40
        return render_fault(request, fault)
41

    
42
def server_demux(request, server_id):
43
    if request.method == 'GET':
44
        return get_server_details(request, server_id)
45
    elif request.method == 'PUT':
46
        return update_server_name(request, server_id)
47
    elif request.method == 'DELETE':
48
        return delete_server(request, server_id)
49
    else:
50
        fault = BadRequest()
51
        return render_fault(request, fault)
52

    
53

    
54
def address_to_dict(ipfour, ipsix):
55
    return {'id': 'public',
56
            'values': [{'version': 4, 'addr': ipfour}, {'version': 6, 'addr': ipsix}]}
57

    
58
def server_to_dict(server, detail=False):
59
    d = dict(id=server.id, name=server.name)
60
    if detail:
61
        d['status'] = utils.get_rsapi_state(server)
62
        d['progress'] = 100 if utils.get_rsapi_state(server) == 'ACTIVE' else 0
63
        d['hostId'] = server.hostid
64
        d['updated'] = server.updated.isoformat()
65
        d['created'] = server.created.isoformat()
66
        d['flavorRef'] = server.flavor.id
67
        d['imageRef'] = server.sourceimage.id
68
        #d['description'] = server.description       # XXX Not in OpenStack docs
69
        
70
        server_meta = server.virtualmachinemetadata_set.all()
71
        metadata = dict((meta.meta_key, meta.meta_value) for meta in server_meta)
72
        if metadata:
73
            d['metadata'] = {'values': metadata}
74
        
75
        addresses = [address_to_dict(server.ipfour, server.ipsix)]
76
        d['addresses'] = {'values': addresses}
77
    return d
78

    
79
def render_server(request, serverdict, status=200):
80
    if request.type == 'xml':
81
        data = render_to_string('server.xml', dict(server=serverdict, is_root=True))
82
    else:
83
        data = json.dumps({'server': serverdict})
84
    return HttpResponse(data, status=status)
85

    
86

    
87
@api_method('GET')
88
def list_servers(request, detail=False):
89
    # Normal Response Codes: 200, 203
90
    # Error Response Codes: computeFault (400, 500),
91
    #                       serviceUnavailable (503),
92
    #                       unauthorized (401),
93
    #                       badRequest (400),
94
    #                       overLimit (413)
95
    
96
    owner = get_user()
97
    user_servers = VirtualMachine.objects.filter(owner=owner, deleted=False)
98
    servers = [server_to_dict(server, detail) for server in user_servers]
99
    
100
    if request.type == 'xml':
101
        data = render_to_string('list_servers.xml', dict(servers=servers, detail=detail))
102
    else:
103
        data = json.dumps({'servers': {'values': servers}})
104
    
105
    return HttpResponse(data, status=200)
106

    
107
@api_method('POST')
108
def create_server(request):
109
    # Normal Response Code: 202
110
    # Error Response Codes: computeFault (400, 500),
111
    #                       serviceUnavailable (503),
112
    #                       unauthorized (401),
113
    #                       badMediaType(415),
114
    #                       itemNotFound (404),
115
    #                       badRequest (400),
116
    #                       serverCapacityUnavailable (503),
117
    #                       overLimit (413)
118
    
119
    req = get_request_dict(request)
120
    
121
    try:
122
        server = req['server']
123
        name = server['name']
124
        sourceimage = Image.objects.get(id=server['imageRef'])
125
        flavor = Flavor.objects.get(id=server['flavorRef'])
126
    except KeyError:
127
        raise BadRequest
128
    except Image.DoesNotExist:
129
        raise ItemNotFound
130
    except Flavor.DoesNotExist:
131
        raise ItemNotFound
132
    
133
    server = VirtualMachine.objects.create(
134
        name=name,
135
        owner=get_user(),
136
        sourceimage=sourceimage,
137
        ipfour='0.0.0.0',
138
        ipsix='::1',
139
        flavor=flavor)
140
                
141
    if request.META.get('SERVER_NAME', None) == 'testserver':
142
        name = 'test-server'
143
        dry_run = True
144
    else:
145
        name = server.backend_id
146
        dry_run = False
147
    
148
    jobId = rapi.CreateInstance(
149
        mode='create',
150
        name=name,
151
        disk_template='plain',
152
        disks=[{"size": 2000}],         #FIXME: Always ask for a 2GB disk for now
153
        nics=[{}],
154
        os='debootstrap+default',       #TODO: select OS from imageRef
155
        ip_check=False,
156
        name_check=False,
157
        pnode=rapi.GetNodes()[0],       #TODO: verify if this is necessary
158
        dry_run=dry_run,
159
        beparams=dict(auto_balance=True, vcpus=flavor.cpu, memory=flavor.ram))
160
    
161
    server.save()
162
        
163
    log.info('created vm with %s cpus, %s ram and %s storage' % (flavor.cpu, flavor.ram, flavor.disk))
164
    
165
    serverdict = server_to_dict(server, detail=True)
166
    serverdict['status'] = 'BUILD'
167
    serverdict['adminPass'] = random_password()
168
    return render_server(request, serverdict, status=202)
169

    
170
@api_method('GET')
171
def get_server_details(request, server_id):
172
    # Normal Response Codes: 200, 203
173
    # Error Response Codes: computeFault (400, 500),
174
    #                       serviceUnavailable (503),
175
    #                       unauthorized (401),
176
    #                       badRequest (400),
177
    #                       itemNotFound (404),
178
    #                       overLimit (413)
179
    
180
    try:
181
        server_id = int(server_id)
182
        server = VirtualMachine.objects.get(id=server_id)
183
    except VirtualMachine.DoesNotExist:
184
        raise ItemNotFound
185
    
186
    serverdict = server_to_dict(server, detail=True)
187
    return render_server(request, serverdict)
188

    
189
@api_method('PUT')
190
def update_server_name(request, server_id):
191
    # Normal Response Code: 204
192
    # Error Response Codes: computeFault (400, 500),
193
    #                       serviceUnavailable (503),
194
    #                       unauthorized (401),
195
    #                       badRequest (400),
196
    #                       badMediaType(415),
197
    #                       itemNotFound (404),
198
    #                       buildInProgress (409),
199
    #                       overLimit (413)
200
    
201
    req = get_request_dict(request)
202
    
203
    try:
204
        name = req['server']['name']
205
        server_id = int(server_id)
206
        server = VirtualMachine.objects.get(id=server_id)
207
    except KeyError:
208
        raise BadRequest
209
    except VirtualMachine.DoesNotExist:
210
        raise ItemNotFound
211
    
212
    server.name = name
213
    server.save()
214
    
215
    return HttpResponse(status=204)
216

    
217
@api_method('DELETE')
218
def delete_server(request, server_id):
219
    # Normal Response Codes: 204
220
    # Error Response Codes: computeFault (400, 500),
221
    #                       serviceUnavailable (503),
222
    #                       unauthorized (401),
223
    #                       itemNotFound (404),
224
    #                       unauthorized (401),
225
    #                       buildInProgress (409),
226
    #                       overLimit (413)
227
    
228
    try:
229
        server_id = int(server_id)
230
        server = VirtualMachine.objects.get(id=server_id)
231
    except VirtualMachine.DoesNotExist:
232
        raise ItemNotFound
233
    
234
    backend.start_action(server, 'DESTROY')
235
    rapi.DeleteInstance(server.backend_id)
236
    return HttpResponse(status=204)
237

    
238
@api_method('POST')
239
def server_action(request, server_id):
240
    try:
241
        server_id = int(server_id)
242
        server = VirtualMachine.objects.get(id=server_id)
243
    except VirtualMachine.DoesNotExist:
244
        raise ItemNotFound
245

    
246
    req = get_request_dict(request)
247
    if len(req) != 1:
248
        raise BadRequest
249
    
250
    key = req.keys()[0]
251
    if key not in server_actions:
252
        raise BadRequest
253
    
254
    return server_actions[key](request, server, req[key])
255

    
256
@api_method('GET')
257
def list_addresses(request, server_id):
258
    # Normal Response Codes: 200, 203
259
    # Error Response Codes: computeFault (400, 500),
260
    #                       serviceUnavailable (503),
261
    #                       unauthorized (401),
262
    #                       badRequest (400),
263
    #                       overLimit (413)
264
    
265
    try:
266
        server_id = int(server_id)
267
        server = VirtualMachine.objects.get(id=server_id)
268
    except VirtualMachine.DoesNotExist:
269
        raise ItemNotFound
270
    
271
    addresses = [address_to_dict(server.ipfour, server.ipsix)]
272
    
273
    if request.type == 'xml':
274
        data = render_to_string('list_addresses.xml', {'addresses': addresses})
275
    else:
276
        data = json.dumps({'addresses': {'values': addresses}})
277
    
278
    return HttpResponse(data, status=200)
279

    
280
@api_method('GET')
281
def list_addresses_by_network(request, server_id, network_id):
282
    # Normal Response Codes: 200, 203
283
    # Error Response Codes: computeFault (400, 500),
284
    #                       serviceUnavailable (503),
285
    #                       unauthorized (401),
286
    #                       badRequest (400),
287
    #                       itemNotFound (404),
288
    #                       overLimit (413)
289
    
290
    try:
291
        server_id = int(server_id)
292
        server = VirtualMachine.objects.get(id=server_id)
293
    except VirtualMachine.DoesNotExist:
294
        raise ItemNotFound
295
    
296
    if network_id != 'public':
297
        raise ItemNotFound
298
    
299
    address = address_to_dict(server.ipfour, server.ipsix)
300
    
301
    if request.type == 'xml':
302
        data = render_to_string('address.xml', {'address': address})
303
    else:
304
        data = json.dumps({'network': address})
305
    
306
    return HttpResponse(data, status=200)