Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (11.2 kB)

1 ff5edb80 Giorgos Korfiatis
# Copyright 2013-2014 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 fa532396 Christos Stavrakakis
56 fa532396 Christos Stavrakakis
    command_option_list = (
57 6aa9924d Giorgos Korfiatis
        make_option("--max-operations",
58 6aa9924d Giorgos Korfiatis
                    help="Limit operations per backend."),
59 d14155e3 Giorgos Korfiatis
        make_option("--users", dest="users",
60 d14155e3 Giorgos Korfiatis
                    help=("Enforce resources only for the specified list "
61 d14155e3 Giorgos Korfiatis
                          "of users, e.g uuid1,uuid2")),
62 12e8c717 Giorgos Korfiatis
        make_option("--exclude-users",
63 12e8c717 Giorgos Korfiatis
                    help=("Exclude list of users from resource enforcement")),
64 f600b74e Giorgos Korfiatis
        make_option("--projects",
65 f600b74e Giorgos Korfiatis
                    help=("Enforce resources only for the specified list "
66 f600b74e Giorgos Korfiatis
                          "of projects, e.g uuid1,uuid2")),
67 f600b74e Giorgos Korfiatis
        make_option("--exclude-projects",
68 f600b74e Giorgos Korfiatis
                    help=("Exclude list of projects from resource enforcement")
69 f600b74e Giorgos Korfiatis
                    ),
70 d14155e3 Giorgos Korfiatis
        make_option("--resources",
71 d14155e3 Giorgos Korfiatis
                    help="Specify resources to check, default: %s" %
72 d14155e3 Giorgos Korfiatis
                    ",".join(DEFAULT_RESOURCES)),
73 d14155e3 Giorgos Korfiatis
        make_option("--fix",
74 d14155e3 Giorgos Korfiatis
                    default=False,
75 d14155e3 Giorgos Korfiatis
                    action="store_true",
76 d14155e3 Giorgos Korfiatis
                    help="Fix violations"),
77 d14155e3 Giorgos Korfiatis
        make_option("--force",
78 d14155e3 Giorgos Korfiatis
                    default=False,
79 d14155e3 Giorgos Korfiatis
                    action="store_true",
80 d14155e3 Giorgos Korfiatis
                    help=("Confirm actions that may permanently "
81 d14155e3 Giorgos Korfiatis
                          "remove a vm")),
82 29e3919d Giorgos Korfiatis
        make_option("--shutdown-timeout",
83 29e3919d Giorgos Korfiatis
                    help="Force vm shutdown after given seconds."),
84 d14155e3 Giorgos Korfiatis
    )
85 d14155e3 Giorgos Korfiatis
86 d14155e3 Giorgos Korfiatis
    def confirm(self):
87 d9a7f0bb Giorgos Korfiatis
        self.stdout.write("Confirm? [y/N] ")
88 d56fa78c Giorgos Korfiatis
        try:
89 d56fa78c Giorgos Korfiatis
            response = raw_input()
90 d56fa78c Giorgos Korfiatis
        except EOFError:
91 d56fa78c Giorgos Korfiatis
            response = "ABORT"
92 d14155e3 Giorgos Korfiatis
        if string.lower(response) not in ['y', 'yes']:
93 d9a7f0bb Giorgos Korfiatis
            self.stderr.write("Aborted.\n")
94 d14155e3 Giorgos Korfiatis
            exit()
95 d14155e3 Giorgos Korfiatis
96 d14155e3 Giorgos Korfiatis
    def get_handlers(self, resources):
97 d14155e3 Giorgos Korfiatis
        def rem(v):
98 d14155e3 Giorgos Korfiatis
            try:
99 d14155e3 Giorgos Korfiatis
                resources.remove(v)
100 d14155e3 Giorgos Korfiatis
                return True
101 d14155e3 Giorgos Korfiatis
            except ValueError:
102 d14155e3 Giorgos Korfiatis
                return False
103 d14155e3 Giorgos Korfiatis
104 d14155e3 Giorgos Korfiatis
        if resources is None:
105 d14155e3 Giorgos Korfiatis
            resources = list(DEFAULT_RESOURCES)
106 d14155e3 Giorgos Korfiatis
        else:
107 d14155e3 Giorgos Korfiatis
            resources = resources.split(",")
108 d14155e3 Giorgos Korfiatis
109 d14155e3 Giorgos Korfiatis
        handlers = [h for h in enforce.RESOURCE_HANDLING if rem(h[0])]
110 d14155e3 Giorgos Korfiatis
        if resources:
