actions.py 7.23 KB
Newer Older
Giorgos Verigakis's avatar
Giorgos Verigakis committed
1
2
3
4
#
# Copyright (c) 2010 Greek Research and Technology Network
#

5
6
from socket import getfqdn

Giorgos Verigakis's avatar
Giorgos Verigakis committed
7
8
from django.conf import settings
from django.http import HttpResponse
9
10
from django.template.loader import render_to_string
from django.utils import simplejson as json
Giorgos Verigakis's avatar
Giorgos Verigakis committed
11

Giorgos Verigakis's avatar
Giorgos Verigakis committed
12
from synnefo.api.faults import BadRequest, ResizeNotAllowed, ServiceUnavailable
13
from synnefo.api.util import random_password
14
from synnefo.util.rapi import GanetiRapiClient
15
from synnefo.util.vapclient import request_forwarding as request_vnc_forwarding
Giorgos Verigakis's avatar
Giorgos Verigakis committed
16
from synnefo.logic import backend
17
from synnefo.logic.utils import get_rsapi_state
Giorgos Verigakis's avatar
Giorgos Verigakis committed
18

19

Giorgos Verigakis's avatar
Giorgos Verigakis committed
20
21
22
23
24
25
server_actions = {}

rapi = GanetiRapiClient(*settings.GANETI_CLUSTER_INFO)


def server_action(name):
Giorgos Verigakis's avatar
Giorgos Verigakis committed
26
27
28
29
30
    '''Decorator for functions implementing server actions.
    
       `name` is the key in the dict passed by the client.
    '''
    
Giorgos Verigakis's avatar
Giorgos Verigakis committed
31
32
33
34
35
    def decorator(func):
        server_actions[name] = func
        return func
    return decorator

36
@server_action('console')
37
def get_console(request, vm, args):
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
    """Arrange for an OOB console of the specified type

    This method arranges for an OOB console of the specified type.
    Only "vnc" type consoles are supported for now.
    It uses a running instance of vncauthproxy to setup proper
    VNC forwarding with a random password, then returns the necessary
    VNC connection info to the caller.

    """
    # Normal Response Code: 200
    # Error Response Codes: computeFault (400, 500),
    #                       serviceUnavailable (503),
    #                       unauthorized (401),
    #                       badRequest (400),
    #                       badMediaType(415),
    #                       itemNotFound (404),
    #                       buildInProgress (409),
    #                       overLimit (413)
    try:
        console_type = args.get('type', '')
        if console_type != 'VNC':
            raise BadRequest(message="type can only be 'VNC'")
    except KeyError:
        raise BadRequest()

    # Use RAPI to get VNC console information for this instance
64
    if get_rsapi_state(vm) != 'ACTIVE':
65
        raise BadRequest(message="Server not in ACTIVE state")
66
    console_data = rapi.GetInstanceConsole(vm.backend_id)
67
68
69
70
71
72
73
74
75
76
77
78
    if console_data['kind'] != 'vnc':
        raise ServiceUnavailable()

    # Let vncauthproxy decide on the source port.
    # FIXME
    # sport = 0
    sport = console_data['port'] - 1000
    daddr = console_data['host']
    dport = console_data['port']
    passwd = random_password()

    request_vnc_forwarding(sport, daddr, dport, passwd)
79
    vnc = { 'host': getfqdn(), 'port': sport, 'password': passwd }
80
81

    # Format to be reviewed by [verigak], FIXME
82
    if request.serialization == 'xml':
83
84
85
86
87
88
89
90
        mimetype = 'application/xml'
        data = render_to_string('vnc.xml', {'vnc': vnc})
    else:
        mimetype = 'application/json'
        data = json.dumps(vnc)

    return HttpResponse(data, mimetype=mimetype, status=200)

Giorgos Verigakis's avatar
Giorgos Verigakis committed
91
92

@server_action('changePassword')
93
def change_password(request, vm, args):
Giorgos Verigakis's avatar
Giorgos Verigakis committed
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
    # Normal Response Code: 202
    # Error Response Codes: computeFault (400, 500),
    #                       serviceUnavailable (503),
    #                       unauthorized (401),
    #                       badRequest (400),
    #                       badMediaType(415),
    #                       itemNotFound (404),
    #                       buildInProgress (409),
    #                       overLimit (413)
    
    try:
        adminPass = args['adminPass']
    except KeyError:
        raise BadRequest()

    raise ServiceUnavailable()

@server_action('reboot')
112
def reboot(request, vm, args):
Giorgos Verigakis's avatar
Giorgos Verigakis committed
113
114
115
116
117
118
119
120
121
122
    # Normal Response Code: 202
    # Error Response Codes: computeFault (400, 500),
    #                       serviceUnavailable (503),
    #                       unauthorized (401),
    #                       badRequest (400),
    #                       badMediaType(415),
    #                       itemNotFound (404),
    #                       buildInProgress (409),
    #                       overLimit (413)
    
