WIP: orchestration for env role creation

This commit is contained in:
dandds 2020-02-05 15:56:53 -05:00
parent 7c7dd08827
commit 4da68a1fab
8 changed files with 116 additions and 27 deletions

View File

@ -935,17 +935,7 @@ class AzureCloudProvider(CloudProviderInterface):
)
def create_user_role(self, payload: UserRoleCSPPayload):
# creds TBD
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
# )
graph_token = self._get_tenant_principal_token(payload.tenant_id)
if graph_token is None:
raise AuthenticationException(
"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"
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:
return UserRoleCSPResult(**response.json())

View File

@ -1,7 +1,7 @@
from typing import Dict
class CloudProviderInterface:
class CloudProviderInterface: # pragma: no cover
def set_secret(self, secret_key: str, secret_value: str):
raise NotImplementedError()

View File

@ -502,15 +502,14 @@ class UserCSPResult(AliasModel):
id: str
class UserRoles(str, Enum):
class UserRoleCSPPayload(BaseCSPPayload):
class Roles(str, Enum):
owner = "owner"
contributor = "contributor"
billing = "billing"
class UserRoleCSPPayload(BaseCSPPayload):
management_group_id: str
role: UserRoles
role: Roles
user_object_id: str

View File

@ -110,9 +110,9 @@ class EnvironmentRoles(object):
def disable(cls, 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
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
db.session.add(environment_role)

View File

@ -8,11 +8,17 @@ from atst.domain.csp.cloud.exceptions import GeneralCSPException
from atst.domain.csp.cloud import CloudProviderInterface
from atst.domain.applications import Applications
from atst.domain.environments import Environments
from atst.domain.environment_roles import EnvironmentRoles
from atst.domain.portfolios import Portfolios
from atst.domain.application_roles import ApplicationRoles
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.domain.csp.cloud.models import ApplicationCSPPayload, UserCSPPayload
from atst.domain.csp.cloud.models import (
ApplicationCSPPayload,
UserCSPPayload,
UserRoleCSPPayload,
)
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):
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)
def create_environment(self, environment_id=None):
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)
@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)
def dispatch_create_environment(self):
for environment_id in Environments.get_environments_pending_creation(

View File

@ -27,6 +27,10 @@ def update_celery(celery, app):
"task": "atst.jobs.dispatch_create_user",
"schedule": 60,
},
"beat-dispatch_create_environment_role": {
"task": "atst.jobs.dispatch_create_environment_role",
"schedule": 60,
},
}
class ContextTask(celery.Task):

View File

@ -115,14 +115,14 @@ def test_disable_checks_env_role_provisioning_status():
cloud_id="cloud-id", root_user_info={"credentials": "credentials"}
)
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)
assert env_role1.disabled
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)
assert env_role2.disabled

View File

@ -1,9 +1,10 @@
import pendulum
import pytest
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.models import UserRoleCSPResult
from atst.domain.portfolios import Portfolios
from atst.models import ApplicationRoleStatus
@ -12,12 +13,14 @@ from atst.jobs import (
dispatch_create_environment,
dispatch_create_application,
dispatch_create_user,
dispatch_create_environment_role,
dispatch_create_atat_admin_user,
dispatch_provision_portfolio,
create_environment,
do_create_user,
do_provision_portfolio,
do_create_environment,
do_create_environment_role,
do_create_application,
do_create_atat_admin_user,
)
@ -310,3 +313,39 @@ def test_provision_portfolio_create_tenant(
# monkeypatch.setattr("atst.jobs.provision_portfolio", mock)
# dispatch_provision_portfolio.run()
# 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"