Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / management / common.py @ 5a5a1f65

History | View | Annotate | Download (10 kB)

1 11300d7b Giorgos Verigakis
# Copyright 2012 GRNET S.A. All rights reserved.
2 11300d7b Giorgos Verigakis
#
3 11300d7b Giorgos Verigakis
# Redistribution and use in source and binary forms, with or
4 11300d7b Giorgos Verigakis
# without modification, are permitted provided that the following
5 11300d7b Giorgos Verigakis
# conditions are met:
6 11300d7b Giorgos Verigakis
#
7 11300d7b Giorgos Verigakis
#   1. Redistributions of source code must retain the above
8 11300d7b Giorgos Verigakis
#      copyright notice, this list of conditions and the following
9 11300d7b Giorgos Verigakis
#      disclaimer.
10 11300d7b Giorgos Verigakis
#
11 11300d7b Giorgos Verigakis
#   2. Redistributions in binary form must reproduce the above
12 11300d7b Giorgos Verigakis
#      copyright notice, this list of conditions and the following
13 11300d7b Giorgos Verigakis
#      disclaimer in the documentation and/or other materials
14 11300d7b Giorgos Verigakis
#      provided with the distribution.
15 11300d7b Giorgos Verigakis
#
16 11300d7b Giorgos Verigakis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 11300d7b Giorgos Verigakis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 11300d7b Giorgos Verigakis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 11300d7b Giorgos Verigakis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 11300d7b Giorgos Verigakis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 11300d7b Giorgos Verigakis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 11300d7b Giorgos Verigakis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 11300d7b Giorgos Verigakis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 11300d7b Giorgos Verigakis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 11300d7b Giorgos Verigakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 11300d7b Giorgos Verigakis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 11300d7b Giorgos Verigakis
# POSSIBILITY OF SUCH DAMAGE.
28 11300d7b Giorgos Verigakis
#
29 11300d7b Giorgos Verigakis
# The views and conclusions contained in the software and
30 11300d7b Giorgos Verigakis
# documentation are those of the authors and should not be
31 11300d7b Giorgos Verigakis
# interpreted as representing official policies, either expressed
32 11300d7b Giorgos Verigakis
# or implied, of GRNET S.A.
33 11300d7b Giorgos Verigakis
34 b84ed662 Christos Stavrakakis
35 53b9ba10 Christos Stavrakakis
import ipaddr
36 11300d7b Giorgos Verigakis
from datetime import datetime
37 11300d7b Giorgos Verigakis
38 11300d7b Giorgos Verigakis
from django.utils.timesince import timesince, timeuntil
39 b84ed662 Christos Stavrakakis
40 53b9ba10 Christos Stavrakakis
from django.core.management import CommandError
41 b84ed662 Christos Stavrakakis
from synnefo.db.models import Backend, VirtualMachine, Network, Flavor
42 b84ed662 Christos Stavrakakis
from synnefo.api.util import get_image as backend_get_image
43 9ae613af Christos Stavrakakis
from synnefo.api.faults import ItemNotFound, BadRequest, OverLimit
44 bad9404c Christos Stavrakakis
from django.core.exceptions import FieldError
45 bad9404c Christos Stavrakakis
46 9ae613af Christos Stavrakakis
from synnefo.api.util import validate_network_params
47 9ae613af Christos Stavrakakis
from synnefo.settings import (CYCLADES_ASTAKOS_SERVICE_TOKEN as ASTAKOS_TOKEN,
48 f1ffc695 Stratos Psomadakis
                              ASTAKOS_URL)
