Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (33.9 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 47c27955 Giorgos Korfiatis
        project = server.get("project")
389 bcd80cd9 Christos Stavrakakis
    except (KeyError, AssertionError):
390 bcd80cd9 Christos Stavrakakis
        raise faults.BadRequest("Malformed request")
391 bcd80cd9 Christos Stavrakakis
392 bcd80cd9 Christos Stavrakakis
    # Verify that personalities are well-formed
393 bcd80cd9 Christos Stavrakakis
    util.verify_personality(personality)
394 bcd80cd9 Christos Stavrakakis
    # Get image information
395 bcd80cd9 Christos Stavrakakis
    image = util.get_image_dict(image_id, user_id)
396 bcd80cd9 Christos Stavrakakis
    # Get flavor (ensure it is active)
397 bcd80cd9 Christos Stavrakakis
    flavor = util.get_flavor(flavor_id, include_deleted=False)
398 62b76f38 Christos Stavrakakis
    if not flavor.allow_create:
399 62b76f38 Christos Stavrakakis
        msg = ("It is not allowed to create a server from flavor with id '%d',"
400 62b76f38 Christos Stavrakakis
               " see 'allow_create' flavor attribute")
401 62b76f38 Christos Stavrakakis
        raise faults.Forbidden(msg % flavor.id)
402 bcd80cd9 Christos Stavrakakis
    # Generate password
403 bcd80cd9 Christos Stavrakakis
    password = util.random_password()
404 bcd80cd9 Christos Stavrakakis
405 41a7fae7 Christos Stavrakakis
    vm = servers.create(user_id, name, password, flavor, image,
406 cb66110b Christos Stavrakakis
                        metadata=metadata, personality=personality,
407 47c27955 Giorgos Korfiatis
                        project=project, networks=networks)
408 bcd80cd9 Christos Stavrakakis
409 bcd80cd9 Christos Stavrakakis
    server = vm_to_dict(vm, detail=True)
410 bcd80cd9 Christos Stavrakakis
    server['status'] = 'BUILD'
411 bcd80cd9 Christos Stavrakakis
    server['adminPass'] = password
412 bcd80cd9 Christos Stavrakakis
413 bcd80cd9 Christos Stavrakakis
    response = render_server(request, server, status=202)
414 4b8e03e5 Christos Stavrakakis
415 bcd80cd9 Christos Stavrakakis
    return response
416 bcd80cd9 Christos Stavrakakis
417 bcd80cd9 Christos Stavrakakis
418 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
419 7e2f9d4b Giorgos Verigakis
def get_server_details(request, server_id):
420 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 200, 203
421 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
422 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
423 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
424 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
425 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
426 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
427 ce55f211 Kostas Papadimitriou
428 0c37a721 Christos Stavrakakis
    log.debug('get_server_details %s', server_id)
429 b3a43976 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq,
430 b3a43976 Christos Stavrakakis
                     prefetch_related="nics__ips")
431 d8e50a39 Giorgos Verigakis
    server = vm_to_dict(vm, detail=True)
432 d8e50a39 Giorgos Verigakis
    return render_server(request, server)
433 7e2f9d4b Giorgos Verigakis
434 55cd40be Vangelis Koukis
435 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='PUT', user_required=True, logger=log)
436 874383a4 Christos Stavrakakis
@transaction.commit_on_success
437 c36934a7 Giorgos Verigakis
def update_server_name(request, server_id):
438 c36934a7 Giorgos Verigakis
    # Normal Response Code: 204
439 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
440 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
441 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
442 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
443 c36934a7 Giorgos Verigakis
    #                       badMediaType(415),
444 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
445 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
446 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
447 aa197ee4 Vangelis Koukis
448 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
449 bf5c82dc Christos Stavrakakis
    log.info('update_server_name %s %s', server_id, req)
450 ce55f211 Kostas Papadimitriou
451 14402edc Christos Stavrakakis
    req = utils.get_attribute(req, "server", attr_type=dict, required=True)
452 14402edc Christos Stavrakakis
    name = utils.get_attribute(req, "name", attr_type=basestring,
453 14402edc Christos Stavrakakis
                               required=True)
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 14402edc Christos Stavrakakis
    if not isinstance(req, dict) and 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 14402edc Christos Stavrakakis
    if not isinstance(action, basestring):