111 d14155e3 Giorgos Korfiatis
            m = "No such resource '%s'" % resources[0]
112 d14155e3 Giorgos Korfiatis
            raise CommandError(m)
113 d14155e3 Giorgos Korfiatis
        return handlers
114 d14155e3 Giorgos Korfiatis
115 d14155e3 Giorgos Korfiatis
    @transaction.commit_on_success
116 d14155e3 Giorgos Korfiatis
    def handle(self, *args, **options):
117 d14155e3 Giorgos Korfiatis
        write = self.stderr.write
118 d14155e3 Giorgos Korfiatis
        fix = options["fix"]
119 d14155e3 Giorgos Korfiatis
        force = options["force"]
120 f600b74e Giorgos Korfiatis
        handlers = self.get_handlers(options["resources"])
121 6aa9924d Giorgos Korfiatis
        maxops = options["max_operations"]
122 6aa9924d Giorgos Korfiatis
        if maxops is not None:
123 6aa9924d Giorgos Korfiatis
            try:
124 6aa9924d Giorgos Korfiatis
                maxops = int(maxops)
125 6aa9924d Giorgos Korfiatis
            except ValueError:
126 6aa9924d Giorgos Korfiatis
                m = "Expected integer max operations."
127 6aa9924d Giorgos Korfiatis
                raise CommandError(m)
128 d14155e3 Giorgos Korfiatis
129 29e3919d Giorgos Korfiatis
        shutdown_timeout = options["shutdown_timeout"]
130 29e3919d Giorgos Korfiatis
        if shutdown_timeout is not None:
131 29e3919d Giorgos Korfiatis
            try:
132 29e3919d Giorgos Korfiatis
                shutdown_timeout = int(shutdown_timeout)
133 29e3919d Giorgos Korfiatis
            except ValueError:
134 29e3919d Giorgos Korfiatis
                m = "Expected integer shutdown timeout."
135 29e3919d Giorgos Korfiatis
                raise CommandError(m)
136 29e3919d Giorgos Korfiatis
137 f600b74e Giorgos Korfiatis
        excluded_users = options['exclude_users']
138 f600b74e Giorgos Korfiatis
        excluded_users = set(excluded_users.split(',')
139 f600b74e Giorgos Korfiatis
                             if excluded_users is not None else [])
140 d14155e3 Giorgos Korfiatis
141 f600b74e Giorgos Korfiatis
        users_to_check = options['users']
142 f600b74e Giorgos Korfiatis
        if users_to_check is not None:
143 f3bdab04 Giorgos Korfiatis
            users_to_check = list(set(users_to_check.split(',')) -
144 f3bdab04 Giorgos Korfiatis
                                  excluded_users)
145 f600b74e Giorgos Korfiatis
146 f600b74e Giorgos Korfiatis
        try:
147 f600b74e Giorgos Korfiatis
            qh_holdings = util.get_qh_users_holdings(users_to_check)
148 f600b74e Giorgos Korfiatis
        except errors.AstakosClientException as e:
149 f600b74e Giorgos Korfiatis
            raise CommandError(e)
150 f600b74e Giorgos Korfiatis
151 f600b74e Giorgos Korfiatis
        excluded_projects = options["exclude_projects"]
152 f600b74e Giorgos Korfiatis
        excluded_projects = set(excluded_projects.split(',')
153 f600b74e Giorgos Korfiatis
                                if excluded_projects is not None else [])
154 f600b74e Giorgos Korfiatis
155 f600b74e Giorgos Korfiatis
        projects_to_check = options["projects"]
156 f600b74e Giorgos Korfiatis
        if projects_to_check is not None:
157 f3bdab04 Giorgos Korfiatis
            projects_to_check = list(set(projects_to_check.split(',')) -
158 f3bdab04 Giorgos Korfiatis
                                     excluded_projects)
159 12e8c717 Giorgos Korfiatis
160 d14155e3 Giorgos Korfiatis
        try:
161 f600b74e Giorgos Korfiatis
            qh_project_holdings = util.get_qh_project_holdings(
162 f600b74e Giorgos Korfiatis
                projects_to_check)
163 d14155e3 Giorgos Korfiatis
        except errors.AstakosClientException as e:
164 d14155e3 Giorgos Korfiatis
            raise CommandError(e)
165 d14155e3 Giorgos Korfiatis
166 f600b74e Giorgos Korfiatis
        qh_project_holdings = sorted(qh_project_holdings.items())