49 2333a2c4 Christos Stavrakakis
from synnefo.logic.rapi import GanetiApiError, GanetiRapiClient
50 3170076a Stratos Psomadakis
from synnefo.lib import astakos
51 11300d7b Giorgos Verigakis
52 5a5a1f65 Stratos Psomadakis
from synnefo.util.text import uenc
53 5a5a1f65 Stratos Psomadakis
54 8814e07c Christos Stavrakakis
import logging
55 8814e07c Christos Stavrakakis
log = logging.getLogger(__name__)
56 8814e07c Christos Stavrakakis
57 11300d7b Giorgos Verigakis
58 11300d7b Giorgos Verigakis
def format_bool(b):
59 11300d7b Giorgos Verigakis
    return 'YES' if b else 'NO'
60 11300d7b Giorgos Verigakis
61 11300d7b Giorgos Verigakis
62 f83ebc98 Christos Stavrakakis
def parse_bool(string):
63 f83ebc98 Christos Stavrakakis
    if string == "True":
64 f83ebc98 Christos Stavrakakis
        return True
65 f83ebc98 Christos Stavrakakis
    elif string == "False":
66 f83ebc98 Christos Stavrakakis
        return False
67 f83ebc98 Christos Stavrakakis
    else:
68 f83ebc98 Christos Stavrakakis
        raise Exception("Can not parse string %s to bool" % string)
69 f83ebc98 Christos Stavrakakis
70 f83ebc98 Christos Stavrakakis
71 11300d7b Giorgos Verigakis
def format_date(d):
72 11300d7b Giorgos Verigakis
    if not d:
73 11300d7b Giorgos Verigakis
        return ''
74 11300d7b Giorgos Verigakis
75 11300d7b Giorgos Verigakis
    if d < datetime.now():
76 11300d7b Giorgos Verigakis
        return timesince(d) + ' ago'
77 11300d7b Giorgos Verigakis
    else:
78 11300d7b Giorgos Verigakis
        return 'in ' + timeuntil(d)
79 f66d8b04 Christos Stavrakakis
80 f66d8b04 Christos Stavrakakis
81 f66d8b04 Christos Stavrakakis
def format_vm_state(vm):
82 f66d8b04 Christos Stavrakakis
    if vm.operstate == "BUILD":
83 f66d8b04 Christos Stavrakakis
        return "BUILD(" + str(vm.buildpercentage) + "%)"
84 f66d8b04 Christos Stavrakakis
    else:
85 f66d8b04 Christos Stavrakakis
        return vm.operstate
86 53b9ba10 Christos Stavrakakis
87 53b9ba10 Christos Stavrakakis
88 53b9ba10 Christos Stavrakakis
def validate_network_info(options):
89 53b9ba10 Christos Stavrakakis
    subnet = options['subnet']
90 53b9ba10 Christos Stavrakakis
    gateway = options['gateway']
91 53b9ba10 Christos Stavrakakis
    subnet6 = options['subnet6']
92 53b9ba10 Christos Stavrakakis
    gateway6 = options['gateway6']
93 53b9ba10 Christos Stavrakakis
94 53b9ba10 Christos Stavrakakis
    try:
95 9ae613af Christos Stavrakakis
        validate_network_params(subnet, gateway)
96 9ae613af Christos Stavrakakis
    except (BadRequest, OverLimit) as e:
97 9ae613af Christos Stavrakakis
        raise CommandError(e)
98 53b9ba10 Christos Stavrakakis
99 53b9ba10 Christos Stavrakakis
    return subnet, gateway, subnet6, gateway6
100 b84ed662 Christos Stavrakakis
101 b84ed662 Christos Stavrakakis
102 b84ed662 Christos Stavrakakis
def get_backend(backend_id):
103 b84ed662 Christos Stavrakakis
    try:
104 b84ed662 Christos Stavrakakis
        backend_id = int(backend_id)
105 b84ed662 Christos Stavrakakis
        return Backend.objects.get(id=backend_id)
106 b84ed662 Christos Stavrakakis
    except ValueError:
107 b84ed662 Christos Stavrakakis
        raise CommandError("Invalid Backend ID: %s" % backend_id)
108 b84ed662 Christos Stavrakakis
    except Backend.DoesNotExist:
