Revision 6aa9924d
b/snf-cyclades-app/synnefo/quotas/enforce.py | ||
---|---|---|
100 | 100 |
diff -= CHANGE[resource](vm) |
101 | 101 |
if vm_actions.get(vm.id) is None: |
102 | 102 |
action = "REMOVE" if vm.operstate == "ERROR" else "SHUTDOWN" |
103 |
vm_actions[vm.id] = viol_id, vm.operstate, action |
|
103 |
vm_actions[vm.id] = viol_id, vm.operstate, vm.backend_id, action
|
|
104 | 104 |
|
105 | 105 |
|
106 | 106 |
def handle_destroy(viol_id, resource, vms, diff, actions): |
... | ... | |
110 | 110 |
if diff < 1: |
111 | 111 |
break |
112 | 112 |
diff -= CHANGE[resource](vm) |
113 |
vm_actions[vm.id] = viol_id, vm.operstate, "REMOVE" |
|
113 |
vm_actions[vm.id] = viol_id, vm.operstate, vm.backend_id, "REMOVE"
|
|
114 | 114 |
|
115 | 115 |
|
116 | 116 |
def _state_after_action(vm, action): |
... | ... | |
121 | 121 |
return vm.operstate # no action |
122 | 122 |
|
123 | 123 |
|
124 |
def _maybe_action(tpl): |
|
125 |
if tpl is None: |
|
126 |
return None |
|
127 |
return tpl[-1] |
|
128 |
|
|
129 |
|
|
124 | 130 |
def sort_ips(vm_actions): |
125 | 131 |
def f(ip): |
126 | 132 |
if not ip.in_use(): |
127 | 133 |
level = 5 |
128 | 134 |
else: |
129 | 135 |
machine = ip.nic.machine |
130 |
_, _, action = vm_actions.get(machine.id, (None, None, None))
|
|
136 |
action = _maybe_action(vm_actions.get(machine.id))
|
|
131 | 137 |
level = VM_SORT_LEVEL[_state_after_action(machine, action)] |
132 | 138 |
return (level, ip.id) |
133 | 139 |
return f |
... | ... | |
142 | 148 |
break |
143 | 149 |
diff -= CHANGE[resource](ip) |
144 | 150 |
state = "USED" if ip.in_use() else "FREE" |
145 |
ip_actions[ip.id] = viol_id, state, "REMOVE" |
|
151 |
if ip.nic and ip.nic.machine: |
|
152 |
backend_id = ip.nic.machine.backend_id |
|
153 |
else: |
|
154 |
backend_id = None |
|
155 |
ip_actions[ip.id] = viol_id, state, backend_id, "REMOVE" |
|
146 | 156 |
|
147 | 157 |
|
148 | 158 |
def get_vms(users=None): |
... | ... | |
186 | 196 |
return False |
187 | 197 |
|
188 | 198 |
|
189 |
def perform_vm_actions(actions, fix=False): |
|
199 |
def allow_operation(backend_id, opcount, maxops): |
|
200 |
if backend_id is None or maxops is None: |
|
201 |
return True |
|
202 |
backend_ops = opcount.get(backend_id, 0) |
|
203 |
if backend_ops >= maxops: |
|
204 |
return False |
|
205 |
opcount[backend_id] = backend_ops + 1 |
|
206 |
return True |
|
207 |
|
|
208 |
|
|
209 |
def perform_vm_actions(actions, opcount, maxops=None, fix=False): |
|
190 | 210 |
log = [] |
191 |
for vm_id, (viol_id, state, vm_action) in actions.iteritems(): |
|
192 |
data = ("vm", vm_id, state, vm_action, viol_id) |
|
211 |
for vm_id, (viol_id, state, backend_id, vm_action) in actions.iteritems(): |
|
212 |
if not allow_operation(backend_id, opcount, maxops): |
|
213 |
continue |
|
214 |
data = ("vm", vm_id, state, backend_id, vm_action, viol_id) |
|
193 | 215 |
if fix: |
194 | 216 |
r = apply_to_vm(vm_action, vm_id) |
195 | 217 |
data += ("DONE" if r else "FAILED",) |
... | ... | |
225 | 247 |
return False |
226 | 248 |
|
227 | 249 |
|
228 |
def perform_floating_ip_actions(actions, fix=False): |
|
250 |
def perform_floating_ip_actions(actions, opcount, maxops=None, fix=False):
|
|
229 | 251 |
log = [] |
230 |
for ip_id, (viol_id, state, ip_action) in actions.iteritems(): |
|
231 |
data = ("floating_ip", ip_id, state, ip_action, viol_id) |
|
252 |
for ip_id, (viol_id, state, backend_id, ip_action) in actions.iteritems(): |
|
253 |
if not allow_operation(backend_id, opcount, maxops): |
|
254 |
continue |
|
255 |
data = ("floating_ip", ip_id, state, backend_id, ip_action, viol_id) |
|
232 | 256 |
if ip_action == "REMOVE": |
233 | 257 |
if fix: |
234 | 258 |
r = remove_ip(ip_id) |
... | ... | |
237 | 261 |
return log |
238 | 262 |
|
239 | 263 |
|
240 |
def perform_actions(actions, fix=False): |
|
264 |
def perform_actions(actions, maxops=None, fix=False):
|
|
241 | 265 |
ACTION_HANDLING = [ |
242 | 266 |
("floating_ip", perform_floating_ip_actions), |
243 | 267 |
("vm", perform_vm_actions), |
244 | 268 |
] |
245 | 269 |
|
270 |
opcount = {} |
|
246 | 271 |
logs = [] |
247 | 272 |
for resource_type, handler in ACTION_HANDLING: |
248 | 273 |
t_actions = actions.get(resource_type, {}) |
249 |
log = handler(t_actions, fix=fix) |
|
274 |
log = handler(t_actions, opcount, maxops=maxops, fix=fix)
|
|
250 | 275 |
logs += log |
251 | 276 |
return logs |
252 | 277 |
|
b/snf-cyclades-app/synnefo/quotas/management/commands/enforce-resources-cyclades.py | ||
---|---|---|
35 | 35 |
from optparse import make_option |
36 | 36 |
from django.db import transaction |
37 | 37 |
|
38 |
from synnefo.lib.ordereddict import OrderedDict |
|
38 | 39 |
from synnefo.quotas import util |
39 | 40 |
from synnefo.quotas import enforce |
40 | 41 |
from synnefo.quotas import errors |
... | ... | |
52 | 53 |
help = """Check and fix quota violations for Cyclades resources. |
53 | 54 |
""" |
54 | 55 |
option_list = SynnefoCommand.option_list + ( |
56 |
make_option("--max-operations", |
|
57 |
help="Limit operations per backend."), |
|
55 | 58 |
make_option("--users", dest="users", |
56 | 59 |
help=("Enforce resources only for the specified list " |
57 | 60 |
"of users, e.g uuid1,uuid2")), |
... | ... | |
100 | 103 |
write = self.stderr.write |
101 | 104 |
fix = options["fix"] |
102 | 105 |
force = options["force"] |
106 |
maxops = options["max_operations"] |
|
107 |
if maxops is not None: |
|
108 |
try: |
|
109 |
maxops = int(maxops) |
|
110 |
except ValueError: |
|
111 |
m = "Expected integer max operations." |
|
112 |
raise CommandError(m) |
|
103 | 113 |
|
104 | 114 |
users = options['users'] |
105 | 115 |
if users is not None: |
... | ... | |
111 | 121 |
except errors.AstakosClientException as e: |
112 | 122 |
raise CommandError(e) |
113 | 123 |
|
124 |
qh_holdings = sorted(qh_holdings.items()) |
|
114 | 125 |
resources = set(h[0] for h in handlers) |
115 | 126 |
dangerous = bool(resources.difference(DEFAULT_RESOURCES)) |
116 | 127 |
|
... | ... | |
119 | 130 |
viol_id = 0 |
120 | 131 |
for resource, handle_resource, resource_type in handlers: |
121 | 132 |
if resource_type not in actions: |
122 |
actions[resource_type] = {}
|
|
133 |
actions[resource_type] = OrderedDict()
|
|
123 | 134 |
actual_resources = enforce.get_actual_resources(resource_type, |
124 | 135 |
users) |
125 |
for user, user_quota in qh_holdings.iteritems():
|
|
136 |
for user, user_quota in qh_holdings: |
|
126 | 137 |
for source, source_quota in user_quota.iteritems(): |
127 | 138 |
try: |
128 | 139 |
qh = util.transform_quotas(source_quota) |
... | ... | |
163 | 174 |
self.confirm() |
164 | 175 |
write("Applying actions. Please wait...\n") |
165 | 176 |
title = "Applied Actions" if fix else "Suggested Actions" |
166 |
log = enforce.perform_actions(actions, fix=fix) |
|
167 |
headers = ("Type", "ID", "State", "Action", "Violation") |
|
177 |
log = enforce.perform_actions(actions, maxops=maxops, fix=fix)
|
|
178 |
headers = ("Type", "ID", "State", "Backend", "Action", "Violation")
|
|
168 | 179 |
if fix: |
169 | 180 |
headers += ("Result",) |
170 | 181 |
pprint_table(self.stderr, log, headers, |
Also available in: Unified diff