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