Revision bf644f91 snf-astakos-app/astakos/im/management/commands/resource-modify.py
b/snf-astakos-app/astakos/im/management/commands/resource-modify.py | ||
---|---|---|
1 |
# Copyright 2013 GRNET S.A. All rights reserved. |
|
1 |
# Copyright 2013, 2014 GRNET S.A. All rights reserved.
|
|
2 | 2 |
# |
3 | 3 |
# Redistribution and use in source and binary forms, with or |
4 | 4 |
# without modification, are permitted provided that the following |
... | ... | |
33 | 33 |
|
34 | 34 |
from optparse import make_option |
35 | 35 |
from django.core.management.base import BaseCommand, CommandError |
36 |
from django.utils import simplejson as json |
|
37 | 36 |
|
38 | 37 |
from snf_django.management import utils |
39 | 38 |
from astakos.im.models import Resource |
40 |
from astakos.im.register import update_resources
|
|
41 |
from ._common import show_resource_value, style_options, check_style, units
|
|
39 |
from astakos.im import register
|
|
40 |
from ._common import style_options, check_style, units |
|
42 | 41 |
|
43 | 42 |
|
44 | 43 |
class Command(BaseCommand): |
... | ... | |
46 | 45 |
help = "Modify a resource's default base quota and boolean flags." |
47 | 46 |
|
48 | 47 |
option_list = BaseCommand.option_list + ( |
49 |
make_option('--default-quota',
|
|
48 |
make_option('--base-default',
|
|
50 | 49 |
metavar='<limit>', |
51 | 50 |
help="Specify default base quota"), |
52 |
make_option('--default-quota-interactive', |
|
53 |
action='store_true', |
|
54 |
default=None, |
|
55 |
help=("Prompt user to change default base quota. " |
|
56 |
"If no resource is given, prompts for all " |
|
57 |
"resources.")), |
|
58 |
make_option('--default-quota-from-file', |
|
59 |
metavar='<limits_file.json>', |
|
60 |
help=("Read default base quota from a file. " |
|
61 |
"File should contain a json dict mapping resource " |
|
62 |
"names to limits")), |
|
63 | 51 |
make_option('--unit-style', |
64 | 52 |
default='mb', |
65 | 53 |
help=("Specify display unit for resource values " |
... | ... | |
74 | 62 |
|
75 | 63 |
def handle(self, *args, **options): |
76 | 64 |
resource_name = args[0] if len(args) > 0 else None |
65 |
if resource_name is None: |
|
66 |
raise CommandError("Please provide a resource name.") |
|
67 |
resource = self.get_resource(resource_name) |
|
77 | 68 |
|
78 | 69 |
actions = { |
79 |
'default_quota': self.change_limit, |
|
80 |
'default_quota_interactive': self.change_interactive, |
|
81 |
'default_quota_from_file': self.change_from_file, |
|
70 |
'base_default': self.change_base_default, |
|
82 | 71 |
'api_visible': self.set_api_visible, |
83 | 72 |
'ui_visible': self.set_ui_visible, |
84 | 73 |
} |
... | ... | |
87 | 76 |
for (key, value) in options.items() |
88 | 77 |
if key in actions and value is not None] |
89 | 78 |
|
90 |
if len(opts) != 1: |
|
91 |
raise CommandError("Please provide exactly one of the options: " |
|
92 |
"--default-quota, --default-quota-interactive, " |
|
93 |
"--default-quota-from-file, " |
|
94 |
"--api-visible, --ui-visible.") |
|
95 |
|
|
96 | 79 |
self.unit_style = options['unit_style'] |
97 | 80 |
check_style(self.unit_style) |
98 | 81 |
|
99 |
key, value = opts[0] |
|
100 |
action = actions[key] |
|
101 |
action(resource_name, value) |
|
102 |
|
|
103 |
def set_api_visible(self, resource_name, allow): |
|
104 |
if resource_name is None: |
|
105 |
raise CommandError("Please provide a resource name.") |
|
82 |
for key, value in opts: |
|
83 |
action = actions[key] |
|
84 |
action(resource, value) |
|
106 | 85 |
|
86 |
def set_api_visible(self, resource, allow): |
|
107 | 87 |
try: |
108 | 88 |
allow = utils.parse_bool(allow) |
109 | 89 |
except ValueError: |
110 | 90 |
raise CommandError("Expecting a boolean value.") |
111 |
resource = self.get_resource(resource_name) |
|
112 | 91 |
resource.api_visible = allow |
113 | 92 |
if not allow and resource.ui_visible: |
114 | 93 |
self.stderr.write("Also resetting 'ui_visible' for consistency.\n") |
115 | 94 |
resource.ui_visible = False |
116 | 95 |
resource.save() |
117 | 96 |
|
118 |
def set_ui_visible(self, resource_name, allow): |
|
119 |
if resource_name is None: |
|
120 |
raise CommandError("Please provide a resource name.") |
|
121 |
|
|
97 |
def set_ui_visible(self, resource, allow): |
|
122 | 98 |
try: |
123 | 99 |
allow = utils.parse_bool(allow) |
124 | 100 |
except ValueError: |
125 | 101 |
raise CommandError("Expecting a boolean value.") |
126 |
resource = self.get_resource(resource_name) |
|
127 |
|
|
128 | 102 |
resource.ui_visible = allow |
129 | 103 |
if allow and not resource.api_visible: |
130 | 104 |
self.stderr.write("Also setting 'api_visible' for consistency.\n") |
... | ... | |
138 | 112 |
raise CommandError("Resource %s does not exist." |
139 | 113 |
% resource_name) |
140 | 114 |
|
141 |
def change_limit(self, resource_name, limit): |
|
142 |
if resource_name is None: |
|
143 |
raise CommandError("Please provide a resource name.") |
|
144 |
|
|
145 |
resource = self.get_resource(resource_name) |
|
146 |
self.change_resource_limit(resource, limit) |
|
147 |
|
|
148 |
def change_from_file(self, resource_name, filename): |
|
149 |
with open(filename) as file_data: |
|
150 |
try: |
|
151 |
config = json.load(file_data) |
|
152 |
except json.JSONDecodeError: |
|
153 |
raise CommandError("Malformed JSON file.") |
|
154 |
if not isinstance(config, dict): |
|
155 |
raise CommandError("Malformed JSON file.") |
|
156 |
self.change_with_conf(resource_name, config) |
|
157 |
|
|
158 |
def change_with_conf(self, resource_name, config): |
|
159 |
if resource_name is None: |
|
160 |
resources = Resource.objects.all().select_for_update() |
|
161 |
else: |
|
162 |
resources = [self.get_resource(resource_name)] |
|
163 |
|
|
164 |
updates = [] |
|
165 |
for resource in resources: |
|
166 |
limit = config.get(resource.name) |
|
167 |
if limit is not None: |
|
168 |
limit = self.parse_limit(limit) |
|
169 |
updates.append((resource, limit)) |
|
170 |
if updates: |
|
171 |
update_resources(updates) |
|
172 |
|
|
173 |
def change_interactive(self, resource_name, _placeholder): |
|
174 |
if resource_name is None: |
|
175 |
resources = Resource.objects.all().select_for_update() |
|
176 |
else: |
|
177 |
resources = [self.get_resource(resource_name)] |
|
178 |
|
|
179 |
updates = [] |
|
180 |
for resource in resources: |
|
181 |
self.stdout.write("Resource '%s' (%s)\n" % |
|
182 |
(resource.name, resource.desc)) |
|
183 |
value = show_resource_value(resource.uplimit, resource.name, |
|
184 |
self.unit_style) |
|
185 |
self.stdout.write("Current limit: %s\n" % value) |
|
186 |
while True: |
|
187 |
self.stdout.write("New limit (leave blank to keep current): ") |
|
188 |
try: |
|
189 |
response = raw_input() |
|
190 |
except EOFError: |
|
191 |
self.stderr.write("Aborted.\n") |
|
192 |
exit() |
|
193 |
if response == "": |
|
194 |
break |
|
195 |
else: |
|
196 |
try: |
|
197 |
value = units.parse(response) |
|
198 |
except units.ParseError: |
|
199 |
continue |
|
200 |
updates.append((resource, value)) |
|
201 |
break |
|
202 |
if updates: |
|
203 |
self.stderr.write("Updating...\n") |
|
204 |
update_resources(updates) |
|
115 |
def change_base_default(self, resource, limit): |
|
116 |
limit = self.parse_limit(limit) |
|
117 |
register.update_base_default(resource, limit) |
|
205 | 118 |
|
206 | 119 |
def parse_limit(self, limit): |
207 | 120 |
try: |
208 |
if isinstance(limit, (int, long)): |
|
209 |
return limit |
|
210 |
if isinstance(limit, basestring): |
|
211 |
return units.parse(limit) |
|
212 |
raise units.ParseError() |
|
121 |
return units.parse(limit) |
|
213 | 122 |
except units.ParseError: |
214 |
m = ("Limit should be an integer, optionally followed by a unit,"
|
|
215 |
" or 'inf'.") |
|
123 |
m = ("Quota limit should be an integer, "
|
|
124 |
"optionally followed by a unit, or 'inf'.")
|
|
216 | 125 |
raise CommandError(m) |
217 |
|
|
218 |
def change_resource_limit(self, resource, limit): |
|
219 |
limit = self.parse_limit(limit) |
|
220 |
update_resources([(resource, limit)]) |
Also available in: Unified diff