Merge pull request #1143 from dod-ccpo/consolidate-csp-interface
Simplify CloudProviderInterface and remove AWS impl.
This commit is contained in:
@@ -4,7 +4,6 @@ import alembic.config
|
||||
import alembic.command
|
||||
from logging.config import dictConfig
|
||||
from werkzeug.datastructures import FileStorage
|
||||
from tempfile import TemporaryDirectory
|
||||
from collections import OrderedDict
|
||||
|
||||
from atst.app import make_app, make_config
|
||||
@@ -41,7 +40,7 @@ def app(request):
|
||||
@pytest.fixture(autouse=True)
|
||||
def skip_audit_log(request):
|
||||
"""
|
||||
Conditionally skip tests marked with 'audit_log' based on the
|
||||
Conditionally skip tests marked with 'audit_log' based on the
|
||||
USE_AUDIT_LOG config value.
|
||||
"""
|
||||
config = make_config()
|
||||
|
@@ -1,100 +0,0 @@
|
||||
import pytest
|
||||
|
||||
from atst.domain.csp.cloud import EnvironmentCreationException
|
||||
from atst.jobs import (
|
||||
do_create_environment,
|
||||
do_create_atat_admin_user,
|
||||
do_create_environment_baseline,
|
||||
)
|
||||
|
||||
# pylint: disable=unused-import
|
||||
from tests.mock_boto3 import mock_aws, mock_boto3, AUTH_CREDENTIALS
|
||||
from tests.factories import EnvironmentFactory
|
||||
|
||||
|
||||
def test_create_environment_succeeds(mock_aws):
|
||||
environment = EnvironmentFactory.create()
|
||||
account_id = mock_aws.create_environment(
|
||||
AUTH_CREDENTIALS, environment.creator, environment
|
||||
)
|
||||
assert "account-id" == account_id
|
||||
|
||||
|
||||
@pytest.mark.mock_boto3({"organizations.describe_create_account.failure": True})
|
||||
def test_create_environment_raises_x_when_account_creation_fails(mock_aws):
|
||||
environment = EnvironmentFactory.create()
|
||||
with pytest.raises(EnvironmentCreationException):
|
||||
mock_aws.create_environment(AUTH_CREDENTIALS, environment.creator, environment)
|
||||
|
||||
|
||||
def test_create_atat_admin_user_succeeds(mock_aws):
|
||||
root_user_info = mock_aws.create_atat_admin_user(
|
||||
AUTH_CREDENTIALS, "csp_environment_id"
|
||||
)
|
||||
assert {
|
||||
"id": "user-id",
|
||||
"username": "user-name",
|
||||
"resource_id": "user-arn",
|
||||
"credentials": {
|
||||
"AccessKeyId": "access-key-id",
|
||||
"SecretAccessKey": "secret-access-key",
|
||||
},
|
||||
} == root_user_info
|
||||
|
||||
|
||||
@pytest.mark.mock_boto3({"iam.create_user.already_exists": True})
|
||||
def test_create_atat_admin_when_user_already_exists(mock_aws):
|
||||
root_user_info = mock_aws.create_atat_admin_user(
|
||||
AUTH_CREDENTIALS, "csp_environment_id"
|
||||
)
|
||||
assert {
|
||||
"id": "user-id",
|
||||
"username": "user-name",
|
||||
"resource_id": "user-arn",
|
||||
"credentials": {
|
||||
"AccessKeyId": "access-key-id",
|
||||
"SecretAccessKey": "secret-access-key",
|
||||
},
|
||||
} == root_user_info
|
||||
|
||||
iam_client = mock_aws.boto3.client("iam")
|
||||
iam_client.get_user.assert_any_call(UserName="atat")
|
||||
|
||||
|
||||
def test_create_environment_baseline_succeeds(mock_aws):
|
||||
baseline_info = mock_aws.create_environment_baseline(
|
||||
AUTH_CREDENTIALS, "csp_environment_id"
|
||||
)
|
||||
assert {"policies": [{"BillingReadOnly": "policy-arn"}]} == baseline_info
|
||||
|
||||
|
||||
@pytest.mark.mock_boto3({"iam.create_policy.already_exists": True})
|
||||
def test_create_environment_baseline_when_policy_already_exists(mock_aws):
|
||||
baseline_info = mock_aws.create_environment_baseline(
|
||||
AUTH_CREDENTIALS, "csp_environment_id"
|
||||
)
|
||||
assert "policies" in baseline_info
|
||||
|
||||
|
||||
def test_aws_provision_environment(mock_aws, session):
|
||||
environment = EnvironmentFactory.create()
|
||||
|
||||
do_create_environment(mock_aws, environment_id=environment.id)
|
||||
do_create_atat_admin_user(mock_aws, environment_id=environment.id)
|
||||
do_create_environment_baseline(mock_aws, environment_id=environment.id)
|
||||
|
||||
session.refresh(environment)
|
||||
|
||||
assert "account-id" == environment.cloud_id
|
||||
assert {
|
||||
"id": "user-id",
|
||||
"username": "user-name",
|
||||
"credentials": {
|
||||
"AccessKeyId": "access-key-id",
|
||||
"SecretAccessKey": "secret-access-key",
|
||||
},
|
||||
"resource_id": "user-arn",
|
||||
} == environment.root_user_info
|
||||
assert {
|
||||
"policies": [{"BillingReadOnly": "policy-arn"}]
|
||||
} == environment.baseline_info
|
@@ -175,40 +175,3 @@ class TestGetEnvironmentsPendingAtatUserCreation(EnvQueryTest):
|
||||
assert (
|
||||
len(Environments.get_environments_pending_atat_user_creation(self.NOW)) == 0
|
||||
)
|
||||
|
||||
|
||||
class TestGetEnvironmentsPendingBaselineCreation(EnvQueryTest):
|
||||
def test_with_provisioned_environment(self):
|
||||
self.create_portfolio_with_clins(
|
||||
[(self.YESTERDAY, self.TOMORROW)],
|
||||
{
|
||||
"cloud_id": uuid4().hex,
|
||||
"root_user_info": {"foo": "bar"},
|
||||
"baseline_info": {"foo": "bar"},
|
||||
},
|
||||
)
|
||||
assert (
|
||||
len(Environments.get_environments_pending_baseline_creation(self.NOW)) == 0
|
||||
)
|
||||
|
||||
def test_with_unprovisioned_environment(self):
|
||||
self.create_portfolio_with_clins(
|
||||
[(self.YESTERDAY, self.TOMORROW)],
|
||||
{
|
||||
"cloud_id": uuid4().hex,
|
||||
"root_user_info": {"foo": "bar"},
|
||||
"baseline_info": None,
|
||||
},
|
||||
)
|
||||
assert (
|
||||
len(Environments.get_environments_pending_baseline_creation(self.NOW)) == 1
|
||||
)
|
||||
|
||||
def test_with_unprovisioned_expired_clins_environment(self):
|
||||
self.create_portfolio_with_clins(
|
||||
[(self.YESTERDAY, self.YESTERDAY)],
|
||||
{"cloud_id": uuid4().hex, "root_user_info": {"foo": "bar"}},
|
||||
)
|
||||
assert (
|
||||
len(Environments.get_environments_pending_baseline_creation(self.NOW)) == 0
|
||||
)
|
||||
|
@@ -1,171 +0,0 @@
|
||||
import pytest
|
||||
from unittest.mock import Mock
|
||||
|
||||
from atst.domain.csp.cloud import AWSCloudProvider
|
||||
|
||||
|
||||
AWS_CONFIG = {
|
||||
"AWS_ACCESS_KEY_ID": "",
|
||||
"AWS_SECRET_KEY": "",
|
||||
"AWS_REGION_NAME": "us-fake-1",
|
||||
}
|
||||
AUTH_CREDENTIALS = {
|
||||
"aws_access_key_id": AWS_CONFIG["AWS_ACCESS_KEY_ID"],
|
||||
"aws_secret_access_key": AWS_CONFIG["AWS_SECRET_KEY"],
|
||||
}
|
||||
|
||||
|
||||
def mock_boto_organizations(_config=None, **kwargs):
|
||||
describe_create_account_status = (
|
||||
"SUCCEEDED"
|
||||
if _config.get("organizations.describe_create_account.failure", False) == False
|
||||
else "FAILED"
|
||||
)
|
||||
|
||||
import boto3
|
||||
|
||||
mock = Mock(wraps=boto3.client("organizations", **kwargs))
|
||||
|
||||
# https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/organizations.html#Organizations.Client.create_account
|
||||
mock.create_account = Mock(
|
||||
return_value={
|
||||
"CreateAccountStatus": {
|
||||
"Id": "create-account-status-id",
|
||||
"AccountName": "account-name",
|
||||
"AccountId": "account-id",
|
||||
"State": "SUCCEEDED",
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
# https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/organizations.html#Organizations.Client.describe_create_account_status
|
||||
mock.describe_create_account_status = Mock(
|
||||
return_value={
|
||||
"CreateAccountStatus": {
|
||||
"Id": "create-account-status-id",
|
||||
"AccountName": "account-name",
|
||||
"AccountId": "account-id",
|
||||
"State": describe_create_account_status,
|
||||
}
|
||||
}
|
||||
)
|
||||
return mock
|
||||
|
||||
|
||||
def mock_boto_iam(_config=None, **kwargs):
|
||||
user_already_exists = _config.get("iam.create_user.already_exists", False)
|
||||
policy_already_exists = _config.get("iam.create_policy.already_exists", False)
|
||||
|
||||
def _raise_entity_already_exists(**kwargs):
|
||||
raise real_iam_client.exceptions.EntityAlreadyExistsException(
|
||||
{"Error": {}}, "operation-name"
|
||||
)
|
||||
|
||||
import boto3
|
||||
|
||||
real_iam_client = boto3.client("iam", **kwargs)
|
||||
mock = Mock(wraps=real_iam_client)
|
||||
mock.exceptions.EntityAlreadyExistsException = (
|
||||
real_iam_client.exceptions.EntityAlreadyExistsException
|
||||
)
|
||||
|
||||
mock.put_user_policy = Mock(return_value={"ResponseMetadata": {}})
|
||||
|
||||
if user_already_exists:
|
||||
mock.create_user = Mock(side_effect=_raise_entity_already_exists)
|
||||
else:
|
||||
mock.create_user = Mock(
|
||||
return_value={
|
||||
"User": {
|
||||
"UserId": "user-id",
|
||||
"Arn": "user-arn",
|
||||
"UserName": "user-name",
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
mock.get_user = Mock(
|
||||
return_value={
|
||||
"User": {"UserId": "user-id", "Arn": "user-arn", "UserName": "user-name"}
|
||||
}
|
||||
)
|
||||
|
||||
mock.create_access_key = Mock(
|
||||
return_value={
|
||||
"AccessKey": {
|
||||
"AccessKeyId": "access-key-id",
|
||||
"SecretAccessKey": "secret-access-key",
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
if policy_already_exists:
|
||||
mock.create_policy = Mock(side_effect=_raise_entity_already_exists)
|
||||
else:
|
||||
mock.create_policy = Mock(return_value={"Policy": {"Arn": "policy-arn"}})
|
||||
|
||||
return mock
|
||||
|
||||
|
||||
def mock_boto_sts(_config=None, **kwargs):
|
||||
import boto3
|
||||
|
||||
mock = Mock(wraps=boto3.client("sts", **kwargs))
|
||||
mock.assume_role = Mock(
|
||||
return_value={
|
||||
"Credentials": {
|
||||
"AccessKeyId": "access-key-id",
|
||||
"SecretAccessKey": "secret-access-key",
|
||||
"SessionToken": "session-token",
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
return mock
|
||||
|
||||
|
||||
class MockBoto3:
|
||||
CLIENTS = {
|
||||
"organizations": mock_boto_organizations,
|
||||
"iam": mock_boto_iam,
|
||||
"sts": mock_boto_sts,
|
||||
}
|
||||
|
||||
def __init__(self, config=None):
|
||||
self.config = config or {}
|
||||
self.client_instances = {}
|
||||
|
||||
def client(self, client_name, **kwargs):
|
||||
"""
|
||||
Return a new mock client for the given `client_name`, either by
|
||||
retrieving it from the `client_instances` cache or by instantiating
|
||||
it for the first time.
|
||||
|
||||
Params should be the same ones you'd pass to `boto3.client`.
|
||||
"""
|
||||
|
||||
if client_name in self.client_instances:
|
||||
return self.client_instances[client_name]
|
||||
|
||||
try:
|
||||
client_fn = self.CLIENTS[client_name]
|
||||
client_instance = client_fn(**kwargs, _config=self.config)
|
||||
self.client_instances[client_name] = client_instance
|
||||
return client_instance
|
||||
except KeyError:
|
||||
raise ValueError(f"MockBoto3: {client_name} client is not yet implemented.")
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def mock_boto3(request):
|
||||
marks = request.node.get_closest_marker("mock_boto3")
|
||||
if marks:
|
||||
mock_config = marks.args[0] if len(marks.args) else {}
|
||||
else:
|
||||
mock_config = {}
|
||||
return MockBoto3(mock_config)
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def mock_aws(mock_boto3):
|
||||
return AWSCloudProvider(AWS_CONFIG, boto3=mock_boto3)
|
@@ -10,10 +10,8 @@ from atst.jobs import (
|
||||
RecordEnvironmentRoleFailure,
|
||||
do_create_environment,
|
||||
do_create_atat_admin_user,
|
||||
do_create_environment_baseline,
|
||||
dispatch_create_environment,
|
||||
dispatch_create_atat_admin_user,
|
||||
dispatch_create_environment_baseline,
|
||||
create_environment,
|
||||
dispatch_provision_user,
|
||||
do_provision_user,
|
||||
@@ -98,17 +96,6 @@ def test_create_atat_admin_user(csp, session):
|
||||
assert environment.root_user_info
|
||||
|
||||
|
||||
def test_create_environment_baseline(csp, session, app):
|
||||
environment = EnvironmentFactory.create(
|
||||
root_user_info={"credentials": csp.root_creds()}
|
||||
)
|
||||
do_create_environment_baseline(csp, environment.id)
|
||||
session.refresh(environment)
|
||||
|
||||
assert environment.baseline_info
|
||||
assert len(app.mailer.messages) > 0
|
||||
|
||||
|
||||
def test_dispatch_create_environment(session, monkeypatch):
|
||||
# Given that I have a portfolio with an active CLIN and two environments,
|
||||
# one of which is deleted
|
||||
@@ -166,39 +153,6 @@ def test_dispatch_create_atat_admin_user(session, monkeypatch):
|
||||
mock.delay.assert_called_once_with(environment_id=environment.id)
|
||||
|
||||
|
||||
def test_dispatch_create_environment_baseline(session, monkeypatch):
|
||||
portfolio = PortfolioFactory.create(
|
||||
applications=[
|
||||
{
|
||||
"environments": [
|
||||
{
|
||||
"cloud_id": uuid4().hex,
|
||||
"root_user_info": {},
|
||||
"baseline_info": None,
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
task_orders=[
|
||||
{
|
||||
"create_clins": [
|
||||
{
|
||||
"start_date": pendulum.now().subtract(days=1),
|
||||
"end_date": pendulum.now().add(days=1),
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
)
|
||||
mock = Mock()
|
||||
monkeypatch.setattr("atst.jobs.create_environment_baseline", mock)
|
||||
environment = portfolio.applications[0].environments[0]
|
||||
|
||||
dispatch_create_environment_baseline.run()
|
||||
|
||||
mock.delay.assert_called_once_with(environment_id=environment.id)
|
||||
|
||||
|
||||
def test_create_environment_no_dupes(session, celery_app, celery_worker):
|
||||
portfolio = PortfolioFactory.create(
|
||||
applications=[
|
||||
|
Reference in New Issue
Block a user