Skip to content

Commit ae58ba2

Browse files
author
Bhautik Vala
committed
[patch] Merge branch 'stable' into MASR6491
2 parents 70f7da3 + e93c898 commit ae58ba2

File tree

3 files changed

+159
-26
lines changed

3 files changed

+159
-26
lines changed

src/mas/devops/ocp.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,3 +332,68 @@ def execInPod(core_v1_api: client.CoreV1Api, pod_name: str, namespace, command:
332332
logger.debug(f"stdout: \n----------------------------------------------------------------\n{stdout}\n----------------------------------------------------------------\n")
333333

334334
return stdout
335+
336+
337+
def updateGlobalPullSecret(dynClient: DynamicClient, registryUrl: str, username: str, password: str) -> dict:
338+
"""
339+
Update the global pull secret in openshift-config namespace with new registry credentials.
340+
341+
Args:
342+
dynClient: OpenShift Dynamic Client
343+
registryUrl: Registry URL (e.g., "myregistry.com:5000")
344+
username: Registry username
345+
password: Registry password
346+
347+
Returns:
348+
dict: Updated secret information
349+
"""
350+
import json
351+
import base64
352+
353+
logger.info(f"Updating global pull secret with credentials for {registryUrl}")
354+
355+
# Get the existing pull secret
356+
secretsAPI = dynClient.resources.get(api_version="v1", kind="Secret")
357+
try:
358+
pullSecret = secretsAPI.get(name="pull-secret", namespace="openshift-config")
359+
except NotFoundError:
360+
raise Exception("Global pull-secret not found in openshift-config namespace")
361+
362+
# Convert to dict to allow modifications
363+
secretDict = pullSecret.to_dict()
364+
365+
# Decode the existing dockerconfigjson
366+
dockerConfigJson = secretDict['data'].get(".dockerconfigjson", "")
367+
dockerConfig = json.loads(base64.b64decode(dockerConfigJson).decode('utf-8'))
368+
369+
# Create auth string (username:password base64 encoded)
370+
authString = base64.b64encode(f"{username}:{password}".encode('utf-8')).decode('utf-8')
371+
372+
# Add or update the registry credentials
373+
if "auths" not in dockerConfig:
374+
dockerConfig["auths"] = {}
375+
376+
dockerConfig["auths"][registryUrl] = {
377+
"username": username,
378+
"password": password,
379+
"email": username,
380+
"auth": authString
381+
}
382+
383+
# Encode back to base64
384+
updatedDockerConfig = base64.b64encode(json.dumps(dockerConfig).encode('utf-8')).decode('utf-8')
385+
386+
# Update the secret dict
387+
secretDict['data'][".dockerconfigjson"] = updatedDockerConfig
388+
389+
# Apply the updated secret
390+
updatedSecret = secretsAPI.apply(body=secretDict, namespace="openshift-config")
391+
392+
logger.info(f"Successfully updated global pull secret with credentials for {registryUrl}")
393+
394+
return {
395+
"name": updatedSecret.metadata.name,
396+
"namespace": updatedSecret.metadata.namespace,
397+
"registry": registryUrl,
398+
"changed": True
399+
}

src/mas/devops/users.py

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -759,17 +759,23 @@ def parse_initial_users_from_aws_secret_json(self, secret_json):
759759
for (email, csv) in secret_json.items():
760760
values = csv.split(",")
761761

762-
if len(values) != 3:
763-
raise Exception(f"Wrong number of CSV values for {email} (expected 3 but got {len(values)})")
762+
if len(values) != 3 and len(values) != 4:
763+
raise Exception(f"Wrong number of CSV values for {email} (expected 3 or 4 but got {len(values)})")
764764

765765
user_type = values[0].strip()
766766
given_name = values[1].strip()
767767
family_name = values[2].strip()
768768

769+
if len(values) == 4:
770+
id = values[3].strip()
771+
else:
772+
id = email
773+
769774
user = {
770775
"email": email,
771776
"given_name": given_name,
772-
"family_name": family_name
777+
"family_name": family_name,
778+
"id": id
773779
}
774780
if user_type == "primary":
775781
primary.append(user)
@@ -817,7 +823,7 @@ def create_initial_users_for_saas(self, initial_users):
817823
for primary_user in primary_users:
818824
self.logger.info("")
819825
try:
820-
self.logger.info(f"Syncing primary user {primary_user['email']}")
826+
self.logger.info(f"Syncing primary user with email {primary_user['email']}")
821827
self.create_initial_user_for_saas(primary_user, "PRIMARY")
822828
completed.append(primary_user)
823829
self.logger.info(f"Completed sync of primary user {primary_user['email']}")
@@ -829,7 +835,7 @@ def create_initial_users_for_saas(self, initial_users):
829835
self.logger.info("")
830836
try:
831837
self.logger.info("")
832-
self.logger.info(f"Syncing secondary user {secondary_user['email']}")
838+
self.logger.info(f"Syncing secondary user with email {secondary_user['email']}")
833839
self.create_initial_user_for_saas(secondary_user, "SECONDARY")
834840
completed.append(secondary_user)
835841
self.logger.info(f"Completed sync of secondary user {secondary_user['email']}")
@@ -855,8 +861,13 @@ def create_initial_user_for_saas(self, user, user_type):
855861
user_given_name = user["given_name"]
856862
user_family_name = user["family_name"]
857863

858-
user_id = user_email
859-
username = user_email
864+
if "id" in user:
865+
user_id = user["id"]
866+
else:
867+
# default to email if no id provided
868+
user_id = user_email
869+
870+
username = user_id
860871
# display_name = re.search('^([^@]+)@', user_email).group(1) # local part of the email
861872
display_name = f"{user_given_name} {user_family_name}"
862873

@@ -874,6 +885,8 @@ def create_initial_user_for_saas(self, user, user_type):
874885
}
875886
is_workspace_admin = True
876887
application_role = "ADMIN"
888+
facilities_role = "PREMIUM"
889+
manage_role = "MANAGEUSER"
877890
# TODO: check which security groups primary users should be members of
878891
manage_security_groups = ["MAXADMIN"]
879892
elif user_type == "SECONDARY":
@@ -889,6 +902,8 @@ def create_initial_user_for_saas(self, user, user_type):
889902
}
890903
is_workspace_admin = False
891904
application_role = "USER"
905+
facilities_role = "BASE"
906+
manage_role = "MANAGEUSER"
892907
# TODO: check which security groups secondary users should be members of
893908
manage_security_groups = []
894909
else:
@@ -906,6 +921,8 @@ def create_initial_user_for_saas(self, user, user_type):
906921
"primary": True
907922
}
908923
],
924+
"phoneNumbers": [],
925+
"addresses": [],
909926
"displayName": display_name,
910927
"issuer": "local",
911928
"permissions": permissions,
@@ -921,8 +938,9 @@ def create_initial_user_for_saas(self, user, user_type):
921938
for mas_application_id in self.mas_workspace_application_ids:
922939
self.await_mas_application_availability(mas_application_id)
923940
if mas_application_id == "manage":
924-
# special case for manage; role is always "MANAGEUSER"
925-
role = "MANAGEUSER"
941+
role = manage_role
942+
elif mas_application_id == "facilities":
943+
role = facilities_role
926944
else:
927945
# otherwise grant the user the appropriate role for their user_type
928946
role = application_role

