def test_improper_tag_format(self): resources = [ tools.get_resource({'custodian_status': 'missingcolon}'}), tools.get_resource({'custodian_status': 'missing: atsign'}) ] self._test_filter_scenario(resources, 0)
def test_tag_filter(self): date = now().strftime('%Y-%m-%d') date_future = (now() + datetime.timedelta(days=1)).strftime('%Y-%m-%d') resources = [ tools.get_resource( {'custodian_status': 'TTL: stop@{0}'.format(date)}), tools.get_resource( {'custodian_status': 'TTL: stop@{0}'.format(date_future)}) ] self._test_filter_scenario(resources, 1)
def test_add_or_update_single_tag_from_resource(self, update_resource_tags): """Verifies we can add a new tag to a VM from values on the VM """ action = self._get_action( { 'tag': { 'type': 'resource', 'key': 'name' }, 'value': { 'type': 'resource', 'key': 'type' } }) resource = tools.get_resource(self.existing_tags) action.process([resource]) tags = tools.get_tags_parameter(update_resource_tags) expected_tags = self.existing_tags.copy() expected_tags.update({resource['name']: resource['type']}) self.assertEqual(tags, expected_tags)
def test_add_or_update_single_tag_from_resource_default(self, update_resource_tags): """Verifies we can add a new tag to a VM from values on the VM when values do not exist with default-value """ action = self._get_action( { 'tag': { 'resource': 'doesnotexist', 'default-value': 'default_tag' }, 'value': { 'resource': 'doesnotexist', 'default-value': 'default_value' } }) resource = tools.get_resource(self.existing_tags) action.process([resource]) tags = tools.get_tags_parameter(update_resource_tags) expected_tags = self.existing_tags.copy() expected_tags.update({'default_tag': 'default_value'}) self.assertEqual(tags, expected_tags)
def test_update_tags(self): resource = tools.get_resource({}) resource_group = tools.get_resource_group_resource({}) client_mock = Mock() action = Mock() action.manager.type = 'resourcegroup' action.session.client.return_value = client_mock TagHelper.update_resource_tags(action, resource_group, self.existing_tags) client_mock.resource_groups.update.assert_called_once() args = client_mock.resource_groups.update.call_args[0] self.assertEqual(args[0], resource_group['name']) self.assertEqual(args[1].tags, self.existing_tags) # Only PATCH tags self.assertListEqual(['tags'], [x for x in args[1].as_dict() if x is not None]) action.manager.type = 'vm' TagHelper.update_resource_tags(action, resource, self.existing_tags) client_mock.resources.update_by_id.assert_called_once() args = client_mock.resources.update_by_id.call_args[0] self.assertEqual(args[0], resource['id']) self.assertEqual(args[2].tags, self.existing_tags) # Only PATCH tags self.assertListEqual(['tags'], [x for x in args[2].as_dict() if x is not None])
def test_misformatted_date_string(self): date = "notadate" resources = [ tools.get_resource( {'custodian_status': 'TTL: stop@{0}'.format(date)}) ] self._test_filter_scenario(resources, 0)
def test_different_op_returns_no_resource(self): date = now().strftime('%Y-%m-%d') resources = [ tools.get_resource( {'custodian_status': 'TTL: delete@{0}'.format(date)}) ] self._test_filter_scenario(resources, 0)
def test_custom_tag_filter(self): date = now().strftime('%Y-%m-%d') resources = [ tools.get_resource({'custom_status': 'TTL: stop@{0}'.format(date)}) ] filter_definition = {'op': 'stop', 'tag': 'custom_status'} self._test_filter_scenario(resources, 1, filter_definition)
def test_timezone_in_datestring(self): tz = Time.get_tz('America/Santiago') date = (now(tz) - datetime.timedelta(hours=1)).strftime('%Y/%m/%d %H%M %Z') resources = [ tools.get_resource( {'custodian_status': 'TTL: stop@{0}'.format(date)}) ] self._test_filter_scenario(resources, 1)
def test_tag_trim_does_nothing_if_space_available(self, update_resource_tags): """Verifies tag trim returns without trimming tags if the resource has space equal to or greater than the space value. """ action = self._get_action({'space': 1}) resource = tools.get_resource(self.existing_tags) action.process([resource]) update_resource_tags.assert_not_called()
def test_add_tags(self, update_resource_tags): resource = tools.get_resource(self.existing_tags) TagHelper.add_tags(None, resource, {}) update_resource_tags.assert_not_called() TagHelper.add_tags(None, resource, {'tag3': 'value3'}) expected_tags = self.existing_tags.copy() expected_tags.update({'tag3': 'value3'}) self.assertEqual(tools.get_tags_parameter(update_resource_tags), expected_tags)
def test_auto_tag_update_false_noop_for_existing_tag(self, update_resource_tags, _2): """Adds CreatorEmail to a resource group""" action = self._get_action({'tag': 'CreatedDate', 'days': 10, 'update': False}) tags = self.existing_tags.copy() tags.update({'CreatedDate': 'do-not-modify'}) resource = tools.get_resource(tags) action.process([resource]) update_resource_tags.assert_not_called()
def _test_event(self, event, expected_tag_value, update_resource_tags): action = self._get_action({'tag': 'CreatorEmail', 'update': True}) resource = tools.get_resource(self.existing_tags) action.process(resources=[resource], event=event) tags = tools.get_tags_parameter(update_resource_tags) expected_tags = self.existing_tags.copy() expected_tags.update({'CreatorEmail': expected_tag_value}) self.assertEqual(tags, expected_tags)
def test_remove_tags(self, update_resource_tags): resource = tools.get_resource(self.existing_tags) TagHelper.remove_tags(None, resource, []) update_resource_tags.assert_not_called() TagHelper.remove_tags(None, resource, ['tag3']) update_resource_tags.assert_not_called() TagHelper.remove_tags(None, resource, ['tag2']) expected_tags = {'tag1': 'value1'} self.assertEqual(tools.get_tags_parameter(update_resource_tags), expected_tags)
def test_removal_works_with_nonexistent_tag(self, update_resource_tags): """Verifies attempting to delete a tag that is not on the resource does not throw an error """ action = self._get_action({'tags': ['tag-does-not-exist']}) tags = self.existing_tags.copy() resource = tools.get_resource(tags) action.process([resource]) update_resource_tags.assert_not_called()
def test_auto_tag_add_created_date_tag(self, update_resource_tags, _2): """Adds CreatorEmail to a resource group.""" action = self._get_action({'tag': 'CreatedDate', 'days': 10, 'update': True}) resource = tools.get_resource(self.existing_tags) action.process([resource]) tags = tools.get_tags_parameter(update_resource_tags) expected_tags = self.existing_tags.copy() expected_tags.update({'CreatedDate': '05.01.2019'}) self.assertEqual(tags, expected_tags)
def test_auto_tag_add_created_date_tag_custom_format(self, update_resource_tags, _2): """Adds CreatorEmail to a resource group.""" action = self._get_action({'tag': 'CreatedDate', 'format': '%m/%d/%Y'}) resource = tools.get_resource(self.existing_tags) action.process([resource]) tags = tools.get_tags_parameter(update_resource_tags) expected_tags = self.existing_tags.copy() expected_tags.update({'CreatedDate': '05/01/2019'}) self.assertEqual(tags, expected_tags)
def test_auto_tag_user_event_grid_event(self, update_resource_tags): event = {'eventTime': '2019-05-01T15:20:04.8336028Z'} action = self._get_action({'tag': 'CreatedDate', 'update': True}) resource = tools.get_resource(self.existing_tags) action.process(resources=[resource], event=event) tags = tools.get_tags_parameter(update_resource_tags) expected_tags = self.existing_tags.copy() expected_tags.update({'CreatedDate': '05.01.2019'}) self.assertEqual(tags, expected_tags)
def test_get_first_element_resource(self): client_mock = Mock() client_mock.activity_logs.list.return_value = self.events manager = Mock() manager.type = 'vm' manager.get_client.return_value = client_mock resource = tools.get_resource({}) base = AutoTagDate(data={'tag': 'test'}, manager=manager) base._prepare_processing() result = base._get_first_event(resource) client_mock.activity_logs.list.assert_called_once() self.assertEqual(result, self.events[-1])
def test_tag_filter(self): date = self.get_test_date().strftime('%Y-%m-%d') date_future = (self.get_test_date() + datetime.timedelta(days=1)).strftime('%Y-%m-%d') resources = [ tools.get_resource( {'custodian_status': 'TTL: stop@{0}'.format(date)}), tools.get_resource({'custom_status': 'TTL: stop@{0}'.format(date)}), tools.get_resource( {'custodian_status': 'TTL: stop@{0}'.format(date_future)}) ] config = [({ 'op': 'stop' }, 1), ({ 'op': 'stop', 'tag': 'custom_status' }, 1)] for c in config: f = self._get_filter(c[0]) result = f.process(resources) self.assertEqual(len(result), c[1])
def test_add_or_update_single_tag(self, update_resource_tags): """Verifies we can add a new tag to a VM and not modify an existing tag on that resource """ action = self._get_action({'tag': 'tag1', 'value': 'value1'}) resource = tools.get_resource(self.existing_tags) action.process([resource]) tags = tools.get_tags_parameter(update_resource_tags) expected_tags = self.existing_tags.copy() expected_tags.update({'tag1': 'value1'}) self.assertEqual(tags, expected_tags)
def test_add_or_update_tags(self, update_resource_tags): """Adds tags to an empty resource group, then updates one tag and adds a new tag """ action = self._get_action({'tags': {'tag1': 'value1', 'pre-existing-1': 'modified'}}) resource = tools.get_resource(self.existing_tags) action.process([resource]) tags = tools.get_tags_parameter(update_resource_tags) expected_tags = self.existing_tags.copy() expected_tags.update({'tag1': 'value1', 'pre-existing-1': 'modified'}) self.assertEqual(tags, expected_tags)
def test_mark_for_op(self, update_resource_tags): action = self._get_action({'op': 'stop', 'days': self.DAYS}) resource = tools.get_resource(self.existing_tags) action.process([resource]) tags = tools.get_tags_parameter(update_resource_tags) date = (self.get_test_date() + datetime.timedelta(days=self.DAYS)).strftime('%Y/%m/%d') expected_value = TagDelayedAction.default_template.format( op='stop', action_date=date) expected_tags = self.existing_tags.copy() expected_tags.update({'custodian_status': expected_value}) self.assertEqual(tags, expected_tags)
def test_remove_single_tag(self, update_resource_tags): """Verifies we can delete a tag without modifying an existing tag on that resource """ action = self._get_action({'tags': ['tag-to-delete']}) tags = self.existing_tags.copy() tags.update({'tag-to-delete': 'value'}) resource = tools.get_resource(tags) action.process([resource]) tags = tools.get_tags_parameter(update_resource_tags) self.assertEqual(tags, self.existing_tags)
def test_remove_tags(self, update_resource_tags): """Verifies we can delete multiple tags without modifying existing tags. """ action = self._get_action( {'tags': ['tag-to-delete-1', 'tag-to-delete-2']}) tags = self.existing_tags.copy() tags.update({'tag-to-delete-1': 'value1', 'tag-to-delete-2': 'value2'}) resource = tools.get_resource(tags) action.process([resource]) tags = tools.get_tags_parameter(update_resource_tags) self.assertEqual(tags, self.existing_tags)
def test_tag_trim_space_0_removes_all_tags_but_preserve(self, update_resource_tags): """Verifies tag trim removes all other tags but tags listed in preserve """ action = self._get_action({'space': 0, 'preserve': [k for k in self.existing_tags.keys()]}) tags = self.existing_tags.copy() tags.update({'tag-to-trim1': 'value1', 'tag-to-trim2': 'value2', 'tag-to-trim-3': 'value3'}) resource = tools.get_resource(tags) action.process([resource]) tags = tools.get_tags_parameter(update_resource_tags) expected_tags = self.existing_tags.copy() self.assertEqual(tags, expected_tags)
def test_tag_trim_removes_tags_for_space(self, update_resource_tags): """Verifies tag trim removes tags when the space value and number of tags on the resource are greater than the max tag value (15) """ action = self._get_action({'space': 15 - len(self.existing_tags), 'preserve': [k for k in self.existing_tags.keys()]}) tags = self.existing_tags.copy() tags.update({'tag-to-trim1': 'value1', 'tag-to-trim2': 'value2'}) resource = tools.get_resource(tags) action.process([resource]) tags = tools.get_tags_parameter(update_resource_tags) expected_tags = self.existing_tags.copy() self.assertEqual(tags, expected_tags)
def test_tag_trim_warns_no_candidates(self, logger_mock, update_resource_tags): """Verifies tag trim warns when there are no candidates to trim """ action = self._get_action({'space': 0, 'preserve': [k for k in self.existing_tags.keys()]}) tags = self.existing_tags.copy() resource = tools.get_resource(tags) action.process([resource]) update_resource_tags.assert_not_called() expected_warning_regex = ( "Could not find any candidates to trim " "/subscriptions/[^/]+/resourceGroups/[^/]+/" "providers/Microsoft.Compute/virtualMachines/[^/]+" ) args, _ = logger_mock.call_args self.assertTrue(re.match(expected_warning_regex, args[0]) is not None)
def test_tag_filter(self): resources = [ tools.get_resource({ 'Pythontest': 'ItWorks', 'Another-Tag-1': 'value1' }) ] config = [({ 'tag:Pythontest': 'present' }, 1), ({ 'tag:Pythontest': 'absent' }, 0), ({ 'tag:Pythontest': 'ItWorks' }, 1), ({ 'tag:Pythontest': 'ItDoesntWork' }, 0)] for c in config: f = self._get_filter(c[0]) result = f.process(resources) self.assertEqual(len(result), c[1])
def test_get_tag_value(self): resource = tools.get_resource(self.existing_tags) self.assertEqual(TagHelper.get_tag_value(resource, 'tag1'), 'value1') self.assertEqual(TagHelper.get_tag_value(resource, 'tag2'), 'value2') self.assertFalse(TagHelper.get_tag_value(resource, 'tag3'))