Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / management / common.py @ 8283d6c1

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 8814e07c Christos Stavrakakis
import logging
53 8814e07c Christos Stavrakakis
log = logging.getLogger(__name__)
54 8814e07c Christos Stavrakakis
55 11300d7b Giorgos Verigakis
56 11300d7b Giorgos Verigakis
def format_bool(b):
57 11300d7b Giorgos Verigakis
    return 'YES' if b else 'NO'
58 11300d7b Giorgos Verigakis
59 11300d7b Giorgos Verigakis
60 f83ebc98 Christos Stavrakakis
def parse_bool(string):
61 f83ebc98 Christos Stavrakakis
    if string == "True":
62 f83ebc98 Christos Stavrakakis
        return True
63 f83ebc98 Christos Stavrakakis
    elif string == "False":
64 f83ebc98 Christos Stavrakakis
        return False
65 f83ebc98 Christos Stavrakakis
    else:
66 f83ebc98 Christos Stavrakakis
        raise Exception("Can not parse string %s to bool" % string)
67 f83ebc98 Christos Stavrakakis
68 f83ebc98 Christos Stavrakakis
69 11300d7b Giorgos Verigakis
def format_date(d):
70 11300d7b Giorgos Verigakis
    if not d:
71 11300d7b Giorgos Verigakis
        return ''
72 11300d7b Giorgos Verigakis
73 11300d7b Giorgos Verigakis
    if d < datetime.now():
74 11300d7b Giorgos Verigakis
        return timesince(d) + ' ago'
75 11300d7b Giorgos Verigakis
    else:
76 11300d7b Giorgos Verigakis
        return 'in ' + timeuntil(d)
77 f66d8b04 Christos Stavrakakis
78 f66d8b04 Christos Stavrakakis
79 f66d8b04 Christos Stavrakakis
def format_vm_state(vm):
80 f66d8b04 Christos Stavrakakis
    if vm.operstate == "BUILD":
81 f66d8b04 Christos Stavrakakis
        return "BUILD(" + str(vm.buildpercentage) + "%)"
82 f66d8b04 Christos Stavrakakis
    else:
83 f66d8b04 Christos Stavrakakis
        return vm.operstate
84 53b9ba10 Christos Stavrakakis
85 53b9ba10 Christos Stavrakakis
86 53b9ba10 Christos Stavrakakis
def validate_network_info(options):
87 53b9ba10 Christos Stavrakakis
    subnet = options['subnet']
88 53b9ba10 Christos Stavrakakis
    gateway = options['gateway']
89 53b9ba10 Christos Stavrakakis
    subnet6 = options['subnet6']
90 53b9ba10 Christos Stavrakakis
    gateway6 = options['gateway6']
91 53b9ba10 Christos Stavrakakis
92 53b9ba10 Christos Stavrakakis
    try:
93 9ae613af Christos Stavrakakis
        validate_network_params(subnet, gateway)
94 9ae613af Christos Stavrakakis
    except (BadRequest, OverLimit) as e:
95 9ae613af Christos Stavrakakis
        raise CommandError(e)
96 53b9ba10 Christos Stavrakakis
97 53b9ba10 Christos Stavrakakis
    return subnet, gateway, subnet6, gateway6
98 b84ed662 Christos Stavrakakis
99 b84ed662 Christos Stavrakakis
100 b84ed662 Christos Stavrakakis
def get_backend(backend_id):
101 b84ed662 Christos Stavrakakis
    try:
102 b84ed662 Christos Stavrakakis
        backend_id = int(backend_id)
103 b84ed662 Christos Stavrakakis
        return Backend.objects.get(id=backend_id)
104 b84ed662 Christos Stavrakakis
    except ValueError:
105 b84ed662 Christos Stavrakakis
        raise CommandError("Invalid Backend ID: %s" % backend_id)
106 b84ed662 Christos Stavrakakis
    except Backend.DoesNotExist:
107 b84ed662 Christos Stavrakakis
        raise CommandError("Backend with ID %s not found in DB. "
108 b84ed662 Christos Stavrakakis
                           " Use snf-manage backend-list to find"
109 b84ed662 Christos Stavrakakis
                           " out available backend IDs." % backend_id)
