Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package ansible-core for openSUSE:Factory checked in at 2025-02-25 16:58:26 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/ansible-core (Old) and /work/SRC/openSUSE:Factory/.ansible-core.new.1873 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ansible-core" Tue Feb 25 16:58:26 2025 rev:39 rq:1248285 version:2.18.3 Changes: -------- --- /work/SRC/openSUSE:Factory/ansible-core/ansible-core.changes 2025-01-29 16:18:46.492362324 +0100 +++ /work/SRC/openSUSE:Factory/.ansible-core.new.1873/ansible-core.changes 2025-02-25 16:58:32.690426308 +0100 @@ -1,0 +2,17 @@ +Tue Feb 25 06:42:58 UTC 2025 - Johannes Kastl <opensuse_buildserv...@ojkastl.de> + +- update to 2.18.3: + * Minor Changes + - ansible-test - Automatically retry HTTP GET/PUT/DELETE + requests on exceptions. + - ansible-test - Use Python's urllib instead of curl for HTTP + requests. + * Bugfixes + - include_vars - fixed erroneous warning if an unreserved + variable name contains a single character that matches a + reserved variable. (#84623) + - linear strategy - fix executing end_role meta tasks for each + host, instead of handling these as implicit run_once tasks + (#84660). + +------------------------------------------------------------------- Old: ---- ansible_core-2.18.2.tar.gz ansible_core-2.18.2.tar.gz.sha256 New: ---- ansible_core-2.18.3.tar.gz ansible_core-2.18.3.tar.gz.sha256 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ ansible-core.spec ++++++ --- /var/tmp/diff_new_pack.A7Rf7O/_old 2025-02-25 16:58:34.178488657 +0100 +++ /var/tmp/diff_new_pack.A7Rf7O/_new 2025-02-25 16:58:34.186488993 +0100 @@ -43,7 +43,7 @@ %endif Name: ansible-core -Version: 2.18.2 +Version: 2.18.3 Release: 0 Summary: Radically simple IT automation License: GPL-3.0-or-later ++++++ ansible_core-2.18.2.tar.gz -> ansible_core-2.18.3.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_core-2.18.2/PKG-INFO new/ansible_core-2.18.3/PKG-INFO --- old/ansible_core-2.18.2/PKG-INFO 2025-01-27 20:45:24.000000000 +0100 +++ new/ansible_core-2.18.3/PKG-INFO 2025-02-24 20:31:36.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.2 Name: ansible-core -Version: 2.18.2 +Version: 2.18.3 Summary: Radically simple IT automation Author: Ansible Project Project-URL: Homepage, https://ansible.com/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_core-2.18.2/ansible_core.egg-info/PKG-INFO new/ansible_core-2.18.3/ansible_core.egg-info/PKG-INFO --- old/ansible_core-2.18.2/ansible_core.egg-info/PKG-INFO 2025-01-27 20:45:24.000000000 +0100 +++ new/ansible_core-2.18.3/ansible_core.egg-info/PKG-INFO 2025-02-24 20:31:36.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.2 Name: ansible-core -Version: 2.18.2 +Version: 2.18.3 Summary: Radically simple IT automation Author: Ansible Project Project-URL: Homepage, https://ansible.com/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_core-2.18.2/ansible_core.egg-info/SOURCES.txt new/ansible_core-2.18.3/ansible_core.egg-info/SOURCES.txt --- old/ansible_core-2.18.2/ansible_core.egg-info/SOURCES.txt 2025-01-27 20:45:24.000000000 +0100 +++ new/ansible_core-2.18.3/ansible_core.egg-info/SOURCES.txt 2025-02-24 20:31:36.000000000 +0100 @@ -3915,11 +3915,13 @@ test/integration/targets/var_precedence/vars/test_var_precedence.yml test/integration/targets/var_reserved/aliases test/integration/targets/var_reserved/tasks/block_vars.yml +test/integration/targets/var_reserved/tasks/include_vars.yml test/integration/targets/var_reserved/tasks/main.yml test/integration/targets/var_reserved/tasks/play_vars.yml test/integration/targets/var_reserved/tasks/set_fact.yml test/integration/targets/var_reserved/tasks/task_vars.yml test/integration/targets/var_reserved/tasks/task_vars_used.yml +test/integration/targets/var_reserved/vars/set_host_variable.yml test/integration/targets/var_templating/aliases test/integration/targets/var_templating/ansible_debug_template.j2 test/integration/targets/var_templating/runme.sh diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_core-2.18.2/changelogs/CHANGELOG-v2.18.rst new/ansible_core-2.18.3/changelogs/CHANGELOG-v2.18.rst --- old/ansible_core-2.18.2/changelogs/CHANGELOG-v2.18.rst 2025-01-27 20:45:24.000000000 +0100 +++ new/ansible_core-2.18.3/changelogs/CHANGELOG-v2.18.rst 2025-02-24 20:31:36.000000000 +0100 @@ -4,6 +4,27 @@ .. contents:: Topics +v2.18.3 +======= + +Release Summary +--------------- + +| Release Date: 2025-02-24 +| `Porting Guide <https://docs.ansible.com/ansible-core/2.18/porting_guides/porting_guide_core_2.18.html>`__ + +Minor Changes +------------- + +- ansible-test - Automatically retry HTTP GET/PUT/DELETE requests on exceptions. +- ansible-test - Use Python's ``urllib`` instead of ``curl`` for HTTP requests. + +Bugfixes +-------- + +- include_vars - fixed erroneous warning if an unreserved variable name contains a single character that matches a reserved variable. (https://github.com/ansible/ansible/issues/84623) +- linear strategy - fix executing ``end_role`` meta tasks for each host, instead of handling these as implicit run_once tasks (https://github.com/ansible/ansible/issues/84660). + v2.18.2 ======= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_core-2.18.2/changelogs/changelog.yaml new/ansible_core-2.18.3/changelogs/changelog.yaml --- old/ansible_core-2.18.2/changelogs/changelog.yaml 2025-01-27 20:45:24.000000000 +0100 +++ new/ansible_core-2.18.3/changelogs/changelog.yaml 2025-02-24 20:31:36.000000000 +0100 @@ -710,3 +710,36 @@ - ssh-clixml.yml - vault_cli_fix.yml release_date: '2025-01-20' + 2.18.3: + changes: + release_summary: '| Release Date: 2025-02-24 + + | `Porting Guide <https://docs.ansible.com/ansible-core/2.18/porting_guides/porting_guide_core_2.18.html>`__ + + ' + codename: Fool in the Rain + fragments: + - 2.18.3_summary.yaml + release_date: '2025-02-24' + 2.18.3rc1: + changes: + bugfixes: + - include_vars - fixed erroneous warning if an unreserved variable name contains + a single character that matches a reserved variable. (https://github.com/ansible/ansible/issues/84623) + - linear strategy - fix executing ``end_role`` meta tasks for each host, instead + of handling these as implicit run_once tasks (https://github.com/ansible/ansible/issues/84660). + minor_changes: + - ansible-test - Automatically retry HTTP GET/PUT/DELETE requests on exceptions. + - ansible-test - Use Python's ``urllib`` instead of ``curl`` for HTTP requests. + release_summary: '| Release Date: 2025-02-17 + + | `Porting Guide <https://docs.ansible.com/ansible-core/2.18/porting_guides/porting_guide_core_2.18.html>`__ + + ' + codename: Fool in the Rain + fragments: + - 2.18.3rc1_summary.yaml + - 84660-fix-meta-end_role-linear-strategy.yml + - ansible-test-curl.yml + - fix-include_vars-reserved-warning.yml + release_date: '2025-02-17' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_core-2.18.2/lib/ansible/module_utils/ansible_release.py new/ansible_core-2.18.3/lib/ansible/module_utils/ansible_release.py --- old/ansible_core-2.18.2/lib/ansible/module_utils/ansible_release.py 2025-01-27 20:45:24.000000000 +0100 +++ new/ansible_core-2.18.3/lib/ansible/module_utils/ansible_release.py 2025-02-24 20:31:36.000000000 +0100 @@ -17,6 +17,6 @@ from __future__ import annotations -__version__ = '2.18.2' +__version__ = '2.18.3' __author__ = 'Ansible, Inc.' __codename__ = "Fool in the Rain" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_core-2.18.2/lib/ansible/modules/meta.py new/ansible_core-2.18.3/lib/ansible/modules/meta.py --- old/ansible_core-2.18.2/lib/ansible/modules/meta.py 2025-01-27 20:45:24.000000000 +0100 +++ new/ansible_core-2.18.3/lib/ansible/modules/meta.py 2025-02-24 20:31:36.000000000 +0100 @@ -22,8 +22,13 @@ points to implicitly trigger handler runs (after pre/post tasks, the final role execution, and the main tasks section of your plays). - V(refresh_inventory) (added in Ansible 2.0) forces the reload of the inventory, which in the case of dynamic inventory scripts means they will be re-executed. If the dynamic inventory script is using a cache, Ansible cannot know this and has no way of refreshing it (you can disable the cache - or, if available for your specific inventory datasource (e.g. aws), you can use the an inventory plugin instead of an inventory script). - This is mainly useful when additional hosts are created and users wish to use them instead of using the M(ansible.builtin.add_host) module. + or, if available for your specific inventory datasource (for example P(amazon.aws.aws_ec2#inventory)), you can use the an inventory plugin instead + of an inventory script). This is mainly useful when additional hosts are created and users wish to use them instead of using the + M(ansible.builtin.add_host) module. + - Note that neither V(refresh_inventory) nor the M(ansible.builtin.add_host) add hosts to the hosts the current play iterates over. + However, if needed, you can explicitly delegate tasks to new hosts with C(delegate_to). Generally, + C(delegate_to) can be used against hosts regardless of whether they are in the inventory or not, as long as + the value supplied is sufficient for the connection plugin to access the host. - V(noop) (added in Ansible 2.0) This literally does 'nothing'. It is mainly used internally and not recommended for general use. - V(clear_facts) (added in Ansible 2.1) causes the gathered facts for the hosts specified in the play's list of hosts to be cleared, including the fact cache. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_core-2.18.2/lib/ansible/plugins/strategy/linear.py new/ansible_core-2.18.3/lib/ansible/plugins/strategy/linear.py --- old/ansible_core-2.18.2/lib/ansible/plugins/strategy/linear.py 2025-01-27 20:45:24.000000000 +0100 +++ new/ansible_core-2.18.3/lib/ansible/plugins/strategy/linear.py 2025-02-24 20:31:36.000000000 +0100 @@ -162,7 +162,7 @@ # for the linear strategy, we run meta tasks just once and for # all hosts currently being iterated over rather than one host results.extend(self._execute_meta(task, play_context, iterator, host)) - if task.args.get('_raw_params', None) not in ('noop', 'reset_connection', 'end_host', 'role_complete', 'flush_handlers'): + if task.args.get('_raw_params', None) not in ('noop', 'reset_connection', 'end_host', 'role_complete', 'flush_handlers', 'end_role'): run_once = True if (task.any_errors_fatal or run_once) and not task.ignore_errors: any_errors_fatal = True diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_core-2.18.2/lib/ansible/release.py new/ansible_core-2.18.3/lib/ansible/release.py --- old/ansible_core-2.18.2/lib/ansible/release.py 2025-01-27 20:45:24.000000000 +0100 +++ new/ansible_core-2.18.3/lib/ansible/release.py 2025-02-24 20:31:36.000000000 +0100 @@ -17,6 +17,6 @@ from __future__ import annotations -__version__ = '2.18.2' +__version__ = '2.18.3' __author__ = 'Ansible, Inc.' __codename__ = "Fool in the Rain" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_core-2.18.2/lib/ansible/vars/manager.py new/ansible_core-2.18.3/lib/ansible/vars/manager.py --- old/ansible_core-2.18.2/lib/ansible/vars/manager.py 2025-01-27 20:45:24.000000000 +0100 +++ new/ansible_core-2.18.3/lib/ansible/vars/manager.py 2025-02-24 20:31:36.000000000 +0100 @@ -599,7 +599,7 @@ Sets a value in the vars_cache for a host. """ - warn_if_reserved(varname) + warn_if_reserved([varname]) if host not in self._vars_cache: self._vars_cache[host] = dict() if varname in self._vars_cache[host] and isinstance(self._vars_cache[host][varname], MutableMapping) and isinstance(value, MutableMapping): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_core-2.18.2/packaging/release.py new/ansible_core-2.18.3/packaging/release.py --- old/ansible_core-2.18.2/packaging/release.py 2025-01-27 20:45:24.000000000 +0100 +++ new/ansible_core-2.18.3/packaging/release.py 2025-02-24 20:31:36.000000000 +0100 @@ -369,6 +369,7 @@ ANSIBLE_BIN_DIR = CHECKOUT_DIR / "bin" ANSIBLE_RELEASE_FILE = ANSIBLE_DIR / "release.py" ANSIBLE_REQUIREMENTS_FILE = CHECKOUT_DIR / "requirements.txt" +ANSIBLE_CHANGELOG_REQUIREMENTS_FILE = CHECKOUT_DIR / "test/lib/ansible_test/_data/requirements/sanity.changelog.txt" ANSIBLE_PYPROJECT_TOML_FILE = CHECKOUT_DIR / "pyproject.toml" DIST_DIR = CHECKOUT_DIR / "dist" @@ -660,23 +661,8 @@ @functools.cache -def ensure_venv() -> dict[str, t.Any]: +def ensure_venv(requirements_content: str) -> dict[str, t.Any]: """Ensure the release venv is ready and return the env vars needed to use it.""" - - # TODO: consider freezing the ansible and release requirements along with their dependencies - - ansible_requirements = ANSIBLE_REQUIREMENTS_FILE.read_text() - - release_requirements = """ -build -twine -""" - - requirements_file = CHECKOUT_DIR / "test/lib/ansible_test/_data/requirements/sanity.changelog.txt" - requirements_content = requirements_file.read_text() - requirements_content += ansible_requirements - requirements_content += release_requirements - requirements_hash = hashlib.sha256(requirements_content.encode()).hexdigest()[:8] python_version = ".".join(map(str, sys.version_info[:2])) @@ -1299,7 +1285,12 @@ @command def generate_changelog() -> None: """Generate the changelog and validate the results.""" - env = ensure_venv() + changelog_requirements = ( + ANSIBLE_CHANGELOG_REQUIREMENTS_FILE.read_text() + + ANSIBLE_REQUIREMENTS_FILE.read_text() # TODO: consider pinning the ansible requirements and dependencies + ) + + env = ensure_venv(changelog_requirements) env.update( PATH=os.pathsep.join((str(ANSIBLE_BIN_DIR), env["PATH"])), PYTHONPATH=ANSIBLE_LIB_DIR, @@ -1353,7 +1344,12 @@ def build(allow_dirty: bool = False) -> None: """Build the sdist and wheel.""" version = get_ansible_version(mode=VersionMode.ALLOW_DEV_POST) - env = ensure_venv() + + # TODO: consider pinning the build requirement and its dependencies + build_requirements = """ +build +""" + env = ensure_venv(build_requirements) dirty = git("status", "--porcelain", "--untracked-files=all", capture_output=True).stdout.strip().splitlines() @@ -1450,7 +1446,12 @@ version = get_ansible_version() sdist_file = get_sdist_path(version) wheel_file = get_wheel_path(version) - env = ensure_venv() + + # TODO: consider pinning the twine requirement and its dependencies + publish_requirements = """ +twine +""" + env = ensure_venv(publish_requirements) if prompt: try: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_core-2.18.2/test/integration/targets/handlers/runme.sh new/ansible_core-2.18.3/test/integration/targets/handlers/runme.sh --- old/ansible_core-2.18.2/test/integration/targets/handlers/runme.sh 2025-01-27 20:45:24.000000000 +0100 +++ new/ansible_core-2.18.3/test/integration/targets/handlers/runme.sh 2025-02-24 20:31:36.000000000 +0100 @@ -135,9 +135,7 @@ [ "$(grep out.txt -ce 'META: noop')" = "1" ] # https://github.com/ansible/ansible/issues/46447 -set +e -test "$(ansible-playbook 46447.yml -i inventory.handlers -vv "$@" 2>&1 | grep -c 'SHOULD NOT GET HERE')" -set -e +test "$(ansible-playbook 46447.yml -i inventory.handlers "$@" 2>&1 | grep -c 'SHOULD NOT GET HERE')" = "0" # https://github.com/ansible/ansible/issues/52561 ansible-playbook 52561.yml -i inventory.handlers "$@" 2>&1 | tee out.txt diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_core-2.18.2/test/integration/targets/roles/end_role.yml new/ansible_core-2.18.3/test/integration/targets/roles/end_role.yml --- old/ansible_core-2.18.2/test/integration/targets/roles/end_role.yml 2025-01-27 20:45:24.000000000 +0100 +++ new/ansible_core-2.18.3/test/integration/targets/roles/end_role.yml 2025-02-24 20:31:36.000000000 +0100 @@ -1,4 +1,4 @@ -- hosts: localhost +- hosts: localhost,testhost gather_facts: false pre_tasks: - set_fact: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_core-2.18.2/test/integration/targets/roles/roles/end_role_inside/tasks/main.yml new/ansible_core-2.18.3/test/integration/targets/roles/roles/end_role_inside/tasks/main.yml --- old/ansible_core-2.18.2/test/integration/targets/roles/roles/end_role_inside/tasks/main.yml 2025-01-27 20:45:24.000000000 +0100 +++ new/ansible_core-2.18.3/test/integration/targets/roles/roles/end_role_inside/tasks/main.yml 2025-02-24 20:31:36.000000000 +0100 @@ -1,7 +1,8 @@ - set_fact: role_executed: "{{ role_executed|default(0)|int + 1 }}" -- command: echo +- debug: + changed_when: true notify: role_handler - meta: end_role diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_core-2.18.2/test/integration/targets/roles/runme.sh new/ansible_core-2.18.3/test/integration/targets/roles/runme.sh --- old/ansible_core-2.18.2/test/integration/targets/roles/runme.sh 2025-01-27 20:45:24.000000000 +0100 +++ new/ansible_core-2.18.3/test/integration/targets/roles/runme.sh 2025-02-24 20:31:36.000000000 +0100 @@ -55,7 +55,7 @@ ansible-playbook privacy.yml -e @vars/privacy_vars.yml "$@" for strategy in linear free; do - [ "$(ANSIBLE_STRATEGY=$strategy ansible-playbook end_role.yml | grep -c CHECKPOINT)" = "1" ] + [ "$(ANSIBLE_STRATEGY=$strategy ansible-playbook -i testhost, end_role.yml | grep -c CHECKPOINT)" = "2" ] [ "$(ANSIBLE_STRATEGY=$strategy ansible-playbook -i host1,host2 end_role_nested.yml | grep -c CHECKPOINT)" = "4" ] done diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_core-2.18.2/test/integration/targets/var_reserved/tasks/include_vars.yml new/ansible_core-2.18.3/test/integration/targets/var_reserved/tasks/include_vars.yml --- old/ansible_core-2.18.2/test/integration/targets/var_reserved/tasks/include_vars.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/ansible_core-2.18.3/test/integration/targets/var_reserved/tasks/include_vars.yml 2025-02-24 20:31:36.000000000 +0100 @@ -0,0 +1,5 @@ +- hosts: localhost + gather_facts: no + tasks: + - include_vars: + file: ../vars/set_host_variable.yml diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_core-2.18.2/test/integration/targets/var_reserved/tasks/main.yml new/ansible_core-2.18.3/test/integration/targets/var_reserved/tasks/main.yml --- old/ansible_core-2.18.2/test/integration/targets/var_reserved/tasks/main.yml 2025-01-27 20:45:24.000000000 +0100 +++ new/ansible_core-2.18.3/test/integration/targets/var_reserved/tasks/main.yml 2025-02-24 20:31:36.000000000 +0100 @@ -2,22 +2,32 @@ vars: canary: Found variable using reserved name block: - - shell: ansible-playbook '{{[ role_path, "tasks", item ~ ".yml"] | path_join }}' + - shell: ansible-playbook '{{[ role_path, "tasks", item.file ~ ".yml"] | path_join }}' environment: ANSIBLE_LOCALHOST_WARNING: 0 + ANSIBLE_FORCE_COLOR: 0 failed_when: false loop: - - play_vars - - block_vars - - task_vars - - task_vars_used - - set_fact + - file: play_vars + name: lipsum + - file: block_vars + name: query + - file: task_vars + name: query + - file: task_vars_used + name: q + - file: set_fact + name: lookup + - file: include_vars + name: query register: play_out - name: check they all complain about bad defined var assert: that: - - canary in item['stderr'] + - item.stderr == warning_message loop: '{{play_out.results}}' loop_control: - label: '{{item.item}}' + label: '{{item.item.file}}' + vars: + warning_message: "[WARNING]: {{ canary }}: {{ item.item.name }}" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_core-2.18.2/test/integration/targets/var_reserved/vars/set_host_variable.yml new/ansible_core-2.18.3/test/integration/targets/var_reserved/vars/set_host_variable.yml --- old/ansible_core-2.18.2/test/integration/targets/var_reserved/vars/set_host_variable.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/ansible_core-2.18.3/test/integration/targets/var_reserved/vars/set_host_variable.yml 2025-02-24 20:31:36.000000000 +0100 @@ -0,0 +1 @@ +query: overwrite global Jinja2 function diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_core-2.18.2/test/lib/ansible_test/_internal/http.py new/ansible_core-2.18.3/test/lib/ansible_test/_internal/http.py --- old/ansible_core-2.18.2/test/lib/ansible_test/_internal/http.py 2025-01-27 20:45:24.000000000 +0100 +++ new/ansible_core-2.18.3/test/lib/ansible_test/_internal/http.py 2025-02-24 20:31:36.000000000 +0100 @@ -1,36 +1,29 @@ -""" -Primitive replacement for requests to avoid extra dependency. -Avoids use of urllib2 due to lack of SNI support. -""" +"""A simple HTTP client.""" from __future__ import annotations +import http.client import json import time import typing as t +import urllib.error +import urllib.request from .util import ( ApplicationError, - SubprocessError, display, ) from .util_common import ( CommonConfig, - run_command, ) class HttpClient: - """Make HTTP requests via curl.""" + """Make HTTP requests.""" - def __init__(self, args: CommonConfig, always: bool = False, insecure: bool = False, proxy: t.Optional[str] = None) -> None: + def __init__(self, args: CommonConfig, always: bool = False) -> None: self.args = args self.always = always - self.insecure = insecure - self.proxy = proxy - - self.username = None - self.password = None def get(self, url: str) -> HttpResponse: """Perform an HTTP GET and return the response.""" @@ -46,74 +39,65 @@ def request(self, method: str, url: str, data: t.Optional[str] = None, headers: t.Optional[dict[str, str]] = None) -> HttpResponse: """Perform an HTTP request and return the response.""" - cmd = ['curl', '-s', '-S', '-i', '-X', method] - - if self.insecure: - cmd += ['--insecure'] - if headers is None: headers = {} - headers['Expect'] = '' # don't send expect continue header - - if self.username: - if self.password: - display.sensitive.add(self.password) - cmd += ['-u', '%s:%s' % (self.username, self.password)] - else: - cmd += ['-u', self.username] + data_bytes = data.encode() if data else None - for header in headers.keys(): - cmd += ['-H', '%s: %s' % (header, headers[header])] + request = urllib.request.Request(method=method, url=url, data=data_bytes, headers=headers) + response: http.client.HTTPResponse - if data is not None: - cmd += ['-d', data] - - if self.proxy: - cmd += ['-x', self.proxy] - - cmd += [url] + display.info(f'HTTP {method} {url}', verbosity=2) attempts = 0 max_attempts = 3 sleep_seconds = 3 - # curl error codes which are safe to retry (request never sent to server) - retry_on_status = ( - 6, # CURLE_COULDNT_RESOLVE_HOST - ) - - stdout = '' + status_code = 200 + reason = 'OK' + body_bytes = b'' while True: attempts += 1 - try: - stdout = run_command(self.args, cmd, capture=True, always=self.always, cmd_verbosity=2)[0] + start = time.monotonic() + + if self.args.explain and not self.always: break - except SubprocessError as ex: - if ex.status in retry_on_status and attempts < max_attempts: - display.warning('%s' % ex) - time.sleep(sleep_seconds) - continue - - raise - - if self.args.explain and not self.always: - return HttpResponse(method, url, 200, '') - - header, body = stdout.split('\r\n\r\n', 1) - - response_headers = header.split('\r\n') - first_line = response_headers[0] - http_response = first_line.split(' ') - status_code = int(http_response[1]) + + try: + try: + with urllib.request.urlopen(request) as response: + status_code = response.status + reason = response.reason + body_bytes = response.read() + except urllib.error.HTTPError as ex: + status_code = ex.status + reason = ex.reason + body_bytes = ex.read() + except Exception as ex: # pylint: disable=broad-exception-caught + if attempts >= max_attempts: + raise + + # all currently implemented methods are idempotent, so retries are unconditionally supported + duration = time.monotonic() - start + display.warning(f'{type(ex).__module__}.{type(ex).__name__}: {ex} [{duration:.2f} seconds]') + time.sleep(sleep_seconds) + + continue + + break + + duration = time.monotonic() - start + display.info(f'HTTP {method} {url} -> HTTP {status_code} ({reason}) [{len(body_bytes)} bytes, {duration:.2f} seconds]', verbosity=3) + + body = body_bytes.decode() return HttpResponse(method, url, status_code, body) class HttpResponse: - """HTTP response from curl.""" + """HTTP response.""" def __init__(self, method: str, url: str, status_code: int, response: str) -> None: self.method = method ++++++ ansible_core-2.18.2.tar.gz.sha256 -> ansible_core-2.18.3.tar.gz.sha256 ++++++ --- /work/SRC/openSUSE:Factory/ansible-core/ansible_core-2.18.2.tar.gz.sha256 2025-01-29 16:18:46.780374268 +0100 +++ /work/SRC/openSUSE:Factory/.ansible-core.new.1873/ansible_core-2.18.3.tar.gz.sha256 2025-02-25 16:58:32.914435694 +0100 @@ -1 +1 @@ -725b047d35942304eb322eb934b98cc5442ac3f49d33827d97171c238c4b69b9 ansible_core-2.18.2.tar.gz +8c4eaca40845238e2601b9bc9dbfbd4f6ed3502cb8b2632789f75ce478abfdee ansible_core-2.18.3.tar.gz