コード例 #1
0
def test_get_config(ssl, protocol):
    """If a base url is specified in the environment, we use it."""
    with mock.patch.object(config, '_CONFIG', None):
        with mock.patch.dict(os.environ, {}, clear=True):
            token = utils.uuid4()
            use_https = 'True' if protocol == 'https' else 'False'
            account_number = int(time.time())
            cloudtrail_prefix = random.choice([
                'aardvark',
                'aardvark-',
                'flying-aardvark-',
                '42',
                utils.uuid4(),
            ])
            bucket_name = 'flying-aardvark-s3'
            os.environ['CLOUDIGRADE_TOKEN'] = token
            os.environ['CLOUDIGRADE_BASE_URL'] = 'example.com'
            os.environ['AWS_S3_BUCKET_NAME'] = bucket_name
            os.environ['CLOUDIGRADE_ROLE_CUSTOMER1'] = '{}:{}:{}'.format(
                utils.uuid4(), account_number, utils.uuid4())
            os.environ['CLOUDTRAIL_PREFIX'] = cloudtrail_prefix
            os.environ['AWS_ACCESS_KEY_ID_CUSTOMER1'] = utils.uuid4()
            os.environ['USE_HTTPS'] = use_https
            os.environ['SSL_VERIFY'] = 'True' if ssl else 'False'
            cfg = config.get_config()
            assert cfg['superuser_token'] == token
            assert cfg['base_url'] == 'example.com'
            assert cfg['scheme'] == protocol
            assert cfg['ssl-verify'] == ssl
            assert cfg['api_version'] == 'v1'
            assert len(cfg['aws_profiles']) == 1
            assert cfg['aws_profiles'][0]['name'] == 'CUSTOMER1'
            assert cfg['aws_profiles'][0]['cloudtrail_name'] == (
                f'{cloudtrail_prefix}{account_number}')
            assert cfg['cloudigrade_s3_bucket'] == bucket_name
コード例 #2
0
def test_negative_super_user_creation_fails():
    """Test that if super user creation fails, we get the right exception.

    If no super user token is provided, then config.get_config will call
    injector.make_super_user. If this fails, we want config.get_config
    to bail out with as informative of a message as possible, so tests
    can fail more gracefully and we can know what happened.

    This test ensures that if injector.make_super_user throws a RuntimeError,
    that config.get_config raises an exceptions.MissingConfigurationError so
    so that integrade.tests.conftest.check_superuser can catch that and let
    the user know what happened.
    """
    with mock.patch.object(config, '_CONFIG', None):
        with mock.patch.dict(os.environ, {}, clear=True):
            account_number = int(time.time())
            os.environ['CLOUDIGRADE_USER'] = '******'
            os.environ['CLOUDIGRADE_PASSWORD'] = '******'
            os.environ['CLOUDIGRADE_BASE_URL'] = 'example.com'
            os.environ['CLOUDIGRADE_ROLE_CUSTOMER1'] = '{}:{}:{}'.format(
                utils.uuid4(), account_number, utils.uuid4())
            os.environ['AWS_ACCESS_KEY_ID_CUSTOMER1'] = utils.uuid4()
            with mock.patch.object(injector,
                                   'make_super_user') as make_super_user:
                make_super_user.side_effect = RuntimeError()
                with pytest.raises(exceptions.MissingConfigurationError):
                    config.get_config()
コード例 #3
0
ファイル: test_api.py プロジェクト: jjeffers/integrade
def test_token_auth():
    """Test TokenAuth generates proper request header."""
    token = uuid4()
    header_format = uuid4()
    auth = api.TokenAuth(token, header_format)
    request = Mock()
    request.headers = {}
    changed_request = auth(request)
    assert changed_request is request
    assert 'Authorization' in request.headers
    assert request.headers['Authorization'] == f'{header_format} {token}'
