Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (33.5 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 2aba7764 Sofia Papagiannaki
        return api.api_method_not_allowed(request,
74 2aba7764 Sofia Papagiannaki
                                          allowed_methods=['GET', 'POST'])
75 7e2f9d4b Giorgos Verigakis
76 55cd40be Vangelis Koukis
77 7e2f9d4b Giorgos Verigakis
def server_demux(request, server_id):
78 7e2f9d4b Giorgos Verigakis
    if request.method == 'GET':
79 7e2f9d4b Giorgos Verigakis
        return get_server_details(request, server_id)
80 7e2f9d4b Giorgos Verigakis
    elif request.method == 'PUT':
81 7e2f9d4b Giorgos Verigakis
        return update_server_name(request, server_id)
82 7e2f9d4b Giorgos Verigakis
    elif request.method == 'DELETE':
83 7e2f9d4b Giorgos Verigakis
        return delete_server(request, server_id)
84 7e2f9d4b Giorgos Verigakis
    else:
85 2aba7764 Sofia Papagiannaki
        return api.api_method_not_allowed(request,
86 2aba7764 Sofia Papagiannaki
                                          allowed_methods=['GET',
87 2aba7764 Sofia Papagiannaki
                                                           'PUT',
88 2aba7764 Sofia Papagiannaki
                                                           'DELETE'])
89 d8e50a39 Giorgos Verigakis
90 55cd40be Vangelis Koukis
91 d8e50a39 Giorgos Verigakis
def metadata_demux(request, server_id):
92 d8e50a39 Giorgos Verigakis
    if request.method == 'GET':
93 d8e50a39 Giorgos Verigakis
        return list_metadata(request, server_id)
94 d8e50a39 Giorgos Verigakis
    elif request.method == 'POST':
95 d8e50a39 Giorgos Verigakis
        return update_metadata(request, server_id)
96 d8e50a39 Giorgos Verigakis
    else:
97 2aba7764 Sofia Papagiannaki
        return api.api_method_not_allowed(request,
98 2aba7764 Sofia Papagiannaki
                                          allowed_methods=['GET', 'POST'])
99 d8e50a39 Giorgos Verigakis
100 55cd40be Vangelis Koukis
101 d8e50a39 Giorgos Verigakis
def metadata_item_demux(request, server_id, key):
102 d8e50a39 Giorgos Verigakis
    if request.method == 'GET':
103 d8e50a39 Giorgos Verigakis
        return get_metadata_item(request, server_id, key)
104 d8e50a39 Giorgos Verigakis
    elif request.method == 'PUT':
105 d8e50a39 Giorgos Verigakis
        return create_metadata_item(request, server_id, key)
106 d8e50a39 Giorgos Verigakis
    elif request.method == 'DELETE':
107 d8e50a39 Giorgos Verigakis
        return delete_metadata_item(request, server_id, key)
108 d8e50a39 Giorgos Verigakis
    else:
109 2aba7764 Sofia Papagiannaki
        return api.api_method_not_allowed(request,
110 2aba7764 Sofia Papagiannaki
                                          allowed_methods=['GET',
111 2aba7764 Sofia Papagiannaki
                                                           'PUT',
112 2aba7764 Sofia Papagiannaki
                                                           'DELETE'])
113 7e2f9d4b Giorgos Verigakis
114 08b079e2 Stavros Sachtouris
115 b3a43976 Christos Stavrakakis
def nic_to_attachments(nic):
116 b3a43976 Christos Stavrakakis
    """Convert a NIC object to 'attachments attribute.
117 b3a43976 Christos Stavrakakis

118 b3a43976 Christos Stavrakakis
    Convert a NIC object to match the format of 'attachments' attribute of the
119 b3a43976 Christos Stavrakakis
    response to the /servers API call.
120 b3a43976 Christos Stavrakakis

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

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

150 b3a43976 Christos Stavrakakis
    Convert a a list of 'attachments' attribute to a list of 'addresses'
151 b3a43976 Christos Stavrakakis
    attribute, as expected in the response to /servers API call.
152 b3a43976 Christos Stavrakakis

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

220 b3a43976 Christos Stavrakakis
    NOTE: 'vm_nics' objects have prefetched the ips
221 b3a43976 Christos Stavrakakis
    """
222 734acd05 Christos Stavrakakis
    for nic in vm_nics:
223 734acd05 Christos Stavrakakis
        for ip in nic.ips.all():
224 734acd05 Christos Stavrakakis
            if ip.ipversion == version and ip.public:
225 734acd05 Christos Stavrakakis
                return ip
226 b3a43976 Christos Stavrakakis
    return None
227 b3a43976 Christos Stavrakakis
228 b3a43976 Christos Stavrakakis
229 b3a43976 Christos Stavrakakis
def get_server_fqdn(vm, vm_nics):
230 d328a525 Christos Stavrakakis
    fqdn_setting = settings.CYCLADES_SERVERS_FQDN
231 d328a525 Christos Stavrakakis
    if fqdn_setting is None:
232 9cec0c17 Christos Stavrakakis
        return None
233 d328a525 Christos Stavrakakis
    elif isinstance(fqdn_setting, basestring):
234 d328a525 Christos Stavrakakis
        return fqdn_setting % {"id": vm.id}
235 d328a525 Christos Stavrakakis
    else:
236 d328a525 Christos Stavrakakis
        msg = ("Invalid setting: CYCLADES_SERVERS_FQDN."
237 d328a525 Christos Stavrakakis
               " Value must be a string.")
238 d328a525 Christos Stavrakakis
        raise faults.InternalServerError(msg)
239 d328a525 Christos Stavrakakis
240 d328a525 Christos Stavrakakis
241 b3a43976 Christos Stavrakakis
def get_server_port_forwarding(vm, vm_nics, fqdn):
242 2522e489 Christos Stavrakakis
    """Create API 'port_forwarding' attribute from corresponding setting.
243 2522e489 Christos Stavrakakis

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

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