示例#1
0
    def setUp(self):
        self.revision = FlotillaServiceRevision(units=[
            FlotillaDockerService(
                'redis.service', 'redis:latest', environment={'FOO': 'bar'})
        ])
        self.rev_hash = self.revision.revision_hash

        self.assignments = MagicMock(spec=Table)
        self.regions = MagicMock(spec=Table)
        self.revisions = MagicMock(spec=Table)
        self.services = MagicMock(spec=Table)
        self.units = MagicMock(spec=Table)
        self.users = MagicMock(spec=Table)
        self.revision_item = MagicMock(spec=Item)
        self.revisions.has_item.return_value = False
        self.revisions.get_item.return_value = self.revision_item

        self.service_item = MagicMock(spec=Item)
        self.service_data = {self.rev_hash: 1}
        self.service_item.__getitem__.side_effect = \
            self.service_data.__getitem__
        self.service_item.__contains__.side_effect = \
            self.service_data.__contains__
        self.service_item.get.side_effect = \
            self.service_data.get
        self.service_item.keys.side_effect = self.service_data.keys
        self.services.get_item.return_value = self.service_item
        self.kms = MagicMock(spec=KMSConnection)
        self.db = FlotillaClientDynamo(self.assignments, self.regions,
                                       self.revisions, self.services,
                                       self.units, self.users, self.kms)
示例#2
0
def add_revision(environment, regions, service_name, label, stream_in):
    files = files_from_tar(stream_in)
    units = get_units(files)

    service_revision = FlotillaServiceRevision(label, units=units)

    for region in regions:
        kms = boto.kms.connect_to_region(region)

        dynamo = boto.dynamodb2.connect_to_region(region)
        tables = DynamoDbTables(dynamo, environment=environment)

        tables.setup(['revisions', 'services', 'units'])
        db = FlotillaClientDynamo(None, None, tables.revisions, tables.services,
                                  tables.units, None, kms)

        db.add_revision(service_name, service_revision)
示例#3
0
def add_revision(environment, regions, service_name, label, stream_in):
    files = files_from_tar(stream_in)
    units = get_units(files)

    service_revision = FlotillaServiceRevision(label, units=units)

    for region in regions:
        kms = boto.kms.connect_to_region(region)

        dynamo = boto.dynamodb2.connect_to_region(region)
        tables = DynamoDbTables(dynamo, environment=environment)

        tables.setup(['revisions', 'services', 'units'])
        db = FlotillaClientDynamo(None, None, tables.revisions,
                                  tables.services, tables.units, None, kms)

        db.add_revision(service_name, service_revision)
示例#4
0
def add_revision(environment, regions, service_name, label, env_vars,
                 highlander, stream_in):
    # Extract services and files from input:
    files = files_from_tar(stream_in)
    services, environments = get_services_environments(files, environment,
                                                       env_vars)

    # Extract metadata from environments:
    service_updates = extract_service_updates(environments.values())
    env_regions = extract_regions(environments.values())
    regions = set(regions) | env_regions

    # Build a ServiceRevision with services+enviroment that are left:
    units = get_units(services, environments)
    service_revision = FlotillaServiceRevision(label, units=units)

    # Add revision and perform updates in each region:
    dynamo_cache = {}
    for region in regions:
        kms = boto.kms.connect_to_region(region)

        dynamo = boto.dynamodb2.connect_to_region(region)
        tables = DynamoDbTables(dynamo, environment=environment)
        dynamo_cache[region] = tables

        tables.setup(['revisions', 'services', 'units'])
        db = FlotillaClientDynamo(None, None, tables.revisions, tables.services,
                                  tables.units, None, kms)

        db.add_revision(service_name, service_revision)
        if service_updates:
            db.configure_service(service_name, service_updates)

    if highlander > 0:
        wait_for_deployment(dynamo_cache, regions, service_name,
                            service_revision.revision_hash, highlander)
