Skip to content

Commit 30236f0

Browse files
committed
Refactored validate_allocations to be resource-agnostic
Quota validation will now behave the same for both resource types. OpenStack's particular use of default quotas is reflected in a new test in `openstack/test_allocation.py` OpenStack integration code is slightly changed to better handle missing object storage quotas Much of the validation logic has been pushed into `base.py`, `openshift.py`, and `openstack.py`
1 parent 0bfb505 commit 30236f0

7 files changed

Lines changed: 315 additions & 286 deletions

File tree

src/coldfront_plugin_cloud/base.py

Lines changed: 102 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
import abc
22
import functools
33
import json
4+
import logging
45
from typing import NamedTuple
56

67
from coldfront.core.allocation import models as allocation_models
78
from coldfront.core.resource import models as resource_models
89

9-
from coldfront_plugin_cloud import attributes
10+
from coldfront_plugin_cloud import attributes, utils
1011
from coldfront_plugin_cloud.models.quota_models import QuotaSpecs
1112

1213

14+
logger = logging.getLogger(__name__)
15+
16+
1317
class ResourceAllocator(abc.ABC):
1418
resource_type = ""
1519

@@ -45,6 +49,94 @@ def get_or_create_federated_user(self, username):
4549
user = self.create_federated_user(username)
4650
return user
4751

52+
def set_default_quota_on_allocation(self, coldfront_attr):
53+
resource_quotaspecs = self.resource_quotaspecs
54+
value = resource_quotaspecs.root[coldfront_attr].quota_by_su_quantity(
55+
self.allocation.quantity
56+
)
57+
utils.set_attribute_on_allocation(self.allocation, coldfront_attr, value)
58+
return value
59+
60+
def set_users(self, project_id, apply):
61+
coldfront_users = allocation_models.AllocationUser.objects.filter(
62+
allocation=self.allocation, status__name="Active"
63+
)
64+
cluster_users = self.get_users(project_id)
65+
failed_validation = False
66+
67+
# Create users that exist in coldfront but not in the resource
68+
for coldfront_user in coldfront_users:
69+
coldfront_username = coldfront_user.user.username
70+
if coldfront_username not in cluster_users:
71+
failed_validation = True
72+
logger.info(f"{coldfront_username} is not part of {project_id}")
73+
if apply:
74+
self.get_or_create_federated_user(coldfront_username)
75+
self.assign_role_on_user(coldfront_username, project_id)
76+
77+
# remove users that are in the resource but not in coldfront
78+
users = set(
79+
[coldfront_user.user.username for coldfront_user in coldfront_users]
80+
)
81+
for allocation_user in cluster_users:
82+
if allocation_user not in users:
83+
failed_validation = True
84+
logger.info(
85+
f"{allocation_user} exists in the resource {project_id} but not in coldfront"
86+
)
87+
if apply:
88+
self.remove_role_from_user(allocation_user, project_id)
89+
90+
return failed_validation
91+
92+
def check_and_apply_quota_attr(
93+
self,
94+
attr: str,
95+
expected_quota: int | None,
96+
current_quota: int | None,
97+
apply: bool,
98+
) -> bool:
99+
failed_validation = False
100+
if current_quota is None and expected_quota is None:
101+
msg = (
102+
f"Value for quota for {attr} is not set anywhere"
103+
f" on {self.allocation_str}"
104+
)
105+
failed_validation = True
106+
107+
if apply:
108+
expected_quota = self.set_default_quota_on_allocation(attr)
109+
msg = f"Added default quota for {attr} to {self.allocation_str} to {expected_quota}"
110+
logger.info(msg)
111+
elif current_quota is not None and expected_quota is None:
112+
msg = (
113+
f'Attribute "{attr}" expected on {self.allocation_str} but not set.'
114+
f" Current quota is {current_quota}."
115+
)
116+
117+
if apply:
118+
utils.set_attribute_on_allocation(self.allocation, attr, current_quota)
119+
120+
# To pass `current_quota != expected_quota` check
121+
expected_quota = current_quota
122+
123+
msg = f"{msg} Attribute set to match current quota."
124+
logger.info(msg)
125+
126+
if current_quota != expected_quota:
127+
msg = (
128+
f"Value for quota for {attr} = {current_quota} does not match expected"
129+
f" value of {expected_quota} on {self.allocation_str}"
130+
)
131+
logger.info(msg)
132+
failed_validation = True
133+
134+
return failed_validation
135+
136+
@functools.cached_property
137+
def allocation_str(self):
138+
return f'allocation {self.allocation.pk} of project "{self.allocation.project.title}"'
139+
48140
@functools.cached_property
49141
def auth_url(self):
50142
return self.resource.get_attribute(attributes.RESOURCE_AUTH_URL).rstrip("/")
@@ -54,7 +146,11 @@ def member_role_name(self):
54146
return self.resource.get_attribute(attributes.RESOURCE_ROLE) or "member"
55147

56148
@abc.abstractmethod
57-
def set_project_configuration(self, project_id, dry_run=False):
149+
def set_project_configuration(self, project_id, apply=True):
150+
pass
151+
152+
@abc.abstractmethod
153+
def get_project(self, project_id):
58154
pass
59155

60156
@abc.abstractmethod
@@ -85,6 +181,10 @@ def get_quota(self, project_id):
85181
def create_federated_user(self, unique_id):
86182
pass
87183

184+
@abc.abstractmethod
185+
def get_users(self, unique_id):
186+
pass
187+
88188
@abc.abstractmethod
89189
def get_federated_user(self, unique_id):
90190
pass

0 commit comments

Comments
 (0)