Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / api / servers.py @ 24ea227b

History | View | Annotate | Download (33 kB)

1 b3fd98ae Christos Stavrakakis
# Copyright 2011-2013 GRNET S.A. All rights reserved.
2 ce55f211 Kostas Papadimitriou
#
3 adee02b8 Giorgos Verigakis
# Redistribution and use in source and binary forms, with or
4 adee02b8 Giorgos Verigakis
# without modification, are permitted provided that the following
5 adee02b8 Giorgos Verigakis
# conditions are met:
6 ce55f211 Kostas Papadimitriou
#
7 adee02b8 Giorgos Verigakis
#   1. Redistributions of source code must retain the above
8 adee02b8 Giorgos Verigakis
#      copyright notice, this list of conditions and the following
9 adee02b8 Giorgos Verigakis
#      disclaimer.
10 ce55f211 Kostas Papadimitriou
#
11 adee02b8 Giorgos Verigakis
#   2. Redistributions in binary form must reproduce the above
12 adee02b8 Giorgos Verigakis
#      copyright notice, this list of conditions and the following
13 adee02b8 Giorgos Verigakis
#      disclaimer in the documentation and/or other materials
14 adee02b8 Giorgos Verigakis
#      provided with the distribution.
15 ce55f211 Kostas Papadimitriou
#
16 adee02b8 Giorgos Verigakis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 adee02b8 Giorgos Verigakis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 adee02b8 Giorgos Verigakis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 adee02b8 Giorgos Verigakis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 adee02b8 Giorgos Verigakis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 adee02b8 Giorgos Verigakis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 adee02b8 Giorgos Verigakis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 adee02b8 Giorgos Verigakis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 adee02b8 Giorgos Verigakis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 adee02b8 Giorgos Verigakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 adee02b8 Giorgos Verigakis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 adee02b8 Giorgos Verigakis
# POSSIBILITY OF SUCH DAMAGE.
28 ce55f211 Kostas Papadimitriou
#
29 adee02b8 Giorgos Verigakis
# The views and conclusions contained in the software and
30 adee02b8 Giorgos Verigakis
# documentation are those of the authors and should not be
31 adee02b8 Giorgos Verigakis
# interpreted as representing official policies, either expressed
32 adee02b8 Giorgos Verigakis
# or implied, of GRNET S.A.
33 7e2f9d4b Giorgos Verigakis
34 ccd0d474 Giorgos Verigakis
from django.conf import settings
35 6b256427 Christos Stavrakakis
from django.conf.urls import patterns
36 a6b17d33 Christos Stavrakakis
37 4dba0480 Christos Stavrakakis
from django.db import transaction
38 7e2f9d4b Giorgos Verigakis
from django.http import HttpResponse
39 7e2f9d4b Giorgos Verigakis
from django.template.loader import render_to_string
40 29a59bc1 Giorgos Verigakis
from django.utils import simplejson as json
41 7e2f9d4b Giorgos Verigakis
42 b3fd98ae Christos Stavrakakis
from snf_django.lib import api
43 b3fd98ae Christos Stavrakakis
from snf_django.lib.api import faults, utils
44 816d7588 Christos Stavrakakis
45 bd40abfa Christos Stavrakakis
from synnefo.api import util
46 41a7fae7 Christos Stavrakakis
from synnefo.db.models import (VirtualMachine, VirtualMachineMetadata)
47 41a7fae7 Christos Stavrakakis
from synnefo.logic import servers, utils as logic_utils
48 9e98ba3c Giorgos Verigakis
49 bf5c82dc Christos Stavrakakis
from logging import getLogger
50 b3fd98ae Christos Stavrakakis
log = getLogger(__name__)
51 7e2f9d4b Giorgos Verigakis
52 e440e835 Christos Stavrakakis
urlpatterns = patterns(
53 e440e835 Christos Stavrakakis
    'synnefo.api.servers',
54 7e2f9d4b Giorgos Verigakis
    (r'^(?:/|.json|.xml)?$', 'demux'),
55 7e2f9d4b Giorgos Verigakis
    (r'^/detail(?:.json|.xml)?$', 'list_servers', {'detail': True}),
56 7e2f9d4b Giorgos Verigakis
    (r'^/(\d+)(?:.json|.xml)?$', 'server_demux'),
57 41a7fae7 Christos Stavrakakis
    (r'^/(\d+)/action(?:.json|.xml)?$', 'demux_server_action'),
58 b016b476 Giorgos Verigakis
    (r'^/(\d+)/ips(?:.json|.xml)?$', 'list_addresses'),
59 b016b476 Giorgos Verigakis
    (r'^/(\d+)/ips/(.+?)(?:.json|.xml)?$', 'list_addresses_by_network'),
60 8a992938 Christos Stavrakakis
    (r'^/(\d+)/metadata(?:.json|.xml)?$', 'metadata_demux'),
61 8a992938 Christos Stavrakakis
    (r'^/(\d+)/metadata/(.+?)(?:.json|.xml)?$', 'metadata_item_demux'),
62 c738c935 Giorgos Verigakis
    (r'^/(\d+)/stats(?:.json|.xml)?$', 'server_stats'),
63 85a634e6 Kostas Papadimitriou
    (r'^/(\d+)/diagnostics(?:.json)?$', 'get_server_diagnostics'),
64 7e2f9d4b Giorgos Verigakis
)
65 7e2f9d4b Giorgos Verigakis
66 7e2f9d4b Giorgos Verigakis
67 7e2f9d4b Giorgos Verigakis
def demux(request):
68 7e2f9d4b Giorgos Verigakis
    if request.method == 'GET':
69 7e2f9d4b Giorgos Verigakis
        return list_servers(request)
70 7e2f9d4b Giorgos Verigakis
    elif request.method == 'POST':
71 7e2f9d4b Giorgos Verigakis
        return create_server(request)
72 7e2f9d4b Giorgos Verigakis
    else:
73 c0720b78 Kostas Papadimitriou
        return api.api_method_not_allowed(request)
74 7e2f9d4b Giorgos Verigakis
75 55cd40be Vangelis Koukis
76 7e2f9d4b Giorgos Verigakis
def server_demux(request, server_id):
77 7e2f9d4b Giorgos Verigakis
    if request.method == 'GET':
78 7e2f9d4b Giorgos Verigakis
        return get_server_details(request, server_id)
79 7e2f9d4b Giorgos Verigakis
    elif request.method == 'PUT':
80 7e2f9d4b Giorgos Verigakis
        return update_server_name(request, server_id)
81 7e2f9d4b Giorgos Verigakis
    elif request.method == 'DELETE':
82 7e2f9d4b Giorgos Verigakis
        return delete_server(request, server_id)
83 7e2f9d4b Giorgos Verigakis
    else:
84 c0720b78 Kostas Papadimitriou
        return api.api_method_not_allowed(request)
85 d8e50a39 Giorgos Verigakis
86 55cd40be Vangelis Koukis
87 d8e50a39 Giorgos Verigakis
def metadata_demux(request, server_id):
88 d8e50a39 Giorgos Verigakis
    if request.method == 'GET':
89 d8e50a39 Giorgos Verigakis
        return list_metadata(request, server_id)
90 d8e50a39 Giorgos Verigakis
    elif request.method == 'POST':
91 d8e50a39 Giorgos Verigakis
        return update_metadata(request, server_id)
92 d8e50a39 Giorgos Verigakis
    else:
93 c0720b78 Kostas Papadimitriou
        return api.api_method_not_allowed(request)
94 d8e50a39 Giorgos Verigakis
95 55cd40be Vangelis Koukis
96 d8e50a39 Giorgos Verigakis
def metadata_item_demux(request, server_id, key):
97 d8e50a39 Giorgos Verigakis
    if request.method == 'GET':
98 d8e50a39 Giorgos Verigakis
        return get_metadata_item(request, server_id, key)
99 d8e50a39 Giorgos Verigakis
    elif request.method == 'PUT':
100 d8e50a39 Giorgos Verigakis
        return create_metadata_item(request, server_id, key)
101 d8e50a39 Giorgos Verigakis
    elif request.method == 'DELETE':
102 d8e50a39 Giorgos Verigakis
        return delete_metadata_item(request, server_id, key)
103 d8e50a39 Giorgos Verigakis
    else:
104 c0720b78 Kostas Papadimitriou
        return api.api_method_not_allowed(request)