123
124
    reboot_type = args.get('type', '')
    if reboot_type not in ('SOFT', 'HARD'):
Giorgos Verigakis's avatar
Giorgos Verigakis committed
125
126
        raise BadRequest()
    
Giorgos Verigakis's avatar
Giorgos Verigakis committed
127
128
    backend.start_action(vm, 'REBOOT')
    rapi.RebootInstance(vm.backend_id, reboot_type.lower())
Giorgos Verigakis's avatar
Giorgos Verigakis committed
129
130
131
    return HttpResponse(status=202)

@server_action('start')
132
def start(request, vm, args):
Giorgos Verigakis's avatar
Giorgos Verigakis committed
133
    # Normal Response Code: 202
Giorgos Verigakis's avatar
Giorgos Verigakis committed
134
135
    # Error Response Codes: serviceUnavailable (503),
    #                       itemNotFound (404)
Giorgos Verigakis's avatar
Giorgos Verigakis committed
136

Giorgos Verigakis's avatar
Giorgos Verigakis committed
137
138
    backend.start_action(vm, 'START')
    rapi.StartupInstance(vm.backend_id)
Giorgos Verigakis's avatar
Giorgos Verigakis committed
139
140
141
    return HttpResponse(status=202)

@server_action('shutdown')
142
def shutdown(request, vm, args):
Giorgos Verigakis's avatar
Giorgos Verigakis committed
143
    # Normal Response Code: 202
Giorgos Verigakis's avatar
Giorgos Verigakis committed
144
145
    # Error Response Codes: serviceUnavailable (503),
    #                       itemNotFound (404)
Giorgos Verigakis's avatar
Giorgos Verigakis committed
146
    
Giorgos Verigakis's avatar
Giorgos Verigakis committed
147
148
    backend.start_action(vm, 'STOP')
    rapi.ShutdownInstance(vm.backend_id)
Giorgos Verigakis's avatar
Giorgos Verigakis committed
149
150
151
    return HttpResponse(status=202)

@server_action('rebuild')
152
def rebuild(request, vm, args):
Giorgos Verigakis's avatar
Giorgos Verigakis committed
153
154
155
156
157
158
159
160
161
162
163
164
165
166
    # Normal Response Code: 202
    # Error Response Codes: computeFault (400, 500),
    #                       serviceUnavailable (503),
    #                       unauthorized (401),
    #                       badRequest (400),
    #                       badMediaType(415),
    #                       itemNotFound (404),
    #                       buildInProgress (409),
    #                       serverCapacityUnavailable (503),
    #                       overLimit (413)

    raise ServiceUnavailable()

@server_action('resize')
167
def resize(request, vm, args):
Giorgos Verigakis's avatar
Giorgos Verigakis committed
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
    # Normal Response Code: 202
    # Error Response Codes: computeFault (400, 500),
    #                       serviceUnavailable (503),
    #                       unauthorized (401),
    #                       badRequest (400),
    #                       badMediaType(415),
    #                       itemNotFound (404),
    #                       buildInProgress (409),
    #                       serverCapacityUnavailable (503),
    #                       overLimit (413),
    #                       resizeNotAllowed (403)
    
    raise ResizeNotAllowed()

@server_action('confirmResize')
183
def confirm_resize(request, vm, args):
Giorgos Verigakis's avatar
Giorgos Verigakis committed
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
    # Normal Response Code: 204
    # Error Response Codes: computeFault (400, 500),
    #                       serviceUnavailable (503),
    #                       unauthorized (401),
    #                       badRequest (400),
    #                       badMediaType(415),
    #                       itemNotFound (404),
    #                       buildInProgress (409),
    #                       serverCapacityUnavailable (503),
    #                       overLimit (413),
    #                       resizeNotAllowed (403)
    
    raise ResizeNotAllowed()

@server_action('revertResize')
199
def revert_resize(request, vm, args):
Giorgos Verigakis's avatar
Giorgos Verigakis committed
200
201
202
203
204
205
206
207
208
209
210
211
212
    # Normal Response Code: 202
    # Error Response Codes: computeFault (400, 500),
    #                       serviceUnavailable (503),
    #                       unauthorized (401),
    #                       badRequest (400),
    #                       badMediaType(415),
    #                       itemNotFound (404),
    #                       buildInProgress (409),
    #                       serverCapacityUnavailable (503),
    #                       overLimit (413),
    #                       resizeNotAllowed (403)

    raise ResizeNotAllowed()