From 1fe9399f99435b975e74988fa854889eff3e3a35 Mon Sep 17 00:00:00 2001 From: tomdds Date: Thu, 29 Aug 2019 14:06:18 -0400 Subject: [PATCH 01/10] Update CloudProviderInterface for provision job consumption --- atst/domain/csp/cloud.py | 156 +++++++++++++++++-------- atst/domain/environment_roles.py | 8 +- atst/domain/environments.py | 4 +- atst/routes/__init__.py | 2 +- atst/routes/applications/__init__.py | 4 +- tests/domain/test_environment_roles.py | 14 +-- tests/domain/test_environments.py | 7 -- 7 files changed, 114 insertions(+), 81 deletions(-) diff --git a/atst/domain/csp/cloud.py b/atst/domain/csp/cloud.py index 5fa322e2..c96f8616 100644 --- a/atst/domain/csp/cloud.py +++ b/atst/domain/csp/cloud.py @@ -1,84 +1,144 @@ from uuid import uuid4 +from atst.models.environment_role import CSPRole + class CloudProviderInterface: - def create_application(self, name): # pragma: no cover - """Create an application in the cloud with the provided name. Returns - the ID of the created object. + def get_auth(self, auth_credentials): + """Validate credentials and create auth object + + Arguments: + auth_credentials -- Object containing credentials + + Returns: + object: An object to be passed into subsequent calls """ raise NotImplementedError() - def delete_application(self, cloud_id): # pragma: no cover - """Delete an application in the cloud with the provided cloud_id. Returns - True for success or raises an error. + def create_environment(self, auth, user): + """Create a new environment in the CSP. + + Arguments: + auth -- Object representing authorization for the CSP + user -- ATAT user authorizing the environment creation + + Returns: + string: ID of created environment """ raise NotImplementedError() - def create_user(self, user): # pragma: no cover - """Create an account in the CSP for specified user. Returns the ID of - the created user. + def create_atat_admin_user(self, auth, csp_environment_id): + """Creates a new, programmatic user in the CSP. Grants this user full permissions to administer + the CSP. Returns a dictionary containing user details, including user's API credentials. + + Arguments: + auth -- Object representing authorization for the CSP + csp_environment_id -- ID of the CSP Environment the admin user should be created in + + Returns: + object: Object representing new remote admin user, including credentials """ raise NotImplementedError() - def create_role(self, environment_role): # pragma: no cover - """Takes an `atst.model.EnvironmentRole` object and allows the - specified user access to the specified cloud entity. + def create_environment_baseline_roles(self, auth, csp_environment_id): + """Provision the baseline set of roles that align with the available + environment roles in the ATAT system. - This _does not_ return a token, but is intended to perform any necessary - setup to allow a token to be generated in the future (for example, - add the user to the cloud entity in some fashion). + Arguments: + auth -- Object representing authorization for the CSP + csp_environment_id -- ID of the CSP Environment to provision roles against. + + Returns: + dict: Returns dict of role name => csp role IDs. """ raise NotImplementedError() - def delete_role(self, environment_role): # pragma: no cover - """Takes an `atst.model.EnvironmentRole` object and performs any action - necessary in the CSP to remove the specified user from the specified - environment. This method does not return anything. + def create_or_update_user(self, auth, user_info, csp_role_id): + """Creates a user or updates an existing user's role. + + Arguments: + auth -- Object representing authorization for the CSP + user_info -- object containing user data, if it has a csp_user_id + it will try to update a user with that id + csp_role_id -- The id of the role the user should be given in the CSP + + Raises: + NotImplementedError: [description] """ raise NotImplementedError() - def get_access_token(self, environment_role): # pragma: no cover - """Takes an `atst.model.EnvironmentRole` object and returns a federated - access token that gives the specified user access to the specified - environment with the proper permissions. + def suspend_user(self, auth, csp_user_id): + """Revoke all privileges for a user. Used to prevent user access while a full + delete is being processed. + + Arguments: + auth -- Object representing authorization for the CSP + csp_user_id -- CSP internal user identifier + + Returns: + None """ raise NotImplementedError() - def calculator_url(self): # pragma: no cover - """Returns a URL for the CSP's estimate calculator.""" + def delete_user(self, auth, csp_user_id): + """Given the csp-internal id for a user, initiate user deletion. + + Arguments: + auth -- Object representing authorization for the CSP + csp_user_id -- CSP internal user identifier + + Returns: + None + + Raises: + TBDException: Some part of user deletion failed + """ + raise NotImplementedError() + + def get_calculator_url(self): + """Returns the calculator url for the CSP. + This will likely be a static property elsewhere once a CSP is chosen. + """ + raise NotImplementedError() + + def get_environment_login_url(self, environment): + """Returns the login url for a given environment + This may move to be a computed property on the Environment domain object + """ raise NotImplementedError() class MockCloudProvider(CloudProviderInterface): - def create_application(self, name): - """Returns an id that represents what would be an application in the - cloud.""" + def get_auth(self, auth_credentials): + return {} + + def create_environment(self, auth, user): return uuid4().hex - def delete_application(self, name): - """Returns an id that represents what would be an application in the - cloud.""" - return True + def create_atat_admin_user(self, auth, csp_environment_id): + return {"id": uuid4().hex, "credentials": {}} - def create_user(self, user): - """Returns an id that represents what would be an user in the cloud.""" - return uuid4().hex + def create_environment_baseline_roles(self, auth, csp_environment_id): + return { + CSPRole.BASIC_ACCESS: uuid4().hex, + CSPRole.NETWORK_ADMIN: uuid4().hex, + CSPRole.BUSINESS_READ: uuid4().hex, + CSPRole.TECHNICAL_READ: uuid4().hex, + } - def create_role(self, environment_role): - # Currently, there is nothing to mock out, so just do nothing. + def create_or_update_user(self, auth, environment_role): + return {"id": uuid4().hex} + + def suspend_user(self, auth, csp_user_id): pass - def delete_role(self, environment_role): - # Currently nothing to do. + def delete_user(self, auth, csp_user_id): pass - def get_access_token(self, environment_role): - # for now, just create a mock token using the user and environment - # cloud IDs and the name of the role in the environment - user_id = environment_role.application_role.user.cloud_id or "" - env_id = environment_role.environment.cloud_id or "" - role_details = environment_role.role - return "::".join([user_id, env_id, role_details]) - - def calculator_url(self): + def get_calculator_url(self): return "https://www.rackspace.com/en-us/calculator" + + def get_environment_login_url(self, environment): + """Returns the login url for a given environment + """ + return "https://www.mycloud.com/my-env-login" diff --git a/atst/domain/environment_roles.py b/atst/domain/environment_roles.py index 9ae57782..b28e94b2 100644 --- a/atst/domain/environment_roles.py +++ b/atst/domain/environment_roles.py @@ -1,5 +1,3 @@ -from flask import current_app as app - from atst.database import db from atst.models import EnvironmentRole, ApplicationRole @@ -10,10 +8,6 @@ class EnvironmentRoles(object): env_role = EnvironmentRole( application_role=application_role, environment=environment, role=role ) - # TODO: move cloud_id behavior to invitation acceptance - # if not user.cloud_id: - # user.cloud_id = app.csp.cloud.create_user(user) - app.csp.cloud.create_role(env_role) return env_role @classmethod @@ -45,7 +39,7 @@ class EnvironmentRoles(object): def delete(cls, application_role_id, environment_id): existing_env_role = EnvironmentRoles.get(application_role_id, environment_id) if existing_env_role: - app.csp.cloud.delete_role(existing_env_role) + # TODO: Set status to pending_delete db.session.delete(existing_env_role) db.session.commit() return True diff --git a/atst/domain/environments.py b/atst/domain/environments.py index bc98bf9f..e21d4cb9 100644 --- a/atst/domain/environments.py +++ b/atst/domain/environments.py @@ -1,4 +1,3 @@ -from flask import current_app as app from sqlalchemy.orm.exc import NoResultFound from atst.database import db @@ -13,7 +12,6 @@ class Environments(object): @classmethod def create(cls, application, name): environment = Environment(application=application, name=name) - environment.cloud_id = app.csp.cloud.create_application(environment.name) db.session.add(environment) db.session.commit() return environment @@ -101,6 +99,6 @@ class Environments(object): if commit: db.session.commit() - app.csp.cloud.delete_application(environment.cloud_id) + # TODO: How do we work around environment deletion being a largely manual process in the CSPs return environment diff --git a/atst/routes/__init__.py b/atst/routes/__init__.py index eaa447be..f2d6da13 100644 --- a/atst/routes/__init__.py +++ b/atst/routes/__init__.py @@ -131,4 +131,4 @@ def csp_environment_access(): @bp.route("/jedi-csp-calculator") def jedi_csp_calculator(): - return redirect(app.csp.cloud.calculator_url()) + return redirect(app.csp.cloud.get_calculator_url()) diff --git a/atst/routes/applications/__init__.py b/atst/routes/applications/__init__.py index 6ba4bda0..8ec1e4cf 100644 --- a/atst/routes/applications/__init__.py +++ b/atst/routes/applications/__init__.py @@ -30,6 +30,6 @@ def access_environment(environment_id): env_role = EnvironmentRoles.get_by_user_and_environment( g.current_user.id, environment_id ) - token = app.csp.cloud.get_access_token(env_role) + login_url = app.csp.cloud.get_environment_login_url(env_role.environment) - return redirect(url_for("atst.csp_environment_access", token=token)) + return redirect(url_for("atst.csp_environment_access", login_url=login_url)) diff --git a/tests/domain/test_environment_roles.py b/tests/domain/test_environment_roles.py index b50d352d..a8618981 100644 --- a/tests/domain/test_environment_roles.py +++ b/tests/domain/test_environment_roles.py @@ -1,5 +1,4 @@ import pytest -from unittest.mock import MagicMock from atst.domain.environment_roles import EnvironmentRoles @@ -19,10 +18,6 @@ def environment(application_role): def test_create(application_role, environment, monkeypatch): - mock_create_role = MagicMock() - monkeypatch.setattr( - "atst.domain.environment_roles.app.csp.cloud.create_role", mock_create_role - ) environment_role = EnvironmentRoles.create( application_role, environment, "network admin" @@ -30,7 +25,6 @@ def test_create(application_role, environment, monkeypatch): assert environment_role.application_role == application_role assert environment_role.environment == environment assert environment_role.role == "network admin" - mock_create_role.assert_called_with(environment_role) def test_get(application_role, environment): @@ -55,16 +49,10 @@ def test_get_by_user_and_environment(application_role, environment): def test_delete(application_role, environment, monkeypatch): - mock_delete_role = MagicMock() - monkeypatch.setattr( - "atst.domain.environment_roles.app.csp.cloud.delete_role", mock_delete_role - ) - - environment_role = EnvironmentRoleFactory.create( + EnvironmentRoleFactory.create( application_role=application_role, environment=environment ) assert EnvironmentRoles.delete(application_role.id, environment.id) - mock_delete_role.assert_called_with(environment_role) assert not EnvironmentRoles.delete(application_role.id, environment.id) diff --git a/tests/domain/test_environments.py b/tests/domain/test_environments.py index 412aca96..e850f2df 100644 --- a/tests/domain/test_environments.py +++ b/tests/domain/test_environments.py @@ -15,13 +15,6 @@ from tests.factories import ( ) -def test_create_environments(): - application = ApplicationFactory.create() - environments = Environments.create_many(application, ["Staging", "Production"]) - for env in environments: - assert env.cloud_id is not None - - def test_update_env_role(): env_role = EnvironmentRoleFactory.create(role=CSPRole.BASIC_ACCESS.value) new_role = CSPRole.TECHNICAL_READ.value From 776887686c063a36b5241c90458fac33c2bad69f Mon Sep 17 00:00:00 2001 From: tomdds Date: Thu, 29 Aug 2019 16:51:44 -0400 Subject: [PATCH 02/10] Generalize baseline provisioning method signature --- atst/domain/csp/cloud.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/atst/domain/csp/cloud.py b/atst/domain/csp/cloud.py index c96f8616..1410d6c0 100644 --- a/atst/domain/csp/cloud.py +++ b/atst/domain/csp/cloud.py @@ -40,16 +40,15 @@ class CloudProviderInterface: """ raise NotImplementedError() - def create_environment_baseline_roles(self, auth, csp_environment_id): - """Provision the baseline set of roles that align with the available - environment roles in the ATAT system. + def create_environment_baseline(self, auth, csp_environment_id): + """Provision the necessary baseline entities (such as roles) in the given environment Arguments: auth -- Object representing authorization for the CSP csp_environment_id -- ID of the CSP Environment to provision roles against. Returns: - dict: Returns dict of role name => csp role IDs. + dict: Returns dict that associates the resource identities with their ATAT representations. """ raise NotImplementedError() @@ -118,7 +117,7 @@ class MockCloudProvider(CloudProviderInterface): def create_atat_admin_user(self, auth, csp_environment_id): return {"id": uuid4().hex, "credentials": {}} - def create_environment_baseline_roles(self, auth, csp_environment_id): + def create_environment_baseline(self, auth, csp_environment_id): return { CSPRole.BASIC_ACCESS: uuid4().hex, CSPRole.NETWORK_ADMIN: uuid4().hex, From 0451dce8cfbafa032b1d07219dc767ff531911bc Mon Sep 17 00:00:00 2001 From: tomdds Date: Thu, 29 Aug 2019 17:01:51 -0400 Subject: [PATCH 03/10] Pass credentials to each CSP method rather than an abstract auth object --- atst/domain/csp/cloud.py | 50 +++++++++++++++------------------------- 1 file changed, 18 insertions(+), 32 deletions(-) diff --git a/atst/domain/csp/cloud.py b/atst/domain/csp/cloud.py index 1410d6c0..8717f7cc 100644 --- a/atst/domain/csp/cloud.py +++ b/atst/domain/csp/cloud.py @@ -4,22 +4,11 @@ from atst.models.environment_role import CSPRole class CloudProviderInterface: - def get_auth(self, auth_credentials): - """Validate credentials and create auth object - - Arguments: - auth_credentials -- Object containing credentials - - Returns: - object: An object to be passed into subsequent calls - """ - raise NotImplementedError() - - def create_environment(self, auth, user): + def create_environment(self, auth_credentials, user): """Create a new environment in the CSP. Arguments: - auth -- Object representing authorization for the CSP + auth_credentials -- Object containing CSP account credentials user -- ATAT user authorizing the environment creation Returns: @@ -27,12 +16,12 @@ class CloudProviderInterface: """ raise NotImplementedError() - def create_atat_admin_user(self, auth, csp_environment_id): + def create_atat_admin_user(self, auth_credentials, csp_environment_id): """Creates a new, programmatic user in the CSP. Grants this user full permissions to administer the CSP. Returns a dictionary containing user details, including user's API credentials. Arguments: - auth -- Object representing authorization for the CSP + auth_credentials -- Object containing CSP account credentials csp_environment_id -- ID of the CSP Environment the admin user should be created in Returns: @@ -40,11 +29,11 @@ class CloudProviderInterface: """ raise NotImplementedError() - def create_environment_baseline(self, auth, csp_environment_id): + def create_environment_baseline(self, auth_credentials, csp_environment_id): """Provision the necessary baseline entities (such as roles) in the given environment Arguments: - auth -- Object representing authorization for the CSP + auth_credentials -- Object containing CSP account credentials csp_environment_id -- ID of the CSP Environment to provision roles against. Returns: @@ -52,11 +41,11 @@ class CloudProviderInterface: """ raise NotImplementedError() - def create_or_update_user(self, auth, user_info, csp_role_id): + def create_or_update_user(self, auth_credentials, user_info, csp_role_id): """Creates a user or updates an existing user's role. Arguments: - auth -- Object representing authorization for the CSP + auth_credentials -- Object containing CSP account credentials user_info -- object containing user data, if it has a csp_user_id it will try to update a user with that id csp_role_id -- The id of the role the user should be given in the CSP @@ -66,12 +55,12 @@ class CloudProviderInterface: """ raise NotImplementedError() - def suspend_user(self, auth, csp_user_id): + def suspend_user(self, auth_credentials, csp_user_id): """Revoke all privileges for a user. Used to prevent user access while a full delete is being processed. Arguments: - auth -- Object representing authorization for the CSP + auth_credentials -- Object containing CSP account credentials csp_user_id -- CSP internal user identifier Returns: @@ -79,11 +68,11 @@ class CloudProviderInterface: """ raise NotImplementedError() - def delete_user(self, auth, csp_user_id): + def delete_user(self, auth_credentials, csp_user_id): """Given the csp-internal id for a user, initiate user deletion. Arguments: - auth -- Object representing authorization for the CSP + auth_credentials -- Object containing CSP account credentials csp_user_id -- CSP internal user identifier Returns: @@ -108,16 +97,13 @@ class CloudProviderInterface: class MockCloudProvider(CloudProviderInterface): - def get_auth(self, auth_credentials): - return {} - - def create_environment(self, auth, user): + def create_environment(self, auth_credentials, user): return uuid4().hex - def create_atat_admin_user(self, auth, csp_environment_id): + def create_atat_admin_user(self, auth_credentials, csp_environment_id): return {"id": uuid4().hex, "credentials": {}} - def create_environment_baseline(self, auth, csp_environment_id): + def create_environment_baseline(self, auth_credentials, csp_environment_id): return { CSPRole.BASIC_ACCESS: uuid4().hex, CSPRole.NETWORK_ADMIN: uuid4().hex, @@ -125,13 +111,13 @@ class MockCloudProvider(CloudProviderInterface): CSPRole.TECHNICAL_READ: uuid4().hex, } - def create_or_update_user(self, auth, environment_role): + def create_or_update_user(self, auth_credentials, environment_role): return {"id": uuid4().hex} - def suspend_user(self, auth, csp_user_id): + def suspend_user(self, auth_credentials, csp_user_id): pass - def delete_user(self, auth, csp_user_id): + def delete_user(self, auth_credentials, csp_user_id): pass def get_calculator_url(self): From cce25679a402ea108760fd3dbcb7a883bc0bd342 Mon Sep 17 00:00:00 2001 From: tomdds Date: Thu, 29 Aug 2019 17:03:00 -0400 Subject: [PATCH 04/10] Define potential structure for admin user return type --- atst/domain/csp/cloud.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/atst/domain/csp/cloud.py b/atst/domain/csp/cloud.py index 8717f7cc..9132b154 100644 --- a/atst/domain/csp/cloud.py +++ b/atst/domain/csp/cloud.py @@ -18,7 +18,7 @@ class CloudProviderInterface: def create_atat_admin_user(self, auth_credentials, csp_environment_id): """Creates a new, programmatic user in the CSP. Grants this user full permissions to administer - the CSP. Returns a dictionary containing user details, including user's API credentials. + the CSP. Arguments: auth_credentials -- Object containing CSP account credentials @@ -26,6 +26,11 @@ class CloudProviderInterface: Returns: object: Object representing new remote admin user, including credentials + Something like: + { + "user_id": string, + "credentials": dict, # structure TBD based on csp + } """ raise NotImplementedError() From 9712e6896e8bb20a642459573100ba9436df0d91 Mon Sep 17 00:00:00 2001 From: tomdds Date: Thu, 29 Aug 2019 17:20:35 -0400 Subject: [PATCH 05/10] Return True from suspend and delete CSP calls --- atst/domain/csp/cloud.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/atst/domain/csp/cloud.py b/atst/domain/csp/cloud.py index 9132b154..e58de376 100644 --- a/atst/domain/csp/cloud.py +++ b/atst/domain/csp/cloud.py @@ -69,7 +69,7 @@ class CloudProviderInterface: csp_user_id -- CSP internal user identifier Returns: - None + bool -- True on success """ raise NotImplementedError() @@ -81,7 +81,7 @@ class CloudProviderInterface: csp_user_id -- CSP internal user identifier Returns: - None + bool -- True on success Raises: TBDException: Some part of user deletion failed From e5e9f5a3e27caae26c698884a579bcd4947a3772 Mon Sep 17 00:00:00 2001 From: tomdds Date: Fri, 30 Aug 2019 09:57:42 -0400 Subject: [PATCH 06/10] Directly pass EnvironmentUser to CSP User upsert --- atst/domain/csp/cloud.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/atst/domain/csp/cloud.py b/atst/domain/csp/cloud.py index e58de376..f3448bc6 100644 --- a/atst/domain/csp/cloud.py +++ b/atst/domain/csp/cloud.py @@ -51,8 +51,8 @@ class CloudProviderInterface: Arguments: auth_credentials -- Object containing CSP account credentials - user_info -- object containing user data, if it has a csp_user_id - it will try to update a user with that id + user_info -- instance of EnvironmentRole containing user data + if it has a csp_user_id it will try to update that user csp_role_id -- The id of the role the user should be given in the CSP Raises: From 8d3f488d6dd9a797c497ef6c5a63e61d0bf8c5ff Mon Sep 17 00:00:00 2001 From: tomdds Date: Tue, 3 Sep 2019 10:10:11 -0400 Subject: [PATCH 07/10] Mark create env test ask skipped --- tests/domain/test_environments.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/domain/test_environments.py b/tests/domain/test_environments.py index e850f2df..4589b179 100644 --- a/tests/domain/test_environments.py +++ b/tests/domain/test_environments.py @@ -15,6 +15,14 @@ from tests.factories import ( ) +@pytest.mark.skip(reason="Reinstate and update once jobs api is up") +def test_create_environments(): + application = ApplicationFactory.create() + environments = Environments.create_many(application, ["Staging", "Production"]) + for env in environments: + assert env.cloud_id is not None + + def test_update_env_role(): env_role = EnvironmentRoleFactory.create(role=CSPRole.BASIC_ACCESS.value) new_role = CSPRole.TECHNICAL_READ.value From 74ad0064289ddf8a6cdfe53bc26933e2e826b26d Mon Sep 17 00:00:00 2001 From: tomdds Date: Tue, 3 Sep 2019 10:41:45 -0400 Subject: [PATCH 08/10] Specify return type of create_or_update_user --- atst/domain/csp/cloud.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/atst/domain/csp/cloud.py b/atst/domain/csp/cloud.py index f3448bc6..b62ab896 100644 --- a/atst/domain/csp/cloud.py +++ b/atst/domain/csp/cloud.py @@ -55,8 +55,8 @@ class CloudProviderInterface: if it has a csp_user_id it will try to update that user csp_role_id -- The id of the role the user should be given in the CSP - Raises: - NotImplementedError: [description] + Returns: + string: Returns the interal csp_user_id of the created/updated user account """ raise NotImplementedError() From a23a4846303aa1ef0cbefbdf6bb734f230dcb6b3 Mon Sep 17 00:00:00 2001 From: tomdds Date: Tue, 3 Sep 2019 10:43:04 -0400 Subject: [PATCH 09/10] add Environment model to create_environment arguments --- atst/domain/csp/cloud.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/atst/domain/csp/cloud.py b/atst/domain/csp/cloud.py index b62ab896..8bff0e59 100644 --- a/atst/domain/csp/cloud.py +++ b/atst/domain/csp/cloud.py @@ -4,12 +4,13 @@ from atst.models.environment_role import CSPRole class CloudProviderInterface: - def create_environment(self, auth_credentials, user): + def create_environment(self, auth_credentials, user, environment): """Create a new environment in the CSP. Arguments: auth_credentials -- Object containing CSP account credentials user -- ATAT user authorizing the environment creation + environment -- ATAT Environment model Returns: string: ID of created environment From 84580a133021ef2d7e7112919b7da8ed6c246c78 Mon Sep 17 00:00:00 2001 From: tomdds Date: Tue, 3 Sep 2019 15:12:14 -0400 Subject: [PATCH 10/10] Add type hinting to cloud interface and fix mismatch in mock implementation --- atst/domain/csp/cloud.py | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/atst/domain/csp/cloud.py b/atst/domain/csp/cloud.py index 8bff0e59..b517699c 100644 --- a/atst/domain/csp/cloud.py +++ b/atst/domain/csp/cloud.py @@ -1,10 +1,16 @@ +from typing import Dict from uuid import uuid4 from atst.models.environment_role import CSPRole +from atst.models.user import User +from atst.models.environment import Environment +from atst.models.environment_role import EnvironmentRole class CloudProviderInterface: - def create_environment(self, auth_credentials, user, environment): + def create_environment( + self, auth_credentials: Dict, user: User, environment: Environment + ) -> str: """Create a new environment in the CSP. Arguments: @@ -17,7 +23,9 @@ class CloudProviderInterface: """ raise NotImplementedError() - def create_atat_admin_user(self, auth_credentials, csp_environment_id): + def create_atat_admin_user( + self, auth_credentials: Dict, csp_environment_id: str + ) -> Dict: """Creates a new, programmatic user in the CSP. Grants this user full permissions to administer the CSP. @@ -35,7 +43,9 @@ class CloudProviderInterface: """ raise NotImplementedError() - def create_environment_baseline(self, auth_credentials, csp_environment_id): + def create_environment_baseline( + self, auth_credentials: Dict, csp_environment_id: str + ) -> Dict: """Provision the necessary baseline entities (such as roles) in the given environment Arguments: @@ -47,7 +57,9 @@ class CloudProviderInterface: """ raise NotImplementedError() - def create_or_update_user(self, auth_credentials, user_info, csp_role_id): + def create_or_update_user( + self, auth_credentials: Dict, user_info: EnvironmentRole, csp_role_id: str + ) -> str: """Creates a user or updates an existing user's role. Arguments: @@ -61,7 +73,7 @@ class CloudProviderInterface: """ raise NotImplementedError() - def suspend_user(self, auth_credentials, csp_user_id): + def suspend_user(self, auth_credentials: Dict, csp_user_id: str) -> bool: """Revoke all privileges for a user. Used to prevent user access while a full delete is being processed. @@ -74,7 +86,7 @@ class CloudProviderInterface: """ raise NotImplementedError() - def delete_user(self, auth_credentials, csp_user_id): + def delete_user(self, auth_credentials: Dict, csp_user_id: str) -> bool: """Given the csp-internal id for a user, initiate user deletion. Arguments: @@ -89,13 +101,13 @@ class CloudProviderInterface: """ raise NotImplementedError() - def get_calculator_url(self): + def get_calculator_url(self) -> str: """Returns the calculator url for the CSP. This will likely be a static property elsewhere once a CSP is chosen. """ raise NotImplementedError() - def get_environment_login_url(self, environment): + def get_environment_login_url(self, environment) -> str: """Returns the login url for a given environment This may move to be a computed property on the Environment domain object """ @@ -103,7 +115,7 @@ class CloudProviderInterface: class MockCloudProvider(CloudProviderInterface): - def create_environment(self, auth_credentials, user): + def create_environment(self, auth_credentials, user, environment): return uuid4().hex def create_atat_admin_user(self, auth_credentials, csp_environment_id): @@ -117,7 +129,7 @@ class MockCloudProvider(CloudProviderInterface): CSPRole.TECHNICAL_READ: uuid4().hex, } - def create_or_update_user(self, auth_credentials, environment_role): + def create_or_update_user(self, auth_credentials, user_info, csp_role_id): return {"id": uuid4().hex} def suspend_user(self, auth_credentials, csp_user_id):