示例#5
0
class TestFlotillaClientDynamo(unittest.TestCase):
    def setUp(self):
        self.revision = FlotillaServiceRevision(units=[
            FlotillaDockerService(
                'redis.service', 'redis:latest', environment={'FOO': 'bar'})
        ])
        self.rev_hash = self.revision.revision_hash

        self.assignments = MagicMock(spec=Table)
        self.regions = MagicMock(spec=Table)
        self.revisions = MagicMock(spec=Table)
        self.services = MagicMock(spec=Table)
        self.units = MagicMock(spec=Table)
        self.users = MagicMock(spec=Table)
        self.revision_item = MagicMock(spec=Item)
        self.revisions.has_item.return_value = False
        self.revisions.get_item.return_value = self.revision_item

        self.service_item = MagicMock(spec=Item)
        self.service_data = {self.rev_hash: 1}
        self.service_item.__getitem__.side_effect = \
            self.service_data.__getitem__
        self.service_item.__contains__.side_effect = \
            self.service_data.__contains__
        self.service_item.get.side_effect = \
            self.service_data.get
        self.service_item.keys.side_effect = self.service_data.keys
        self.services.get_item.return_value = self.service_item
        self.kms = MagicMock(spec=KMSConnection)
        self.db = FlotillaClientDynamo(self.assignments, self.regions,
                                       self.revisions, self.services,
                                       self.units, self.users, self.kms)

    def test_add_revision(self):
        self.db.add_revision(SERVICE_NAME, self.revision)

        self.units.batch_write.assert_called_with()
        self.revisions.new_item.assert_called_with(ANY)

    def test_add_revision_existing(self):
        self.revisions.has_item.return_value = True

        self.db.add_revision(SERVICE_NAME, self.revision)

        self.revisions.new_item.assert_not_called()

    def test_add_revision_missing_unit(self):
        self.units.has_item.return_value = False

        self.db.add_revision(SERVICE_NAME, self.revision)

        self.units.batch_write.assert_called_with()
        self.units.new_item.assert_called_with(ANY)

    def test_add_revision_missing_service(self):
        self.services.get_item.side_effect = ItemNotFound()

        self.db.add_revision(SERVICE_NAME, self.revision)

        self.services.new_item.assert_called_with(SERVICE_NAME)

    def test_del_revision(self):
        self.db.del_revision(SERVICE_NAME, self.rev_hash)
        self.service_item.partial_save.assert_called_with()
        self.revision_item.delete.assert_called_with()

    def test_del_revision_not_on_service(self):
        del self.service_data[self.rev_hash]
        self.db.del_revision(SERVICE_NAME, self.rev_hash)
        self.service_item.partial_save.assert_not_called()

    def test_del_revision_service_missing(self):
        self.services.get_item.side_effect = ItemNotFound()
        self.db.del_revision(SERVICE_NAME, self.rev_hash)
        self.service_item.partial_save.assert_not_called()

    def test_del_revision_revision_missing(self):
        self.revisions.get_item.side_effect = ItemNotFound()
        self.db.del_revision(SERVICE_NAME, self.rev_hash)
        self.revisions.delete.assert_not_called()

    def test_set_revision_weight(self):
        self.db.set_revision_weight(SERVICE_NAME, self.rev_hash, 2)
        self.service_item.partial_save.assert_called_with()

    def test_set_revision_weight_service_missing(self):
        self.services.get_item.side_effect = ItemNotFound()
        self.db.set_revision_weight(SERVICE_NAME, self.rev_hash, 2)
        self.service_item.partial_save.assert_not_called()

    def test_get_revisions(self):
        self.revisions.batch_get.return_value = [{
            'rev_hash': self.rev_hash,
            'label': 'test',
            'units': ['000', '001']
        }]
        self.units.batch_get.return_value = [{
            'name': 'test',
            'unit_file': '',
            'environment': '',
            'unit_hash': '000'
        }, {
            'name': 'test',
            'unit_file': '',
            'environment': '',
            'unit_hash': '001'
        }]
        revisions = self.db.get_revisions(SERVICE_NAME)

        self.assertEqual(1, len(revisions))
        test_rev = revisions[0]
        self.assertEqual('test', test_rev.label)
        self.assertEqual(2, len(test_rev.units))

    def test_get_revisions_not_found(self):
        self.services.get_item.side_effect = ItemNotFound()
        revisions = self.db.get_revisions(SERVICE_NAME)
        self.assertEqual(0, len(revisions))

    def test_configure_region_create(self):
        self.regions.get_item.side_effect = ItemNotFound()
        self.db.configure_region('us-east-1', {'az1': 'us-east-1a'})
        self.regions.new_item.assert_called_with('us-east-1')

    def test_configure_region_exists(self):
        existing_region = MagicMock(spec=Item)
        self.regions.get_item.return_value = existing_region
        self.db.configure_region('us-east-1', {'az1': 'us-east-1a'})
        existing_region.save.assert_called_with(overwrite=True)

    def test_configure_service_create(self):
        self.services.get_item.side_effect = ItemNotFound()

        self.db.configure_service(SERVICE_NAME, {'key': 'value'})

        self.services.new_item.assert_called_with(SERVICE_NAME)

    def test_configure_service_exists(self):
        existing_service = MagicMock(spec=Item)
        self.services.get_item.return_value = existing_service

        self.db.configure_service(SERVICE_NAME, {'key': 'value'})

        existing_service.save.assert_called_with()

    def test_configure_user_create(self):
        self.users.get_item.side_effect = ItemNotFound()

        self.db.configure_user(USERNAME, {'key': 'value'})

        self.users.new_item.assert_called_with(USERNAME)

    def test_configure_user_exists(self):
        existing_user = MagicMock(spec=Item)
        self.users.get_item.return_value = existing_user

        self.db.configure_user(USERNAME, {'key': 'value'})

        existing_user.save.assert_called_with()

    def test_set_global(self):
        self.db.set_global(self.revision)

        self.units.batch_write.assert_called_with()
        self.revisions.new_item.assert_called_with(ANY)
        self.assignments.batch_write.assert_called_with()

    def test_encrypt_environment(self):
        self.kms.generate_data_key.return_value = {
            'Plaintext': '0000000000000000',
            'CiphertextBlob': 'topsecret'
        }

        unit = {}
        self.db._encrypt_environment('key-12345', {}, unit)
        self.assertEqual(unit['environment_key'], 'topsecret'.encode('base64'))
        self.assertTrue('environment_iv' in unit)
        self.assertTrue('environment_data' in unit)

    def test_check_users(self):
        usernames = ['found', 'missing']
        self.users.batch_get.return_value = [{'username': '******'}]

        missing_users = self.db.check_users(usernames)
        self.assertEquals(missing_users, set(['missing']))

    def test_store_revision_encryption(self):
        self.units.has_item.return_value = False
        self.db._encrypt_environment = MagicMock(return_value=('blob', 'key'))

        self.db._store_revision(self.revision, 'key')

        self.db._encrypt_environment.assert_called_with('key', ANY, ANY)