105 7e2f9d4b Giorgos Verigakis
106 08b079e2 Stavros Sachtouris
107 b3a43976 Christos Stavrakakis
def nic_to_attachments(nic):
108 b3a43976 Christos Stavrakakis
    """Convert a NIC object to 'attachments attribute.
109 b3a43976 Christos Stavrakakis

110 b3a43976 Christos Stavrakakis
    Convert a NIC object to match the format of 'attachments' attribute of the
111 b3a43976 Christos Stavrakakis
    response to the /servers API call.
112 b3a43976 Christos Stavrakakis

113 b3a43976 Christos Stavrakakis
    NOTE: The 'ips' of the NIC object have been prefetched in order to avoid DB
114 b3a43976 Christos Stavrakakis
    queries. No subsequent queries for 'ips' (like filtering) should be
115 b3a43976 Christos Stavrakakis
    performed because this will return in a new DB query.
116 b3a43976 Christos Stavrakakis

117 b3a43976 Christos Stavrakakis
    """
118 c988fcca Christos Stavrakakis
    d = {'id': nic.id,
119 b3a43976 Christos Stavrakakis
         'network_id': str(nic.network_id),
120 7fede91e Christos Stavrakakis
         'mac_address': nic.mac,
121 92d2d1ce Christos Stavrakakis
         'ipv4': '',
122 92d2d1ce Christos Stavrakakis
         'ipv6': ''}
123 47c66641 Dimitris Aragiorgis
124 207b70d5 Giorgos Verigakis
    if nic.firewall_profile:
125 207b70d5 Giorgos Verigakis
        d['firewallProfile'] = nic.firewall_profile
126 b3a43976 Christos Stavrakakis
127 b3a43976 Christos Stavrakakis
    for ip in nic.ips.all():
128 b3a43976 Christos Stavrakakis
        if not ip.deleted:
129 b3a43976 Christos Stavrakakis
            ip_type = "floating" if ip.floating_ip else "fixed"
130 b3a43976 Christos Stavrakakis
            if ip.ipversion == 4:
131 b3a43976 Christos Stavrakakis
                d["ipv4"] = ip.address
132 b3a43976 Christos Stavrakakis
                d["OS-EXT-IPS:type"] = ip_type
133 b3a43976 Christos Stavrakakis
            else:
134 b3a43976 Christos Stavrakakis
                d["ipv6"] = ip.address
135 b3a43976 Christos Stavrakakis
                d["OS-EXT-IPS:type"] = ip_type
136 d44c236b Giorgos Verigakis
    return d
137 b016b476 Giorgos Verigakis
138 55cd40be Vangelis Koukis
139 78c165cf Christos Stavrakakis
def attachments_to_addresses(attachments):
140 b3a43976 Christos Stavrakakis
    """Convert 'attachments' attribute to 'addresses'.
141 b3a43976 Christos Stavrakakis

142 b3a43976 Christos Stavrakakis
    Convert a a list of 'attachments' attribute to a list of 'addresses'
143 b3a43976 Christos Stavrakakis
    attribute, as expected in the response to /servers API call.
144 b3a43976 Christos Stavrakakis

145 b3a43976 Christos Stavrakakis
    """
146 1f638a85 Christos Stavrakakis
    addresses = {}
147 78c165cf Christos Stavrakakis
    for nic in attachments:
148 b3a43976 Christos Stavrakakis
        net_addrs = []
149 92d2d1ce Christos Stavrakakis
        if nic["ipv4"]:
150 b3a43976 Christos Stavrakakis
            net_addrs.append({"version": 4,
151 b3a43976 Christos Stavrakakis
                              "addr": nic["ipv4"],
152 b3a43976 Christos Stavrakakis
                              "OS-EXT-IPS:type": nic["OS-EXT-IPS:type"]})
153 78c165cf Christos Stavrakakis
        if nic["ipv6"]:
154 b3a43976 Christos Stavrakakis
            net_addrs.append({"version": 6,
155 b3a43976 Christos Stavrakakis
                              "addr": nic["ipv6"],
156 b3a43976 Christos Stavrakakis
                              "OS-EXT-IPS:type": nic["OS-EXT-IPS:type"]})
157 b3a43976 Christos Stavrakakis
        addresses[nic["network_id"]] = net_addrs
158 1f638a85 Christos Stavrakakis
    return addresses
159 1f638a85 Christos Stavrakakis
160 1f638a85 Christos Stavrakakis
161 d8e50a39 Giorgos Verigakis
def vm_to_dict(vm, detail=False):
162 d8e50a39 Giorgos Verigakis
    d = dict(id=vm.id, name=vm.name)
163 1b696c26 Christos Stavrakakis
    d['links'] = util.vm_to_links(vm.id)
164 7e2f9d4b Giorgos Verigakis
    if detail:
165 936e0be3 Christos Stavrakakis
        d['user_id'] = vm.userid
166 936e0be3 Christos Stavrakakis
        d['tenant_id'] = vm.userid
167 41a7fae7 Christos Stavrakakis
        d['status'] = logic_utils.get_rsapi_state(vm)
168 41a7fae7 Christos Stavrakakis
        d['SNF:task_state'] = logic_utils.get_task_state(vm)
169 41a7fae7 Christos Stavrakakis
        d['progress'] = 100 if d['status'] == 'ACTIVE' else vm.buildpercentage
170 d8e50a39 Giorgos Verigakis
        d['hostId'] = vm.hostid
171 b3fd98ae Christos Stavrakakis
        d['updated'] = utils.isoformat(vm.updated)
172 b3fd98ae Christos Stavrakakis
        d['created'] = utils.isoformat(vm.created)
173 1b696c26 Christos Stavrakakis
        d['flavor'] = {"id": vm.flavor.id,
174 1b696c26 Christos Stavrakakis
                       "links": util.flavor_to_links(vm.flavor.id)}
175 1b696c26 Christos Stavrakakis
        d['image'] = {"id": vm.imageid,
176 1b696c26 Christos Stavrakakis
                      "links": util.image_to_links(vm.imageid)}
177 e221ade2 Christos Stavrakakis
        d['suspended'] = vm.suspended
178 ce55f211 Kostas Papadimitriou
179 7cc3c7d9 Giorgos Verigakis
        metadata = dict((m.meta_key, m.meta_value) for m in vm.metadata.all())
180 1b696c26 Christos Stavrakakis
        d['metadata'] = metadata
181 aa197ee4 Vangelis Koukis
182 b3a43976 Christos Stavrakakis
        nics = vm.nics.all()
183 b3a43976 Christos Stavrakakis
        active_nics = filter(lambda nic: nic.state == "ACTIVE", nics)
184 b3a43976 Christos Stavrakakis
        active_nics.sort(key=lambda nic: nic.id)
185 b3a43976 Christos Stavrakakis
        attachments = map(nic_to_attachments, active_nics)
186 5029ff36 Christos Stavrakakis
        d['attachments'] = attachments
187 78c165cf Christos Stavrakakis
        d['addresses'] = attachments_to_addresses(attachments)
188 85a634e6 Kostas Papadimitriou
189 85a634e6 Kostas Papadimitriou
        # include the latest vm diagnostic, if set
190 85a634e6 Kostas Papadimitriou
        diagnostic = vm.get_last_diagnostic()
191 85a634e6 Kostas Papadimitriou
        if diagnostic:
192 85a634e6 Kostas Papadimitriou
            d['diagnostics'] = diagnostics_to_dict([diagnostic])
193 1b696c26 Christos Stavrakakis
        else:
194 1b696c26 Christos Stavrakakis
            d['diagnostics'] = []
195 f8352d29 Christos Stavrakakis
        # Fixed
196 f8352d29 Christos Stavrakakis
        d["security_groups"] = [{"name": "default"}]
197 f8352d29 Christos Stavrakakis
        d["key_name"] = None
198 f8352d29 Christos Stavrakakis
        d["config_drive"] = ""
199 f8352d29 Christos Stavrakakis
        d["accessIPv4"] = ""
200 f8352d29 Christos Stavrakakis
        d["accessIPv6"] = ""
201 b3a43976 Christos Stavrakakis
        fqdn = get_server_fqdn(vm, active_nics)
202 2522e489 Christos Stavrakakis
        d["SNF:fqdn"] = fqdn
