Skip to content

Commit e5ed352

Browse files
committed
Allow adding default labels to Openshift allocations
All Openshift projects created through Coldfront will now have an additional label: `'nerc.mghpcc.org/allow-unencrypted-routes': "true"` `validate_allocations` has also been changed to ensure all current Openshift projects contain a few default labels: ``` PROJECT_DEFAULT_LABELS = { 'opendatahub.io/dashboard': "true", 'modelmesh-enabled': "true", 'nerc.mghpcc.org/allow-unencrypted-routes': "true" } ``` Implementing this required code in the Openshift allocator to interact with the Namespace API. For reasons not entirely clear in the documentation, it is not possible change a Project’s labels directly. This is only possible through the Namespace API.
1 parent c9ef7a1 commit e5ed352

File tree

3 files changed

+69
-5
lines changed

3 files changed

+69
-5
lines changed

src/coldfront_plugin_cloud/management/commands/validate_allocations.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,22 @@ def sync_users(project_id, allocation, allocator, apply):
5252

5353
return failed_validation
5454

55+
@staticmethod
56+
def sync_openshift_project_labels(project_id, allocator, apply):
57+
cloud_namespace_obj = allocator._openshift_get_namespace(project_id)
58+
cloud_namespace_obj_labels = cloud_namespace_obj["metadata"]["labels"]
59+
if missing_or_incorrect_labels := [
60+
label_items[0] for label_items in openshift.PROJECT_DEFAULT_LABELS.items() if
61+
label_items not in cloud_namespace_obj_labels.items()
62+
]:
63+
logger.warning(
64+
f"Openshift project {project_id} is missing default labels: {', '.join(missing_or_incorrect_labels)}"
65+
)
66+
cloud_namespace_obj_labels.update(openshift.PROJECT_DEFAULT_LABELS)
67+
if apply:
68+
allocator.patch_project(project_id, cloud_namespace_obj)
69+
logger.warning(f"Labels updated for Openshift project {project_id}: {', '.join(missing_or_incorrect_labels)}")
70+
5571
def check_institution_specific_code(self, allocation, apply):
5672
attr = attributes.ALLOCATION_INSTITUTION_SPECIFIC_CODE
5773
isc = allocation.get_attribute(attr)
@@ -183,6 +199,7 @@ def handle(self, *args, **options):
183199
quota = allocator.get_quota(project_id)
184200

185201
failed_validation = Command.sync_users(project_id, allocation, allocator, options["apply"])
202+
Command.sync_openshift_project_labels(project_id, allocator, options["apply"])
186203

187204
for attr in tasks.get_expected_attributes(allocator):
188205
key_with_lambda = allocator.QUOTA_KEY_MAPPING.get(attr, None)

src/coldfront_plugin_cloud/openshift.py

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@
2727
"uid",
2828
]
2929

30+
31+
PROJECT_DEFAULT_LABELS = {
32+
'opendatahub.io/dashboard': "true",
33+
'modelmesh-enabled': "true",
34+
'nerc.mghpcc.org/allow-unencrypted-routes': "true"
35+
}
36+
37+
3038
def clean_openshift_metadata(obj):
3139
if "metadata" in obj:
3240
for attr in IGNORED_ATTRIBUTES:
@@ -146,6 +154,9 @@ def create_project(self, suggested_project_name):
146154
self._create_project(project_name, project_id)
147155
return self.Project(project_name, project_id)
148156

157+
def patch_project(self, project_id, new_project_spec):
158+
self._openshift_patch_namespace(project_id, new_project_spec)
159+
149160
def delete_moc_quotas(self, project_id):
150161
"""deletes all resourcequotas from an openshift project"""
151162
resourcequotas = self._openshift_get_resourcequotas(project_id)
@@ -238,14 +249,10 @@ def _create_project(self, project_name, project_id):
238249
headers = {"Content-type": "application/json"}
239250
annotations = {"cf_project_id": str(self.allocation.project_id),
240251
"cf_pi": self.allocation.project.pi.username}
241-
labels = {
242-
'opendatahub.io/dashboard': "true",
243-
'modelmesh-enabled': "true",
244-
}
245252

246253
payload = {"displayName": project_name,
247254
"annotations": annotations,
248-
"labels": labels}
255+
"labels": PROJECT_DEFAULT_LABELS}
249256
r = self.session.put(url, data=json.dumps(payload), headers=headers)
250257
self.check_response(r)
251258

@@ -323,6 +330,15 @@ def _openshift_useridentitymapping_exists(self, user_name, id_user):
323330
def _openshift_get_project(self, project_name):
324331
api = self.get_resource_api(API_PROJECT, "Project")
325332
return clean_openshift_metadata(api.get(name=project_name).to_dict())
333+
334+
def _openshift_get_namespace(self, namespace_name):
335+
api = self.get_resource_api(API_CORE, "Namespace")
336+
return clean_openshift_metadata(api.get(name=namespace_name).to_dict())
337+
338+
def _openshift_patch_namespace(self, project_name, new_project_spec):
339+
# During testing, apparently we can't patch Projects, but we can do so with Namespaces
340+
api = self.get_resource_api(API_CORE, "Namespace")
341+
res = api.patch(name=project_name, body=new_project_spec)
326342

327343
def _openshift_get_resourcequotas(self, project_id):
328344
"""Returns a list of resourcequota objects in namespace with name `project_id`"""

src/coldfront_plugin_cloud/tests/functional/openshift/test_allocation.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,3 +214,34 @@ def test_reactivate_allocation(self):
214214
})
215215

216216
allocator._get_role(user.username, project_id)
217+
218+
def test_project_default_labels(self):
219+
user = self.new_user()
220+
project = self.new_project(pi=user)
221+
allocation = self.new_allocation(project, self.resource, 1)
222+
allocator = openshift.OpenShiftResourceAllocator(self.resource,
223+
allocation)
224+
225+
tasks.activate_allocation(allocation.pk)
226+
allocation.refresh_from_db()
227+
228+
project_id = allocation.get_attribute(attributes.ALLOCATION_PROJECT_ID)
229+
230+
# Check project labels
231+
namespace_dict_labels = allocator._openshift_get_namespace(project_id)["metadata"]["labels"]
232+
self.assertTrue(namespace_dict_labels.items() > openshift.PROJECT_DEFAULT_LABELS.items())
233+
234+
# What if we have a new custom label, or changed value?
235+
openshift.PROJECT_DEFAULT_LABELS["test"] = "test"
236+
call_command('validate_allocations', apply=True)
237+
238+
namespace_dict_labels = allocator._openshift_get_namespace(project_id)["metadata"]["labels"]
239+
self.assertTrue(namespace_dict_labels.items() > openshift.PROJECT_DEFAULT_LABELS.items())
240+
241+
# What if a deafult label is removed (or cloud label
242+
# already has other unrelated labels)? Cloud label should still remain
243+
del openshift.PROJECT_DEFAULT_LABELS["test"]
244+
call_command('validate_allocations', apply=True)
245+
namespace_dict_labels = allocator._openshift_get_namespace(project_id)["metadata"]["labels"]
246+
self.assertTrue(namespace_dict_labels.items() > {"test": "test"}.items())
247+
self.assertTrue(namespace_dict_labels.items() > openshift.PROJECT_DEFAULT_LABELS.items())

0 commit comments

Comments
 (0)