109 b84ed662 Christos Stavrakakis
        raise CommandError("Backend with ID %s not found in DB. "
110 b84ed662 Christos Stavrakakis
                           " Use snf-manage backend-list to find"
111 b84ed662 Christos Stavrakakis
                           " out available backend IDs." % backend_id)
112 b84ed662 Christos Stavrakakis
113 b84ed662 Christos Stavrakakis
114 b84ed662 Christos Stavrakakis
def get_image(image_id, user_id):
115 b84ed662 Christos Stavrakakis
    if image_id:
116 b84ed662 Christos Stavrakakis
        try:
117 b84ed662 Christos Stavrakakis
            return backend_get_image(image_id, user_id)
118 b84ed662 Christos Stavrakakis
        except ItemNotFound:
119 b84ed662 Christos Stavrakakis
            raise CommandError("Image with ID %s not found."
120 b84ed662 Christos Stavrakakis
                               " Use snf-manage image-list to find"
121 b84ed662 Christos Stavrakakis
                               " out available image IDs." % image_id)
122 b84ed662 Christos Stavrakakis
    else:
123 b84ed662 Christos Stavrakakis
        raise CommandError("image-id is mandatory")
124 b84ed662 Christos Stavrakakis
125 b84ed662 Christos Stavrakakis
126 b84ed662 Christos Stavrakakis
def get_vm(server_id):
127 b84ed662 Christos Stavrakakis
    try:
128 b84ed662 Christos Stavrakakis
        server_id = int(server_id)
129 b84ed662 Christos Stavrakakis
        return VirtualMachine.objects.get(id=server_id)
130 b84ed662 Christos Stavrakakis
    except ValueError:
131 b84ed662 Christos Stavrakakis
        raise CommandError("Invalid server ID: %s", server_id)
132 b84ed662 Christos Stavrakakis
    except VirtualMachine.DoesNotExist:
133 b84ed662 Christos Stavrakakis
        raise CommandError("Server with ID %s not found in DB."
134 b84ed662 Christos Stavrakakis
                           " Use snf-manage server-list to find out"
135 b84ed662 Christos Stavrakakis
                           " available server IDs." % server_id)
136 b84ed662 Christos Stavrakakis
137 b84ed662 Christos Stavrakakis
138 b84ed662 Christos Stavrakakis
def get_network(network_id):
139 b84ed662 Christos Stavrakakis
    try:
140 b84ed662 Christos Stavrakakis
        network_id = int(network_id)
141 b84ed662 Christos Stavrakakis
        return Network.objects.get(id=network_id)
142 b84ed662 Christos Stavrakakis
    except ValueError:
143 b84ed662 Christos Stavrakakis
        raise CommandError("Invalid network ID: %s", network_id)
144 b84ed662 Christos Stavrakakis
    except Network.DoesNotExist:
145 b84ed662 Christos Stavrakakis
        raise CommandError("Network with ID %s not found in DB."
146 b84ed662 Christos Stavrakakis
                           " Use snf-manage network-list to find out"
147 b84ed662 Christos Stavrakakis
                           " available network IDs." % network_id)
148 b84ed662 Christos Stavrakakis
149 b84ed662 Christos Stavrakakis
150 b84ed662 Christos Stavrakakis
def get_flavor(flavor_id):
151 b84ed662 Christos Stavrakakis
    try:
152 b84ed662 Christos Stavrakakis
        flavor_id = int(flavor_id)
153 b84ed662 Christos Stavrakakis
        return Flavor.objects.get(id=flavor_id)
154 b84ed662 Christos Stavrakakis
    except ValueError:
155 b84ed662 Christos Stavrakakis
        raise CommandError("Invalid flavor ID: %s", flavor_id)
156 b84ed662 Christos Stavrakakis
    except Flavor.DoesNotExist:
157 b84ed662 Christos Stavrakakis
        raise CommandError("Flavor with ID %s not found in DB."
158 b84ed662 Christos Stavrakakis
                           " Use snf-manage flavor-list to find out"
159 b84ed662 Christos Stavrakakis
                           " available flavor IDs." % flavor_id)
160 bad9404c Christos Stavrakakis
161 bad9404c Christos Stavrakakis
162 bad9404c Christos Stavrakakis
def filter_results(objects, filter_by):
163 bad9404c Christos Stavrakakis
    filter_list = filter_by.split(",")
164 bad9404c Christos Stavrakakis
    filter_dict = {}
165 bad9404c Christos Stavrakakis
    exclude_dict = {}
166 bad9404c Christos Stavrakakis
167 bad9404c Christos Stavrakakis
    def map_field_type(query):
168 bad9404c Christos Stavrakakis
        def fix_bool(val):
169 bad9404c Christos Stavrakakis
            if val.lower() in ("yes", "true", "t"):
170 bad9404c Christos Stavrakakis
                return True
171 bad9404c Christos Stavrakakis
            if val.lower() in ("no", "false", "f"):
172 bad9404c Christos Stavrakakis
                return False
173 bad9404c Christos Stavrakakis
            return val
174 bad9404c Christos Stavrakakis
175 bad9404c Christos Stavrakakis
        if "!=" in query:
176 bad9404c Christos Stavrakakis
            key, val = query.split("!=")
177 bad9404c Christos Stavrakakis
            exclude_dict[key] = fix_bool(val)
178 bad9404c Christos Stavrakakis
            return
179 bad9404c Christos Stavrakakis
        OP_MAP = {
180 bad9404c Christos Stavrakakis
            ">=": "__gte",
181 bad9404c Christos Stavrakakis
            "=>": "__gte",
182 bad9404c Christos Stavrakakis
            ">":  "__gt",
183 bad9404c Christos Stavrakakis
            "<=": "__lte",
184 bad9404c Christos Stavrakakis
            "=<": "__lte",
185 bad9404c Christos Stavrakakis
            "<":  "__lt",
186 2d30ccdd Stratos Psomadakis
            "=":  "",
187 bad9404c Christos Stavrakakis
        }
188 bad9404c Christos Stavrakakis
        for op, new_op in OP_MAP.items():
189 bad9404c Christos Stavrakakis
            if op in query:
190 bad9404c Christos Stavrakakis
                key, val = query.split(op)
191 bad9404c Christos Stavrakakis
                filter_dict[key + new_op] = fix_bool(val)
192 bad9404c Christos Stavrakakis
                return
193 bad9404c Christos Stavrakakis
194 bad9404c Christos Stavrakakis
    map(lambda x: map_field_type(x), filter_list)
195 bad9404c Christos Stavrakakis
196 bad9404c Christos Stavrakakis
    try:
197 bad9404c Christos Stavrakakis
        objects = objects.filter(**filter_dict)
198 bad9404c Christos Stavrakakis
        return objects.exclude(**exclude_dict)
199 bad9404c Christos Stavrakakis
    except FieldError as e:
200 bad9404c Christos Stavrakakis
        raise CommandError(e)
201 8b3e98f8 Christos Stavrakakis
    except Exception as e:
202 8b3e98f8 Christos Stavrakakis
        raise CommandError("Can not filter results: %s" % e)
203 2333a2c4 Christos Stavrakakis
204 2333a2c4 Christos Stavrakakis
205 2333a2c4 Christos Stavrakakis
def check_backend_credentials(clustername, port, username, password):
206 2333a2c4 Christos Stavrakakis
    try:
207 2333a2c4 Christos Stavrakakis
        client = GanetiRapiClient(clustername, port, username, password)
208 2333a2c4 Christos Stavrakakis
        # This command will raise an exception if there is no
209 2333a2c4 Christos Stavrakakis
        # write-access
210 2333a2c4 Christos Stavrakakis
        client.ModifyCluster()