203 b3a43976 Christos Stavrakakis
        d["SNF:port_forwarding"] = get_server_port_forwarding(vm, active_nics,
204 b3a43976 Christos Stavrakakis
                                                              fqdn)
205 7e2f9d4b Giorgos Verigakis
    return d
206 7e2f9d4b Giorgos Verigakis
207 d8e50a39 Giorgos Verigakis
208 b3a43976 Christos Stavrakakis
def get_server_public_ip(vm_nics, version=4):
209 b3a43976 Christos Stavrakakis
    """Get the first public IP address of a server.
210 b3a43976 Christos Stavrakakis

211 b3a43976 Christos Stavrakakis
    NOTE: 'vm_nics' objects have prefetched the ips
212 b3a43976 Christos Stavrakakis
    """
213 b3a43976 Christos Stavrakakis
    for version in [4, 6]:
214 b3a43976 Christos Stavrakakis
        for nic in vm_nics:
215 b3a43976 Christos Stavrakakis
            for ip in nic.ips.all():
216 b3a43976 Christos Stavrakakis
                if ip.ipversion == version and ip.public:
217 b3a43976 Christos Stavrakakis
                    return ip
218 b3a43976 Christos Stavrakakis
    return None
219 b3a43976 Christos Stavrakakis
220 b3a43976 Christos Stavrakakis
221 b3a43976 Christos Stavrakakis
def get_server_fqdn(vm, vm_nics):
222 b3a43976 Christos Stavrakakis
    public_ip = get_server_public_ip(vm_nics)
223 b3a43976 Christos Stavrakakis
    if public_ip is None:
224 b3a43976 Christos Stavrakakis
        return ""
225 b3a43976 Christos Stavrakakis
226 d328a525 Christos Stavrakakis
    fqdn_setting = settings.CYCLADES_SERVERS_FQDN
227 d328a525 Christos Stavrakakis
    if fqdn_setting is None:
228 b3a43976 Christos Stavrakakis
        return public_ip.address
229 d328a525 Christos Stavrakakis
    elif isinstance(fqdn_setting, basestring):
230 d328a525 Christos Stavrakakis
        return fqdn_setting % {"id": vm.id}
231 d328a525 Christos Stavrakakis
    else:
232 d328a525 Christos Stavrakakis
        msg = ("Invalid setting: CYCLADES_SERVERS_FQDN."
233 d328a525 Christos Stavrakakis
               " Value must be a string.")
234 d328a525 Christos Stavrakakis
        raise faults.InternalServerError(msg)
235 d328a525 Christos Stavrakakis
236 d328a525 Christos Stavrakakis
237 b3a43976 Christos Stavrakakis
def get_server_port_forwarding(vm, vm_nics, fqdn):
238 2522e489 Christos Stavrakakis
    """Create API 'port_forwarding' attribute from corresponding setting.
239 2522e489 Christos Stavrakakis

240 2522e489 Christos Stavrakakis
    Create the 'port_forwarding' API vm attribute based on the corresponding
241 2522e489 Christos Stavrakakis
    setting (CYCLADES_PORT_FORWARDING), which can be either a tuple
242 2522e489 Christos Stavrakakis
    of the form (host, port) or a callable object returning such tuple. In
243 2522e489 Christos Stavrakakis
    case of callable object, must be called with the following arguments:
244 2522e489 Christos Stavrakakis
    * ip_address
245 2522e489 Christos Stavrakakis
    * server_id
246 2522e489 Christos Stavrakakis
    * fqdn
247 2522e489 Christos Stavrakakis
    * owner UUID
248 2522e489 Christos Stavrakakis

249 b3a43976 Christos Stavrakakis
    NOTE: 'vm_nics' objects have prefetched the ips
250 2522e489 Christos Stavrakakis
    """
251 2522e489 Christos Stavrakakis
    port_forwarding = {}
252 b3a43976 Christos Stavrakakis
    public_ip = get_server_public_ip(vm_nics)
253 b3a43976 Christos Stavrakakis
    if public_ip is None:
254 b3a43976 Christos Stavrakakis
        return port_forwarding
255 2522e489 Christos Stavrakakis
    for dport, to_dest in settings.CYCLADES_PORT_FORWARDING.items():
256 2522e489 Christos Stavrakakis
        if hasattr(to_dest, "__call__"):
257 b3a43976 Christos Stavrakakis
            to_dest = to_dest(public_ip.address, vm.id, fqdn, vm.userid)
258 2522e489 Christos Stavrakakis
        msg = ("Invalid setting: CYCLADES_PORT_FOWARDING."
259 2522e489 Christos Stavrakakis
               " Value must be a tuple of two elements (host, port).")
260 2522e489 Christos Stavrakakis
        if not isinstance(to_dest, tuple) or len(to_dest) != 2:
261 2522e489 Christos Stavrakakis
                raise faults.InternalServerError(msg)
262 2522e489 Christos Stavrakakis
        else:
263 2522e489 Christos Stavrakakis
            try:
264 2522e489 Christos Stavrakakis
                host, port = to_dest
265 2522e489 Christos Stavrakakis
            except (TypeError, ValueError):
266 2522e489 Christos Stavrakakis
                raise faults.InternalServerError(msg)
267 2522e489 Christos Stavrakakis
268 2522e489 Christos Stavrakakis
        port_forwarding[dport] = {"host": host, "port": str(port)}
269 2522e489 Christos Stavrakakis
    return port_forwarding
270 2522e489 Christos Stavrakakis
271 2522e489 Christos Stavrakakis
272 85a634e6 Kostas Papadimitriou
def diagnostics_to_dict(diagnostics):
273 85a634e6 Kostas Papadimitriou
    """
274 85a634e6 Kostas Papadimitriou
    Extract api data from diagnostics QuerySet.
275 85a634e6 Kostas Papadimitriou
    """
276 85a634e6 Kostas Papadimitriou
    entries = list()
277 85a634e6 Kostas Papadimitriou
278 85a634e6 Kostas Papadimitriou
    for diagnostic in diagnostics:
279 85a634e6 Kostas Papadimitriou
        # format source date if set
280 85a634e6 Kostas Papadimitriou
        formatted_source_date = None
281 85a634e6 Kostas Papadimitriou
        if diagnostic.source_date:
282 b3fd98ae Christos Stavrakakis
            formatted_source_date = utils.isoformat(diagnostic.source_date)
283 85a634e6 Kostas Papadimitriou
284 85a634e6 Kostas Papadimitriou
        entry = {
285 85a634e6 Kostas Papadimitriou
            'source': diagnostic.source,
286 b3fd98ae Christos Stavrakakis
            'created': utils.isoformat(diagnostic.created),
287 85a634e6 Kostas Papadimitriou
            'message': diagnostic.message,
288 85a634e6 Kostas Papadimitriou
            'details': diagnostic.details,
289 85a634e6 Kostas Papadimitriou
            'level': diagnostic.level,
290 85a634e6 Kostas Papadimitriou
        }
291 85a634e6 Kostas Papadimitriou
292 85a634e6 Kostas Papadimitriou
        if formatted_source_date:
293 85a634e6 Kostas Papadimitriou
            entry['source_date'] = formatted_source_date
294 85a634e6 Kostas Papadimitriou
295 85a634e6 Kostas Papadimitriou
        entries.append(entry)
296 85a634e6 Kostas Papadimitriou
297 85a634e6 Kostas Papadimitriou
    return entries
298 85a634e6 Kostas Papadimitriou
299 85a634e6 Kostas Papadimitriou
300 d8e50a39 Giorgos Verigakis
def render_server(request, server, status=200):
301 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
302 b36f78fa Giorgos Verigakis
        data = render_to_string('server.xml', {
303 b36f78fa Giorgos Verigakis
            'server': server,
304 b36f78fa Giorgos Verigakis
            'is_root': True})
305 7e2f9d4b Giorgos Verigakis
    else:
306 d8e50a39 Giorgos Verigakis
        data = json.dumps({'server': server})
307 c36934a7 Giorgos Verigakis
    return HttpResponse(data, status=status)
308 aa197ee4 Vangelis Koukis
309 7e2f9d4b Giorgos Verigakis
310 85a634e6 Kostas Papadimitriou
def render_diagnostics(request, diagnostics_dict, status=200):
311 85a634e6 Kostas Papadimitriou
    """
312 85a634e6 Kostas Papadimitriou
    Render diagnostics dictionary to json response.
313 85a634e6 Kostas Papadimitriou
    """
