Consolidate boolean/mk_boolean conversion functions into a single location
Consolidate the module_utils, constants, and config functions that convert values into booleans into a single function in module_utils. Port code to use the module_utils.validate.convert_bool.boolean function isntead of mk_boolean.
This commit is contained in:
parent
f9c60e1a82
commit
ff22528b07
30 changed files with 433 additions and 102 deletions
|
@ -168,7 +168,8 @@ except ImportError:
|
|||
|
||||
from time import time
|
||||
|
||||
from ansible.constants import get_config, mk_boolean
|
||||
from ansible.constants import get_config
|
||||
from ansible.module_utils.parsing.convert_bool import boolean
|
||||
|
||||
|
||||
NON_CALLABLES = (basestring, bool, dict, int, list, type(None))
|
||||
|
@ -288,7 +289,7 @@ def _list_into_cache(regions):
|
|||
if not cbs_attachments[region]:
|
||||
cbs = pyrax.connect_to_cloud_blockstorage(region)
|
||||
for vol in cbs.list():
|
||||
if mk_boolean(vol.bootable):
|
||||
if boolean(vol.bootable, strict=False):
|
||||
for attachment in vol.attachments:
|
||||
metadata = vol.volume_image_metadata
|
||||
server_id = attachment['server_id']
|
||||
|
|
|
@ -41,6 +41,7 @@ from ansible.cli import CLI
|
|||
from ansible.errors import AnsibleError
|
||||
from ansible.executor.task_queue_manager import TaskQueueManager
|
||||
from ansible.module_utils._text import to_native, to_text
|
||||
from ansible.module_utils.parsing.convert_bool import boolean
|
||||
from ansible.parsing.splitter import parse_kv
|
||||
from ansible.playbook.play import Play
|
||||
from ansible.plugins import module_loader
|
||||
|
@ -295,7 +296,7 @@ class ConsoleCLI(CLI, cmd.Cmd):
|
|||
def do_become(self, arg):
|
||||
"""Toggle whether plays run with become"""
|
||||
if arg:
|
||||
self.options.become = C.mk_boolean(arg)
|
||||
self.options.become = boolean(arg, strict=False)
|
||||
display.v("become changed to %s" % self.options.become)
|
||||
self.set_prompt()
|
||||
else:
|
||||
|
@ -329,7 +330,7 @@ class ConsoleCLI(CLI, cmd.Cmd):
|
|||
def do_check(self, arg):
|
||||
"""Toggle whether plays run with check mode"""
|
||||
if arg:
|
||||
self.options.check = C.mk_boolean(arg)
|
||||
self.options.check = boolean(arg, strict=False)
|
||||
display.v("check mode changed to %s" % self.options.check)
|
||||
else:
|
||||
display.display("Please specify check mode value, e.g. `check yes`")
|
||||
|
@ -337,7 +338,7 @@ class ConsoleCLI(CLI, cmd.Cmd):
|
|||
def do_diff(self, arg):
|
||||
"""Toggle whether plays run with diff"""
|
||||
if arg:
|
||||
self.options.diff = C.mk_boolean(arg)
|
||||
self.options.diff = boolean(arg, strict=False)
|
||||
display.v("diff mode changed to %s" % self.options.diff)
|
||||
else:
|
||||
display.display("Please specify a diff value , e.g. `diff yes`")
|
||||
|
|
|
@ -25,8 +25,6 @@ Setting = namedtuple('Setting','name value origin')
|
|||
|
||||
class ConfigData(object):
|
||||
|
||||
BOOL_TRUE = frozenset(["true", "t", "y", "1", "yes", "on"])
|
||||
|
||||
def __init__(self):
|
||||
self._global_settings = {}
|
||||
self._plugins = {}
|
||||
|
|
|
@ -29,6 +29,7 @@ from ansible.errors import AnsibleOptionsError, AnsibleError
|
|||
from ansible.module_utils.six import string_types
|
||||
from ansible.module_utils.six.moves import configparser
|
||||
from ansible.module_utils._text import to_text, to_bytes, to_native
|
||||
from ansible.module_utils.parsing.convert_bool import boolean
|
||||
from ansible.parsing.quoting import unquote
|
||||
from ansible.utils.path import unfrackpath
|
||||
from ansible.utils.path import makedirs_safe
|
||||
|
@ -41,6 +42,7 @@ def resolve_path(path):
|
|||
|
||||
return unfrackpath(path, follow=False)
|
||||
|
||||
|
||||
def get_ini_config(p, entries):
|
||||
''' returns the value of last ini entry found '''
|
||||
value = None
|
||||
|
@ -54,7 +56,6 @@ def get_ini_config(p, entries):
|
|||
return value
|
||||
|
||||
|
||||
|
||||
class ConfigManager(object):
|
||||
|
||||
def __init__(self, conf_file=None):
|
||||
|
@ -179,14 +180,6 @@ class ConfigManager(object):
|
|||
|
||||
return path
|
||||
|
||||
def make_boolean(self, value):
|
||||
ret = value
|
||||
if not isinstance(value, bool):
|
||||
if value is None:
|
||||
ret = False
|
||||
ret = (to_text(value).lower() in self.data.BOOL_TRUE)
|
||||
return ret
|
||||
|
||||
def ensure_type(self, value, value_type):
|
||||
''' return a configuration variable with casting
|
||||
:arg value: The value to ensure correct typing of
|
||||
|
@ -205,7 +198,7 @@ class ConfigManager(object):
|
|||
each part for environment variables and tildes.
|
||||
'''
|
||||
if value_type == 'boolean':
|
||||
value = self.make_boolean(value)
|
||||
value = boolean(value, strict=False)
|
||||
|
||||
elif value:
|
||||
if value_type == 'integer':
|
||||
|
|
|
@ -22,6 +22,7 @@ __metaclass__ = type
|
|||
from string import ascii_letters, digits
|
||||
|
||||
from ansible.module_utils._text import to_text
|
||||
from ansible.module_utils.parsing.convert_bool import boolean, BOOLEANS_TRUE
|
||||
from ansible.config.manager import ConfigManager
|
||||
|
||||
_config = ConfigManager()
|
||||
|
@ -32,8 +33,14 @@ for setting in _config.data.get_settings():
|
|||
|
||||
|
||||
def mk_boolean(value):
|
||||
''' moved '''
|
||||
return _config.make_boolean(value)
|
||||
''' moved to module_utils'''
|
||||
try:
|
||||
from __main__ import display
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
display.deprecated('ansible.constants.mk_boolean() is deprecated. Use ansible.module_utils.parsing.convert_bool.boolean() instead', version='2.8')
|
||||
return boolean(value, strict=False)
|
||||
|
||||
|
||||
# ### CONSTANTS ### yes, actual ones
|
||||
|
@ -60,7 +67,7 @@ BECOME_MISSING_STRINGS = {
|
|||
'ksu': 'No password given',
|
||||
'pmrun': ''
|
||||
} # FIXME: deal with i18n
|
||||
BOOL_TRUE = _config.data.BOOL_TRUE
|
||||
BOOL_TRUE = BOOLEANS_TRUE
|
||||
DEFAULT_BECOME_PASS = None
|
||||
DEFAULT_PASSWORD_CHARS = to_text(ascii_letters + digits + ".,:-_", errors='strict') # characters included in auto-generated passwords
|
||||
DEFAULT_SUDO_PASS = None
|
||||
|
|
|
@ -23,14 +23,11 @@ import fnmatch
|
|||
|
||||
from ansible import constants as C
|
||||
from ansible.module_utils.six import iteritems
|
||||
from ansible.module_utils.parsing.convert_bool import boolean
|
||||
from ansible.playbook.block import Block
|
||||
from ansible.playbook.task import Task
|
||||
|
||||
|
||||
boolean = C.mk_boolean
|
||||
|
||||
__all__ = ['PlayIterator']
|
||||
|
||||
try:
|
||||
from __main__ import display
|
||||
except ImportError:
|
||||
|
@ -38,6 +35,9 @@ except ImportError:
|
|||
display = Display()
|
||||
|
||||
|
||||
__all__ = ['PlayIterator']
|
||||
|
||||
|
||||
class HostState:
|
||||
def __init__(self, blocks):
|
||||
self._blocks = blocks[:]
|
||||
|
@ -300,10 +300,10 @@ class PlayIterator:
|
|||
# NOT explicitly set gather_facts to False.
|
||||
|
||||
gathering = C.DEFAULT_GATHERING
|
||||
implied = self._play.gather_facts is None or boolean(self._play.gather_facts)
|
||||
implied = self._play.gather_facts is None or boolean(self._play.gather_facts, strict=False)
|
||||
|
||||
if (gathering == 'implicit' and implied) or \
|
||||
(gathering == 'explicit' and boolean(self._play.gather_facts)) or \
|
||||
(gathering == 'explicit' and boolean(self._play.gather_facts, strict=False)) or \
|
||||
(gathering == 'smart' and implied and not (self._variable_manager._fact_cache.get(host.name, {}).get('module_setup', False))):
|
||||
# The setup block is always self._blocks[0], as we inject it
|
||||
# during the play compilation in __init__ above.
|
||||
|
|
|
@ -28,10 +28,6 @@
|
|||
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
BOOLEANS_TRUE = ['y', 'yes', 'on', '1', 'true', 1, True]
|
||||
BOOLEANS_FALSE = ['n', 'no', 'off', '0', 'false', 0, False]
|
||||
BOOLEANS = BOOLEANS_TRUE + BOOLEANS_FALSE
|
||||
|
||||
SIZE_RANGES = {
|
||||
'Y': 1 << 80,
|
||||
'Z': 1 << 70,
|
||||
|
@ -178,6 +174,8 @@ from ansible.module_utils.six import (
|
|||
)
|
||||
from ansible.module_utils.six.moves import map, reduce, shlex_quote
|
||||
from ansible.module_utils._text import to_native, to_bytes, to_text
|
||||
from ansible.module_utils.parsing.convert_bool import BOOLEANS, BOOLEANS_FALSE, BOOLEANS_TRUE, boolean
|
||||
|
||||
|
||||
PASSWORD_MATCH = re.compile(r'^(?:.+[-_\s])?pass(?:[-_\s]?(?:word|phrase|wrd|wd)?)(?:[-_\s].+)?$', re.I)
|
||||
|
||||
|
@ -1658,8 +1656,7 @@ class AnsibleModule(object):
|
|||
lowered_choices = None
|
||||
if param[k] == 'False':
|
||||
lowered_choices = _lenient_lowercase(choices)
|
||||
FALSEY = frozenset(BOOLEANS_FALSE)
|
||||
overlap = FALSEY.intersection(choices)
|
||||
overlap = BOOLEANS_FALSE.intersection(choices)
|
||||
if len(overlap) == 1:
|
||||
# Extract from a set
|
||||
(param[k],) = overlap
|
||||
|
@ -1667,8 +1664,7 @@ class AnsibleModule(object):
|
|||
if param[k] == 'True':
|
||||
if lowered_choices is None:
|
||||
lowered_choices = _lenient_lowercase(choices)
|
||||
TRUTHY = frozenset(BOOLEANS_TRUE)
|
||||
overlap = TRUTHY.intersection(choices)
|
||||
overlap = BOOLEANS_TRUE.intersection(choices)
|
||||
if len(overlap) == 1:
|
||||
(param[k],) = overlap
|
||||
|
||||
|
@ -2045,16 +2041,13 @@ class AnsibleModule(object):
|
|||
|
||||
def boolean(self, arg):
|
||||
''' return a bool for the arg '''
|
||||
if arg is None or isinstance(arg, bool):
|
||||
if arg is None:
|
||||
return arg
|
||||
if isinstance(arg, string_types):
|
||||
arg = arg.lower()
|
||||
if arg in BOOLEANS_TRUE:
|
||||
return True
|
||||
elif arg in BOOLEANS_FALSE:
|
||||
return False
|
||||
else:
|
||||
self.fail_json(msg='%s is not a valid boolean. Valid booleans include: %s' % (to_text(arg), ','.join(['%s' % x for x in BOOLEANS])))
|
||||
|
||||
try:
|
||||
return boolean(arg)
|
||||
except TypeError as e:
|
||||
self.fail_json(msg=to_native(e))
|
||||
|
||||
def jsonify(self, data):
|
||||
for encoding in ("utf-8", "latin-1"):
|
||||
|
|
|
@ -23,8 +23,9 @@ import sys
|
|||
import copy
|
||||
from distutils.version import LooseVersion
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule, BOOLEANS_TRUE, BOOLEANS_FALSE
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.six.moves.urllib.parse import urlparse
|
||||
from ansible.module_utils.parsing.convert_bool import BOOLEANS_TRUE, BOOLEANS_FALSE
|
||||
|
||||
HAS_DOCKER_PY = True
|
||||
HAS_DOCKER_PY_2 = False
|
||||
|
|
|
@ -29,7 +29,7 @@ import re
|
|||
import shlex
|
||||
import time
|
||||
|
||||
from ansible.module_utils.basic import BOOLEANS_TRUE, BOOLEANS_FALSE, get_exception
|
||||
from ansible.module_utils.parsing.convert_bool import BOOLEANS_TRUE, BOOLEANS_FALSE
|
||||
from ansible.module_utils.six import string_types, text_type
|
||||
from ansible.module_utils.six.moves import zip
|
||||
|
||||
|
@ -163,8 +163,7 @@ class CommandRunner(object):
|
|||
def add_conditional(self, condition):
|
||||
try:
|
||||
self.conditionals.add(Conditional(condition))
|
||||
except AttributeError:
|
||||
exc = get_exception()
|
||||
except AttributeError as exc:
|
||||
raise AddConditionError(msg=str(exc), condition=condition)
|
||||
|
||||
def run(self):
|
||||
|
|
0
lib/ansible/module_utils/parsing/__init__.py
Normal file
0
lib/ansible/module_utils/parsing/__init__.py
Normal file
26
lib/ansible/module_utils/parsing/convert_bool.py
Normal file
26
lib/ansible/module_utils/parsing/convert_bool.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
# Copyright: 2017, Ansible Project
|
||||
# License: GNU General Public License v3 or later (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt )
|
||||
|
||||
from ansible.module_utils.six import binary_type, text_type
|
||||
from ansible.module_utils._text import to_text
|
||||
|
||||
|
||||
BOOLEANS_TRUE = frozenset(('y', 'yes', 'on', '1', 'true', 't', 1, 1.0, True))
|
||||
BOOLEANS_FALSE = frozenset(('n', 'no', 'off', '0', 'false', 'f', 0, 0.0, False))
|
||||
BOOLEANS = BOOLEANS_TRUE.union(BOOLEANS_FALSE)
|
||||
|
||||
|
||||
def boolean(value, strict=True):
|
||||
if isinstance(value, bool):
|
||||
return value
|
||||
|
||||
normalized_value = value
|
||||
if isinstance(value, (text_type, binary_type)):
|
||||
normalized_value = to_text(value, errors='surrogate_or_strict').lower()
|
||||
|
||||
if normalized_value in BOOLEANS_TRUE:
|
||||
return True
|
||||
elif normalized_value in BOOLEANS_FALSE or not strict:
|
||||
return False
|
||||
|
||||
raise TypeError('%s is not a valid boolean. Valid booleans include: %s' % (to_text(value), ', '.join(repr(i) for i in BOOLEANS)))
|
|
@ -32,7 +32,6 @@ import os
|
|||
import re
|
||||
from uuid import UUID
|
||||
|
||||
from ansible.module_utils.basic import BOOLEANS
|
||||
from ansible.module_utils.six import text_type, binary_type
|
||||
|
||||
FINAL_STATUSES = ('ACTIVE', 'ERROR')
|
||||
|
|
|
@ -28,8 +28,8 @@ from functools import partial
|
|||
from jinja2.exceptions import UndefinedError
|
||||
|
||||
from ansible import constants as C
|
||||
from ansible.constants import mk_boolean as boolean
|
||||
from ansible.module_utils.six import iteritems, string_types, with_metaclass
|
||||
from ansible.module_utils.parsing.convert_bool import boolean
|
||||
from ansible.errors import AnsibleParserError, AnsibleUndefinedVariable
|
||||
from ansible.module_utils._text import to_text
|
||||
from ansible.playbook.attribute import Attribute, FieldAttribute
|
||||
|
@ -388,7 +388,7 @@ class Base(with_metaclass(BaseMeta, object)):
|
|||
elif attribute.isa == 'float':
|
||||
value = float(value)
|
||||
elif attribute.isa == 'bool':
|
||||
value = boolean(value)
|
||||
value = boolean(value, strict=False)
|
||||
elif attribute.isa == 'percent':
|
||||
# special value, which may be an integer or float
|
||||
# with an optional '%' at the end
|
||||
|
|
|
@ -33,21 +33,21 @@ from ansible.errors import AnsibleError
|
|||
from ansible.module_utils.six import iteritems
|
||||
from ansible.module_utils.six.moves import shlex_quote
|
||||
from ansible.module_utils._text import to_bytes
|
||||
from ansible.module_utils.parsing.convert_bool import boolean
|
||||
from ansible.playbook.attribute import FieldAttribute
|
||||
from ansible.playbook.base import Base
|
||||
from ansible.utils.ssh_functions import check_for_controlpersist
|
||||
|
||||
|
||||
boolean = C.mk_boolean
|
||||
|
||||
__all__ = ['PlayContext']
|
||||
|
||||
try:
|
||||
from __main__ import display
|
||||
except ImportError:
|
||||
from ansible.utils.display import Display
|
||||
display = Display()
|
||||
|
||||
|
||||
__all__ = ['PlayContext']
|
||||
|
||||
# the magic variable mapping dictionary below is used to translate
|
||||
# host/inventory variables to fields in the PlayContext
|
||||
# object. The dictionary values are tuples, to account for aliases
|
||||
|
@ -289,7 +289,7 @@ class PlayContext(Base):
|
|||
self.become_method = options.become_method
|
||||
self.become_user = options.become_user
|
||||
|
||||
self.check_mode = boolean(options.check)
|
||||
self.check_mode = boolean(options.check, strict=False)
|
||||
|
||||
# get ssh options FIXME: make these common to all connections
|
||||
for flag in ['ssh_common_args', 'docker_extra_args', 'sftp_extra_args', 'scp_extra_args', 'ssh_extra_args']:
|
||||
|
|
|
@ -25,9 +25,9 @@ import os.path
|
|||
import re
|
||||
import tempfile
|
||||
|
||||
from ansible.constants import mk_boolean as boolean
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.module_utils._text import to_native, to_text
|
||||
from ansible.module_utils.parsing.convert_bool import boolean
|
||||
from ansible.plugins.action import ActionBase
|
||||
from ansible.utils.hashing import checksum_s
|
||||
|
||||
|
@ -101,7 +101,7 @@ class ActionModule(ActionBase):
|
|||
result['msg'] = "src and dest are required"
|
||||
return result
|
||||
|
||||
if boolean(remote_src):
|
||||
if boolean(remote_src, strict=False):
|
||||
result.update(self._execute_module(tmp=tmp, task_vars=task_vars))
|
||||
return result
|
||||
else:
|
||||
|
|
|
@ -24,9 +24,9 @@ import os
|
|||
import stat
|
||||
import tempfile
|
||||
|
||||
from ansible.constants import mk_boolean as boolean
|
||||
from ansible.errors import AnsibleError, AnsibleFileNotFound
|
||||
from ansible.module_utils._text import to_bytes, to_native, to_text
|
||||
from ansible.module_utils.parsing.convert_bool import boolean
|
||||
from ansible.plugins.action import ActionBase
|
||||
from ansible.utils.hashing import checksum
|
||||
|
||||
|
@ -43,11 +43,11 @@ class ActionModule(ActionBase):
|
|||
source = self._task.args.get('src', None)
|
||||
content = self._task.args.get('content', None)
|
||||
dest = self._task.args.get('dest', None)
|
||||
raw = boolean(self._task.args.get('raw', 'no'))
|
||||
force = boolean(self._task.args.get('force', 'yes'))
|
||||
remote_src = boolean(self._task.args.get('remote_src', False))
|
||||
follow = boolean(self._task.args.get('follow', False))
|
||||
decrypt = boolean(self._task.args.get('decrypt', True))
|
||||
raw = boolean(self._task.args.get('raw', 'no'), strict=False)
|
||||
force = boolean(self._task.args.get('force', 'yes'), strict=False)
|
||||
remote_src = boolean(self._task.args.get('remote_src', False), strict=False)
|
||||
follow = boolean(self._task.args.get('follow', False), strict=False)
|
||||
decrypt = boolean(self._task.args.get('decrypt', True), strict=False)
|
||||
|
||||
result['failed'] = True
|
||||
if (source is None and content is None) or dest is None:
|
||||
|
|
|
@ -20,10 +20,10 @@ __metaclass__ = type
|
|||
import os
|
||||
import base64
|
||||
|
||||
from ansible.constants import mk_boolean as boolean
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.module_utils._text import to_bytes
|
||||
from ansible.module_utils.six import string_types
|
||||
from ansible.module_utils.parsing.convert_bool import boolean
|
||||
from ansible.plugins.action import ActionBase
|
||||
from ansible.utils.hashing import checksum, checksum_s, md5, secure_hash
|
||||
from ansible.utils.path import makedirs_safe
|
||||
|
@ -51,9 +51,11 @@ class ActionModule(ActionBase):
|
|||
|
||||
source = self._task.args.get('src', None)
|
||||
dest = self._task.args.get('dest', None)
|
||||
flat = boolean(self._task.args.get('flat'))
|
||||
fail_on_missing = boolean(self._task.args.get('fail_on_missing'))
|
||||
validate_checksum = boolean(self._task.args.get('validate_checksum', self._task.args.get('validate_md5', True)))
|
||||
flat = boolean(self._task.args.get('flat'), strict=False)
|
||||
fail_on_missing = boolean(self._task.args.get('fail_on_missing'), strict=False)
|
||||
validate_checksum = boolean(self._task.args.get('validate_checksum',
|
||||
self._task.args.get('validate_md5', True)),
|
||||
strict=False)
|
||||
|
||||
# validate source and dest are strings FIXME: use basic.py and module specs
|
||||
if not isinstance(source, string_types):
|
||||
|
|
|
@ -20,9 +20,9 @@ __metaclass__ = type
|
|||
|
||||
import os
|
||||
|
||||
from ansible.constants import mk_boolean as boolean
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.module_utils._text import to_native
|
||||
from ansible.module_utils.parsing.convert_bool import boolean
|
||||
from ansible.plugins.action import ActionBase
|
||||
|
||||
|
||||
|
@ -35,7 +35,7 @@ class ActionModule(ActionBase):
|
|||
result = super(ActionModule, self).run(tmp, task_vars)
|
||||
|
||||
src = self._task.args.get('src', None)
|
||||
remote_src = boolean(self._task.args.get('remote_src', 'no'))
|
||||
remote_src = boolean(self._task.args.get('remote_src', 'no'), strict=False)
|
||||
|
||||
if src is None:
|
||||
result['failed'] = True
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
from ansible.constants import mk_boolean as boolean
|
||||
from ansible.module_utils.six import iteritems, string_types
|
||||
from ansible.module_utils.parsing.convert_bool import boolean
|
||||
from ansible.plugins.action import ActionBase
|
||||
from ansible.utils.vars import isidentifier
|
||||
|
||||
|
@ -46,7 +46,7 @@ class ActionModule(ActionBase):
|
|||
return result
|
||||
|
||||
if isinstance(v, string_types) and v.lower() in ('true', 'false', 'yes', 'no'):
|
||||
v = boolean(v)
|
||||
v = boolean(v, strict=False)
|
||||
facts[k] = v
|
||||
|
||||
result['changed'] = False
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
from ansible.constants import mk_boolean as boolean
|
||||
from ansible.module_utils.six import iteritems, string_types
|
||||
from ansible.module_utils.parsing.convert_bool import boolean
|
||||
from ansible.plugins.action import ActionBase
|
||||
from ansible.utils.vars import isidentifier
|
||||
|
||||
|
@ -53,7 +53,7 @@ class ActionModule(ActionBase):
|
|||
val = self._task.args.get(opt, None)
|
||||
if val is not None:
|
||||
if not isinstance(val, bool):
|
||||
stats[opt] = boolean(self._templar.template(val))
|
||||
stats[opt] = boolean(self._templar.template(val), strict=False)
|
||||
else:
|
||||
stats[opt] = val
|
||||
|
||||
|
|
|
@ -23,12 +23,11 @@ from collections import MutableSequence
|
|||
from ansible import constants as C
|
||||
from ansible.module_utils.six import string_types
|
||||
from ansible.module_utils._text import to_text
|
||||
from ansible.module_utils.parsing.convert_bool import boolean
|
||||
from ansible.playbook.play_context import MAGIC_VARIABLE_MAPPING
|
||||
from ansible.plugins.action import ActionBase
|
||||
from ansible.plugins import connection_loader
|
||||
|
||||
boolean = C.mk_boolean
|
||||
|
||||
|
||||
class ActionModule(ActionBase):
|
||||
|
||||
|
@ -314,7 +313,7 @@ class ActionModule(ActionBase):
|
|||
user = None
|
||||
if not dest_is_local:
|
||||
# Src and dest rsync "path" handling
|
||||
if boolean(_tmp_args.get('set_remote_user', 'yes')):
|
||||
if boolean(_tmp_args.get('set_remote_user', 'yes'), strict=False):
|
||||
if use_delegate:
|
||||
user = task_vars.get('ansible_delegated_vars', dict()).get('ansible_ssh_user', None)
|
||||
if not user:
|
||||
|
|
|
@ -22,12 +22,11 @@ import os
|
|||
from ansible import constants as C
|
||||
from ansible.errors import AnsibleError, AnsibleFileNotFound
|
||||
from ansible.module_utils._text import to_text
|
||||
from ansible.module_utils.parsing.convert_bool import boolean
|
||||
from ansible.plugins.action import ActionBase
|
||||
from ansible.template import generate_ansible_template_vars
|
||||
from ansible.utils.hashing import checksum_s
|
||||
|
||||
boolean = C.mk_boolean
|
||||
|
||||
|
||||
class ActionModule(ActionBase):
|
||||
|
||||
|
@ -58,7 +57,7 @@ class ActionModule(ActionBase):
|
|||
|
||||
source = self._task.args.get('src', None)
|
||||
dest = self._task.args.get('dest', None)
|
||||
force = boolean(self._task.args.get('force', True))
|
||||
force = boolean(self._task.args.get('force', True), strict=False)
|
||||
state = self._task.args.get('state', None)
|
||||
newline_sequence = self._task.args.get('newline_sequence', self.DEFAULT_NEWLINE_SEQUENCE)
|
||||
variable_start_string = self._task.args.get('variable_start_string', None)
|
||||
|
|
|
@ -21,10 +21,9 @@ __metaclass__ = type
|
|||
import os
|
||||
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.module_utils._text import to_native
|
||||
from ansible.module_utils.pycompat24 import get_exception
|
||||
from ansible.module_utils._text import to_text
|
||||
from ansible.module_utils.parsing.convert_bool import boolean
|
||||
from ansible.plugins.action import ActionBase
|
||||
from ansible.constants import mk_boolean as boolean
|
||||
|
||||
|
||||
class ActionModule(ActionBase):
|
||||
|
@ -40,7 +39,7 @@ class ActionModule(ActionBase):
|
|||
|
||||
source = self._task.args.get('src', None)
|
||||
dest = self._task.args.get('dest', None)
|
||||
remote_src = boolean(self._task.args.get('remote_src', False))
|
||||
remote_src = boolean(self._task.args.get('remote_src', False), strict=False)
|
||||
creates = self._task.args.get('creates', None)
|
||||
decrypt = self._task.args.get('decrypt', True)
|
||||
|
||||
|
@ -53,7 +52,7 @@ class ActionModule(ActionBase):
|
|||
return result
|
||||
# We will take the information from copy and store it in
|
||||
# the remote_src var to use later in this file.
|
||||
self._task.args['remote_src'] = remote_src = not boolean(self._task.args.pop('copy'))
|
||||
self._task.args['remote_src'] = remote_src = not boolean(self._task.args.pop('copy'), strict=False)
|
||||
|
||||
if source is None or dest is None:
|
||||
result['failed'] = True
|
||||
|
@ -79,17 +78,17 @@ class ActionModule(ActionBase):
|
|||
if not remote_src:
|
||||
try:
|
||||
source = self._loader.get_real_file(self._find_needle('files', source), decrypt=decrypt)
|
||||
except AnsibleError:
|
||||
except AnsibleError as e:
|
||||
result['failed'] = True
|
||||
result['msg'] = to_native(get_exception())
|
||||
result['msg'] = to_text(e)
|
||||
self._remove_tmp_path(tmp)
|
||||
return result
|
||||
|
||||
try:
|
||||
remote_stat = self._execute_remote_stat(dest, all_vars=task_vars, follow=True)
|
||||
except AnsibleError:
|
||||
except AnsibleError as e:
|
||||
result['failed'] = True
|
||||
result['msg'] = to_native(get_exception())
|
||||
result['msg'] = to_text(e)
|
||||
self._remove_tmp_path(tmp)
|
||||
return result
|
||||
|
||||
|
|
|
@ -28,8 +28,8 @@ try:
|
|||
except ImportError:
|
||||
cli = None
|
||||
|
||||
from ansible.constants import mk_boolean
|
||||
from ansible.module_utils.urls import open_url
|
||||
from ansible.module_utils.parsing.convert_bool import boolean
|
||||
from ansible.plugins.callback import CallbackBase
|
||||
|
||||
try:
|
||||
|
@ -79,8 +79,9 @@ class CallbackModule(CallbackBase):
|
|||
self.webhook_url = os.getenv('SLACK_WEBHOOK_URL')
|
||||
self.channel = os.getenv('SLACK_CHANNEL', '#ansible')
|
||||
self.username = os.getenv('SLACK_USERNAME', 'ansible')
|
||||
self.show_invocation = mk_boolean(
|
||||
os.getenv('SLACK_INVOCATION', self._display.verbosity > 1)
|
||||
self.show_invocation = boolean(
|
||||
os.getenv('SLACK_INVOCATION', self._display.verbosity > 1),
|
||||
strict=False
|
||||
)
|
||||
|
||||
if self.webhook_url is None:
|
||||
|
|
|
@ -111,16 +111,14 @@ from functools import wraps
|
|||
from ansible import constants as C
|
||||
from ansible.errors import AnsibleError, AnsibleConnectionFailure, AnsibleFileNotFound
|
||||
from ansible.errors import AnsibleOptionsError
|
||||
from ansible.module_utils.basic import BOOLEANS
|
||||
from ansible.compat import selectors
|
||||
from ansible.module_utils.six import PY3, text_type, binary_type
|
||||
from ansible.module_utils.six.moves import shlex_quote
|
||||
from ansible.module_utils._text import to_bytes, to_native, to_text
|
||||
from ansible.module_utils.parsing.convert_bool import BOOLEANS, boolean
|
||||
from ansible.plugins.connection import ConnectionBase, BUFSIZE
|
||||
from ansible.utils.path import unfrackpath, makedirs_safe
|
||||
|
||||
boolean = C.mk_boolean
|
||||
|
||||
try:
|
||||
from __main__ import display
|
||||
except ImportError:
|
||||
|
@ -791,7 +789,7 @@ class Connection(ConnectionBase):
|
|||
if not isinstance(scp_if_ssh, bool):
|
||||
scp_if_ssh = scp_if_ssh.lower()
|
||||
if scp_if_ssh in BOOLEANS:
|
||||
scp_if_ssh = boolean(scp_if_ssh)
|
||||
scp_if_ssh = boolean(scp_if_ssh, strict=False)
|
||||
elif scp_if_ssh != 'smart':
|
||||
raise AnsibleOptionsError('scp_if_ssh needs to be one of [smart|True|False]')
|
||||
if scp_if_ssh == 'smart':
|
||||
|
|
|
@ -122,9 +122,9 @@ import os
|
|||
|
||||
from jinja2.exceptions import UndefinedError
|
||||
|
||||
from ansible.constants import mk_boolean as boolean
|
||||
from ansible.errors import AnsibleFileNotFound, AnsibleLookupError, AnsibleUndefinedVariable
|
||||
from ansible.module_utils.six import string_types
|
||||
from ansible.module_utils.parsing.convert_bool import boolean
|
||||
from ansible.plugins.lookup import LookupBase
|
||||
|
||||
|
||||
|
@ -145,7 +145,7 @@ class LookupModule(LookupBase):
|
|||
if isinstance(term, dict):
|
||||
files = term.get('files', [])
|
||||
paths = term.get('paths', [])
|
||||
skip = boolean(term.get('skip', False))
|
||||
skip = boolean(term.get('skip', False), strict=False)
|
||||
|
||||
filelist = files
|
||||
if isinstance(files, string_types):
|
||||
|
|
|
@ -46,8 +46,8 @@ __metaclass__ = type
|
|||
import os
|
||||
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.module_utils.parsing.convert_bool import boolean
|
||||
from ansible.plugins.lookup import LookupBase
|
||||
from ansible.constants import mk_boolean as boolean
|
||||
|
||||
HAS_HVAC = False
|
||||
try:
|
||||
|
@ -149,7 +149,7 @@ class HashiVault:
|
|||
self.client.auth_ldap(username, password, mount_point)
|
||||
|
||||
def boolean_or_cacert(self, validate_certs, cacert):
|
||||
validate_certs = boolean(validate_certs)
|
||||
validate_certs = boolean(validate_certs, strict=False)
|
||||
'''' return a bool or cacert '''
|
||||
if validate_certs is True:
|
||||
if cacert != '':
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
from ansible.constants import mk_boolean as boolean
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.module_utils.six import string_types
|
||||
from ansible.module_utils.parsing.convert_bool import boolean
|
||||
from ansible.plugins.lookup import LookupBase
|
||||
from ansible.utils.listify import listify_lookup_plugin_terms
|
||||
|
||||
|
@ -72,7 +72,7 @@ class LookupModule(LookupBase):
|
|||
# this particular item is to be skipped
|
||||
continue
|
||||
|
||||
skip_missing = boolean(flags.get('skip_missing', False))
|
||||
skip_missing = boolean(flags.get('skip_missing', False), strict=False)
|
||||
subvalue = item0
|
||||
lastsubkey = False
|
||||
sublist = []
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
injector.py
|
256
test/runner/injector/importer.py
Executable file
256
test/runner/injector/importer.py
Executable file
|
@ -0,0 +1,256 @@
|
|||
#!/usr/bin/env python
|
||||
"""Interpreter and code coverage injector for use with ansible-test.
|
||||
|
||||
The injector serves two main purposes:
|
||||
|
||||
1) Control the python interpreter used to run test tools and ansible code.
|
||||
2) Provide optional code coverage analysis of ansible code.
|
||||
|
||||
The injector is executed one of two ways:
|
||||
|
||||
1) On the controller via a symbolic link such as ansible or pytest.
|
||||
This is accomplished by prepending the injector directory to the PATH by ansible-test.
|
||||
|
||||
2) As the python interpreter when running ansible modules.
|
||||
This is only supported when connecting to the local host.
|
||||
Otherwise set the ANSIBLE_TEST_REMOTE_INTERPRETER environment variable.
|
||||
It can be empty to auto-detect the python interpreter on the remote host.
|
||||
If not empty it will be used to set ansible_python_interpreter.
|
||||
|
||||
NOTE: Running ansible-test with the --tox option or inside a virtual environment
|
||||
may prevent the injector from working for tests which use connection
|
||||
types other than local, or which use become, due to lack of permissions
|
||||
to access the interpreter for the virtual environment.
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import, print_function
|
||||
|
||||
import errno
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import pipes
|
||||
import logging
|
||||
import getpass
|
||||
|
||||
logger = logging.getLogger('injector') # pylint: disable=locally-disabled, invalid-name
|
||||
# pylint: disable=locally-disabled, invalid-name
|
||||
config = None # type: InjectorConfig
|
||||
|
||||
|
||||
class InjectorConfig(object):
|
||||
"""Mandatory configuration."""
|
||||
def __init__(self, config_path):
|
||||
"""Initialize config."""
|
||||
with open(config_path) as config_fd:
|
||||
_config = json.load(config_fd)
|
||||
|
||||
self.python_interpreter = _config['python_interpreter']
|
||||
self.coverage_file = _config['coverage_file']
|
||||
|
||||
# Read from the environment instead of config since it needs to be changed by integration test scripts.
|
||||
# It also does not need to flow from the controller to the remote. It is only used on the controller.
|
||||
self.remote_interpreter = os.environ.get('ANSIBLE_TEST_REMOTE_INTERPRETER', None)
|
||||
|
||||
self.arguments = [to_text(c) for c in sys.argv]
|
||||
|
||||
|
||||
def to_text(value):
|
||||
"""
|
||||
:type value: str | None
|
||||
:rtype: str | None
|
||||
"""
|
||||
if value is None:
|
||||
return None
|
||||
|
||||
if isinstance(value, bytes):
|
||||
return value.decode('utf-8')
|
||||
|
||||
return u'%s' % value
|
||||
|
||||
|
||||
def main():
|
||||
"""Main entry point."""
|
||||
global config # pylint: disable=locally-disabled, global-statement
|
||||
|
||||
formatter = logging.Formatter('%(asctime)s %(process)d %(levelname)s %(message)s')
|
||||
log_name = 'ansible-test-coverage.%s.log' % getpass.getuser()
|
||||
self_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
handler = logging.FileHandler(os.path.join('/tmp', log_name))
|
||||
handler.setFormatter(formatter)
|
||||
logger.addHandler(handler)
|
||||
|
||||
handler = logging.FileHandler(os.path.abspath(os.path.join(self_dir, '..', 'logs', log_name)))
|
||||
handler.setFormatter(formatter)
|
||||
logger.addHandler(handler)
|
||||
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
try:
|
||||
logger.debug('Self: %s', __file__)
|
||||
|
||||
config_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'injector.json')
|
||||
|
||||
try:
|
||||
config = InjectorConfig(config_path)
|
||||
except IOError:
|
||||
logger.exception('Error reading config: %s', config_path)
|
||||
exit('No injector config found. Set ANSIBLE_TEST_REMOTE_INTERPRETER if the test is not connecting to the local host.')
|
||||
|
||||
logger.debug('Arguments: %s', ' '.join(pipes.quote(c) for c in config.arguments))
|
||||
logger.debug('Python interpreter: %s', config.python_interpreter)
|
||||
logger.debug('Remote interpreter: %s', config.remote_interpreter)
|
||||
logger.debug('Coverage file: %s', config.coverage_file)
|
||||
|
||||
require_cwd = False
|
||||
|
||||
if os.path.basename(__file__) == 'injector.py':
|
||||
if config.coverage_file:
|
||||
args, env, require_cwd = cover()
|
||||
else:
|
||||
args, env = runner()
|
||||
else:
|
||||
args, env = injector()
|
||||
|
||||
logger.debug('Run command: %s', ' '.join(pipes.quote(c) for c in args))
|
||||
|
||||
altered_cwd = False
|
||||
|
||||
try:
|
||||
cwd = os.getcwd()
|
||||
except OSError as ex:
|
||||
# some platforms, such as OS X, may not allow querying the working directory when using become to drop privileges
|
||||
if ex.errno != errno.EACCES:
|
||||
raise
|
||||
if require_cwd:
|
||||
# make sure the program we execute can determine the working directory if it's required
|
||||
cwd = '/'
|
||||
os.chdir(cwd)
|
||||
altered_cwd = True
|
||||
else:
|
||||
cwd = None
|
||||
|
||||
logger.debug('Working directory: %s%s', cwd or '?', ' (altered)' if altered_cwd else '')
|
||||
|
||||
for key in sorted(env.keys()):
|
||||
logger.debug('%s=%s', key, env[key])
|
||||
|
||||
os.execvpe(args[0], args, env)
|
||||
except Exception as ex:
|
||||
logger.fatal(ex)
|
||||
raise
|
||||
|
||||
|
||||
def injector():
|
||||
"""
|
||||
:rtype: list[str], dict[str, str]
|
||||
"""
|
||||
command = os.path.basename(__file__)
|
||||
executable = find_executable(command)
|
||||
|
||||
if config.coverage_file:
|
||||
args, env = coverage_command()
|
||||
else:
|
||||
args, env = [config.python_interpreter], os.environ.copy()
|
||||
|
||||
args += [executable]
|
||||
|
||||
if command in ('ansible', 'ansible-playbook', 'ansible-pull'):
|
||||
if config.remote_interpreter is None:
|
||||
interpreter = os.path.join(os.path.dirname(__file__), 'injector.py')
|
||||
elif config.remote_interpreter == '':
|
||||
interpreter = None
|
||||
else:
|
||||
interpreter = config.remote_interpreter
|
||||
|
||||
if interpreter:
|
||||
args += ['--extra-vars', 'ansible_python_interpreter=' + interpreter]
|
||||
|
||||
args += config.arguments[1:]
|
||||
|
||||
return args, env
|
||||
|
||||
|
||||
def runner():
|
||||
"""
|
||||
:rtype: list[str], dict[str, str]
|
||||
"""
|
||||
args, env = [config.python_interpreter], os.environ.copy()
|
||||
|
||||
args += config.arguments[1:]
|
||||
|
||||
return args, env
|
||||
|
||||
|
||||
def cover():
|
||||
"""
|
||||
:rtype: list[str], dict[str, str], bool
|
||||
"""
|
||||
if len(config.arguments) > 1:
|
||||
executable = config.arguments[1]
|
||||
else:
|
||||
executable = ''
|
||||
|
||||
require_cwd = False
|
||||
|
||||
if os.path.basename(executable).startswith('ansible_module_'):
|
||||
args, env = coverage_command()
|
||||
# coverage requires knowing the working directory
|
||||
require_cwd = True
|
||||
else:
|
||||
args, env = [config.python_interpreter], os.environ.copy()
|
||||
|
||||
args += config.arguments[1:]
|
||||
|
||||
return args, env, require_cwd
|
||||
|
||||
|
||||
def coverage_command():
|
||||
"""
|
||||
:rtype: list[str], dict[str, str]
|
||||
"""
|
||||
self_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
args = [
|
||||
config.python_interpreter,
|
||||
'-m',
|
||||
'coverage.__main__',
|
||||
'run',
|
||||
'--rcfile',
|
||||
os.path.join(self_dir, '.coveragerc'),
|
||||
]
|
||||
|
||||
env = os.environ.copy()
|
||||
env['COVERAGE_FILE'] = config.coverage_file
|
||||
|
||||
return args, env
|
||||
|
||||
|
||||
def find_executable(executable):
|
||||
"""
|
||||
:type executable: str
|
||||
:rtype: str
|
||||
"""
|
||||
self = os.path.abspath(__file__)
|
||||
path = os.environ.get('PATH', os.defpath)
|
||||
seen_dirs = set()
|
||||
|
||||
for path_dir in path.split(os.pathsep):
|
||||
if path_dir in seen_dirs:
|
||||
continue
|
||||
|
||||
seen_dirs.add(path_dir)
|
||||
candidate = os.path.abspath(os.path.join(path_dir, executable))
|
||||
|
||||
if candidate == self:
|
||||
continue
|
||||
|
||||
if os.path.exists(candidate) and os.access(candidate, os.F_OK | os.X_OK):
|
||||
return candidate
|
||||
|
||||
raise Exception('Executable "%s" not found in path: %s' % (executable, path))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
60
test/units/module_utils/parsing/test_convert_bool.py
Normal file
60
test/units/module_utils/parsing/test_convert_bool.py
Normal file
|
@ -0,0 +1,60 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright: (c) 2017 Ansible Project
|
||||
# License: GNU General Public License v3 or later (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt )
|
||||
|
||||
# Make coding more python3-ish
|
||||
from __future__ import (absolute_import, division)
|
||||
__metaclass__ = type
|
||||
|
||||
import pytest
|
||||
|
||||
from ansible.module_utils.parsing.convert_bool import boolean
|
||||
|
||||
|
||||
class TestBoolean:
|
||||
def test_bools(self):
|
||||
assert boolean(True) is True
|
||||
assert boolean(False) is False
|
||||
|
||||
def test_none(self):
|
||||
with pytest.raises(TypeError):
|
||||
assert boolean(None, strict=True) is False
|
||||
assert boolean(None, strict=False) is False
|
||||
|
||||
def test_numbers(self):
|
||||
assert boolean(1) is True
|
||||
assert boolean(0) is False
|
||||
assert boolean(0.0) is False
|
||||
|
||||
# Current boolean() doesn't consider these to be true values
|
||||
# def test_other_numbers(self):
|
||||
# assert boolean(2) is True
|
||||
# assert boolean(-1) is True
|
||||
# assert boolean(0.1) is True
|
||||
|
||||
def test_strings(self):
|
||||
assert boolean("true") is True
|
||||
assert boolean("TRUE") is True
|
||||
assert boolean("t") is True
|
||||
assert boolean("yes") is True
|
||||
assert boolean("y") is True
|
||||
assert boolean("on") is True
|
||||
|
||||
def test_junk_values_nonstrict(self):
|
||||
assert boolean("flibbity", strict=False) is False
|
||||
assert boolean(42, strict=False) is False
|
||||
assert boolean(42.0, strict=False) is False
|
||||
assert boolean(object(), strict=False) is False
|
||||
|
||||
def test_junk_values_strict(self):
|
||||
with pytest.raises(TypeError):
|
||||
assert boolean("flibbity", strict=True)is False
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
assert boolean(42, strict=True)is False
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
assert boolean(42.0, strict=True)is False
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
assert boolean(object(), strict=True)is False
|
Loading…
Reference in a new issue