211 2333a2c4 Christos Stavrakakis
    except GanetiApiError as e:
212 2333a2c4 Christos Stavrakakis
        raise CommandError(e)
213 2333a2c4 Christos Stavrakakis
214 2333a2c4 Christos Stavrakakis
    info = client.GetInfo()
215 2333a2c4 Christos Stavrakakis
    info_name = info['name']
216 2333a2c4 Christos Stavrakakis
    if info_name != clustername:
217 2333a2c4 Christos Stavrakakis
        raise CommandError("Invalid clustername value. Please use the"
218 2333a2c4 Christos Stavrakakis
                           " Ganeti Cluster name: %s" % info_name)
219 7a0aa449 Christos Stavrakakis
220 7a0aa449 Christos Stavrakakis
221 7a0aa449 Christos Stavrakakis
def pprint_table(out, table, headers=None, separator=None):
222 7a0aa449 Christos Stavrakakis
    """Print a pretty, aligned string representation of table.
223 7a0aa449 Christos Stavrakakis

224 7a0aa449 Christos Stavrakakis
    Works by finding out the max width of each column and padding to data
225 7a0aa449 Christos Stavrakakis
    to this value.
226 7a0aa449 Christos Stavrakakis
    """
227 7a0aa449 Christos Stavrakakis
228 7d36f85e Christos Stavrakakis
    assert(isinstance(table, (list, tuple))), "Invalid table type"
229 7a0aa449 Christos Stavrakakis
    sep = separator if separator else "  "
230 7a0aa449 Christos Stavrakakis
231 7a0aa449 Christos Stavrakakis
    if headers:
232 7d36f85e Christos Stavrakakis
        assert(isinstance(headers, (list, tuple))), "Invalid headers type"
233 7a0aa449 Christos Stavrakakis
        table.insert(0, headers)
234 7a0aa449 Christos Stavrakakis
235 7a0aa449 Christos Stavrakakis
    # Find out the max width of each column
236 5a5a1f65 Stratos Psomadakis
    widths = [max(map(len, col)) for col in zip(*table)]
237 7a0aa449 Christos Stavrakakis
238 7a0aa449 Christos Stavrakakis
    t_length = sum(widths) + len(sep) * (len(widths) - 1)
239 7a0aa449 Christos Stavrakakis
    if headers:
240 7a0aa449 Christos Stavrakakis
        # pretty print the headers
241 db4873f8 Christos Stavrakakis
        print >> out, sep.join((str(val).rjust(width)
242 5112da27 Christos Stavrakakis
                               for val, width in zip(headers, widths)))
243 7a0aa449 Christos Stavrakakis
        print >> out, "-" * t_length
244 7a0aa449 Christos Stavrakakis
        # remove headers
245 7a0aa449 Christos Stavrakakis
        table = table[1:]
246 7a0aa449 Christos Stavrakakis
247 7a0aa449 Christos Stavrakakis
    # print the rest table
248 7a0aa449 Christos Stavrakakis
    for row in table:
249 5a5a1f65 Stratos Psomadakis
        print >> out, sep.join(uenc(val.rjust(width))
250 5a5a1f65 Stratos Psomadakis
                               for val, width in zip(row, widths))
251 3170076a Stratos Psomadakis
252 3170076a Stratos Psomadakis
253 8283d6c1 Stratos Psomadakis
class UserCache(object):
254 8283d6c1 Stratos Psomadakis
    """uuid<->displayname user 'cache'"""
255 3fa01ebd Stratos Psomadakis
256 f1ffc695 Stratos Psomadakis
    user_catalogs_url = ASTAKOS_URL.replace("im/authenticate",
257 f1ffc695 Stratos Psomadakis
                                            "service/api/user_catalogs")
258 f1ffc695 Stratos Psomadakis
259 8283d6c1 Stratos Psomadakis
    def __init__(self, split=100):
260 3170076a Stratos Psomadakis
        self.users = {}
