Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / quotas / management / commands / enforce-resources-cyclades.py @ 4220c336

History | View | Annotate | Download (7.5 kB)

1 d14155e3 Giorgos Korfiatis
# Copyright 2013 GRNET S.A. All rights reserved.
2 d14155e3 Giorgos Korfiatis
#
3 d14155e3 Giorgos Korfiatis
# Redistribution and use in source and binary forms, with or
4 d14155e3 Giorgos Korfiatis
# without modification, are permitted provided that the following
5 d14155e3 Giorgos Korfiatis
# conditions are met:
6 d14155e3 Giorgos Korfiatis
#
7 d14155e3 Giorgos Korfiatis
#   1. Redistributions of source code must retain the above
8 d14155e3 Giorgos Korfiatis
#      copyright notice, this list of conditions and the following
9 d14155e3 Giorgos Korfiatis
#      disclaimer.
10 d14155e3 Giorgos Korfiatis
#
11 d14155e3 Giorgos Korfiatis
#   2. Redistributions in binary form must reproduce the above
12 d14155e3 Giorgos Korfiatis
#      copyright notice, this list of conditions and the following
13 d14155e3 Giorgos Korfiatis
#      disclaimer in the documentation and/or other materials
14 d14155e3 Giorgos Korfiatis
#      provided with the distribution.
15 d14155e3 Giorgos Korfiatis
#
16 d14155e3 Giorgos Korfiatis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 d14155e3 Giorgos Korfiatis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 d14155e3 Giorgos Korfiatis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 d14155e3 Giorgos Korfiatis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 d14155e3 Giorgos Korfiatis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 d14155e3 Giorgos Korfiatis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 d14155e3 Giorgos Korfiatis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 d14155e3 Giorgos Korfiatis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 d14155e3 Giorgos Korfiatis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 d14155e3 Giorgos Korfiatis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 d14155e3 Giorgos Korfiatis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 d14155e3 Giorgos Korfiatis
# POSSIBILITY OF SUCH DAMAGE.
28 d14155e3 Giorgos Korfiatis
#
29 d14155e3 Giorgos Korfiatis
# The views and conclusions contained in the software and
30 d14155e3 Giorgos Korfiatis
# documentation are those of the authors and should not be
31 d14155e3 Giorgos Korfiatis
# interpreted as representing official policies, either expressed
32 d14155e3 Giorgos Korfiatis
# or implied, of GRNET S.A.
33 d14155e3 Giorgos Korfiatis
34 d14155e3 Giorgos Korfiatis
import string
35 d14155e3 Giorgos Korfiatis
from optparse import make_option
36 d14155e3 Giorgos Korfiatis
from django.db import transaction
37 d14155e3 Giorgos Korfiatis
38 6aa9924d Giorgos Korfiatis
from synnefo.lib.ordereddict import OrderedDict
39 d14155e3 Giorgos Korfiatis
from synnefo.quotas import util
40 d14155e3 Giorgos Korfiatis
from synnefo.quotas import enforce
41 d14155e3 Giorgos Korfiatis
from synnefo.quotas import errors
42 d14155e3 Giorgos Korfiatis
from snf_django.management.commands import SynnefoCommand, CommandError
43 d14155e3 Giorgos Korfiatis
from snf_django.management.utils import pprint_table
44 d14155e3 Giorgos Korfiatis
45 d14155e3 Giorgos Korfiatis
46 d14155e3 Giorgos Korfiatis
DEFAULT_RESOURCES = ["cyclades.cpu",
47 d14155e3 Giorgos Korfiatis
                     "cyclades.ram",
48 d14155e3 Giorgos Korfiatis
                     "cyclades.floating_ip",
49 d14155e3 Giorgos Korfiatis
                     ]
50 d14155e3 Giorgos Korfiatis
51 d14155e3 Giorgos Korfiatis
52 d14155e3 Giorgos Korfiatis
class Command(SynnefoCommand):
53 d14155e3 Giorgos Korfiatis
    help = """Check and fix quota violations for Cyclades resources.
54 d14155e3 Giorgos Korfiatis
    """
55 d14155e3 Giorgos Korfiatis
    option_list = SynnefoCommand.option_list + (
56 6aa9924d Giorgos Korfiatis
        make_option("--max-operations",
57 6aa9924d Giorgos Korfiatis
                    help="Limit operations per backend."),
58 d14155e3 Giorgos Korfiatis
        make_option("--users", dest="users",
59 d14155e3 Giorgos Korfiatis
                    help=("Enforce resources only for the specified list "
60 d14155e3 Giorgos Korfiatis
                          "of users, e.g uuid1,uuid2")),
61 12e8c717 Giorgos Korfiatis
        make_option("--exclude-users",
62 12e8c717 Giorgos Korfiatis
                    help=("Exclude list of users from resource enforcement")),
63 d14155e3 Giorgos Korfiatis
        make_option("--resources",
64 d14155e3 Giorgos Korfiatis
                    help="Specify resources to check, default: %s" %
65 d14155e3 Giorgos Korfiatis
                    ",".join(DEFAULT_RESOURCES)),
66 d14155e3 Giorgos Korfiatis
        make_option("--fix",
67 d14155e3 Giorgos Korfiatis
                    default=False,
68 d14155e3 Giorgos Korfiatis
                    action="store_true",
69 d14155e3 Giorgos Korfiatis
                    help="Fix violations"),
70 d14155e3 Giorgos Korfiatis
        make_option("--force",
71 d14155e3 Giorgos Korfiatis
                    default=False,
72 d14155e3 Giorgos Korfiatis
                    action="store_true",
73 d14155e3 Giorgos Korfiatis
                    help=("Confirm actions that may permanently "
74 d14155e3 Giorgos Korfiatis
                          "remove a vm")),
75 d14155e3 Giorgos Korfiatis
    )