512 14402edc Christos Stavrakakis
        raise faults.BadRequest("Malformed Request. Invalid action.")
513 7f2dbcad Christos Stavrakakis
514 41a7fae7 Christos Stavrakakis
    if key_to_action(action) not in [x[0] for x in VirtualMachine.ACTIONS]:
515 41a7fae7 Christos Stavrakakis
        if action not in ARBITRARY_ACTIONS:
516 41a7fae7 Christos Stavrakakis
            raise faults.BadRequest("Action %s not supported" % action)
517 14402edc Christos Stavrakakis
    action_args = utils.get_attribute(req, action, required=True,
518 14402edc Christos Stavrakakis
                                      attr_type=dict)
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 14402edc Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq,
534 14402edc Christos Stavrakakis
                     prefetch_related="nics__ips")
535 b3a43976 Christos Stavrakakis
    attachments = [nic_to_attachments(nic)
536 b3a43976 Christos Stavrakakis
                   for nic in vm.nics.filter(state="ACTIVE")]
537 78c165cf Christos Stavrakakis
    addresses = attachments_to_addresses(attachments)
538 ce55f211 Kostas Papadimitriou
539 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
540 b016b476 Giorgos Verigakis
        data = render_to_string('list_addresses.xml', {'addresses': addresses})
541 b016b476 Giorgos Verigakis
    else:
542 1f638a85 Christos Stavrakakis
        data = json.dumps({'addresses': addresses, 'attachments': attachments})
543 aa197ee4 Vangelis Koukis
544 b016b476 Giorgos Verigakis
    return HttpResponse(data, status=200)
545 b016b476 Giorgos Verigakis
546 55cd40be Vangelis Koukis
547 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
548 b016b476 Giorgos Verigakis
def list_addresses_by_network(request, server_id, network_id):
549 b016b476 Giorgos Verigakis
    # Normal Response Codes: 200, 203
550 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
551 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
552 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
553 b016b476 Giorgos Verigakis
    #                       badRequest (400),
554 b016b476 Giorgos Verigakis
    #                       itemNotFound (404),
555 b016b476 Giorgos Verigakis
    #                       overLimit (413)
556 ce55f211 Kostas Papadimitriou
557 0c37a721 Christos Stavrakakis
    log.debug('list_addresses_by_network %s %s', server_id, network_id)
558 4b3b8688 Giorgos Verigakis
    machine = util.get_vm(server_id, request.user_uniq)
559 4b3b8688 Giorgos Verigakis
    network = util.get_network(network_id, request.user_uniq)
560 7c714455 Christos Stavrakakis
    nics = machine.nics.filter(network=network, state="ACTIVE")
561 b3a43976 Christos Stavrakakis
    addresses = attachments_to_addresses(map(nic_to_attachments, nics))
562 ce55f211 Kostas Papadimitriou
563 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
564 1f638a85 Christos Stavrakakis
        data = render_to_string('address.xml', {'addresses': addresses})
565 b016b476 Giorgos Verigakis
    else:
566 1f638a85 Christos Stavrakakis
        data = json.dumps({'network': addresses})
567 aa197ee4 Vangelis Koukis
568 b016b476 Giorgos Verigakis
    return HttpResponse(data, status=200)
569 d8e50a39 Giorgos Verigakis
570 55cd40be Vangelis Koukis
571 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
572 d8e50a39 Giorgos Verigakis
def list_metadata(request, server_id):
573 d8e50a39 Giorgos Verigakis
    # Normal Response Codes: 200, 203
574 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
575 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
576 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
577 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
578 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
579 ce55f211 Kostas Papadimitriou
580 0c37a721 Christos Stavrakakis
    log.debug('list_server_metadata %s', server_id)
581 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
582 7cc3c7d9 Giorgos Verigakis
    metadata = dict((m.meta_key, m.meta_value) for m in vm.metadata.all())
583 5029ff36 Christos Stavrakakis
    return util.render_metadata(request, metadata, use_values=False,
584 5029ff36 Christos Stavrakakis
                                status=200)