110 b84ed662 Christos Stavrakakis
111 b84ed662 Christos Stavrakakis
112 b84ed662 Christos Stavrakakis
def get_image(image_id, user_id):
113 b84ed662 Christos Stavrakakis
    if image_id:
114 b84ed662 Christos Stavrakakis
        try:
115 b84ed662 Christos Stavrakakis
            return backend_get_image(image_id, user_id)
116 b84ed662 Christos Stavrakakis
        except ItemNotFound:
117 b84ed662 Christos Stavrakakis
            raise CommandError("Image with ID %s not found."
118 b84ed662 Christos Stavrakakis
                               " Use snf-manage image-list to find"
119 b84ed662 Christos Stavrakakis
                               " out available image IDs." % image_id)
120 b84ed662 Christos Stavrakakis
    else:
121 b84ed662 Christos Stavrakakis
        raise CommandError("image-id is mandatory")
122 b84ed662 Christos Stavrakakis
123 b84ed662 Christos Stavrakakis
124 b84ed662 Christos Stavrakakis
def get_vm(server_id):
125 b84ed662 Christos Stavrakakis
    try:
126 b84ed662 Christos Stavrakakis
        server_id = int(server_id)
127 b84ed662 Christos Stavrakakis
        return VirtualMachine.objects.get(id=server_id)
128 b84ed662 Christos Stavrakakis
    except ValueError:
129 b84ed662 Christos Stavrakakis
        raise CommandError("Invalid server ID: %s", server_id)
130 b84ed662 Christos Stavrakakis
    except VirtualMachine.DoesNotExist:
131 b84ed662 Christos Stavrakakis
        raise CommandError("Server with ID %s not found in DB."
132 b84ed662 Christos Stavrakakis
                           " Use snf-manage server-list to find out"
133 b84ed662 Christos Stavrakakis
                           " available server IDs." % server_id)
134 b84ed662 Christos Stavrakakis
135 b84ed662 Christos Stavrakakis
136 b84ed662 Christos Stavrakakis
def get_network(network_id):
137 b84ed662 Christos Stavrakakis
    try:
138 b84ed662 Christos Stavrakakis
        network_id = int(network_id)
139 b84ed662 Christos Stavrakakis
        return Network.objects.get(id=network_id)
140 b84ed662 Christos Stavrakakis
    except ValueError:
141 b84ed662 Christos Stavrakakis
        raise CommandError("Invalid network ID: %s", network_id)
142 b84ed662 Christos Stavrakakis
    except Network.DoesNotExist:
143 b84ed662 Christos Stavrakakis
        raise CommandError("Network with ID %s not found in DB."
144 b84ed662 Christos Stavrakakis
                           " Use snf-manage network-list to find out"
145 b84ed662 Christos Stavrakakis
                           " available network IDs." % network_id)
146 b84ed662 Christos Stavrakakis
147 b84ed662 Christos Stavrakakis
148 b84ed662 Christos Stavrakakis
def get_flavor(flavor_id):
149 b84ed662 Christos Stavrakakis
    try:
150 b84ed662 Christos Stavrakakis
        flavor_id = int(flavor_id)
151 b84ed662 Christos Stavrakakis
        return Flavor.objects.get(id=flavor_id)
152 b84ed662 Christos Stavrakakis
    except ValueError:
153 b84ed662 Christos Stavrakakis
        raise CommandError("Invalid flavor ID: %s", flavor_id)
154 b84ed662 Christos Stavrakakis
    except Flavor.DoesNotExist:
155 b84ed662 Christos Stavrakakis
        raise CommandError("Flavor with ID %s not found in DB."
156 b84ed662 Christos Stavrakakis
                           " Use snf-manage flavor-list to find out"
157 b84ed662 Christos Stavrakakis
                           " available flavor IDs." % flavor_id)
158 bad9404c Christos Stavrakakis
159 bad9404c Christos Stavrakakis
160 bad9404c Christos Stavrakakis
def filter_results(objects, filter_by):
161 bad9404c Christos Stavrakakis
    filter_list = filter_by.split(",")
162 bad9404c Christos Stavrakakis
    filter_dict = {}
163 bad9404c Christos Stavrakakis
    exclude_dict = {}
164 bad9404c Christos Stavrakakis
165 bad9404c Christos Stavrakakis
    def map_field_type(query):
