moto/tests/test_config/test_config.py
2019-03-02 18:37:20 -08:00

488 lines
21 KiB
Python

from datetime import datetime, timedelta
import boto3
from botocore.exceptions import ClientError
from nose.tools import assert_raises
from moto.config import mock_config
@mock_config
def test_put_configuration_recorder():
client = boto3.client('config', region_name='us-west-2')
# Try without a name supplied:
with assert_raises(ClientError) as ce:
client.put_configuration_recorder(ConfigurationRecorder={'roleARN': 'somearn'})
assert ce.exception.response['Error']['Code'] == 'InvalidConfigurationRecorderNameException'
assert 'is not valid, blank string.' in ce.exception.response['Error']['Message']
# Try with a really long name:
with assert_raises(ClientError) as ce:
client.put_configuration_recorder(ConfigurationRecorder={'name': 'a' * 257, 'roleARN': 'somearn'})
assert ce.exception.response['Error']['Code'] == 'ValidationException'
assert 'Member must have length less than or equal to 256' in ce.exception.response['Error']['Message']
# With resource types and flags set to True:
bad_groups = [
{'allSupported': True, 'includeGlobalResourceTypes': True, 'resourceTypes': ['item']},
{'allSupported': False, 'includeGlobalResourceTypes': True, 'resourceTypes': ['item']},
{'allSupported': True, 'includeGlobalResourceTypes': False, 'resourceTypes': ['item']},
{'allSupported': False, 'includeGlobalResourceTypes': False, 'resourceTypes': []}
]
for bg in bad_groups:
with assert_raises(ClientError) as ce:
client.put_configuration_recorder(ConfigurationRecorder={
'name': 'default',
'roleARN': 'somearn',
'recordingGroup': bg
})
assert ce.exception.response['Error']['Code'] == 'InvalidRecordingGroupException'
assert ce.exception.response['Error']['Message'] == 'The recording group provided is not valid'
# With an invalid Resource Type:
with assert_raises(ClientError) as ce:
client.put_configuration_recorder(ConfigurationRecorder={
'name': 'default',
'roleARN': 'somearn',
'recordingGroup': {
'allSupported': False,
'includeGlobalResourceTypes': False,
# 2 good, and 2 bad:
'resourceTypes': ['AWS::EC2::Volume', 'LOLNO', 'AWS::EC2::VPC', 'LOLSTILLNO']
}
})
assert ce.exception.response['Error']['Code'] == 'ValidationException'
assert "2 validation error detected: Value '['LOLNO', 'LOLSTILLNO']" in str(ce.exception.response['Error']['Message'])
assert 'AWS::EC2::Instance' in ce.exception.response['Error']['Message']
# Create a proper one:
client.put_configuration_recorder(ConfigurationRecorder={
'name': 'testrecorder',
'roleARN': 'somearn',
'recordingGroup': {
'allSupported': False,
'includeGlobalResourceTypes': False,
'resourceTypes': ['AWS::EC2::Volume', 'AWS::EC2::VPC']
}
})
result = client.describe_configuration_recorders()['ConfigurationRecorders']
assert len(result) == 1
assert result[0]['name'] == 'testrecorder'
assert result[0]['roleARN'] == 'somearn'
assert not result[0]['recordingGroup']['allSupported']
assert not result[0]['recordingGroup']['includeGlobalResourceTypes']
assert len(result[0]['recordingGroup']['resourceTypes']) == 2
assert 'AWS::EC2::Volume' in result[0]['recordingGroup']['resourceTypes'] \
and 'AWS::EC2::VPC' in result[0]['recordingGroup']['resourceTypes']
# Now update the configuration recorder:
client.put_configuration_recorder(ConfigurationRecorder={
'name': 'testrecorder',
'roleARN': 'somearn',
'recordingGroup': {
'allSupported': True,
'includeGlobalResourceTypes': True
}
})
result = client.describe_configuration_recorders()['ConfigurationRecorders']
assert len(result) == 1
assert result[0]['name'] == 'testrecorder'
assert result[0]['roleARN'] == 'somearn'
assert result[0]['recordingGroup']['allSupported']
assert result[0]['recordingGroup']['includeGlobalResourceTypes']
assert len(result[0]['recordingGroup']['resourceTypes']) == 0
# With a default recording group (i.e. lacking one)
client.put_configuration_recorder(ConfigurationRecorder={'name': 'testrecorder', 'roleARN': 'somearn'})
result = client.describe_configuration_recorders()['ConfigurationRecorders']
assert len(result) == 1
assert result[0]['name'] == 'testrecorder'
assert result[0]['roleARN'] == 'somearn'
assert result[0]['recordingGroup']['allSupported']
assert not result[0]['recordingGroup']['includeGlobalResourceTypes']
assert not result[0]['recordingGroup'].get('resourceTypes')
# Can currently only have exactly 1 Config Recorder in an account/region:
with assert_raises(ClientError) as ce:
client.put_configuration_recorder(ConfigurationRecorder={
'name': 'someotherrecorder',
'roleARN': 'somearn',
'recordingGroup': {
'allSupported': False,
'includeGlobalResourceTypes': False,
}
})
assert ce.exception.response['Error']['Code'] == 'MaxNumberOfConfigurationRecordersExceededException'
assert "maximum number of configuration recorders: 1 is reached." in ce.exception.response['Error']['Message']
@mock_config
def test_describe_configurations():
client = boto3.client('config', region_name='us-west-2')
# Without any configurations:
result = client.describe_configuration_recorders()
assert not result['ConfigurationRecorders']
client.put_configuration_recorder(ConfigurationRecorder={
'name': 'testrecorder',
'roleARN': 'somearn',
'recordingGroup': {
'allSupported': False,
'includeGlobalResourceTypes': False,
'resourceTypes': ['AWS::EC2::Volume', 'AWS::EC2::VPC']
}
})
result = client.describe_configuration_recorders()['ConfigurationRecorders']
assert len(result) == 1
assert result[0]['name'] == 'testrecorder'
assert result[0]['roleARN'] == 'somearn'
assert not result[0]['recordingGroup']['allSupported']
assert not result[0]['recordingGroup']['includeGlobalResourceTypes']
assert len(result[0]['recordingGroup']['resourceTypes']) == 2
assert 'AWS::EC2::Volume' in result[0]['recordingGroup']['resourceTypes'] \
and 'AWS::EC2::VPC' in result[0]['recordingGroup']['resourceTypes']
# Specify an incorrect name:
with assert_raises(ClientError) as ce:
client.describe_configuration_recorders(ConfigurationRecorderNames=['wrong'])
assert ce.exception.response['Error']['Code'] == 'NoSuchConfigurationRecorderException'
assert 'wrong' in ce.exception.response['Error']['Message']
# And with both a good and wrong name:
with assert_raises(ClientError) as ce:
client.describe_configuration_recorders(ConfigurationRecorderNames=['testrecorder', 'wrong'])
assert ce.exception.response['Error']['Code'] == 'NoSuchConfigurationRecorderException'
assert 'wrong' in ce.exception.response['Error']['Message']
@mock_config
def test_delivery_channels():
client = boto3.client('config', region_name='us-west-2')
# Try without a config recorder:
with assert_raises(ClientError) as ce:
client.put_delivery_channel(DeliveryChannel={})
assert ce.exception.response['Error']['Code'] == 'NoAvailableConfigurationRecorderException'
assert ce.exception.response['Error']['Message'] == 'Configuration recorder is not available to ' \
'put delivery channel.'
# Create a config recorder to continue testing:
client.put_configuration_recorder(ConfigurationRecorder={
'name': 'testrecorder',
'roleARN': 'somearn',
'recordingGroup': {
'allSupported': False,
'includeGlobalResourceTypes': False,
'resourceTypes': ['AWS::EC2::Volume', 'AWS::EC2::VPC']
}
})
# Try without a name supplied:
with assert_raises(ClientError) as ce:
client.put_delivery_channel(DeliveryChannel={})
assert ce.exception.response['Error']['Code'] == 'InvalidDeliveryChannelNameException'
assert 'is not valid, blank string.' in ce.exception.response['Error']['Message']
# Try with a really long name:
with assert_raises(ClientError) as ce:
client.put_delivery_channel(DeliveryChannel={'name': 'a' * 257})
assert ce.exception.response['Error']['Code'] == 'ValidationException'
assert 'Member must have length less than or equal to 256' in ce.exception.response['Error']['Message']
# Without specifying a bucket name:
with assert_raises(ClientError) as ce:
client.put_delivery_channel(DeliveryChannel={'name': 'testchannel'})
assert ce.exception.response['Error']['Code'] == 'NoSuchBucketException'
assert ce.exception.response['Error']['Message'] == 'Cannot find a S3 bucket with an empty bucket name.'
with assert_raises(ClientError) as ce:
client.put_delivery_channel(DeliveryChannel={'name': 'testchannel', 's3BucketName': ''})
assert ce.exception.response['Error']['Code'] == 'NoSuchBucketException'
assert ce.exception.response['Error']['Message'] == 'Cannot find a S3 bucket with an empty bucket name.'
# With an empty string for the S3 key prefix:
with assert_raises(ClientError) as ce:
client.put_delivery_channel(DeliveryChannel={
'name': 'testchannel', 's3BucketName': 'somebucket', 's3KeyPrefix': ''})
assert ce.exception.response['Error']['Code'] == 'InvalidS3KeyPrefixException'
assert 'empty s3 key prefix.' in ce.exception.response['Error']['Message']
# With an empty string for the SNS ARN:
with assert_raises(ClientError) as ce:
client.put_delivery_channel(DeliveryChannel={
'name': 'testchannel', 's3BucketName': 'somebucket', 'snsTopicARN': ''})
assert ce.exception.response['Error']['Code'] == 'InvalidSNSTopicARNException'
assert 'The sns topic arn' in ce.exception.response['Error']['Message']
# With an invalid delivery frequency:
with assert_raises(ClientError) as ce:
client.put_delivery_channel(DeliveryChannel={
'name': 'testchannel',
's3BucketName': 'somebucket',
'configSnapshotDeliveryProperties': {'deliveryFrequency': 'WRONG'}
})
assert ce.exception.response['Error']['Code'] == 'InvalidDeliveryFrequency'
assert 'WRONG' in ce.exception.response['Error']['Message']
assert 'TwentyFour_Hours' in ce.exception.response['Error']['Message']
# Create a proper one:
client.put_delivery_channel(DeliveryChannel={'name': 'testchannel', 's3BucketName': 'somebucket'})
result = client.describe_delivery_channels()['DeliveryChannels']
assert len(result) == 1
assert len(result[0].keys()) == 2
assert result[0]['name'] == 'testchannel'
assert result[0]['s3BucketName'] == 'somebucket'
# Overwrite it with another proper configuration:
client.put_delivery_channel(DeliveryChannel={
'name': 'testchannel',
's3BucketName': 'somebucket',
'snsTopicARN': 'sometopicarn',
'configSnapshotDeliveryProperties': {'deliveryFrequency': 'TwentyFour_Hours'}
})
result = client.describe_delivery_channels()['DeliveryChannels']
assert len(result) == 1
assert len(result[0].keys()) == 4
assert result[0]['name'] == 'testchannel'
assert result[0]['s3BucketName'] == 'somebucket'
assert result[0]['snsTopicARN'] == 'sometopicarn'
assert result[0]['configSnapshotDeliveryProperties']['deliveryFrequency'] == 'TwentyFour_Hours'
# Can only have 1:
with assert_raises(ClientError) as ce:
client.put_delivery_channel(DeliveryChannel={'name': 'testchannel2', 's3BucketName': 'somebucket'})
assert ce.exception.response['Error']['Code'] == 'MaxNumberOfDeliveryChannelsExceededException'
assert 'because the maximum number of delivery channels: 1 is reached.' in ce.exception.response['Error']['Message']
@mock_config
def test_describe_delivery_channels():
client = boto3.client('config', region_name='us-west-2')
client.put_configuration_recorder(ConfigurationRecorder={
'name': 'testrecorder',
'roleARN': 'somearn',
'recordingGroup': {
'allSupported': False,
'includeGlobalResourceTypes': False,
'resourceTypes': ['AWS::EC2::Volume', 'AWS::EC2::VPC']
}
})
# Without any channels:
result = client.describe_delivery_channels()
assert not result['DeliveryChannels']
client.put_delivery_channel(DeliveryChannel={'name': 'testchannel', 's3BucketName': 'somebucket'})
result = client.describe_delivery_channels()['DeliveryChannels']
assert len(result) == 1
assert len(result[0].keys()) == 2
assert result[0]['name'] == 'testchannel'
assert result[0]['s3BucketName'] == 'somebucket'
# Overwrite it with another proper configuration:
client.put_delivery_channel(DeliveryChannel={
'name': 'testchannel',
's3BucketName': 'somebucket',
'snsTopicARN': 'sometopicarn',
'configSnapshotDeliveryProperties': {'deliveryFrequency': 'TwentyFour_Hours'}
})
result = client.describe_delivery_channels()['DeliveryChannels']
assert len(result) == 1
assert len(result[0].keys()) == 4
assert result[0]['name'] == 'testchannel'
assert result[0]['s3BucketName'] == 'somebucket'
assert result[0]['snsTopicARN'] == 'sometopicarn'
assert result[0]['configSnapshotDeliveryProperties']['deliveryFrequency'] == 'TwentyFour_Hours'
# Specify an incorrect name:
with assert_raises(ClientError) as ce:
client.describe_delivery_channels(DeliveryChannelNames=['wrong'])
assert ce.exception.response['Error']['Code'] == 'NoSuchDeliveryChannelException'
assert 'wrong' in ce.exception.response['Error']['Message']
# And with both a good and wrong name:
with assert_raises(ClientError) as ce:
client.describe_delivery_channels(DeliveryChannelNames=['testchannel', 'wrong'])
assert ce.exception.response['Error']['Code'] == 'NoSuchDeliveryChannelException'
assert 'wrong' in ce.exception.response['Error']['Message']
@mock_config
def test_start_configuration_recorder():
client = boto3.client('config', region_name='us-west-2')
# Without a config recorder:
with assert_raises(ClientError) as ce:
client.start_configuration_recorder(ConfigurationRecorderName='testrecorder')
assert ce.exception.response['Error']['Code'] == 'NoSuchConfigurationRecorderException'
# Make the config recorder;
client.put_configuration_recorder(ConfigurationRecorder={
'name': 'testrecorder',
'roleARN': 'somearn',
'recordingGroup': {
'allSupported': False,
'includeGlobalResourceTypes': False,
'resourceTypes': ['AWS::EC2::Volume', 'AWS::EC2::VPC']
}
})
# Without a delivery channel:
with assert_raises(ClientError) as ce:
client.start_configuration_recorder(ConfigurationRecorderName='testrecorder')
assert ce.exception.response['Error']['Code'] == 'NoAvailableDeliveryChannelException'
# Make the delivery channel:
client.put_delivery_channel(DeliveryChannel={'name': 'testchannel', 's3BucketName': 'somebucket'})
# Start it:
client.start_configuration_recorder(ConfigurationRecorderName='testrecorder')
# Verify it's enabled:
result = client.describe_configuration_recorder_status()['ConfigurationRecordersStatus']
lower_bound = (datetime.utcnow() - timedelta(minutes=5))
assert result[0]['recording']
assert result[0]['lastStatus'] == 'PENDING'
assert lower_bound < result[0]['lastStartTime'].replace(tzinfo=None) <= datetime.utcnow()
assert lower_bound < result[0]['lastStatusChangeTime'].replace(tzinfo=None) <= datetime.utcnow()
@mock_config
def test_stop_configuration_recorder():
client = boto3.client('config', region_name='us-west-2')
# Without a config recorder:
with assert_raises(ClientError) as ce:
client.stop_configuration_recorder(ConfigurationRecorderName='testrecorder')
assert ce.exception.response['Error']['Code'] == 'NoSuchConfigurationRecorderException'
# Make the config recorder;
client.put_configuration_recorder(ConfigurationRecorder={
'name': 'testrecorder',
'roleARN': 'somearn',
'recordingGroup': {
'allSupported': False,
'includeGlobalResourceTypes': False,
'resourceTypes': ['AWS::EC2::Volume', 'AWS::EC2::VPC']
}
})
# Make the delivery channel for creation:
client.put_delivery_channel(DeliveryChannel={'name': 'testchannel', 's3BucketName': 'somebucket'})
# Start it:
client.start_configuration_recorder(ConfigurationRecorderName='testrecorder')
client.stop_configuration_recorder(ConfigurationRecorderName='testrecorder')
# Verify it's disabled:
result = client.describe_configuration_recorder_status()['ConfigurationRecordersStatus']
lower_bound = (datetime.utcnow() - timedelta(minutes=5))
assert not result[0]['recording']
assert result[0]['lastStatus'] == 'PENDING'
assert lower_bound < result[0]['lastStartTime'].replace(tzinfo=None) <= datetime.utcnow()
assert lower_bound < result[0]['lastStopTime'].replace(tzinfo=None) <= datetime.utcnow()
assert lower_bound < result[0]['lastStatusChangeTime'].replace(tzinfo=None) <= datetime.utcnow()
@mock_config
def test_describe_configuration_recorder_status():
client = boto3.client('config', region_name='us-west-2')
# Without any:
result = client.describe_configuration_recorder_status()
assert not result['ConfigurationRecordersStatus']
# Make the config recorder;
client.put_configuration_recorder(ConfigurationRecorder={
'name': 'testrecorder',
'roleARN': 'somearn',
'recordingGroup': {
'allSupported': False,
'includeGlobalResourceTypes': False,
'resourceTypes': ['AWS::EC2::Volume', 'AWS::EC2::VPC']
}
})
# Without specifying a config recorder:
result = client.describe_configuration_recorder_status()['ConfigurationRecordersStatus']
assert len(result) == 1
assert result[0]['name'] == 'testrecorder'
assert not result[0]['recording']
# With a proper name:
result = client.describe_configuration_recorder_status(
ConfigurationRecorderNames=['testrecorder'])['ConfigurationRecordersStatus']
assert len(result) == 1
assert result[0]['name'] == 'testrecorder'
assert not result[0]['recording']
# Invalid name:
with assert_raises(ClientError) as ce:
client.describe_configuration_recorder_status(ConfigurationRecorderNames=['testrecorder', 'wrong'])
assert ce.exception.response['Error']['Code'] == 'NoSuchConfigurationRecorderException'
assert 'wrong' in ce.exception.response['Error']['Message']
@mock_config
def test_delete_configuration_recorder():
client = boto3.client('config', region_name='us-west-2')
# Make the config recorder;
client.put_configuration_recorder(ConfigurationRecorder={
'name': 'testrecorder',
'roleARN': 'somearn',
'recordingGroup': {
'allSupported': False,
'includeGlobalResourceTypes': False,
'resourceTypes': ['AWS::EC2::Volume', 'AWS::EC2::VPC']
}
})
# Delete it:
client.delete_configuration_recorder(ConfigurationRecorderName='testrecorder')
# Try again -- it should be deleted:
with assert_raises(ClientError) as ce:
client.delete_configuration_recorder(ConfigurationRecorderName='testrecorder')
assert ce.exception.response['Error']['Code'] == 'NoSuchConfigurationRecorderException'
@mock_config
def test_delete_delivery_channel():
client = boto3.client('config', region_name='us-west-2')
# Need a recorder to test the constraint on recording being enabled:
client.put_configuration_recorder(ConfigurationRecorder={
'name': 'testrecorder',
'roleARN': 'somearn',
'recordingGroup': {
'allSupported': False,
'includeGlobalResourceTypes': False,
'resourceTypes': ['AWS::EC2::Volume', 'AWS::EC2::VPC']
}
})
client.put_delivery_channel(DeliveryChannel={'name': 'testchannel', 's3BucketName': 'somebucket'})
client.start_configuration_recorder(ConfigurationRecorderName='testrecorder')
# With the recorder enabled:
with assert_raises(ClientError) as ce:
client.delete_delivery_channel(DeliveryChannelName='testchannel')
assert ce.exception.response['Error']['Code'] == 'LastDeliveryChannelDeleteFailedException'
assert 'because there is a running configuration recorder.' in ce.exception.response['Error']['Message']
# Stop recording:
client.stop_configuration_recorder(ConfigurationRecorderName='testrecorder')
# Try again:
client.delete_delivery_channel(DeliveryChannelName='testchannel')
# Verify:
with assert_raises(ClientError) as ce:
client.delete_delivery_channel(DeliveryChannelName='testchannel')
assert ce.exception.response['Error']['Code'] == 'NoSuchDeliveryChannelException'