Revision f600b74e

b/snf-cyclades-app/synnefo/quotas/enforce.py
155 155
        ip_actions[ip.id] = viol_id, state, backend_id, "REMOVE"
156 156

  
157 157

  
158
def get_vms(users=None):
158
def get_vms(users=None, projects=None):
159 159
    vms = VirtualMachine.objects.filter(deleted=False).\
160 160
        select_related("flavor").order_by('-id')
161 161
    if users is not None:
162 162
        vms = vms.filter(userid__in=users)
163
    if projects is not None:
164
        vms = vms.filter(project__in=projects)
163 165

  
164
    return _partition_by(lambda vm: vm.userid, vms)
166
    vmsdict = _partition_by(lambda vm: vm.project, vms)
167
    for project, projectdict in vmsdict.iteritems():
168
        vmsdict[project] = _partition_by(lambda vm: vm.userid, projectdict)
169
    return vmsdict
165 170

  
166 171

  
167
def get_floating_ips(users=None):
172
def get_floating_ips(users=None, projects=None):
168 173
    ips = IPAddress.objects.filter(deleted=False, floating_ip=True).\
169 174
        select_related("nic__machine")
170 175
    if users is not None:
171 176
        ips = ips.filter(userid__in=users)
177
    if projects is not None:
178
        ips = ips.filter(project__in=projects)
172 179

  
173
    return _partition_by(lambda ip: ip.userid, ips)
180
    ipsdict = _partition_by(lambda ip: ip.project, ips)
181
    for project, projectdict in ipsdict.iteritems():
182
        ipsdict[project] = _partition_by(lambda ip: ip.userid, projectdict)
183
    return ipsdict
174 184

  
175 185

  
176
def get_actual_resources(resource_type, users=None):
186
def get_actual_resources(resource_type, users=None, projects=None):
177 187
    ACTUAL_RESOURCES = {
178 188
        "vm": get_vms,
179 189
        "floating_ip": get_floating_ips,
180 190
        }
181
    return ACTUAL_RESOURCES[resource_type](users=users)
191
    return ACTUAL_RESOURCES[resource_type](users=users, projects=projects)
192

  
193

  
194
def skip_check(obj, to_check=None, excluded=None):
195
    return (to_check is not None and obj not in to_check or
196
            excluded is not None and obj in excluded)
197

  
198

  
199
def pick_project_resources(project_dict, users=None, excluded_users=None):
200
    resources = []
201
    for user, user_resources in project_dict.iteritems():
202
        if skip_check(user, users, excluded_users):
203
            continue
204
        resources += user_resources
205
    return resources
182 206

  
183 207

  
184 208
VM_ACTION = {
b/snf-cyclades-app/synnefo/quotas/management/commands/enforce-resources-cyclades.py
60 60
                          "of users, e.g uuid1,uuid2")),
61 61
        make_option("--exclude-users",
62 62
                    help=("Exclude list of users from resource enforcement")),
63
        make_option("--projects",
64
                    help=("Enforce resources only for the specified list "
65
                          "of projects, e.g uuid1,uuid2")),
66
        make_option("--exclude-projects",
67
                    help=("Exclude list of projects from resource enforcement")
68
                    ),
63 69
        make_option("--resources",
64 70
                    help="Specify resources to check, default: %s" %
65 71
                    ",".join(DEFAULT_RESOURCES)),
......
110 116
        write = self.stderr.write
111 117
        fix = options["fix"]
112 118
        force = options["force"]
119
        handlers = self.get_handlers(options["resources"])
113 120
        maxops = options["max_operations"]
114 121
        if maxops is not None:
115 122
            try:
......
126 133
                m = "Expected integer shutdown timeout."
127 134
                raise CommandError(m)
128 135

  
129
        users = options['users']
130
        if users is not None:
131
            users = users.split(',')
136
        excluded_users = options['exclude_users']
137
        excluded_users = set(excluded_users.split(',')
138
                             if excluded_users is not None else [])
132 139

  
133
        excluded = options['exclude_users']
134
        excluded = set(excluded.split(',') if excluded is not None else [])
140
        users_to_check = options['users']
141
        if users_to_check is not None:
142
            users_to_check = set(users_to_check.split(',')) - excluded_users
143

  
144
        try:
145
            qh_holdings = util.get_qh_users_holdings(users_to_check)
146
        except errors.AstakosClientException as e:
147
            raise CommandError(e)
148

  
149
        excluded_projects = options["exclude_projects"]
150
        excluded_projects = set(excluded_projects.split(',')
151
                                if excluded_projects is not None else [])
152

  
153
        projects_to_check = options["projects"]
154
        if projects_to_check is not None:
155
            projects_to_check = set(projects_to_check.split(',')) - \
156
                excluded_projects
135 157

  
136
        handlers = self.get_handlers(options["resources"])
137 158
        try:
138
            qh_holdings = util.get_qh_users_holdings(users)
