Support modification of non string properties

Support modification of non string properties.  Introduced
the concept of types to the AnsibleProperty object and when
a property is set if the type is not str or None then
the value will be loaded via yaml and processed into the
appropriate python type.  At write time it is then written
out via yaml dump rather than always writing it out as a
string.

Change-Id: Iab1d10430cb919cf968e4357c93e23ed360bf338
Jira-Issue: OPENSTACK-1698
This commit is contained in:
Borne Mace 2017-11-28 21:52:47 -08:00
parent c8a5730220
commit 3d47927ad3
6 changed files with 55 additions and 41 deletions

View File

@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import logging import logging
import yaml
import kollacli.i18n as u import kollacli.i18n as u
@ -44,21 +45,29 @@ class PropertyApi(object):
:type change_set: list of strings :type change_set: list of strings
""" """
ansible_properties = AnsibleProperties()
for key, value in property_dict.items(): for key, value in property_dict.items():
check_arg(key, u._('Property Key'), str) check_arg(key, u._('Property Key'), str)
current_property = ansible_properties.get_property(key)
if current_property is not None:
current_property_type = current_property.value_type
if (current_property_type is not str and
current_property is not None):
value = yaml.safe_load(value)
check_arg(value, u._('Property Value'),
current_property_type, empty_ok=True)
property_dict[key] = value
else:
check_arg(value, u._('Property Value'), str, empty_ok=True) check_arg(value, u._('Property Value'), str, empty_ok=True)
if '"' in value: if type(value) is str and '"' in value:
raise InvalidArgument(u._('Cannot use double quotes in ' raise InvalidArgument(u._('Cannot use double quotes in '
'a property value.')) 'a property value.'))
property_dict = safe_decode(property_dict)
self._check_type(property_type) self._check_type(property_type)
if property_type is not GLOBAL_TYPE: if property_type is not GLOBAL_TYPE:
check_arg(change_set, u._('Change Set'), list, none_ok=True) check_arg(change_set, u._('Change Set'), list, none_ok=True)
change_set = safe_decode(change_set) change_set = safe_decode(change_set)
ansible_properties = AnsibleProperties()
if property_type == GLOBAL_TYPE: if property_type == GLOBAL_TYPE:
ansible_properties.set_property(property_dict) ansible_properties.set_property(property_dict)
elif property_type == GROUP_TYPE: elif property_type == GROUP_TYPE:
@ -142,7 +151,7 @@ class Property(object):
Members: Members:
- name (str): key - name (str): key
- value (str): value - value (Any): value
- file_name (str): name of file property is from - file_name (str): name of file property is from
- overrides (bool): does the property override some other value - overrides (bool): does the property override some other value
- orig_value (str): the value which is overridden or None - orig_value (str): the value which is overridden or None
@ -151,6 +160,7 @@ class Property(object):
- ovr_global (bool): true if property is overridden at global level - ovr_global (bool): true if property is overridden at global level
- ovr_group (bool): true if property is overridden at group level - ovr_group (bool): true if property is overridden at group level
- ovr_host (bool): true if property is overridden at host level - ovr_host (bool): true if property is overridden at host level
- value_type (type): the python type of the value
""" """
def __init__(self, ansible_property, override_flags): def __init__(self, ansible_property, override_flags):
@ -161,6 +171,7 @@ class Property(object):
self.orig_value = ansible_property.orig_value self.orig_value = ansible_property.orig_value
self.target = ansible_property.target self.target = ansible_property.target
self.prop_type = ansible_property.prop_type self.prop_type = ansible_property.prop_type
self.value_type = ansible_property.value_type
if override_flags is not None: if override_flags is not None:
self.ovr_global = override_flags.ovr_global self.ovr_global = override_flags.ovr_global

View File

@ -219,8 +219,9 @@ def _run_deploy_rules(playbook):
expected_files = ['account.ring.gz', expected_files = ['account.ring.gz',
'container.ring.gz', 'container.ring.gz',
'object.ring.gz'] 'object.ring.gz']
is_enabled = properties.get_property('enable_swift') is_swift_enabled = _is_service_enabled('swift', inventory, properties)
if is_string_true(is_enabled):
if is_swift_enabled:
path_pre = os.path.join(get_kolla_etc(), 'config', 'swift') path_pre = os.path.join(get_kolla_etc(), 'config', 'swift')
for expected_file in expected_files: for expected_file in expected_files:
path = os.path.join(path_pre, expected_file) path = os.path.join(path_pre, expected_file)
@ -235,15 +236,10 @@ def _run_deploy_rules(playbook):
def _is_service_enabled(servicename, inventory, properties): def _is_service_enabled(servicename, inventory, properties):
service_enabled = False
service = inventory.get_service(servicename) service = inventory.get_service(servicename)
if service is not None: if service is not None:
enabled_property = 'enable_' + servicename.replace('-', '_') enabled_property = 'enable_' + servicename.replace('-', '_')
is_enabled = properties.get_property(enabled_property) is_enabled = properties.get_property_value(enabled_property)
if is_string_true(is_enabled): if type(is_enabled) is str:
service_enabled = True is_enabled = is_string_true(is_enabled)
else: return is_enabled
service_enabled = False
return service_enabled