261 3170076a Stratos Psomadakis
262 8283d6c1 Stratos Psomadakis
        self.split = split
263 8283d6c1 Stratos Psomadakis
        assert(self.split > 0), "split must be positive"
264 8283d6c1 Stratos Psomadakis
265 8283d6c1 Stratos Psomadakis
    def fetch_names(self, uuid_list):
266 8283d6c1 Stratos Psomadakis
        l = len(uuid_list)
267 8283d6c1 Stratos Psomadakis
268 8283d6c1 Stratos Psomadakis
        start = 0
269 8283d6c1 Stratos Psomadakis
        while start < l:
270 8283d6c1 Stratos Psomadakis
            end = self.split if l > self.split else l
271 8283d6c1 Stratos Psomadakis
            try:
272 8283d6c1 Stratos Psomadakis
                names = \
273 8283d6c1 Stratos Psomadakis
                    astakos.get_displaynames(token=ASTAKOS_TOKEN,
274 8283d6c1 Stratos Psomadakis
                                             url=UserCache.user_catalogs_url,
275 8283d6c1 Stratos Psomadakis
                                             uuids=uuid_list[start:end])
276 8283d6c1 Stratos Psomadakis
                self.users.update(names)
277 8283d6c1 Stratos Psomadakis
            except Exception as e:
278 8283d6c1 Stratos Psomadakis
                log.error("Failed to fetch names: %s",  e)
279 8283d6c1 Stratos Psomadakis
280 8283d6c1 Stratos Psomadakis
            start = end
281 8283d6c1 Stratos Psomadakis
282 8283d6c1 Stratos Psomadakis
    def get_uuid(self, name):
283 8283d6c1 Stratos Psomadakis
        if not name in self.users:
284 8283d6c1 Stratos Psomadakis
            try:
285 8283d6c1 Stratos Psomadakis
                self.users[name] = \
286 8283d6c1 Stratos Psomadakis
                    astakos.get_user_uuid(token=ASTAKOS_TOKEN,
287 8283d6c1 Stratos Psomadakis
                                          url=UserCache.user_catalogs_url,
288 8283d6c1 Stratos Psomadakis
                                          displayname=name)
289 8283d6c1 Stratos Psomadakis
            except Exception as e:
290 8283d6c1 Stratos Psomadakis
                log.error("Can not get uuid for name %s: %s", name, e)
291 8283d6c1 Stratos Psomadakis
                self.users[name] = name
292 8283d6c1 Stratos Psomadakis
293 8283d6c1 Stratos Psomadakis
        return self.users[name]
294 8283d6c1 Stratos Psomadakis
295 8283d6c1 Stratos Psomadakis
    def get_name(self, uuid):
296 8814e07c Christos Stavrakakis
        """Do the uuid-to-email resolving"""
297 3fa01ebd Stratos Psomadakis
298 3170076a Stratos Psomadakis
        if not uuid in self.users:
299 3fa01ebd Stratos Psomadakis
            try:
300 f1ffc695 Stratos Psomadakis
                self.users[uuid] = \
301 8814e07c Christos Stavrakakis
                    astakos.get_displayname(token=ASTAKOS_TOKEN,
302 8283d6c1 Stratos Psomadakis
                                            url=UserCache.user_catalogs_url,
303 8814e07c Christos Stavrakakis
                                            uuid=uuid)
304 8814e07c Christos Stavrakakis
            except Exception as e:
305 8814e07c Christos Stavrakakis
                log.error("Can not get display name for uuid %s: %s", uuid, e)
306 4500650c Stratos Psomadakis
                self.users[uuid] = "-"
307 3170076a Stratos Psomadakis
308 3170076a Stratos Psomadakis
        return self.users[uuid]
309 4500650c Stratos Psomadakis
310 4500650c Stratos Psomadakis
311 4500650c Stratos Psomadakis
class Omit(object):
312 4500650c Stratos Psomadakis
    pass