test/src/test_users.py

Lines changed: 67 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1573,7 +1573,8 @@ def test_parse_initial_users_from_aws_secret_json(user_utils):
15731573
{
15741574
"user1@example.com": "primary,joe,bloggs",
15751575
"user2@example.com": " primary , ben , bob ",
1576-
"user3@example.com": "secondary ,bill, bibb"
1576+
"user3@example.com": "secondary ,bill, bibb",
1577+
"user4@example.com": "primary ,bab, bub,user4"
15771578
}
15781579
)
15791580

@@ -1583,19 +1584,28 @@ def test_parse_initial_users_from_aws_secret_json(user_utils):
15831584
{
15841585
"email": "user1@example.com",
15851586
"given_name": "joe",
1586-
"family_name": "bloggs"
1587+
"family_name": "bloggs",
1588+
"id": "user1@example.com",
15871589
},
15881590
{
15891591
"email": "user2@example.com",
15901592
"given_name": "ben",
1591-
"family_name": "bob"
1593+
"family_name": "bob",
1594+
"id": "user2@example.com",
1595+
},
1596+
{
1597+
"email": "user4@example.com",
1598+
"given_name": "bab",
1599+
"family_name": "bub",
1600+
"id": "user4",
15921601
}
15931602
],
15941603
"secondary": [
15951604
{
15961605
"email": "user3@example.com",
15971606
"given_name": "bill",
1598-
"family_name": "bibb"
1607+
"family_name": "bibb",
1608+
"id": "user3@example.com",
15991609
}
16001610
]
16011611
}
@@ -1607,7 +1617,7 @@ def test_parse_initial_users_from_aws_secret_json(user_utils):
16071617
user_utils.parse_initial_users_from_aws_secret_json({
16081618
"user1@example.com": "primary"
16091619
})
1610-
assert "Wrong number of CSV values for user1@example.com (expected 3 but got 1)" == str(excinfo.value)
1620+
assert "Wrong number of CSV values for user1@example.com (expected 3 or 4 but got 1)" == str(excinfo.value)
16111621