314 85a634e6 Kostas Papadimitriou
    return HttpResponse(json.dumps(diagnostics_dict), status=status)
315 85a634e6 Kostas Papadimitriou
316 85a634e6 Kostas Papadimitriou
317 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
318 85a634e6 Kostas Papadimitriou
def get_server_diagnostics(request, server_id):
319 85a634e6 Kostas Papadimitriou
    """
320 85a634e6 Kostas Papadimitriou
    Virtual machine diagnostics api view.
321 85a634e6 Kostas Papadimitriou
    """
322 85a634e6 Kostas Papadimitriou
    log.debug('server_diagnostics %s', server_id)
323 85a634e6 Kostas Papadimitriou
    vm = util.get_vm(server_id, request.user_uniq)
324 85a634e6 Kostas Papadimitriou
    diagnostics = diagnostics_to_dict(vm.diagnostics.all())
325 85a634e6 Kostas Papadimitriou
    return render_diagnostics(request, diagnostics)
326 85a634e6 Kostas Papadimitriou
327 85a634e6 Kostas Papadimitriou
328 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
329 7e2f9d4b Giorgos Verigakis
def list_servers(request, detail=False):
330 7e2f9d4b Giorgos Verigakis
    # Normal Response Codes: 200, 203
331 7e2f9d4b Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
332 7e2f9d4b Giorgos Verigakis
    #                       serviceUnavailable (503),
333 7e2f9d4b Giorgos Verigakis
    #                       unauthorized (401),
334 7e2f9d4b Giorgos Verigakis
    #                       badRequest (400),
335 7e2f9d4b Giorgos Verigakis
    #                       overLimit (413)
336 ce55f211 Kostas Papadimitriou
337 0c37a721 Christos Stavrakakis
    log.debug('list_servers detail=%s', detail)
338 e524ed5f Kostas Papadimitriou
    user_vms = VirtualMachine.objects.filter(userid=request.user_uniq)
339 b3a43976 Christos Stavrakakis
    if detail:
340 b3a43976 Christos Stavrakakis
        user_vms = user_vms.prefetch_related("nics__ips")
341 ce55f211 Kostas Papadimitriou
342 b6bc4afa Christos Stavrakakis
    user_vms = utils.filter_modified_since(request, objects=user_vms)
343 ce55f211 Kostas Papadimitriou
344 41a7fae7 Christos Stavrakakis
    servers_dict = [vm_to_dict(server, detail)
345 41a7fae7 Christos Stavrakakis
                    for server in user_vms.order_by('id')]
346 aa197ee4 Vangelis Koukis
347 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
348 b36f78fa Giorgos Verigakis
        data = render_to_string('list_servers.xml', {
349 41a7fae7 Christos Stavrakakis
            'servers': servers_dict,
350 b36f78fa Giorgos Verigakis
            'detail': detail})
351 7e2f9d4b Giorgos Verigakis
    else:
352 41a7fae7 Christos Stavrakakis
        data = json.dumps({'servers': servers_dict})
353 aa197ee4 Vangelis Koukis
354 c36934a7 Giorgos Verigakis
    return HttpResponse(data, status=200)
355 7e2f9d4b Giorgos Verigakis
356 55cd40be Vangelis Koukis
357 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='POST', user_required=True, logger=log)
358 2509ce17 Christos Stavrakakis
def create_server(request):
359 7e2f9d4b Giorgos Verigakis
    # Normal Response Code: 202
360 7e2f9d4b Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
361 7e2f9d4b Giorgos Verigakis
    #                       serviceUnavailable (503),
362 7e2f9d4b Giorgos Verigakis
    #                       unauthorized (401),
363 7e2f9d4b Giorgos Verigakis
    #                       badMediaType(415),
364 7e2f9d4b Giorgos Verigakis
    #                       itemNotFound (404),
365 7e2f9d4b Giorgos Verigakis
    #                       badRequest (400),
366 7e2f9d4b Giorgos Verigakis
    #                       serverCapacityUnavailable (503),
367 7e2f9d4b Giorgos Verigakis
    #                       overLimit (413)
368 bcd80cd9 Christos Stavrakakis
    req = utils.get_request_dict(request)
369 bcd80cd9 Christos Stavrakakis
    log.info('create_server %s', req)
370 bcd80cd9 Christos Stavrakakis
    user_id = request.user_uniq
371 bcd80cd9 Christos Stavrakakis
372 7e2f9d4b Giorgos Verigakis
    try:
373 bcd80cd9 Christos Stavrakakis
        server = req['server']
374 bcd80cd9 Christos Stavrakakis
        name = server['name']
375 bcd80cd9 Christos Stavrakakis
        metadata = server.get('metadata', {})
376 bcd80cd9 Christos Stavrakakis
        assert isinstance(metadata, dict)
377 bcd80cd9 Christos Stavrakakis
        image_id = server['imageRef']
378 bcd80cd9 Christos Stavrakakis
        flavor_id = server['flavorRef']
379 bcd80cd9 Christos Stavrakakis
        personality = server.get('personality', [])
380 bcd80cd9 Christos Stavrakakis
        assert isinstance(personality, list)
381 3aecadc8 Christos Stavrakakis
        networks = server.get("networks")
382 3aecadc8 Christos Stavrakakis
        if networks is not None:
383 3aecadc8 Christos Stavrakakis
            assert isinstance(networks, list)
384 bcd80cd9 Christos Stavrakakis
    except (KeyError, AssertionError):
385 bcd80cd9 Christos Stavrakakis
        raise faults.BadRequest("Malformed request")
386 bcd80cd9 Christos Stavrakakis
387 bcd80cd9 Christos Stavrakakis
    # Verify that personalities are well-formed
388 bcd80cd9 Christos Stavrakakis
    util.verify_personality(personality)
389 bcd80cd9 Christos Stavrakakis
    # Get image information
390 bcd80cd9 Christos Stavrakakis
    image = util.get_image_dict(image_id, user_id)
391 bcd80cd9 Christos Stavrakakis
    # Get flavor (ensure it is active)
392 bcd80cd9 Christos Stavrakakis
    flavor = util.get_flavor(flavor_id, include_deleted=False)
393 bcd80cd9 Christos Stavrakakis
    # Generate password
394 bcd80cd9 Christos Stavrakakis
    password = util.random_password()
395 bcd80cd9 Christos Stavrakakis
396 41a7fae7 Christos Stavrakakis
    vm = servers.create(user_id, name, password, flavor, image,
397 cb66110b Christos Stavrakakis
                        metadata=metadata, personality=personality,
398 d2c3c533 Christos Stavrakakis
                        networks=networks)
399 bcd80cd9 Christos Stavrakakis
400 bcd80cd9 Christos Stavrakakis
    server = vm_to_dict(vm, detail=True)
401 bcd80cd9 Christos Stavrakakis
    server['status'] = 'BUILD'
402 bcd80cd9 Christos Stavrakakis
    server['adminPass'] = password
403 bcd80cd9 Christos Stavrakakis
404 bcd80cd9 Christos Stavrakakis
    response = render_server(request, server, status=202)
405 4b8e03e5 Christos Stavrakakis
406 bcd80cd9 Christos Stavrakakis
    return response
407 bcd80cd9 Christos Stavrakakis
408 bcd80cd9 Christos Stavrakakis
409 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
410 7e2f9d4b Giorgos Verigakis
def get_server_details(request, server_id):
411 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 200, 203
412 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
413 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
414 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
415 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
416 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
417 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
418 ce55f211 Kostas Papadimitriou
419 0c37a721 Christos Stavrakakis
    log.debug('get_server_details %s', server_id)
420 b3a43976 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq,
421 b3a43976 Christos Stavrakakis
                     prefetch_related="nics__ips")
422 d8e50a39 Giorgos Verigakis
    server = vm_to_dict(vm, detail=True)
423 d8e50a39 Giorgos Verigakis
    return render_server(request, server)
424 7e2f9d4b Giorgos Verigakis
425 55cd40be Vangelis Koukis
426 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='PUT', user_required=True, logger=log)
427 874383a4 Christos Stavrakakis
@transaction.commit_on_success
428 c36934a7 Giorgos Verigakis
def update_server_name(request, server_id):
429 c36934a7 Giorgos Verigakis
    # Normal Response Code: 204
