From 800b44d45a3bd80fa27e35268f55b280e6610351 Mon Sep 17 00:00:00 2001 From: Preston Tamkin <845970+prestomation@users.noreply.github.com> Date: Thu, 15 Feb 2024 14:29:54 -0800 Subject: [PATCH] feat: Support Deadline Cloud Monitor migration away from Studios (#179) Currently, deadline-cloud uses the studio_id= key in the AWS SDK profile to determine if the profile comes from Deadline Cloud Monitor Desktop. This is used in a few ways 1. This is used in telemetry 2. This is used as an input to ListFarms, as this is part of how the Deadline Cloud API works 3. This is used to know that Deadline Cloud Monitor Desktop is being used so it can be reported in the credential settings and the Login/Logout actions can do the right thing. Going forward Deadline Cloud will use a monitor_id instead. The AWS SDK profile will be unambiguous in what it contains, either a studioId or a monitorId. This change now supports both models. In general we use both and call them 'monitorId' as this is only a temporary situation. One area where we disambiguate these internally is for case 2 above: with monitorId ListFarms() no longer needs this input. This change is only expected to last 4-6 weeks, at which time all code referring to Studio will be removed. Testing: Unit tests pass and some are updated. Some are specifically for this studioId in list_farms so those remain, but others have been changed to reflect monitor. This means the studioId is not as well tested but this is short-lived I have Deadline Cloud Monitor Desktop locally and logged into two setups, one using a Studio and one using a monitor. With both, I tested deadline-cloud list farms and noticed they both worked as expected Signed-off-by: Preston Tamkin <845970+prestomation@users.noreply.github.com> --- README.md | 2 +- src/deadline/client/api/__init__.py | 1 + src/deadline/client/api/_list_apis.py | 1 + src/deadline/client/api/_session.py | 22 ++++++++++++++----- src/deadline/client/api/_telemetry.py | 11 +++++++++- test/unit/deadline_client/api/test_api_job.py | 2 +- .../api/test_api_storage_profile.py | 2 +- .../deadline_client/api/test_api_telemetry.py | 4 ++-- .../deadline_client/cli/test_cli_creds.py | 4 ++-- 9 files changed, 36 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 39fe2954..1347ada9 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ It is divided into the following submodules: This submodule contains utilities to call boto3 in a standardized way using an aws profile configured for Amazon Deadline Cloud, helpers for working with -Nimble Studio login/logout, and objects representing Amazon Deadline Cloud +Deadline Cloud Monitor Desktop login/logout, and objects representing Amazon Deadline Cloud resources. ### cli diff --git a/src/deadline/client/api/__init__.py b/src/deadline/client/api/__init__.py index 9d5268eb..3da55f67 100644 --- a/src/deadline/client/api/__init__.py +++ b/src/deadline/client/api/__init__.py @@ -83,6 +83,7 @@ def check_deadline_api_available(config: Optional[ConfigParser] = None) -> bool: if user_id: list_farm_params["principalId"] = str(user_id) + # We don't do this filtering for Monitors, so specifically check StudioId studio_id = get_studio_id(config=config) if studio_id: list_farm_params["studioId"] = str(studio_id) diff --git a/src/deadline/client/api/_list_apis.py b/src/deadline/client/api/_list_apis.py index dbac2970..8b7a82db 100644 --- a/src/deadline/client/api/_list_apis.py +++ b/src/deadline/client/api/_list_apis.py @@ -42,6 +42,7 @@ def list_farms(config=None, **kwargs): kwargs["principalId"] = user_id if "studioId" not in kwargs: + # We don't do this filtering for Monitors, so specifically check StudioId studio_id = get_studio_id(config=config) if studio_id: kwargs["studioId"] = studio_id diff --git a/src/deadline/client/api/_session.py b/src/deadline/client/api/_session.py index e6e53ba7..6850560f 100644 --- a/src/deadline/client/api/_session.py +++ b/src/deadline/client/api/_session.py @@ -144,8 +144,8 @@ def get_credentials_type(config: Optional[ConfigParser] = None) -> AwsCredential profile_config = session._session.get_scoped_config() except ProfileNotFound: return AwsCredentialsType.NOT_VALID - if "studio_id" in profile_config: - # CTDX adds some Nimble-specific keys here which we can use to know that this came from CTDX + if "studio_id" in profile_config or "monitor_id" in profile_config: + # Deadline Cloud Monitor Desktop adds some Deadline Cloud-specific keys here which we can use to know that this came from the app return AwsCredentialsType.DEADLINE_CLOUD_MONITOR_LOGIN else: return AwsCredentialsType.HOST_PROVIDED @@ -155,13 +155,13 @@ def get_user_and_identity_store_id( config: Optional[ConfigParser] = None, ) -> tuple[Optional[str], Optional[str]]: """ - If logged in with Nimble Studio Deadline Cloud Monitor, returns a tuple + If logged in with Deadline Cloud Monitor Desktop, returns a tuple (user_id, identity_store_id), otherwise returns None. """ session = get_boto3_session(config=config) profile_config = session._session.get_scoped_config() - if "studio_id" in profile_config: + if "studio_id" in profile_config or "monitor_id" in profile_config: return (profile_config["user_id"], profile_config["identity_store_id"]) else: return None, None @@ -171,7 +171,7 @@ def get_studio_id( config: Optional[ConfigParser] = None, ) -> Optional[str]: """ - If logged in with Nimble Studio Deadline Cloud Monitor, returns Studio Id, otherwise returns None. + If logged in with Deadline Cloud Monitor to a Nimble Studio, returns Studio Id, otherwise returns None. """ session = get_boto3_session(config=config) profile_config = session._session.get_scoped_config() @@ -179,6 +179,18 @@ def get_studio_id( return profile_config.get("studio_id", None) +def get_monitor_id( + config: Optional[ConfigParser] = None, +) -> Optional[str]: + """ + If logged in with Deadline Cloud Monitor to a Deadline Monitor, returns Monitor Id, otherwise returns None. + """ + session = get_boto3_session(config=config) + profile_config = session._session.get_scoped_config() + + return profile_config.get("monitor_id", None) + + def get_queue_user_boto3_session( deadline: BaseClient, config: Optional[ConfigParser] = None, diff --git a/src/deadline/client/api/_telemetry.py b/src/deadline/client/api/_telemetry.py index 5e40de68..24c8a7ce 100644 --- a/src/deadline/client/api/_telemetry.py +++ b/src/deadline/client/api/_telemetry.py @@ -18,7 +18,12 @@ from ...job_attachments.progress_tracker import SummaryStatistics -from ._session import get_studio_id, get_user_and_identity_store_id, get_deadline_endpoint_url +from ._session import ( + get_studio_id, + get_monitor_id, + get_user_and_identity_store_id, + get_deadline_endpoint_url, +) from ..config import config_file from .. import version @@ -140,6 +145,10 @@ def _get_system_metadata(self, config: Optional[ConfigParser]) -> Dict[str, Any] if studio_id: metadata["studio_id"] = studio_id + monitor_id: Optional[str] = get_monitor_id(config=config) + if monitor_id: + metadata["monitor_id"] = monitor_id + return metadata def _exit_cleanly(self): diff --git a/test/unit/deadline_client/api/test_api_job.py b/test/unit/deadline_client/api/test_api_job.py index 5d5358cf..d9e712f3 100644 --- a/test/unit/deadline_client/api/test_api_job.py +++ b/test/unit/deadline_client/api/test_api_job.py @@ -60,7 +60,7 @@ def test_list_jobs_principal_id(fresh_deadline_config, pass_principal_id_filter, ] if user_identities: session_mock()._session.get_scoped_config.return_value = { - "studio_id": "studioid", + "monitor_id": "monitor-amonitorid", "user_id": "userid", "identity_store_id": "idstoreid", } diff --git a/test/unit/deadline_client/api/test_api_storage_profile.py b/test/unit/deadline_client/api/test_api_storage_profile.py index be8e6b53..4a457fd5 100644 --- a/test/unit/deadline_client/api/test_api_storage_profile.py +++ b/test/unit/deadline_client/api/test_api_storage_profile.py @@ -64,7 +64,7 @@ def test_list_storage_profiles_for_queue(fresh_deadline_config, user_identities) ] if user_identities: session_mock()._session.get_scoped_config.return_value = { - "studio_id": "studioid", + "monitor_id": "studioid", "user_id": "userid", "identity_store_id": "idstoreid", } diff --git a/test/unit/deadline_client/api/test_api_telemetry.py b/test/unit/deadline_client/api/test_api_telemetry.py index a2429880..d1010068 100644 --- a/test/unit/deadline_client/api/test_api_telemetry.py +++ b/test/unit/deadline_client/api/test_api_telemetry.py @@ -17,8 +17,8 @@ def fixture_telemetry_client(fresh_deadline_config): config.set_setting("defaults.aws_profile_name", "SomeRandomProfileName") with patch.object(api.TelemetryClient, "_start_threads"), patch.object( - api._telemetry, "get_studio_id", side_effect=["studio-id"] - ), patch.object( + api._telemetry, "get_monitor_id", side_effect=["monitor-id"] + ), patch.object(api._telemetry, "get_studio_id", side_effect=[None]), patch.object( api._telemetry, "get_user_and_identity_store_id", side_effect=[("user-id", "identity-store-id")], diff --git a/test/unit/deadline_client/cli/test_cli_creds.py b/test/unit/deadline_client/cli/test_cli_creds.py index dd9fd3d3..e04047d0 100644 --- a/test/unit/deadline_client/cli/test_cli_creds.py +++ b/test/unit/deadline_client/cli/test_cli_creds.py @@ -20,7 +20,7 @@ def test_cli_deadline_cloud_monitor_login_and_logout(fresh_deadline_config): """ scoped_config = { "credential_process": "/bin/DeadlineCloudMonitor get-credentials --profile sandbox-us-west-2", - "studio_id": "us-west-2:stid-1g9neezauta8ease", + "monitor_id": "monitor-1g9neezauta8ease", "region": "us-west-2", } @@ -114,7 +114,7 @@ def test_cli_creds_status_json(fresh_deadline_config): } scoped_config = { "credential_process": "/bin/DeadlineCloudMonitor get-credentials --profile sandbox-us-west-2", - "studio_id": "us-west-2:stid-1g9neezauta8ease", + "monitor_id": "monitor-1g9neezauta8ease", "region": "us-west-2", } config.set_setting("defaults.aws_profile_name", profile_name)