summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2016-09-21 02:33:51 +0000
committerGerrit Code Review <review@openstack.org>2016-09-21 02:33:51 +0000
commit0493eb18a3db76413e23cc96b6f35b31a94faff5 (patch)
treea6b05574e9f98325a4547855b66fb04a8bf832b2
parentc5ae32382d38462e3c299399169b8557aaa3db95 (diff)
parent00a757eea109f5e21d7cd85ad2f09cdb9ddae94f (diff)
downloadpython-heatclient-0493eb18a3db76413e23cc96b6f35b31a94faff5.tar.gz
Merge "Update .gitreview for stable/newton" into stable/newton
-rw-r--r--heatclient/common/deployment_utils.py4
-rw-r--r--heatclient/common/environment_format.py16
-rw-r--r--heatclient/common/event_utils.py3
-rw-r--r--heatclient/common/utils.py72
-rw-r--r--heatclient/openstack/common/apiclient/base.py4
-rw-r--r--heatclient/openstack/common/apiclient/client.py9
-rw-r--r--heatclient/osc/v1/event.py4
-rw-r--r--heatclient/tests/unit/__init__.py5
-rw-r--r--heatclient/tests/unit/osc/v1/test_template.py2
-rw-r--r--heatclient/tests/unit/test_common_http.py2
-rw-r--r--heatclient/tests/unit/test_environment_format.py18
-rw-r--r--heatclient/tests/unit/test_events.py2
-rw-r--r--heatclient/tests/unit/test_resources.py2
-rw-r--r--heatclient/tests/unit/test_shell.py2
-rw-r--r--heatclient/tests/unit/test_template_utils.py4
-rw-r--r--heatclient/tests/unit/test_utils.py142
-rw-r--r--heatclient/v1/shell.py8
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 '