585 d8e50a39 Giorgos Verigakis
586 55cd40be Vangelis Koukis
587 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='POST', user_required=True, logger=log)
588 874383a4 Christos Stavrakakis
@transaction.commit_on_success
589 d8e50a39 Giorgos Verigakis
def update_metadata(request, server_id):
590 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 201
591 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
592 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
593 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
594 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
595 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
596 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
597 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
598 ce55f211 Kostas Papadimitriou
599 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
600 bf5c82dc Christos Stavrakakis
    log.info('update_server_metadata %s %s', server_id, req)
601 e221ade2 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
602 14402edc Christos Stavrakakis
    metadata = utils.get_attribute(req, "metadata", required=True,
603 14402edc Christos Stavrakakis
                                   attr_type=dict)
604 ce55f211 Kostas Papadimitriou
605 7cc3c7d9 Giorgos Verigakis
    for key, val in metadata.items():
606 14402edc Christos Stavrakakis
        if not isinstance(key, (basestring, int)) or\
607 14402edc Christos Stavrakakis
           not isinstance(val, (basestring, int)):
608 14402edc Christos Stavrakakis
            raise faults.BadRequest("Malformed Request. Invalid metadata.")
609 7cc3c7d9 Giorgos Verigakis
        meta, created = vm.metadata.get_or_create(meta_key=key)
610 7cc3c7d9 Giorgos Verigakis
        meta.meta_value = val
611 7cc3c7d9 Giorgos Verigakis
        meta.save()
612 ce55f211 Kostas Papadimitriou
613 7cc3c7d9 Giorgos Verigakis
    vm.save()
614 7cc3c7d9 Giorgos Verigakis
    vm_meta = dict((m.meta_key, m.meta_value) for m in vm.metadata.all())
615 7cc3c7d9 Giorgos Verigakis
    return util.render_metadata(request, vm_meta, status=201)
616 d8e50a39 Giorgos Verigakis
617 55cd40be Vangelis Koukis
618 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
619 d8e50a39 Giorgos Verigakis
def get_metadata_item(request, server_id, key):
620 d8e50a39 Giorgos Verigakis
    # Normal Response Codes: 200, 203
621 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
622 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
623 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
624 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
625 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
626 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
627 ce55f211 Kostas Papadimitriou
628 0c37a721 Christos Stavrakakis
    log.debug('get_server_metadata_item %s %s', server_id, key)
629 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
630 b36f78fa Giorgos Verigakis
    meta = util.get_vm_meta(vm, key)
631 62b894c0 Giorgos Verigakis
    d = {meta.meta_key: meta.meta_value}
632 62b894c0 Giorgos Verigakis
    return util.render_meta(request, d, status=200)
633 d8e50a39 Giorgos Verigakis
634 55cd40be Vangelis Koukis
635 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='PUT', user_required=True, logger=log)
636 4dba0480 Christos Stavrakakis
@transaction.commit_on_success
637 d8e50a39 Giorgos Verigakis
def create_metadata_item(request, server_id, key):
638 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 201
639 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
640 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
641 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
642 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
643 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
644 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
645 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
646 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
647 ce55f211 Kostas Papadimitriou
648 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
649 bf5c82dc Christos Stavrakakis
    log.info('create_server_metadata_item %s %s %s', server_id, key, req)
650 e221ade2 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
651 d8e50a39 Giorgos Verigakis
    try:
652 d8e50a39 Giorgos Verigakis
        metadict = req['meta']
653 d8e50a39 Giorgos Verigakis
        assert isinstance(metadict, dict)
654 d8e50a39 Giorgos Verigakis
        assert len(metadict) == 1
655 d8e50a39 Giorgos Verigakis
        assert key in metadict
656 d8e50a39 Giorgos Verigakis
    except (KeyError, AssertionError):
657 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
658 ce55f211 Kostas Papadimitriou
659 b36f78fa Giorgos Verigakis
    meta, created = VirtualMachineMetadata.objects.get_or_create(
660 b36f78fa Giorgos Verigakis
        meta_key=key,
661 b36f78fa Giorgos Verigakis
        vm=vm)
662 ce55f211 Kostas Papadimitriou
663 d8e50a39 Giorgos Verigakis
    meta.meta_value = metadict[key]
