Statistics
| Branch: | Tag: | Revision:

root / api / servers.py @ 4e6f9904

History | View | Annotate | Download (10 kB)

1 7e2f9d4b Giorgos Verigakis
#
2 7e2f9d4b Giorgos Verigakis
# Copyright (c) 2010 Greek Research and Technology Network
3 7e2f9d4b Giorgos Verigakis
#
4 7e2f9d4b Giorgos Verigakis
5 b016b476 Giorgos Verigakis
from synnefo.api.actions import server_actions
6 7e2f9d4b Giorgos Verigakis
from synnefo.api.errors import *
7 7e2f9d4b Giorgos Verigakis
from synnefo.api.util import *
8 7e2f9d4b Giorgos Verigakis
from synnefo.db.models import *
9 7e2f9d4b Giorgos Verigakis
from synnefo.util.rapi import GanetiRapiClient
10 7e2f9d4b Giorgos Verigakis
11 b016b476 Giorgos Verigakis
from django.conf import settings
12 7e2f9d4b Giorgos Verigakis
from django.conf.urls.defaults import *
13 7e2f9d4b Giorgos Verigakis
from django.http import HttpResponse
14 7e2f9d4b Giorgos Verigakis
from django.template.loader import render_to_string
15 7e2f9d4b Giorgos Verigakis
16 7e2f9d4b Giorgos Verigakis
from logging import getLogger
17 7e2f9d4b Giorgos Verigakis
18 7e2f9d4b Giorgos Verigakis
import json
19 7e2f9d4b Giorgos Verigakis
20 7e2f9d4b Giorgos Verigakis
21 7e2f9d4b Giorgos Verigakis
log = getLogger('synnefo.api.servers')
22 7e2f9d4b Giorgos Verigakis
rapi = GanetiRapiClient(*settings.GANETI_CLUSTER_INFO)
23 7e2f9d4b Giorgos Verigakis
24 7e2f9d4b Giorgos Verigakis
urlpatterns = patterns('synnefo.api.servers',
25 7e2f9d4b Giorgos Verigakis
    (r'^(?:/|.json|.xml)?$', 'demux'),
26 7e2f9d4b Giorgos Verigakis
    (r'^/detail(?:.json|.xml)?$', 'list_servers', {'detail': True}),
27 7e2f9d4b Giorgos Verigakis
    (r'^/(\d+)(?:.json|.xml)?$', 'server_demux'),
28 b016b476 Giorgos Verigakis
    (r'^/(\d+)/action(?:.json|.xml)?$', 'server_action'),
29 b016b476 Giorgos Verigakis
    (r'^/(\d+)/ips(?:.json|.xml)?$', 'list_addresses'),
30 b016b476 Giorgos Verigakis
    (r'^/(\d+)/ips/(.+?)(?:.json|.xml)?$', 'list_addresses_by_network'),
31 7e2f9d4b Giorgos Verigakis
)
32 7e2f9d4b Giorgos Verigakis
33 7e2f9d4b Giorgos Verigakis
34 7e2f9d4b Giorgos Verigakis
def demux(request):
35 7e2f9d4b Giorgos Verigakis
    if request.method == 'GET':
36 7e2f9d4b Giorgos Verigakis
        return list_servers(request)
37 7e2f9d4b Giorgos Verigakis
    elif request.method == 'POST':
38 7e2f9d4b Giorgos Verigakis
        return create_server(request)
39 7e2f9d4b Giorgos Verigakis
    else:
40 c36934a7 Giorgos Verigakis
        fault = BadRequest()
41 c36934a7 Giorgos Verigakis
        return render_fault(request, fault)
42 7e2f9d4b Giorgos Verigakis
43 7e2f9d4b Giorgos Verigakis
def server_demux(request, server_id):
44 7e2f9d4b Giorgos Verigakis
    if request.method == 'GET':
45 7e2f9d4b Giorgos Verigakis
        return get_server_details(request, server_id)
46 7e2f9d4b Giorgos Verigakis
    elif request.method == 'PUT':
47 7e2f9d4b Giorgos Verigakis
        return update_server_name(request, server_id)
48 7e2f9d4b Giorgos Verigakis
    elif request.method == 'DELETE':
49 7e2f9d4b Giorgos Verigakis
        return delete_server(request, server_id)
50 7e2f9d4b Giorgos Verigakis
    else:
51 c36934a7 Giorgos Verigakis
        fault = BadRequest()
52 c36934a7 Giorgos Verigakis
        return render_fault(request, fault)
