diff --git a/AutoscalingLifecycle/__init__.py b/AutoscalingLifecycle/__init__.py index fb3f3b0..6baebc2 100644 --- a/AutoscalingLifecycle/__init__.py +++ b/AutoscalingLifecycle/__init__.py @@ -484,6 +484,9 @@ class LifecycleHandler(object): 'triggers': [], 'stop_after_state_change': False } + __illegal_trigger_names = [ + 'trigger' + ] # @@ -536,6 +539,12 @@ def __add_transition(self, sources: list, dest: str, config: dict): trigger = self.__default_trigger.copy() trigger.update(config) + name = trigger.get('name') + trigger.pop('name') + + if name in self.__illegal_trigger_names: + raise ConfigurationError('trigger name %s is not allowed' % name) + # prepare functions will be executed first prepare = trigger.get('prepare') if type(prepare) is not list: @@ -579,9 +588,6 @@ def __add_transition(self, sources: list, dest: str, config: dict): if stop_after_trigger: after += [self.__continue_with_next_state] - name = trigger.get('name') - trigger.pop('name') - if trigger != { }: raise TriggerParameterConfigurationError( 'unknown options %s for trigger %s' % (", ".join(trigger.keys()), name)) diff --git a/requirements.txt b/requirements.txt index 2639cf1..68038f6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ boto3>=1.7.5 botocore>=1.10.55 boltons>=18.0.1,<19.0.0 -transitions>=0.6.8 +transitions>=0.6.9 mock==1.3.0 diff --git a/setup.py b/setup.py index fa0de8b..cd8ccc8 100644 --- a/setup.py +++ b/setup.py @@ -3,11 +3,11 @@ with open("README.md", "r") as fh: long_description = fh.read() -requires = ['boltons>=18.0.1,<19.0.0', 'transitions>=0.6.8'] +requires = ['boltons>=18.0.1,<19.0.0', 'transitions>=0.6.9'] setuptools.setup( name = "AutoscalingLifecycle", - version = "0.45.0", + version = "0.46.0", author = "Jan Schumann", author_email = "js@schumann-it.com", description = "A library to handle aws autoscaling lifecycle events", diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 0000000..1c1ae28 --- /dev/null +++ b/test/__init__.py @@ -0,0 +1 @@ +name = "AutoscalingTests" diff --git a/tests/fixtures/2730b156-4765-4ae7-b870-56c380012717.json b/test/fixtures/2730b156-4765-4ae7-b870-56c380012717.json similarity index 100% rename from tests/fixtures/2730b156-4765-4ae7-b870-56c380012717.json rename to test/fixtures/2730b156-4765-4ae7-b870-56c380012717.json diff --git a/tests/fixtures/autoscaling_event.json b/test/fixtures/autoscaling_event.json similarity index 100% rename from tests/fixtures/autoscaling_event.json rename to test/fixtures/autoscaling_event.json diff --git a/tests/fixtures/i-007de616626a946ce.json b/test/fixtures/i-007de616626a946ce.json similarity index 100% rename from tests/fixtures/i-007de616626a946ce.json rename to test/fixtures/i-007de616626a946ce.json diff --git a/tests/fixtures/ssm_event.json b/test/fixtures/ssm_event.json similarity index 100% rename from tests/fixtures/ssm_event.json rename to test/fixtures/ssm_event.json diff --git a/tests/unit/test_lifecycle_handler.py b/test/test_lifecycle_handler.py similarity index 95% rename from tests/unit/test_lifecycle_handler.py rename to test/test_lifecycle_handler.py index 63103d1..f3df5a2 100644 --- a/tests/unit/test_lifecycle_handler.py +++ b/test/test_lifecycle_handler.py @@ -1,12 +1,16 @@ import json +import os import types import unittest +from logging import INFO +from logging import StreamHandler from unittest import mock from transitions.core import Condition from AutoscalingLifecycle import LifecycleHandler from AutoscalingLifecycle import Model +from AutoscalingLifecycle import ConfigurationError from AutoscalingLifecycle.clients import DynamoDbClient from AutoscalingLifecycle.entity import CommandRepository from AutoscalingLifecycle.entity import NodeRepository @@ -14,6 +18,10 @@ from AutoscalingLifecycle.logging import Logging +def get_fixture(name): + return open(os.path.dirname(os.path.abspath(__file__)) + '/fixtures/' + name, 'r') + + class MockModel(Model): __transitions = [] __state_machine_attributes = { } @@ -37,7 +45,7 @@ def transitions(self, value): class MockDynamoDbClient(DynamoDbClient): def get_item(self, id): try: - fh = open('../fixtures/' + id + '.json', 'r') + fh = get_fixture(id + '.json') data = json.load(fh) fh.close() except Exception: @@ -55,9 +63,9 @@ class TestLifecycleHandler(unittest.TestCase): def setUp(self): logging = Logging("TEST", True) - # h = StreamHandler() - # h.setLevel(INFO) - # logging.add_handler(h, "[%(asctime)s] [%(levelname)s] [%(name)s] %(message)s") + #h = StreamHandler() + #h.setLevel(INFO) + #logging.add_handler(h, "[%(asctime)s] [%(levelname)s] [%(name)s] %(message)s") client = MockDynamoDbClient(mock.Mock(), mock.Mock(), logging, 'table') repositories = Repositories(client, logging.get_logger()) @@ -81,6 +89,20 @@ def get_default_tansition_config(self): ] + def get_illegal_trigger_name_tansition_config(self): + return [ + { + 'source': 'source', + 'dest': 'destination', + 'triggers': [ + { + 'name': 'trigger', + }, + ] + }, + ] + + def get_stop_tansition_with_error_config(self): return [ { @@ -256,7 +278,7 @@ def get_handle_failure_transition_config(self): 'dest': 'last', 'triggers': [ { - 'name': 'trigger', + 'name': 'failure_trigger', 'before': [self.trigger_no_error], }, @@ -533,6 +555,7 @@ def get_docker_transitions(self): } ] + def get_stop_after_state_change_transition_config(self): return [ { @@ -540,7 +563,7 @@ def get_stop_after_state_change_transition_config(self): 'dest': 'destination', 'triggers': [ { - 'name': 'trigger', + 'name': 'trigger_1', }, ], }, @@ -549,7 +572,7 @@ def get_stop_after_state_change_transition_config(self): 'dest': 'last', 'triggers': [ { - 'name': 'trigger2', + 'name': 'trigger_2', } ], 'stop_after_state_change': True @@ -565,6 +588,7 @@ def get_stop_after_state_change_transition_config(self): }, ] + def get_validate_transitions(self): model = mock.Mock() return [ @@ -663,7 +687,8 @@ def get_validate_transitions(self): }, { # allow all launching states except new to this transition - 'source': ['pending', 'initializing', 'initialized', 'online', 'ready', 'update_varnish', 'update_services', 'running'], + 'source': ['pending', 'initializing', 'initialized', 'online', 'ready', 'update_varnish', + 'update_services', 'running'], 'dest': 'reduce_varnish', 'triggers': [ { @@ -803,6 +828,7 @@ def get_validate_transitions(self): }, ] + def trigger_raise_error(self, *args, **kwargs): raise RuntimeError("error in trigger method") @@ -856,6 +882,7 @@ def test_stop_after_trigger_flag_is_accepted(self): self.assertIsInstance(transition.after[-1], types.MethodType) self.assertEqual(transition.after[-1].__name__, '__continue_with_next_state') + def test_stop_after_state_change_flag_is_accepted(self): config = self.get_default_tansition_config() config[0].update({ 'stop_after_state_change': True }) @@ -889,7 +916,7 @@ def test_ignore_errors_flag_is_accepted(self): def test_ignore_errors_behavior(self): self.model.transitions = self.get_handle_ignore_errors_transition_config() - fh = open('../fixtures/ssm_event.json', 'r') + fh = get_fixture('ssm_event.json') message = json.load(fh) fh.close() handler = LifecycleHandler(self.model) @@ -902,7 +929,7 @@ def test_ignore_errors_behavior(self): def test_failure_behavior(self): self.model.transitions = self.get_handle_failure_transition_config() - fh = open('../fixtures/ssm_event.json', 'r') + fh = get_fixture('ssm_event.json') message = json.load(fh) fh.close() handler = LifecycleHandler(self.model) @@ -915,7 +942,7 @@ def test_failure_behavior(self): def test_failure_in_failure_handling_behavior(self): self.model.transitions = self.get_handle_failure_in_failure_transition_config() - fh = open('../fixtures/ssm_event.json', 'r') + fh = get_fixture('ssm_event.json') message = json.load(fh) fh.close() handler = LifecycleHandler(self.model) @@ -931,7 +958,7 @@ def test_failure_in_failure_handling_behavior(self): def test_conditions_behavior(self): self.model.transitions = self.get_handle_conditions_transition_config() - fh = open('../fixtures/ssm_event.json', 'r') + fh = get_fixture('ssm_event.json') message = json.load(fh) fh.close() handler = LifecycleHandler(self.model) @@ -944,7 +971,7 @@ def test_conditions_behavior(self): def test_docker_transitions_for_new_node(self): self.model.transitions = self.get_docker_transitions() - fh = open('../fixtures/autoscaling_event.json', 'r') + fh = get_fixture('autoscaling_event.json') message = json.load(fh) fh.close() handler = LifecycleHandler(self.model) @@ -957,7 +984,7 @@ def test_docker_transitions_for_new_node(self): def test_stop_transition_after_state_change(self): self.model.transitions = self.get_stop_after_state_change_transition_config() - fh = open('../fixtures/ssm_event.json', 'r') + fh = get_fixture('ssm_event.json') message = json.load(fh) fh.close() handler = LifecycleHandler(self.model) @@ -970,7 +997,7 @@ def test_stop_transition_after_state_change(self): def test_stop_transition_with_error(self): self.model.transitions = self.get_stop_tansition_with_error_config() - fh = open('../fixtures/ssm_event.json', 'r') + fh = get_fixture('ssm_event.json') message = json.load(fh) fh.close() handler = LifecycleHandler(self.model) @@ -985,3 +1012,16 @@ def test_validation(self): handler = LifecycleHandler(self.model) self.assertEqual(21, len(handler.machine.states.keys())) + + + def test_illegal_trigger_name_raises(self): + config = self.get_default_tansition_config() + config[0].get('triggers')[0].update({ 'name': 'trigger' }) + + model = mock.Mock() + model.get_transitions.return_value = config + + with self.assertRaises(ConfigurationError) as context: + _ = LifecycleHandler(model) + self.assertTrue('trigger name trigger is not allowed' in context.exception) +