Example #1
0
def test_perform_snapshot_ignore_instance(mocker):
    """Test for method of the same name."""
    # some default settings for this test
    region = 'us-west-2'

    snapshot_settings = {
        'snapshot': {
            'minimum': 5,
            'frequency': '2 hours',
            'retention': '5 days'
        },
        'match': {
            'tag:backup': 'yes'
        },
        'ignore': []
    }

    # create an instance and record the id
    instance_id = mocks.create_instances(region, count=1)[0]
    snapshot_settings['ignore'].append(instance_id)

    # need to filter instances, so need dynamodb present
    mocks.create_dynamodb('us-east-1')
    dynamo.store_configuration('us-east-1', 'some_unique_id', '111122223333',
                               snapshot_settings)

    # patch the final method that takes a snapshot
    mocker.patch('ebs_snapper.utils.snapshot_and_tag')

    # since there are no snapshots, we should expect this to trigger one
    ctx = utils.MockContext()
    snapshot.perform_snapshot(ctx, region)

    # test results
    utils.snapshot_and_tag.assert_not_called()  # pylint: disable=E1103
Example #2
0
def test_clean_snapshots_tagged_timeout(mocker):
    """Test that we _DONT_ clean anything if runtime > 4 minutes"""
    # default settings
    region = 'us-east-1'
    mocks.create_dynamodb(region)
    ctx = utils.MockContext()
    ctx.set_remaining_time_in_millis(5)  # 5 millis remaining

    # create an instance and record the id
    instance_id = mocks.create_instances(region, count=1)[0]

    # setup the min # snaps for the instance
    config_data = {
        "match": {"instance-id": instance_id},
        "snapshot": {
            "retention": "6 days", "minimum": 0, "frequency": "13 hours"
        }
    }

    # put it in the table, be sure it succeeded
    dynamo.store_configuration(region, 'foo', '111122223333', config_data)

    # figure out the EBS volume that came with our instance
    volume_id = utils.get_volumes([instance_id], region)[0]['VolumeId']

    # make a snapshot that should be deleted today too
    now = datetime.datetime.now(dateutil.tz.tzutc())
    delete_on = now.strftime('%Y-%m-%d')
    utils.snapshot_and_tag(instance_id, 'ami-123abc', volume_id, delete_on, region)

    mocker.patch('ebs_snapper.utils.delete_snapshot')
    clean.clean_snapshot(ctx, region)

    # ensure we DO NOT take a snapshot if our runtime was 5 minutes
    assert not utils.delete_snapshot.called
Example #3
0
def test_get_instance():
    """Test for method of the same name"""
    # def get_instance(instance_id, region):
    region = 'us-west-2'

    instance_id = mocks.create_instances(region, count=1)[0]
    found_instance = utils.get_instance(instance_id, region)
    assert found_instance['InstanceId'] == instance_id
Example #4
0
def test_perform_fanout_all_regions_clean(mocker):
    """Test for method of the same name."""
    mocks.create_sns_topic('CleanSnapshotTopic')
    mocks.create_dynamodb()

    expected_regions = utils.get_regions()
    for r in expected_regions:  # must have an instance in the region to clean it
        mocks.create_instances(region=r)
    expected_sns_topic = utils.get_topic_arn('CleanSnapshotTopic', 'us-east-1')

    ctx = utils.MockContext()
    mocker.patch('ebs_snapper.clean.send_fanout_message')

    # fan out, and be sure we touched every region
    clean.perform_fanout_all_regions(ctx)
    for r in expected_regions:
        clean.send_fanout_message.assert_any_call(  # pylint: disable=E1103
            ctx,
            cli=False,
            region=r,
            topic_arn=expected_sns_topic)
