Statistics
| Branch: | Tag: | Revision:

root / api / servers.py @ c36934a7

History | View | Annotate | Download (7.6 kB)

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

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

    
10
from django.conf.urls.defaults import *
11
from django.http import HttpResponse
12
from django.template.loader import render_to_string
13

    
14
from logging import getLogger
15

    
16
import json
17

    
18

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

    
22
urlpatterns = patterns('synnefo.api.servers',
23
    (r'^(?:/|.json|.xml)?$', 'demux'),
24
    (r'^/detail(?:.json|.xml)?$', 'list_servers', {'detail': True}),
25
    (r'^/(\d+)(?:.json|.xml)?$', 'server_demux'),
26
)
27

    
28

    
29
def demux(request):
30
    if request.method == 'GET':
31
        return list_servers(request)
32
    elif request.method == 'POST':
33
        return create_server(request)
34
    else:
35
        fault = BadRequest()
36
        return render_fault(request, fault)
37

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

    
49

    
50
def server_to_dict(server, detail=False):
51
    d = dict(id=server.id, name=server.name)
52
    if detail:
53
        d['status'] = server.rsapi_state
54
        d['progress'] = 100 if server.rsapi_state == 'ACTIVE' else 0
55
        d['hostId'] = server.hostid
56
        d['updated'] = server.updated.isoformat()
57
        d['created'] = server.created.isoformat()
58
        d['flavorId'] = server.flavor.id            # XXX Should use flavorRef instead?
59
        d['imageId'] = server.sourceimage.id        # XXX Should use imageRef instead?
60
        d['description'] = server.description       # XXX Not in OpenStack docs
61
        
62
        server_meta = server.virtualmachinemetadata_set.all()
63
        metadata = dict((meta.meta_key, meta.meta_value) for meta in server_meta)
64
        if metadata:
65
            d['metadata'] = dict(values=metadata)
66
        
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})
70
    return d
71

    
72
def render_server(request, serverdict, status=200):
73
    if request.type == 'xml':
74
        data = render_to_string('server.xml', dict(server=serverdict, is_root=True))
75
    else:
76
        data = json.dumps({'server': serverdict})
77
    return HttpResponse(data, status=status)
78

    
79

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

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

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

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

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