Skip to content

Commit e4c6eb5

Browse files
authored
Merge pull request #2802 from StackStorm/1.5.1
Release branch for StackStorm v1.5.1
2 parents 49b938c + e7f13b2 commit e4c6eb5

File tree

24 files changed

+237
-61
lines changed

24 files changed

+237
-61
lines changed

CHANGELOG.rst

+14
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
11
Changelog
22
=========
33

4+
1.5.1 - July 13, 2016
5+
---------------------
6+
7+
* Fix trigger registration when using st2-register-content script with ``--register-triggers``
8+
flag. (bug-fix)
9+
* Fix an issue with CronTimer sometimes not firing due to TriggerInstance creation failure.
10+
(bug-fix)
11+
Reported by Cody A. Ray
12+
* Add support for default values when a new pack configuration is used. Now if a default value
13+
is specified for a required config item in the config schema and a value for that item is not
14+
provided in the config, default value from config schema is used. (improvement)
15+
* Allow user to prevent execution parameter merging when re-running an execution by passing
16+
``?no_merge=true`` query parameter to the execution re-run API endpoint. (improvement)
17+
418
1.5.0 - June 24, 2016
519
---------------------
620

Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
11
---
2-
payload:
3-
result: 10
4-
work: done
5-
type: st2.trigger
2+
name: sample_trigger
3+
description: Sample trigger

st2api/st2api/controllers/v1/actionexecutions.py

+13-9
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
from st2common.models.api.action import LiveActionAPI
3838
from st2common.models.api.action import LiveActionCreateAPI
3939
from st2common.models.api.base import jsexpose
40+
from st2common.models.api.base import cast_argument_value
4041
from st2common.models.api.execution import ActionExecutionAPI
4142
from st2common.persistence.liveaction import LiveAction
4243
from st2common.persistence.execution import ActionExecution
@@ -276,22 +277,25 @@ def validate(self):
276277
return self
277278

278279
@jsexpose(body_cls=ExecutionSpecificationAPI, status_code=http_client.CREATED)
279-
def post(self, spec, execution_id):
280+
def post(self, spec_api, execution_id, no_merge=False):
280281
"""
281282
Re-run the provided action execution optionally specifying override parameters.
282283
283284
Handles requests:
284285
285286
POST /executions/<id>/re_run
286287
"""
288+
no_merge = cast_argument_value(value_type=bool, value=no_merge)
287289
existing_execution = self._get_one(id=execution_id, exclude_fields=self.exclude_fields)
288290

289-
if spec.tasks and existing_execution.runner['name'] != 'mistral-v2':
291+
if spec_api.tasks and existing_execution.runner['name'] != 'mistral-v2':
290292
raise ValueError('Task option is only supported for Mistral workflows.')
291293

292294
# Merge in any parameters provided by the user
293-
new_parameters = copy.deepcopy(getattr(existing_execution, 'parameters', {}))
294-
new_parameters.update(spec.parameters)
295+
new_parameters = {}
296+
if not no_merge:
297+
new_parameters.update(getattr(existing_execution, 'parameters', {}))
298+
new_parameters.update(spec_api.parameters)
295299

296300
# Create object for the new execution
297301
action_ref = existing_execution.action['ref']
@@ -303,11 +307,11 @@ def post(self, spec, execution_id):
303307
}
304308
}
305309

306-
if spec.tasks:
307-
context['re-run']['tasks'] = spec.tasks
310+
if spec_api.tasks:
311+
context['re-run']['tasks'] = spec_api.tasks
308312

309-
if spec.reset:
310-
context['re-run']['reset'] = spec.reset
313+
if spec_api.reset:
314+
context['re-run']['reset'] = spec_api.reset
311315

312316
# Add trace to the new execution
313317
trace = trace_service.get_trace_db_by_action_execution(
@@ -319,7 +323,7 @@ def post(self, spec, execution_id):
319323
new_liveaction_api = LiveActionCreateAPI(action=action_ref,
320324
context=context,
321325
parameters=new_parameters,
322-
user=spec.user)
326+
user=spec_api.user)
323327