Example #5
0
def test_clean_tagged_snapshots_ignore_volume(mocker):
    """Test for method of the same name."""
    # default settings
    region = 'us-east-1'
    mocks.create_dynamodb(region)

    # create an instance and record the id
    instance_id = mocks.create_instances(region, count=1)[0]
    ctx = utils.MockContext()

    # setup the min # snaps for the instance
    config_data = {
        "match": {
            "instance-id": instance_id
        },
        "snapshot": {
            "retention": "6 days",
            "minimum": 0,
            "frequency": "13 hours"
        },
        "ignore": []
    }

    # put it in the table, be sure it succeeded
    dynamo.store_configuration(region, 'foo', AWS_MOCK_ACCOUNT, config_data)

    # figure out the EBS volume that came with our instance
    volume_id = utils.get_volumes([instance_id], region)[0]['VolumeId']
    config_data["ignore"].append(volume_id)

    # make a snapshot that should be deleted today too
    now = datetime.datetime.now(dateutil.tz.tzutc())
    delete_on = now.strftime('%Y-%m-%d')
    utils.snapshot_and_tag(instance_id, 'ami-123abc', volume_id, delete_on,
                           region)
    snapshot_id = utils.most_recent_snapshot(volume_id, region)['SnapshotId']

    mocker.patch('ebs_snapper.utils.delete_snapshot')
    clean.clean_snapshot(ctx, region)

    # ensure we deleted this snapshot if it was ready to die today
    utils.delete_snapshot.assert_any_call(snapshot_id, region)  # pylint: disable=E1103

    # now raise the minimum, and check to be sure we didn't delete
    utils.delete_snapshot.reset_mock()  # pylint: disable=E1103
    config_data['snapshot']['minimum'] = 5
    dynamo.store_configuration(region, 'foo', AWS_MOCK_ACCOUNT, config_data)
    clean.clean_snapshot(ctx, region)
    utils.delete_snapshot.assert_not_called()  # pylint: disable=E1103
Example #6
0
def test_clean_tagged_snapshots_ignore_retention(mocker):
    """Test for method of the same name."""
    # default settings
    region = 'us-east-1'
    mocks.create_dynamodb(region)

    # create two instances and record the id of one of them
    instance_id_list = mocks.create_instances(region, count=2)
    instance_id = instance_id_list[0]
    ctx = utils.MockContext()

    # setup the min # snaps for the instance
    config_data = {
        "match": {
            "instance-id": instance_id
        },
        "snapshot": {
            "retention": "6 days",
            "minimum": 5,
            "frequency": "13 hours"
        },
        "ignore_retention": True
    }

    # put it in the table, be sure it succeeded
    dynamo.store_configuration(region, 'foo', AWS_MOCK_ACCOUNT, config_data)

    # figure out the EBS volume that came with our instance
    volume_id = utils.get_volumes([instance_id], region)[0]['VolumeId']

    # make a snapshot that should be deleted today (but 5 snap retention)
    now = datetime.datetime.now(dateutil.tz.tzutc())
    delete_on = now.strftime('%Y-%m-%d')
    utils.snapshot_and_tag(instance_id, 'ami-123abc', volume_id, delete_on,
                           region)
    snapshot_id = utils.most_recent_snapshot(volume_id, region)['SnapshotId']

    # now delete the instance and volume, keep the snapshot
    client = boto3.client('ec2', region_name=region)
    client.terminate_instances(InstanceIds=[instance_id])

    mocker.patch('ebs_snapper.utils.delete_snapshot')
    dynamo.store_configuration(region, 'foo', AWS_MOCK_ACCOUNT, config_data)
    clean.clean_snapshot(ctx, region)
    utils.delete_snapshot.assert_any_call(snapshot_id, region)  # pylint: disable=E1103
