WIP: orchestration for env role creation
This commit is contained in:
parent
7c7dd08827
commit
4da68a1fab
@ -935,17 +935,7 @@ class AzureCloudProvider(CloudProviderInterface):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def create_user_role(self, payload: UserRoleCSPPayload):
|
def create_user_role(self, payload: UserRoleCSPPayload):
|
||||||
# creds TBD
|
graph_token = self._get_tenant_principal_token(payload.tenant_id)
|
||||||
graph_token = ""
|
|
||||||
# graph_token = self._get_up_token_for_resource(
|
|
||||||
# username,
|
|
||||||
# password,
|
|
||||||
# payload.tenant_id,
|
|
||||||
# self.sdk.cloud.endpoints.resource_manager
|
|
||||||
# )
|
|
||||||
# graph_token = self._get_tenant_principal_token(
|
|
||||||
# payload.tenant_id
|
|
||||||
# )
|
|
||||||
if graph_token is None:
|
if graph_token is None:
|
||||||
raise AuthenticationException(
|
raise AuthenticationException(
|
||||||
"Could not resolve graph token for tenant admin"
|
"Could not resolve graph token for tenant admin"
|
||||||
@ -968,7 +958,7 @@ class AzureCloudProvider(CloudProviderInterface):
|
|||||||
|
|
||||||
url = f"{self.sdk.cloud.endpoints.resource_manager}/providers/Microsoft.Management/managementGroups/{payload.tenant_id}/providers/Microsoft.Authorization/roleAssignments/{assignment_guid}?api-version=2015-07-01"
|
url = f"{self.sdk.cloud.endpoints.resource_manager}/providers/Microsoft.Management/managementGroups/{payload.tenant_id}/providers/Microsoft.Authorization/roleAssignments/{assignment_guid}?api-version=2015-07-01"
|
||||||
|
|
||||||
response = self.sdk.requests.post(url, headers=auth_header, json=request_body)
|
response = self.sdk.requests.put(url, headers=auth_header, json=request_body)
|
||||||
|
|
||||||
if response.ok:
|
if response.ok:
|
||||||
return UserRoleCSPResult(**response.json())
|
return UserRoleCSPResult(**response.json())
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
|
||||||
|
|
||||||
class CloudProviderInterface:
|
class CloudProviderInterface: # pragma: no cover
|
||||||
def set_secret(self, secret_key: str, secret_value: str):
|
def set_secret(self, secret_key: str, secret_value: str):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
@ -502,15 +502,14 @@ class UserCSPResult(AliasModel):
|
|||||||
id: str
|
id: str
|
||||||
|
|
||||||
|
|
||||||
class UserRoles(str, Enum):
|
class UserRoleCSPPayload(BaseCSPPayload):
|
||||||
|
class Roles(str, Enum):
|
||||||
owner = "owner"
|
owner = "owner"
|
||||||
contributor = "contributor"
|
contributor = "contributor"
|
||||||
billing = "billing"
|
billing = "billing"
|
||||||
|
|
||||||
|
|
||||||
class UserRoleCSPPayload(BaseCSPPayload):
|
|
||||||
management_group_id: str
|
management_group_id: str
|
||||||
role: UserRoles
|
role: Roles
|
||||||
user_object_id: str
|
user_object_id: str
|
||||||
|
|
||||||
|
|
||||||
|
@ -110,9 +110,9 @@ class EnvironmentRoles(object):
|
|||||||
def disable(cls, environment_role_id):
|
def disable(cls, environment_role_id):
|
||||||
environment_role = EnvironmentRoles.get_by_id(environment_role_id)
|
environment_role = EnvironmentRoles.get_by_id(environment_role_id)
|
||||||
|
|
||||||
if environment_role.csp_user_id and not environment_role.environment.is_pending:
|
if environment_role.cloud_id and not environment_role.environment.is_pending:
|
||||||
credentials = environment_role.environment.csp_credentials
|
credentials = environment_role.environment.csp_credentials
|
||||||
app.csp.cloud.disable_user(credentials, environment_role.csp_user_id)
|
app.csp.cloud.disable_user(credentials, environment_role.cloud_id)
|
||||||
|
|
||||||
environment_role.status = EnvironmentRole.Status.DISABLED
|
environment_role.status = EnvironmentRole.Status.DISABLED
|
||||||
db.session.add(environment_role)
|
db.session.add(environment_role)
|
||||||
|
59
atst/jobs.py
59
atst/jobs.py
@ -8,11 +8,17 @@ from atst.domain.csp.cloud.exceptions import GeneralCSPException
|
|||||||
from atst.domain.csp.cloud import CloudProviderInterface
|
from atst.domain.csp.cloud import CloudProviderInterface
|
||||||
from atst.domain.applications import Applications
|
from atst.domain.applications import Applications
|
||||||
from atst.domain.environments import Environments
|
from atst.domain.environments import Environments
|
||||||
|
from atst.domain.environment_roles import EnvironmentRoles
|
||||||
from atst.domain.portfolios import Portfolios
|
from atst.domain.portfolios import Portfolios
|
||||||
from atst.domain.application_roles import ApplicationRoles
|
from atst.domain.application_roles import ApplicationRoles
|
||||||
from atst.models.utils import claim_for_update, claim_many_for_update
|
from atst.models.utils import claim_for_update, claim_many_for_update
|
||||||
|
from atst.models import CSPRole
|
||||||
from atst.utils.localization import translate
|
from atst.utils.localization import translate
|
||||||
from atst.domain.csp.cloud.models import ApplicationCSPPayload, UserCSPPayload
|
from atst.domain.csp.cloud.models import (
|
||||||
|
ApplicationCSPPayload,
|
||||||
|
UserCSPPayload,
|
||||||
|
UserRoleCSPPayload,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class RecordFailure(celery.Task):
|
class RecordFailure(celery.Task):
|
||||||
@ -138,6 +144,41 @@ def do_create_environment(csp: CloudProviderInterface, environment_id=None):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def do_create_environment_role(csp: CloudProviderInterface, environment_role_id=None):
|
||||||
|
env_role = EnvironmentRoles.get_by_id(environment_role_id)
|
||||||
|
|
||||||
|
with claim_for_update(env_role) as env_role:
|
||||||
|
|
||||||
|
if env_role.cloud_id is not None:
|
||||||
|
return
|
||||||
|
|
||||||
|
env = env_role.environment
|
||||||
|
csp_details = env.application.portfolio.csp_data
|
||||||
|
app_role = env_role.application_role
|
||||||
|
|
||||||
|
role = None
|
||||||
|
if env_role.role == CSPRole.ADMIN:
|
||||||
|
role = UserRoleCSPPayload.Roles.owner
|
||||||
|
elif env_role.role == CSPRole.BILLING_READ:
|
||||||
|
role = UserRoleCSPPayload.Roles.billing
|
||||||
|
elif env_role.role == CSPRole.CONTRIBUTOR:
|
||||||
|
role = UserRoleCSPPayload.Roles.contributor
|
||||||
|
|
||||||
|
# resolve role
|
||||||
|
payload = UserRoleCSPPayload(
|
||||||
|
tenant_id=csp_details.get("tenant_id"),
|
||||||
|
management_group_id=env.cloud_id,
|
||||||
|
user_object_id=app_role.cloud_id,
|
||||||
|
role=role,
|
||||||
|
)
|
||||||
|
result = csp.create_user_role(payload)
|
||||||
|
|
||||||
|
env_role.cloud_id = result.id
|
||||||
|
db.session.add(env_role)
|
||||||
|
db.session.commit()
|
||||||
|
# TODO: should send notification email to the user, maybe with their portal login name
|
||||||
|
|
||||||
|
|
||||||
def do_create_atat_admin_user(csp: CloudProviderInterface, environment_id=None):
|
def do_create_atat_admin_user(csp: CloudProviderInterface, environment_id=None):
|
||||||
environment = Environments.get(environment_id)
|
environment = Environments.get(environment_id)
|
||||||
|
|
||||||
@ -186,6 +227,16 @@ def create_user(self, application_role_ids=None):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@celery.task(bind=True, base=RecordFailure)
|
||||||
|
def create_environment_role(self, environment_role_id=None):
|
||||||
|
do_work(
|
||||||
|
do_create_environment_role,
|
||||||
|
self,
|
||||||
|
app.csp.cloud,
|
||||||
|
environment_role_id=environment_role_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@celery.task(bind=True, base=RecordFailure)
|
@celery.task(bind=True, base=RecordFailure)
|
||||||
def create_environment(self, environment_id=None):
|
def create_environment(self, environment_id=None):
|
||||||
do_work(do_create_environment, self, app.csp.cloud, environment_id=environment_id)
|
do_work(do_create_environment, self, app.csp.cloud, environment_id=environment_id)
|
||||||
@ -219,6 +270,12 @@ def dispatch_create_user(self):
|
|||||||
create_user.delay(application_role_ids=application_role_ids)
|
create_user.delay(application_role_ids=application_role_ids)
|
||||||
|
|
||||||
|
|
||||||
|
@celery.task(bind=True)
|
||||||
|
def dispatch_create_environment_role(self):
|
||||||
|
for environment_role_id in EnvironmentRoles.get_pending_creation():
|
||||||
|
create_environment_role.delay(environment_role_id=environment_role_id)
|
||||||
|
|
||||||
|
|
||||||
@celery.task(bind=True)
|
@celery.task(bind=True)
|
||||||
def dispatch_create_environment(self):
|
def dispatch_create_environment(self):
|
||||||
for environment_id in Environments.get_environments_pending_creation(
|
for environment_id in Environments.get_environments_pending_creation(
|
||||||
|
@ -27,6 +27,10 @@ def update_celery(celery, app):
|
|||||||
"task": "atst.jobs.dispatch_create_user",
|
"task": "atst.jobs.dispatch_create_user",
|
||||||
"schedule": 60,
|
"schedule": 60,
|
||||||
},
|
},
|
||||||
|
"beat-dispatch_create_environment_role": {
|
||||||
|
"task": "atst.jobs.dispatch_create_environment_role",
|
||||||
|
"schedule": 60,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
class ContextTask(celery.Task):
|
class ContextTask(celery.Task):
|
||||||
|
@ -115,14 +115,14 @@ def test_disable_checks_env_role_provisioning_status():
|
|||||||
cloud_id="cloud-id", root_user_info={"credentials": "credentials"}
|
cloud_id="cloud-id", root_user_info={"credentials": "credentials"}
|
||||||
)
|
)
|
||||||
env_role1 = EnvironmentRoleFactory.create(environment=environment)
|
env_role1 = EnvironmentRoleFactory.create(environment=environment)
|
||||||
assert not env_role1.csp_user_id
|
assert not env_role1.cloud_id
|
||||||
env_role1 = EnvironmentRoles.disable(env_role1.id)
|
env_role1 = EnvironmentRoles.disable(env_role1.id)
|
||||||
assert env_role1.disabled
|
assert env_role1.disabled
|
||||||
|
|
||||||
env_role2 = EnvironmentRoleFactory.create(
|
env_role2 = EnvironmentRoleFactory.create(
|
||||||
environment=environment, csp_user_id="123456"
|
environment=environment, cloud_id="123456"
|
||||||
)
|
)
|
||||||
assert env_role2.csp_user_id
|
assert env_role2.cloud_id
|
||||||
env_role2 = EnvironmentRoles.disable(env_role2.id)
|
env_role2 = EnvironmentRoles.disable(env_role2.id)
|
||||||
assert env_role2.disabled
|
assert env_role2.disabled
|
||||||
|
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import pendulum
|
import pendulum
|
||||||
import pytest
|
import pytest
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from unittest.mock import Mock
|
from unittest.mock import Mock, MagicMock
|
||||||
|
|
||||||
from atst.domain.csp.cloud import MockCloudProvider
|
from atst.domain.csp.cloud import MockCloudProvider
|
||||||
|
from atst.domain.csp.cloud.models import UserRoleCSPResult
|
||||||
from atst.domain.portfolios import Portfolios
|
from atst.domain.portfolios import Portfolios
|
||||||
from atst.models import ApplicationRoleStatus
|
from atst.models import ApplicationRoleStatus
|
||||||
|
|
||||||
@ -12,12 +13,14 @@ from atst.jobs import (
|
|||||||
dispatch_create_environment,
|
dispatch_create_environment,
|
||||||
dispatch_create_application,
|
dispatch_create_application,
|
||||||
dispatch_create_user,
|
dispatch_create_user,
|
||||||
|
dispatch_create_environment_role,
|
||||||
dispatch_create_atat_admin_user,
|
dispatch_create_atat_admin_user,
|
||||||
dispatch_provision_portfolio,
|
dispatch_provision_portfolio,
|
||||||
create_environment,
|
create_environment,
|
||||||
do_create_user,
|
do_create_user,
|
||||||
do_provision_portfolio,
|
do_provision_portfolio,
|
||||||
do_create_environment,
|
do_create_environment,
|
||||||
|
do_create_environment_role,
|
||||||
do_create_application,
|
do_create_application,
|
||||||
do_create_atat_admin_user,
|
do_create_atat_admin_user,
|
||||||
)
|
)
|
||||||
@ -310,3 +313,39 @@ def test_provision_portfolio_create_tenant(
|
|||||||
# monkeypatch.setattr("atst.jobs.provision_portfolio", mock)
|
# monkeypatch.setattr("atst.jobs.provision_portfolio", mock)
|
||||||
# dispatch_provision_portfolio.run()
|
# dispatch_provision_portfolio.run()
|
||||||
# mock.delay.assert_called_once_with(portfolio_id=portfolio.id)
|
# mock.delay.assert_called_once_with(portfolio_id=portfolio.id)
|
||||||
|
|
||||||
|
|
||||||
|
def test_dispatch_create_environment_role(monkeypatch):
|
||||||
|
portfolio = PortfolioFactory.create(csp_data={"tenant_id": "123"})
|
||||||
|
app_role = ApplicationRoleFactory.create(
|
||||||
|
application=ApplicationFactory.create(portfolio=portfolio),
|
||||||
|
status=ApplicationRoleStatus.ACTIVE,
|
||||||
|
cloud_id="123",
|
||||||
|
)
|
||||||
|
env_role = EnvironmentRoleFactory.create(application_role=app_role)
|
||||||
|
|
||||||
|
mock = Mock()
|
||||||
|
monkeypatch.setattr("atst.jobs.create_environment_role", mock)
|
||||||
|
|
||||||
|
dispatch_create_environment_role.run()
|
||||||
|
|
||||||
|
mock.delay.assert_called_once_with(environment_role_id=env_role.id)
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_environment_role():
|
||||||
|
portfolio = PortfolioFactory.create(csp_data={"tenant_id": "123"})
|
||||||
|
app = ApplicationFactory.create(portfolio=portfolio)
|
||||||
|
app_role = ApplicationRoleFactory.create(
|
||||||
|
application=app, status=ApplicationRoleStatus.ACTIVE, cloud_id="123",
|
||||||
|
)
|
||||||
|
env = EnvironmentFactory.create(application=app, cloud_id="123")
|
||||||
|
env_role = EnvironmentRoleFactory.create(
|
||||||
|
environment=env, application_role=app_role, cloud_id=None
|
||||||
|
)
|
||||||
|
|
||||||
|
csp = Mock()
|
||||||
|
result = UserRoleCSPResult(id="a-cloud-id")
|
||||||
|
csp.create_user_role = MagicMock(return_value=result)
|
||||||
|
do_create_environment_role(csp, environment_role_id=env_role.id)
|
||||||
|
|
||||||
|
assert env_role.cloud_id == "a-cloud-id"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user