Overridable safety (#53458)
* create overridable sanitation function * now used in aws, gce and azure plugins * added new option to these plugins to work in conjunction with general toggle to make it easier to emulate inventory script behavior.
This commit is contained in:
parent
e9f9bcae6a
commit
3e52a6a693
5 changed files with 88 additions and 12 deletions
3
changelogs/fragments/allow_bad_things.yml
Normal file
3
changelogs/fragments/allow_bad_things.yml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
minor_changes:
|
||||||
|
- Embed an overridable static sanitization method into base inventory plugin class to allow individual plugins to optionally override
|
||||||
|
Add override implementation to inital set of cloud plugins
|
|
@ -150,6 +150,7 @@ class BaseInventoryPlugin(AnsiblePlugin):
|
||||||
""" Parses an Inventory Source"""
|
""" Parses an Inventory Source"""
|
||||||
|
|
||||||
TYPE = 'generator'
|
TYPE = 'generator'
|
||||||
|
_sanitize_group_name = staticmethod(to_safe_group_name)
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
|
@ -371,7 +372,7 @@ class Constructable(object):
|
||||||
self.templar.set_available_variables(variables)
|
self.templar.set_available_variables(variables)
|
||||||
for group_name in groups:
|
for group_name in groups:
|
||||||
conditional = "{%% if %s %%} True {%% else %%} False {%% endif %%}" % groups[group_name]
|
conditional = "{%% if %s %%} True {%% else %%} False {%% endif %%}" % groups[group_name]
|
||||||
group_name = to_safe_group_name(group_name)
|
group_name = self._sanitize_group_name(group_name)
|
||||||
try:
|
try:
|
||||||
result = boolean(self.templar.template(conditional))
|
result = boolean(self.templar.template(conditional))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -380,7 +381,7 @@ class Constructable(object):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if result:
|
if result:
|
||||||
# ensure group exists, use sanatized name
|
# ensure group exists, use sanitized name
|
||||||
group_name = self.inventory.add_group(group_name)
|
group_name = self.inventory.add_group(group_name)
|
||||||
# add host to group
|
# add host to group
|
||||||
self.inventory.add_child(group_name, host)
|
self.inventory.add_child(group_name, host)
|
||||||
|
@ -418,12 +419,12 @@ class Constructable(object):
|
||||||
raise AnsibleParserError("Invalid group name format, expected a string or a list of them or dictionary, got: %s" % type(key))
|
raise AnsibleParserError("Invalid group name format, expected a string or a list of them or dictionary, got: %s" % type(key))
|
||||||
|
|
||||||
for bare_name in new_raw_group_names:
|
for bare_name in new_raw_group_names:
|
||||||
gname = to_safe_group_name('%s%s%s' % (prefix, sep, bare_name))
|
gname = self._sanitize_group_name('%s%s%s' % (prefix, sep, bare_name))
|
||||||
self.inventory.add_group(gname)
|
self.inventory.add_group(gname)
|
||||||
self.inventory.add_child(gname, host)
|
self.inventory.add_child(gname, host)
|
||||||
|
|
||||||
if raw_parent_name:
|
if raw_parent_name:
|
||||||
parent_name = to_safe_group_name(raw_parent_name)
|
parent_name = self._sanitize_group_name(raw_parent_name)
|
||||||
self.inventory.add_group(parent_name)
|
self.inventory.add_group(parent_name)
|
||||||
self.inventory.add_child(parent_name, gname)
|
self.inventory.add_child(parent_name, gname)
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,20 @@ DOCUMENTATION = '''
|
||||||
False in the inventory config file which will allow 403 errors to be gracefully skipped.
|
False in the inventory config file which will allow 403 errors to be gracefully skipped.
|
||||||
type: bool
|
type: bool
|
||||||
default: True
|
default: True
|
||||||
|
use_contrib_script_compatible_sanitization:
|
||||||
|
description:
|
||||||
|
- By default this plugin is using a general group name sanitization to create safe and usable group names for use in Ansible.
|
||||||
|
This option allows you to override that, in efforts to allow migration from the old inventory script and
|
||||||
|
matches the sanitization of groups when the script's ``replace_dash_in_groups`` option is set to ``False``.
|
||||||
|
To replicate behavior of ``replace_dash_in_groups = True`` with constructed groups,
|
||||||
|
you will need to replace hyphens with underscores via the regex_replace filter for those entries.
|
||||||
|
- For this to work you should also turn off the TRANSFORM_INVALID_GROUP_CHARS setting,
|
||||||
|
otherwise the core engine will just use the standard sanitization on top.
|
||||||
|
- This is not the default as such names break certain functionality as not all characters are valid Python identifiers
|
||||||
|
which group names end up being used as.
|
||||||
|
type: bool
|
||||||
|
default: False
|
||||||
|
version_added: '2.8'
|
||||||
'''
|
'''
|
||||||
|
|
||||||
EXAMPLES = '''
|
EXAMPLES = '''
|
||||||
|
@ -135,12 +149,13 @@ compose:
|
||||||
# (note: this does not modify inventory_hostname, which is set via I(hostnames))
|
# (note: this does not modify inventory_hostname, which is set via I(hostnames))
|
||||||
ansible_host: private_ip_address
|
ansible_host: private_ip_address
|
||||||
'''
|
'''
|
||||||
|
import re
|
||||||
|
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
from ansible.module_utils._text import to_native, to_text
|
from ansible.module_utils._text import to_native, to_text
|
||||||
from ansible.module_utils.ec2 import ansible_dict_to_boto3_filter_list, boto3_tag_list_to_ansible_dict
|
from ansible.module_utils.ec2 import ansible_dict_to_boto3_filter_list, boto3_tag_list_to_ansible_dict
|
||||||
from ansible.module_utils.ec2 import camel_dict_to_snake_dict
|
from ansible.module_utils.ec2 import camel_dict_to_snake_dict
|
||||||
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable, to_safe_group_name
|
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable
|
||||||
from ansible.utils.display import Display
|
from ansible.utils.display import Display
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -431,7 +446,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||||
break
|
break
|
||||||
if hostname:
|
if hostname:
|
||||||
if ':' in to_text(hostname):
|
if ':' in to_text(hostname):
|
||||||
return to_safe_group_name(to_text(hostname))
|
return self._sanitize_group_name((to_text(hostname)))
|
||||||
else:
|
else:
|
||||||
return to_text(hostname)
|
return to_text(hostname)
|
||||||
|
|
||||||
|
@ -518,9 +533,14 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def parse(self, inventory, loader, path, cache=True):
|
def parse(self, inventory, loader, path, cache=True):
|
||||||
|
|
||||||
super(InventoryModule, self).parse(inventory, loader, path)
|
super(InventoryModule, self).parse(inventory, loader, path)
|
||||||
|
|
||||||
config_data = self._read_config_data(path)
|
self._read_config_data(path)
|
||||||
|
|
||||||
|
if self.get_option('use_contrib_script_compatible_sanitization'):
|
||||||
|
self._sanitize_group_name = self._legacy_script_compatible_group_sanitization
|
||||||
|
|
||||||
self._set_credentials()
|
self._set_credentials()
|
||||||
|
|
||||||
# get user specifications
|
# get user specifications
|
||||||
|
@ -553,3 +573,11 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||||
# when the user is using caching, update the cached inventory
|
# when the user is using caching, update the cached inventory
|
||||||
if cache_needs_update or (not cache and self.get_option('cache')):
|
if cache_needs_update or (not cache and self.get_option('cache')):
|
||||||
self.cache.set(cache_key, results)
|
self.cache.set(cache_key, results)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _legacy_script_compatible_group_sanitization(name):
|
||||||
|
|
||||||
|
# note that while this mirrors what the script used to do, it has many issues with unicode and usability in python
|
||||||
|
regex = re.compile(r"[^A-Za-z0-9\_\-]")
|
||||||
|
|
||||||
|
return regex.sub('_', name)
|
||||||
|
|
|
@ -60,6 +60,20 @@ DOCUMENTATION = r'''
|
||||||
C(exclude_host_filters) to exclude powered-off and not-fully-provisioned hosts. Set this to a different
|
C(exclude_host_filters) to exclude powered-off and not-fully-provisioned hosts. Set this to a different
|
||||||
value or empty list if you need to include hosts in these states.
|
value or empty list if you need to include hosts in these states.
|
||||||
default: ['powerstate != "running"', 'provisioning_state != "succeeded"']
|
default: ['powerstate != "running"', 'provisioning_state != "succeeded"']
|
||||||
|
use_contrib_script_compatible_sanitization:
|
||||||
|
description:
|
||||||
|
- By default this plugin is using a general group name sanitization to create safe and usable group names for use in Ansible.
|
||||||
|
This option allows you to override that, in efforts to allow migration from the old inventory script and
|
||||||
|
matches the sanitization of groups when the script's ``replace_dash_in_groups`` option is set to ``False``.
|
||||||
|
To replicate behavior of ``replace_dash_in_groups = True`` with constructed groups,
|
||||||
|
you will need to replace hyphens with underscores via the regex_replace filter for those entries.
|
||||||
|
- For this to work you should also turn off the TRANSFORM_INVALID_GROUP_CHARS setting,
|
||||||
|
otherwise the core engine will just use the standard sanitization on top.
|
||||||
|
- This is not the default as such names break certain functionality as not all characters are valid Python identifiers
|
||||||
|
which group names end up being used as.
|
||||||
|
type: bool
|
||||||
|
default: False
|
||||||
|
version_added: '2.8'
|
||||||
'''
|
'''
|
||||||
|
|
||||||
EXAMPLES = '''
|
EXAMPLES = '''
|
||||||
|
@ -152,7 +166,7 @@ except ImportError:
|
||||||
|
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from ansible import release
|
from ansible import release
|
||||||
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable
|
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable
|
||||||
from ansible.module_utils.six import iteritems
|
from ansible.module_utils.six import iteritems
|
||||||
from ansible.module_utils.azure_rm_common import AzureRMAuth
|
from ansible.module_utils.azure_rm_common import AzureRMAuth
|
||||||
from ansible.errors import AnsibleParserError, AnsibleError
|
from ansible.errors import AnsibleParserError, AnsibleError
|
||||||
|
@ -227,6 +241,10 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
|
||||||
super(InventoryModule, self).parse(inventory, loader, path)
|
super(InventoryModule, self).parse(inventory, loader, path)
|
||||||
|
|
||||||
self._read_config_data(path)
|
self._read_config_data(path)
|
||||||
|
|
||||||
|
if self.get_option('use_contrib_script_compatible_sanitization'):
|
||||||
|
self._sanitize_group_name = self._legacy_script_compatible_group_sanitization
|
||||||
|
|
||||||
self._batch_fetch = self.get_option('batch_fetch')
|
self._batch_fetch = self.get_option('batch_fetch')
|
||||||
|
|
||||||
self._filters = self.get_option('exclude_host_filters') + self.get_option('default_host_filters')
|
self._filters = self.get_option('exclude_host_filters') + self.get_option('default_host_filters')
|
||||||
|
@ -234,7 +252,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
|
||||||
try:
|
try:
|
||||||
self._credential_setup()
|
self._credential_setup()
|
||||||
self._get_hosts()
|
self._get_hosts()
|
||||||
except Exception as ex:
|
except Exception:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def _credential_setup(self):
|
def _credential_setup(self):
|
||||||
|
@ -446,10 +464,18 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
|
||||||
|
|
||||||
return json.loads(content)
|
return json.loads(content)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _legacy_script_compatible_group_sanitization(name):
|
||||||
|
|
||||||
|
# note that while this mirrors what the script used to do, it has many issues with unicode and usability in python
|
||||||
|
regex = re.compile(r"[^A-Za-z0-9\_\-]")
|
||||||
|
|
||||||
|
return regex.sub('_', name)
|
||||||
|
|
||||||
# VM list (all, N resource groups): VM -> InstanceView, N NICs, N PublicIPAddress)
|
# VM list (all, N resource groups): VM -> InstanceView, N NICs, N PublicIPAddress)
|
||||||
# VMSS VMs (all SS, N specific SS, N resource groups?): SS -> VM -> InstanceView, N NICs, N PublicIPAddress)
|
# VMSS VMs (all SS, N specific SS, N resource groups?): SS -> VM -> InstanceView, N NICs, N PublicIPAddress)
|
||||||
|
|
||||||
|
|
||||||
class AzureHost(object):
|
class AzureHost(object):
|
||||||
_powerstate_regex = re.compile('^PowerState/(?P<powerstate>.+)$')
|
_powerstate_regex = re.compile('^PowerState/(?P<powerstate>.+)$')
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,17 @@ DOCUMENTATION = '''
|
||||||
vars_prefix:
|
vars_prefix:
|
||||||
description: prefix to apply to host variables, does not include facts nor params
|
description: prefix to apply to host variables, does not include facts nor params
|
||||||
default: ''
|
default: ''
|
||||||
|
use_contrib_script_compatible_sanitization:
|
||||||
|
description:
|
||||||
|
- By default this plugin is using a general group name sanitization to create safe and usable group names for use in Ansible.
|
||||||
|
This option allows you to override that, in efforts to allow migration from the old inventory script.
|
||||||
|
- For this to work you should also turn off the TRANSFORM_INVALID_GROUP_CHARS setting,
|
||||||
|
otherwise the core engine will just use the standard sanitization on top.
|
||||||
|
- This is not the default as such names break certain functionality as not all characters are valid Python identifiers
|
||||||
|
which group names end up being used as.
|
||||||
|
type: bool
|
||||||
|
default: False
|
||||||
|
version_added: '2.8'
|
||||||
'''
|
'''
|
||||||
|
|
||||||
EXAMPLES = '''
|
EXAMPLES = '''
|
||||||
|
@ -81,10 +92,9 @@ compose:
|
||||||
'''
|
'''
|
||||||
|
|
||||||
from ansible.errors import AnsibleError, AnsibleParserError
|
from ansible.errors import AnsibleError, AnsibleParserError
|
||||||
from ansible.module_utils._text import to_native, to_text
|
from ansible.module_utils._text import to_native
|
||||||
from ansible.module_utils.six import string_types
|
|
||||||
from ansible.module_utils.gcp_utils import GcpSession, navigate_hash, GcpRequestException
|
from ansible.module_utils.gcp_utils import GcpSession, navigate_hash, GcpRequestException
|
||||||
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable, to_safe_group_name
|
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
@ -325,6 +335,9 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||||
config_data = {}
|
config_data = {}
|
||||||
config_data = self._read_config_data(path)
|
config_data = self._read_config_data(path)
|
||||||
|
|
||||||
|
if self.get_option('use_contrib_script_compatible_sanitization'):
|
||||||
|
self._sanitize_group_name = self._legacy_script_compatible_group_sanitization
|
||||||
|
|
||||||
# get user specifications
|
# get user specifications
|
||||||
if 'zones' in config_data:
|
if 'zones' in config_data:
|
||||||
if not isinstance(config_data['zones'], list):
|
if not isinstance(config_data['zones'], list):
|
||||||
|
@ -380,3 +393,8 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||||
|
|
||||||
if cache_needs_update:
|
if cache_needs_update:
|
||||||
self.cache.set(cache_key, cached_data)
|
self.cache.set(cache_key, cached_data)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _legacy_script_compatible_group_sanitization(name):
|
||||||
|
|
||||||
|
return name
|
||||||
|
|
Loading…
Reference in a new issue