def test_deleted_not_done(self): """Ensures nothing happens when instance deletion status is not DONE.""" def json_request(*args, **kwargs): return {'status': 'error'} def send_machine_event(*args, **kwargs): pass self.mock(instances.net, 'json_request', json_request) self.mock(instances.metrics, 'send_machine_event', send_machine_event) key = instances.get_instance_key( 'base-name', 'revision', 'zone', 'instance-name', ) key = models.Instance( key=key, instance_group_manager=instances.get_instance_group_manager_key( key), pending_deletion=True, url='url', ).put() models.InstanceGroupManager( key=instances.get_instance_group_manager_key(key), ).put() models.InstanceTemplateRevision( key=instances.get_instance_group_manager_key(key).parent(), project='project', ).put() instances.delete_pending(key)
def test_pending_metadata_updates(self): """Ensures pending metadata updates are compressed and activated.""" key = models.Instance( key=instances.get_instance_key( 'base-name', 'revision', 'zone', 'instance-name', ), pending_metadata_updates=[ models.MetadataUpdate(metadata={'key1': 'value1'}), models.MetadataUpdate(metadata={'key2': 'value2'}), models.MetadataUpdate(metadata={ 'key3': 'value3', 'key1': 'value' }), ], ).put() expected_active_metadata_update = models.MetadataUpdate( metadata={ 'key1': 'value', 'key2': 'value2', 'key3': 'value3', }) metadata.compress_pending_metadata_updates(key) self.assertEqual(key.get().active_metadata_update, expected_active_metadata_update) self.failIf(key.get().pending_metadata_updates)
def test_dimensions(self): """Ensures dimensions are returned.""" instance = models.Instance(key=instances.get_instance_key( 'base-name', 'revision', 'zone', 'instance-name', ), ) instance_template_revision = models.InstanceTemplateRevision( dimensions=machine_provider.Dimensions( os_family=machine_provider.OSFamily.LINUX, ), disk_size_gb=300, machine_type='n1-standard-8', ) expected_dimensions = { 'backend': 'GCE', 'disk_size_gb': 300, 'hostname': 'instance-name', 'memory_gb': 30, 'num_cpus': 8, 'os_family': 'LINUX', } self.assertEqual( catalog.extract_dimensions(instance, instance_template_revision), expected_dimensions, )
def test_creates(self): """Ensures entity gets created.""" def fetch(*args, **kwargs): return ['url/name'] def send_machine_event(*args, **kwargs): pass self.mock(instances, 'fetch', fetch) self.mock(instances.metrics, 'send_machine_event', send_machine_event) key = instances.get_instance_key( 'base-name', 'revision', 'zone', 'name', ) models.InstanceGroupManager( key=instances.get_instance_group_manager_key(key), url='url', ).put() expected_instances = [ key, ] expected_url = 'url/name' instances.ensure_entities_exist( instances.get_instance_group_manager_key(key)) self.assertItemsEqual( instances.get_instance_group_manager_key(key).get().instances, expected_instances, ) self.assertEqual(key.get().url, expected_url)
def test_metadata_updated(self): """Ensures metadata is updated.""" def json_request(*args, **kwargs): return {'metadata': {'fingerprint': 'fingerprint', 'items': []}} def set_metadata(*args, **kwargs): return collections.namedtuple('operation', ['url'])(url='url') self.mock(metadata.net, 'json_request', json_request) self.mock(metadata.gce.Project, 'set_metadata', set_metadata) key = models.Instance( key=instances.get_instance_key( 'base-name', 'revision', 'zone', 'instance-name', ), active_metadata_update=models.MetadataUpdate(metadata={ 'key': 'value', }, ), ).put() models.InstanceGroupManager(key=key.parent(), ).put() models.InstanceTemplateRevision( key=key.parent().parent(), project='project', ).put() expected_url = 'url' metadata.update(key) self.assertEqual(key.get().active_metadata_update.url, expected_url)
def test_grandparent_unspecified(self): """Ensures nothing happens when the grandparent doesn't exist.""" def json_request(*args, **kwargs): self.fail('json_request called') def send_machine_event(*args, **kwargs): self.fail('send_machine_event called') self.mock(instances.net, 'json_request', json_request) self.mock(instances.metrics, 'send_machine_event', send_machine_event) key = instances.get_instance_key( 'base-name', 'revision', 'zone', 'instance-name', ) key = models.Instance( key=key, instance_group_manager=instances.get_instance_group_manager_key( key), pending_deletion=True, url='url', ).put() models.InstanceGroupManager( key=instances.get_instance_group_manager_key(key), ).put() instances.delete_pending(key)
def test_not_cataloged(self): """Ensures an instance is set for deletion when not cataloged.""" def delete_machine(*args, **kwargs): return {'error': 'ENTRY_NOT_FOUND'} def send_machine_event(*args, **kwargs): pass self.mock(catalog.machine_provider, 'delete_machine', delete_machine) self.mock(catalog.metrics, 'send_machine_event', send_machine_event) key = instances.get_instance_key( 'base-name', 'revision', 'zone', 'instance-name', ) key = models.Instance( key=key, cataloged=False, instance_group_manager=instances.get_instance_group_manager_key( key), ).put() catalog.remove(key) self.failIf(key.get().cataloged) self.failUnless(key.get().pending_deletion)
def test_service_account_not_found(self): """Ensures nothing happens when a service account doesn't exist.""" def add_machine(*args, **kwargs): self.fail('add_machine called') self.mock(catalog.machine_provider, 'add_machine', add_machine) key = instances.get_instance_key( 'base-name', 'revision', 'zone', 'instance-name', ) key = models.Instance( key=key, instance_group_manager=instances.get_instance_group_manager_key( key), ).put() models.InstanceGroupManager( key=instances.get_instance_group_manager_key(key), ).put() models.InstanceTemplateRevision( key=instances.get_instance_group_manager_key( key).parent(), ).put() catalog.catalog(key) self.failIf(key.get().cataloged)
def test_removed(self): """Ensures an instance can be removed.""" def delete_machine(*args, **kwargs): return {} def send_machine_event(*args, **kwargs): pass self.mock(catalog.machine_provider, 'delete_machine', delete_machine) self.mock(catalog.metrics, 'send_machine_event', send_machine_event) key = instances.get_instance_key( 'base-name', 'revision', 'zone', 'instance-name', ) key = models.Instance( key=key, cataloged=True, instance_group_manager=instances.get_instance_group_manager_key( key), ).put() catalog.remove(key) self.failUnless(key.get().cataloged) self.failUnless(key.get().pending_deletion)
def test_creates(self): """Ensures entity gets created.""" def fetch(*args, **kwargs): return ['url/name'] self.mock(instances, 'fetch', fetch) key = instances.get_instance_key( 'base-name', 'revision', 'zone', 'name', ) models.InstanceGroupManager( key=key.parent(), url='url', ).put() expected_instances = [ key, ] expected_url = 'url/name' instances.ensure_entities_exist(key.parent()) self.assertItemsEqual(key.parent().get().instances, expected_instances) self.assertEqual(key.get().url, expected_url)
def test_not_cataloged(self): """Ensures nothing happens when the instance is not cataloged.""" def retrieve_machine(*args, **kwargs): self.fail('retrieve_machine called') self.mock(catalog.machine_provider, 'retrieve_machine', retrieve_machine) key = instances.get_instance_key( 'base-name', 'revision', 'zone', 'instance-name', ) key = models.Instance( key=key, cataloged=False, instance_group_manager=instances.get_instance_group_manager_key( key), ).put() catalog.update_cataloged_instance(key) self.failIf(key.get().cataloged) self.failIf(key.get().leased) self.failIf(key.get().pending_deletion)
def test_updated_lease_expiration_ts(self): """Ensures an instance can be updated with a lease_expiration_ts.""" now = int(utils.time_time()) def retrieve_machine(*args, **kwargs): return { 'lease_expiration_ts': str(now), } self.mock(catalog.machine_provider, 'retrieve_machine', retrieve_machine) key = instances.get_instance_key( 'base-name', 'revision', 'zone', 'instance-name', ) key = models.Instance( key=key, cataloged=True, instance_group_manager=instances.get_instance_group_manager_key( key), ).put() self.failIf(key.get().leased) catalog.update_cataloged_instance(key) self.failUnless(key.get().cataloged) self.assertEqual(key.get().lease_expiration_ts, datetime.datetime.utcfromtimestamp(now)) self.failUnless(key.get().leased) self.failIf(key.get().pending_deletion)
def test_retrieval_error(self): """Ensures an instance is set for deletion when not found.""" def retrieve_machine(*args, **kwargs): raise net.NotFoundError('404', 404, '404') def send_machine_event(*args, **kwargs): pass self.mock(catalog.machine_provider, 'retrieve_machine', retrieve_machine) self.mock(catalog.metrics, 'send_machine_event', send_machine_event) key = instances.get_instance_key( 'base-name', 'revision', 'zone', 'instance-name', ) key = models.Instance( key=key, cataloged=True, instance_group_manager=instances.get_instance_group_manager_key( key), ).put() catalog.update_cataloged_instance(key) self.failUnless(key.get().cataloged) self.failIf(key.get().leased) self.failUnless(key.get().pending_deletion)
def test_active_metadata_update(self): """Ensures nothing happens when a metadata update is already active.""" key = models.Instance( key=instances.get_instance_key( 'base-name', 'revision', 'zone', 'instance-name', ), active_metadata_update=models.MetadataUpdate( metadata={'key1': 'value1'}, ), pending_metadata_updates=[ models.MetadataUpdate(metadata={'key2': 'value2'}), ], ).put() expected_active_metadata_update = models.MetadataUpdate( metadata={'key1': 'value1'}, ) expected_pending_metadata_updates = [ models.MetadataUpdate(metadata={'key2': 'value2'}), ] metadata.compress_pending_metadata_updates(key) self.assertEqual(key.get().active_metadata_update, expected_active_metadata_update) self.assertEqual(key.get().pending_metadata_updates, expected_pending_metadata_updates)
def test_deleted(self): """Ensures the entity is marked deleted when the instance doesn't exists.""" def json_request(*args, **kwargs): raise net.NotFoundError('404', 404, '404') def send_machine_event(*args, **kwargs): pass self.mock(cleanup.net, 'json_request', json_request) self.mock(cleanup.metrics, 'send_machine_event', send_machine_event) key = models.Instance( key=instances.get_instance_key( 'base-name', 'revision', 'zone', 'instance-name', ), pending_deletion=True, url='url', ).put() cleanup.check_deleted_instance(key) self.failUnless(key.get().deleted)
def test_already_exists(self): """Ensures nothing happens when the entity already exists.""" def fetch(*args, **kwargs): return ['url/name'] self.mock(instances, 'fetch', fetch) key = models.Instance( key=instances.get_instance_key( 'base-name', 'revision', 'zone', 'name', ), ).put() models.InstanceGroupManager( key=key.parent(), url='url', ).put() expected_instances = [ key, ] instances.ensure_entities_exist(key.parent()) self.failIf(key.get().url) self.assertItemsEqual(key.parent().get().instances, expected_instances)
def test_not_drained(self): """Ensures nothing happens when the parent is not drained.""" def json_request(*args, **kwargs): self.fail('json_request called') self.mock(cleanup.net, 'json_request', json_request) key = instances.get_instance_key( 'base-name', 'revision', 'zone', 'instance-name', ) key = models.Instance( key=key, instance_group_manager=instances.get_instance_group_manager_key( key), url='url', ).put() models.InstanceGroupManager( key=instances.get_instance_group_manager_key(key), ).put() models.InstanceTemplateRevision( key=instances.get_instance_group_manager_key( key).parent(), ).put() models.InstanceTemplate(key=instances.get_instance_group_manager_key( key).parent().parent(), ).put() cleanup.cleanup_drained_instance(key) self.failIf(key.get().deleted)
def test_not_pending_deletion(self): """Ensures nothing happens when the instance isn't pending deletion.""" def json_request(*args, **kwargs): self.fail('json_request called') def send_machine_event(*args, **kwargs): self.fail('send_machine_event called') self.mock(instances.net, 'json_request', json_request) self.mock(instances.metrics, 'send_machine_event', send_machine_event) key = instances.get_instance_key( 'base-name', 'revision', 'zone', 'instance-name', ) key = models.Instance( key=key, instance_group_manager=instances.get_instance_group_manager_key( key), pending_deletion=False, url='url', ).put() models.InstanceGroupManager( key=instances.get_instance_group_manager_key(key), ).put() models.InstanceTemplateRevision( key=instances.get_instance_group_manager_key(key).parent(), project='project', ).put() instances.delete_pending(key)
def test_cataloging_error_hostname_reuse(self): """Ensures an instance is marked cataloged on HOSTNAME_REUSE.""" def add_machine(*args, **kwargs): return {'error': 'HOSTNAME_REUSE'} def send_machine_event(*args, **kwargs): pass self.mock(catalog.machine_provider, 'add_machine', add_machine) self.mock(catalog.metrics, 'send_machine_event', send_machine_event) key = instances.get_instance_key( 'base-name', 'revision', 'zone', 'instance-name', ) key = models.Instance( key=key, instance_group_manager=instances.get_instance_group_manager_key( key), ).put() models.InstanceGroupManager( key=instances.get_instance_group_manager_key(key), ).put() models.InstanceTemplateRevision( key=instances.get_instance_group_manager_key(key).parent(), service_accounts=[ models.ServiceAccount(name='service-account'), ], ).put() catalog.catalog(key) self.failUnless(key.get().cataloged)
def test_error_surfaced(self): """Ensures errors are surfaced.""" def json_request(*args, **kwargs): raise net.Error('403', 403, '403') def send_machine_event(*args, **kwargs): pass self.mock(instances.net, 'json_request', json_request) self.mock(instances.metrics, 'send_machine_event', send_machine_event) key = instances.get_instance_key( 'base-name', 'revision', 'zone', 'instance-name', ) key = models.Instance( key=key, instance_group_manager=instances.get_instance_group_manager_key( key), pending_deletion=True, url='url', ).put() models.InstanceGroupManager( key=instances.get_instance_group_manager_key(key), ).put() models.InstanceTemplateRevision( key=instances.get_instance_group_manager_key(key).parent(), project='project', ).put() self.assertRaises(net.Error, instances.delete_pending, key)
def test_deletion_ts(self): """Ensures deletion_ts is not overwritten, but deletion call is repeated.""" def json_request(*args, **kwargs): return {'status': 'DONE'} def send_machine_event(*args, **kwargs): pass self.mock(instances.net, 'json_request', json_request) self.mock(instances.metrics, 'send_machine_event', send_machine_event) now = utils.utcnow() key = instances.get_instance_key( 'base-name', 'revision', 'zone', 'instance-name', ) key = models.Instance( key=key, deletion_ts=now, instance_group_manager=instances.get_instance_group_manager_key( key), pending_deletion=True, url='url', ).put() models.InstanceGroupManager( key=instances.get_instance_group_manager_key(key), ).put() models.InstanceTemplateRevision( key=instances.get_instance_group_manager_key(key).parent(), project='project', ).put() instances.delete_pending(key) self.assertEqual(key.get().deletion_ts, now)
def test_no_active_metadata_update(self): """Ensures nothing happens when active metadata update is unspecified.""" key = models.Instance(key=instances.get_instance_key( 'base-name', 'revision', 'zone', 'instance-name', ), ).put() metadata.associate_metadata_operation(key, 'checksum', 'url') self.failIf(key.get().active_metadata_update)
def test_no_pending_metadata_updates(self): """Ensures nothing happens when there are no pending metadata updates.""" key = models.Instance(key=instances.get_instance_key( 'base-name', 'revision', 'zone', 'instance-name', ), ).put() metadata.compress_pending_metadata_updates(key) self.failIf(key.get().active_metadata_update) self.failIf(key.get().pending_metadata_updates)
def test_sets(self): """Ensures the deletion_ts can be set.""" now = utils.utcnow() key = models.Instance(key=instances.get_instance_key( 'base-name', 'revision', 'zone', 'instance-name', ), ).put() instances.set_deletion_time(key, now) self.assertEqual(key.get().deletion_ts, now)
def test_lease_expiration_ts_added(self): now = utils.utcnow() key = models.Instance(key=instances.get_instance_key( 'base-name', 'revision', 'zone', 'instance-name', ), ).put() instances.add_lease_expiration_ts(key, now) self.assertEqual(key.get().lease_expiration_ts, now) self.failUnless(key.get().leased)
def test_entity_exists(self): """Ensures nothing happens when the entity already exists.""" key = models.Instance(key=instances.get_instance_key( 'base-name', 'revision', 'zone', 'instance-name', ), ).put() future = instances.ensure_entity_exists(key, 'url') future.wait() self.failIf(key.get().url)
def test_creates(self): """Ensures entity is created when it doesn't exist.""" key=instances.get_instance_key( 'base-name', 'revision', 'zone', 'instance-name', ) expected_url = 'url' future = instances.ensure_entity_exists(key, expected_url) future.wait() self.assertEqual(key.get().url, expected_url)
def test_cataloged(self): """Ensures an instance can be cataloged.""" key = instances.get_instance_key( 'base-name', 'revision', 'zone', 'instance-name', ) key = models.Instance( key=key, cataloged=False, ).put() catalog.set_cataloged(key) self.failUnless(key.get().cataloged)
def test_not_drained_or_pending_deletion(self): """Ensures nothing happens when the entity isn't drained or pending.""" key = models.Instance( key=instances.get_instance_key( 'base-name', 'revision', 'zone', 'instance-name', ), pending_deletion=False, ).put() cleanup.set_instance_deleted(key, False) self.failIf(key.get().deleted)
def test_drained(self): """Ensures the entity is marked as deleted when drained.""" key = models.Instance( key=instances.get_instance_key( 'base-name', 'revision', 'zone', 'instance-name', ), pending_deletion=False, ).put() cleanup.set_instance_deleted(key, True) self.failUnless(key.get().deleted)
def test_subscribed(self): """Ensures subscribed instance has pending metadata update.""" key = models.Instance( key=instances.get_instance_key( 'base-name', 'revision', 'zone', 'instance-name', ), ).put() models.InstanceGroupManager( key=key.parent(), ).put() models.InstanceTemplateRevision( key=key.parent().parent(), service_accounts=[ models.ServiceAccount( name='name', scopes=[ 'scope', ], ), ], ).put() message = { 'ackId': 'id', 'message': { 'attributes': { 'key': key.urlsafe(), 'subscription': 'subscription', 'subscription_project': 'subscription-project', }, 'data': base64.b64encode('SUBSCRIBED'), }, } expected_pending_metadata_updates = [ models.MetadataUpdate( metadata={ 'pubsub_service_account': 'name', 'pubsub_subscription': 'subscription', 'pubsub_subscription_project': 'subscription-project', }, ) ] pubsub.process(message).wait() self.assertEqual( key.get().pending_metadata_updates, expected_pending_metadata_updates)
def test_leased(self): """Ensures nothing happens when an instance is leased.""" key = models.Instance( key=instances.get_instance_key( 'base-name', 'revision', 'zone', 'instance-name', ), ).put() message = { 'ackId': 'id', 'message': { 'attributes': { 'key': key.urlsafe(), }, 'data': base64.b64encode('LEASED'), }, } pubsub.process(message).wait() self.failUnless(key.get())
def test_reclaimed(self): """Ensures reclaimed instance is marked for deletion.""" key = models.Instance( key=instances.get_instance_key( 'base-name', 'revision', 'zone', 'instance-name', ), ).put() message = { 'ackId': 'id', 'message': { 'attributes': { 'key': key.urlsafe(), }, 'data': base64.b64encode('RECLAIMED'), }, } pubsub.process(message).wait() self.failUnless(key.get().pending_deletion)
def test_unexpected_key(self): """Ensures nothing happens when key has unexpected kind.""" key = models.Instance( key=instances.get_instance_key( 'base-name', 'revision', 'zone', 'instance-name', ), ).put() models.InstanceGroupManager( key=key.parent(), ).put() models.InstanceTemplateRevision( key=key.parent().parent(), service_accounts=[ models.ServiceAccount( name='name', scopes=[ 'scope', ], ), ], ).put() message = { 'ackId': 'id', 'message': { 'attributes': { 'key': key.parent().urlsafe(), 'subscription': 'subscription', 'subscription_project': 'subscription-project', }, 'data': base64.b64encode('SUBSCRIBED'), }, } pubsub.process(message).wait() self.failIf(key.get().pending_metadata_updates)