76 d14155e3 Giorgos Korfiatis
77 d14155e3 Giorgos Korfiatis
    def confirm(self):
78 4220c336 Giorgos Korfiatis
        self.stdout.write("Confirm? [y/N] ")
79 d14155e3 Giorgos Korfiatis
        response = raw_input()
80 d14155e3 Giorgos Korfiatis
        if string.lower(response) not in ['y', 'yes']:
81 4220c336 Giorgos Korfiatis
            self.stderr.write("Aborted.\n")
82 d14155e3 Giorgos Korfiatis
            exit()
83 d14155e3 Giorgos Korfiatis
84 d14155e3 Giorgos Korfiatis
    def get_handlers(self, resources):
85 d14155e3 Giorgos Korfiatis
        def rem(v):
86 d14155e3 Giorgos Korfiatis
            try:
87 d14155e3 Giorgos Korfiatis
                resources.remove(v)
88 d14155e3 Giorgos Korfiatis
                return True
89 d14155e3 Giorgos Korfiatis
            except ValueError:
90 d14155e3 Giorgos Korfiatis
                return False
91 d14155e3 Giorgos Korfiatis
92 d14155e3 Giorgos Korfiatis
        if resources is None:
93 d14155e3 Giorgos Korfiatis
            resources = list(DEFAULT_RESOURCES)
94 d14155e3 Giorgos Korfiatis
        else:
95 d14155e3 Giorgos Korfiatis
            resources = resources.split(",")
96 d14155e3 Giorgos Korfiatis
97 d14155e3 Giorgos Korfiatis
        handlers = [h for h in enforce.RESOURCE_HANDLING if rem(h[0])]
98 d14155e3 Giorgos Korfiatis
        if resources:
99 d14155e3 Giorgos Korfiatis
            m = "No such resource '%s'" % resources[0]
100 d14155e3 Giorgos Korfiatis
            raise CommandError(m)
101 d14155e3 Giorgos Korfiatis
        return handlers
102 d14155e3 Giorgos Korfiatis
103 d14155e3 Giorgos Korfiatis
    @transaction.commit_on_success
104 d14155e3 Giorgos Korfiatis
    def handle(self, *args, **options):
105 d14155e3 Giorgos Korfiatis
        write = self.stderr.write
106 d14155e3 Giorgos Korfiatis
        fix = options["fix"]
107 d14155e3 Giorgos Korfiatis
        force = options["force"]
108 6aa9924d Giorgos Korfiatis
        maxops = options["max_operations"]
109 6aa9924d Giorgos Korfiatis
        if maxops is not None:
110 6aa9924d Giorgos Korfiatis
            try:
111 6aa9924d Giorgos Korfiatis
                maxops = int(maxops)
112 6aa9924d Giorgos Korfiatis
            except ValueError:
113 6aa9924d Giorgos Korfiatis
                m = "Expected integer max operations."
114 6aa9924d Giorgos Korfiatis
                raise CommandError(m)
115 d14155e3 Giorgos Korfiatis
116 d14155e3 Giorgos Korfiatis
        users = options['users']
117 d14155e3 Giorgos Korfiatis
        if users is not None:
118 d14155e3 Giorgos Korfiatis
            users = users.split(',')
119 d14155e3 Giorgos Korfiatis
120 12e8c717 Giorgos Korfiatis
        excluded = options['exclude_users']
121 12e8c717 Giorgos Korfiatis
        excluded = set(excluded.split(',') if excluded is not None else [])
122 12e8c717 Giorgos Korfiatis
123 d14155e3 Giorgos Korfiatis
        handlers = self.get_handlers(options["resources"])
124 d14155e3 Giorgos Korfiatis
        try:
125 d14155e3 Giorgos Korfiatis
            qh_holdings = util.get_qh_users_holdings(users)
126 d14155e3 Giorgos Korfiatis
        except errors.AstakosClientException as e:
127 d14155e3 Giorgos Korfiatis
            raise CommandError(e)
128 d14155e3 Giorgos Korfiatis
129 6aa9924d Giorgos Korfiatis
        qh_holdings = sorted(qh_holdings.items())
130 d14155e3 Giorgos Korfiatis
        resources = set(h[0] for h in handlers)