コード例 #4
0
def test_raise_exception_missing_aws_image_config():
    """Test that when no aws_image_config file is present, an error is raised.

    This only occurs when the config.get_aws_image_config() function is called.
    """
    with mock.patch.object(config, '_AWS_CONFIG', None):
        with mock.patch.object(xdg.BaseDirectory, 'load_config_paths') as lcp:
            lcp.return_value = ('fake_path', )
            with mock.patch.object(os.path, 'isfile') as isfile:
                isfile.return_value = False
                with pytest.raises(exceptions.ConfigFileNotFoundError):
                    # pylint:disable=protected-access
                    config._get_config_file_path(utils.uuid4(), utils.uuid4())
        assert isfile.call_count == 1
コード例 #5
0
def test_negative_get_config_missing():
    """If a base url is specified in the environment, we use it."""
    with mock.patch.object(config, '_CONFIG', None):
        with mock.patch.dict(os.environ, {}, clear=True):
            with mock.patch.object(injector,
                                   'make_super_user') as make_super_user:
                make_super_user.return_value = utils.uuid4()
                os.environ['CLOUDIGRADE_ROLE_CUSTOMER1'] = '{}:{}:{}'.format(
                    utils.uuid4(), '1234', utils.uuid4())
                try:
                    config.get_config()
                except exceptions.MissingConfigurationError as e:
                    msg = str(e)
                    msg.replace('\n', ' ')
                    assert 'AWS access key id' in msg
コード例 #6
0
def create_bucket_for_cloudtrail(aws_profile):
    """Create an s3 bucket suitable to point cloudtrail to for given aws_profile.

    :returns: (string) name of the s3 bucket to point the cloudtrail to.
    """
    session = aws_session(aws_profile)
    s3client = session.client('s3')
    bucket_name = uuid4()
    s3client.create_bucket(Bucket=bucket_name, ACL='public-read-write')
    unique_name1 = uuid4()
    unique_name2 = uuid4()
    new_policy = {
        'Version':
        '2012-10-17',
        'Statement': [{
            'Sid': f'{unique_name1}',
            'Effect': 'Allow',
            'Principal': {
                'Service': 'cloudtrail.amazonaws.com'
            },
            'Action': 's3:GetBucketAcl',
            'Resource': f'arn:aws:s3:::{bucket_name}'
        }, {
            'Sid': f'{unique_name2}',
            'Effect': 'Allow',
            'Principal': {
                'Service': 'cloudtrail.amazonaws.com'
            },
            'Action': 's3:PutObject',
            'Resource': f'arn:aws:s3:::{bucket_name}/AWSLogs/*',
            'Condition': {
                'StringEquals': {
                    's3:x-amz-acl': 'bucket-owner-full-control'
                }
            }
        }]
    }

    s3_resource = session.resource('s3')
    bucket_policy = s3_resource.BucketPolicy(bucket_name)
    bucket_policy.put(Policy=json.dumps(new_policy))
    return bucket_name
コード例 #7
0
def test_create():
    """Ensure user accounts can be created with username and password.

    :id: 5099a61d-7aa6-4c1b-8408-d030f210cd08
    :description: Ensure an user account can be created by an super user
        account with only username and password.
    :steps: With an authenticated superuser, send a post request to
        /auth/user/create/ with an username and password.
    :expectedresults: The server returns a 201 response with the information of
        the created user. The information should include the information passed
        as payload to the create request and also an ID should be created.
    """
    create_user_account({
        'email': '',
        'password': gen_password(),
        'username': uuid4(),
    })
コード例 #8
0
def test_create_with_email():
    """Ensure user accounts can be created with username, email and password.

    :id: 003ac47f-9946-4ffe-b49d-732dbffe1cfc
    :description: Ensure an user account can be created by an super user
        account with username, email and password.
    :steps: With an authenticated superuser, send a post request to
        /auth/user/create/ with an username, email and password.
    :expectedresults: The server returns a 201 response with the information of
        the created user. The information should include the information passed
        as payload to the create request and also an ID should be created.
    """
    create_user_account({
        'email': '*****@*****.**',
        'username': uuid4(),
        'password': gen_password()
    })