159
            qh_project_holdings = util.get_qh_project_holdings(
160
                projects_to_check)
139 161
        except errors.AstakosClientException as e:
140 162
            raise CommandError(e)
141 163

  
164
        qh_project_holdings = sorted(qh_project_holdings.items())
142 165
        qh_holdings = sorted(qh_holdings.items())
143 166
        resources = set(h[0] for h in handlers)
144 167
        dangerous = bool(resources.difference(DEFAULT_RESOURCES))
......
147 170
        actions = {}
148 171
        overlimit = []
149 172
        viol_id = 0
173

  
174
        for resource, handle_resource, resource_type in handlers:
175
            if resource_type not in actions:
176
                actions[resource_type] = OrderedDict()
177
            actual_resources = enforce.get_actual_resources(
178
                resource_type, projects=projects_to_check)
179
            for project, project_quota in qh_project_holdings:
180
                if enforce.skip_check(project, projects_to_check,
181
                                      excluded_projects):
182
                    continue
183
                try:
184
                    qh = util.transform_project_quotas(project_quota)
185
                    qh_value, qh_limit, qh_pending = qh[resource]
186
                except KeyError:
187
                    write("Resource '%s' does not exist in Quotaholder"
188
                          " for project '%s'!\n" %
189
                          (resource, project))
190
                    continue
191
                if qh_pending:
192
                    write("Pending commission for project '%s', "
193
                          "resource '%s'. Skipping\n" %
194
                          (project, resource))
195
                    continue
196
                diff = qh_value - qh_limit
197
                if diff > 0:
198
                    viol_id += 1
199
                    overlimit.append((viol_id, "project", project, "",
200
                                      resource, qh_limit, qh_value))
201
                    relevant_resources = enforce.pick_project_resources(
202
                        actual_resources[project], users=users_to_check,
203
                        excluded_users=excluded_users)
204
                    handle_resource(viol_id, resource, relevant_resources,
205
                                    diff, actions)
206

  
150 207
        for resource, handle_resource, resource_type in handlers:
151 208
            if resource_type not in actions:
152 209
                actions[resource_type] = OrderedDict()
153 210
            actual_resources = enforce.get_actual_resources(resource_type,
154
                                                            users)
211
                                                            users_to_check)
155 212
            for user, user_quota in qh_holdings:
156
                if user in excluded:
213
                if enforce.skip_check(user, users_to_check, excluded_users):
157 214
                    continue
158 215
                for source, source_quota in user_quota.iteritems():
216
                    if enforce.skip_check(source, projects_to_check,
217
                                          excluded_projects):
218
                        continue
159 219
                    try:
160 220
                        qh = util.transform_quotas(source_quota)
161 221
                        qh_value, qh_limit, qh_pending = qh[resource]
......
172 232
                    diff = qh_value - qh_limit
173 233
                    if diff > 0:
174 234
                        viol_id += 1
175
                        overlimit.append((viol_id, user, source, resource,
176
                                          qh_limit, qh_value))
177
                        relevant_resources = actual_resources[user]
235
                        overlimit.append((viol_id, "user", user, source,
236
                                          resource, qh_limit, qh_value))
237
                        relevant_resources = actual_resources[source][user]
178 238
                        handle_resource(viol_id, resource, relevant_resources,
179 239
                                        diff, actions)
180 240

  
......
182 242
            write("No violations.\n")
183 243
            return
184 244

  
185
        headers = ("#", "User", "Source", "Resource", "Limit", "Usage")
245
        headers = ("#", "Type", "Holder", "Source", "Resource", "Limit",
246
                   "Usage")
186 247
        pprint_table(self.stdout, overlimit, headers,
187 248
                     options["output_format"], title="Violations")
188 249

  
b/snf-cyclades-app/synnefo/quotas/util.py
123 123
    return qs
124 124

  
125 125

  
126
def get_qh_project_holdings(projects=None):
127
    qh = Quotaholder.get()
128
    if projects is None or len(projects) != 1:
129
        req = None
130
    else:
131
        req = projects[0]
132
    quotas = qh.service_get_project_quotas(req)
133

  
134
    if projects is None:
135
        return quotas
136

  
137
    qs = {}
138
    for project in projects:
139
        try:
140
            qs[project] = quotas[project]
141
        except KeyError:
142
            pass
143
    return qs
144

  
145

  
126 146
def transform_quotas(quotas):
127 147
    d = {}
128 148
    for resource, counters in quotas.iteritems():
......
131 151
        pending = counters['pending']
132 152
        d[resource] = (used, limit, pending)
133 153
    return d
154

  
155

  
156
def transform_project_quotas(quotas):
157
    d = {}
158
    for resource, counters in quotas.iteritems():
159
        used = counters['project_usage']
160
        limit = counters['project_limit']
161
        pending = counters['project_pending']
162
        d[resource] = (used, limit, pending)
163
    return d

Also available in: Unified diff