430 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
431 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
432 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
433 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
434 c36934a7 Giorgos Verigakis
    #                       badMediaType(415),
435 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
436 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
437 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
438 aa197ee4 Vangelis Koukis
439 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
440 bf5c82dc Christos Stavrakakis
    log.info('update_server_name %s %s', server_id, req)
441 ce55f211 Kostas Papadimitriou
442 7e2f9d4b Giorgos Verigakis
    try:
443 7e2f9d4b Giorgos Verigakis
        name = req['server']['name']
444 529178b1 Giorgos Verigakis
    except (TypeError, KeyError):
445 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
446 aa197ee4 Vangelis Koukis
447 7f2dbcad Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, for_update=True,
448 7f2dbcad Christos Stavrakakis
                     non_suspended=True)
449 a52cc1b4 Christos Stavrakakis
450 a52cc1b4 Christos Stavrakakis
    servers.rename(vm, new_name=name)
451 aa197ee4 Vangelis Koukis
452 7e2f9d4b Giorgos Verigakis
    return HttpResponse(status=204)
453 7e2f9d4b Giorgos Verigakis
454 55cd40be Vangelis Koukis
455 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='DELETE', user_required=True, logger=log)
456 7e2f9d4b Giorgos Verigakis
def delete_server(request, server_id):
457 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 204
458 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
459 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
460 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
461 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
462 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
463 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
464 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
465 ce55f211 Kostas Papadimitriou
466 bf5c82dc Christos Stavrakakis
    log.info('delete_server %s', server_id)
467 7f2dbcad Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, for_update=True,
468 7f2dbcad Christos Stavrakakis
                     non_suspended=True)
469 41a7fae7 Christos Stavrakakis
    vm = servers.destroy(vm)
470 7e2f9d4b Giorgos Verigakis
    return HttpResponse(status=204)
471 b016b476 Giorgos Verigakis
472 55cd40be Vangelis Koukis
473 04a95cf3 Kostas Papadimitriou
# additional server actions
474 04a95cf3 Kostas Papadimitriou
ARBITRARY_ACTIONS = ['console', 'firewallProfile']
475 04a95cf3 Kostas Papadimitriou
476 e440e835 Christos Stavrakakis
477 7f2dbcad Christos Stavrakakis
def key_to_action(key):
478 7f2dbcad Christos Stavrakakis
    """Map HTTP request key to a VM Action"""
479 7f2dbcad Christos Stavrakakis
    if key == "shutdown":
480 7f2dbcad Christos Stavrakakis
        return "STOP"
481 7f2dbcad Christos Stavrakakis
    if key == "delete":
482 7f2dbcad Christos Stavrakakis
        return "DESTROY"
483 b7f21824 Kostas Papadimitriou
    if key in ARBITRARY_ACTIONS:
484 7f2dbcad Christos Stavrakakis
        return None
485 7f2dbcad Christos Stavrakakis
    else:
486 7f2dbcad Christos Stavrakakis
        return key.upper()
487 7f2dbcad Christos Stavrakakis
488 7f2dbcad Christos Stavrakakis
489 41a7fae7 Christos Stavrakakis
@api.api_method(http_method='POST', user_required=True, logger=log)
490 41a7fae7 Christos Stavrakakis
@transaction.commit_on_success
491 41a7fae7 Christos Stavrakakis
def demux_server_action(request, server_id):
492 41a7fae7 Christos Stavrakakis
    req = utils.get_request_dict(request)
493 41a7fae7 Christos Stavrakakis
    log.debug('server_action %s %s', server_id, req)
494 7f2dbcad Christos Stavrakakis
495 41a7fae7 Christos Stavrakakis
    if len(req) != 1:
496 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Malformed request")
497 41a7fae7 Christos Stavrakakis
498 41a7fae7 Christos Stavrakakis
    # Do not allow any action on deleted or suspended VMs
499 41a7fae7 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, for_update=True,
500 41a7fae7 Christos Stavrakakis
                     non_deleted=True, non_suspended=True)
501 7f2dbcad Christos Stavrakakis
502 ece5581b Christos Stavrakakis
    action = req.keys()[0]
503 7f2dbcad Christos Stavrakakis
504 41a7fae7 Christos Stavrakakis
    if key_to_action(action) not in [x[0] for x in VirtualMachine.ACTIONS]:
505 41a7fae7 Christos Stavrakakis
        if action not in ARBITRARY_ACTIONS:
506 41a7fae7 Christos Stavrakakis
            raise faults.BadRequest("Action %s not supported" % action)
507 41a7fae7 Christos Stavrakakis
    action_args = req[action]
508 7f2dbcad Christos Stavrakakis
509 41a7fae7 Christos Stavrakakis
    if not isinstance(action_args, dict):
510 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Invalid argument")
511 7f2dbcad Christos Stavrakakis
512 41a7fae7 Christos Stavrakakis
    return server_actions[action](request, vm, action_args)
513 7f2dbcad Christos Stavrakakis
514 7f2dbcad Christos Stavrakakis
515 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
516 b016b476 Giorgos Verigakis
def list_addresses(request, server_id):
517 b016b476 Giorgos Verigakis
    # Normal Response Codes: 200, 203
518 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
519 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
520 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
521 b016b476 Giorgos Verigakis
    #                       badRequest (400),
522 b016b476 Giorgos Verigakis
    #                       overLimit (413)
523 ce55f211 Kostas Papadimitriou
524 0c37a721 Christos Stavrakakis
    log.debug('list_addresses %s', server_id)
525 b3a43976 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, prefetch_related="nic__ips")
526 b3a43976 Christos Stavrakakis
    attachments = [nic_to_attachments(nic)
527 b3a43976 Christos Stavrakakis
                   for nic in vm.nics.filter(state="ACTIVE")]
528 78c165cf Christos Stavrakakis
    addresses = attachments_to_addresses(attachments)
529 ce55f211 Kostas Papadimitriou
530 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
531 b016b476 Giorgos Verigakis
        data = render_to_string('list_addresses.xml', {'addresses': addresses})
532 b016b476 Giorgos Verigakis
    else:
533 1f638a85 Christos Stavrakakis
        data = json.dumps({'addresses': addresses, 'attachments': attachments})
534 aa197ee4 Vangelis Koukis
535 b016b476 Giorgos Verigakis
    return HttpResponse(data, status=200)
536 b016b476 Giorgos Verigakis
537 55cd40be Vangelis Koukis
538 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
539 b016b476 Giorgos Verigakis
def list_addresses_by_network(request, server_id, network_id):
540 b016b476 Giorgos Verigakis
    # Normal Response Codes: 200, 203
541 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
542 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
543 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
544 b016b476 Giorgos Verigakis
    #                       badRequest (400),
545 b016b476 Giorgos Verigakis
    #                       itemNotFound (404),
546 b016b476 Giorgos Verigakis
    #                       overLimit (413)
547 ce55f211 Kostas Papadimitriou
548 0c37a721 Christos Stavrakakis
    log.debug('list_addresses_by_network %s %s', server_id, network_id)
549 4b3b8688 Giorgos Verigakis
    machine = util.get_vm(server_id, request.user_uniq)
550 4b3b8688 Giorgos Verigakis
    network = util.get_network(network_id, request.user_uniq)
551 7c714455 Christos Stavrakakis
    nics = machine.nics.filter(network=network, state="ACTIVE")
552 b3a43976 Christos Stavrakakis
    addresses = attachments_to_addresses(map(nic_to_attachments, nics))
553 ce55f211 Kostas Papadimitriou
554 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
555 1f638a85 Christos Stavrakakis
        data = render_to_string('address.xml', {'addresses': addresses})
556 b016b476 Giorgos Verigakis
    else:
557 1f638a85 Christos Stavrakakis
        data = json.dumps({'network': addresses})
558 aa197ee4 Vangelis Koukis
559 b016b476 Giorgos Verigakis
    return HttpResponse(data, status=200)
560 d8e50a39 Giorgos Verigakis
561 55cd40be Vangelis Koukis
562 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
563 d8e50a39 Giorgos Verigakis
def list_metadata(request, server_id):
564 d8e50a39 Giorgos Verigakis
    # Normal Response Codes: 200, 203
565 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
566 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
567 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
568 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
569 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
570 ce55f211 Kostas Papadimitriou
571 0c37a721 Christos Stavrakakis
    log.debug('list_server_metadata %s', server_id)