664 d8e50a39 Giorgos Verigakis
    meta.save()
665 5509b599 Giorgos Verigakis
    vm.save()
666 62b894c0 Giorgos Verigakis
    d = {meta.meta_key: meta.meta_value}
667 62b894c0 Giorgos Verigakis
    return util.render_meta(request, d, status=201)
668 d8e50a39 Giorgos Verigakis
669 55cd40be Vangelis Koukis
670 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='DELETE', user_required=True, logger=log)
671 4dba0480 Christos Stavrakakis
@transaction.commit_on_success
672 d8e50a39 Giorgos Verigakis
def delete_metadata_item(request, server_id, key):
673 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 204
674 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
675 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
676 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
677 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
678 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
679 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
680 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
681 d8e50a39 Giorgos Verigakis
    #                       overLimit (413),
682 ce55f211 Kostas Papadimitriou
683 bf5c82dc Christos Stavrakakis
    log.info('delete_server_metadata_item %s %s', server_id, key)
684 e221ade2 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
685 b36f78fa Giorgos Verigakis
    meta = util.get_vm_meta(vm, key)
686 d8e50a39 Giorgos Verigakis
    meta.delete()
687 5509b599 Giorgos Verigakis
    vm.save()
688 d8e50a39 Giorgos Verigakis
    return HttpResponse(status=204)
689 c738c935 Giorgos Verigakis
690 55cd40be Vangelis Koukis
691 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
692 c738c935 Giorgos Verigakis
def server_stats(request, server_id):
693 c738c935 Giorgos Verigakis
    # Normal Response Codes: 200
694 c738c935 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
695 c738c935 Giorgos Verigakis
    #                       serviceUnavailable (503),
696 c738c935 Giorgos Verigakis
    #                       unauthorized (401),
697 c738c935 Giorgos Verigakis
    #                       badRequest (400),
698 c738c935 Giorgos Verigakis
    #                       itemNotFound (404),
699 c738c935 Giorgos Verigakis
    #                       overLimit (413)
700 ce55f211 Kostas Papadimitriou
701 0c37a721 Christos Stavrakakis
    log.debug('server_stats %s', server_id)
702 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
703 bd16bf3e Stratos Psomadakis
    secret = util.stats_encrypt(vm.backend_vm_id)
704 ce55f211 Kostas Papadimitriou
705 c738c935 Giorgos Verigakis
    stats = {
706 c738c935 Giorgos Verigakis
        'serverRef': vm.id,
707 c738c935 Giorgos Verigakis
        'refresh': settings.STATS_REFRESH_PERIOD,
708 5391d6b5 Giorgos Verigakis
        'cpuBar': settings.CPU_BAR_GRAPH_URL % secret,
709 5391d6b5 Giorgos Verigakis
        'cpuTimeSeries': settings.CPU_TIMESERIES_GRAPH_URL % secret,
710 5391d6b5 Giorgos Verigakis
        'netBar': settings.NET_BAR_GRAPH_URL % secret,
711 5391d6b5 Giorgos Verigakis
        'netTimeSeries': settings.NET_TIMESERIES_GRAPH_URL % secret}
712 ce55f211 Kostas Papadimitriou
713 c738c935 Giorgos Verigakis
    if request.serialization == 'xml':
714 c738c935 Giorgos Verigakis
        data = render_to_string('server_stats.xml', stats)
715 c738c935 Giorgos Verigakis
    else:
716 c738c935 Giorgos Verigakis
        data = json.dumps({'stats': stats})
717 c738c935 Giorgos Verigakis
718 c738c935 Giorgos Verigakis
    return HttpResponse(data, status=200)
719 41a7fae7 Christos Stavrakakis
720 41a7fae7 Christos Stavrakakis
721 41a7fae7 Christos Stavrakakis
# ACTIONS
722 41a7fae7 Christos Stavrakakis
723 41a7fae7 Christos Stavrakakis
724 41a7fae7 Christos Stavrakakis
server_actions = {}
725 41a7fae7 Christos Stavrakakis
network_actions = {}
726 41a7fae7 Christos Stavrakakis
727 41a7fae7 Christos Stavrakakis
728 41a7fae7 Christos Stavrakakis
def server_action(name):
729 41a7fae7 Christos Stavrakakis
    '''Decorator for functions implementing server actions.
730 41a7fae7 Christos Stavrakakis
    `name` is the key in the dict passed by the client.
731 41a7fae7 Christos Stavrakakis
    '''
