Bump version of main to 12.0.0; execute announced deprecations (#10883)

* Bump version to 12.0.0.

* Remove deprecated modules and plugins.

* state is now required.

* Change default of prepend_hash from auto to never.

* Remove support for force=''.

* Always delegate 'debug'.

* Remove ignore_value_none and ctx_ignore_none parameters.

* Remove parameters on_success and on_failure.

* Update BOTMETA.

* Adjust docs reference.

* Forgot required=True.

* Fix changelog fragment.

* Adjust unit tests.

* Fix changelog.

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>

---------

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
This commit is contained in:
Felix Fontein 2025-10-09 13:50:07 +02:00 committed by GitHub
commit 0b72737cab
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 43 additions and 901 deletions

10
.github/BOTMETA.yml vendored
View file

@ -99,7 +99,6 @@ files:
$callbacks/unixy.py:
labels: unixy
maintainers: akatch
$callbacks/yaml.py: {}
$connections/:
labels: connections
$connections/chroot.py: {}
@ -394,9 +393,6 @@ files:
$module_utils/puppet.py:
labels: puppet
maintainers: russoz
$module_utils/pure.py:
labels: pure pure_storage
maintainers: $team_purestorage
$module_utils/redfish_utils.py:
labels: redfish_utils
maintainers: $team_redfish
@ -480,8 +476,6 @@ files:
keywords: beadm dladm illumos ipadm nexenta omnios openindiana pfexec smartos solaris sunos zfs zpool
labels: beadm solaris
maintainers: $team_solaris
$modules/bearychat.py:
maintainers: tonyseek
$modules/bigpanda.py:
ignore: hkariti
$modules/bitbucket_:
@ -587,9 +581,6 @@ files:
$modules/etcd3.py:
ignore: vfauth
maintainers: evrardjp
$modules/facter.py:
labels: facter
maintainers: $team_ansible_core gamethis
$modules/facter_facts.py:
labels: facter
maintainers: russoz $team_ansible_core gamethis
@ -1610,7 +1601,6 @@ macros:
team_networking: NilashishC Qalthos danielmellado ganeshrn justjais trishnaguha sganesh-infoblox privateip
team_opennebula: ilicmilan meerkampdvv rsmontero xorel nilsding
team_oracle: manojmeda mross22 nalsaber
team_purestorage: bannaych dnix101 genegr lionmax opslounge raekins sdodsley sile16
team_redfish: mraineri tomasg2012 xmadsen renxulei rajeevkallur bhavya06 jyundt
team_rhsm: cnsnyder ptoscano
team_scaleway: remyleone abarbare

View file

@ -0,0 +1,16 @@
removed_features:
- "yaml callback plugin - the deprecated plugin has been removed. Use the default callback with ``result_format=yaml`` instead (https://github.com/ansible-collections/community.general/pull/10883)."
- "purestorage doc fragment - the modules using this doc fragment have been removed from community.general 3.0.0 (https://github.com/ansible-collections/community.general/pull/10883)."
- "pure module utils - the modules using this module utils have been removed from community.general 3.0.0 (https://github.com/ansible-collections/community.general/pull/10883)."
- "bearychat - the module has been removed as the chat service is no longer available (https://github.com/ansible-collections/community.general/pull/10883)."
- "facter - the module has been replaced by ``community.general.facter_facts`` (https://github.com/ansible-collections/community.general/pull/10883)."
- "pacemaker_cluster - the option ``state`` is now required (https://github.com/ansible-collections/community.general/pull/10883)."
- >-
opkg - the value ``""`` for the option ``force`` is no longer allowed. Omit ``force`` instead (https://github.com/ansible-collections/community.general/pull/10883).
- "cmd_runner_fmt module utils - the parameter ``ctx_ignore_none`` to argument formatters has been removed (https://github.com/ansible-collections/community.general/pull/10883)."
- "cmd_runner module utils - the parameter ``ignore_value_none`` to ``CmdRunner.__call__()`` has been removed (https://github.com/ansible-collections/community.general/pull/10883)."
- >-
mh.deco module utils - the parameters ``on_success`` and ``on_failure`` of ``cause()`` have been removed; use ``when="success"`` and ``when="failure"`` instead (https://github.com/ansible-collections/community.general/pull/10883).
breaking_changes:
- "slack - the default of ``prepend_hash`` changed from ``auto`` to ``never`` (https://github.com/ansible-collections/community.general/pull/10883)."
- "mh.base module utils - ``debug`` will now always be delegated to the underlying ``AnsibleModule`` object (https://github.com/ansible-collections/community.general/pull/10883)."

View file

@ -5,7 +5,7 @@
namespace: community
name: general
version: 11.4.0
version: 12.0.0
readme: README.md
authors:
- Ansible (https://github.com/ansible)

View file

@ -100,7 +100,7 @@ plugin_routing:
warning_text: Use the 'default' callback plugin with 'display_failed_stderr
= yes' option.
yaml:
deprecation:
tombstone:
removal_version: 12.0.0
warning_text: >-
The plugin has been superseded by the option `result_format=yaml` in callback plugin ansible.builtin.default from ansible-core 2.13 onwards.
@ -153,7 +153,7 @@ plugin_routing:
removal_version: 13.0.0
warning_text: Project Atomic was sunset by the end of 2019.
bearychat:
deprecation:
tombstone:
removal_version: 12.0.0
warning_text: Chat service is no longer available.
catapult:
@ -257,7 +257,7 @@ plugin_routing:
docker_volume_info:
redirect: community.docker.docker_volume_info
facter:
deprecation:
tombstone:
removal_version: 12.0.0
warning_text: Use community.general.facter_facts instead.
flowdock:
@ -1084,7 +1084,7 @@ plugin_routing:
removal_version: 15.0.0
warning_text: The proxmox content has been moved to community.proxmox.
purestorage:
deprecation:
tombstone:
removal_version: 12.0.0
warning_text: The modules for purestorage were removed in community.general 3.0.0, this document fragment was left behind.
rackspace:
@ -1121,7 +1121,7 @@ plugin_routing:
removal_version: 15.0.0
warning_text: The proxmox content has been moved to community.proxmox.
pure:
deprecation:
tombstone:
removal_version: 12.0.0
warning_text: The modules for purestorage were removed in community.general 3.0.0, this module util was left behind.
rax:

View file

@ -1,195 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
# Make coding more python3-ish
from __future__ import annotations
DOCUMENTATION = r"""
author: Unknown (!UNKNOWN)
name: yaml
type: stdout
short_description: YAML-ized Ansible screen output
deprecated:
removed_in: 12.0.0
why: Starting in ansible-core 2.13, the P(ansible.builtin.default#callback) callback has support for printing output in
YAML format.
alternative: Use O(ansible.builtin.default#callback:result_format=yaml).
description:
- Ansible output that can be quite a bit easier to read than the default JSON formatting.
extends_documentation_fragment:
- default_callback
requirements:
- set as stdout in configuration
seealso:
- plugin: ansible.builtin.default
plugin_type: callback
description: >-
There is a parameter O(ansible.builtin.default#callback:result_format) in P(ansible.builtin.default#callback) that allows
you to change the output format to YAML.
notes:
- With ansible-core 2.13 or newer, you can instead specify V(yaml) for the parameter O(ansible.builtin.default#callback:result_format)
in P(ansible.builtin.default#callback).
"""
import yaml
import json
import re
import string
from collections.abc import Mapping, Sequence
from ansible.module_utils.common.text.converters import to_text
from ansible.plugins.callback import strip_internal_keys, module_response_deepcopy
from ansible.plugins.callback.default import CallbackModule as Default
# from http://stackoverflow.com/a/15423007/115478
def should_use_block(value):
"""Returns true if string should be in block format"""
for c in "\u000a\u000d\u001c\u001d\u001e\u0085\u2028\u2029":
if c in value:
return True
return False
def adjust_str_value_for_block(value):
# we care more about readable than accuracy, so...
# ...no trailing space
value = value.rstrip()
# ...and non-printable characters
value = ''.join(x for x in value if x in string.printable or ord(x) >= 0xA0)
# ...tabs prevent blocks from expanding
value = value.expandtabs()
# ...and odd bits of whitespace
value = re.sub(r'[\x0b\x0c\r]', '', value)
# ...as does trailing space
value = re.sub(r' +\n', '\n', value)
return value
def create_string_node(tag, value, style, default_style):
if style is None:
if should_use_block(value):
style = '|'
value = adjust_str_value_for_block(value)
else:
style = default_style
return yaml.representer.ScalarNode(tag, value, style=style)
try:
from ansible.module_utils.common.yaml import HAS_LIBYAML
# import below was added in https://github.com/ansible/ansible/pull/85039,
# first contained in ansible-core 2.19.0b2:
from ansible.utils.vars import transform_to_native_types
if HAS_LIBYAML:
from yaml.cyaml import CSafeDumper as SafeDumper
else:
from yaml import SafeDumper
class MyDumper(SafeDumper):
def represent_scalar(self, tag, value, style=None):
"""Uses block style for multi-line strings"""
node = create_string_node(tag, value, style, self.default_style)
if self.alias_key is not None:
self.represented_objects[self.alias_key] = node
return node
except ImportError:
# In case transform_to_native_types cannot be imported, we either have ansible-core 2.19.0b1
# (or some random commit from the devel or stable-2.19 branch after merging the DT changes
# and before transform_to_native_types was added), or we have a version without the DT changes.
# Here we simply assume we have a version without the DT changes, and thus can continue as
# with ansible-core 2.18 and before.
transform_to_native_types = None
from ansible.parsing.yaml.dumper import AnsibleDumper
class MyDumper(AnsibleDumper): # pylint: disable=inherit-non-class
def represent_scalar(self, tag, value, style=None):
"""Uses block style for multi-line strings"""
node = create_string_node(tag, value, style, self.default_style)
if self.alias_key is not None:
self.represented_objects[self.alias_key] = node
return node
def transform_recursively(value, transform):
# Since 2.19.0b7, this should no longer be needed:
# https://github.com/ansible/ansible/issues/85325
# https://github.com/ansible/ansible/pull/85389
if isinstance(value, Mapping):
return {transform(k): transform(v) for k, v in value.items()}
if isinstance(value, Sequence) and not isinstance(value, (str, bytes)):
return [transform(e) for e in value]
return transform(value)
class CallbackModule(Default):
"""
Variation of the Default output which uses nicely readable YAML instead
of JSON for printing results.
"""
CALLBACK_VERSION = 2.0
CALLBACK_TYPE = 'stdout'
CALLBACK_NAME = 'community.general.yaml'
def __init__(self):
super(CallbackModule, self).__init__()
def _dump_results(self, result, indent=None, sort_keys=True, keep_invocation=False):
if result.get('_ansible_no_log', False):
return json.dumps(dict(censored="The output has been hidden due to the fact that 'no_log: true' was specified for this result"))
# All result keys stating with _ansible_ are internal, so remove them from the result before we output anything.
abridged_result = strip_internal_keys(module_response_deepcopy(result))
# remove invocation unless specifically wanting it
if not keep_invocation and self._display.verbosity < 3 and 'invocation' in result:
del abridged_result['invocation']
# remove diff information from screen output
if self._display.verbosity < 3 and 'diff' in result:
del abridged_result['diff']
# remove exception from screen output
if 'exception' in abridged_result:
del abridged_result['exception']
dumped = ''
# put changed and skipped into a header line
if 'changed' in abridged_result:
dumped += f"changed={str(abridged_result['changed']).lower()} "
del abridged_result['changed']
if 'skipped' in abridged_result:
dumped += f"skipped={str(abridged_result['skipped']).lower()} "
del abridged_result['skipped']
# if we already have stdout, we don't need stdout_lines
if 'stdout' in abridged_result and 'stdout_lines' in abridged_result:
abridged_result['stdout_lines'] = '<omitted>'
# if we already have stderr, we don't need stderr_lines
if 'stderr' in abridged_result and 'stderr_lines' in abridged_result:
abridged_result['stderr_lines'] = '<omitted>'
if abridged_result:
dumped += '\n'
if transform_to_native_types is not None:
abridged_result = transform_recursively(abridged_result, lambda v: transform_to_native_types(v, redact=False))
dumped += to_text(yaml.dump(abridged_result, allow_unicode=True, width=1000, Dumper=MyDumper, default_flow_style=False))
# indent by a couple of spaces
dumped = '\n '.join(dumped.split('\n')).rstrip()
return dumped
def _serialize_diff(self, diff):
return to_text(yaml.dump(diff, allow_unicode=True, width=1000, Dumper=AnsibleDumper, default_flow_style=False))

View file

@ -1,51 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2017, Simon Dodsley <simon@purestorage.com>
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
class ModuleDocFragment(object):
# Documentation fragment for FlashBlade
FB = r"""
options:
fb_url:
description:
- FlashBlade management IP address or Hostname.
type: str
api_token:
description:
- FlashBlade API token for admin privileged user.
type: str
notes:
- This module requires the C(purity_fb) Python library.
- You must set E(PUREFB_URL) and E(PUREFB_API) environment variables if O(fb_url) and O(api_token) arguments are not passed
to the module directly.
requirements:
- purity_fb >= 1.1
"""
# Documentation fragment for FlashArray
FA = r"""
options:
fa_url:
description:
- FlashArray management IPv4 address or Hostname.
type: str
required: true
api_token:
description:
- FlashArray API token for admin privileged user.
type: str
required: true
notes:
- This module requires the C(purestorage) Python library.
- You must set E(PUREFA_URL) and E(PUREFA_API) environment variables if O(fa_url) and O(api_token) arguments are not passed
to the module directly.
requirements:
- purestorage
"""

View file

@ -132,16 +132,7 @@ class CmdRunner(object):
def binary(self):
return self.command[0]
# remove parameter ignore_value_none in community.general 12.0.0
def __call__(self, args_order=None, output_process=None, ignore_value_none=None, check_mode_skip=False, check_mode_return=None, **kwargs):
if ignore_value_none is None:
ignore_value_none = True
else:
self.module.deprecate(
"Using ignore_value_none when creating the runner context is now deprecated, "
"and the parameter will be removed in community.general 12.0.0. ",
version="12.0.0", collection_name="community.general"
)
def __call__(self, args_order=None, output_process=None, check_mode_skip=False, check_mode_return=None, **kwargs):
if output_process is None:
output_process = _process_as_is
if args_order is None:
@ -153,7 +144,6 @@ class CmdRunner(object):
return _CmdRunnerContext(runner=self,
args_order=args_order,
output_process=output_process,
ignore_value_none=ignore_value_none, # DEPRECATION: remove in community.general 12.0.0
check_mode_skip=check_mode_skip,
check_mode_return=check_mode_return, **kwargs)
@ -165,12 +155,10 @@ class CmdRunner(object):
class _CmdRunnerContext(object):
def __init__(self, runner, args_order, output_process, ignore_value_none, check_mode_skip, check_mode_return, **kwargs):
def __init__(self, runner, args_order, output_process, check_mode_skip, check_mode_return, **kwargs):
self.runner = runner
self.args_order = tuple(args_order)
self.output_process = output_process
# DEPRECATION: parameter ignore_value_none at the context level is deprecated and will be removed in community.general 12.0.0
self.ignore_value_none = ignore_value_none
self.check_mode_skip = check_mode_skip
self.check_mode_return = check_mode_return
self.run_command_args = dict(kwargs)
@ -209,8 +197,7 @@ class _CmdRunnerContext(object):
value = named_args[arg_name]
elif not runner.arg_formats[arg_name].ignore_missing_value:
raise MissingArgumentValue(self.args_order, arg_name)
# DEPRECATION: remove parameter ctx_ignore_none in 12.0.0
self.cmd.extend(runner.arg_formats[arg_name](value, ctx_ignore_none=self.ignore_value_none))
self.cmd.extend(runner.arg_formats[arg_name](value))
except MissingArgumentValue:
raise
except Exception as e:
@ -226,7 +213,6 @@ class _CmdRunnerContext(object):
@property
def run_info(self):
return dict(
ignore_value_none=self.ignore_value_none, # DEPRECATION: remove in community.general 12.0.0
check_rc=self.check_rc,
environ_update=self.environ_update,
args_order=self.args_order,

View file

@ -16,16 +16,13 @@ def _ensure_list(value):
class _ArgFormat(object):
# DEPRECATION: set default value for ignore_none to True in community.general 12.0.0
def __init__(self, func, ignore_none=None, ignore_missing_value=False):
def __init__(self, func, ignore_none=True, ignore_missing_value=False):
self.func = func
self.ignore_none = ignore_none
self.ignore_missing_value = ignore_missing_value
# DEPRECATION: remove parameter ctx_ignore_none in community.general 12.0.0
def __call__(self, value, ctx_ignore_none=True):
# DEPRECATION: replace ctx_ignore_none with True in community.general 12.0.0
ignore_none = self.ignore_none if self.ignore_none is not None else ctx_ignore_none
def __call__(self, value):
ignore_none = self.ignore_none if self.ignore_none is not None else True
if value is None and ignore_none:
return []
f = self.func

View file

@ -15,9 +15,8 @@ from ansible_collections.community.general.plugins.module_utils.mh.deco import m
class ModuleHelperBase(object):
module = None
ModuleHelperException = _MHE
# in 12.0.0 add 'debug' to the tuple
_delegated_to_module = (
'check_mode', 'get_bin_path', 'warn', 'deprecate',
'check_mode', 'get_bin_path', 'warn', 'deprecate', 'debug',
)
def __init__(self, module=None):
@ -29,18 +28,6 @@ class ModuleHelperBase(object):
if not isinstance(self.module, AnsibleModule):
self.module = AnsibleModule(**self.module)
# in 12.0.0 remove this if statement entirely
if hasattr(self, 'debug'):
msg = (
"This class ({cls}) has an attribute 'debug' defined and that is deprecated. "
"Method 'debug' will be an integral part of ModuleHelper in community.general "
"12.0.0, delegated to the underlying AnsibleModule object. "
"Please rename the existing attribute to prevent this message from showing.".format(cls=self.__class__.__name__)
)
self.deprecate(msg, version="12.0.0", collection_name="community.general")
else:
self._delegated_to_module = self._delegated_to_module + ('debug',)
@property
def diff_mode(self):
return self.module._diff

View file

@ -13,22 +13,16 @@ from functools import wraps
from ansible_collections.community.general.plugins.module_utils.mh.exceptions import ModuleHelperException
def cause_changes(on_success=None, on_failure=None, when=None):
# Parameters on_success and on_failure are deprecated and should be removed in community.general 12.0.0
def cause_changes(when=None):
def deco(func):
@wraps(func)
def wrapper(self, *args, **kwargs):
try:
func(self, *args, **kwargs)
if on_success is not None:
self.changed = on_success
elif when == "success":
if when == "success":
self.changed = True
except Exception:
if on_failure is not None:
self.changed = on_failure
elif when == "failure":
if when == "failure":
self.changed = True
raise
finally:

View file

@ -1,115 +0,0 @@
# -*- coding: utf-8 -*-
# This code is part of Ansible, but is an independent component.
# This particular file snippet, and this file snippet only, is BSD licensed.
# Modules you write using this snippet, which is embedded dynamically by Ansible
# still belong to the author of the module, and may assign their own license
# to the complete work.
#
# Copyright (c), Simon Dodsley <simon@purestorage.com>,2017
# Simplified BSD License (see LICENSES/BSD-2-Clause.txt or https://opensource.org/licenses/BSD-2-Clause)
# SPDX-License-Identifier: BSD-2-Clause
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
HAS_PURESTORAGE = True
try:
from purestorage import purestorage
except ImportError:
HAS_PURESTORAGE = False
HAS_PURITY_FB = True
try:
from purity_fb import PurityFb, FileSystem, FileSystemSnapshot, SnapshotSuffix, rest # noqa: F401, pylint: disable=unused-import
except ImportError:
HAS_PURITY_FB = False
# (TODO: remove next line!)
from functools import wraps # noqa: F401, pylint: disable=unused-import
from os import environ
# (TODO: remove next line!)
from os import path # noqa: F401, pylint: disable=unused-import
import platform
VERSION = 1.2
USER_AGENT_BASE = 'Ansible'
API_AGENT_VERSION = 1.5
def get_system(module):
"""Return System Object or Fail"""
user_agent = '%(base)s %(class)s/%(version)s (%(platform)s)' % {
'base': USER_AGENT_BASE,
'class': __name__,
'version': VERSION,
'platform': platform.platform()
}
array_name = module.params['fa_url']
api = module.params['api_token']
if array_name and api:
system = purestorage.FlashArray(array_name, api_token=api, user_agent=user_agent)
elif environ.get('PUREFA_URL') and environ.get('PUREFA_API'):
system = purestorage.FlashArray(environ.get('PUREFA_URL'), api_token=(environ.get('PUREFA_API')), user_agent=user_agent)
else:
module.fail_json(msg="You must set PUREFA_URL and PUREFA_API environment variables or the fa_url and api_token module arguments")
try:
system.get()
except Exception:
module.fail_json(msg="Pure Storage FlashArray authentication failed. Check your credentials")
return system
def get_blade(module):
"""Return System Object or Fail"""
user_agent = '%(base)s %(class)s/%(version)s (%(platform)s)' % {
'base': USER_AGENT_BASE,
'class': __name__,
'version': VERSION,
'platform': platform.platform()
}
blade_name = module.params['fb_url']
api = module.params['api_token']
if blade_name and api:
blade = PurityFb(blade_name)
blade.disable_verify_ssl()
try:
blade.login(api)
versions = blade.api_version.list_versions().versions
if API_AGENT_VERSION in versions:
blade._api_client.user_agent = user_agent
except rest.ApiException as e:
module.fail_json(msg="Pure Storage FlashBlade authentication failed. Check your credentials")
elif environ.get('PUREFB_URL') and environ.get('PUREFB_API'):
blade = PurityFb(environ.get('PUREFB_URL'))
blade.disable_verify_ssl()
try:
blade.login(environ.get('PUREFB_API'))
versions = blade.api_version.list_versions().versions
if API_AGENT_VERSION in versions:
blade._api_client.user_agent = user_agent
except rest.ApiException as e:
module.fail_json(msg="Pure Storage FlashBlade authentication failed. Check your credentials")
else:
module.fail_json(msg="You must set PUREFB_URL and PUREFB_API environment variables or the fb_url and api_token module arguments")
return blade
def purefa_argument_spec():
"""Return standard base dictionary used for the argument_spec argument in AnsibleModule"""
return dict(
fa_url=dict(),
api_token=dict(no_log=True),
)
def purefb_argument_spec():
"""Return standard base dictionary used for the argument_spec argument in AnsibleModule"""
return dict(
fb_url=dict(),
api_token=dict(no_log=True),
)

View file

@ -1,176 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright (c) 2016, Jiangge Zhang <tonyseek@gmail.com>
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = r"""
module: bearychat
short_description: Send BearyChat notifications
description:
- The M(community.general.bearychat) module sends notifications to U(https://bearychat.com) using the Incoming Robot integration.
deprecated:
removed_in: 12.0.0
why: Chat service is no longer available.
alternative: There is none.
author: "Jiangge Zhang (@tonyseek)"
extends_documentation_fragment:
- community.general.attributes
attributes:
check_mode:
support: none
diff_mode:
support: none
options:
url:
type: str
description:
- BearyChat WebHook URL. This authenticates you to the bearychat service. It looks like
V(https://hook.bearychat.com/=ae2CF/incoming/e61bd5c57b164e04b11ac02e66f47f60).
required: true
text:
type: str
description:
- Message to send.
markdown:
description:
- If V(true), text is parsed as markdown.
default: true
type: bool
channel:
type: str
description:
- Channel to send the message to. If absent, the message goes to the default channel selected by the O(url).
attachments:
type: list
elements: dict
description:
- Define a list of attachments. For more information, see
U(https://github.com/bearyinnovative/bearychat-tutorial/blob/master/robots/incoming.md#attachments).
"""
EXAMPLES = r"""
- name: Send notification message via BearyChat
local_action:
module: bearychat
url: |
https://hook.bearychat.com/=ae2CF/incoming/e61bd5c57b164e04b11ac02e66f47f60
text: "{{ inventory_hostname }} completed"
- name: Send notification message via BearyChat all options
local_action:
module: bearychat
url: |
https://hook.bearychat.com/=ae2CF/incoming/e61bd5c57b164e04b11ac02e66f47f60
text: "{{ inventory_hostname }} completed"
markdown: false
channel: "#ansible"
attachments:
- title: "Ansible on {{ inventory_hostname }}"
text: "May the Force be with you."
color: "#ffffff"
images:
- http://example.com/index.png
"""
RETURN = r"""
msg:
description: Execution result.
returned: success
type: str
sample: "OK"
"""
try:
from ansible.module_utils.six.moves.urllib.parse import urlparse, urlunparse
HAS_URLPARSE = True
except Exception:
HAS_URLPARSE = False
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.urls import fetch_url
def build_payload_for_bearychat(module, text, markdown, channel, attachments):
payload = {}
if text is not None:
payload['text'] = text
if markdown is not None:
payload['markdown'] = markdown
if channel is not None:
payload['channel'] = channel
if attachments is not None:
payload.setdefault('attachments', []).extend(
build_payload_for_bearychat_attachment(
module, item.get('title'), item.get('text'), item.get('color'),
item.get('images'))
for item in attachments)
payload = 'payload=%s' % module.jsonify(payload)
return payload
def build_payload_for_bearychat_attachment(module, title, text, color, images):
attachment = {}
if title is not None:
attachment['title'] = title
if text is not None:
attachment['text'] = text
if color is not None:
attachment['color'] = color
if images is not None:
target_images = attachment.setdefault('images', [])
if not isinstance(images, (list, tuple)):
images = [images]
for image in images:
if isinstance(image, dict) and 'url' in image:
image = {'url': image['url']}
elif hasattr(image, 'startswith') and image.startswith('http'):
image = {'url': image}
else:
module.fail_json(
msg="BearyChat doesn't have support for this kind of "
"attachment image")
target_images.append(image)
return attachment
def do_notify_bearychat(module, url, payload):
response, info = fetch_url(module, url, data=payload)
if info['status'] != 200:
url_info = urlparse(url)
obscured_incoming_webhook = urlunparse(
(url_info.scheme, url_info.netloc, '[obscured]', '', '', ''))
module.fail_json(
msg=" failed to send %s to %s: %s" % (
payload, obscured_incoming_webhook, info['msg']))
def main():
module = AnsibleModule(argument_spec={
'url': dict(type='str', required=True, no_log=True),
'text': dict(type='str'),
'markdown': dict(default=True, type='bool'),
'channel': dict(type='str'),
'attachments': dict(type='list', elements='dict'),
})
if not HAS_URLPARSE:
module.fail_json(msg='urlparse is not installed')
url = module.params['url']
text = module.params['text']
markdown = module.params['markdown']
channel = module.params['channel']
attachments = module.params['attachments']
payload = build_payload_for_bearychat(
module, text, markdown, channel, attachments)
do_notify_bearychat(module, url, payload)
module.exit_json(msg="OK")
if __name__ == '__main__':
main()

View file

@ -1,82 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright (c) 2012, Michael DeHaan <michael.dehaan@gmail.com>
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = r"""
module: facter
short_description: Runs the discovery program C(facter) on the remote system
description:
- Runs the C(facter) discovery program (U(https://github.com/puppetlabs/facter)) on the remote system, returning JSON data
that can be useful for inventory purposes.
deprecated:
removed_in: 12.0.0
why: The module has been replaced by M(community.general.facter_facts).
alternative: Use M(community.general.facter_facts) instead.
extends_documentation_fragment:
- community.general.attributes
attributes:
check_mode:
support: none
diff_mode:
support: none
options:
arguments:
description:
- Specifies arguments for facter.
type: list
elements: str
requirements:
- facter
- ruby-json
author:
- Ansible Core Team
- Michael DeHaan
"""
EXAMPLES = r"""
# Example command-line invocation
# ansible www.example.net -m facter
- name: Execute facter no arguments
community.general.facter:
- name: Execute facter with arguments
community.general.facter:
arguments:
- -p
- system_uptime
- timezone
- is_virtual
"""
import json
from ansible.module_utils.basic import AnsibleModule
def main():
module = AnsibleModule(
argument_spec=dict(
arguments=dict(type='list', elements='str')
)
)
facter_path = module.get_bin_path(
'facter',
opt_dirs=['/opt/puppetlabs/bin'])
cmd = [facter_path, "--json"]
if module.params['arguments']:
cmd += module.params['arguments']
rc, out, err = module.run_command(cmd, check_rc=True)
module.exit_json(**json.loads(out))
if __name__ == '__main__':
main()

View file

@ -13,7 +13,7 @@ DOCUMENTATION = r"""
module: ohai
short_description: Returns inventory data from I(Ohai)
description:
- Similar to the M(community.general.facter) module, this runs the I(Ohai) discovery program (U(https://docs.chef.io/ohai.html))
- Similar to the M(community.general.facter_facts) module, this runs the I(Ohai) discovery program (U(https://docs.chef.io/ohai.html))
on the remote host and returns JSON inventory data. I(Ohai) data is a bit more verbose and nested than I(facter).
extends_documentation_fragment:
- community.general.attributes

View file

@ -43,10 +43,7 @@ options:
force:
description:
- The C(opkg --force) parameter used.
- State V("") is deprecated and will be removed in community.general 12.0.0. Please omit the parameter O(force) to obtain
the same behavior.
choices:
- ""
- "depends"
- "maintainer"
- "reinstall"
@ -128,7 +125,7 @@ class Opkg(StateModuleHelper):
argument_spec=dict(
name=dict(aliases=["pkg"], required=True, type="list", elements="str"),
state=dict(default="present", choices=["present", "installed", "absent", "removed"]),
force=dict(choices=["", "depends", "maintainer", "reinstall", "overwrite", "downgrade", "space",
force=dict(choices=["depends", "maintainer", "reinstall", "overwrite", "downgrade", "space",
"postinstall", "remove", "checksum", "removal-of-dependent-packages"]),
update_cache=dict(default=False, type='bool'),
executable=dict(type="path"),
@ -147,15 +144,6 @@ class Opkg(StateModuleHelper):
removed="remove",
)
def _force(value):
# 12.0.0 function _force() to be removed entirely
if value == "":
self.deprecate('Value "" is deprecated. Simply omit the parameter "force" to prevent any --force-X argument when running opkg',
version="12.0.0",
collection_name="community.general")
value = None
return cmd_runner_fmt.as_optval("--force-")(value, ctx_ignore_none=True)
dir, cmd = os.path.split(self.vars.executable) if self.vars.executable else (None, "opkg")
self.runner = CmdRunner(
@ -164,7 +152,7 @@ class Opkg(StateModuleHelper):
arg_formats=dict(
package=cmd_runner_fmt.as_list(),
state=cmd_runner_fmt.as_map(state_map),
force=cmd_runner_fmt.as_func(_force), # 12.0.0 replace with cmd_runner_fmt.as_optval("--force-")
force=cmd_runner_fmt.as_optval("--force-"),
update_cache=cmd_runner_fmt.as_bool("update"),
version=cmd_runner_fmt.as_fixed("--version"),
),

View file

@ -30,6 +30,7 @@ options:
- The value V(maintenance) has been added in community.general 11.1.0.
choices: [cleanup, offline, online, restart, maintenance]
type: str
required: true
name:
description:
- Specify which node of the cluster you want to manage. V(null) == the cluster status itself, V(all) == check the status
@ -74,7 +75,7 @@ class PacemakerCluster(StateModuleHelper):
module = dict(
argument_spec=dict(
state=dict(type='str', choices=[
'cleanup', 'offline', 'online', 'restart', 'maintenance']),
'cleanup', 'offline', 'online', 'restart', 'maintenance'], required=True),
name=dict(type='str', aliases=['node']),
timeout=dict(type='int', default=300),
force=dict(type='bool', default=True)
@ -106,13 +107,6 @@ class PacemakerCluster(StateModuleHelper):
collection_name='community.general'
)
if not self.module.params['state']:
self.module.deprecate(
'Parameter "state" values not set is being deprecated. Make sure to provide a value for "state"',
version='12.0.0',
collection_name='community.general'
)
def __quit_module__(self):
self.vars.set('value', self._get()['out'])

View file

@ -143,10 +143,10 @@ options:
prefixes only cover a small set of the prefixes that should not have a V(#) prepended. Since an exact condition which
O(channel) values must not have the V(#) prefix is not known, the value V(auto) for this option is deprecated in the
future. It is best to explicitly set O(prepend_hash=always) or O(prepend_hash=never) to obtain the needed behavior.
- The B(current default) is V(auto), which has been B(deprecated) since community.general 10.2.0. It is going to change
to V(never) in community.general 12.0.0. To prevent deprecation warnings you can explicitly set O(prepend_hash) to
the value you want. We suggest to only use V(always) or V(never), but not V(auto), when explicitly setting a value.
# when the default changes in community.general 12.0.0, add deprecation for the `auto` value for 14.0.0
- Before community.general 12.0.0, the default was V(auto). It has been deprecated since community.general 10.2.0.
- Note that V(auto) will be deprecated in a future version.
# TODO: Deprecate 'auto' in community.general 13.0.0
default: never
choices:
- 'always'
- 'never'
@ -466,7 +466,7 @@ def main():
attachments=dict(type='list', elements='dict'),
blocks=dict(type='list', elements='dict'),
message_id=dict(type='str'),
prepend_hash=dict(type='str', choices=['always', 'never', 'auto']),
prepend_hash=dict(type='str', choices=['always', 'never', 'auto'], default='never'),
),
supports_check_mode=True,
)
@ -487,15 +487,6 @@ def main():
message_id = module.params['message_id']
prepend_hash = module.params['prepend_hash']
if prepend_hash is None:
module.deprecate(
"The default value 'auto' for 'prepend_hash' is deprecated and will change to 'never' in community.general 12.0.0."
" You can explicitly set 'prepend_hash' in your task to avoid this deprecation warning",
version="12.0.0",
collection_name="community.general",
)
prepend_hash = 'auto'
color_choices = ['normal', 'good', 'warning', 'danger']
if color not in color_choices and not is_valid_hex_color(color):
module.fail_json(msg="Color value specified should be either one of %r "

View file

@ -1,6 +0,0 @@
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
azp/posix/1
needs/target/callback

View file

@ -1,7 +0,0 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
dependencies:
- setup_remote_tmp_dir

View file

@ -1,143 +0,0 @@
---
####################################################################
# WARNING: These are designed specifically for Ansible tests #
# and should not be used as examples of how to write Ansible roles #
####################################################################
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- name: Write vault password to disk
ansible.builtin.copy:
dest: "{{ remote_tmp_dir }}/vault-password"
content: asdf
- name: Run tests
include_role:
name: callback
vars:
tests:
- name: Basic run
environment:
ANSIBLE_NOCOLOR: 'true'
ANSIBLE_FORCE_COLOR: 'false'
ANSIBLE_STDOUT_CALLBACK: community.general.yaml
playbook: |
- hosts: testhost
gather_facts: false
tasks:
- name: Sample task name
debug:
msg: sample debug msg
expected_output:
- ""
- "PLAY [testhost] ****************************************************************"
- ""
- "TASK [Sample task name] ********************************************************"
- "ok: [testhost] => "
- " msg: sample debug msg"
- ""
- "PLAY RECAP *********************************************************************"
- "testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
- name: Test umlauts in multiline
environment:
ANSIBLE_NOCOLOR: 'true'
ANSIBLE_FORCE_COLOR: 'false'
ANSIBLE_STDOUT_CALLBACK: community.general.yaml
playbook: |
- hosts: testhost
gather_facts: false
tasks:
- name: Umlaut output
debug:
msg: "äöü\néêè\nßï☺"
expected_output:
- ""
- "PLAY [testhost] ****************************************************************"
- ""
- "TASK [Umlaut output] ***********************************************************"
- "ok: [testhost] => "
- " msg: |-"
- " äöü"
- " éêè"
- " ßï☺"
- ""
- "PLAY RECAP *********************************************************************"
- "testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
- name: Test to_yaml
environment:
ANSIBLE_NOCOLOR: 'true'
ANSIBLE_FORCE_COLOR: 'false'
ANSIBLE_STDOUT_CALLBACK: community.general.yaml
playbook: !unsafe |
- hosts: testhost
gather_facts: false
vars:
data: |
line 1
line 2
line 3
tasks:
- name: Test to_yaml
debug:
msg: "{{ data | to_yaml }}"
expected_output:
- ""
- "PLAY [testhost] ****************************************************************"
- ""
- "TASK [Test to_yaml] ************************************************************"
- "ok: [testhost] => "
- " msg: |-"
- " 'line 1"
- " "
- " line 2"
- " "
- " line 3"
- " "
- " '"
- ""
- "PLAY RECAP *********************************************************************"
- "testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
- name: Some more fun with data tagging
environment:
ANSIBLE_NOCOLOR: 'true'
ANSIBLE_FORCE_COLOR: 'false'
ANSIBLE_STDOUT_CALLBACK: community.general.yaml
extra_cli_arguments: "--vault-password-file {{ remote_tmp_dir }}/vault-password"
playbook: !unsafe |
- hosts: testhost
gather_facts: false
vars:
foo: bar
baz: !vault |
$ANSIBLE_VAULT;1.1;AES256
30393064316433636636373336363538663034643135363938646665393661353833633865313765
3835366434646339313337663335393865336163663434310a316161313662666466333332353731
64663064366461643162666137303737643164376134303034306366383830336232363837636638
3830653338626130360a313639623231353931356563313065373661303262646337383534663932
64353461663065333362346264326335373032313333343539646661656634653138646332313639
3566313765626464613734623664663266336237646139373935
tasks:
- name: Test regular string
debug:
var: foo
- name: Test vaulted string
debug:
var: baz
expected_output:
- ""
- "PLAY [testhost] ****************************************************************"
- ""
- "TASK [Test regular string] *****************************************************"
- "ok: [testhost] => "
- " foo: bar"
- ""
- "TASK [Test vaulted string] *****************************************************"
- "ok: [testhost] => "
- " baz: aBcDeFgHiJkLmNoPqRsTuVwXyZ012345"
- ""
- "PLAY RECAP *********************************************************************"
- "testhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "

View file

@ -205,7 +205,7 @@ TC_RUNNER = dict(
results="0-/-ni-/-nu"
),
),
aa_bb_ignore_none_with_none=(
aa_bb_with_none=(
dict(
args_bundle=dict(
aa=dict(type="int", value=49, fmt_func=cmd_runner_fmt.as_opt_eq_val, fmt_arg="--answer"),
@ -214,7 +214,6 @@ TC_RUNNER = dict(
runner_init_args=dict(default_args_order=['bb', 'aa']),
runner_ctx_args=dict(
args_order=['aa', 'bb'],
ignore_value_none=True, # default
),
),
dict(runner_ctx_run_args=dict(bb=None), rc=0, out="ni", err="nu"),
@ -224,25 +223,6 @@ TC_RUNNER = dict(
),
),
),
aa_bb_ignore_not_none_with_none=(
dict(
args_bundle=dict(
aa=dict(type="int", value=49, fmt_func=cmd_runner_fmt.as_opt_eq_val, fmt_arg="--answer"),
bb=dict(fmt_func=cmd_runner_fmt.as_bool, fmt_arg="--bb-here"),
),
runner_init_args=dict(default_args_order=['bb', 'aa']),
runner_ctx_args=dict(
args_order=['aa', 'bb'],
ignore_value_none=False,
),
),
dict(runner_ctx_run_args=dict(aa=None, bb=True), rc=0, out="ni", err="nu"),
dict(
run_info=dict(
cmd=['/mock/bin/testing', '--answer=None', '--bb-here'],
),
),
),
aa_bb_fixed=(
dict(
args_bundle=dict(

View file

@ -23,12 +23,6 @@ CAUSE_CHG_DECO_PARAMS = ['deco_args', 'expect_exception', 'expect_changed']
CAUSE_CHG_DECO = dict(
none_succ=dict(deco_args={}, expect_exception=False, expect_changed=None),
none_fail=dict(deco_args={}, expect_exception=True, expect_changed=None),
onsucc_succ=dict(deco_args=dict(on_success=True), expect_exception=False, expect_changed=True),
onsucc_fail=dict(deco_args=dict(on_success=True), expect_exception=True, expect_changed=None),
onfail_succ=dict(deco_args=dict(on_failure=True), expect_exception=False, expect_changed=None),
onfail_fail=dict(deco_args=dict(on_failure=True), expect_exception=True, expect_changed=True),
onboth_succ=dict(deco_args=dict(on_success=True, on_failure=True), expect_exception=False, expect_changed=True),
onboth_fail=dict(deco_args=dict(on_success=True, on_failure=True), expect_exception=True, expect_changed=True),
whensucc_succ=dict(deco_args=dict(when="success"), expect_exception=False, expect_changed=True),
whensucc_fail=dict(deco_args=dict(when="success"), expect_exception=True, expect_changed=None),
whenfail_succ=dict(deco_args=dict(when="failure"), expect_exception=False, expect_changed=None),