コード例 #9
0
ファイル: test_login.py プロジェクト: jjeffers/integrade
def test_token_negative(endpoint):
    """Given that we have an invalid token, we cannot make requests.

    :id: a87f7069-3ee9-4435-a953-fd8664199419
    :description: Test that if we have a bad token, we cannot use it to make
        requests to any of the /api/v1/* endpoints
    :steps:
        1) Send a GET request with a invalid authorization token in the header
           to all /api/v1/* endpoints.
        2) Assert that we get a 401 response for all requests.
    :expectedresults: The server rejects our invalid token for all /api/v1/*
        endpoints.
    """
    client = api.Client(response_handler=api.echo_handler)
    auth = api.TokenAuth(uuid4())
    response = client.get(f'/api/v1/{endpoint}', auth=auth)
    assert response.status_code == 401
    assert response.json() == {'detail': 'Invalid token.'}
コード例 #10
0
def create_cloud_account(auth, n, cloudtrails_to_delete=None, name=_SENTINEL):
    """Create a cloud account based on configured AWS customer info."""
    client = api.Client(authenticate=False)
    cfg = config.get_config()
    aws_profile = cfg['aws_profiles'][n]
    acct_arn = aws_profile['arn']
    cloud_account = {
        'account_arn': acct_arn,
        'name': uuid4() if name is _SENTINEL else name,
        'resourcetype': 'AwsAccount'
    }
    create_response = client.post(urls.CLOUD_ACCOUNT,
                                  payload=cloud_account,
                                  auth=auth)
    assert create_response.status_code == 201

    if isinstance(cloudtrails_to_delete, list):
        cloudtrails_to_delete.append(
            (aws_profile['name'], aws_profile['cloudtrail_name']))
    return create_response.json()
コード例 #11
0
def test_create_multiple_cloud_accounts(drop_account_data,
                                        cloudtrails_to_delete):
    """Ensure cloud accounts can be registered to a user.

    :id: f1db2617-fd15-4270-b9d3-595db001e1e7
    :description: Ensure an user can register multiple cloud accounts as long
        as each ARN is associated with unique cloud accounts.
    :steps: 1) Create a user and authenticate with their password
        2) Send POSTS with each of the cloud account's information to
            'api/v1/account/'
        3) Send a GET to 'api/v1/account/' to get a list of the cloud accounts
    :expectedresults: The server returns a 201 response with the information of
        the created accounts.
    """
    client = api.Client(authenticate=False)
    auth = get_auth()
    cfg = config.get_config()
    accts = []
    for profile in cfg['aws_profiles']:
        arn = profile['arn']
        cloud_account = {
            'account_arn': arn,
            'name': uuid4(),
            'resourcetype': 'AwsAccount'
        }
        create_response = client.post(urls.CLOUD_ACCOUNT,
                                      payload=cloud_account,
                                      auth=auth)
        assert create_response.status_code == 201
        cloudtrails_to_delete.append(
            (profile['name'], profile['cloudtrail_name']))

        accts.append(create_response.json())

    # list cloud accounts associated with this user
    list_response = client.get(urls.CLOUD_ACCOUNT, auth=auth)
    for acct in accts:
        assert acct in list_response.json()['results']
コード例 #12
0
ファイル: test_utils.py プロジェクト: jjeffers/integrade
def test_uuid4():
    """Test we get a unique string each time we call uuid4()."""
    assert isinstance(uuid4(), str)
    assert uuid4() != uuid4()
コード例 #13
0
ファイル: test_api.py プロジェクト: jjeffers/integrade
from json import JSONDecodeError
from unittest import mock
from unittest.mock import Mock, patch
from urllib.parse import urljoin

import pytest

import requests

from integrade import api, config, exceptions
from integrade.utils import uuid4


VALID_CONFIG = {
    'superuser': '******',
    'superuser_pass': uuid4(),
    'base_url': 'example.com',
                'superuser_token': uuid4(),
                'scheme': 'http',
                'ssl-verify': False,
                'api_version': 'v1'
}


