Compare commits

...

No commits in common. "c8s" and "c8-beta" have entirely different histories.
c8s ... c8-beta

10 changed files with 16 additions and 391 deletions

8
.ansible-core.metadata Normal file
View File

@ -0,0 +1,8 @@
560f248ccb0b98256c5b50c86a002c2c1e57edb6 SOURCES/Jinja2-3.1.2.tar.gz
192b9f6598e1ae036301f72781973c6f46e50aa2 SOURCES/MarkupSafe-2.1.2.tar.gz
4ae417bcadf07c709e0819f489e08248d9a3971b SOURCES/ansible-core-2.16.3.tar.gz
7cb698b495d479255d56642ccd8d402dcbd7fe97 SOURCES/ansible-documentation-2.16.3.tar.gz
6e53dd117d09e6cd5d8596bf99a0dcbb202b8aad SOURCES/docutils-0.20.1.tar.gz
b8caff3bec760723db6af4092c68075e22bdb769 SOURCES/packaging-21.3.tar.gz
96464a9452e95e980c3a1fad1020fe00e29c0ae3 SOURCES/pyparsing-3.0.7.tar.gz
2f587f4095bb70039c1d995635ae55af8eab08dc SOURCES/resolvelib-1.0.1.tar.gz

34
.gitignore vendored
View File

@ -1,28 +1,8 @@
SOURCES/Jinja2-3.1.2.tar.gz
SOURCES/MarkupSafe-2.1.0.tar.gz
SOURCES/ansible-core-2.14.2.tar.gz
SOURCES/packaging-20.4.tar.gz
SOURCES/pyparsing-2.4.7.tar.gz
SOURCES/resolvelib-0.5.4.tar.gz
/Jinja2-3.1.2.tar.gz
/MarkupSafe-2.1.0.tar.gz
/ansible-core-2.14.2.tar.gz
/packaging-20.4.tar.gz
/pyparsing-2.4.7.tar.gz
/resolvelib-0.5.4.tar.gz
/MarkupSafe-2.1.2.tar.gz
/ansible-core-2.15.0.tar.gz
/packaging-21.3.tar.gz
/pyparsing-3.0.7.tar.gz
/resolvelib-1.0.1.tar.gz
/ansible-core-2.15.1.tar.gz
/ansible-core-2.15.2.tar.gz
/ansible-core-2.15.3.tar.gz
/ansible-documentation-2.15.3.tar.gz
/docutils-0.20.1.tar.gz
/ansible-core-2.16.1.tar.gz
/ansible-documentation-2.16.1.tar.gz
/ansible-core-2.16.2.tar.gz
/ansible-documentation-2.16.2.tar.gz
/ansible-core-2.16.3.tar.gz
/ansible-documentation-2.16.3.tar.gz
SOURCES/MarkupSafe-2.1.2.tar.gz
SOURCES/ansible-core-2.16.3.tar.gz
SOURCES/ansible-documentation-2.16.3.tar.gz
SOURCES/docutils-0.20.1.tar.gz
SOURCES/packaging-21.3.tar.gz
SOURCES/pyparsing-3.0.7.tar.gz
SOURCES/resolvelib-1.0.1.tar.gz

View File

