Revision b016b476

b/api/actions.py
1
#
2
# Copyright (c) 2010 Greek Research and Technology Network
3
#
4

  
5
from synnefo.api.errors import *
6
from synnefo.util.rapi import GanetiRapiClient
7

  
8
from django.conf import settings
9
from django.http import HttpResponse
10

  
11
server_actions = {}
12

  
13
rapi = GanetiRapiClient(*settings.GANETI_CLUSTER_INFO)
14

  
15

  
16
def server_action(name):
17
    def decorator(func):
18
        server_actions[name] = func
19
        return func
20
    return decorator
21

  
22

  
23
@server_action('changePassword')
24
def change_password(server, args):
25
    # Normal Response Code: 202
26
    # Error Response Codes: computeFault (400, 500),
27
    #                       serviceUnavailable (503),
28
    #                       unauthorized (401),
29
    #                       badRequest (400),
30
    #                       badMediaType(415),
31
    #                       itemNotFound (404),
32
    #                       buildInProgress (409),
33
    #                       overLimit (413)
34
    
35
    try:
36
        adminPass = args['adminPass']
37
    except KeyError:
38
        raise BadRequest()
39

  
40
    raise ServiceUnavailable()
41

  
42
@server_action('reboot')
43
def reboot(server, args):
44
    # Normal Response Code: 202
45
    # Error Response Codes: computeFault (400, 500),
46
    #                       serviceUnavailable (503),
47
    #                       unauthorized (401),
48
    #                       badRequest (400),
49
    #                       badMediaType(415),
50
    #                       itemNotFound (404),
51
    #                       buildInProgress (409),
52
    #                       overLimit (413)
53
    
54
    type = args.get('type', '')
55
    if type not in ('SOFT', 'HARD'):
56
        raise BadRequest()
57
    
58
    server.start_action('REBOOT')
59
    rapi.RebootInstance(server.backend_id, type.lower())
60
    return HttpResponse(status=202)
61

  
62
@server_action('start')
63
def start(server, args):
64
    # Normal Response Code: 202
65
    # Error Response Codes: serviceUnavailable (503), itemNotFound (404)
66

  
67
    server.start_action('START')
68
    rapi.StartupInstance(server.backend_id)
69
    return HttpResponse(status=202)
70

  
71
@server_action('shutdown')
72
def shutdown(server, args):
73
    # Normal Response Code: 202
74
    # Error Response Codes: serviceUnavailable (503), itemNotFound (404)
75
    
76
    server.start_action('STOP')
77
    rapi.ShutdownInstance(server.backend_id)
78
    return HttpResponse(status=202)
79

  
80
@server_action('rebuild')
81
def rebuild(server, args):
82
    # Normal Response Code: 202
83
    # Error Response Codes: computeFault (400, 500),
84
    #                       serviceUnavailable (503),
85
    #                       unauthorized (401),
86
    #                       badRequest (400),
87
    #                       badMediaType(415),
88
    #                       itemNotFound (404),
89
    #                       buildInProgress (409),
90
    #                       serverCapacityUnavailable (503),
91
    #                       overLimit (413)
92

  
93
    raise ServiceUnavailable()
94

  
95
@server_action('resize')
96
def resize(server, args):
97
    # Normal Response Code: 202
98
    # Error Response Codes: computeFault (400, 500),
99
    #                       serviceUnavailable (503),
100
    #                       unauthorized (401),
101
    #                       badRequest (400),
102
    #                       badMediaType(415),
103
    #                       itemNotFound (404),
104
    #                       buildInProgress (409),
105
    #                       serverCapacityUnavailable (503),
106
    #                       overLimit (413),
107
    #                       resizeNotAllowed (403)
108
    
109
    raise ResizeNotAllowed()
110

  
111
@server_action('confirmResize')
112
def confirm_resize(server, args):
113
    # Normal Response Code: 204
114
    # Error Response Codes: computeFault (400, 500),
115
    #                       serviceUnavailable (503),
116
    #                       unauthorized (401),
117
    #                       badRequest (400),
118
    #                       badMediaType(415),
119
    #                       itemNotFound (404),
120
    #                       buildInProgress (409),
121
    #                       serverCapacityUnavailable (503),
122
    #                       overLimit (413),
123
    #                       resizeNotAllowed (403)