53 7e2f9d4b Giorgos Verigakis
54 c36934a7 Giorgos Verigakis
55 b016b476 Giorgos Verigakis
def address_to_dict(ipfour, ipsix):
56 b016b476 Giorgos Verigakis
    return {'id': 'public',
57 b016b476 Giorgos Verigakis
            'values': [{'version': 4, 'addr': ipfour}, {'version': 6, 'addr': ipsix}]}
58 b016b476 Giorgos Verigakis
59 c36934a7 Giorgos Verigakis
def server_to_dict(server, detail=False):
60 c36934a7 Giorgos Verigakis
    d = dict(id=server.id, name=server.name)
61 7e2f9d4b Giorgos Verigakis
    if detail:
62 c36934a7 Giorgos Verigakis
        d['status'] = server.rsapi_state
63 c36934a7 Giorgos Verigakis
        d['progress'] = 100 if server.rsapi_state == 'ACTIVE' else 0
64 c36934a7 Giorgos Verigakis
        d['hostId'] = server.hostid
65 c36934a7 Giorgos Verigakis
        d['updated'] = server.updated.isoformat()
66 c36934a7 Giorgos Verigakis
        d['created'] = server.created.isoformat()
67 90d90bd2 Giorgos Verigakis
        d['flavorRef'] = server.flavor.id
68 90d90bd2 Giorgos Verigakis
        d['imageRef'] = server.sourceimage.id
69 4e6f9904 Markos Gogoulos
        #d['description'] = server.description       # XXX Not in OpenStack docs
70 7e2f9d4b Giorgos Verigakis
        
71 c36934a7 Giorgos Verigakis
        server_meta = server.virtualmachinemetadata_set.all()
72 c36934a7 Giorgos Verigakis
        metadata = dict((meta.meta_key, meta.meta_value) for meta in server_meta)
73 7e2f9d4b Giorgos Verigakis
        if metadata:
74 b9a77976 Giorgos Verigakis
            d['metadata'] = {'values': metadata}
75 7e2f9d4b Giorgos Verigakis
        
76 b9a77976 Giorgos Verigakis
        addresses = [address_to_dict(server.ipfour, server.ipsix)]
77 b9a77976 Giorgos Verigakis
        d['addresses'] = {'values': addresses}
78 7e2f9d4b Giorgos Verigakis
    return d
79 7e2f9d4b Giorgos Verigakis
80 c36934a7 Giorgos Verigakis
def render_server(request, serverdict, status=200):
81 7e2f9d4b Giorgos Verigakis
    if request.type == 'xml':
82 c36934a7 Giorgos Verigakis
        data = render_to_string('server.xml', dict(server=serverdict, is_root=True))
83 7e2f9d4b Giorgos Verigakis
    else:
84 c36934a7 Giorgos Verigakis
        data = json.dumps({'server': serverdict})
85 c36934a7 Giorgos Verigakis
    return HttpResponse(data, status=status)
86 7e2f9d4b Giorgos Verigakis
87 7e2f9d4b Giorgos Verigakis
88 c36934a7 Giorgos Verigakis
@api_method('GET')
89 7e2f9d4b Giorgos Verigakis
def list_servers(request, detail=False):
90 7e2f9d4b Giorgos Verigakis
    # Normal Response Codes: 200, 203
91 7e2f9d4b Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
92 7e2f9d4b Giorgos Verigakis
    #                       serviceUnavailable (503),
93 7e2f9d4b Giorgos Verigakis
    #                       unauthorized (401),
94 7e2f9d4b Giorgos Verigakis
    #                       badRequest (400),
95 7e2f9d4b Giorgos Verigakis
    #                       overLimit (413)
96 c36934a7 Giorgos Verigakis
    
97 7e2f9d4b Giorgos Verigakis
    owner = get_user()
98 c36934a7 Giorgos Verigakis
    user_servers = VirtualMachine.objects.filter(owner=owner, deleted=False)
99 c36934a7 Giorgos Verigakis
    servers = [server_to_dict(server, detail) for server in user_servers]
100 c36934a7 Giorgos Verigakis
    
101 7e2f9d4b Giorgos Verigakis
    if request.type == 'xml':
102 7e2f9d4b Giorgos Verigakis
        data = render_to_string('list_servers.xml', dict(servers=servers, detail=detail))
103 7e2f9d4b Giorgos Verigakis
    else:
104 c36934a7 Giorgos Verigakis
        data = json.dumps({'servers': {'values': servers}})
105 c36934a7 Giorgos Verigakis
    
106 c36934a7 Giorgos Verigakis
    return HttpResponse(data, status=200)