732 41a7fae7 Christos Stavrakakis
733 41a7fae7 Christos Stavrakakis
    def decorator(func):
734 41a7fae7 Christos Stavrakakis
        server_actions[name] = func
735 41a7fae7 Christos Stavrakakis
        return func
736 41a7fae7 Christos Stavrakakis
    return decorator
737 41a7fae7 Christos Stavrakakis
738 41a7fae7 Christos Stavrakakis
739 41a7fae7 Christos Stavrakakis
def network_action(name):
740 41a7fae7 Christos Stavrakakis
    '''Decorator for functions implementing network actions.
741 41a7fae7 Christos Stavrakakis
    `name` is the key in the dict passed by the client.
742 41a7fae7 Christos Stavrakakis
    '''
743 41a7fae7 Christos Stavrakakis
744 41a7fae7 Christos Stavrakakis
    def decorator(func):
745 41a7fae7 Christos Stavrakakis
        network_actions[name] = func
746 41a7fae7 Christos Stavrakakis
        return func
747 41a7fae7 Christos Stavrakakis
    return decorator
748 41a7fae7 Christos Stavrakakis
749 41a7fae7 Christos Stavrakakis
750 41a7fae7 Christos Stavrakakis
@server_action('start')
751 41a7fae7 Christos Stavrakakis
def start(request, vm, args):
752 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 202
753 41a7fae7 Christos Stavrakakis
    # Error Response Codes: serviceUnavailable (503),
754 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404)
755 41a7fae7 Christos Stavrakakis
    vm = servers.start(vm)
756 41a7fae7 Christos Stavrakakis
    return HttpResponse(status=202)
757 41a7fae7 Christos Stavrakakis
758 41a7fae7 Christos Stavrakakis
759 41a7fae7 Christos Stavrakakis
@server_action('shutdown')
760 41a7fae7 Christos Stavrakakis
def shutdown(request, vm, args):
761 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 202
762 41a7fae7 Christos Stavrakakis
    # Error Response Codes: serviceUnavailable (503),
763 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404)
764 41a7fae7 Christos Stavrakakis
    vm = servers.stop(vm)
765 41a7fae7 Christos Stavrakakis
    return HttpResponse(status=202)
766 41a7fae7 Christos Stavrakakis
767 41a7fae7 Christos Stavrakakis
768 41a7fae7 Christos Stavrakakis
@server_action('reboot')
769 41a7fae7 Christos Stavrakakis
def reboot(request, vm, args):
770 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 202
771 41a7fae7 Christos Stavrakakis
    # Error Response Codes: computeFault (400, 500),
772 41a7fae7 Christos Stavrakakis
    #                       serviceUnavailable (503),
773 41a7fae7 Christos Stavrakakis
    #                       unauthorized (401),
774 41a7fae7 Christos Stavrakakis
    #                       badRequest (400),
775 41a7fae7 Christos Stavrakakis
    #                       badMediaType(415),
776 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404),
777 41a7fae7 Christos Stavrakakis
    #                       buildInProgress (409),
778 41a7fae7 Christos Stavrakakis
    #                       overLimit (413)
779 41a7fae7 Christos Stavrakakis
780 bbae3e45 Christos Stavrakakis
    reboot_type = args.get("type", "SOFT")
781 bbae3e45 Christos Stavrakakis
    if reboot_type not in ["SOFT", "HARD"]:
782 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Invalid 'type' attribute.")
783 41a7fae7 Christos Stavrakakis
    vm = servers.reboot(vm, reboot_type=reboot_type)
784 41a7fae7 Christos Stavrakakis
    return HttpResponse(status=202)
785 41a7fae7 Christos Stavrakakis
786 41a7fae7 Christos Stavrakakis
787 41a7fae7 Christos Stavrakakis
@server_action('firewallProfile')
788 41a7fae7 Christos Stavrakakis
def set_firewall_profile(request, vm, args):
789 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 200
790 41a7fae7 Christos Stavrakakis
    # Error Response Codes: computeFault (400, 500),