View File

@ -14,7 +14,6 @@
import copy import copy
import logging import logging
import os import os
import six
import yaml import yaml
import kollacli.i18n as u import kollacli.i18n as u
@ -220,7 +219,7 @@ class AnsibleProperties(object):
prop_list += self.group_props[group.name] prop_list += self.group_props[group.name]
return prop_list return prop_list
def get_property(self, property_name): def get_property_value(self, property_name):
self._load_properties() self._load_properties()
prop_val = None prop_val = None
if property_name in self.unique_global_props: if property_name in self.unique_global_props:
@ -228,6 +227,10 @@ class AnsibleProperties(object):
prop_val = prop.value prop_val = prop.value
return prop_val return prop_val
def get_property(self, property_name):
self._load_properties()
return self.unique_global_props.get(property_name)
def get_all_unique(self): def get_all_unique(self):
self._load_properties() self._load_properties()
unique_list = [] unique_list = []
@ -239,21 +242,6 @@ class AnsibleProperties(object):
self._load_properties() self._load_properties()
return self.unique_override_flags return self.unique_override_flags
# TODO(bmace) -- if this isn't used for 2.1.x it should be removed
# property listing is still being tweaked so leaving for
# the time being in case we want to use it
def filter_jinja2(self, contents):
new_contents = {}
for key, value in contents.items():
if not isinstance(value, six.string_types):
LOG.debug('removing non-string: %s', value)
continue
if value and '{{' in value and '}}' in value:
LOG.debug('removing jinja2 value: %s', value)
continue
new_contents[key] = value
return new_contents
def set_property(self, property_dict): def set_property(self, property_dict):
change_property(self.globals_path, property_dict, change_property(self.globals_path, property_dict,
clear=False) clear=False)
@ -365,6 +353,7 @@ class AnsibleProperty(object):
self.overrides = overrides self.overrides = overrides
self.orig_value = orig_value self.orig_value = orig_value
self.target = target self.target = target
self.value_type = type(value)
class OverrideFlags(object): class OverrideFlags(object):

View File

@ -62,9 +62,9 @@ class HostLogs(object):
ansible_properties = AnsibleProperties() ansible_properties = AnsibleProperties()
base_distro = \ base_distro = \
ansible_properties.get_property('kolla_base_distro') ansible_properties.get_property_value('kolla_base_distro')
install_type = \ install_type = \
ansible_properties.get_property('kolla_install_type') ansible_properties.get_property_value('kolla_install_type')
# typically this prefix will be "ol-openstack-" # typically this prefix will be "ol-openstack-"
container_prefix = base_distro + '-' + install_type + '-' container_prefix = base_distro + '-' + install_type + '-'

View File

@ -286,7 +286,13 @@ def change_property(file_path, property_dict, clear=False):
# clear existing property # clear existing property
continue continue
# edit existing property # edit existing property
line = '%s: "%s"' % (split_key, cloned_dict[split_key]) value = cloned_dict[split_key]
if type(value) is not str:
value = yaml.safe_dump(value).strip()
line = '%s: %s' % (split_key, value)
else:
line = '%s: "%s"' % (split_key, value)
# clear out the key after we are done, all existing keys # clear out the key after we are done, all existing keys
# will be appended at the end (or for clear, ignored) # will be appended at the end (or for clear, ignored)
del cloned_dict[split_key] del cloned_dict[split_key]
@ -294,10 +300,22 @@ def change_property(file_path, property_dict, clear=False):
if not clear: if not clear:
# add new properties to file # add new properties to file
for key, value in cloned_dict.items(): for key, value in cloned_dict.items():
if type(value) is not str:
value = yaml.safe_dump(value).strip()
line = '%s: %s' % (key, value)
else:
line = '%s: "%s"' % (key, value) line = '%s: "%s"' % (key, value)
# when we are doing an append we want to avoid
# blank lines before the new entry
if new_contents[-1:][0] == '':
del new_contents[-1]
new_contents.append(line) new_contents.append(line)
write_data = '\n'.join(new_contents) # if the last line is blank, trim it off
if new_contents[-1:][0] == '':
del new_contents[-1]
write_data = '\n'.join(new_contents) + '\n'
sync_write_file(file_path, write_data) sync_write_file(file_path, write_data)

View File

@ -195,8 +195,8 @@ class TestFunctional(KollaCliTest):
bad_path = self._is_size_ok(sizes, 0, '=', 3) bad_path = self._is_size_ok(sizes, 0, '=', 3)
self.assertIsNone(bad_path, 'Size of file %s is ' % bad_path + self.assertIsNone(bad_path, 'Size of file %s is ' % bad_path +
'different from initial size ' 'different from initial size '
'(%s %s)' '(%s %s %s)'
% (switch, targets_csv)) % (switch, targets_csv, str(sizes)))
# test setting empty string # test setting empty string
value = '""' value = '""'