Statistics
| Branch: | Tag: | Revision:

root / api / servers.py @ b016b476

History | View | Annotate | Download (10.1 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 c36934a7 Giorgos Verigakis
        d['flavorId'] = server.flavor.id            # XXX Should use flavorRef instead?
68 c36934a7 Giorgos Verigakis
        d['imageId'] = server.sourceimage.id        # XXX Should use imageRef instead?
69 c36934a7 Giorgos Verigakis
        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 7e2f9d4b Giorgos Verigakis
            d['metadata'] = dict(values=metadata)
75 7e2f9d4b Giorgos Verigakis
        
76 b016b476 Giorgos Verigakis
        d['addresses'] = [address_to_dict(server.ipfour, server.ipsix)]
77 7e2f9d4b Giorgos Verigakis
    return d
78 7e2f9d4b Giorgos Verigakis
79 c36934a7 Giorgos Verigakis
def render_server(request, serverdict, status=200):
80 7e2f9d4b Giorgos Verigakis
    if request.type == 'xml':
81 c36934a7 Giorgos Verigakis
        data = render_to_string('server.xml', dict(server=serverdict, is_root=True))
82 7e2f9d4b Giorgos Verigakis
    else:
83 c36934a7 Giorgos Verigakis
        data = json.dumps({'server': serverdict})
84 c36934a7 Giorgos Verigakis
    return HttpResponse(data, status=status)
85 7e2f9d4b Giorgos Verigakis
86 7e2f9d4b Giorgos Verigakis
87 c36934a7 Giorgos Verigakis
@api_method('GET')
88 7e2f9d4b Giorgos Verigakis
def list_servers(request, detail=False):
89 7e2f9d4b Giorgos Verigakis
    # Normal Response Codes: 200, 203
90 7e2f9d4b Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
91 7e2f9d4b Giorgos Verigakis
    #                       serviceUnavailable (503),
92 7e2f9d4b Giorgos Verigakis
    #                       unauthorized (401),
93 7e2f9d4b Giorgos Verigakis
    #                       badRequest (400),
94 7e2f9d4b Giorgos Verigakis
    #                       overLimit (413)
95 c36934a7 Giorgos Verigakis
    
96 7e2f9d4b Giorgos Verigakis
    owner = get_user()
97 c36934a7 Giorgos Verigakis
    user_servers = VirtualMachine.objects.filter(owner=owner, deleted=False)
98 c36934a7 Giorgos Verigakis
    servers = [server_to_dict(server, detail) for server in user_servers]
99 c36934a7 Giorgos Verigakis
    
100 7e2f9d4b Giorgos Verigakis
    if request.type == 'xml':
101 7e2f9d4b Giorgos Verigakis
        data = render_to_string('list_servers.xml', dict(servers=servers, detail=detail))
102 7e2f9d4b Giorgos Verigakis
    else:
103 c36934a7 Giorgos Verigakis
        data = json.dumps({'servers': {'values': servers}})
104 c36934a7 Giorgos Verigakis
    
105 c36934a7 Giorgos Verigakis
    return HttpResponse(data, status=200)
106 7e2f9d4b Giorgos Verigakis
107 c36934a7 Giorgos Verigakis
@api_method('POST')
108 7e2f9d4b Giorgos Verigakis
def create_server(request):
109 7e2f9d4b Giorgos Verigakis
    # Normal Response Code: 202
110 7e2f9d4b Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
111 7e2f9d4b Giorgos Verigakis
    #                       serviceUnavailable (503),
112 7e2f9d4b Giorgos Verigakis
    #                       unauthorized (401),
113 7e2f9d4b Giorgos Verigakis
    #                       badMediaType(415),
114 7e2f9d4b Giorgos Verigakis
    #                       itemNotFound (404),
115 7e2f9d4b Giorgos Verigakis
    #                       badRequest (400),
116 7e2f9d4b Giorgos Verigakis
    #                       serverCapacityUnavailable (503),
117 7e2f9d4b Giorgos Verigakis
    #                       overLimit (413)
118 7e2f9d4b Giorgos Verigakis
    
119 7e2f9d4b Giorgos Verigakis
    req = get_request_dict(request)
120 7e2f9d4b Giorgos Verigakis
    
121 7e2f9d4b Giorgos Verigakis
    try:
122 7e2f9d4b Giorgos Verigakis
        server = req['server']
123 7e2f9d4b Giorgos Verigakis
        name = server['name']
124 7e2f9d4b Giorgos Verigakis
        sourceimage = Image.objects.get(id=server['imageId'])
125 7e2f9d4b Giorgos Verigakis
        flavor = Flavor.objects.get(id=server['flavorId'])
126 7e2f9d4b Giorgos Verigakis
    except KeyError:
127 7e2f9d4b Giorgos Verigakis
        raise BadRequest
128 7e2f9d4b Giorgos Verigakis
    except Image.DoesNotExist:
129 7e2f9d4b Giorgos Verigakis
        raise ItemNotFound
130 7e2f9d4b Giorgos Verigakis
    except Flavor.DoesNotExist:
131 7e2f9d4b Giorgos Verigakis
        raise ItemNotFound
132 7e2f9d4b Giorgos Verigakis
    
133 c36934a7 Giorgos Verigakis
    server = VirtualMachine.objects.create(
134 7e2f9d4b Giorgos Verigakis
        name=name,
135 7e2f9d4b Giorgos Verigakis
        owner=get_user(),
136 7e2f9d4b Giorgos Verigakis
        sourceimage=sourceimage,
137 7e2f9d4b Giorgos Verigakis
        ipfour='0.0.0.0',
138 7e2f9d4b Giorgos Verigakis
        ipsix='::1',
139 7e2f9d4b Giorgos Verigakis
        flavor=flavor)
140 7e2f9d4b Giorgos Verigakis
                
141 7e2f9d4b Giorgos Verigakis
    if request.META.get('SERVER_NAME', None) == 'testserver':
142 7e2f9d4b Giorgos Verigakis
        name = 'test-server'
143 7e2f9d4b Giorgos Verigakis
        dry_run = True
144 7e2f9d4b Giorgos Verigakis
    else:
145 c36934a7 Giorgos Verigakis
        name = server.backend_id
146 7e2f9d4b Giorgos Verigakis
        dry_run = False
147 7e2f9d4b Giorgos Verigakis
    
148 7e2f9d4b Giorgos Verigakis
    jobId = rapi.CreateInstance(
149 7e2f9d4b Giorgos Verigakis
        mode='create',
150 7e2f9d4b Giorgos Verigakis
        name=name,
151 7e2f9d4b Giorgos Verigakis
        disk_template='plain',
152 7e2f9d4b Giorgos Verigakis
        disks=[{"size": 2000}],         #FIXME: Always ask for a 2GB disk for now
153 7e2f9d4b Giorgos Verigakis
        nics=[{}],
154 7e2f9d4b Giorgos Verigakis
        os='debootstrap+default',       #TODO: select OS from imageId
155 7e2f9d4b Giorgos Verigakis
        ip_check=False,
156 7e2f9d4b Giorgos Verigakis
        nam_check=False,
157 7e2f9d4b Giorgos Verigakis
        pnode=rapi.GetNodes()[0],       #TODO: verify if this is necessary
158 7e2f9d4b Giorgos Verigakis
        dry_run=dry_run,
159 7e2f9d4b Giorgos Verigakis
        beparams=dict(auto_balance=True, vcpus=flavor.cpu, memory=flavor.ram))
160 7e2f9d4b Giorgos Verigakis
    
161 c36934a7 Giorgos Verigakis
    server.save()
162 7e2f9d4b Giorgos Verigakis
        
163 7e2f9d4b Giorgos Verigakis
    log.info('created vm with %s cpus, %s ram and %s storage' % (flavor.cpu, flavor.ram, flavor.disk))
164 7e2f9d4b Giorgos Verigakis
    
165 c36934a7 Giorgos Verigakis
    serverdict = server_to_dict(server, detail=True)
166 c36934a7 Giorgos Verigakis
    serverdict['status'] = 'BUILD'
167 c36934a7 Giorgos Verigakis
    serverdict['adminPass'] = random_password()
168 c36934a7 Giorgos Verigakis
    return render_server(request, serverdict, status=202)
169 7e2f9d4b Giorgos Verigakis
170 c36934a7 Giorgos Verigakis
@api_method('GET')
171 7e2f9d4b Giorgos Verigakis
def get_server_details(request, server_id):
172 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 200, 203
173 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
174 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
175 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
176 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
177 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
178 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
179 c36934a7 Giorgos Verigakis
    
180 7e2f9d4b Giorgos Verigakis
    try:
181 c36934a7 Giorgos Verigakis
        server_id = int(server_id)
182 c36934a7 Giorgos Verigakis
        server = VirtualMachine.objects.get(id=server_id)
183 7e2f9d4b Giorgos Verigakis
    except VirtualMachine.DoesNotExist:
184 c36934a7 Giorgos Verigakis
        raise ItemNotFound
185 7e2f9d4b Giorgos Verigakis
    
186 c36934a7 Giorgos Verigakis
    serverdict = server_to_dict(server, detail=True)
187 c36934a7 Giorgos Verigakis
    return render_server(request, serverdict)
188 7e2f9d4b Giorgos Verigakis
189 c36934a7 Giorgos Verigakis
@api_method('PUT')
190 c36934a7 Giorgos Verigakis
def update_server_name(request, server_id):
191 c36934a7 Giorgos Verigakis
    # Normal Response Code: 204
192 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
193 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
194 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
195 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
196 c36934a7 Giorgos Verigakis
    #                       badMediaType(415),
197 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
198 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
199 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
200 c36934a7 Giorgos Verigakis
    
201 7e2f9d4b Giorgos Verigakis
    req = get_request_dict(request)
202 7e2f9d4b Giorgos Verigakis
    
203 7e2f9d4b Giorgos Verigakis
    try:
204 7e2f9d4b Giorgos Verigakis
        name = req['server']['name']
205 c36934a7 Giorgos Verigakis
        server_id = int(server_id)
206 c36934a7 Giorgos Verigakis
        server = VirtualMachine.objects.get(id=server_id)
207 7e2f9d4b Giorgos Verigakis
    except KeyError:
208 7e2f9d4b Giorgos Verigakis
        raise BadRequest
209 7e2f9d4b Giorgos Verigakis
    except VirtualMachine.DoesNotExist:
210 c36934a7 Giorgos Verigakis
        raise ItemNotFound
211 7e2f9d4b Giorgos Verigakis
    
212 c36934a7 Giorgos Verigakis
    server.name = name
213 c36934a7 Giorgos Verigakis
    server.save()
214 7e2f9d4b Giorgos Verigakis
    
215 7e2f9d4b Giorgos Verigakis
    return HttpResponse(status=204)
216 7e2f9d4b Giorgos Verigakis
217 c36934a7 Giorgos Verigakis
@api_method('DELETE')
218 7e2f9d4b Giorgos Verigakis
def delete_server(request, server_id):
219 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 204
220 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
221 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
222 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
223 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
224 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
225 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
226 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
227 c36934a7 Giorgos Verigakis
    
228 7e2f9d4b Giorgos Verigakis
    try:
229 c36934a7 Giorgos Verigakis
        server_id = int(server_id)
230 c36934a7 Giorgos Verigakis
        server = VirtualMachine.objects.get(id=server_id)
231 7e2f9d4b Giorgos Verigakis
    except VirtualMachine.DoesNotExist:
232 c36934a7 Giorgos Verigakis
        raise ItemNotFound
233 7e2f9d4b Giorgos Verigakis
    
234 c36934a7 Giorgos Verigakis
    server.start_action('DESTROY')
235 c36934a7 Giorgos Verigakis
    rapi.DeleteInstance(server.backend_id)
236 7e2f9d4b Giorgos Verigakis
    return HttpResponse(status=204)
237 b016b476 Giorgos Verigakis
238 b016b476 Giorgos Verigakis
@api_method('POST')
239 b016b476 Giorgos Verigakis
def server_action(request, server_id):
240 b016b476 Giorgos Verigakis
    try:
241 b016b476 Giorgos Verigakis
        server_id = int(server_id)
242 b016b476 Giorgos Verigakis
        server = VirtualMachine.objects.get(id=server_id)
243 b016b476 Giorgos Verigakis
    except VirtualMachine.DoesNotExist:
244 b016b476 Giorgos Verigakis
        raise ItemNotFound
245 b016b476 Giorgos Verigakis
246 b016b476 Giorgos Verigakis
    req = get_request_dict(request)
247 b016b476 Giorgos Verigakis
    if len(req) != 1:
248 b016b476 Giorgos Verigakis
        raise BadRequest
249 b016b476 Giorgos Verigakis
    
250 b016b476 Giorgos Verigakis
    key = req.keys()[0]
251 b016b476 Giorgos Verigakis
    if key not in server_actions:
252 b016b476 Giorgos Verigakis
        raise BadRequest
253 b016b476 Giorgos Verigakis
    
254 b016b476 Giorgos Verigakis
    return server_actions[key](server, req[key])
255 b016b476 Giorgos Verigakis
256 b016b476 Giorgos Verigakis
@api_method('GET')
257 b016b476 Giorgos Verigakis
def list_addresses(request, server_id):
258 b016b476 Giorgos Verigakis
    # Normal Response Codes: 200, 203
259 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
260 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
261 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
262 b016b476 Giorgos Verigakis
    #                       badRequest (400),
263 b016b476 Giorgos Verigakis
    #                       overLimit (413)
264 b016b476 Giorgos Verigakis
    
265 b016b476 Giorgos Verigakis
    try:
266 b016b476 Giorgos Verigakis
        server_id = int(server_id)
267 b016b476 Giorgos Verigakis
        server = VirtualMachine.objects.get(id=server_id)
268 b016b476 Giorgos Verigakis
    except VirtualMachine.DoesNotExist:
269 b016b476 Giorgos Verigakis
        raise ItemNotFound
270 b016b476 Giorgos Verigakis
    
271 b016b476 Giorgos Verigakis
    addresses = [address_to_dict(server.ipfour, server.ipsix)]
272 b016b476 Giorgos Verigakis
    
273 b016b476 Giorgos Verigakis
    if request.type == 'xml':
274 b016b476 Giorgos Verigakis
        data = render_to_string('list_addresses.xml', {'addresses': addresses})
275 b016b476 Giorgos Verigakis
    else:
276 b016b476 Giorgos Verigakis
        data = json.dumps({'addresses': {'values': addresses}})
277 b016b476 Giorgos Verigakis
    
278 b016b476 Giorgos Verigakis
    return HttpResponse(data, status=200)
279 b016b476 Giorgos Verigakis
280 b016b476 Giorgos Verigakis
@api_method('GET')
281 b016b476 Giorgos Verigakis
def list_addresses_by_network(request, server_id, network_id):
282 b016b476 Giorgos Verigakis
    # Normal Response Codes: 200, 203
283 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
284 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
285 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
286 b016b476 Giorgos Verigakis
    #                       badRequest (400),
287 b016b476 Giorgos Verigakis
    #                       itemNotFound (404),
288 b016b476 Giorgos Verigakis
    #                       overLimit (413)
289 b016b476 Giorgos Verigakis
    
290 b016b476 Giorgos Verigakis
    try:
291 b016b476 Giorgos Verigakis
        server_id = int(server_id)
292 b016b476 Giorgos Verigakis
        server = VirtualMachine.objects.get(id=server_id)
293 b016b476 Giorgos Verigakis
    except VirtualMachine.DoesNotExist:
294 b016b476 Giorgos Verigakis
        raise ItemNotFound
295 b016b476 Giorgos Verigakis
    
296 b016b476 Giorgos Verigakis
    if network_id != 'public':
297 b016b476 Giorgos Verigakis
        raise ItemNotFound
298 b016b476 Giorgos Verigakis
    
299 b016b476 Giorgos Verigakis
    address = address_to_dict(server.ipfour, server.ipsix)
300 b016b476 Giorgos Verigakis
    
301 b016b476 Giorgos Verigakis
    if request.type == 'xml':
302 b016b476 Giorgos Verigakis
        data = render_to_string('address.xml', {'address': address})
303 b016b476 Giorgos Verigakis
    else:
304 b016b476 Giorgos Verigakis
        data = json.dumps({'network': address})
305 b016b476 Giorgos Verigakis
    
306 b016b476 Giorgos Verigakis
    return HttpResponse(data, status=200)