107 7e2f9d4b Giorgos Verigakis
108 c36934a7 Giorgos Verigakis
@api_method('POST')
109 7e2f9d4b Giorgos Verigakis
def create_server(request):
110 7e2f9d4b Giorgos Verigakis
    # Normal Response Code: 202
111 7e2f9d4b Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
112 7e2f9d4b Giorgos Verigakis
    #                       serviceUnavailable (503),
113 7e2f9d4b Giorgos Verigakis
    #                       unauthorized (401),
114 7e2f9d4b Giorgos Verigakis
    #                       badMediaType(415),
115 7e2f9d4b Giorgos Verigakis
    #                       itemNotFound (404),
116 7e2f9d4b Giorgos Verigakis
    #                       badRequest (400),
117 7e2f9d4b Giorgos Verigakis
    #                       serverCapacityUnavailable (503),
118 7e2f9d4b Giorgos Verigakis
    #                       overLimit (413)
119 7e2f9d4b Giorgos Verigakis
    
120 7e2f9d4b Giorgos Verigakis
    req = get_request_dict(request)
121 7e2f9d4b Giorgos Verigakis
    
122 7e2f9d4b Giorgos Verigakis
    try:
123 7e2f9d4b Giorgos Verigakis
        server = req['server']
124 7e2f9d4b Giorgos Verigakis
        name = server['name']
125 90d90bd2 Giorgos Verigakis
        sourceimage = Image.objects.get(id=server['imageRef'])
126 90d90bd2 Giorgos Verigakis
        flavor = Flavor.objects.get(id=server['flavorRef'])
127 7e2f9d4b Giorgos Verigakis
    except KeyError:
128 7e2f9d4b Giorgos Verigakis
        raise BadRequest
129 7e2f9d4b Giorgos Verigakis
    except Image.DoesNotExist:
130 7e2f9d4b Giorgos Verigakis
        raise ItemNotFound
131 7e2f9d4b Giorgos Verigakis
    except Flavor.DoesNotExist:
132 7e2f9d4b Giorgos Verigakis
        raise ItemNotFound
133 7e2f9d4b Giorgos Verigakis
    
134 c36934a7 Giorgos Verigakis
    server = VirtualMachine.objects.create(
135 7e2f9d4b Giorgos Verigakis
        name=name,
136 7e2f9d4b Giorgos Verigakis
        owner=get_user(),
137 7e2f9d4b Giorgos Verigakis
        sourceimage=sourceimage,
138 7e2f9d4b Giorgos Verigakis
        ipfour='0.0.0.0',
139 7e2f9d4b Giorgos Verigakis
        ipsix='::1',
140 7e2f9d4b Giorgos Verigakis
        flavor=flavor)
141 7e2f9d4b Giorgos Verigakis
                
142 7e2f9d4b Giorgos Verigakis
    if request.META.get('SERVER_NAME', None) == 'testserver':
143 7e2f9d4b Giorgos Verigakis
        name = 'test-server'
144 7e2f9d4b Giorgos Verigakis
        dry_run = True
145 7e2f9d4b Giorgos Verigakis
    else:
146 c36934a7 Giorgos Verigakis
        name = server.backend_id
147 7e2f9d4b Giorgos Verigakis
        dry_run = False
148 7e2f9d4b Giorgos Verigakis
    
149 7e2f9d4b Giorgos Verigakis
    jobId = rapi.CreateInstance(
150 7e2f9d4b Giorgos Verigakis
        mode='create',
151 7e2f9d4b Giorgos Verigakis
        name=name,
152 7e2f9d4b Giorgos Verigakis
        disk_template='plain',
153 7e2f9d4b Giorgos Verigakis
        disks=[{"size": 2000}],         #FIXME: Always ask for a 2GB disk for now
154 7e2f9d4b Giorgos Verigakis
        nics=[{}],
155 90d90bd2 Giorgos Verigakis
        os='debootstrap+default',       #TODO: select OS from imageRef
156 7e2f9d4b Giorgos Verigakis
        ip_check=False,
157 90d90bd2 Giorgos Verigakis
        name_check=False,
158 7e2f9d4b Giorgos Verigakis
        pnode=rapi.GetNodes()[0],       #TODO: verify if this is necessary
159 7e2f9d4b Giorgos Verigakis
        dry_run=dry_run,
160 7e2f9d4b Giorgos Verigakis
        beparams=dict(auto_balance=True, vcpus=flavor.cpu, memory=flavor.ram))
161 7e2f9d4b Giorgos Verigakis
    
162 c36934a7 Giorgos Verigakis
    server.save()