@ -38,7 +38,7 @@
Name: ansible-core
Summary: SSH-based configuration management, deployment, and task execution system
Version: 2.16.3
Release: 3%{?dist}
Release: 2%{?dist}
ExcludeArch: i686
Group: Development/Libraries
@ -59,11 +59,6 @@ Source8: https://sourceforge.net/projects/docutils/files/docutils/%{docutils_ver
Patch0: remove-bundled-deps-from-requirements.patch
%if 0%{!?centos:1} && 0%{?rhel}
Source99: telemetry.py
Patch99: telemetry.patch
%endif
URL: http://ansible.com
# We conflict old ansible, and any version of ansible-base.
@ -128,10 +123,6 @@ developed for ansible.
# Fix all Python shebangs recursively in ansible-test
%{py3_shebang_fix} test/lib/ansible_test
%if 0%{!?centos:1} && 0%{?rhel}
%patch -P99 -p1
%endif
%build
%{py3_build}
@ -186,12 +177,6 @@ mkdir -p %{buildroot}%{_sysconfdir}/ansible/roles/
cp ../ansible-documentation-%{version}/examples/hosts %{buildroot}%{_sysconfdir}/ansible/
cp ../ansible-documentation-%{version}/examples/ansible.cfg %{buildroot}%{_sysconfdir}/ansible/
%if 0%{!?centos:1} && 0%{?rhel}
mkdir -p %{buildroot}%{_datadir}/ansible/telemetry
cp %{SOURCE99} %{buildroot}%{_datadir}/ansible/telemetry/
%py_byte_compile %{__python3} %{buildroot}%{_datadir}/ansible/telemetry/telemetry.py
%endif
mkdir -p %{buildroot}/%{_mandir}/man1/
mkdir -p docs/man/man1
@ -225,9 +210,6 @@ strip --strip-unneeded %{vendor_path}/markupsafe/_speedups%{python3_ext_suffix}
%{python3_sitelib}/ansible_test
%changelog
* Wed Jul 29 2026 Dimitri Savineau <dsavinea@redhat.com> - 2.16.3-3
- Add telemetry for RHEL (RHEL-219532)
* Mon Feb 05 2024 Dimitri Savineau <dsavinea@redhat.com> - 2.16.3-2
- rebuild with python 3.12 (RHEL-24141)

View File

@ -1,6 +0,0 @@
--- !Policy
product_versions:
- rhel-8
decision_context: osci_compose_gate
rules:
- !PassingTestCaseRule {test_case_name: osci.brew-build.tier0.functional}

View File

@ -1,8 +0,0 @@
SHA512 (ansible-core-2.16.3.tar.gz) = 62b7d23d3d639f118a4b87dccc02ec5f373fd56ae6c5fb56c8adf0818d0f5bbf3b6de47a29da9ef2d8c3f4b7e3a99978677bc9bfda1eb4cb9640b79abb763f77
SHA512 (ansible-documentation-2.16.3.tar.gz) = c073b0b961e38bee560be78e2c12534facec891f6e375df14fdcaf99241f711cf6955ee58b936f7f23ab62a732d2dbde5fd279976989be06e747c2bf3db41661
SHA512 (docutils-0.20.1.tar.gz) = a0ddca315d03677003036d6a8052ac96fbd3fcc4508564938ea684d79bedb4d322d83449c7b26e55b19b0aadd6e46ca9ac409bb16279a20f06c70e9c15ef5eb0
SHA512 (Jinja2-3.1.2.tar.gz) = 5dfe122c1beef5305b34d25f22f96607bd3a6cba098b03091850ea36fefe62b645a7218d7584b35bea252393ac922c9bb3654a9e90f23bcfb273e811fcf2f2c1
SHA512 (MarkupSafe-2.1.2.tar.gz) = 84dbeddaf2df713b3cce94eb64876fea8f80c608e25130c18e4691be2b1dea56df8b772d26c0caca88231ef795125eb9678210c33bf20518c18e3047912ddb4b
SHA512 (packaging-21.3.tar.gz) = 2e3aa276a4229ac7dc0654d586799473ced9761a83aa4159660d37ae1a2a8f30e987248dd0e260e2834106b589f259a57ce9936eef0dcc3c430a99ac6b663e05
SHA512 (pyparsing-3.0.7.tar.gz) = 1e692f4cdaa6b6e8ca2729d0a3e2ba16d978f1957c538b6de3a4220ec7d996bdbe87c41c43abab851fffa3b0498a05841373e435602917b8c095042e273badb5
SHA512 (resolvelib-1.0.1.tar.gz) = 52c872fb2a22c47de022a661dc4d8de8c6af450f1cff6f2b99cd91bf7eccae5b6ee223793f50b9679c1c6caedbd8bb63330915ee6f10533b1a0ed239d068b36f

View File