Example #7
0
def test_perform_snapshot_skipped(mocker):
    """Test for method of the same name."""
    # some default settings for this test
    region = 'us-west-2'
    snapshot_settings = {
        'snapshot': {
            'minimum': 5,
            'frequency': '2 hours',
            'retention': '5 days'
        },
        'match': {
            'tag:backup': 'yes'
        }
    }
    mocks.create_dynamodb('us-east-1')
    dynamo.store_configuration('us-east-1', 'some_unique_id', '111122223333',
                               snapshot_settings)

    # create an instance and record the id
    instance_id = mocks.create_instances(region, count=1)[0]

    # figure out the EBS volume that came with our instance
    instance_details = utils.get_instance(instance_id, region)
    block_devices = instance_details.get('BlockDeviceMappings', [])
    volume_id = block_devices[0]['Ebs']['VolumeId']

    # determine what we should be tagging the snapshot
    ret, freq = utils.parse_snapshot_settings(snapshot_settings)  # pylint: disable=unused-variable
    now = datetime.datetime.now(dateutil.tz.tzutc())
    delete_on_dt = now + ret
    delete_on = delete_on_dt.strftime('%Y-%m-%d')

    # now take a snapshot, so we expect this next one to be skipped
    utils.snapshot_and_tag(instance_id, 'ami-123abc', volume_id, delete_on,
                           region)

    # patch the final method that takes a snapshot
    mocker.patch('ebs_snapper.utils.snapshot_and_tag')

    # since there are no snapshots, we should expect this to trigger one
    ctx = utils.MockContext()
    snapshot.perform_snapshot(ctx, region)

    # test results (should not create a second snapshot)
    utils.snapshot_and_tag.assert_not_called()  # pylint: disable=E1103
def test_perform_snapshot_ignore_volume(mocker):
    """Test for method of the same name."""
    # some default settings for this test
    region = 'us-west-2'

    snapshot_settings = {
        'snapshot': {
            'minimum': 5,
            'frequency': '2 hours',
            'retention': '5 days'
        },
        'match': {
            'tag:backup': 'yes'
        },
        'ignore': []
    }

    # create an instance and record the id
    instance_id = mocks.create_instances(region, count=1)[0]

    # need to filter instances, so need dynamodb present
    mocks.create_dynamodb('us-east-1')
    dynamo.store_configuration('us-east-1', 'some_unique_id', AWS_MOCK_ACCOUNT,
                               snapshot_settings)

    # figure out the EBS volume that came with our instance
    instance_details = utils.get_instance(instance_id, region)
    block_devices = instance_details.get('BlockDeviceMappings', [])
    volume_id = block_devices[0]['Ebs']['VolumeId']
    snapshot_settings['ignore'].append(volume_id)

    # patch the final method that takes a snapshot
    mocker.patch('ebs_snapper.utils.snapshot_and_tag')

    # since there are no snapshots, we should expect this to trigger one
    ctx = utils.MockContext()
    snapshot.perform_snapshot(ctx, region)

    # test results
    utils.snapshot_and_tag.assert_not_called()  # pylint: disable=E1103
Example #9
0
def test_perform_snapshot(mocker):
    """Test for method of the same name."""
    # some default settings for this test
    region = 'us-west-2'

    snapshot_settings = {
        'snapshot': {'minimum': 5, 'frequency': '2 hours', 'retention': '5 days'},
        'match': {'tag:backup': 'yes'}
    }

    # create an instance and record the id
    instance_id = mocks.create_instances(region, count=1)[0]

    # need to filter instances, so need dynamodb present
    mocks.create_dynamodb('us-east-1')
    dynamo.store_configuration('us-east-1', 'some_unique_id', '111122223333', snapshot_settings)

    # figure out the EBS volume that came with our instance
    instance_details = utils.get_instance(instance_id, region)
    block_devices = instance_details.get('BlockDeviceMappings', [])
    volume_id = block_devices[0]['Ebs']['VolumeId']

    # determine what we should be tagging the snapshot
    ret, freq = utils.parse_snapshot_settings(snapshot_settings)  # pylint: disable=unused-variable
    now = datetime.datetime.now(dateutil.tz.tzutc())
    delete_on_dt = now + ret
    delete_on = delete_on_dt.strftime('%Y-%m-%d')

    # apply some tags
    client = boto3.client('ec2', region_name=region)
    instance_tags = [
        {'Key': 'Name', 'Value': 'Foo'},
        {'Key': 'Service', 'Value': 'Bar'},
        {'Key': 'backup', 'Value': 'yes'},
    ]
    client.create_tags(DryRun=False, Resources=[instance_id], Tags=instance_tags)

    # override one of the tags
    volume_tags = [{'Key': 'Service', 'Value': 'Baz'}]
    client.create_tags(DryRun=False, Resources=[volume_id], Tags=volume_tags)

    # when combined, we expect tags to be this.
    tags = [
        {'Key': 'Name', 'Value': 'Foo'},
        {'Key': 'Service', 'Value': 'Baz'},
        {'Key': 'backup', 'Value': 'yes'},
    ]

    # patch the final method that takes a snapshot
    mocker.patch('ebs_snapper.utils.snapshot_and_tag')

    # since there are no snapshots, we should expect this to trigger one
    ctx = utils.MockContext()
    snapshot.perform_snapshot(ctx, region)

    # test results
    utils.snapshot_and_tag.assert_any_call(  # pylint: disable=E1103
        instance_id,
        'ami-123abc',
        volume_id,
        delete_on,
        region,
        additional_tags=tags)