572 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
573 7cc3c7d9 Giorgos Verigakis
    metadata = dict((m.meta_key, m.meta_value) for m in vm.metadata.all())
574 5029ff36 Christos Stavrakakis
    return util.render_metadata(request, metadata, use_values=False,
575 5029ff36 Christos Stavrakakis
                                status=200)
576 d8e50a39 Giorgos Verigakis
577 55cd40be Vangelis Koukis
578 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='POST', user_required=True, logger=log)
579 874383a4 Christos Stavrakakis
@transaction.commit_on_success
580 d8e50a39 Giorgos Verigakis
def update_metadata(request, server_id):
581 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 201
582 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
583 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
584 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
585 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
586 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
587 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
588 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
589 ce55f211 Kostas Papadimitriou
590 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
591 bf5c82dc Christos Stavrakakis
    log.info('update_server_metadata %s %s', server_id, req)
592 e221ade2 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
593 d8e50a39 Giorgos Verigakis
    try:
594 d8e50a39 Giorgos Verigakis
        metadata = req['metadata']
595 d8e50a39 Giorgos Verigakis
        assert isinstance(metadata, dict)
596 d8e50a39 Giorgos Verigakis
    except (KeyError, AssertionError):
597 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
598 ce55f211 Kostas Papadimitriou
599 7cc3c7d9 Giorgos Verigakis
    for key, val in metadata.items():
600 7cc3c7d9 Giorgos Verigakis
        meta, created = vm.metadata.get_or_create(meta_key=key)
601 7cc3c7d9 Giorgos Verigakis
        meta.meta_value = val
602 7cc3c7d9 Giorgos Verigakis
        meta.save()
603 ce55f211 Kostas Papadimitriou
604 7cc3c7d9 Giorgos Verigakis
    vm.save()
605 7cc3c7d9 Giorgos Verigakis
    vm_meta = dict((m.meta_key, m.meta_value) for m in vm.metadata.all())
606 7cc3c7d9 Giorgos Verigakis
    return util.render_metadata(request, vm_meta, status=201)
607 d8e50a39 Giorgos Verigakis
608 55cd40be Vangelis Koukis
609 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
610 d8e50a39 Giorgos Verigakis
def get_metadata_item(request, server_id, key):
611 d8e50a39 Giorgos Verigakis
    # Normal Response Codes: 200, 203
612 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
613 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
614 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
615 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
616 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
617 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
618 ce55f211 Kostas Papadimitriou
619 0c37a721 Christos Stavrakakis
    log.debug('get_server_metadata_item %s %s', server_id, key)
620 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
621 b36f78fa Giorgos Verigakis
    meta = util.get_vm_meta(vm, key)
622 62b894c0 Giorgos Verigakis
    d = {meta.meta_key: meta.meta_value}
623 62b894c0 Giorgos Verigakis
    return util.render_meta(request, d, status=200)
624 d8e50a39 Giorgos Verigakis
625 55cd40be Vangelis Koukis
626 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='PUT', user_required=True, logger=log)
627 4dba0480 Christos Stavrakakis
@transaction.commit_on_success
628 d8e50a39 Giorgos Verigakis
def create_metadata_item(request, server_id, key):
629 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 201
630 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
631 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
632 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
633 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
634 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
635 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
636 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
637 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
638 ce55f211 Kostas Papadimitriou
639 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
640 bf5c82dc Christos Stavrakakis
    log.info('create_server_metadata_item %s %s %s', server_id, key, req)
641 e221ade2 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
642 d8e50a39 Giorgos Verigakis
    try:
643 d8e50a39 Giorgos Verigakis
        metadict = req['meta']
644 d8e50a39 Giorgos Verigakis
        assert isinstance(metadict, dict)
645 d8e50a39 Giorgos Verigakis
        assert len(metadict) == 1
646 d8e50a39 Giorgos Verigakis
        assert key in metadict
647 d8e50a39 Giorgos Verigakis
    except (KeyError, AssertionError):
648 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
649 ce55f211 Kostas Papadimitriou
650 b36f78fa Giorgos Verigakis
    meta, created = VirtualMachineMetadata.objects.get_or_create(
651 b36f78fa Giorgos Verigakis
        meta_key=key,
652 b36f78fa Giorgos Verigakis
        vm=vm)
653 ce55f211 Kostas Papadimitriou
654 d8e50a39 Giorgos Verigakis
    meta.meta_value = metadict[key]
655 d8e50a39 Giorgos Verigakis
    meta.save()
656 5509b599 Giorgos Verigakis
    vm.save()
657 62b894c0 Giorgos Verigakis
    d = {meta.meta_key: meta.meta_value}
658 62b894c0 Giorgos Verigakis
    return util.render_meta(request, d, status=201)
659 d8e50a39 Giorgos Verigakis
660 55cd40be Vangelis Koukis
661 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='DELETE', user_required=True, logger=log)
662 4dba0480 Christos Stavrakakis
@transaction.commit_on_success
663 d8e50a39 Giorgos Verigakis
def delete_metadata_item(request, server_id, key):
664 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 204
665 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
666 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
667 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
668 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
669 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
670 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
671 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
672 d8e50a39 Giorgos Verigakis
    #                       overLimit (413),
673 ce55f211 Kostas Papadimitriou
674 bf5c82dc Christos Stavrakakis
    log.info('delete_server_metadata_item %s %s', server_id, key)
675 e221ade2 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
676 b36f78fa Giorgos Verigakis
    meta = util.get_vm_meta(vm, key)
677 d8e50a39 Giorgos Verigakis
    meta.delete()
678 5509b599 Giorgos Verigakis
    vm.save()
679 d8e50a39 Giorgos Verigakis
    return HttpResponse(status=204)
680 c738c935 Giorgos Verigakis
681 55cd40be Vangelis Koukis
682 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
683 c738c935 Giorgos Verigakis
def server_stats(request, server_id):
684 c738c935 Giorgos Verigakis
    # Normal Response Codes: 200
685 c738c935 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
686 c738c935 Giorgos Verigakis
    #                       serviceUnavailable (503),
687 c738c935 Giorgos Verigakis
    #                       unauthorized (401),
688 c738c935 Giorgos Verigakis
    #                       badRequest (400),
689 c738c935 Giorgos Verigakis
    #                       itemNotFound (404),
690 c738c935 Giorgos Verigakis
    #                       overLimit (413)
691 ce55f211 Kostas Papadimitriou
692 0c37a721 Christos Stavrakakis
    log.debug('server_stats %s', server_id)
693 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
694 924d8085 Christos Stavrakakis
    #secret = util.encrypt(vm.backend_vm_id)
695 924d8085 Christos Stavrakakis
    secret = vm.backend_vm_id      # XXX disable backend id encryption
696 ce55f211 Kostas Papadimitriou
697 c738c935 Giorgos Verigakis
    stats = {
698 c738c935 Giorgos Verigakis
        'serverRef': vm.id,
699 c738c935 Giorgos Verigakis
        'refresh': settings.STATS_REFRESH_PERIOD,
700 5391d6b5 Giorgos Verigakis
        'cpuBar': settings.CPU_BAR_GRAPH_URL % secret,
701 5391d6b5 Giorgos Verigakis
        'cpuTimeSeries': settings.CPU_TIMESERIES_GRAPH_URL % secret,
702 5391d6b5 Giorgos Verigakis
        'netBar': settings.NET_BAR_GRAPH_URL % secret,
703 5391d6b5 Giorgos Verigakis
        'netTimeSeries': settings.NET_TIMESERIES_GRAPH_URL % secret}
704 ce55f211 Kostas Papadimitriou
705 c738c935 Giorgos Verigakis
    if request.serialization == 'xml':
706 c738c935 Giorgos Verigakis
        data = render_to_string('server_stats.xml', stats)
707 c738c935 Giorgos Verigakis
    else:
708 c738c935 Giorgos Verigakis
        data = json.dumps({'stats': stats})
709 c738c935 Giorgos Verigakis
710 c738c935 Giorgos Verigakis
    return HttpResponse(data, status=200)