@ -1,13 +0,0 @@
diff --git a/lib/ansible/plugins/loader.py b/lib/ansible/plugins/loader.py
index f3252d7142..1e4d3bca38 100644
--- a/lib/ansible/plugins/loader.py
+++ b/lib/ansible/plugins/loader.py
@@ -1532,7 +1532,7 @@ cache_loader = PluginLoader(
callback_loader = PluginLoader(
'CallbackModule',
'ansible.plugins.callback',
- C.DEFAULT_CALLBACK_PLUGIN_PATH,
+ C.DEFAULT_CALLBACK_PLUGIN_PATH + ['/usr/share/ansible/telemetry'],
'callback_plugins',
)

View File

@ -1,302 +0,0 @@
#! /usr/libexec/platform-python
# Copyright: Contributors to the Ansible project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
DOCUMENTATION = '''
name: telemetry
short_description: Track various telemetry related data and store in journald
description:
- Track various telemetry related data and store in journald
type: aggregate
options:
bypass_insights_check:
name: Bypass Insights Check
description: Bypass check to see if insights-client is active
default: false
type: bool
env:
- name: TELEMETRY_BYPASS_INSIGHTS_CHECK
notes:
- The file can also be executed directly from the CLI to retrieve
the stored telemetry data from journald
'''
import contextlib
import ctypes
import datetime
import functools
import importlib.util
import json
import os
import pathlib
import subprocess
import sys
import uuid
from collections import Counter, defaultdict
if __name__ == '__main__':
# When run as a script via insights-client, these are not needed
CallbackBase = object
Display = None
else:
from ansible.executor.task_result import TaskResult
from ansible.module_utils.common.yaml import yaml_load
from ansible.plugins.callback import CallbackBase
from ansible.plugins.loader import connection_loader
from ansible.release import __version__ as ansible_version
from ansible.utils.display import Display
journal_sendv = None
try:
from systemd import journal
journal_sendv = journal.sendv
except ImportError:
# When invoked using the non-system python
# the systemd python bindings are not available
with contextlib.suppress(AttributeError, OSError):
_libsysetmd = ctypes.CDLL('libsystemd.so.0')
sd_journal_send = _libsysetmd.sd_journal_send
def journal_sendv(*args):
b_args = [ctypes.c_char_p(a.encode()) for a in args] + [None]
sd_journal_send(*b_args)
if sys.version_info >= (3, 10):
from importlib.resources import files
else:
# importlib.resources below Python 3.10 doesn't support
# custom loaders, this is not a full featured replacement
# but suffices for the needs of this plugin
def files(name):
spec = importlib.util.find_spec(name)
if spec is None:
raise ImportError(name)
origin = pathlib.Path(spec.origin)
if origin.name == '__synthetic__':
origin = origin.parent
return origin
if Display:
display = Display()
_CORE_SYN_COLLECTIONS = frozenset((
'ansible.builtin',
'ansible.legacy',
))
_CORE_FACT_MODULES = frozenset((
'setup',
'ansible.builtin.setup',
'ansible.legacy.setup',
'gather_facts',
'ansible.builtin.gather_facts',
'ansible.legacy.gather_facts',
))
_ANSIBLE_TELEMETRY_MESSAGE_ID = uuid.UUID('73df9e03d8c6473eb811065c4ebc370a')
@functools.lru_cache(maxsize=None)
def _get_connection_fqcn(task, host):
connection = host.vars.get('ansible_connection')
if not connection:
connection = task.connection
is_connection_fqcn = '.' in connection
if is_connection_fqcn:
return connection
return connection_loader.get_with_context(
connection,
class_only=True,
collection_list=task.collections,
).plugin_load_context.resolved_fqcn
class CallbackModule(CallbackBase):
CALLBACK_VERSION = 2.0
CALLBACK_TYPE = 'aggregate'
CALLBACK_NAME = 'telemetry'
def __init__(self, *args, **kwargs):
self.wants_implicit_tasks = False
self.disabled = False
self._telemetry = {
'collections': defaultdict(
lambda: {
'resources': defaultdict(
lambda: defaultdict(lambda: {
'count': 0,
})
),
'version': '*',
},
),
}
self._hosts = set()
self._os = {}
self._conn_cache = {}
def _is_insights_client_active(self):
if self.get_option('bypass_insights_check'):
return True
if not os.path.exists('/etc/insights-client/.registered'):
return False
with contextlib.suppress(subprocess.CalledProcessError):
subprocess.run(
['systemctl', 'is-active', '--quiet', 'insights-client.timer'],
capture_output=True,
check=True,
)
return True
return False
def _set_disabled(self):
if not self._is_insights_client_active():
return True
if journal_sendv is None:
return True
return False
def set_options(self, task_keys=None, var_options=None, direct=None):
super().set_options(task_keys=task_keys, var_options=var_options, direct=direct)
self.disabled = self._set_disabled()
def _track_os(self, host_name, result):
if host_name in self._os:
return
try:
af = result.get('ansible_facts')
except AttributeError:
return
if not af:
return
try:
os_name = '%(ansible_distribution)s-%(ansible_distribution_version)s' % af
except KeyError:
return
else:
self._os[host_name] = os_name
def _handle_result(self, *args, **kwargs):
if not args:
return
result = args[0]
if not isinstance(result, TaskResult):
return
host = result._host
host_name = host.get_name()
task = result._task
role = task._role
self._hosts.add(host_name)
action = task.resolved_action
action_collection = None
if action and '.' in action:
action_collection = '.'.join(action.split('.', 2)[:2])
if action in _CORE_FACT_MODULES:
self._track_os(host_name, result._result)
role_collection = None
role_name = None if not role else role.get_name()
if role and '.' in role_name:
role_collection = '.'.join(role_name.split('.', 2)[:2])
connection_collection = None
connection = _get_connection_fqcn(task, host)
if '.' in connection:
connection_collection = '.'.join(connection.split('.')[:2])
collections = self._telemetry['collections']
for resource, collection, name in (('action', action_collection, action),
('role', role_collection, role_name),
('connection', connection_collection, connection)):
if not collection:
continue
collections[collection]['resources'][resource][name]['count'] += 1
# v2_on_file_diff = _handle_result
v2_runner_item_on_failed = _handle_result
v2_runner_item_on_ok = _handle_result
v2_runner_item_on_skipped = _handle_result
v2_runner_on_async_failed = _handle_result
v2_runner_on_async_ok = _handle_result
v2_runner_on_async_poll = _handle_result
v2_runner_on_failed = _handle_result
v2_runner_on_ok = _handle_result
v2_runner_on_skipped = _handle_result
v2_runner_on_unreachable = _handle_result
v2_runner_retry = _handle_result
def v2_playbook_on_stats(self, stats):
self._telemetry['ansible_core'] = {
'version': ansible_version,
}
self._telemetry['hosts'] = {
'count': len(self._hosts),
'os': Counter(self._os.values()),
}
for collection in self._telemetry['collections']:
if collection in _CORE_SYN_COLLECTIONS:
continue
cpath = files('ansible_collections.%s' % collection)
for candidate in ('METADATA.json', 'galaxy.yml'):
mdfile = cpath.joinpath(candidate)
if mdfile.exists():
self._telemetry['collections'][collection]['version'] = yaml_load(
mdfile.read_text()
).get('version', '*')
break
with contextlib.suppress(Exception):
self._write_journal()
def _write_journal(self):
journal_sendv(
'MESSAGE=%s' % json.dumps(self._telemetry, separators=(',', ':')),
'MESSAGE_ID=%s' % _ANSIBLE_TELEMETRY_MESSAGE_ID.hex,
'ANSIBLE_TELEMETRY=core',
'ANSIBLE_TELEMETRY_ID=%s' % uuid.uuid4().hex,
)
@contextlib.contextmanager
def _get_journal_reader(seek=None):
with journal.Reader() as j:
if seek:
j.seek_realtime(seek)
j.add_match('MESSAGE_ID=%s' % _ANSIBLE_TELEMETRY_MESSAGE_ID.hex)
j.add_match('ANSIBLE_TELEMETRY=core')
yield j
def main():
lastupload_file = pathlib.Path('/etc/insights-client/.lastupload')
lastupload = None
with contextlib.suppress(ValueError, OSError):
lastupload = datetime.datetime.strptime(
lastupload_file.read_text(),
'%Y-%m-%dT%H:%M:%S.%f'
)
with _get_journal_reader(lastupload) as j:
for entry in j:
print(entry['MESSAGE'])
if __name__ == '__main__':
main()

View File

@ -1,16 +0,0 @@
---
- hosts: localhost
gather_facts: yes
roles:
- role: standard-test-basic
tags:
- classic
tests:
- simple:
dir: .
run: /usr/bin/ansible localhost -m dnf -a "list=installed"
# tasks:
# This is only used as part of rpm-ostree which has extensive tests
# and there is no point to testing it separately.
# - name: true
# shell: true