Statistics
| Branch: | Tag: | Revision:

root / api / servers.py @ c36934a7

History | View | Annotate | Download (7.6 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 7e2f9d4b Giorgos Verigakis
from synnefo.api.errors import *
6 7e2f9d4b Giorgos Verigakis
from synnefo.api.util import *
7 7e2f9d4b Giorgos Verigakis
from synnefo.db.models import *
8 7e2f9d4b Giorgos Verigakis
from synnefo.util.rapi import GanetiRapiClient
9 7e2f9d4b Giorgos Verigakis
10 7e2f9d4b Giorgos Verigakis
from django.conf.urls.defaults import *
11 7e2f9d4b Giorgos Verigakis
from django.http import HttpResponse
12 7e2f9d4b Giorgos Verigakis
from django.template.loader import render_to_string
13 7e2f9d4b Giorgos Verigakis
14 7e2f9d4b Giorgos Verigakis
from logging import getLogger
15 7e2f9d4b Giorgos Verigakis
16 7e2f9d4b Giorgos Verigakis
import json
17 7e2f9d4b Giorgos Verigakis
18 7e2f9d4b Giorgos Verigakis
19 7e2f9d4b Giorgos Verigakis
log = getLogger('synnefo.api.servers')
20 7e2f9d4b Giorgos Verigakis
rapi = GanetiRapiClient(*settings.GANETI_CLUSTER_INFO)
21 7e2f9d4b Giorgos Verigakis
22 7e2f9d4b Giorgos Verigakis
urlpatterns = patterns('synnefo.api.servers',
23 7e2f9d4b Giorgos Verigakis
    (r'^(?:/|.json|.xml)?$', 'demux'),
24 7e2f9d4b Giorgos Verigakis
    (r'^/detail(?:.json|.xml)?$', 'list_servers', {'detail': True}),
25 7e2f9d4b Giorgos Verigakis
    (r'^/(\d+)(?:.json|.xml)?$', 'server_demux'),
26 7e2f9d4b Giorgos Verigakis
)
27 7e2f9d4b Giorgos Verigakis
28 7e2f9d4b Giorgos Verigakis
29 7e2f9d4b Giorgos Verigakis
def demux(request):
30 7e2f9d4b Giorgos Verigakis
    if request.method == 'GET':
31 7e2f9d4b Giorgos Verigakis
        return list_servers(request)
32 7e2f9d4b Giorgos Verigakis
    elif request.method == 'POST':
33 7e2f9d4b Giorgos Verigakis
        return create_server(request)
34 7e2f9d4b Giorgos Verigakis
    else:
35 c36934a7 Giorgos Verigakis
        fault = BadRequest()
36 c36934a7 Giorgos Verigakis
        return render_fault(request, fault)
37 7e2f9d4b Giorgos Verigakis
38 7e2f9d4b Giorgos Verigakis
def server_demux(request, server_id):
39 7e2f9d4b Giorgos Verigakis
    if request.method == 'GET':
40 7e2f9d4b Giorgos Verigakis
        return get_server_details(request, server_id)
41 7e2f9d4b Giorgos Verigakis
    elif request.method == 'PUT':
42 7e2f9d4b Giorgos Verigakis
        return update_server_name(request, server_id)
43 7e2f9d4b Giorgos Verigakis
    elif request.method == 'DELETE':
44 7e2f9d4b Giorgos Verigakis
        return delete_server(request, server_id)
45 7e2f9d4b Giorgos Verigakis
    else:
46 c36934a7 Giorgos Verigakis
        fault = BadRequest()
47 c36934a7 Giorgos Verigakis
        return render_fault(request, fault)
48 7e2f9d4b Giorgos Verigakis
49 c36934a7 Giorgos Verigakis
50 c36934a7 Giorgos Verigakis
def server_to_dict(server, detail=False):
51 c36934a7 Giorgos Verigakis
    d = dict(id=server.id, name=server.name)
52 7e2f9d4b Giorgos Verigakis
    if detail:
53 c36934a7 Giorgos Verigakis
        d['status'] = server.rsapi_state
54 c36934a7 Giorgos Verigakis
        d['progress'] = 100 if server.rsapi_state == 'ACTIVE' else 0
55 c36934a7 Giorgos Verigakis
        d['hostId'] = server.hostid
56 c36934a7 Giorgos Verigakis
        d['updated'] = server.updated.isoformat()
57 c36934a7 Giorgos Verigakis
        d['created'] = server.created.isoformat()
58 c36934a7 Giorgos Verigakis
        d['flavorId'] = server.flavor.id            # XXX Should use flavorRef instead?
59 c36934a7 Giorgos Verigakis
        d['imageId'] = server.sourceimage.id        # XXX Should use imageRef instead?
60 c36934a7 Giorgos Verigakis
        d['description'] = server.description       # XXX Not in OpenStack docs
61 7e2f9d4b Giorgos Verigakis
        
62 c36934a7 Giorgos Verigakis
        server_meta = server.virtualmachinemetadata_set.all()
63 c36934a7 Giorgos Verigakis
        metadata = dict((meta.meta_key, meta.meta_value) for meta in server_meta)
64 7e2f9d4b Giorgos Verigakis
        if metadata:
65 7e2f9d4b Giorgos Verigakis
            d['metadata'] = dict(values=metadata)
66 7e2f9d4b Giorgos Verigakis
        
67 c36934a7 Giorgos Verigakis
        public_addrs = [dict(version=4, addr=server.ipfour), dict(version=6, addr=server.ipsix)]
68 7e2f9d4b Giorgos Verigakis
        d['addresses'] = {'values': []}
69 7e2f9d4b Giorgos Verigakis
        d['addresses']['values'].append({'id': 'public', 'values': public_addrs})
70 7e2f9d4b Giorgos Verigakis
    return d
71 7e2f9d4b Giorgos Verigakis
72 c36934a7 Giorgos Verigakis
def render_server(request, serverdict, status=200):
73 7e2f9d4b Giorgos Verigakis
    if request.type == 'xml':
74 c36934a7 Giorgos Verigakis
        data = render_to_string('server.xml', dict(server=serverdict, is_root=True))
75 7e2f9d4b Giorgos Verigakis
    else:
76 c36934a7 Giorgos Verigakis
        data = json.dumps({'server': serverdict})
77 c36934a7 Giorgos Verigakis
    return HttpResponse(data, status=status)
78 7e2f9d4b Giorgos Verigakis
79 7e2f9d4b Giorgos Verigakis
80 c36934a7 Giorgos Verigakis
@api_method('GET')
81 7e2f9d4b Giorgos Verigakis
def list_servers(request, detail=False):
82 7e2f9d4b Giorgos Verigakis
    # Normal Response Codes: 200, 203
83 7e2f9d4b Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
84 7e2f9d4b Giorgos Verigakis
    #                       serviceUnavailable (503),
85 7e2f9d4b Giorgos Verigakis
    #                       unauthorized (401),
86 7e2f9d4b Giorgos Verigakis
    #                       badRequest (400),
87 7e2f9d4b Giorgos Verigakis
    #                       overLimit (413)
88 c36934a7 Giorgos Verigakis
    
89 7e2f9d4b Giorgos Verigakis
    owner = get_user()
90 c36934a7 Giorgos Verigakis
    user_servers = VirtualMachine.objects.filter(owner=owner, deleted=False)
91 c36934a7 Giorgos Verigakis
    servers = [server_to_dict(server, detail) for server in user_servers]
92 c36934a7 Giorgos Verigakis
    
93 7e2f9d4b Giorgos Verigakis
    if request.type == 'xml':
94 7e2f9d4b Giorgos Verigakis
        data = render_to_string('list_servers.xml', dict(servers=servers, detail=detail))
95 7e2f9d4b Giorgos Verigakis
    else:
96 c36934a7 Giorgos Verigakis
        data = json.dumps({'servers': {'values': servers}})
97 c36934a7 Giorgos Verigakis
    
98 c36934a7 Giorgos Verigakis
    return HttpResponse(data, status=200)
99 7e2f9d4b Giorgos Verigakis
100 c36934a7 Giorgos Verigakis
@api_method('POST')
101 7e2f9d4b Giorgos Verigakis
def create_server(request):
102 7e2f9d4b Giorgos Verigakis
    # Normal Response Code: 202
103 7e2f9d4b Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
104 7e2f9d4b Giorgos Verigakis
    #                       serviceUnavailable (503),
105 7e2f9d4b Giorgos Verigakis
    #                       unauthorized (401),
106 7e2f9d4b Giorgos Verigakis
    #                       badMediaType(415),
107 7e2f9d4b Giorgos Verigakis
    #                       itemNotFound (404),
108 7e2f9d4b Giorgos Verigakis
    #                       badRequest (400),
109 7e2f9d4b Giorgos Verigakis
    #                       serverCapacityUnavailable (503),
110 7e2f9d4b Giorgos Verigakis
    #                       overLimit (413)
111 7e2f9d4b Giorgos Verigakis
    
112 7e2f9d4b Giorgos Verigakis
    req = get_request_dict(request)
113 7e2f9d4b Giorgos Verigakis
    
114 7e2f9d4b Giorgos Verigakis
    try:
115 7e2f9d4b Giorgos Verigakis
        server = req['server']
116 7e2f9d4b Giorgos Verigakis
        name = server['name']
117 7e2f9d4b Giorgos Verigakis
        sourceimage = Image.objects.get(id=server['imageId'])
118 7e2f9d4b Giorgos Verigakis
        flavor = Flavor.objects.get(id=server['flavorId'])
119 7e2f9d4b Giorgos Verigakis
    except KeyError:
120 7e2f9d4b Giorgos Verigakis
        raise BadRequest
121 7e2f9d4b Giorgos Verigakis
    except Image.DoesNotExist:
122 7e2f9d4b Giorgos Verigakis
        raise ItemNotFound
123 7e2f9d4b Giorgos Verigakis
    except Flavor.DoesNotExist:
124 7e2f9d4b Giorgos Verigakis
        raise ItemNotFound
125 7e2f9d4b Giorgos Verigakis
    
126 c36934a7 Giorgos Verigakis
    server = VirtualMachine.objects.create(
127 7e2f9d4b Giorgos Verigakis
        name=name,
128 7e2f9d4b Giorgos Verigakis
        owner=get_user(),
129 7e2f9d4b Giorgos Verigakis
        sourceimage=sourceimage,
130 7e2f9d4b Giorgos Verigakis
        ipfour='0.0.0.0',
131 7e2f9d4b Giorgos Verigakis
        ipsix='::1',
132 7e2f9d4b Giorgos Verigakis
        flavor=flavor)
133 7e2f9d4b Giorgos Verigakis
                
134 7e2f9d4b Giorgos Verigakis
    if request.META.get('SERVER_NAME', None) == 'testserver':
135 7e2f9d4b Giorgos Verigakis
        name = 'test-server'
136 7e2f9d4b Giorgos Verigakis
        dry_run = True
137 7e2f9d4b Giorgos Verigakis
    else:
138 c36934a7 Giorgos Verigakis
        name = server.backend_id
139 7e2f9d4b Giorgos Verigakis
        dry_run = False
140 7e2f9d4b Giorgos Verigakis
    
141 7e2f9d4b Giorgos Verigakis
    jobId = rapi.CreateInstance(
142 7e2f9d4b Giorgos Verigakis
        mode='create',
143 7e2f9d4b Giorgos Verigakis
        name=name,
144 7e2f9d4b Giorgos Verigakis
        disk_template='plain',
145 7e2f9d4b Giorgos Verigakis
        disks=[{"size": 2000}],         #FIXME: Always ask for a 2GB disk for now
146 7e2f9d4b Giorgos Verigakis
        nics=[{}],
147 7e2f9d4b Giorgos Verigakis
        os='debootstrap+default',       #TODO: select OS from imageId
148 7e2f9d4b Giorgos Verigakis
        ip_check=False,
149 7e2f9d4b Giorgos Verigakis
        nam_check=False,
150 7e2f9d4b Giorgos Verigakis
        pnode=rapi.GetNodes()[0],       #TODO: verify if this is necessary
151 7e2f9d4b Giorgos Verigakis
        dry_run=dry_run,
152 7e2f9d4b Giorgos Verigakis
        beparams=dict(auto_balance=True, vcpus=flavor.cpu, memory=flavor.ram))
153 7e2f9d4b Giorgos Verigakis
    
154 c36934a7 Giorgos Verigakis
    server.save()
155 7e2f9d4b Giorgos Verigakis
        
156 7e2f9d4b Giorgos Verigakis
    log.info('created vm with %s cpus, %s ram and %s storage' % (flavor.cpu, flavor.ram, flavor.disk))
157 7e2f9d4b Giorgos Verigakis
    
158 c36934a7 Giorgos Verigakis
    serverdict = server_to_dict(server, detail=True)
159 c36934a7 Giorgos Verigakis
    serverdict['status'] = 'BUILD'
160 c36934a7 Giorgos Verigakis
    serverdict['adminPass'] = random_password()
161 c36934a7 Giorgos Verigakis
    return render_server(request, serverdict, status=202)
162 7e2f9d4b Giorgos Verigakis
163 c36934a7 Giorgos Verigakis
@api_method('GET')
164 7e2f9d4b Giorgos Verigakis
def get_server_details(request, server_id):
165 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 200, 203
166 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
167 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
168 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
169 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
170 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
171 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
172 c36934a7 Giorgos Verigakis
    
173 7e2f9d4b Giorgos Verigakis
    try:
174 c36934a7 Giorgos Verigakis
        server_id = int(server_id)
175 c36934a7 Giorgos Verigakis
        server = VirtualMachine.objects.get(id=server_id)
176 7e2f9d4b Giorgos Verigakis
    except VirtualMachine.DoesNotExist:
177 c36934a7 Giorgos Verigakis
        raise ItemNotFound
178 7e2f9d4b Giorgos Verigakis
    
179 c36934a7 Giorgos Verigakis
    serverdict = server_to_dict(server, detail=True)
180 c36934a7 Giorgos Verigakis
    return render_server(request, serverdict)
181 7e2f9d4b Giorgos Verigakis
182 c36934a7 Giorgos Verigakis
@api_method('PUT')
183 c36934a7 Giorgos Verigakis
def update_server_name(request, server_id):
184 c36934a7 Giorgos Verigakis
    # Normal Response Code: 204
185 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
186 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
187 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
188 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
189 c36934a7 Giorgos Verigakis
    #                       badMediaType(415),
190 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
191 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
192 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
193 c36934a7 Giorgos Verigakis
    
194 7e2f9d4b Giorgos Verigakis
    req = get_request_dict(request)
195 7e2f9d4b Giorgos Verigakis
    
196 7e2f9d4b Giorgos Verigakis
    try:
197 7e2f9d4b Giorgos Verigakis
        name = req['server']['name']
198 c36934a7 Giorgos Verigakis
        server_id = int(server_id)
199 c36934a7 Giorgos Verigakis
        server = VirtualMachine.objects.get(id=server_id)
200 7e2f9d4b Giorgos Verigakis
    except KeyError:
201 7e2f9d4b Giorgos Verigakis
        raise BadRequest
202 7e2f9d4b Giorgos Verigakis
    except VirtualMachine.DoesNotExist:
203 c36934a7 Giorgos Verigakis
        raise ItemNotFound
204 7e2f9d4b Giorgos Verigakis
    
205 c36934a7 Giorgos Verigakis
    server.name = name
206 c36934a7 Giorgos Verigakis
    server.save()
207 7e2f9d4b Giorgos Verigakis
    
208 7e2f9d4b Giorgos Verigakis
    return HttpResponse(status=204)
209 7e2f9d4b Giorgos Verigakis
210 c36934a7 Giorgos Verigakis
@api_method('DELETE')
211 7e2f9d4b Giorgos Verigakis
def delete_server(request, server_id):
212 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 204
213 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
214 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
215 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
216 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
217 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
218 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
219 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
220 c36934a7 Giorgos Verigakis
    
221 7e2f9d4b Giorgos Verigakis
    try:
222 c36934a7 Giorgos Verigakis
        server_id = int(server_id)
223 c36934a7 Giorgos Verigakis
        server = VirtualMachine.objects.get(id=server_id)
224 7e2f9d4b Giorgos Verigakis
    except VirtualMachine.DoesNotExist:
225 c36934a7 Giorgos Verigakis
        raise ItemNotFound
226 7e2f9d4b Giorgos Verigakis
    
227 c36934a7 Giorgos Verigakis
    server.start_action('DESTROY')
228 c36934a7 Giorgos Verigakis
    rapi.DeleteInstance(server.backend_id)
229 7e2f9d4b Giorgos Verigakis
    return HttpResponse(status=204)