131 d14155e3 Giorgos Korfiatis
        dangerous = bool(resources.difference(DEFAULT_RESOURCES))
132 d14155e3 Giorgos Korfiatis
133 d14155e3 Giorgos Korfiatis
        actions = {}
134 d14155e3 Giorgos Korfiatis
        overlimit = []
135 d14155e3 Giorgos Korfiatis
        viol_id = 0
136 d14155e3 Giorgos Korfiatis
        for resource, handle_resource, resource_type in handlers:
137 d14155e3 Giorgos Korfiatis
            if resource_type not in actions:
138 6aa9924d Giorgos Korfiatis
                actions[resource_type] = OrderedDict()
139 d14155e3 Giorgos Korfiatis
            actual_resources = enforce.get_actual_resources(resource_type,
140 d14155e3 Giorgos Korfiatis
                                                            users)
141 6aa9924d Giorgos Korfiatis
            for user, user_quota in qh_holdings:
142 12e8c717 Giorgos Korfiatis
                if user in excluded:
143 12e8c717 Giorgos Korfiatis
                    continue
144 d14155e3 Giorgos Korfiatis
                for source, source_quota in user_quota.iteritems():
145 d14155e3 Giorgos Korfiatis
                    try:
146 d14155e3 Giorgos Korfiatis
                        qh = util.transform_quotas(source_quota)
147 d14155e3 Giorgos Korfiatis
                        qh_value, qh_limit, qh_pending = qh[resource]
148 d14155e3 Giorgos Korfiatis
                    except KeyError:
149 d14155e3 Giorgos Korfiatis
                        write("Resource '%s' does not exist in Quotaholder"
150 d14155e3 Giorgos Korfiatis
                              " for user '%s' and source '%s'!\n" %
151 d14155e3 Giorgos Korfiatis
                              (resource, user, source))
152 d14155e3 Giorgos Korfiatis
                        continue
153 d14155e3 Giorgos Korfiatis
                    if qh_pending:
154 d14155e3 Giorgos Korfiatis
                        write("Pending commission for user '%s', source '%s', "
155 d14155e3 Giorgos Korfiatis
                              "resource '%s'. Skipping\n" %
156 d14155e3 Giorgos Korfiatis
                              (user, source, resource))
157 d14155e3 Giorgos Korfiatis
                        continue
158 d14155e3 Giorgos Korfiatis
                    diff = qh_value - qh_limit
159 d14155e3 Giorgos Korfiatis
                    if diff > 0:
160 d14155e3 Giorgos Korfiatis
                        viol_id += 1
161 d14155e3 Giorgos Korfiatis
                        overlimit.append((viol_id, user, source, resource,
162 d14155e3 Giorgos Korfiatis
                                          qh_limit, qh_value))
163 d14155e3 Giorgos Korfiatis
                        relevant_resources = actual_resources[user]
164 d14155e3 Giorgos Korfiatis
                        handle_resource(viol_id, resource, relevant_resources,
165 d14155e3 Giorgos Korfiatis
                                        diff, actions)
166 d14155e3 Giorgos Korfiatis
167 d14155e3 Giorgos Korfiatis
        if not overlimit:
168 d14155e3 Giorgos Korfiatis
            write("No violations.\n")
169 d14155e3 Giorgos Korfiatis
            return
170 d14155e3 Giorgos Korfiatis
171 d14155e3 Giorgos Korfiatis
        headers = ("#", "User", "Source", "Resource", "Limit", "Usage")
172 4220c336 Giorgos Korfiatis
        pprint_table(self.stdout, overlimit, headers,
173 d14155e3 Giorgos Korfiatis
                     options["output_format"], title="Violations")
174 d14155e3 Giorgos Korfiatis
175 d14155e3 Giorgos Korfiatis
        if any(actions.values()):
176 4220c336 Giorgos Korfiatis
            self.stdout.write("\n")
177 d14155e3 Giorgos Korfiatis
            if fix:
178 d14155e3 Giorgos Korfiatis
                if dangerous and not force:
179 d14155e3 Giorgos Korfiatis
                    write("You are enforcing resources that may permanently "
180 d14155e3 Giorgos Korfiatis
                          "remove a vm.\n")
181 d14155e3 Giorgos Korfiatis
                    self.confirm()
182 d14155e3 Giorgos Korfiatis
                write("Applying actions. Please wait...\n")
183 d14155e3 Giorgos Korfiatis
            title = "Applied Actions" if fix else "Suggested Actions"
184 6aa9924d Giorgos Korfiatis
            log = enforce.perform_actions(actions, maxops=maxops, fix=fix)
185 6aa9924d Giorgos Korfiatis
            headers = ("Type", "ID", "State", "Backend", "Action", "Violation")
186 d14155e3 Giorgos Korfiatis
            if fix:
187 d14155e3 Giorgos Korfiatis
                headers += ("Result",)
188 4220c336 Giorgos Korfiatis
            pprint_table(self.stdout, log, headers,
189 d14155e3 Giorgos Korfiatis
                         options["output_format"], title=title)