16121622
with pytest.raises(Exception) as excinfo:
16131623
user_utils.parse_initial_users_from_aws_secret_json({
@@ -1642,32 +1652,64 @@ def test_create_initial_user_for_saas_unsupported_type(user_utils):
16421652
# Assisted by watsonx Code Assistant
16431653

16441654

1645-
@pytest.mark.parametrize("user_type, permissions, entitlement, is_workspace_admin, application_role, manage_security_groups", [
1655+
@pytest.mark.parametrize("user_type, user_id, user_email, permissions, entitlement, is_workspace_admin, application_role, manage_role, facilities_role, manage_security_groups", [
16461656
(
16471657
"PRIMARY",
1658+
None,
1659+
"bill.bob@acme.com",
16481660
{"systemAdmin": False, "userAdmin": True, "apikeyAdmin": False},
16491661
{"application": "PREMIUM", "admin": "ADMIN_BASE", "alwaysReserveLicense": True},
16501662
True,
16511663
"ADMIN",
1664+
"MANAGEUSER",
1665+
"PREMIUM",
16521666
["MAXADMIN"]
16531667
),
1668+
(
1669+
"PRIMARY",
1670+
"billbob",
1671+
"bill.bob@acme.com",
1672+
{"systemAdmin": False, "userAdmin": True, "apikeyAdmin": False},
1673+
{"application": "PREMIUM", "admin": "ADMIN_BASE", "alwaysReserveLicense": True},
1674+
True,
1675+
"ADMIN",
1676+
"MANAGEUSER",
1677+
"PREMIUM",
1678+
["MAXADMIN"]
1679+
),
1680+
(
1681+
"SECONDARY",
1682+
None,
1683+
"bab.bon@acme.com",
1684+
{"systemAdmin": False, "userAdmin": False, "apikeyAdmin": False},
1685+
{"application": "BASE", "admin": "NONE", "alwaysReserveLicense": True},
1686+
False,
1687+
"USER",
1688+
"MANAGEUSER",
1689+
"BASE",
1690+
[]
1691+
),
16541692
(
16551693
"SECONDARY",
1694+
"babbon",
1695+
"bab.bon@acme.com",
16561696
{"systemAdmin": False, "userAdmin": False, "apikeyAdmin": False},
16571697
{"application": "BASE", "admin": "NONE", "alwaysReserveLicense": True},
16581698
False,
16591699
"USER",
1700+
"MANAGEUSER",
1701+
"BASE",
16601702
[]
16611703
)
16621704
])
16631705
def test_create_initial_user_for_saas(
1664-
user_type, permissions, entitlement, is_workspace_admin, application_role, manage_security_groups,
1706+
user_type, user_id, user_email, permissions, entitlement, is_workspace_admin, application_role, manage_role, facilities_role, manage_security_groups,
16651707
user_utils, requests_mock
16661708
):
16671709
user_utils.get_or_create_user = MagicMock()
16681710
user_utils.link_user_to_local_idp = MagicMock()
16691711
user_utils.add_user_to_workspace = MagicMock()
1670-
mas_workspace_application_ids = ["manage", "iot"]
1712+
mas_workspace_application_ids = ["manage", "iot", "facilities"]
16711713
user_utils.get_mas_applications_in_workspace = MagicMock(return_value=map(lambda x: {"id": x}, mas_workspace_application_ids))
16721714
user_utils.await_mas_application_availability = MagicMock()
16731715
user_utils.set_user_application_permission = MagicMock()
@@ -1676,20 +1718,24 @@ def test_create_initial_user_for_saas(
16761718
user_utils.create_or_get_manage_api_key_for_user = MagicMock(return_value=manage_api_key)
16771719
user_utils.add_user_to_manage_group = MagicMock()
16781720

1679-
user_email = "bill.bob@acme.com"
16801721
user_given_name = "billy"
16811722
user_family_name = "bobby"
1682-
user_id = user_email
1683-
username = user_email
16841723
display_name = f"{user_given_name} {user_family_name}"
16851724

1686-
user_utils.create_initial_user_for_saas({
1725+
initial_users = {
16871726
"email": user_email,
16881727
"given_name": user_given_name,
16891728
"family_name": user_family_name
1690-
},
1691-
user_type
1692-
)
1729+
}
1730+
1731+
if user_id is None:
1732+
user_id = user_email
1733+
else:
1734+
initial_users["id"] = user_id
1735+
1736+
username = user_id
1737+
1738+
user_utils.create_initial_user_for_saas(initial_users, user_type)
16931739

16941740
user_utils.get_or_create_user.assert_called_once_with({
16951741
"id": user_id,
@@ -1703,6 +1749,8 @@ def test_create_initial_user_for_saas(
17031749
"primary": True
17041750
}
17051751
],
1752+
"phoneNumbers": [],
1753+
"addresses": [],
17061754
"displayName": display_name,
17071755
"issuer": "local",
17081756
"permissions": permissions,
@@ -1714,12 +1762,14 @@ def test_create_initial_user_for_saas(
17141762
user_utils.add_user_to_workspace.assert_called_once_with(user_id, is_workspace_admin=is_workspace_admin)
17151763
user_utils.await_mas_application_availability.assert_has_calls([call("manage"), call("iot")])
17161764
user_utils.set_user_application_permission.assert_has_calls([
1717-
call(user_id, "manage", "MANAGEUSER"),
1765+
call(user_id, "manage", manage_role),
17181766
call(user_id, "iot", application_role),
1767+
call(user_id, "facilities", facilities_role),
17191768
])
17201769
user_utils.check_user_sync.assert_has_calls([
17211770
call(user_id, "manage"),
1722-
call(user_id, "iot")
1771+
call(user_id, "iot"),
1772+
call(user_id, "facilities")
17231773
])
17241774

17251775
if len(manage_security_groups) > 0:

0 commit comments

Comments
 (0)