167 6aa9924d Giorgos Korfiatis
        qh_holdings = sorted(qh_holdings.items())
168 d14155e3 Giorgos Korfiatis
        resources = set(h[0] for h in handlers)
169 d14155e3 Giorgos Korfiatis
        dangerous = bool(resources.difference(DEFAULT_RESOURCES))
170 d14155e3 Giorgos Korfiatis
171 29e3919d Giorgos Korfiatis
        opts = {"shutdown_timeout": shutdown_timeout}
172 d14155e3 Giorgos Korfiatis
        actions = {}
173 d14155e3 Giorgos Korfiatis
        overlimit = []
174 d14155e3 Giorgos Korfiatis
        viol_id = 0
175 f600b74e Giorgos Korfiatis
176 7e4cd6c0 Giorgos Korfiatis
        if users_to_check is None:
177 7e4cd6c0 Giorgos Korfiatis
            for resource, handle_resource, resource_type in handlers:
178 7e4cd6c0 Giorgos Korfiatis
                if resource_type not in actions:
179 7e4cd6c0 Giorgos Korfiatis
                    actions[resource_type] = OrderedDict()
180 7e4cd6c0 Giorgos Korfiatis
                actual_resources = enforce.get_actual_resources(
181 7e4cd6c0 Giorgos Korfiatis
                    resource_type, projects=projects_to_check)
182 7e4cd6c0 Giorgos Korfiatis
                for project, project_quota in qh_project_holdings:
183 7e4cd6c0 Giorgos Korfiatis
                    if enforce.skip_check(project, projects_to_check,
184 7e4cd6c0 Giorgos Korfiatis
                                          excluded_projects):
185 7e4cd6c0 Giorgos Korfiatis
                        continue
186 7e4cd6c0 Giorgos Korfiatis
                    try:
187 7e4cd6c0 Giorgos Korfiatis
                        qh = util.transform_project_quotas(project_quota)
188 7e4cd6c0 Giorgos Korfiatis
                        qh_value, qh_limit, qh_pending = qh[resource]
189 7e4cd6c0 Giorgos Korfiatis
                    except KeyError:
190 7e4cd6c0 Giorgos Korfiatis
                        write("Resource '%s' does not exist in Quotaholder"
191 7e4cd6c0 Giorgos Korfiatis
                              " for project '%s'!\n" %
192 7e4cd6c0 Giorgos Korfiatis
                              (resource, project))
193 7e4cd6c0 Giorgos Korfiatis
                        continue
194 7e4cd6c0 Giorgos Korfiatis
                    if qh_pending:
195 7e4cd6c0 Giorgos Korfiatis
                        write("Pending commission for project '%s', "
196 7e4cd6c0 Giorgos Korfiatis
                              "resource '%s'. Skipping\n" %
197 7e4cd6c0 Giorgos Korfiatis
                              (project, resource))
198 7e4cd6c0 Giorgos Korfiatis
                        continue
199 7e4cd6c0 Giorgos Korfiatis
                    diff = qh_value - qh_limit
200 7e4cd6c0 Giorgos Korfiatis
                    if diff > 0:
201 7e4cd6c0 Giorgos Korfiatis
                        viol_id += 1
202 7e4cd6c0 Giorgos Korfiatis
                        overlimit.append((viol_id, "project", project, "",
203 7e4cd6c0 Giorgos Korfiatis
                                          resource, qh_limit, qh_value))
204 7e4cd6c0 Giorgos Korfiatis
                        relevant_resources = enforce.pick_project_resources(
205 7e4cd6c0 Giorgos Korfiatis
                            actual_resources[project], users=users_to_check,
206 7e4cd6c0 Giorgos Korfiatis
                            excluded_users=excluded_users)
207 7e4cd6c0 Giorgos Korfiatis
                        handle_resource(viol_id, resource, relevant_resources,
208 7e4cd6c0 Giorgos Korfiatis
                                        diff, actions)
209 f600b74e Giorgos Korfiatis
210 d14155e3 Giorgos Korfiatis
        for resource, handle_resource, resource_type in handlers:
211 d14155e3 Giorgos Korfiatis
            if resource_type not in actions:
212 6aa9924d Giorgos Korfiatis
                actions[resource_type] = OrderedDict()
213 d14155e3 Giorgos Korfiatis
            actual_resources = enforce.get_actual_resources(resource_type,
214 f600b74e Giorgos Korfiatis
                                                            users_to_check)
215 6aa9924d Giorgos Korfiatis
            for user, user_quota in qh_holdings:
