diff options
author | Jenkins <jenkins@review.openstack.org> | 2016-09-21 02:33:51 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2016-09-21 02:33:51 +0000 |
commit | 0493eb18a3db76413e23cc96b6f35b31a94faff5 (patch) | |
tree | a6b05574e9f98325a4547855b66fb04a8bf832b2 | |
parent | c5ae32382d38462e3c299399169b8557aaa3db95 (diff) | |
parent | 00a757eea109f5e21d7cd85ad2f09cdb9ddae94f (diff) | |
download | python-heatclient-0493eb18a3db76413e23cc96b6f35b31a94faff5.tar.gz |
Merge "Update .gitreview for stable/newton" into stable/newton
-rw-r--r-- | heatclient/common/deployment_utils.py | 4 | ||||
-rw-r--r-- | heatclient/common/environment_format.py | 16 | ||||
-rw-r--r-- | heatclient/common/event_utils.py | 3 | ||||
-rw-r--r-- | heatclient/common/utils.py | 72 | ||||
-rw-r--r-- | heatclient/openstack/common/apiclient/base.py | 4 | ||||
-rw-r--r-- | heatclient/openstack/common/apiclient/client.py | 9 | ||||
-rw-r--r-- | heatclient/osc/v1/event.py | 4 | ||||
-rw-r--r-- | heatclient/tests/unit/__init__.py | 5 | ||||
-rw-r--r-- | heatclient/tests/unit/osc/v1/test_template.py | 2 | ||||
-rw-r--r-- | heatclient/tests/unit/test_common_http.py | 2 | ||||
-rw-r--r-- | heatclient/tests/unit/test_environment_format.py | 18 | ||||
-rw-r--r-- | heatclient/tests/unit/test_events.py | 2 | ||||
-rw-r--r-- | heatclient/tests/unit/test_resources.py | 2 | ||||
-rw-r--r-- | heatclient/tests/unit/test_shell.py | 2 | ||||
-rw-r--r-- | heatclient/tests/unit/test_template_utils.py | 4 | ||||
-rw-r--r-- | heatclient/tests/unit/test_utils.py | 142 | ||||
-rw-r--r-- | heatclient/v1/shell.py | 8 |
17 files changed, 268 insertions, 31 deletions
diff --git a/heatclient/common/deployment_utils.py b/heatclient/common/deployment_utils.py index adb1769..ee209dc 100644 --- a/heatclient/common/deployment_utils.py +++ b/heatclient/common/deployment_utils.py @@ -20,13 +20,13 @@ from swiftclient import utils as swiftclient_utils from heatclient import exc from heatclient.openstack.common._i18n import _ -from heatclient.v1.software_configs import SoftwareConfig +from heatclient.v1 import software_configs def build_derived_config_params(action, source, name, input_values, server_id, signal_transport, signal_id=None): - if isinstance(source, SoftwareConfig): + if isinstance(source, software_configs.SoftwareConfig): source = source.to_dict() input_values = input_values or {} inputs = copy.deepcopy(source.get('inputs')) or [] diff --git a/heatclient/common/environment_format.py b/heatclient/common/environment_format.py index 6870b79..8f2c4ea 100644 --- a/heatclient/common/environment_format.py +++ b/heatclient/common/environment_format.py @@ -17,9 +17,13 @@ from heatclient.openstack.common._i18n import _ SECTIONS = ( - PARAMETER_DEFAULTS, PARAMETERS, RESOURCE_REGISTRY, EVENT_SINKS + PARAMETER_DEFAULTS, PARAMETERS, RESOURCE_REGISTRY, + ENCRYPTED_PARAM_NAMES, EVENT_SINKS, + PARAMETER_MERGE_STRATEGIES ) = ( - 'parameter_defaults', 'parameters', 'resource_registry', 'event_sinks' + 'parameter_defaults', 'parameters', 'resource_registry', + 'encrypted_param_names', 'event_sinks', + 'parameter_merge_strategies' ) @@ -55,7 +59,9 @@ def parse(env_str): def default_for_missing(env): """Checks a parsed environment for missing sections.""" - for param in SECTIONS: - if param not in env: - env[param] = {} + if param not in env and param != PARAMETER_MERGE_STRATEGIES: + if param in (ENCRYPTED_PARAM_NAMES, EVENT_SINKS): + env[param] = [] + else: + env[param] = {} diff --git a/heatclient/common/event_utils.py b/heatclient/common/event_utils.py index 6acbbd6..c0bc42e 100644 --- a/heatclient/common/event_utils.py +++ b/heatclient/common/event_utils.py @@ -179,6 +179,7 @@ def poll_for_events(hc, stack_name, action=None, poll_period=5, marker=None, msg_template = _("\n Stack %(name)s %(status)s \n") if not out: out = sys.stdout + event_log_context = utils.EventLogContext() while True: events = get_events(hc, stack_id=stack_name, nested_depth=nested_depth, event_args={'sort_dir': 'asc', @@ -190,7 +191,7 @@ def poll_for_events(hc, stack_name, action=None, poll_period=5, marker=None, no_event_polls = 0 # set marker to last event that was received. marker = getattr(events[-1], 'id', None) - events_log = utils.event_log_formatter(events) + events_log = utils.event_log_formatter(events, event_log_context) out.write(events_log) out.write('\n') diff --git a/heatclient/common/utils.py b/heatclient/common/utils.py index a36ab38..f2b20f1 100644 --- a/heatclient/common/utils.py +++ b/heatclient/common/utils.py @@ -97,16 +97,84 @@ def print_dict(d, formatters=None): print(pt.get_string(sortby='Property')) -def event_log_formatter(events): +class EventLogContext(object): + + def __init__(self): + # key is a stack id or the name of the nested stack, value is a tuple + # of the parent stack id, and the name of the resource in the parent + # stack + self.id_to_res_info = {} + + def prepend_paths(self, resource_path, stack_id): + if stack_id not in self.id_to_res_info: + return + stack_id, res_name = self.id_to_res_info.get(stack_id) + if res_name in self.id_to_res_info: + # do a double lookup to skip the ugly stack name that doesn't + # correspond to an actual resource name + n_stack_id, res_name = self.id_to_res_info.get(res_name) + resource_path.insert(0, res_name) + self.prepend_paths(resource_path, n_stack_id) + elif res_name: + resource_path.insert(0, res_name) + + def build_resource_name(self, event): + res_name = getattr(event, 'resource_name') + + # Contribute this event to self.id_to_res_info to assist with + # future calls to build_resource_name + + def get_stack_id(): + for l in getattr(event, 'links', []): + if l.get('rel') == 'stack': + if 'href' not in l: + return None + stack_link = l['href'] + return stack_link.split('/')[-1] + + stack_id = get_stack_id() + if not stack_id: + return res_name + phys_id = getattr(event, 'physical_resource_id') + status = getattr(event, 'resource_status') + + is_stack_event = stack_id == phys_id + if is_stack_event: + # this is an event for a stack + self.id_to_res_info[stack_id] = (stack_id, res_name) + elif phys_id and status == 'CREATE_IN_PROGRESS': + # this might be an event for a resource which creates a stack + self.id_to_res_info[phys_id] = (stack_id, res_name) + + # Now build this resource path based on previous calls to + # build_resource_name + resource_path = [] + if res_name and not is_stack_event: + resource_path.append(res_name) + self.prepend_paths(resource_path, stack_id) + + return '.'.join(resource_path) + + +def event_log_formatter(events, event_log_context=None): """Return the events in log format.""" event_log = [] log_format = ("%(event_time)s " "[%(rsrc_name)s]: %(rsrc_status)s %(rsrc_status_reason)s") + + # It is preferable for a context to be passed in, but there might be enough + # events in this call to build a better resource name, so create a context + # anyway + if event_log_context is None: + event_log_context = EventLogContext() + for event in events: + rsrc_name = event_log_context.build_resource_name(event) + event_time = getattr(event, 'event_time', '') log = log_format % { 'event_time': event_time.replace('T', ' '), - 'rsrc_name': getattr(event, 'resource_name', ''), + 'rsrc_name': rsrc_name, 'rsrc_status': getattr(event, 'resource_status', ''), 'rsrc_status_reason': getattr(event, 'resource_status_reason', '') } diff --git a/heatclient/openstack/common/apiclient/base.py b/heatclient/openstack/common/apiclient/base.py index 0a99ab2..3e68528 100644 --- a/heatclient/openstack/common/apiclient/base.py +++ b/heatclient/openstack/common/apiclient/base.py @@ -286,7 +286,7 @@ class CrudManager(BaseManager): {}, {}]}`). - `key`: Usually a singular noun by convention (e.g. `entity`); used to refer to an individual member of the collection. - + """ collection_key = None key = None @@ -446,7 +446,7 @@ class Resource(object): This is pretty much just a bag for attributes. """ - + HUMAN_ID = False NAME_ATTR = 'name' diff --git a/heatclient/openstack/common/apiclient/client.py b/heatclient/openstack/common/apiclient/client.py index 24c6e73..8733772 100644 --- a/heatclient/openstack/common/apiclient/client.py +++ b/heatclient/openstack/common/apiclient/client.py @@ -145,13 +145,10 @@ class HTTPClient(object): resp.text) def serialize(self, kwargs): - if kwargs.get('json') is not None: + json_data = kwargs.pop('json', None) + if json_data is not None: kwargs['headers']['Content-Type'] = 'application/json' - kwargs['data'] = json.dumps(kwargs['json']) - try: - del kwargs['json'] - except KeyError: - pass + kwargs['data'] = json.dumps(json_data) def get_timings(self): return self.times diff --git a/heatclient/osc/v1/event.py b/heatclient/osc/v1/event.py index 870726c..4c6e4e0 100644 --- a/heatclient/osc/v1/event.py +++ b/heatclient/osc/v1/event.py @@ -177,6 +177,7 @@ class ListEvent(command.Lister): marker = parsed_args.marker try: + event_log_context = heat_utils.EventLogContext() while True: events = event_utils.get_events( client, @@ -186,7 +187,8 @@ class ListEvent(command.Lister): marker=marker) if events: marker = getattr(events[-1], 'id', None) - events_log = heat_utils.event_log_formatter(events) + events_log = heat_utils.event_log_formatter( + events, event_log_context) self.app.stdout.write(events_log) self.app.stdout.write('\n') time.sleep(5) diff --git a/heatclient/tests/unit/__init__.py b/heatclient/tests/unit/__init__.py index e69de29..b1967c8 100644 --- a/heatclient/tests/unit/__init__.py +++ b/heatclient/tests/unit/__init__.py @@ -0,0 +1,5 @@ +import sys + +from mox3 import mox + +sys.modules['mox'] = mox diff --git a/heatclient/tests/unit/osc/v1/test_template.py b/heatclient/tests/unit/osc/v1/test_template.py index c69637d..895f628 100644 --- a/heatclient/tests/unit/osc/v1/test_template.py +++ b/heatclient/tests/unit/osc/v1/test_template.py @@ -117,7 +117,7 @@ class TestTemplateValidate(TestTemplate): self.assertEqual(1, self.stack_client.validate.call_count) args = self.stack_client.validate.call_args[1] self.assertEqual(args.get('environment'), {'parameters': {}}) - self.assertTrue(self.env_path in args.get('environment_files')[0]) + self.assertIn(self.env_path, args.get('environment_files')[0]) self.assertEqual([], columns) self.assertEqual([], data) diff --git a/heatclient/tests/unit/test_common_http.py b/heatclient/tests/unit/test_common_http.py index 3636585..9ccc24a 100644 --- a/heatclient/tests/unit/test_common_http.py +++ b/heatclient/tests/unit/test_common_http.py @@ -18,7 +18,7 @@ import socket from keystoneauth1 import adapter import mock -from mox3 import mox +import mox from oslo_serialization import jsonutils import requests import six diff --git a/heatclient/tests/unit/test_environment_format.py b/heatclient/tests/unit/test_environment_format.py index d0614b2..905c910 100644 --- a/heatclient/tests/unit/test_environment_format.py +++ b/heatclient/tests/unit/test_environment_format.py @@ -27,15 +27,31 @@ class YamlEnvironmentTest(testtools.TestCase): yaml1 = '' yaml2 = ''' parameter_defaults: {} +encrypted_param_names: [] parameters: {} resource_registry: {} -event_sinks: {} +event_sinks: [] ''' tpl1 = environment_format.parse(yaml1) environment_format.default_for_missing(tpl1) tpl2 = environment_format.parse(yaml2) self.assertEqual(tpl2, tpl1) + def test_param_valid_strategy_section(self): + yaml1 = '' + yaml2 = ''' +parameters: {} +encrypted_param_names: [] +parameter_defaults: {} +parameter_merge_strategies: {} +event_sinks: [] +resource_registry: {} +''' + tpl1 = environment_format.parse(yaml1) + environment_format.default_for_missing(tpl1) + tpl2 = environment_format.parse(yaml2) + self.assertNotEqual(tpl1, tpl2) + def test_wrong_sections(self): env = ''' parameters: {} diff --git a/heatclient/tests/unit/test_events.py b/heatclient/tests/unit/test_events.py index 584f713..f6071a5 100644 --- a/heatclient/tests/unit/test_events.py +++ b/heatclient/tests/unit/test_events.py @@ -13,7 +13,7 @@ # under the License. import mock -from mox3 import mox +import mox import testtools from heatclient.common import utils diff --git a/heatclient/tests/unit/test_resources.py b/heatclient/tests/unit/test_resources.py index d5200e3..b3c5c30 100644 --- a/heatclient/tests/unit/test_resources.py +++ b/heatclient/tests/unit/test_resources.py @@ -12,7 +12,7 @@ # License for the specific language governing permissions and limitations # under the License. -from mox3 import mox +import mox from six.moves.urllib import parse import testtools diff --git a/heatclient/tests/unit/test_shell.py b/heatclient/tests/unit/test_shell.py index 7071363..f88f7fc 100644 --- a/heatclient/tests/unit/test_shell.py +++ b/heatclient/tests/unit/test_shell.py @@ -19,7 +19,7 @@ import uuid import fixtures from keystoneauth1 import fixture as keystone_fixture import mock -from mox3 import mox +import mox from oslo_serialization import jsonutils from oslo_utils import encodeutils from oslotest import mockpatch diff --git a/heatclient/tests/unit/test_template_utils.py b/heatclient/tests/unit/test_template_utils.py index 6440af2..7de72b5 100644 --- a/heatclient/tests/unit/test_template_utils.py +++ b/heatclient/tests/unit/test_template_utils.py @@ -15,7 +15,7 @@ import base64 import json import tempfile -from mox3 import mox +import mox import six from six.moves.urllib import error from six.moves.urllib import request @@ -411,7 +411,7 @@ class ShellEnvironmentTest(testtools.TestCase): files['file:///home/b/a.yaml']) self.assertEqual(['file:///home/my/dir/env1.yaml'], env_file_list) - self.assertTrue('file:///home/my/dir/env1.yaml' in files) + self.assertIn('file:///home/my/dir/env1.yaml', files) self.assertEqual(expected_env, json.loads(files['file:///home/my/dir/env1.yaml'])) diff --git a/heatclient/tests/unit/test_utils.py b/heatclient/tests/unit/test_utils.py index a58dc22..3491816 100644 --- a/heatclient/tests/unit/test_utils.py +++ b/heatclient/tests/unit/test_utils.py @@ -191,6 +191,148 @@ class ShellTest(testtools.TestCase): self.assertEqual(expected, utils.event_log_formatter(events_list)) self.assertEqual('', utils.event_log_formatter([])) + def test_event_log_formatter_resource_path_old_heat(self): + + events = [{ + 'resource_name': 'nested', + 'event_time': '2016-09-05T04:10:24Z', + 'links': [{ + 'href': 'http://192.0.2.1:8004/v1/t/stacks/' + 'nested/1bed5d4d-41d6-4451-b274-c073ebee375d', + 'rel': 'stack' + }], + 'logical_resource_id': 'nested', + 'resource_status': 'CREATE_IN_PROGRESS', + 'resource_status_reason': 'Stack CREATE started', + 'physical_resource_id': '1bed5d4d-41d6-4451-b274-c073ebee375d', + }, { + 'resource_name': 'rg1', + 'event_time': '2016-09-05T04:10:24Z', + 'links': [{ + 'href': 'http://192.0.2.1:8004/v1/t/stacks/' + 'nested/1bed5d4d-41d6-4451-b274-c073ebee375d', + 'rel': 'stack' + }], + 'logical_resource_id': 'rg1', + 'resource_status': 'CREATE_IN_PROGRESS', + 'resource_status_reason': 'state changed', + 'physical_resource_id': None, # note the None from old heat + 'id': '375c49ae-cefb-4fb3-8f4d-1d5f1b9e3e5d' + }, { + 'resource_name': 'nested-rg1-m4zxcs4pra6t', + 'event_time': '2016-09-05T04:10:24Z', + 'links': [{ + 'href': 'http://192.0.2.1:8004/v1/t/stacks/' + 'nested-rg1-m4zxcs4pra6t/' + '3400bbad-a825-4226-ac23-c607846420db', + 'rel': 'stack' + }], + 'logical_resource_id': 'nested-rg1-m4zxcs4pra6t', + 'resource_status': 'CREATE_IN_PROGRESS', + 'resource_status_reason': 'Stack CREATE started', + 'physical_resource_id': '3400bbad-a825-4226-ac23-c607846420db', + 'id': '7e521c84-cd35-4f4c-b0de-962bd3cc40a8' + }, { + 'resource_name': '1', + 'event_time': '2016-09-05T04:10:24Z', + 'links': [{ + 'href': 'http://192.0.2.1:8004/v1/t/stacks/' + 'nested-rg1-m4zxcs4pra6t/' + '3400bbad-a825-4226-ac23-c607846420db', + 'rel': 'stack' + }], + 'logical_resource_id': '1', + 'resource_status': 'CREATE_IN_PROGRESS', + 'resource_status_reason': 'state changed', + 'physical_resource_id': None, # note the None from old heat + 'id': 'c6186c16-94ef-4214-a11a-7e3cc8a17f82' + }] + + events_list = [hc_res.Resource(manager=None, info=event) + for event in events] + + expected = '''\ +2016-09-05 04:10:24Z [nested]: \ +CREATE_IN_PROGRESS Stack CREATE started +2016-09-05 04:10:24Z [nested.rg1]: \ +CREATE_IN_PROGRESS state changed +2016-09-05 04:10:24Z [nested-rg1-m4zxcs4pra6t]: \ +CREATE_IN_PROGRESS Stack CREATE started +2016-09-05 04:10:24Z [nested-rg1-m4zxcs4pra6t.1]: \ +CREATE_IN_PROGRESS state changed''' + self.assertEqual(expected, utils.event_log_formatter(events_list)) + + def test_event_log_formatter_resource_path(self): + + events = [{ + 'resource_name': 'nested', + 'event_time': '2016-09-05T04:10:24Z', + 'links': [{ + 'href': 'http://192.0.2.1:8004/v1/t/stacks/' + 'nested/1bed5d4d-41d6-4451-b274-c073ebee375d', + 'rel': 'stack' + }], + 'logical_resource_id': 'nested', + 'resource_status': 'CREATE_IN_PROGRESS', + 'resource_status_reason': 'Stack CREATE started', + 'physical_resource_id': '1bed5d4d-41d6-4451-b274-c073ebee375d', + }, { + 'resource_name': 'rg1', + 'event_time': '2016-09-05T04:10:24Z', + 'links': [{ + 'href': 'http://192.0.2.1:8004/v1/t/stacks/' + 'nested/1bed5d4d-41d6-4451-b274-c073ebee375d', + 'rel': 'stack' + }], + 'logical_resource_id': 'rg1', + 'resource_status': 'CREATE_IN_PROGRESS', + 'resource_status_reason': 'state changed', + 'physical_resource_id': 'nested-rg1-m4zxcs4pra6t', + 'id': '375c49ae-cefb-4fb3-8f4d-1d5f1b9e3e5d' + }, { + 'resource_name': 'nested-rg1-m4zxcs4pra6t', + 'event_time': '2016-09-05T04:10:24Z', + 'links': [{ + 'href': 'http://192.0.2.1:8004/v1/t/stacks/' + 'nested-rg1-m4zxcs4pra6t/' + '3400bbad-a825-4226-ac23-c607846420db', + 'rel': 'stack' + }], + 'logical_resource_id': 'nested-rg1-m4zxcs4pra6t', + 'resource_status': 'CREATE_IN_PROGRESS', + 'resource_status_reason': 'Stack CREATE started', + 'physical_resource_id': '3400bbad-a825-4226-ac23-c607846420db', + 'id': '7e521c84-cd35-4f4c-b0de-962bd3cc40a8' + }, { + 'resource_name': '1', + 'event_time': '2016-09-05T04:10:24Z', + 'links': [{ + 'href': 'http://192.0.2.1:8004/v1/t/stacks/' + 'nested-rg1-m4zxcs4pra6t/' + '3400bbad-a825-4226-ac23-c607846420db', + 'rel': 'stack' + }], + 'logical_resource_id': '1', + 'resource_status': 'CREATE_IN_PROGRESS', + 'resource_status_reason': 'state changed', + 'physical_resource_id': 'nested-rg1-m4zxcs4pra6t-1-z6sgpq54n6e7', + 'id': 'c6186c16-94ef-4214-a11a-7e3cc8a17f82' + }] + + events_list = [hc_res.Resource(manager=None, info=event) + for event in events] + + expected = '''\ +2016-09-05 04:10:24Z [nested]: \ +CREATE_IN_PROGRESS Stack CREATE started +2016-09-05 04:10:24Z [nested.rg1]: \ +CREATE_IN_PROGRESS state changed +2016-09-05 04:10:24Z [nested.rg1]: \ +CREATE_IN_PROGRESS Stack CREATE started +2016-09-05 04:10:24Z [nested.rg1.1]: \ +CREATE_IN_PROGRESS state changed''' + self.assertEqual(expected, utils.event_log_formatter(events_list)) + class ShellTestParameterFiles(testtools.TestCase): diff --git a/heatclient/v1/shell.py b/heatclient/v1/shell.py index 76d40a4..ac4ecb9 100644 --- a/heatclient/v1/shell.py +++ b/heatclient/v1/shell.py @@ -417,7 +417,7 @@ def do_action_check(hc, args): @utils.arg('id', metavar='<NAME or ID>', help=_('Name or ID of stack to describe.')) @utils.arg('--no-resolve-outputs', action="store_true", - help='Do not resolve outputs of the stack.') + help=_('Do not resolve outputs of the stack.')) def do_stack_show(hc, args): '''Describe the stack.''' show_deprecated('heat stack-show', 'openstack stack show') @@ -462,10 +462,10 @@ def do_stack_show(hc, args): 'updated.') % {'true': strutils.TRUE_STRINGS, 'false': strutils.FALSE_STRINGS}) @utils.arg('-y', '--dry-run', default=False, action="store_true", - help='Do not actually perform the stack update, but show what ' - 'would be changed') + help=_('Do not actually perform the stack update, but show what ' + 'would be changed')) @utils.arg('-n', '--show-nested', default=False, action="store_true", - help='Show nested stacks when performing --dry-run') + help=_('Show nested stacks when performing --dry-run')) @utils.arg('-P', '--parameters', metavar='<KEY1=VALUE1;KEY2=VALUE2...>', help=_('Parameter values used to create the stack. ' 'This can be specified multiple times, or once with ' |