From 17d0e86e60f4ea7aad808a0b9e5199e951a8a92a Mon Sep 17 00:00:00 2001 From: Tomaz Muraus Date: Sun, 21 Dec 2014 01:03:38 +0100 Subject: [PATCH 01/15] Fix sensor and webhook trigger registration and also revert to the old behavior (we want to update trigger info in db on every registration call). --- .../st2reactor/bootstrap/sensorsregistrar.py | 4 + st2reactor/st2reactor/container/utils.py | 79 ++++++++++++++++--- 2 files changed, 71 insertions(+), 12 deletions(-) diff --git a/st2reactor/st2reactor/bootstrap/sensorsregistrar.py b/st2reactor/st2reactor/bootstrap/sensorsregistrar.py index dc1ebbd1e2..1c918ebb08 100644 --- a/st2reactor/st2reactor/bootstrap/sensorsregistrar.py +++ b/st2reactor/st2reactor/bootstrap/sensorsregistrar.py @@ -63,6 +63,10 @@ def _register_sensor_from_pack(self, pack, sensor): trigger_types = metadata.get('trigger_types', []) poll_interval = metadata.get('poll_interval', None) + # Add pack to each trigger type item + for trigger_type in trigger_types: + trigger_type['pack'] = pack + # Add TrigerType models to the DB trigger_type_dbs = container_utils.add_trigger_models(trigger_types=trigger_types) diff --git a/st2reactor/st2reactor/container/utils.py b/st2reactor/st2reactor/container/utils.py index 66032c903c..1dd4bde03b 100644 --- a/st2reactor/st2reactor/container/utils.py +++ b/st2reactor/st2reactor/container/utils.py @@ -17,8 +17,8 @@ from st2common import log as logging from st2common.exceptions.sensors import TriggerTypeRegistrationException -from st2common.persistence.reactor import SensorType, TriggerInstance -from st2common.models.db.reactor import SensorTypeDB, TriggerInstanceDB +from st2common.persistence.reactor import SensorType, TriggerType, TriggerInstance +from st2common.models.db.reactor import SensorTypeDB, TriggerTypeDB, TriggerInstanceDB from st2common.services import triggers as TriggerService from st2common.constants.pack import SYSTEM_PACK_NAME from st2common.constants.sensors import MINIMUM_POLL_INTERVAL @@ -49,8 +49,33 @@ def create_trigger_instance(trigger, payload, occurrence_time): return TriggerInstance.add_or_update(trigger_instance) -def _create_trigger_type(trigger_type): - return TriggerService.create_trigger_type_db(trigger_type) +def _create_trigger_type(pack, name, description=None, payload_schema=None, + parameters_schema=None): + triggertypes = TriggerType.query(pack=pack, name=name) + is_update = False + if len(triggertypes) > 0: + trigger_type = triggertypes[0] + LOG.debug('Found existing trigger id:%s with name:%s. Will update ' + 'trigger.', trigger_type.id, name) + is_update = True + else: + trigger_type = TriggerTypeDB() + + trigger_type.pack = pack + trigger_type.name = name + trigger_type.description = description + trigger_type.payload_schema = payload_schema + trigger_type.parameters_schema = parameters_schema + try: + triggertype_db = TriggerType.add_or_update(trigger_type) + except: + LOG.exception('Validation failed for TriggerType=%s.', trigger_type) + raise TriggerTypeRegistrationException('Invalid TriggerType name=%s.' % name) + if is_update: + LOG.audit('TriggerType updated. TriggerType=%s', triggertype_db) + else: + LOG.audit('TriggerType created. TriggerType=%s', triggertype_db) + return triggertype_db def _validate_trigger_type(trigger_type): @@ -65,13 +90,29 @@ def _validate_trigger_type(trigger_type): def _create_trigger(trigger_type): + """ + :param trigger_type: TriggerType db object. + :type trigger_type: :class:`TriggerTypeDB` + """ if hasattr(trigger_type, 'parameters_schema') and not trigger_type['parameters_schema']: - trigger_dict = { - 'name': trigger_type.name, - 'pack': trigger_type.pack, - 'type': trigger_type.get_reference().ref - } - return TriggerService.create_trigger_db(trigger_dict) + trigger_db = TriggerService.get_trigger_db({'pack': trigger_type.pack, + 'name': trigger_type.name}) + + if trigger_db is None: + trigger_dict = { + 'name': trigger_type.name, + 'pack': trigger_type.pack, + 'type': trigger_type.get_reference().ref + } + + try: + trigger_db = TriggerService.create_trigger_db(trigger_dict) + except: + LOG.exception('Validation failed for Trigger=%s.', trigger_dict) + raise TriggerTypeRegistrationException( + 'Unable to create Trigger for TriggerType=%s.' % trigger_type.name) + else: + return trigger_db else: LOG.debug('Won\'t create Trigger object as TriggerType %s expects ' + 'parameters.', trigger_type) @@ -79,7 +120,19 @@ def _create_trigger(trigger_type): def _add_trigger_models(trigger_type): - trigger_type = _create_trigger_type(trigger_type) + pack = trigger_type['pack'] + description = trigger_type['description'] if 'description' in trigger_type else '' + payload_schema = trigger_type['payload_schema'] if 'payload_schema' in trigger_type else {} + parameters_schema = trigger_type['parameters_schema'] \ + if 'parameters_schema' in trigger_type else {} + + trigger_type = _create_trigger_type( + pack=pack, + name=trigger_type['name'], + description=description, + payload_schema=payload_schema, + parameters_schema=parameters_schema + ) trigger = _create_trigger(trigger_type=trigger_type) return (trigger_type, trigger) @@ -89,7 +142,9 @@ def add_trigger_models(trigger_types): Register trigger types. :param trigger_types: A list of triggers to register. - :type trigger_types: ``list`` of trigger_type. + :type trigger_types: ``list`` of ``dict`` + + :rtype: ``list`` of ``tuple`` (trigger_type, trigger) """ [r for r in (_validate_trigger_type(trigger_type) for trigger_type in trigger_types) if r is not None] From 9b168f1d905b7e522b995281e4c74354bf0ac4b7 Mon Sep 17 00:00:00 2001 From: Tomaz Muraus Date: Mon, 22 Dec 2014 17:29:28 +0100 Subject: [PATCH 02/15] Update code to use new create_or_update functions from the trigger service module. --- st2common/st2common/services/triggers.py | 83 +++++++++++++++++++++++- st2reactor/st2reactor/container/utils.py | 67 +++++++------------ 2 files changed, 106 insertions(+), 44 deletions(-) diff --git a/st2common/st2common/services/triggers.py b/st2common/st2common/services/triggers.py index 7813b45e6d..bb405abfb0 100644 --- a/st2common/st2common/services/triggers.py +++ b/st2common/st2common/services/triggers.py @@ -18,6 +18,17 @@ from st2common.models.system.common import ResourceReference from st2common.persistence.reactor import (Trigger, TriggerType) +__all__ = [ + 'get_trigger_db', + 'get_trigger_type_db', + + 'create_trigger_db', + 'create_trigger_type_db', + + 'create_or_update_trigger_db', + 'create_or_update_trigger_type_db' +] + LOG = logging.getLogger(__name__) @@ -110,11 +121,44 @@ def create_trigger_db(trigger): trigger_db = get_trigger_db(trigger_api) if not trigger_db: trigger_db = TriggerAPI.to_model(trigger_api) - LOG.debug('verified trigger and formulated TriggerDB=%s', trigger_db) + LOG.debug('Verified trigger and formulated TriggerDB=%s', trigger_db) trigger_db = Trigger.add_or_update(trigger_db) return trigger_db +def create_or_update_trigger_db(trigger): + """ + Create a new TriggerDB model if one doesn't exist yet or update existing + one. + + :param trigger: Trigger info. + :type trigger: ``dict`` + """ + assert isinstance(trigger, dict) + + trigger_api = TriggerAPI(**trigger) + trigger_api = TriggerAPI.to_model(trigger_api) + + existing_trigger_db = get_trigger_db(trigger_api) + + if existing_trigger_db: + is_update = True + else: + is_update = False + + if is_update: + trigger_api.id = existing_trigger_db.id + + trigger_db = Trigger.add_or_update(trigger_api) + + if is_update: + LOG.audit('Trigger updated. Trigger=%s', trigger_db) + else: + LOG.audit('Trigger created. Trigger=%s', trigger_db) + + return trigger_db + + def create_trigger_db_from_rule(rule): trigger_api = _get_trigger_api_given_rule(rule) return create_trigger_db(trigger_api) @@ -133,8 +177,45 @@ def create_trigger_type_db(trigger_type): ref = ResourceReference.to_string_reference(name=trigger_type_api.name, pack=trigger_type_api.pack) trigger_type_db = get_trigger_type_db(ref) + if not trigger_type_db: trigger_type_db = TriggerTypeAPI.to_model(trigger_type_api) LOG.debug('verified trigger and formulated TriggerDB=%s', trigger_type_db) trigger_type_db = TriggerType.add_or_update(trigger_type_db) return trigger_type_db + + +def create_or_update_trigger_type_db(trigger_type): + """ + Create or update a trigger type db object in the db given trigger_type definition as dict. + + :param trigger_type: Trigger type model. + :type trigger_type: ``dict`` + + :rtype: ``object`` + """ + assert isinstance(trigger_type, dict) + + trigger_type_api = TriggerTypeAPI(**trigger_type) + trigger_type_api = TriggerTypeAPI.to_model(trigger_type_api) + + ref = ResourceReference.to_string_reference(name=trigger_type_api.name, + pack=trigger_type_api.pack) + + existing_trigger_type_db = get_trigger_type_db(ref) + if existing_trigger_type_db: + is_update = True + else: + is_update = False + + if is_update: + trigger_type_api.id = existing_trigger_type_db.id + + trigger_type_db = TriggerType.add_or_update(trigger_type_api) + + if is_update: + LOG.audit('TriggerType updated. TriggerType=%s', trigger_type_db) + else: + LOG.audit('TriggerType created. TriggerType=%s', trigger_type_db) + + return trigger_type_db diff --git a/st2reactor/st2reactor/container/utils.py b/st2reactor/st2reactor/container/utils.py index 1dd4bde03b..20b565998f 100644 --- a/st2reactor/st2reactor/container/utils.py +++ b/st2reactor/st2reactor/container/utils.py @@ -51,31 +51,16 @@ def create_trigger_instance(trigger, payload, occurrence_time): def _create_trigger_type(pack, name, description=None, payload_schema=None, parameters_schema=None): - triggertypes = TriggerType.query(pack=pack, name=name) - is_update = False - if len(triggertypes) > 0: - trigger_type = triggertypes[0] - LOG.debug('Found existing trigger id:%s with name:%s. Will update ' - 'trigger.', trigger_type.id, name) - is_update = True - else: - trigger_type = TriggerTypeDB() - - trigger_type.pack = pack - trigger_type.name = name - trigger_type.description = description - trigger_type.payload_schema = payload_schema - trigger_type.parameters_schema = parameters_schema - try: - triggertype_db = TriggerType.add_or_update(trigger_type) - except: - LOG.exception('Validation failed for TriggerType=%s.', trigger_type) - raise TriggerTypeRegistrationException('Invalid TriggerType name=%s.' % name) - if is_update: - LOG.audit('TriggerType updated. TriggerType=%s', triggertype_db) - else: - LOG.audit('TriggerType created. TriggerType=%s', triggertype_db) - return triggertype_db + trigger_type = { + 'name': name, + 'pack': pack, + 'description': description, + 'payload_schema': payload_schema, + 'parameters_schema': parameters_schema + } + + trigger_type_db = TriggerService.create_or_update_trigger_type_db(trigger_type=trigger_type) + return trigger_type_db def _validate_trigger_type(trigger_type): @@ -95,24 +80,20 @@ def _create_trigger(trigger_type): :type trigger_type: :class:`TriggerTypeDB` """ if hasattr(trigger_type, 'parameters_schema') and not trigger_type['parameters_schema']: - trigger_db = TriggerService.get_trigger_db({'pack': trigger_type.pack, - 'name': trigger_type.name}) - - if trigger_db is None: - trigger_dict = { - 'name': trigger_type.name, - 'pack': trigger_type.pack, - 'type': trigger_type.get_reference().ref - } - - try: - trigger_db = TriggerService.create_trigger_db(trigger_dict) - except: - LOG.exception('Validation failed for Trigger=%s.', trigger_dict) - raise TriggerTypeRegistrationException( - 'Unable to create Trigger for TriggerType=%s.' % trigger_type.name) - else: - return trigger_db + trigger_dict = { + 'name': trigger_type.name, + 'pack': trigger_type.pack, + 'type': trigger_type.get_reference().ref + } + + try: + trigger_db = TriggerService.create_or_update_trigger_db(trigger=trigger_dict) + except: + LOG.exception('Validation failed for Trigger=%s.', trigger_dict) + raise TriggerTypeRegistrationException( + 'Unable to create Trigger for TriggerType=%s.' % trigger_type.name) + else: + return trigger_db else: LOG.debug('Won\'t create Trigger object as TriggerType %s expects ' + 'parameters.', trigger_type) From c7b0a68d0eb2e295e645d3a7edd1d0da45533480 Mon Sep 17 00:00:00 2001 From: Tomaz Muraus Date: Mon, 22 Dec 2014 17:44:18 +0100 Subject: [PATCH 03/15] Fix a bug in RuleAPI.to_model API which caused the same trigger model to be created multiple times if the "rule.trigger" dict didn't contain a "name" attribute. Instead of using the existing Trigger object, this method created a new trigger with a random uuid for the name. Name attribute doesn't need to be specified by the user, since the name can be inferred from "type" attribute. --- st2common/st2common/services/triggers.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/st2common/st2common/services/triggers.py b/st2common/st2common/services/triggers.py index bb405abfb0..de2e05e1d4 100644 --- a/st2common/st2common/services/triggers.py +++ b/st2common/st2common/services/triggers.py @@ -103,12 +103,12 @@ def _get_trigger_api_given_rule(rule): trigger = rule.trigger triggertype_ref = ResourceReference.from_string_reference(trigger.get('type')) trigger_dict = {} - trigger_name = trigger.get('name', None) - if trigger_name: - trigger_dict['name'] = trigger_name + + trigger_dict['name'] = triggertype_ref.name trigger_dict['pack'] = triggertype_ref.pack trigger_dict['type'] = triggertype_ref.ref trigger_dict['parameters'] = rule.trigger.get('parameters', {}) + trigger_api = TriggerAPI(**trigger_dict) return trigger_api From 12891eafe922f9a80ea203ee8e6d343fc5c05cbb Mon Sep 17 00:00:00 2001 From: Tomaz Muraus Date: Mon, 22 Dec 2014 17:47:54 +0100 Subject: [PATCH 04/15] Fix lint. --- st2reactor/st2reactor/container/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/st2reactor/st2reactor/container/utils.py b/st2reactor/st2reactor/container/utils.py index 20b565998f..1ad6f38a05 100644 --- a/st2reactor/st2reactor/container/utils.py +++ b/st2reactor/st2reactor/container/utils.py @@ -17,8 +17,8 @@ from st2common import log as logging from st2common.exceptions.sensors import TriggerTypeRegistrationException -from st2common.persistence.reactor import SensorType, TriggerType, TriggerInstance -from st2common.models.db.reactor import SensorTypeDB, TriggerTypeDB, TriggerInstanceDB +from st2common.persistence.reactor import SensorType, TriggerInstance +from st2common.models.db.reactor import SensorTypeDB, TriggerInstanceDB from st2common.services import triggers as TriggerService from st2common.constants.pack import SYSTEM_PACK_NAME from st2common.constants.sensors import MINIMUM_POLL_INTERVAL From 1513bb8a9e3da1ba81f63ac28e1cbfdd233bf283 Mon Sep 17 00:00:00 2001 From: Tomaz Muraus Date: Mon, 22 Dec 2014 18:59:16 +0100 Subject: [PATCH 05/15] Add tests for sensor registration. --- .../pack_with_sensor/sensors/test_sensor.yaml | 12 ++ .../test_sensor_and_rule_registration.py | 106 ++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 st2reactor/tests/fixtures/packs/pack_with_sensor/sensors/test_sensor.yaml create mode 100644 st2reactor/tests/test_sensor_and_rule_registration.py diff --git a/st2reactor/tests/fixtures/packs/pack_with_sensor/sensors/test_sensor.yaml b/st2reactor/tests/fixtures/packs/pack_with_sensor/sensors/test_sensor.yaml new file mode 100644 index 0000000000..11a6fd6992 --- /dev/null +++ b/st2reactor/tests/fixtures/packs/pack_with_sensor/sensors/test_sensor.yaml @@ -0,0 +1,12 @@ +--- + class_name: "TestSensor" + entry_point: "test_sensor.py" + description: "Test sensor" + poll_interval: 10 + trigger_types: + - + name: "trigger_type_1" + description: "1" + - + name: "trigger_type_2" + description: "2" diff --git a/st2reactor/tests/test_sensor_and_rule_registration.py b/st2reactor/tests/test_sensor_and_rule_registration.py new file mode 100644 index 0000000000..62afdccbbc --- /dev/null +++ b/st2reactor/tests/test_sensor_and_rule_registration.py @@ -0,0 +1,106 @@ +# Licensed to the StackStorm, Inc ('StackStorm') under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +from st2tests import DbTestCase +from st2common.models.db.reactor import SensorTypeDB +from st2common.models.db.reactor import TriggerDB +from st2common.models.db.reactor import TriggerTypeDB +from st2common.persistence.reactor import SensorType +from st2common.persistence.reactor import Trigger +from st2common.persistence.reactor import TriggerType +from st2reactor.bootstrap.sensorsregistrar import SensorsRegistrar + +CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) + + +class SensorRegistrationTestCase(DbTestCase): + def setUp(self): + self._packs_base_path = os.path.join(CURRENT_DIR, 'fixtures/packs') + + def test_register_sensors(self): + # Verify DB is empty at the beginning + self.assertEqual(len(SensorType.get_all()), 0) + self.assertEqual(len(TriggerType.get_all()), 0) + self.assertEqual(len(Trigger.get_all()), 0) + + registrar = SensorsRegistrar() + registrar.register_sensors_from_packs(base_dir=self._packs_base_path) + + # Verify objects have been created + sensor_dbs = SensorType.get_all() + trigger_type_dbs = TriggerType.get_all() + trigger_dbs = Trigger.get_all() + + self.assertEqual(len(sensor_dbs), 1) + self.assertEqual(len(trigger_type_dbs), 2) + self.assertEqual(len(trigger_dbs), 2) + + self.assertEqual(sensor_dbs[0].name, 'TestSensor') + self.assertEqual(sensor_dbs[0].poll_interval, 10) + + self.assertEqual(trigger_type_dbs[0].name, 'trigger_type_1') + self.assertEqual(trigger_type_dbs[0].pack, 'pack_with_sensor') + self.assertEqual(trigger_type_dbs[1].name, 'trigger_type_2') + self.assertEqual(trigger_type_dbs[1].pack, 'pack_with_sensor') + + # Verify second call to registration doesn't create a duplicate objects + registrar.register_sensors_from_packs(base_dir=self._packs_base_path) + + sensor_dbs = SensorType.get_all() + trigger_type_dbs = TriggerType.get_all() + trigger_dbs = Trigger.get_all() + + self.assertEqual(len(sensor_dbs), 1) + self.assertEqual(len(trigger_type_dbs), 2) + self.assertEqual(len(trigger_dbs), 2) + + self.assertEqual(sensor_dbs[0].name, 'TestSensor') + self.assertEqual(sensor_dbs[0].poll_interval, 10) + + self.assertEqual(trigger_type_dbs[0].name, 'trigger_type_1') + self.assertEqual(trigger_type_dbs[0].pack, 'pack_with_sensor') + self.assertEqual(trigger_type_dbs[1].name, 'trigger_type_2') + self.assertEqual(trigger_type_dbs[1].pack, 'pack_with_sensor') + + # Verify sensor and trigger data is updated on registration + original_load = registrar._meta_loader.load + def mock_load(*args, **kwargs): + # Update poll_interval and trigger_type_2 description + data = original_load(*args, **kwargs) + data['poll_interval'] = 50 + data['trigger_types'][1]['description'] = 'test 2' + return data + registrar._meta_loader.load = mock_load + + registrar.register_sensors_from_packs(base_dir=self._packs_base_path) + + sensor_dbs = SensorType.get_all() + trigger_type_dbs = TriggerType.get_all() + trigger_dbs = Trigger.get_all() + + self.assertEqual(len(sensor_dbs), 1) + self.assertEqual(len(trigger_type_dbs), 2) + self.assertEqual(len(trigger_dbs), 2) + + self.assertEqual(sensor_dbs[0].name, 'TestSensor') + self.assertEqual(sensor_dbs[0].poll_interval, 50) + + self.assertEqual(trigger_type_dbs[0].name, 'trigger_type_1') + self.assertEqual(trigger_type_dbs[0].pack, 'pack_with_sensor') + self.assertEqual(trigger_type_dbs[1].name, 'trigger_type_2') + self.assertEqual(trigger_type_dbs[1].pack, 'pack_with_sensor') + self.assertEqual(trigger_type_dbs[1].description, 'test 2') From dc07e98d4dc04cf961640b738e80ec1bd285e92b Mon Sep 17 00:00:00 2001 From: Tomaz Muraus Date: Mon, 22 Dec 2014 19:03:04 +0100 Subject: [PATCH 06/15] Fix a bug and add missing description attribute. --- contrib/examples/actions/mistral-basic.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/examples/actions/mistral-basic.yaml b/contrib/examples/actions/mistral-basic.yaml index d2144cf2d3..d5f57dc44e 100644 --- a/contrib/examples/actions/mistral-basic.yaml +++ b/contrib/examples/actions/mistral-basic.yaml @@ -1,5 +1,6 @@ name: 'examples.mistral-basic' version: '2.0' +description: 'Basic mistral workflow example' workflows: demo: type: direct From 6ea82ec189aa11fd183f66bc396bd3a60c825693 Mon Sep 17 00:00:00 2001 From: Tomaz Muraus Date: Mon, 22 Dec 2014 19:18:07 +0100 Subject: [PATCH 07/15] Move workflows to a sub-directory to avoid erronous errors. --- contrib/packs/actions/install.meta.yaml | 2 +- contrib/packs/actions/uninstall.meta.yaml | 3 +-- contrib/packs/actions/{ => workflows}/install.yaml | 0 contrib/packs/actions/{ => workflows}/uninstall.yaml | 0 4 files changed, 2 insertions(+), 3 deletions(-) rename contrib/packs/actions/{ => workflows}/install.yaml (100%) rename contrib/packs/actions/{ => workflows}/uninstall.yaml (100%) diff --git a/contrib/packs/actions/install.meta.yaml b/contrib/packs/actions/install.meta.yaml index ac5fc5be47..aab6bb19a5 100644 --- a/contrib/packs/actions/install.meta.yaml +++ b/contrib/packs/actions/install.meta.yaml @@ -5,7 +5,7 @@ Will download pack, load the actions, sensors and rules from the pack. Note that install require reboot of some st2 services." enabled: true - entry_point: "install.yaml" + entry_point: "workflows/install.yaml" parameters: packs: type: "array" diff --git a/contrib/packs/actions/uninstall.meta.yaml b/contrib/packs/actions/uninstall.meta.yaml index 98788e5cf4..469298dbf7 100644 --- a/contrib/packs/actions/uninstall.meta.yaml +++ b/contrib/packs/actions/uninstall.meta.yaml @@ -5,11 +5,10 @@ Removes pack and content from st2. Note that uninstall require reboot of some st2 services." enabled: true - entry_point: "uninstall.yaml" + entry_point: "workflows/uninstall.yaml" parameters: packs: type: "array" items: type: "string" required: true - diff --git a/contrib/packs/actions/install.yaml b/contrib/packs/actions/workflows/install.yaml similarity index 100% rename from contrib/packs/actions/install.yaml rename to contrib/packs/actions/workflows/install.yaml diff --git a/contrib/packs/actions/uninstall.yaml b/contrib/packs/actions/workflows/uninstall.yaml similarity index 100% rename from contrib/packs/actions/uninstall.yaml rename to contrib/packs/actions/workflows/uninstall.yaml From 6e7962eff08b4ab9f9d3005aa1a9d6c2d6fe7357 Mon Sep 17 00:00:00 2001 From: Tomaz Muraus Date: Mon, 22 Dec 2014 19:48:31 +0100 Subject: [PATCH 08/15] Update changelog. --- CHANGELOG.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2d78b0efcb..ae16142a43 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -21,6 +21,8 @@ Docs: http://docks.stackstorm.com/latest actions were executed through SSH, now they are executed directly without the overhead of SSH. * Fix local runner so it correctly executes a command under the provider system user if ``user`` parameter is provided. (bug-fix) +* Fix a bug with a Trigger database object in some cases being created twice when registering a + rule. (bug-fix) v0.6.0 - December 8, 2014 ------------------------- From 334e5fdec2d4382d635dd173853deeba9fed1b3f Mon Sep 17 00:00:00 2001 From: Tomaz Muraus Date: Mon, 22 Dec 2014 19:59:57 +0100 Subject: [PATCH 09/15] Add tests for rules registration. --- .../test_sensor_and_rule_registration.py | 36 +++++++++++++++++-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/st2reactor/tests/test_sensor_and_rule_registration.py b/st2reactor/tests/test_sensor_and_rule_registration.py index 62afdccbbc..16f5e63b9e 100644 --- a/st2reactor/tests/test_sensor_and_rule_registration.py +++ b/st2reactor/tests/test_sensor_and_rule_registration.py @@ -16,13 +16,12 @@ import os from st2tests import DbTestCase -from st2common.models.db.reactor import SensorTypeDB -from st2common.models.db.reactor import TriggerDB -from st2common.models.db.reactor import TriggerTypeDB from st2common.persistence.reactor import SensorType from st2common.persistence.reactor import Trigger from st2common.persistence.reactor import TriggerType +from st2common.persistence.reactor import Rule from st2reactor.bootstrap.sensorsregistrar import SensorsRegistrar +from st2reactor.bootstrap.rulesregistrar import RulesRegistrar CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) @@ -78,6 +77,7 @@ def test_register_sensors(self): # Verify sensor and trigger data is updated on registration original_load = registrar._meta_loader.load + def mock_load(*args, **kwargs): # Update poll_interval and trigger_type_2 description data = original_load(*args, **kwargs) @@ -104,3 +104,33 @@ def mock_load(*args, **kwargs): self.assertEqual(trigger_type_dbs[1].name, 'trigger_type_2') self.assertEqual(trigger_type_dbs[1].pack, 'pack_with_sensor') self.assertEqual(trigger_type_dbs[1].description, 'test 2') + + +class RuleRegistrationTestCase(DbTestCase): + def setUp(self): + self._packs_base_path = os.path.join(CURRENT_DIR, 'fixtures/packs') + + def test_register_rules(self): + # Verify DB is empty at the beginning + self.assertEqual(len(Rule.get_all()), 0) + self.assertEqual(len(Trigger.get_all()), 0) + + registrar = RulesRegistrar() + registrar.register_rules_from_packs(base_dir=self._packs_base_path) + + # Verify modeles are created + rule_dbs = Rule.get_all() + trigger_dbs = Trigger.get_all() + self.assertEqual(len(rule_dbs), 1) + self.assertEqual(len(trigger_dbs), 1) + + self.assertEqual(rule_dbs[0].name, 'sample.with_timer') + self.assertEqual(trigger_dbs[0].name, 'st2.IntervalTimer') + + # Verify second register call updates existing models + registrar.register_rules_from_packs(base_dir=self._packs_base_path) + + rule_dbs = Rule.get_all() + trigger_dbs = Trigger.get_all() + self.assertEqual(len(rule_dbs), 1) + self.assertEqual(len(trigger_dbs), 1) From 972139eee02d117d1dfeb54ce2ec4014e5b87562 Mon Sep 17 00:00:00 2001 From: Tomaz Muraus Date: Mon, 22 Dec 2014 20:13:19 +0100 Subject: [PATCH 10/15] Rename file. --- .../{test_fabric_system_model.py => test_fabric_system_models.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename st2common/tests/unit/{test_fabric_system_model.py => test_fabric_system_models.py} (100%) diff --git a/st2common/tests/unit/test_fabric_system_model.py b/st2common/tests/unit/test_fabric_system_models.py similarity index 100% rename from st2common/tests/unit/test_fabric_system_model.py rename to st2common/tests/unit/test_fabric_system_models.py From f3ad48279d7373a49e37fd96d1b47044d8b314bd Mon Sep 17 00:00:00 2001 From: Tomaz Muraus Date: Mon, 22 Dec 2014 20:38:49 +0100 Subject: [PATCH 11/15] Fix a bug - also assign "parallel" and "timeout" variable. --- st2common/st2common/models/system/action.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/st2common/st2common/models/system/action.py b/st2common/st2common/models/system/action.py index 4d3a72ef93..cb80f1d66f 100644 --- a/st2common/st2common/models/system/action.py +++ b/st2common/st2common/models/system/action.py @@ -51,6 +51,7 @@ def __init__(self, name, action_exec_id, command, user, env_vars=None, sudo=Fals self.env_vars = env_vars or {} self.user = user self.sudo = sudo + self.timeout = timeout def get_full_command_string(self): if self.sudo: @@ -250,6 +251,7 @@ def __init__(self, name, action_exec_id, script_local_path_abs, script_local_lib self.on_behalf_user = on_behalf_user self.remote_script = os.path.join(self.remote_dir, pipes.quote(self.script_name)) self.hosts = hosts + self.parallel = parallel self.command = self._format_command() LOG.debug('RemoteScriptAction: command to run on remote box: %s', self.command) From 52741cfadecb347355928fe49d96e9c75da71673 Mon Sep 17 00:00:00 2001 From: Tomaz Muraus Date: Mon, 22 Dec 2014 20:40:18 +0100 Subject: [PATCH 12/15] Add tests for instantiating RemoteAction and RemoteScriptAction class. --- .../tests/unit/test_fabric_system_models.py | 49 ++++++++++++++++++- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/st2common/tests/unit/test_fabric_system_models.py b/st2common/tests/unit/test_fabric_system_models.py index 019112ba0e..1c0050f686 100644 --- a/st2common/tests/unit/test_fabric_system_models.py +++ b/st2common/tests/unit/test_fabric_system_models.py @@ -15,11 +15,56 @@ import unittest2 -from st2common.models.system.action import (FabricRemoteAction, FabricRemoteScriptAction) +from st2common.models.system.action import RemoteAction +from st2common.models.system.action import RemoteScriptAction +from st2common.models.system.action import FabricRemoteAction +from st2common.models.system.action import FabricRemoteScriptAction -class FabricRemoteActionsTest(unittest2.TestCase): +class RemoteActionTestCase(unittest2.TestCase): + def test_instantiation(self): + action = RemoteAction(name='name', action_exec_id='aeid', command='ls -la', + env_vars={'a': 1}, on_behalf_user='onbehalf', user='user', + hosts=['localhost'], parallel=False, sudo=True, timeout=10) + self.assertEqual(action.name, 'name') + self.assertEqual(action.action_exec_id, 'aeid') + self.assertEqual(action.command, 'ls -la') + self.assertEqual(action.env_vars, {'a': 1}) + self.assertEqual(action.on_behalf_user, 'onbehalf') + self.assertEqual(action.user, 'user') + self.assertEqual(action.hosts, ['localhost']) + self.assertEqual(action.parallel, False) + self.assertEqual(action.sudo, True) + self.assertEqual(action.timeout, 10) + +class RemoteScriptActionTestCase(unittest2.TestCase): + def test_instantiation(self): + action = RemoteScriptAction(name='name', action_exec_id='aeid', + script_local_path_abs='/tmp/sc/ma_script.sh', + script_local_libs_path_abs='/tmp/sc/libs', named_args=None, + positional_args=None, env_vars={'a': 1}, on_behalf_user='onbehalf', + user='user', remote_dir='/home/mauser', hosts=['localhost'], + parallel=False, sudo=True, timeout=10) + self.assertEqual(action.name, 'name') + self.assertEqual(action.action_exec_id, 'aeid') + self.assertEqual(action.script_local_libs_path_abs, '/tmp/sc/libs') + self.assertEqual(action.env_vars, {'a': 1}) + self.assertEqual(action.on_behalf_user, 'onbehalf') + self.assertEqual(action.user, 'user') + self.assertEqual(action.remote_dir, '/home/mauser') + self.assertEqual(action.hosts, ['localhost']) + self.assertEqual(action.parallel, False) + self.assertEqual(action.sudo, True) + self.assertEqual(action.timeout, 10) + + self.assertEqual(action.script_local_dir, '/tmp/sc') + self.assertEqual(action.script_name, 'ma_script.sh') + self.assertEqual(action.remote_script, '/home/mauser/ma_script.sh') + self.assertEqual(action.command, '/home/mauser/ma_script.sh') + + +class FabricRemoteActionTestCase(unittest2.TestCase): def test_fabric_remote_action_method(self): remote_action = FabricRemoteAction('foo', 'foo-id', 'ls -lrth', on_behalf_user='stan', parallel=True, sudo=False) From 99c436710b8f549f685915557aef28addf575436 Mon Sep 17 00:00:00 2001 From: Tomaz Muraus Date: Mon, 22 Dec 2014 20:41:14 +0100 Subject: [PATCH 13/15] Rename file. --- ...{test_fabric_system_models.py => test_action_system_models.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename st2common/tests/unit/{test_fabric_system_models.py => test_action_system_models.py} (100%) diff --git a/st2common/tests/unit/test_fabric_system_models.py b/st2common/tests/unit/test_action_system_models.py similarity index 100% rename from st2common/tests/unit/test_fabric_system_models.py rename to st2common/tests/unit/test_action_system_models.py From b528717d7b0627b7cf236021232f3c87b6879206 Mon Sep 17 00:00:00 2001 From: Tomaz Muraus Date: Mon, 22 Dec 2014 20:43:18 +0100 Subject: [PATCH 14/15] Fix lint. --- st2common/tests/unit/test_action_system_models.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/st2common/tests/unit/test_action_system_models.py b/st2common/tests/unit/test_action_system_models.py index 1c0050f686..7d988c7ecf 100644 --- a/st2common/tests/unit/test_action_system_models.py +++ b/st2common/tests/unit/test_action_system_models.py @@ -43,8 +43,9 @@ def test_instantiation(self): action = RemoteScriptAction(name='name', action_exec_id='aeid', script_local_path_abs='/tmp/sc/ma_script.sh', script_local_libs_path_abs='/tmp/sc/libs', named_args=None, - positional_args=None, env_vars={'a': 1}, on_behalf_user='onbehalf', - user='user', remote_dir='/home/mauser', hosts=['localhost'], + positional_args=None, env_vars={'a': 1}, + on_behalf_user='onbehalf', user='user', + remote_dir='/home/mauser', hosts=['localhost'], parallel=False, sudo=True, timeout=10) self.assertEqual(action.name, 'name') self.assertEqual(action.action_exec_id, 'aeid') From 8a446bce38f102c022b8b0974d9b734b6a6ec6cb Mon Sep 17 00:00:00 2001 From: Tomaz Muraus Date: Mon, 22 Dec 2014 20:43:25 +0100 Subject: [PATCH 15/15] Add missing file. --- .../pack_with_rules/rules/rule_with_timer.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 st2reactor/tests/fixtures/packs/pack_with_rules/rules/rule_with_timer.yaml diff --git a/st2reactor/tests/fixtures/packs/pack_with_rules/rules/rule_with_timer.yaml b/st2reactor/tests/fixtures/packs/pack_with_rules/rules/rule_with_timer.yaml new file mode 100644 index 0000000000..f5cf652d9c --- /dev/null +++ b/st2reactor/tests/fixtures/packs/pack_with_rules/rules/rule_with_timer.yaml @@ -0,0 +1,15 @@ + +--- + name: "sample.with_timer" + description: "Sample rule using an Interval Timer." + trigger: + type: "core.st2.IntervalTimer" + parameters: + delta: 5 + unit: "seconds" + criteria: {} + action: + ref: "core.local" + parameters: + cmd: "echo \"{{trigger.executed_at}}\"" + enabled: true