324328
return self._handle_schedule_execution(liveaction_api=new_liveaction_api)
325329

st2api/tests/unit/controllers/v1/test_base.py

+10
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,13 @@ def test_wildcard_origin(self):
6565
self.assertEqual(response.status_int, 200)
6666
self.assertEqual(response.headers['Access-Control-Allow-Origin'],
6767
'*')
68+
69+
def test_valid_status_code_is_returned_on_invalid_path(self):
70+
# TypeError: get_all() takes exactly 1 argument (2 given)
71+
resp = self.app.get('/v1/executions/577f775b0640fd1451f2030b/re_run', expect_errors=True)
72+
self.assertEqual(resp.status_int, 404)
73+
74+
# get_one() takes exactly 2 arguments (4 given)
75+
resp = self.app.get('/v1/executions/577f775b0640fd1451f2030b/re_run/a/b',
76+
expect_errors=True)
77+
self.assertEqual(resp.status_int, 404)

st2client/requirements.txt

+1
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ pytz
66
pyyaml<4.0,>=3.11
77
requests<3.0,>=2.7.0
88
six==1.9.0
9+
argcomplete==1.4.1

st2client/st2client/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515

16-
__version__ = '1.5.0'
16+
__version__ = '1.5.1'

st2common/st2common/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515

16-
__version__ = '1.5.0'
16+
__version__ = '1.5.1'

st2common/st2common/bootstrap/triggersregistrar.py

+4-18
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@
2121
from st2common.constants.meta import ALLOWED_EXTS
2222
from st2common.bootstrap.base import ResourceRegistrar
2323
import st2common.content.utils as content_utils
24-
from st2common.models.api.trigger import TriggerTypeAPI
25-
from st2common.persistence.trigger import TriggerType
24+
from st2common.models.utils import sensor_type_utils
2625