def mock_request():
    """Return a mock request to include as attribute of mock response."""
    mock_request = mock.Mock(
        body='{"Test Body"}',
        path_url='/example/path/',
        headers={'Authorization': 'authorizationkey'},
        text='Some text',
コード例 #14
0
def test_create_cloud_account(drop_account_data, cloudtrails_to_delete):
    """Ensure cloud accounts can be registered to a user.

    :id: f7a9225b-83af-4567-b59a-a8bb62d612c9
    :description: Ensure an user can register a cloud account by specifying
        the role ARN.
    :steps: 1) Create a user and authenticate with their password
        2) Send a POST with the cloud account information to 'api/v1/account/'
        3) Send a GET to 'api/v1/account/' to get a list of the cloud accounts
        4) Attempt to create a duplicate and expect it to be rejected
        5) Attempt to delete the account and expect to succeed
    :expectedresults:
        1) The server returns a 201 response with the information
            of the created account.
        2) The account cannot be duplicated, and attempts to do so receive a
            400 status code.
        3) The account can be deleted and we get a 200 response.
    """
    auth = get_auth()
    client = api.Client(authenticate=False)
    cfg = config.get_config()
    aws_profile = cfg['aws_profiles'][0]
    profile_name = aws_profile['name']
    acct_arn = aws_profile['arn']
    cloud_account = {
        'account_arn': acct_arn,
        'name': uuid4(),
        'resourcetype': 'AwsAccount'
    }
    start = time()
    create_response = client.post(urls.CLOUD_ACCOUNT,
                                  payload=cloud_account,
                                  auth=auth)
    end = time()
    create_data = create_response.json()
    assert end - start < 7
    assert create_response.status_code == 201
    assert create_data['account_arn'] == acct_arn
    assert create_data['aws_account_id'] == aws_profile['account_number']

    # Assert that a cloudtrail has been set up in the customer's account
    cloudtrail_client = aws_utils.aws_session(profile_name).client(
        'cloudtrail')
    trail_names = [
        trail['Name']
        for trail in cloudtrail_client.describe_trails()['trailList']
    ]
    assert aws_profile['cloudtrail_name'] in trail_names
    # since account was created, add trail to cleanup
    cloudtrails_to_delete.append(
        (profile_name, aws_profile['cloudtrail_name']))

    acct = create_response.json()

    # get specific account
    account_url = urljoin(urls.CLOUD_ACCOUNT, '{}/'.format(acct['id']))
    get_response = client.get(account_url, auth=auth)
    assert acct == get_response.json()

    # list cloud accounts associated with this user
    list_response = client.get(urls.CLOUD_ACCOUNT, auth=auth)
    assert acct in list_response.json()['results']

    # Check if account name can be patched
    payload = {
        'name': 'new_name',
        'resourcetype': 'AwsAccount',
    }
    response = client.patch(account_url, payload=payload, auth=auth)
    response = client.get(account_url, auth=auth)
    assert response.json()['name'] == 'new_name'

    # Check if an account can be updated
    payload = {
        'account_arn': acct_arn,
        'name': 'new_name2',
        'resourcetype': 'AwsAccount',
    }
    response = client.put(account_url, payload=payload, auth=auth)
    response = client.get(account_url, auth=auth)
    assert response.json()['name'] == 'new_name2'

    # assert we cannot create duplicate
    client.response_handler = api.echo_handler
    response = client.post(urls.CLOUD_ACCOUNT,
                           payload=cloud_account,
                           auth=auth)
    assert response.status_code == 400
    assert 'account_arn' in response.json().keys()
    assert 'already exists' in response.json()['account_arn'][0]

    # attempt to delete the specific account
    delete_response = client.delete(urljoin(urls.CLOUD_ACCOUNT,
                                            '{}/'.format(acct['id'])),
                                    auth=auth)
    assert delete_response.status_code == 204
コード例 #15
0
ファイル: test_images.py プロジェクト: jjeffers/integrade
def images_data():
    """Create test data for the tests on this module.

    To be able to verify that the image API endpoing works we need:

    * One super user acccount
    * Two regular user account
    * Image data for each user
    """
    utils.drop_image_data()

    user1 = utils.create_user_account()
    user2 = utils.create_user_account()
    auth1 = utils.get_auth(user1)
    auth2 = utils.get_auth(user2)

    # user1 will have 2 images
    images1 = [
        {
            'ec2_ami_id': str(random.randint(100000, 999999999999)),
            'rhel': True,
            'rhel_detected': True,
            'openshift': False,
            'openshift_detected': False,
        },
        {
            'ec2_ami_id': str(random.randint(100000, 999999999999)),
            'rhel': False,
            'rhel_detected': False,
            'openshift': True,
            'openshift_detected': True,
        },
    ]

    # user2 will have 3 images
    images2 = [
        {
            'ec2_ami_id': str(random.randint(100000, 999999999999)),
            'rhel': True,
            'rhel_detected': True,
            'openshift': False,
            'openshift_detected': False,
        },
        {
            'ec2_ami_id': str(random.randint(100000, 999999999999)),
            'rhel': True,
            'rhel_detected': True,
            'openshift': True,
            'openshift_detected': True,
        },
        {
            'ec2_ami_id': str(random.randint(100000, 999999999999)),
            'rhel': False,
            'rhel_detected': False,
            'openshift': True,
            'openshift_detected': True,
        },
    ]

    for user, images in zip((user1, user2), (images1, images2)):
        account = inject_aws_cloud_account(
            user['id'],
            name=uuid4(),
        )

        for image in images:
            if image['rhel'] and image['openshift']:
                image_type = 'rhel,openshift'
            elif image['rhel'] and not image['openshift']:
                image_type = 'rhel'
            elif not image['rhel'] and image['openshift']:
                image_type = 'openshift'
            else:
                raise ValueError('Not a valid image type.')

            image['id'] = inject_instance_data(
                account['id'],
                image_type,
                [random.randint(0, 20)],
                ec2_ami_id=image['ec2_ami_id'],
            )['image_id']

    return user1, user2, auth1, auth2, images1, images2
コード例 #16
0
ファイル: test_images.py プロジェクト: jjeffers/integrade
def test_challenge_image(superuser, method):
    """Test if a challenge flags for RHEL and OS can be changed.

    :id: ec5fe0b6-9852-48db-a2ba-98d01aeaac28
    :description: Try to change challenge flags on an image and ensure that
        change is reflected afterwards.
    :steps:
        1. Create an image in a known account and make sure the challenge
           flags are false by default.
        2. Use both PUT and PATCH forms of the image endpoint to set a flag to
           true
    :expectedresults:
        The image data now reflects this change.
    """
    cfg = config.get_config()
    user = utils.create_user_account()
    auth = utils.get_auth(user)

    client = api.Client(authenticate=False)
    account = inject_aws_cloud_account(
        user['id'],
        name=uuid4(),
    )
    image_type = ''
    ec2_ami_id = str(random.randint(100000, 999999999999))

    image_id = inject_instance_data(
        account['id'],
        image_type,
        [random.randint(0, 20)],
        ec2_ami_id=ec2_ami_id,
    )['image_id']

    if superuser:
        auth = api.TokenAuth(cfg.get('superuser_token'))

    image_url = urljoin(urls.IMAGE, str(image_id)) + '/'

    # Ensure the image owner can fetch it
    response = client.get(image_url, auth=auth).json()

    assert response['rhel_challenged'] is False
    assert response['openshift_challenged'] is False

    for tag in ('rhel', 'openshift'):
        if method == 'put':
            response[f'{tag}_challenged'] = True
            response = client.put(image_url, response, auth=auth).json()
        elif method == 'patch':
            data = {
                'resourcetype': 'AwsMachineImage',
                f'{tag}_challenged': True,
            }
            response = client.patch(image_url, data, auth=auth).json()
        else:
            pytest.fail(f'Unknown method "{method}"')
        assert response[f'{tag}_challenged'] is True

    # Make sure the change is reflected in new responses
    response = client.get(image_url, auth=auth).json()
    response[f'{tag}_challenged'] = True

    # Ensure any other user can't fetch it
    response = client.get(image_url, auth=auth)
    assert response.status_code == 200
    assert response.json()[f'{tag}_challenged']
コード例 #17
0
ファイル: config.py プロジェクト: jjeffers/integrade
def get_config(create_superuser=True, need_base_url=True):
    """Return a copy of the global config dictionary.

    This method makes use of a cache. If the cache is empty, the configuration
    file is parsed and the cache is populated. Otherwise, a copy of the cached
    configuration object is returned.

    :returns: A copy of the global integrade configuration object.
    """
    global _CONFIG  # pylint:disable=global-statement
    if _CONFIG is None:
        _CONFIG = {}
        _CONFIG['api_version'] = os.getenv('CLOUDIGRADE_API_VERSION', 'v1')
        _CONFIG['cloudigrade_s3_bucket'] = os.getenv('AWS_S3_BUCKET_NAME')

        ref_slug = os.environ.get('CI_COMMIT_REF_SLUG', '')
        cloudtrail_prefix = os.getenv('CLOUDTRAIL_PREFIX',
                                      f'review-{ref_slug}')

        # The location of the API endpoints and UI may be configured directly
        # with `CLOUDIGRADE_BASE_URL` -OR- we can determine a location based
        # on `CI_COMMIT_REF_SLUG` which comes from Gitlab CI and is our
        # current branch name.

        _CONFIG['base_url'] = os.getenv(
            'CLOUDIGRADE_BASE_URL',
            f'review-{ref_slug}.5a9f.insights-dev.openshiftapps.com',
        )

        _CONFIG['openshift_prefix'] = os.getenv(
            'OPENSHIFT_PREFIX',
            f'c-review-{ref_slug[:29]}-',
        )

        # pull all customer roles out of environ

        def is_role(string):
            return string.startswith('CLOUDIGRADE_ROLE_')

        def profile_name(string): return string.replace(
            'CLOUDIGRADE_ROLE_', '')

        profiles = [{'arn': os.environ.get(role),
                     'name': profile_name(role)}
                    for role in filter(is_role, os.environ.keys())
                    ]
        profiles.sort(key=lambda p: p['name'])
        _CONFIG['aws_profiles'] = profiles

        missing_config_errors = []

        try:
            aws_image_config = get_aws_image_config()
        except exceptions.ConfigFileNotFoundError:
            aws_image_config = {}

        for i, profile in enumerate(_CONFIG['aws_profiles']):
            profile_name = profile['name'].upper()
            acct_arn = profile['arn']
            acct_num = [
                num for num in filter(
                    str.isdigit,
                    acct_arn.split(':'))][0]
            profile['account_number'] = acct_num
            profile['cloudtrail_name'] = f'{cloudtrail_prefix}{acct_num}'
            profile['access_key_id'] = os.environ.get(
                f'AWS_ACCESS_KEY_ID_{profile_name}')
            profile['images'] = aws_image_config.get('profiles', {}).get(
                profile_name, {}).get('images', [])

            if i == 0:
                if not profile['access_key_id']:
                    missing_config_errors.append(
                        f'Could not find AWS access key id for {profile_name}')

        if _CONFIG['base_url'] == '' and need_base_url:
            missing_config_errors.append(
                'Could not find $CLOUDIGRADE_BASE_URL set in in'
                ' your environment.'
            )
        if os.environ.get('USE_HTTPS', 'false').lower() == 'true':
            _CONFIG['scheme'] = 'https'
        else:
            _CONFIG['scheme'] = 'http'
        if os.environ.get('SSL_VERIFY', 'false').lower() == 'true':
            _CONFIG['ssl-verify'] = True
        else:
            _CONFIG['ssl-verify'] = False

        if missing_config_errors:
            raise exceptions.MissingConfigurationError(
                '\n'.join(missing_config_errors)
            )
        super_username = os.environ.get(
            'CLOUDIGRADE_USER', utils.uuid4()
        )
        _CONFIG['super_user_name'] = super_username
        super_password = os.environ.get(
            'CLOUDIGRADE_PASSWORD', utils.gen_password()
        )
        _CONFIG['super_user_password'] = super_password
        token = os.environ.get('CLOUDIGRADE_TOKEN', False)
        if not token and create_superuser:
            try:
                token = injector.make_super_user(
                    super_username, super_password)
            except RuntimeError as e:
                raise exceptions.MissingConfigurationError(
                    'Could not create a super user or token, error:\n'
                    f'{repr(e)}'
                )
        _CONFIG['superuser_token'] = token
    return deepcopy(_CONFIG)
コード例 #18
0
def test_create_cloud_account(cloudtrails_to_delete, aws_profile, request):
    """Ensure cloud accounts can be registered to a user.

    :id: bb8fa2a4-7ff7-43e6-affb-7a2dedaaab74
    :description: Ensure a user can create a cloud account.
    :steps: 1) Log in as a user.
    2) Send POST with the cloud account's information to
        'api/v2/account/'
    3) Send a GET to 'api/v2/account/' to get a list of the cloud accounts
    4) Run an instance in that account
    5) Check that Cloudigrade and AWS both show same instance_id
    6) Delete account
    7) Check instance in AWS
    :expectedresults: The server returns a 201 response with the information
    of the created account. Cloudigrade and AWS both show same instance_id.
    Delete account response returns status 204. After deletion, AWS
    instance_id.state is 'terminated'.
    """
    account_id = 0
    arn = aws_profile['arn']
    client = api.ClientV2()
    acct_data_params = {
        'account_arn': arn,
        'name': uuid4(),
        'cloud_type': 'aws',
    }
    delete_preexisting_accounts(aws_profile)
    # POST
    # Create an account
    add_acct_response = client.request('post',
                                       'accounts/',
                                       data=acct_data_params)
    assert add_acct_response.status_code == 201

    # Check AWS permissions
    acct_details = add_acct_response.json()
    permission = acct_details['content_object']['account_arn']
    assert 'allow-dev11-cloudigrade-metering' in permission

    # Start AWS session and cloudtrail client
    session = aws_utils.aws_session('DEV07CUSTOMER')
    env_bucket_name = config.get_config()['openshift_prefix'].strip(
        'c-review-')
    aws_cloudtrails = session.client(
        'cloudtrail').describe_trails()['trailList']
    aws_cloudtrail_found = False
    aws_cloudtrail_arn = ''
    cloudtrails_client = session.client('cloudtrail')

    # Find the cloudtrail for this particular account and check that
    # it's enabled.
    for trail in aws_cloudtrails:
        if env_bucket_name in trail['S3BucketName']:
            aws_cloudtrail_found = True
            aws_cloudtrail_arn = trail['TrailARN']
    assert aws_cloudtrail_found is True
    trail_status = cloudtrails_client.get_trail_status(Name=aws_cloudtrail_arn)
    assert trail_status['IsLogging'] is True

    # Find the recently added account so we can delete it
    accounts = fetch_api_accounts()
    for acct in accounts:
        if acct['content_object']['account_arn'] == arn:
            account_id = acct['account_id']

    # DELETE
    # Delete that account
    endpoint = f'accounts/{account_id}/'
    delete_acct_response = client.request('delete', endpoint)
    assert delete_acct_response.status_code == 204
    # Check that deleted account is no longer present in cloudigrade
    accounts = fetch_api_accounts()
    assert account_id not in accounts

    # Check that the cloudtrail has been disabled
    trail_status = cloudtrails_client.get_trail_status(Name=aws_cloudtrail_arn)
    assert trail_status['IsLogging'] is False

    # Cleanup: Remove cloudtrail from AWS
    cloudtrails_to_delete.append(
        (aws_profile['name'], aws_profile['cloudtrail_name']))