163 7e2f9d4b Giorgos Verigakis
        
164 7e2f9d4b Giorgos Verigakis
    log.info('created vm with %s cpus, %s ram and %s storage' % (flavor.cpu, flavor.ram, flavor.disk))
165 7e2f9d4b Giorgos Verigakis
    
166 c36934a7 Giorgos Verigakis
    serverdict = server_to_dict(server, detail=True)
167 c36934a7 Giorgos Verigakis
    serverdict['status'] = 'BUILD'
168 c36934a7 Giorgos Verigakis
    serverdict['adminPass'] = random_password()
169 c36934a7 Giorgos Verigakis
    return render_server(request, serverdict, status=202)
170 7e2f9d4b Giorgos Verigakis
171 c36934a7 Giorgos Verigakis
@api_method('GET')
172 7e2f9d4b Giorgos Verigakis
def get_server_details(request, server_id):
173 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 200, 203
174 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
175 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
176 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
177 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
178 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
179 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
180 c36934a7 Giorgos Verigakis
    
181 7e2f9d4b Giorgos Verigakis
    try:
182 c36934a7 Giorgos Verigakis
        server_id = int(server_id)
183 c36934a7 Giorgos Verigakis
        server = VirtualMachine.objects.get(id=server_id)
184 7e2f9d4b Giorgos Verigakis
    except VirtualMachine.DoesNotExist:
185 c36934a7 Giorgos Verigakis
        raise ItemNotFound
186 7e2f9d4b Giorgos Verigakis
    
187 c36934a7 Giorgos Verigakis
    serverdict = server_to_dict(server, detail=True)
188 c36934a7 Giorgos Verigakis
    return render_server(request, serverdict)
189 7e2f9d4b Giorgos Verigakis
190 c36934a7 Giorgos Verigakis
@api_method('PUT')
191 c36934a7 Giorgos Verigakis
def update_server_name(request, server_id):
192 c36934a7 Giorgos Verigakis
    # Normal Response Code: 204
193 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
194 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
195 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
196 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
197 c36934a7 Giorgos Verigakis
    #                       badMediaType(415),
198 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
199 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
200 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
201 c36934a7 Giorgos Verigakis
    
202 7e2f9d4b Giorgos Verigakis
    req = get_request_dict(request)
203 7e2f9d4b Giorgos Verigakis
    
204 7e2f9d4b Giorgos Verigakis
    try:
205 7e2f9d4b Giorgos Verigakis
        name = req['server']['name']
206 c36934a7 Giorgos Verigakis
        server_id = int(server_id)
207 c36934a7 Giorgos Verigakis
        server = VirtualMachine.objects.get(id=server_id)
208 7e2f9d4b Giorgos Verigakis
    except KeyError:
209 7e2f9d4b Giorgos Verigakis
        raise BadRequest
210 7e2f9d4b Giorgos Verigakis
    except VirtualMachine.DoesNotExist:
211 c36934a7 Giorgos Verigakis
        raise ItemNotFound
212 7e2f9d4b Giorgos Verigakis
    
213 c36934a7 Giorgos Verigakis
    server.name = name
214 c36934a7 Giorgos Verigakis
    server.save()
215 7e2f9d4b Giorgos Verigakis
    
216 7e2f9d4b Giorgos Verigakis
    return HttpResponse(status=204)
217 7e2f9d4b Giorgos Verigakis
218 c36934a7 Giorgos Verigakis
@api_method('DELETE')
219 7e2f9d4b Giorgos Verigakis
def delete_server(request, server_id):
220 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 204
221 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
222 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
223 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
224 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
225 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
226 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
227 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
228 c36934a7 Giorgos Verigakis
    
229 7e2f9d4b Giorgos Verigakis
    try:
230 c36934a7 Giorgos Verigakis
        server_id = int(server_id)
231 c36934a7 Giorgos Verigakis
        server = VirtualMachine.objects.get(id=server_id)
232 7e2f9d4b Giorgos Verigakis
    except VirtualMachine.DoesNotExist:
233 c36934a7 Giorgos Verigakis
        raise ItemNotFound
234 7e2f9d4b Giorgos Verigakis
    
235 c36934a7 Giorgos Verigakis
    server.start_action('DESTROY')
236 c36934a7 Giorgos Verigakis
    rapi.DeleteInstance(server.backend_id)
237 7e2f9d4b Giorgos Verigakis
    return HttpResponse(status=204)
238 b016b476 Giorgos Verigakis
239 b016b476 Giorgos Verigakis
@api_method('POST')
240 b016b476 Giorgos Verigakis
def server_action(request, server_id):
241 b016b476 Giorgos Verigakis
    try:
242 b016b476 Giorgos Verigakis
        server_id = int(server_id)
243 b016b476 Giorgos Verigakis
        server = VirtualMachine.objects.get(id=server_id)
244 b016b476 Giorgos Verigakis
    except VirtualMachine.DoesNotExist:
245 b016b476 Giorgos Verigakis
        raise ItemNotFound
246 b016b476 Giorgos Verigakis
247 b016b476 Giorgos Verigakis
    req = get_request_dict(request)
248 b016b476 Giorgos Verigakis
    if len(req) != 1:
249 b016b476 Giorgos Verigakis
        raise BadRequest
250 b016b476 Giorgos Verigakis
    
251 b016b476 Giorgos Verigakis
    key = req.keys()[0]
252 b016b476 Giorgos Verigakis
    if key not in server_actions:
253 b016b476 Giorgos Verigakis
        raise BadRequest
254 b016b476 Giorgos Verigakis
    
255 b016b476 Giorgos Verigakis
    return server_actions[key](server, req[key])
256 b016b476 Giorgos Verigakis
257 b016b476 Giorgos Verigakis
@api_method('GET')
258 b016b476 Giorgos Verigakis
def list_addresses(request, server_id):
259 b016b476 Giorgos Verigakis
    # Normal Response Codes: 200, 203
260 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
261 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
262 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
263 b016b476 Giorgos Verigakis
    #                       badRequest (400),
264 b016b476 Giorgos Verigakis
    #                       overLimit (413)
265 b016b476 Giorgos Verigakis
    
266 b016b476 Giorgos Verigakis
    try:
267 b016b476 Giorgos Verigakis
        server_id = int(server_id)
268 b016b476 Giorgos Verigakis
        server = VirtualMachine.objects.get(id=server_id)
269 b016b476 Giorgos Verigakis
    except VirtualMachine.DoesNotExist:
270 b016b476 Giorgos Verigakis
        raise ItemNotFound
271 b016b476 Giorgos Verigakis
    
272 b016b476 Giorgos Verigakis
    addresses = [address_to_dict(server.ipfour, server.ipsix)]
273 b016b476 Giorgos Verigakis
    
274 b016b476 Giorgos Verigakis
    if request.type == 'xml':
275 b016b476 Giorgos Verigakis
        data = render_to_string('list_addresses.xml', {'addresses': addresses})
276 b016b476 Giorgos Verigakis
    else:
277 b016b476 Giorgos Verigakis
        data = json.dumps({'addresses': {'values': addresses}})
278 b016b476 Giorgos Verigakis
    
279 b016b476 Giorgos Verigakis
    return HttpResponse(data, status=200)
280 b016b476 Giorgos Verigakis
281 b016b476 Giorgos Verigakis
@api_method('GET')
282 b016b476 Giorgos Verigakis
def list_addresses_by_network(request, server_id, network_id):
283 b016b476 Giorgos Verigakis
    # Normal Response Codes: 200, 203
284 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
285 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
286 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
287 b016b476 Giorgos Verigakis
    #                       badRequest (400),
288 b016b476 Giorgos Verigakis
    #                       itemNotFound (404),
289 b016b476 Giorgos Verigakis
    #                       overLimit (413)
290 b016b476 Giorgos Verigakis
    
291 b016b476 Giorgos Verigakis
    try:
292 b016b476 Giorgos Verigakis
        server_id = int(server_id)
293 b016b476 Giorgos Verigakis
        server = VirtualMachine.objects.get(id=server_id)
294 b016b476 Giorgos Verigakis
    except VirtualMachine.DoesNotExist:
295 b016b476 Giorgos Verigakis
        raise ItemNotFound
296 b016b476 Giorgos Verigakis
    
297 b016b476 Giorgos Verigakis
    if network_id != 'public':
298 b016b476 Giorgos Verigakis
        raise ItemNotFound
299 b016b476 Giorgos Verigakis
    
300 b016b476 Giorgos Verigakis
    address = address_to_dict(server.ipfour, server.ipsix)
301 b016b476 Giorgos Verigakis
    
302 b016b476 Giorgos Verigakis
    if request.type == 'xml':
303 b016b476 Giorgos Verigakis
        data = render_to_string('address.xml', {'address': address})
304 b016b476 Giorgos Verigakis
    else:
305 b016b476 Giorgos Verigakis
        data = json.dumps({'network': address})
306 b016b476 Giorgos Verigakis
    
307 b016b476 Giorgos Verigakis
    return HttpResponse(data, status=200)