2726
__all__ = [
2827
'TriggersRegistrar',
@@ -135,22 +134,9 @@ def _register_trigger_from_pack(self, pack, trigger):
135134
raise Exception('Model is in pack "%s" but field "pack" is different: %s' %
136135
(pack, pack_field))
137136

138-
trigger_api = TriggerTypeAPI(**content)
139-
trigger_model = TriggerTypeAPI.to_model(trigger_api)
140-
141-
trigger_types = TriggerType.query(pack=trigger_model.pack, name=trigger_model.name)
142-
if len(trigger_types) >= 1:
143-
trigger_type = trigger_types[0]
144-
LOG.debug('Found existing trigger id:%s with name:%s. Will update it.',
145-
trigger_type.id, trigger_type.name)
146-
trigger_model.id = trigger_type.id
147-
148-
try:
149-
trigger_model = TriggerType.add_or_update(trigger_model)
150-
except:
151-
LOG.exception('Failed creating trigger model for %s', trigger)
152-
153-
return trigger_model
137+
trigger_types = [content]
138+
result = sensor_type_utils.create_trigger_types(trigger_types=trigger_types)
139+
return result[0] if result else None
154140

155141

156142
def register_triggers(packs_base_paths=None, pack_dir=None, use_pack_cache=True,

st2common/st2common/models/db/__init__.py

+3
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,9 @@ def get_by_name(self, value):
169169
def get_by_id(self, value):
170170
return self.get(id=value, raise_exception=True)
171171

172+
def get_by_uid(self, value):
173+
return self.get(uid=value, raise_exception=True)
174+
172175
def get_by_ref(self, value):
173176
return self.get(ref=value, raise_exception=True)
174177

st2common/st2common/models/utils/action_param_utils.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def _merge_param_meta_values(action_meta=None, runner_meta=None):
4040
elif key in runner_meta_keys and key not in action_meta_keys:
4141
merged_meta[key] = runner_meta[key]
4242
else:
43-
if key in ['immutable', 'required']:
43+
if key in ['immutable']:
4444
merged_meta[key] = runner_meta.get(key, False) or action_meta.get(key, False)
4545
else:
4646
merged_meta[key] = action_meta.get(key)

st2common/st2common/models/utils/sensor_type_utils.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222

2323
__all__ = [
2424
'to_sensor_db_model',
25-
'get_sensor_entry_point'
25+
'get_sensor_entry_point',
26+
'create_trigger_types'
2627
]
2728

2829

@@ -53,7 +54,7 @@ def to_sensor_db_model(sensor_api_model=None):
5354
# Add pack to each trigger type item
5455
for trigger_type in trigger_types:
5556
trigger_type['pack'] = pack
56-
trigger_type_refs = _create_trigger_types(trigger_types)
57+
trigger_type_refs = create_trigger_types(trigger_types)
5758

5859
return _create_sensor_type(pack=pack,
5960
name=class_name,
@@ -65,7 +66,7 @@ def to_sensor_db_model(sensor_api_model=None):
6566
enabled=enabled)
6667

6768

68-
def _create_trigger_types(trigger_types):
69+
def create_trigger_types(trigger_types):
6970
if not trigger_types:
7071
return []
7172

st2common/st2common/persistence/base.py

+4
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ def get_by_name(cls, value):
8383
def get_by_id(cls, value):
8484
return cls._get_impl().get_by_id(value)
8585

86+
@classmethod
87+
def get_by_uid(cls, value):
88+
return cls._get_impl().get_by_uid(value)
89+
8690
@classmethod
8791
def get_by_ref(cls, value):
8892
return cls._get_impl().get_by_ref(value)

st2common/st2common/services/triggers.py

+40-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
'add_trigger_models',
2929

3030
'get_trigger_db_by_ref',
31+
'get_trigger_db_by_id',
32+
'get_trigger_db_by_uid',
3133
'get_trigger_db_given_type_and_params',
3234
'get_trigger_type_db',
3335

@@ -92,6 +94,42 @@ def get_trigger_db_given_type_and_params(type=None, parameters=None):
9294
return None
9395

9496

97+
def get_trigger_db_by_id(id):
98+
"""
99+
Returns the trigger object from db given a trigger id.
100+
101+
:param ref: Reference to the trigger db object.
102+
:type ref: ``str``
103+
104+
:rtype: ``object``
105+
"""
106+
try:
107+
return Trigger.get_by_id(id)
108+
except StackStormDBObjectNotFoundError as e:
109+
LOG.debug('Database lookup for id="%s" resulted in exception : %s.',
110+
id, e, exc_info=True)
111+
112+
return None
113+
114+
115+
def get_trigger_db_by_uid(uid):
116+
"""
117+
Returns the trigger object from db given a trigger uid.
118+
119+
:param ref: Reference to the trigger db object.
120+
:type ref: ``str``
121+
122+
:rtype: ``object``
123+
"""
124+
try:
125+
return Trigger.get_by_uid(uid)
126+
except StackStormDBObjectNotFoundError as e:
127+
LOG.debug('Database lookup for uid="%s" resulted in exception : %s.',
128+
uid, e, exc_info=True)
129+
130+
return None
131+
132+
95133
def get_trigger_db_by_ref(ref):
96134
"""
97135
Returns the trigger object from db given a string ref.
@@ -355,7 +393,8 @@ def _validate_trigger_type(trigger_type):
355393
required_fields = ['name']
356394
for field in required_fields:
357395
if field not in trigger_type:
358-
raise TriggerTypeRegistrationException('Invalid trigger type. Missing field %s' % field)
396+
raise TriggerTypeRegistrationException('Invalid trigger type. Missing field "%s"' %
397+
(field))
359398

360399

361400
def _create_trigger(trigger_type):

st2common/st2common/util/api.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ def get_exception_for_type_error(func, exc):
115115

116116
# Note: Those checks are hacky, but it's better than having no checks and silently
117117
# accepting invalid requests
118-
invalid_num_args_pattern = ('%s\(\) takes %s \d+ arguments \(\d+ given\)' %
118+
invalid_num_args_pattern = ('%s\(\) takes %s \d+ arguments? \(\d+ given\)' %
119119
(func_name, '(exactly|at most|at least)'))
120120
unexpected_keyword_arg_pattern = ('%s\(\) got an unexpected keyword argument \'(.*?)\'' %
121121
(func_name))

st2common/st2common/util/config_loader.py

+9
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,15 @@ def _get_values_for_config(self, config_schema_db, config_db):
103103
# Static value, no resolution needed
104104
result[config_item_key] = config_item_value
105105

106+
# If config_schema is available we do a second pass and set default values for required
107+
# items which values are not provided / available in the config itself
108+
for schema_item_key, schema_item in six.iteritems(schema_values):
109+
default_value = schema_item.get('default', None)
110+
is_required = schema_item.get('required', False)
111+
112+
if is_required and default_value and not result.get(schema_item_key, None):
113+
result[schema_item_key] = default_value
114+
106115
return result
107116

108117
def _get_datastore_value_for_expression(self, value, config_schema_item=None):

st2common/tests/unit/test_action_param_utils.py

+12
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,18 @@ def test_merge_param_meta_values(self):
106106
# Immutability is set in action.
107107
self.assertEqual(merged_meta['immutable'], action_meta['immutable'])
108108

109+
def test_merge_param_meta_require_override(self):
110+
action_meta = {
111+
'required': False
112+
}
113+
runner_meta = {
114+
'required': True
115+
}
116+
merged_meta = action_param_utils._merge_param_meta_values(action_meta=action_meta,
117+
runner_meta=runner_meta)
118+
119+
self.assertEqual(merged_meta['required'], action_meta['required'])
120+
109121
def test_validate_action_inputs(self):
110122
requires, unexpected = action_param_utils.validate_action_parameters(
111123
self.action_dbs['action-1'].ref, {'foo': 'bar'})

st2common/tests/unit/test_config_loader.py

+14-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ def test_get_config_all_values_are_loaded_from_local_config(self):
4444
def test_get_config_some_values_overriden_in_datastore(self):
4545
# Test a scenario where some values are overriden in datastore via pack
4646
# flobal config
47-
4847
kvp_db = set_datastore_value_for_config_key(pack_name='dummy_pack_5',
4948
key_name='api_secret',
5049
value='some_api_secret',
@@ -71,7 +70,21 @@ def test_get_config_some_values_overriden_in_datastore(self):
7170
'api_key': 'some_api_key',
7271
'api_secret': 'some_api_secret',
7372
'regions': ['us-west-1'],
73+
'region': 'default-region-value',
7474
'private_key_path': 'some_private_key'
7575
}
7676

7777
self.assertEqual(config, expected_config)
78+
79+
def test_get_config_default_value_from_config_schema_is_used(self):
80+
# No value is provided for "region" in the config, default value from config schema
81+
# should be used
82+
loader = ContentPackConfigLoader(pack_name='dummy_pack_5')
83+
config = loader.get_config()
84+
self.assertEqual(config['region'], 'default-region-value')
85+
86+
# Here a default value is specified in schema but an explicit value is provided in the
87+
# config
88+
loader = ContentPackConfigLoader(pack_name='dummy_pack_1')
89+
config = loader.get_config()
90+
self.assertEqual(config['region'], 'us-west-1')

st2common/tests/unit/test_sensor_type_utils.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def test_to_sensor_db_model_no_trigger_types(self):
3535
self.assertEqual(sensor_model.artifact_uri, sensor_meta['artifact_uri'])
3636
self.assertListEqual(sensor_model.trigger_types, [])
3737

38-
@mock.patch.object(sensor_type_utils, '_create_trigger_types', mock.MagicMock(
38+
@mock.patch.object(sensor_type_utils, 'create_trigger_types', mock.MagicMock(
3939
return_value=['mock.trigger_ref']))
4040
def test_to_sensor_db_model_with_trigger_types(self):
4141
sensor_meta = {

0 commit comments

Comments
 (0)