124
    
125
    raise ResizeNotAllowed()
126

  
127
@server_action('revertResize')
128
def revert_resize(server, args):
129
    # Normal Response Code: 202
130
    # Error Response Codes: computeFault (400, 500),
131
    #                       serviceUnavailable (503),
132
    #                       unauthorized (401),
133
    #                       badRequest (400),
134
    #                       badMediaType(415),
135
    #                       itemNotFound (404),
136
    #                       buildInProgress (409),
137
    #                       serverCapacityUnavailable (503),
138
    #                       overLimit (413),
139
    #                       resizeNotAllowed (403)
140

  
141
    raise ResizeNotAllowed()
b/api/errors.py
19 19
class Unauthorized(Fault):
20 20
    code = 401
21 21

  
22
class ResizeNotAllowed(Fault):
23
    code = 403
24

  
22 25
class ItemNotFound(Fault):
23 26
    code = 404
24 27

  
b/api/servers.py
2 2
# Copyright (c) 2010 Greek Research and Technology Network
3 3
#
4 4

  
5
from synnefo.api.actions import server_actions
5 6
from synnefo.api.errors import *
6 7
from synnefo.api.util import *
7 8
from synnefo.db.models import *
8 9
from synnefo.util.rapi import GanetiRapiClient
9 10

  
11
from django.conf import settings
10 12
from django.conf.urls.defaults import *
11 13
from django.http import HttpResponse
12 14
from django.template.loader import render_to_string
......
23 25
    (r'^(?:/|.json|.xml)?$', 'demux'),
24 26
    (r'^/detail(?:.json|.xml)?$', 'list_servers', {'detail': True}),
25 27
    (r'^/(\d+)(?:.json|.xml)?$', 'server_demux'),
28
    (r'^/(\d+)/action(?:.json|.xml)?$', 'server_action'),
29
    (r'^/(\d+)/ips(?:.json|.xml)?$', 'list_addresses'),
30
    (r'^/(\d+)/ips/(.+?)(?:.json|.xml)?$', 'list_addresses_by_network'),
26 31
)
27 32

  
28 33

  
......
47 52
        return render_fault(request, fault)
48 53

  
49 54

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

  
50 59
def server_to_dict(server, detail=False):
51 60
    d = dict(id=server.id, name=server.name)
52 61
    if detail:
......
64 73
        if metadata:
65 74
            d['metadata'] = dict(values=metadata)
66 75
        
67
        public_addrs = [dict(version=4, addr=server.ipfour), dict(version=6, addr=server.ipsix)]
68
        d['addresses'] = {'values': []}
69
        d['addresses']['values'].append({'id': 'public', 'values': public_addrs})
76
        d['addresses'] = [address_to_dict(server.ipfour, server.ipsix)]
70 77
    return d
71 78

  
72 79
def render_server(request, serverdict, status=200):
......
227 234
    server.start_action('DESTROY')
228 235
    rapi.DeleteInstance(server.backend_id)
229 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](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)
b/api/templates/address.xml
1
{% spaceless %}
2
<?xml version="1.0" encoding="UTF-8"?>
3
<network xmlns="http://docs.openstack.org/compute/api/v1.1" id="{{ address.id }}">
4
  {% for ip in address.values %}
5
  <ip version="{{ ip.version }}" addr="{{ ip.addr }}"/>
6
  {% endfor %}
7
</network>
8
{% endspaceless %}
b/api/templates/list_addresses.xml
1
{% spaceless %}
2
<?xml version="1.0" encoding="UTF-8"?>
3
<addresses xmlns="http://docs.openstack.org/compute/api/v1.1">
4
  {% for address in addresses %}
5
  <network id="{{ address.id }}">
6
    {% for ip in address.values %}
7
    <ip version="{{ ip.version }}" addr="{{ ip.addr }}"/>
8
    {% endfor %}
9
  </network>
10
  {% endfor %}
11
</addresses>
12
{% endspaceless %}
b/tools/list_servers
34 34
buf = resp.read()
35 35
reply = json.loads(buf)
36 36

  
37
for server in reply['servers']:
37
for server in reply['servers']['values']:
38 38
    id = server.pop('id')
39 39
    name = server.pop('name')
40 40
    if options.detail:

Also available in: Unified diff