711 41a7fae7 Christos Stavrakakis
712 41a7fae7 Christos Stavrakakis
713 41a7fae7 Christos Stavrakakis
# ACTIONS
714 41a7fae7 Christos Stavrakakis
715 41a7fae7 Christos Stavrakakis
716 41a7fae7 Christos Stavrakakis
server_actions = {}
717 41a7fae7 Christos Stavrakakis
network_actions = {}
718 41a7fae7 Christos Stavrakakis
719 41a7fae7 Christos Stavrakakis
720 41a7fae7 Christos Stavrakakis
def server_action(name):
721 41a7fae7 Christos Stavrakakis
    '''Decorator for functions implementing server actions.
722 41a7fae7 Christos Stavrakakis
    `name` is the key in the dict passed by the client.
723 41a7fae7 Christos Stavrakakis
    '''
724 41a7fae7 Christos Stavrakakis
725 41a7fae7 Christos Stavrakakis
    def decorator(func):
726 41a7fae7 Christos Stavrakakis
        server_actions[name] = func
727 41a7fae7 Christos Stavrakakis
        return func
728 41a7fae7 Christos Stavrakakis
    return decorator
729 41a7fae7 Christos Stavrakakis
730 41a7fae7 Christos Stavrakakis
731 41a7fae7 Christos Stavrakakis
def network_action(name):
732 41a7fae7 Christos Stavrakakis
    '''Decorator for functions implementing network actions.
733 41a7fae7 Christos Stavrakakis
    `name` is the key in the dict passed by the client.
734 41a7fae7 Christos Stavrakakis
    '''
735 41a7fae7 Christos Stavrakakis
736 41a7fae7 Christos Stavrakakis
    def decorator(func):
737 41a7fae7 Christos Stavrakakis
        network_actions[name] = func
738 41a7fae7 Christos Stavrakakis
        return func
739 41a7fae7 Christos Stavrakakis
    return decorator
740 41a7fae7 Christos Stavrakakis
741 41a7fae7 Christos Stavrakakis
742 41a7fae7 Christos Stavrakakis
@server_action('start')
743 41a7fae7 Christos Stavrakakis
def start(request, vm, args):
744 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 202
745 41a7fae7 Christos Stavrakakis
    # Error Response Codes: serviceUnavailable (503),
746 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404)
747 41a7fae7 Christos Stavrakakis
    vm = servers.start(vm)
748 41a7fae7 Christos Stavrakakis
    return HttpResponse(status=202)
749 41a7fae7 Christos Stavrakakis
750 41a7fae7 Christos Stavrakakis
751 41a7fae7 Christos Stavrakakis
@server_action('shutdown')
752 41a7fae7 Christos Stavrakakis
def shutdown(request, vm, args):
753 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 202
754 41a7fae7 Christos Stavrakakis
    # Error Response Codes: serviceUnavailable (503),
755 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404)
756 41a7fae7 Christos Stavrakakis
    vm = servers.stop(vm)
757 41a7fae7 Christos Stavrakakis
    return HttpResponse(status=202)
758 41a7fae7 Christos Stavrakakis
759 41a7fae7 Christos Stavrakakis
760 41a7fae7 Christos Stavrakakis
@server_action('reboot')
761 41a7fae7 Christos Stavrakakis
def reboot(request, vm, args):
762 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 202
763 41a7fae7 Christos Stavrakakis
    # Error Response Codes: computeFault (400, 500),
764 41a7fae7 Christos Stavrakakis
    #                       serviceUnavailable (503),
765 41a7fae7 Christos Stavrakakis
    #                       unauthorized (401),
766 41a7fae7 Christos Stavrakakis
    #                       badRequest (400),
767 41a7fae7 Christos Stavrakakis
    #                       badMediaType(415),
768 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404),
769 41a7fae7 Christos Stavrakakis
    #                       buildInProgress (409),
770 41a7fae7 Christos Stavrakakis
    #                       overLimit (413)
771 41a7fae7 Christos Stavrakakis
772 bbae3e45 Christos Stavrakakis
    reboot_type = args.get("type", "SOFT")
773 bbae3e45 Christos Stavrakakis
    if reboot_type not in ["SOFT", "HARD"]:
774 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Invalid 'type' attribute.")
775 41a7fae7 Christos Stavrakakis
    vm = servers.reboot(vm, reboot_type=reboot_type)
776 41a7fae7 Christos Stavrakakis
    return HttpResponse(status=202)
777 41a7fae7 Christos Stavrakakis
778 41a7fae7 Christos Stavrakakis
779 41a7fae7 Christos Stavrakakis
@server_action('firewallProfile')
780 41a7fae7 Christos Stavrakakis
def set_firewall_profile(request, vm, args):
781 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 200
782 41a7fae7 Christos Stavrakakis
    # Error Response Codes: computeFault (400, 500),
783 41a7fae7 Christos Stavrakakis
    #                       serviceUnavailable (503),
784 41a7fae7 Christos Stavrakakis
    #                       unauthorized (401),
785 41a7fae7 Christos Stavrakakis
    #                       badRequest (400),
786 41a7fae7 Christos Stavrakakis
    #                       badMediaType(415),
787 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404),
788 41a7fae7 Christos Stavrakakis
    #                       buildInProgress (409),
789 41a7fae7 Christos Stavrakakis
    #                       overLimit (413)
790 41a7fae7 Christos Stavrakakis
    profile = args.get("profile")
791 41a7fae7 Christos Stavrakakis
    if profile is None:
792 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Missing 'profile' attribute")
793 d0545590 Christos Stavrakakis
    nic_id = args.get("nic")
794 d0545590 Christos Stavrakakis
    if nic_id is None:
795 d0545590 Christos Stavrakakis
        raise faults.BadRequest("Missing 'nic' attribute")
796 c988fcca Christos Stavrakakis
    nic = util.get_vm_nic(vm, nic_id)
797 d0545590 Christos Stavrakakis
    servers.set_firewall_profile(vm, profile=profile, nic=nic)
798 41a7fae7 Christos Stavrakakis
    return HttpResponse(status=202)
799 41a7fae7 Christos Stavrakakis
800 41a7fae7 Christos Stavrakakis
801 41a7fae7 Christos Stavrakakis
@server_action('resize')
802 41a7fae7 Christos Stavrakakis
def resize(request, vm, args):
803 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 202
804 41a7fae7 Christos Stavrakakis
    # Error Response Codes: computeFault (400, 500),
805 41a7fae7 Christos Stavrakakis
    #                       serviceUnavailable (503),
806 41a7fae7 Christos Stavrakakis
    #                       unauthorized (401),
807 41a7fae7 Christos Stavrakakis
    #                       badRequest (400),
808 41a7fae7 Christos Stavrakakis
    #                       badMediaType(415),
809 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404),
810 41a7fae7 Christos Stavrakakis
    #                       buildInProgress (409),
811 41a7fae7 Christos Stavrakakis
    #                       serverCapacityUnavailable (503),
812 41a7fae7 Christos Stavrakakis
    #                       overLimit (413),
813 41a7fae7 Christos Stavrakakis
    #                       resizeNotAllowed (403)
814 41a7fae7 Christos Stavrakakis
    flavorRef = args.get("flavorRef")
815 41a7fae7 Christos Stavrakakis
    if flavorRef is None:
816 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Missing 'flavorRef' attribute.")
817 41a7fae7 Christos Stavrakakis
    flavor = util.get_flavor(flavor_id=flavorRef, include_deleted=False)
818 41a7fae7 Christos Stavrakakis
    servers.resize(vm, flavor=flavor)
819 41a7fae7 Christos Stavrakakis
    return HttpResponse(status=202)
820 41a7fae7 Christos Stavrakakis
821 41a7fae7 Christos Stavrakakis
822 41a7fae7 Christos Stavrakakis
@server_action('console')
823 41a7fae7 Christos Stavrakakis
def get_console(request, vm, args):
824 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 200
825 41a7fae7 Christos Stavrakakis
    # Error Response Codes: computeFault (400, 500),
826 41a7fae7 Christos Stavrakakis
    #                       serviceUnavailable (503),
827 41a7fae7 Christos Stavrakakis
    #                       unauthorized (401),
828 41a7fae7 Christos Stavrakakis
    #                       badRequest (400),
829 41a7fae7 Christos Stavrakakis
    #                       badMediaType(415),
830 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404),
831 41a7fae7 Christos Stavrakakis
    #                       buildInProgress (409),
832 41a7fae7 Christos Stavrakakis
    #                       overLimit (413)
833 41a7fae7 Christos Stavrakakis
834 41a7fae7 Christos Stavrakakis
    log.info("Get console  VM %s: %s", vm, args)