791 41a7fae7 Christos Stavrakakis
    #                       serviceUnavailable (503),
792 41a7fae7 Christos Stavrakakis
    #                       unauthorized (401),
793 41a7fae7 Christos Stavrakakis
    #                       badRequest (400),
794 41a7fae7 Christos Stavrakakis
    #                       badMediaType(415),
795 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404),
796 41a7fae7 Christos Stavrakakis
    #                       buildInProgress (409),
797 41a7fae7 Christos Stavrakakis
    #                       overLimit (413)
798 41a7fae7 Christos Stavrakakis
    profile = args.get("profile")
799 41a7fae7 Christos Stavrakakis
    if profile is None:
800 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Missing 'profile' attribute")
801 d0545590 Christos Stavrakakis
    nic_id = args.get("nic")
802 d0545590 Christos Stavrakakis
    if nic_id is None:
803 d0545590 Christos Stavrakakis
        raise faults.BadRequest("Missing 'nic' attribute")
804 c988fcca Christos Stavrakakis
    nic = util.get_vm_nic(vm, nic_id)
805 d0545590 Christos Stavrakakis
    servers.set_firewall_profile(vm, profile=profile, nic=nic)
806 41a7fae7 Christos Stavrakakis
    return HttpResponse(status=202)
807 41a7fae7 Christos Stavrakakis
808 41a7fae7 Christos Stavrakakis
809 41a7fae7 Christos Stavrakakis
@server_action('resize')
810 41a7fae7 Christos Stavrakakis
def resize(request, vm, args):
811 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 202
812 41a7fae7 Christos Stavrakakis
    # Error Response Codes: computeFault (400, 500),
813 41a7fae7 Christos Stavrakakis
    #                       serviceUnavailable (503),
814 41a7fae7 Christos Stavrakakis
    #                       unauthorized (401),
815 41a7fae7 Christos Stavrakakis
    #                       badRequest (400),
816 41a7fae7 Christos Stavrakakis
    #                       badMediaType(415),
817 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404),
818 41a7fae7 Christos Stavrakakis
    #                       buildInProgress (409),
819 41a7fae7 Christos Stavrakakis
    #                       serverCapacityUnavailable (503),
820 41a7fae7 Christos Stavrakakis
    #                       overLimit (413),
821 41a7fae7 Christos Stavrakakis
    #                       resizeNotAllowed (403)
822 41a7fae7 Christos Stavrakakis
    flavorRef = args.get("flavorRef")
823 41a7fae7 Christos Stavrakakis
    if flavorRef is None:
824 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Missing 'flavorRef' attribute.")
825 41a7fae7 Christos Stavrakakis
    flavor = util.get_flavor(flavor_id=flavorRef, include_deleted=False)
826 41a7fae7 Christos Stavrakakis
    servers.resize(vm, flavor=flavor)
827 41a7fae7 Christos Stavrakakis
    return HttpResponse(status=202)
828 41a7fae7 Christos Stavrakakis
829 41a7fae7 Christos Stavrakakis
830 41a7fae7 Christos Stavrakakis
@server_action('console')
831 41a7fae7 Christos Stavrakakis
def get_console(request, vm, args):
832 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 200
833 41a7fae7 Christos Stavrakakis
    # Error Response Codes: computeFault (400, 500),
834 41a7fae7 Christos Stavrakakis
    #                       serviceUnavailable (503),
835 41a7fae7 Christos Stavrakakis
    #                       unauthorized (401),
836 41a7fae7 Christos Stavrakakis
    #                       badRequest (400),
837 41a7fae7 Christos Stavrakakis
    #                       badMediaType(415),
838 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404),
839 41a7fae7 Christos Stavrakakis
    #                       buildInProgress (409),
840 41a7fae7 Christos Stavrakakis
    #                       overLimit (413)
841 41a7fae7 Christos Stavrakakis
842 41a7fae7 Christos Stavrakakis
    log.info("Get console  VM %s: %s", vm, args)
843 41a7fae7 Christos Stavrakakis
844 41a7fae7 Christos Stavrakakis
    console_type = args.get("type")