Example #10
0
def test_calculate_relevant_tags():
    """Confirm that tags are calculated correctly, and don't exceed 10"""
    # client.create_tags()
    region = 'us-west-2'
    client = boto3.client('ec2', region_name=region)

    # some instance tags (pad to fill it after)
    instance_tags = [
        {
            'Key': 'Foo',
            'Value': 'Bar'
        },  # normal tag
        {
            'Key': 'BusinessUnit',
            'Value': 'Dept1'
        }  # billing tag
    ]
    for i in xrange(0, 8):
        instance_tags.append({
            'Key': "foo-" + str(i),
            'Value': "bar-" + str(i)
        })

    # some volume tags (pad to fill it after)
    volume_tags = [
        {
            'Key': 'Foo',
            'Value': 'Baz'
        },  # more normal tags
        {
            'Key': 'BusinessUnit',
            'Value': 'Dept2'
        },  # billing tag override
        {
            'Key': 'Cluster',
            'Value': 'Bank'
        }  # billing tag that won't override
    ]
    # 47 because volumes can only have 50 tags too
    for i in xrange(0, 47):
        volume_tags.append({
            'Key': "foo-" + str(i),
            'Value': "bar-" + str(i + 100)
        })

    # create an instance and record the id
    instance_id = mocks.create_instances(region, count=1)[0]
    client.create_tags(Resources=[instance_id], Tags=instance_tags)

    # figure out the EBS volume that came with our instance
    volume_id = utils.get_volumes([instance_id], region)[0]['VolumeId']
    client.create_tags(Resources=[volume_id], Tags=volume_tags)

    # make some snapshots that should be deleted today
    now = datetime.now(dateutil.tz.tzutc())
    delete_on = now.strftime('%Y-%m-%d')

    instance_data = utils.get_instance(instance_id, region=region)
    volume_data = utils.get_volume(volume_id, region=region)
    expected_tags = utils.calculate_relevant_tags(
        instance_data.get('Tags', None), volume_data.get('Tags', None))

    # create the snapshot
    utils.snapshot_and_tag(instance_id,
                           'ami-123abc',
                           volume_id,
                           delete_on,
                           region,
                           additional_tags=expected_tags)

    # now confirm the tags are correct
    snapshots = utils.get_snapshots_by_volume(volume_id, region)
    created_snap = snapshots[0]

    # check those expected tags
    expected_pairs = {
        'BusinessUnit': 'Dept2',
        'Cluster': 'Bank',
        'DeleteOn': delete_on,
        # moto returns tags in very random order, for testing purposes,
        # so I can't really test anything else with the foo-* tags here
    }

    for k, v in expected_pairs.iteritems():
        assert {'Key': k, 'Value': v} in created_snap['Tags']

    # be sure we don't include the last tag of the 50, it should have been chopped off
    # because of the DeleteOn tag taking an extra space, and 50 tags + DeleteOn > 50 max tags
    assert {
        'Key': 'foo-47',
        'Value': 'bar-' + str(47 + 100)
    } not in created_snap['Tags']