216 f600b74e Giorgos Korfiatis
                if enforce.skip_check(user, users_to_check, excluded_users):
217 12e8c717 Giorgos Korfiatis
                    continue
218 d14155e3 Giorgos Korfiatis
                for source, source_quota in user_quota.iteritems():
219 f600b74e Giorgos Korfiatis
                    if enforce.skip_check(source, projects_to_check,
220 f600b74e Giorgos Korfiatis
                                          excluded_projects):
221 f600b74e Giorgos Korfiatis
                        continue
222 d14155e3 Giorgos Korfiatis
                    try:
223 d14155e3 Giorgos Korfiatis
                        qh = util.transform_quotas(source_quota)
224 d14155e3 Giorgos Korfiatis
                        qh_value, qh_limit, qh_pending = qh[resource]
225 d14155e3 Giorgos Korfiatis
                    except KeyError:
226 d14155e3 Giorgos Korfiatis
                        write("Resource '%s' does not exist in Quotaholder"
227 d14155e3 Giorgos Korfiatis
                              " for user '%s' and source '%s'!\n" %
228 d14155e3 Giorgos Korfiatis
                              (resource, user, source))
229 d14155e3 Giorgos Korfiatis
                        continue
230 d14155e3 Giorgos Korfiatis
                    if qh_pending:
231 d14155e3 Giorgos Korfiatis
                        write("Pending commission for user '%s', source '%s', "
232 d14155e3 Giorgos Korfiatis
                              "resource '%s'. Skipping\n" %
233 d14155e3 Giorgos Korfiatis
                              (user, source, resource))
234 d14155e3 Giorgos Korfiatis
                        continue
235 d14155e3 Giorgos Korfiatis
                    diff = qh_value - qh_limit
236 d14155e3 Giorgos Korfiatis
                    if diff > 0:
237 d14155e3 Giorgos Korfiatis
                        viol_id += 1
238 f600b74e Giorgos Korfiatis
                        overlimit.append((viol_id, "user", user, source,
239 f600b74e Giorgos Korfiatis
                                          resource, qh_limit, qh_value))
240 f600b74e Giorgos Korfiatis
                        relevant_resources = actual_resources[source][user]
241 d14155e3 Giorgos Korfiatis
                        handle_resource(viol_id, resource, relevant_resources,
242 d14155e3 Giorgos Korfiatis
                                        diff, actions)
243 d14155e3 Giorgos Korfiatis
244 d14155e3 Giorgos Korfiatis
        if not overlimit:
245 d14155e3 Giorgos Korfiatis
            write("No violations.\n")
246 d14155e3 Giorgos Korfiatis
            return
247 d14155e3 Giorgos Korfiatis
248 f600b74e Giorgos Korfiatis
        headers = ("#", "Type", "Holder", "Source", "Resource", "Limit",
249 f600b74e Giorgos Korfiatis
                   "Usage")
250 d9a7f0bb Giorgos Korfiatis
        pprint_table(self.stdout, overlimit, headers,
251 d14155e3 Giorgos Korfiatis
                     options["output_format"], title="Violations")
252 d14155e3 Giorgos Korfiatis
253 d14155e3 Giorgos Korfiatis
        if any(actions.values()):
254 d9a7f0bb Giorgos Korfiatis
            self.stdout.write("\n")
255 d14155e3 Giorgos Korfiatis
            if fix:
256 d14155e3 Giorgos Korfiatis
                if dangerous and not force:
257 d14155e3 Giorgos Korfiatis
                    write("You are enforcing resources that may permanently "
258 d14155e3 Giorgos Korfiatis
                          "remove a vm.\n")
259 d14155e3 Giorgos Korfiatis
                    self.confirm()
260 d14155e3 Giorgos Korfiatis
                write("Applying actions. Please wait...\n")
261 d14155e3 Giorgos Korfiatis
            title = "Applied Actions" if fix else "Suggested Actions"
262 29e3919d Giorgos Korfiatis
            log = enforce.perform_actions(actions, maxops=maxops, fix=fix,
263 29e3919d Giorgos Korfiatis
                                          options=opts)
264 6aa9924d Giorgos Korfiatis
            headers = ("Type", "ID", "State", "Backend", "Action", "Violation")
265 d14155e3 Giorgos Korfiatis
            if fix:
266 d14155e3 Giorgos Korfiatis
                headers += ("Result",)
267 d9a7f0bb Giorgos Korfiatis
            pprint_table(self.stdout, log, headers,
268 d14155e3 Giorgos Korfiatis
                         options["output_format"], title=title)