166 bad9404c Christos Stavrakakis
        def fix_bool(val):
167 bad9404c Christos Stavrakakis
            if val.lower() in ("yes", "true", "t"):
168 bad9404c Christos Stavrakakis
                return True
169 bad9404c Christos Stavrakakis
            if val.lower() in ("no", "false", "f"):
170 bad9404c Christos Stavrakakis
                return False
171 bad9404c Christos Stavrakakis
            return val
172 bad9404c Christos Stavrakakis
173 bad9404c Christos Stavrakakis
        if "!=" in query:
174 bad9404c Christos Stavrakakis
            key, val = query.split("!=")
175 bad9404c Christos Stavrakakis
            exclude_dict[key] = fix_bool(val)
176 bad9404c Christos Stavrakakis
            return
177 bad9404c Christos Stavrakakis
        OP_MAP = {
178 bad9404c Christos Stavrakakis
            ">=": "__gte",
179 bad9404c Christos Stavrakakis
            "=>": "__gte",
180 bad9404c Christos Stavrakakis
            ">":  "__gt",
181 bad9404c Christos Stavrakakis
            "<=": "__lte",
182 bad9404c Christos Stavrakakis
            "=<": "__lte",
183 bad9404c Christos Stavrakakis
            "<":  "__lt",
184 2d30ccdd Stratos Psomadakis
            "=":  "",
185 bad9404c Christos Stavrakakis
        }
186 bad9404c Christos Stavrakakis
        for op, new_op in OP_MAP.items():
187 bad9404c Christos Stavrakakis
            if op in query:
188 bad9404c Christos Stavrakakis
                key, val = query.split(op)
189 bad9404c Christos Stavrakakis
                filter_dict[key + new_op] = fix_bool(val)
190 bad9404c Christos Stavrakakis
                return
191 bad9404c Christos Stavrakakis
192 bad9404c Christos Stavrakakis
    map(lambda x: map_field_type(x), filter_list)
193 bad9404c Christos Stavrakakis
194 bad9404c Christos Stavrakakis
    try:
195 bad9404c Christos Stavrakakis
        objects = objects.filter(**filter_dict)
196 bad9404c Christos Stavrakakis
        return objects.exclude(**exclude_dict)
197 bad9404c Christos Stavrakakis
    except FieldError as e:
198 bad9404c Christos Stavrakakis
        raise CommandError(e)
199 8b3e98f8 Christos Stavrakakis
    except Exception as e:
200 8b3e98f8 Christos Stavrakakis
        raise CommandError("Can not filter results: %s" % e)
201 2333a2c4 Christos Stavrakakis
202 2333a2c4 Christos Stavrakakis
203 2333a2c4 Christos Stavrakakis
def check_backend_credentials(clustername, port, username, password):
204 2333a2c4 Christos Stavrakakis
    try:
205 2333a2c4 Christos Stavrakakis
        client = GanetiRapiClient(clustername, port, username, password)
206 2333a2c4 Christos Stavrakakis
        # This command will raise an exception if there is no
207 2333a2c4 Christos Stavrakakis
        # write-access
208 2333a2c4 Christos Stavrakakis
        client.ModifyCluster()
209 2333a2c4 Christos Stavrakakis
    except GanetiApiError as e:
210 2333a2c4 Christos Stavrakakis
        raise CommandError(e)
211 2333a2c4 Christos Stavrakakis
212 2333a2c4 Christos Stavrakakis
    info = client.GetInfo()
213 2333a2c4 Christos Stavrakakis
    info_name = info['name']
214 2333a2c4 Christos Stavrakakis
    if info_name != clustername:
215 2333a2c4 Christos Stavrakakis
        raise CommandError("Invalid clustername value. Please use the"
216 2333a2c4 Christos Stavrakakis
                           " Ganeti Cluster name: %s" % info_name)
217 7a0aa449 Christos Stavrakakis
218 7a0aa449 Christos Stavrakakis
219 7a0aa449 Christos Stavrakakis
def pprint_table(out, table, headers=None, separator=None):
220 7a0aa449 Christos Stavrakakis
    """Print a pretty, aligned string representation of table.
221 7a0aa449 Christos Stavrakakis

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