845 41a7fae7 Christos Stavrakakis
    if console_type is None:
846 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("No console 'type' specified.")
847 41a7fae7 Christos Stavrakakis
    elif console_type != "vnc":
848 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Console 'type' can only be 'vnc'.")
849 41a7fae7 Christos Stavrakakis
    console_info = servers.console(vm, console_type)
850 41a7fae7 Christos Stavrakakis
851 41a7fae7 Christos Stavrakakis
    if request.serialization == 'xml':
852 41a7fae7 Christos Stavrakakis
        mimetype = 'application/xml'
853 41a7fae7 Christos Stavrakakis
        data = render_to_string('console.xml', {'console': console_info})
854 41a7fae7 Christos Stavrakakis
    else:
855 41a7fae7 Christos Stavrakakis
        mimetype = 'application/json'
856 41a7fae7 Christos Stavrakakis
        data = json.dumps({'console': console_info})
857 41a7fae7 Christos Stavrakakis
858 41a7fae7 Christos Stavrakakis
    return HttpResponse(data, mimetype=mimetype, status=200)
859 41a7fae7 Christos Stavrakakis
860 41a7fae7 Christos Stavrakakis
861 41a7fae7 Christos Stavrakakis
@server_action('changePassword')
862 41a7fae7 Christos Stavrakakis
def change_password(request, vm, args):
863 41a7fae7 Christos Stavrakakis
    raise faults.NotImplemented('Changing password is not supported.')
864 41a7fae7 Christos Stavrakakis
865 41a7fae7 Christos Stavrakakis
866 41a7fae7 Christos Stavrakakis
@server_action('rebuild')
867 41a7fae7 Christos Stavrakakis
def rebuild(request, vm, args):
868 41a7fae7 Christos Stavrakakis
    raise faults.NotImplemented('Rebuild not supported.')
869 41a7fae7 Christos Stavrakakis
870 41a7fae7 Christos Stavrakakis
871 41a7fae7 Christos Stavrakakis
@server_action('confirmResize')
872 41a7fae7 Christos Stavrakakis
def confirm_resize(request, vm, args):
873 41a7fae7 Christos Stavrakakis
    raise faults.NotImplemented('Resize not supported.')
874 41a7fae7 Christos Stavrakakis
875 41a7fae7 Christos Stavrakakis
876 41a7fae7 Christos Stavrakakis
@server_action('revertResize')
877 41a7fae7 Christos Stavrakakis
def revert_resize(request, vm, args):
878 41a7fae7 Christos Stavrakakis
    raise faults.NotImplemented('Resize not supported.')
879 41a7fae7 Christos Stavrakakis
880 41a7fae7 Christos Stavrakakis
881 41a7fae7 Christos Stavrakakis
@network_action('add')
882 41a7fae7 Christos Stavrakakis
@transaction.commit_on_success
883 41a7fae7 Christos Stavrakakis
def add(request, net, args):
884 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 202
885 41a7fae7 Christos Stavrakakis
    # Error Response Codes: computeFault (400, 500),
886 41a7fae7 Christos Stavrakakis
    #                       serviceUnavailable (503),
887 41a7fae7 Christos Stavrakakis
    #                       unauthorized (401),
888 41a7fae7 Christos Stavrakakis
    #                       badRequest (400),
889 41a7fae7 Christos Stavrakakis
    #                       buildInProgress (409),
890 41a7fae7 Christos Stavrakakis
    #                       badMediaType(415),
891 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404),
892 41a7fae7 Christos Stavrakakis
    #                       overLimit (413)
893 41a7fae7 Christos Stavrakakis
    server_id = args.get('serverRef', None)
894 41a7fae7 Christos Stavrakakis
    if not server_id:
895 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest('Malformed Request.')
896 41a7fae7 Christos Stavrakakis
897 41a7fae7 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
898 41a7fae7 Christos Stavrakakis
    servers.connect(vm, network=net)
899 41a7fae7 Christos Stavrakakis
    return HttpResponse(status=202)
