Statistics
| Branch: | Tag: | Revision:

root / api / servers.py @ 7e2f9d4b

History | View | Annotate | Download (6.3 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
        return HttpResponse(status=404)
36

    
37
def server_demux(request, server_id):
38
    if request.method == 'GET':
39
        return get_server_details(request, server_id)
40
    elif request.method == 'PUT':
41
        return update_server_name(request, server_id)
42
    elif request.method == 'DELETE':
43
        return delete_server(request, server_id)
44
    else:
45
        return HttpResponse(status=404)
46

    
47
def server_dict(vm, detail=False):
48
    d = dict(id=vm.id, name=vm.name)
49
    if detail:
50
        d['status'] = vm.rsapi_state
51
        d['progress'] = 100 if vm.rsapi_state == 'ACTIVE' else 0
52
        d['hostId'] = vm.hostid
53
        d['updated'] = vm.updated.isoformat()
54
        d['created'] = vm.created.isoformat()
55
        d['flavorId'] = vm.flavor.id            # XXX Should use flavorRef instead?
56
        d['imageId'] = vm.sourceimage.id        # XXX Should use imageRef instead?
57
        d['description'] = vm.description       # XXX Not in OpenStack docs
58
        
59
        vm_meta = vm.virtualmachinemetadata_set.all()
60
        metadata = dict((meta.meta_key, meta.meta_value) for meta in vm_meta)
61
        if metadata:
62
            d['metadata'] = dict(values=metadata)
63
        
64
        public_addrs = [dict(version=4, addr=vm.ipfour), dict(version=6, addr=vm.ipsix)]
65
        d['addresses'] = {'values': []}
66
        d['addresses']['values'].append({'id': 'public', 'values': public_addrs})
67
    return d
68

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

    
78

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

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

    
161
@api_method
162
def get_server_details(request, server_id):
163
    try:
164
        vm = VirtualMachine.objects.get(id=int(server_id))
165
    except VirtualMachine.DoesNotExist:
166
        raise NotFound
167
    
168
    server = server_dict(vm, detail=True)
169
    return render_server(server, request)
170

    
171
@api_method
172
def update_server_name(request, server_id):    
173
    req = get_request_dict(request)
174
    
175
    try:
176
        name = req['server']['name']
177
        vm = VirtualMachine.objects.get(id=int(server_id))
178
    except KeyError:
179
        raise BadRequest
180
    except VirtualMachine.DoesNotExist:
181
        raise NotFound
182
    
183
    vm.name = name
184
    vm.save()
185
    
186
    return HttpResponse(status=204)
187

    
188
@api_method
189
def delete_server(request, server_id):
190
    try:
191
        vm = VirtualMachine.objects.get(id=int(server_id))
192
    except VirtualMachine.DoesNotExist:
193
        raise NotFound
194
    
195
    vm.start_action('DESTROY')
196
    rapi.DeleteInstance(vm.backend_id)
197
    vm.state = 'DESTROYED'
198
    vm.save()
199
    return HttpResponse(status=204)