Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / management / common.py @ 7a0aa449

History | View | Annotate | Download (8.1 kB)

1
# Copyright 2012 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

    
34

    
35
import ipaddr
36
from datetime import datetime
37

    
38
from django.utils.timesince import timesince, timeuntil
39

    
40
from django.core.management import CommandError
41
from synnefo.db.models import Backend, VirtualMachine, Network, Flavor
42
from synnefo.api.util import get_image as backend_get_image
43
from synnefo.api.faults import ItemNotFound
44
from django.core.exceptions import FieldError
45

    
46
from synnefo.api.util import validate_network_size
47
from synnefo.settings import MAX_CIDR_BLOCK
48
from synnefo.logic.rapi import GanetiApiError, GanetiRapiClient
49

    
50

    
51
def format_bool(b):
52
    return 'YES' if b else 'NO'
53

    
54

    
55
def format_date(d):
56
    if not d:
57
        return ''
58

    
59
    if d < datetime.now():
60
        return timesince(d) + ' ago'
61
    else:
62
        return 'in ' + timeuntil(d)
63

    
64

    
65
def format_vm_state(vm):
66
    if vm.operstate == "BUILD":
67
        return "BUILD(" + str(vm.buildpercentage) + "%)"
68
    else:
69
        return vm.operstate
70

    
71

    
72
def validate_network_info(options):
73
    subnet = options['subnet']
74
    gateway = options['gateway']
75
    subnet6 = options['subnet6']
76
    gateway6 = options['gateway6']
77

    
78
    try:
79
        net = ipaddr.IPv4Network(subnet)
80
        prefix = net.prefixlen
81
        if not validate_network_size(prefix):
82
            raise CommandError("Unsupport network mask %d."
83
                               " Must be in range (%s,29] "
84
                               % (prefix, MAX_CIDR_BLOCK))
85
    except ValueError:
86
        raise CommandError('Malformed subnet')
87
    try:
88
        gateway and ipaddr.IPv4Address(gateway) or None
89
    except ValueError:
90
        raise CommandError('Malformed gateway')
91

    
92
    try:
93
        subnet6 and ipaddr.IPv6Network(subnet6) or None
94
    except ValueError:
95
        raise CommandError('Malformed subnet6')
96

    
97
    try:
98
        gateway6 and ipaddr.IPv6Address(gateway6) or None
99
    except ValueError:
100
        raise CommandError('Malformed gateway6')
101

    
102
    return subnet, gateway, subnet6, gateway6
103

    
104

    
105
def get_backend(backend_id):
106
    try:
107
        backend_id = int(backend_id)
108
        return Backend.objects.get(id=backend_id)
109
    except ValueError:
110
        raise CommandError("Invalid Backend ID: %s" % backend_id)
111
    except Backend.DoesNotExist:
112
        raise CommandError("Backend with ID %s not found in DB. "
113
                           " Use snf-manage backend-list to find"
114
                           " out available backend IDs." % backend_id)
115

    
116

    
117
def get_image(image_id, user_id):
118
    if image_id:
119
        try:
120
            return backend_get_image(image_id, user_id)
121
        except ItemNotFound:
122
            raise CommandError("Image with ID %s not found."
123
                               " Use snf-manage image-list to find"
124
                               " out available image IDs." % image_id)
125
    else:
126
        raise CommandError("image-id is mandatory")
127

    
128

    
129
def get_vm(server_id):
130
    try:
131
        server_id = int(server_id)
132
        return VirtualMachine.objects.get(id=server_id)
133
    except ValueError:
134
        raise CommandError("Invalid server ID: %s", server_id)
135
    except VirtualMachine.DoesNotExist:
136
        raise CommandError("Server with ID %s not found in DB."
137
                           " Use snf-manage server-list to find out"
138
                           " available server IDs." % server_id)
139

    
140

    
141
def get_network(network_id):
142
    try:
143
        network_id = int(network_id)
144
        return Network.objects.get(id=network_id)
145
    except ValueError:
146
        raise CommandError("Invalid network ID: %s", network_id)
147
    except Network.DoesNotExist:
148
        raise CommandError("Network with ID %s not found in DB."
149
                           " Use snf-manage network-list to find out"
150
                           " available network IDs." % network_id)
151

    
152

    
153
def get_flavor(flavor_id):
154
    try:
155
        flavor_id = int(flavor_id)
156
        return Flavor.objects.get(id=flavor_id)
157
    except ValueError:
158
        raise CommandError("Invalid flavor ID: %s", flavor_id)
159
    except Flavor.DoesNotExist:
160
        raise CommandError("Flavor with ID %s not found in DB."
161
                           " Use snf-manage flavor-list to find out"
162
                           " available flavor IDs." % flavor_id)
163

    
164

    
165
def filter_results(objects, filter_by):
166
    filter_list = filter_by.split(",")
167
    filter_dict = {}
168
    exclude_dict = {}
169

    
170
    def map_field_type(query):
171
        def fix_bool(val):
172
            if val.lower() in ("yes", "true", "t"):
173
                return True
174
            if val.lower() in ("no", "false", "f"):
175
                return False
176
            return val
177

    
178
        if "!=" in query:
179
            key, val = query.split("!=")
180
            exclude_dict[key] = fix_bool(val)
181
            return
182
        OP_MAP = {
183
            ">=": "__gte",
184
            "=>": "__gte",
185
            ">":  "__gt",
186
            "<=": "__lte",
187
            "=<": "__lte",
188
            "<":  "__lt",
189
            "=":  ""
190
        }
191
        for op, new_op in OP_MAP.items():
192
            if op in query:
193
                key, val = query.split(op)
194
                filter_dict[key + new_op] = fix_bool(val)
195
                return
196

    
197
    map(lambda x: map_field_type(x), filter_list)
198

    
199
    try:
200
        objects = objects.filter(**filter_dict)
201
        return objects.exclude(**exclude_dict)
202
    except FieldError as e:
203
        raise CommandError(e)
204

    
205

    
206
def check_backend_credentials(clustername, port, username, password):
207
    try:
208
        client = GanetiRapiClient(clustername, port, username, password)
209
        # This command will raise an exception if there is no
210
        # write-access
211
        client.ModifyCluster()
212
    except GanetiApiError as e:
213
        raise CommandError(e)
214

    
215
    info = client.GetInfo()
216
    info_name = info['name']
217
    if info_name != clustername:
218
        raise CommandError("Invalid clustername value. Please use the"
219
                           " Ganeti Cluster name: %s" % info_name)
220

    
221

    
222
def pprint_table(out, table, headers=None, separator=None):
223
    """Print a pretty, aligned string representation of table.
224

225
    Works by finding out the max width of each column and padding to data
226
    to this value.
227
    """
228

    
229
    sep = separator if separator else "  "
230

    
231
    if headers:
232
        table.insert(0, headers)
233

    
234
    # Find out the max width of each column
235
    widths = [max(map(len, col)) for col in zip(*table)]
236

    
237
    t_length = sum(widths) + len(sep) * (len(widths) - 1)
238
    if headers:
239
        # pretty print the headers
240
        print >> out, sep.join((val.rjust(width) for val, width \
241
                                                 in zip(headers, widths)))
242
        print >> out, "-" * t_length
243
        # remove headers
244
        table = table[1:]
245

    
246
    # print the rest table
247
    for row in table:
248
        print >> out, sep.join((val.rjust(width).encode('utf8') \
249
                                for val, width in zip(row, widths)))