900 41a7fae7 Christos Stavrakakis
901 41a7fae7 Christos Stavrakakis
902 41a7fae7 Christos Stavrakakis
@network_action('remove')
903 41a7fae7 Christos Stavrakakis
@transaction.commit_on_success
904 41a7fae7 Christos Stavrakakis
def remove(request, net, args):
905 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 202
906 41a7fae7 Christos Stavrakakis
    # Error Response Codes: computeFault (400, 500),
907 41a7fae7 Christos Stavrakakis
    #                       serviceUnavailable (503),
908 41a7fae7 Christos Stavrakakis
    #                       unauthorized (401),
909 41a7fae7 Christos Stavrakakis
    #                       badRequest (400),
910 41a7fae7 Christos Stavrakakis
    #                       badMediaType(415),
911 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404),
912 41a7fae7 Christos Stavrakakis
    #                       overLimit (413)
913 41a7fae7 Christos Stavrakakis
914 41a7fae7 Christos Stavrakakis
    attachment = args.get("attachment")
915 41a7fae7 Christos Stavrakakis
    if attachment is None:
916 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Missing 'attachment' attribute.")
917 41a7fae7 Christos Stavrakakis
    try:
918 c988fcca Christos Stavrakakis
        nic_id = int(attachment)
919 41a7fae7 Christos Stavrakakis
    except (ValueError, TypeError):
920 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Invalid 'attachment' attribute.")
921 41a7fae7 Christos Stavrakakis
922 c988fcca Christos Stavrakakis
    nic = util.get_nic(nic_id=nic_id)
923 c988fcca Christos Stavrakakis
    server_id = nic.machine_id
924 41a7fae7 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
925 c988fcca Christos Stavrakakis
926 7c714455 Christos Stavrakakis
    servers.disconnect(vm, nic)
927 41a7fae7 Christos Stavrakakis
928 41a7fae7 Christos Stavrakakis
    return HttpResponse(status=202)
929 9ba6bb95 Christos Stavrakakis
930 9ba6bb95 Christos Stavrakakis
931 f8675683 Christos Stavrakakis
@server_action("addFloatingIp")
932 9ba6bb95 Christos Stavrakakis
def add_floating_ip(request, vm, args):
933 9ba6bb95 Christos Stavrakakis
    address = args.get("address")
934 9ba6bb95 Christos Stavrakakis
    if address is None:
935 9ba6bb95 Christos Stavrakakis
        raise faults.BadRequest("Missing 'address' attribute")
936 9ba6bb95 Christos Stavrakakis
937 fae6e5f0 Christos Stavrakakis
    userid = vm.userid
938 fae6e5f0 Christos Stavrakakis
    floating_ip = util.get_floating_ip_by_address(userid, address,
939 fae6e5f0 Christos Stavrakakis
                                                  for_update=True)
940 fae6e5f0 Christos Stavrakakis
    servers.create_port(userid, floating_ip.network, machine=vm,
941 fae6e5f0 Christos Stavrakakis
                        user_ipaddress=floating_ip)
942 9ba6bb95 Christos Stavrakakis
    return HttpResponse(status=202)
943 9ba6bb95 Christos Stavrakakis
944 9ba6bb95 Christos Stavrakakis
945 f8675683 Christos Stavrakakis
@server_action("removeFloatingIp")
946 9ba6bb95 Christos Stavrakakis
def remove_floating_ip(request, vm, args):
947 9ba6bb95 Christos Stavrakakis
    address = args.get("address")
948 9ba6bb95 Christos Stavrakakis
    if address is None:
949 9ba6bb95 Christos Stavrakakis
        raise faults.BadRequest("Missing 'address' attribute")
950 fae6e5f0 Christos Stavrakakis
    floating_ip = util.get_floating_ip_by_address(vm.userid, address,
951 fae6e5f0 Christos Stavrakakis
                                                  for_update=True)
952 fae6e5f0 Christos Stavrakakis
    if floating_ip.nic is None:
953 fae6e5f0 Christos Stavrakakis
        raise faults.BadRequest("Floating IP %s not attached to instance"
954 fae6e5f0 Christos Stavrakakis
                                % address)
955 fae6e5f0 Christos Stavrakakis
    servers.delete_port(floating_ip.nic)
956 9ba6bb95 Christos Stavrakakis
    return HttpResponse(status=202)