Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
c1d492d
[minor] initial drop of user utils + script for saas
tomklapiscak Mar 24, 2025
3f247d0
make link_user_to_local_idp idempotent
tomklapiscak Mar 24, 2025
b016143
make add_user_to_workspace idempotent
tomklapiscak Mar 24, 2025
af1dbf5
fetcg MAS apps, wait for them to be ready, set user permissions and c…
tomklapiscak Mar 24, 2025
88423bc
Make set_user_application_permission idempotent
tomklapiscak Mar 24, 2025
f928bbe
use internal services for calling MAS APIs
tomklapiscak Mar 24, 2025
c8ac382
make ports configurable for local testing
tomklapiscak Mar 24, 2025
f455893
make add_user_to_manage_group idempotent.
tomklapiscak Mar 26, 2025
141a807
set different manage security groups based on user type
tomklapiscak Mar 26, 2025
f828dac
Add ability to source inital user configuration from AWS SM
tomklapiscak Mar 27, 2025
f2f364e
verify application availability up front
tomklapiscak Mar 27, 2025
28fbe6c
remove completed users from initial_users secret
tomklapiscak Mar 27, 2025
6272517
email_password=true
tomklapiscak Mar 27, 2025
53e1ac5
tweaks
tomklapiscak Mar 28, 2025
601746a
fix
tomklapiscak Mar 28, 2025
ac4b69f
ensure rc 1 reported if >0 failures
tomklapiscak Mar 28, 2025
9b47eb9
set INFO log level default
tomklapiscak Mar 28, 2025
9113aaa
also report failures in yaml-file mode
tomklapiscak Mar 31, 2025
db3c76b
WIP: unit tests
tomklapiscak Mar 31, 2025
395ea42
more unit tests
tomklapiscak Apr 1, 2025
76264f8
unit tests + user resync logic
tomklapiscak Apr 1, 2025
5435b2b
more unit tests
tomklapiscak Apr 1, 2025
45fad67
unit tests
tomklapiscak Apr 1, 2025
dfcb873
don't shadow patch with var
tomklapiscak Apr 1, 2025
f6c2cb9
unit tests
tomklapiscak Apr 1, 2025
f9ff747
more unit tests
tomklapiscak Apr 1, 2025
fcfba5b
unit tests
tomklapiscak Apr 1, 2025
84c222f
unit tests
tomklapiscak Apr 1, 2025
9888627
unit tests
tomklapiscak Apr 2, 2025
9cf9fce
more unit tests
tomklapiscak Apr 11, 2025
dbdcc9b
remove confusing manage_apikey computed property
tomklapiscak Apr 11, 2025
caaad9f
unit tests
tomklapiscak Apr 11, 2025
60a5004
unit tests
tomklapiscak Apr 11, 2025
481a76f
unit tests
tomklapiscak Apr 11, 2025
ea45197
unit tests
tomklapiscak Apr 11, 2025
626850d
unit tests
tomklapiscak Apr 11, 2025
137eb14
unit tests
tomklapiscak Apr 11, 2025
eaddbf7
unit tests
tomklapiscak Apr 11, 2025
526ba15
remove unused, untested methods
tomklapiscak Apr 11, 2025
8d79dbe
Merge remote-tracking branch 'origin/stable' into mascore6072
tomklapiscak Apr 11, 2025
82bb5db
Merge remote-tracking branch 'origin/stable' into mascore6072
tomklapiscak Apr 16, 2025
02814f6
fix application role ADMIN (not ADMINISTRATOR)
tomklapiscak Apr 17, 2025
2514d50
skip user creation if no secret found
tomklapiscak Apr 17, 2025
74a226c
fix unit test
tomklapiscak Apr 17, 2025
6b36c9c
Merge remote-tracking branch 'origin/stable' into mascore6072
tomklapiscak May 1, 2025
2d907dd
Merge remote-tracking branch 'origin/stable' into mascore6072
tomklapiscak May 6, 2025
8589749
comments
tomklapiscak May 8, 2025
993701d
requested changes
tomklapiscak May 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,56 @@ updateTektonDefinitions(pipelinesNamespace, "/mascli/templates/ibm-mas-tekton.ya
pipelineURL = launchUpgradePipeline(self.dynamicClient, instanceId)
print(pipelineURL)
```


mas-devops-create-initial-users
---------------------------------------------


Add to /etc/hosts
```
127.0.0.1 tgk01-masdev.mas-tgk01-manage.svc.cluster.local
127.0.0.1 coreapi.mas-tgk01-core.svc.cluster.local
127.0.0.1 admin-dashboard.mas-tgk01-core.svc.cluster.local
```

```bash
SM_AWS_REGION=""
SM_AWS_ACCESS_KEY_ID=""
SM_AWS_SECRET_ACCESS_KEY=""

aws configure set default.region ${SM_AWS_REGION}
aws configure set aws_access_key_id ${SM_AWS_ACCESS_KEY_ID}
aws configure set aws_secret_access_key ${SM_AWS_SECRET_ACCESS_KEY}


oc login --token=sha256~xxx --server=https://xxx:6443

oc port-forward service/admin-dashboard 8445:443 -n mas-tgk01-core
oc port-forward service/coreapi 8444:443 -n mas-tgk01-core
oc port-forward service/tgk01-masdev 8443:443 -n mas-tgk01-manage

mas-devops-create-initial-users-for-saas \
--mas-instance-id tgk01 \
--mas-workspace-id masdev \
--log-level INFO \
--initial-users-secret-name "aws-dev/noble4/tgk01/initial_users" \
--manage-api-port 8443 \
--coreapi-port 8444 \
--admin-dashboard-port 8445


mas-devops-create-initial-users-for-saas \
--mas-instance-id tgk01 \
--mas-workspace-id masdev \
--log-level INFO \
--initial-users-yaml-file /home/tom/workspaces/notes/mascore3423/example-users-single.yaml \
--manage-api-port 8443 \
--coreapi-port 8444 \
--admin-dashboard-port 8445
```

Example of initial_users secret:
```json
{"john.smith1@example.com":"primary,john1,smith1","john.smith2@example.com":"primary,john2,smith2","john.smith3@example.com":"secondary,john3,smith3"}
```
146 changes: 146 additions & 0 deletions bin/mas-devops-create-initial-users-for-saas
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
#!/usr/bin/env python3

# *****************************************************************************
# Copyright (c) 2025 IBM Corporation and other Contributors.
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License v1.0
# which accompanies this distribution, and is available at
# http://www.eclipse.org/legal/epl-v10.html
#
# *****************************************************************************

from kubernetes import client, config
from kubernetes.config.config_exception import ConfigException
import argparse
import logging
import urllib3
urllib3.disable_warnings()
import yaml
import json
import sys

import boto3
from botocore.exceptions import ClientError

from mas.devops.users import MASUserUtils



if __name__ == "__main__":
parser = argparse.ArgumentParser()

# Primary Options
parser.add_argument("--mas-instance-id", required=True)
parser.add_argument("--mas-workspace-id", required=True)
parser.add_argument("--log-level", required=False, choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"], default="INFO")
parser.add_argument("--coreapi-port", required=False, default=443)
parser.add_argument("--admin-dashboard-port", required=False, default=443)
parser.add_argument("--manage-api-port", required=False, default=443)


group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("--initial-users-yaml-file")
group.add_argument("--initial-users-secret-name")

args, unknown = parser.parse_known_args()

log_level = getattr(logging, args.log_level)

logger = logging.getLogger()
logger.setLevel(log_level)

ch = logging.StreamHandler()
ch.setLevel(log_level)
chFormatter = logging.Formatter(
"%(asctime)-25s %(name)-50s [%(threadName)s] %(levelname)-8s %(message)s"
)
ch.setFormatter(chFormatter)
logger.addHandler(ch)

mas_instance_id = args.mas_instance_id
mas_workspace_id = args.mas_workspace_id
initial_users_yaml_file = args.initial_users_yaml_file
initial_users_secret_name = args.initial_users_secret_name
coreapi_port = args.coreapi_port
admin_dashboard_port = args.admin_dashboard_port
manage_api_port = args.manage_api_port


logger.info("Configuration:")
logger.info("--------------")
logger.info(f"mas_instance_id: {mas_instance_id}")
logger.info(f"mas_workspace_id: {mas_workspace_id}")
logger.info(f"initial_users_yaml_file: {initial_users_yaml_file}")
logger.info(f"initial_users_secret_name: {initial_users_secret_name}")
logger.info(f"log_level: {log_level}")
logger.info(f"coreapi_port: {coreapi_port}")
logger.info(f"admin_dashboard_port: {admin_dashboard_port}")
logger.info(f"manage_api_port: {manage_api_port}")
logger.info("")

try:
# Try to load in-cluster configuration
config.load_incluster_config()
logger.debug("Loaded in-cluster configuration")
except ConfigException:
# If that fails, fall back to kubeconfig file
config.load_kube_config()
logger.debug("Loaded kubeconfig file")


user_utils = MASUserUtils(mas_instance_id, mas_workspace_id, client.api_client.ApiClient(), coreapi_port=coreapi_port, admin_dashboard_port=admin_dashboard_port, manage_api_port=manage_api_port)

if initial_users_secret_name is not None:

logger.info(f"Loading initial_users configuration from secret {initial_users_secret_name}")

session = boto3.session.Session()
aws_sm_client = session.client(
service_name='secretsmanager',
)
try:
initial_users_secret = aws_sm_client.get_secret_value( # pragma: allowlist secret
SecretId=initial_users_secret_name
)
except ClientError as e:
if e.response['Error']['Code'] == 'ResourceNotFoundException':
logger.info(f"Secret {initial_users_secret_name} was not found, nothing to do, exiting now.")
sys.exit(0)

raise Exception(f"Failed to fetch secret {initial_users_secret_name}: {str(e)}")

secret_json = json.loads(initial_users_secret['SecretString'])
initial_users = user_utils.parse_initial_users_from_aws_secret_json(secret_json)
elif initial_users_yaml_file is not None:
with open(initial_users_yaml_file, 'r') as file:
initial_users = yaml.safe_load(file)
else:
raise Exception("Something unexpected happened")


result = user_utils.create_initial_users_for_saas(initial_users)

# if user details were sourced from an AWS SM secret, remove the completed entries from the secret
# so we don't try and resync them the next time round (and potentially undo an update made by a customer)
if initial_users_secret_name is not None:
has_updates = False
for completed_user in result["completed"]:
logger.info(f"Removing synced user {completed_user['email']} from {initial_users_secret_name} secret")
secret_json.pop(completed_user["email"])
has_updates = True

if has_updates:
logger.info(f"Updating secret {initial_users_secret_name}")
try:
aws_sm_client.update_secret( # pragma: allowlist secret
SecretId=initial_users_secret_name,
SecretString=json.dumps(secret_json)
)
except ClientError as e:
raise Exception(f"Failed to update secret {initial_users_secret_name}: {str(e)}")


if len(result["failed"]) > 0:
failed_user_ids = list(map(lambda u : u["email"], result["failed"]))
raise Exception(f"Sync failed for the following user IDs {failed_user_ids}")
13 changes: 8 additions & 5 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,16 @@ def get_version(rel_path):
'kubernetes', # Apache Software License
'kubeconfig', # BSD License
'jinja2', # BSD License
'jinja2-base64-filters' # MIT License
'jinja2-base64-filters', # MIT License
'boto3' # Apache Software License
],
extras_require={
'dev': [
'build', # MIT License
'flake8', # MIT License
'pytest', # MIT License
'pytest-mock' # MIT License
'build', # MIT License
'flake8', # MIT License
'pytest', # MIT License
'pytest-mock', # MIT License
'requests-mock' # Apache Software License
]
},
classifiers=[
Expand All @@ -85,6 +87,7 @@ def get_version(rel_path):
],
scripts=[
'bin/mas-devops-db2-validate-config',
'bin/mas-devops-create-initial-users-for-saas',
'bin/mas-devops-saas-job-cleaner'
]
)
Loading