835 41a7fae7 Christos Stavrakakis
836 41a7fae7 Christos Stavrakakis
    console_type = args.get("type")
837 41a7fae7 Christos Stavrakakis
    if console_type is None:
838 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("No console 'type' specified.")
839 41a7fae7 Christos Stavrakakis
    elif console_type != "vnc":
840 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Console 'type' can only be 'vnc'.")
841 41a7fae7 Christos Stavrakakis
    console_info = servers.console(vm, console_type)
842 41a7fae7 Christos Stavrakakis
843 41a7fae7 Christos Stavrakakis
    if request.serialization == 'xml':
844 41a7fae7 Christos Stavrakakis
        mimetype = 'application/xml'
845 41a7fae7 Christos Stavrakakis
        data = render_to_string('console.xml', {'console': console_info})
846 41a7fae7 Christos Stavrakakis
    else:
847 41a7fae7 Christos Stavrakakis
        mimetype = 'application/json'
848 41a7fae7 Christos Stavrakakis
        data = json.dumps({'console': console_info})
849 41a7fae7 Christos Stavrakakis
850 41a7fae7 Christos Stavrakakis
    return HttpResponse(data, mimetype=mimetype, status=200)
851 41a7fae7 Christos Stavrakakis
852 41a7fae7 Christos Stavrakakis
853 41a7fae7 Christos Stavrakakis
@server_action('changePassword')
854 41a7fae7 Christos Stavrakakis
def change_password(request, vm, args):
855 41a7fae7 Christos Stavrakakis
    raise faults.NotImplemented('Changing password is not supported.')
856 41a7fae7 Christos Stavrakakis
857 41a7fae7 Christos Stavrakakis
858 41a7fae7 Christos Stavrakakis
@server_action('rebuild')
859 41a7fae7 Christos Stavrakakis
def rebuild(request, vm, args):
860 41a7fae7 Christos Stavrakakis
    raise faults.NotImplemented('Rebuild not supported.')
861 41a7fae7 Christos Stavrakakis
862 41a7fae7 Christos Stavrakakis
863 41a7fae7 Christos Stavrakakis
@server_action('confirmResize')
864 41a7fae7 Christos Stavrakakis
def confirm_resize(request, vm, args):
865 41a7fae7 Christos Stavrakakis
    raise faults.NotImplemented('Resize not supported.')
866 41a7fae7 Christos Stavrakakis
867 41a7fae7 Christos Stavrakakis
868 41a7fae7 Christos Stavrakakis
@server_action('revertResize')
869 41a7fae7 Christos Stavrakakis
def revert_resize(request, vm, args):
870 41a7fae7 Christos Stavrakakis
    raise faults.NotImplemented('Resize not supported.')
871 41a7fae7 Christos Stavrakakis
872 41a7fae7 Christos Stavrakakis
873 41a7fae7 Christos Stavrakakis
@network_action('add')
874 41a7fae7 Christos Stavrakakis
@transaction.commit_on_success
875 41a7fae7 Christos Stavrakakis
def add(request, net, args):
876 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 202
877 41a7fae7 Christos Stavrakakis
    # Error Response Codes: computeFault (400, 500),
878 41a7fae7 Christos Stavrakakis
    #                       serviceUnavailable (503),
879 41a7fae7 Christos Stavrakakis
    #                       unauthorized (401),
880 41a7fae7 Christos Stavrakakis
    #                       badRequest (400),
881 41a7fae7 Christos Stavrakakis
    #                       buildInProgress (409),
882 41a7fae7 Christos Stavrakakis
    #                       badMediaType(415),
883 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404),
884 41a7fae7 Christos Stavrakakis
    #                       overLimit (413)
885 41a7fae7 Christos Stavrakakis
    server_id = args.get('serverRef', None)
886 41a7fae7 Christos Stavrakakis
    if not server_id:
887 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest('Malformed Request.')
888 41a7fae7 Christos Stavrakakis
889 41a7fae7 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
890 41a7fae7 Christos Stavrakakis
    servers.connect(vm, network=net)
891 41a7fae7 Christos Stavrakakis
    return HttpResponse(status=202)
892 41a7fae7 Christos Stavrakakis
893 41a7fae7 Christos Stavrakakis
894 41a7fae7 Christos Stavrakakis
@network_action('remove')
895 41a7fae7 Christos Stavrakakis
@transaction.commit_on_success
896 41a7fae7 Christos Stavrakakis
def remove(request, net, args):
897 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 202
898 41a7fae7 Christos Stavrakakis
    # Error Response Codes: computeFault (400, 500),
899 41a7fae7 Christos Stavrakakis
    #                       serviceUnavailable (503),
900 41a7fae7 Christos Stavrakakis
    #                       unauthorized (401),
901 41a7fae7 Christos Stavrakakis
    #                       badRequest (400),
902 41a7fae7 Christos Stavrakakis
    #                       badMediaType(415),
903 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404),
904 41a7fae7 Christos Stavrakakis
    #                       overLimit (413)
905 41a7fae7 Christos Stavrakakis
906 41a7fae7 Christos Stavrakakis
    attachment = args.get("attachment")
907 41a7fae7 Christos Stavrakakis
    if attachment is None:
908 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Missing 'attachment' attribute.")
909 41a7fae7 Christos Stavrakakis
    try:
910 c988fcca Christos Stavrakakis
        nic_id = int(attachment)
911 41a7fae7 Christos Stavrakakis
    except (ValueError, TypeError):
912 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Invalid 'attachment' attribute.")
913 41a7fae7 Christos Stavrakakis
914 c988fcca Christos Stavrakakis
    nic = util.get_nic(nic_id=nic_id)
915 c988fcca Christos Stavrakakis
    server_id = nic.machine_id
916 41a7fae7 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
917 c988fcca Christos Stavrakakis
918 7c714455 Christos Stavrakakis
    servers.disconnect(vm, nic)
919 41a7fae7 Christos Stavrakakis
920 41a7fae7 Christos Stavrakakis
    return HttpResponse(status=202)
921 9ba6bb95 Christos Stavrakakis
922 9ba6bb95 Christos Stavrakakis
923 f8675683 Christos Stavrakakis
@server_action("addFloatingIp")
924 9ba6bb95 Christos Stavrakakis
def add_floating_ip(request, vm, args):
925 9ba6bb95 Christos Stavrakakis
    address = args.get("address")
926 9ba6bb95 Christos Stavrakakis
    if address is None:
927 9ba6bb95 Christos Stavrakakis
        raise faults.BadRequest("Missing 'address' attribute")
928 9ba6bb95 Christos Stavrakakis
929 fae6e5f0 Christos Stavrakakis
    userid = vm.userid
930 fae6e5f0 Christos Stavrakakis
    floating_ip = util.get_floating_ip_by_address(userid, address,
931 fae6e5f0 Christos Stavrakakis
                                                  for_update=True)
932 fae6e5f0 Christos Stavrakakis
    servers.create_port(userid, floating_ip.network, machine=vm,
933 fae6e5f0 Christos Stavrakakis
                        user_ipaddress=floating_ip)
934 9ba6bb95 Christos Stavrakakis
    return HttpResponse(status=202)
935 9ba6bb95 Christos Stavrakakis
936 9ba6bb95 Christos Stavrakakis
937 f8675683 Christos Stavrakakis
@server_action("removeFloatingIp")
938 9ba6bb95 Christos Stavrakakis
def remove_floating_ip(request, vm, args):
939 9ba6bb95 Christos Stavrakakis
    address = args.get("address")
940 9ba6bb95 Christos Stavrakakis
    if address is None:
941 9ba6bb95 Christos Stavrakakis
        raise faults.BadRequest("Missing 'address' attribute")
942 fae6e5f0 Christos Stavrakakis
    floating_ip = util.get_floating_ip_by_address(vm.userid, address,
943 fae6e5f0 Christos Stavrakakis
                                                  for_update=True)
944 fae6e5f0 Christos Stavrakakis
    if floating_ip.nic is None:
945 fae6e5f0 Christos Stavrakakis
        raise faults.BadRequest("Floating IP %s not attached to instance"
946 fae6e5f0 Christos Stavrakakis
                                % address)
947 fae6e5f0 Christos Stavrakakis
    servers.delete_port(floating_ip.nic)
948 9ba6bb95 Christos Stavrakakis
    return HttpResponse(status=202)