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