Merge pull request #1143 from dod-ccpo/consolidate-csp-interface

Simplify CloudProviderInterface and remove AWS impl.
This commit is contained in:
richard-dds
2019-10-29 13:47:14 -04:00
committed by GitHub
13 changed files with 60 additions and 874 deletions

View File

@@ -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()

View File

@@ -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

View File

@@ -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
)

View File

@@ -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)

View File

@@ -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=[