ansible-core 2.17.8rc1__py3-none-any.whl → 2.17.9__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of ansible-core might be problematic. Click here for more details.

@@ -17,6 +17,6 @@
17
17
 
18
18
  from __future__ import annotations
19
19
 
20
- __version__ = '2.17.8rc1'
20
+ __version__ = '2.17.9'
21
21
  __author__ = 'Ansible, Inc.'
22
22
  __codename__ = "Gallows Pole"
ansible/release.py CHANGED
@@ -17,6 +17,6 @@
17
17
 
18
18
  from __future__ import annotations
19
19
 
20
- __version__ = '2.17.8rc1'
20
+ __version__ = '2.17.9'
21
21
  __author__ = 'Ansible, Inc.'
22
22
  __codename__ = "Gallows Pole"
ansible/vars/manager.py CHANGED
@@ -742,7 +742,7 @@ class VariableManager:
742
742
  Sets a value in the vars_cache for a host.
743
743
  """
744
744
 
745
- warn_if_reserved(varname)
745
+ warn_if_reserved([varname])
746
746
  if host not in self._vars_cache:
747
747
  self._vars_cache[host] = dict()
748
748
  if varname in self._vars_cache[host] and isinstance(self._vars_cache[host][varname], MutableMapping) and isinstance(value, MutableMapping):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: ansible-core
3
- Version: 2.17.8rc1
3
+ Version: 2.17.9
4
4
  Summary: Radically simple IT automation
5
5
  Home-page: https://ansible.com/
6
6
  Author: Ansible, Inc.
@@ -3,7 +3,7 @@ ansible/__main__.py,sha256=EnLcULXNtSXkuJ8igEHPPLBTZKAwqXv4PvMEhvzp2Oo,1430
3
3
  ansible/constants.py,sha256=vRwEcoynqtuKDPKsxKUY94XzrTSV3J0y1slb907DioU,9140
4
4
  ansible/context.py,sha256=oKYyfjfWpy8vDeProtqfnqSmuij_t75_5e5t0U_hQ1g,1933
5
5
  ansible/keyword_desc.yml,sha256=vE9joFgSeHR4Djl7Bd-HHVCrGByRCrTUmWYZ8LKPZKk,7412
6
- ansible/release.py,sha256=6Dy9q8KH2ZvKbDZF6q4lT39JV3mbLV0m6qKxPAOV19c,835
6
+ ansible/release.py,sha256=Gr8CQiQF_-7iMpwjYSTe1fpkqwQqQI5ZzEQHxyvFeNI,832
7
7
  ansible/_vendor/__init__.py,sha256=2QBeBwT7uG7M3Aw-pIdCpt6XPtHMCpbEKfACYKA7xIg,2033
8
8
  ansible/cli/__init__.py,sha256=fzgR82NIGBH3GujIMehhAaP4KYszn4uztuCaFYRUpGk,28718
9
9
  ansible/cli/adhoc.py,sha256=quJ9WzRzf3dz_dtDGmahNMffqyNVy1jzQCMo21YL5Qg,8194
@@ -140,7 +140,7 @@ ansible/inventory/host.py,sha256=PDb5OTplhfpUIvdHiP2BckUOB1gUl302N-3sW0_sTyg,503
140
140
  ansible/inventory/manager.py,sha256=45mHgZTAkQ3IjAtrgsNzJXvynC-HIEor-JJE-V3xXN4,29454
141
141
  ansible/module_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
142
142
  ansible/module_utils/_text.py,sha256=VkWgAnSNVCbTQqZgllUObBFsH3uM4EUW5srl1UR9t1g,544
143
- ansible/module_utils/ansible_release.py,sha256=6Dy9q8KH2ZvKbDZF6q4lT39JV3mbLV0m6qKxPAOV19c,835
143
+ ansible/module_utils/ansible_release.py,sha256=Gr8CQiQF_-7iMpwjYSTe1fpkqwQqQI5ZzEQHxyvFeNI,832
144
144
  ansible/module_utils/api.py,sha256=DWIuLW5gDWuyyDHLLgGnub42Qa8kagDdkf1xDeLAFl4,5784
145
145
  ansible/module_utils/basic.py,sha256=UcDamm_6bkL3HXxKvQcSUlzDOHkIlvd8AYGuqJNmZeI,86113
146
146
  ansible/module_utils/connection.py,sha256=q_BdUaST6E44ltHsWPOFOheXK9vKmzaJvP-eQOrOrmE,8394
@@ -675,10 +675,10 @@ ansible/vars/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
675
675
  ansible/vars/clean.py,sha256=X2WMksJMWITQ9FsM-Fb_YxT_hAGDqJ3urSTJzYBEdAk,5999
676
676
  ansible/vars/fact_cache.py,sha256=M57vMhkQ2DrzvNaZkfaCmKQJUqP1Rn_A31_X-5YBfzQ,1903
677
677
  ansible/vars/hostvars.py,sha256=o11xrzDVYn23renGbb3lx3R-nH9qOjLFju5IYJanDxg,5324
678
- ansible/vars/manager.py,sha256=DLw853m8IVmEYP9YMrJbsJyGSEhkTD1H9BsctjJqL3k,38869
678
+ ansible/vars/manager.py,sha256=Yuo51lu4UVfzxMS63zYtZMcI8iFYgLXtg0p8fnq3Y7E,38871
679
679
  ansible/vars/plugins.py,sha256=RsRU9fiLcJwPIAyTYnmVZglsiEOMCIgQskflavE-XnE,4546
680
680
  ansible/vars/reserved.py,sha256=Tsc4m2UwVce3dOvSWrjT2wB3lpNJtUyNZn45zNhsW0I,2869
681
- ansible_core-2.17.8rc1.data/scripts/ansible-test,sha256=dyY2HtRZotRQO3b89HGXY_KnJgBvgsm4eLIe4B2LUoA,1637
681
+ ansible_core-2.17.9.data/scripts/ansible-test,sha256=dyY2HtRZotRQO3b89HGXY_KnJgBvgsm4eLIe4B2LUoA,1637
682
682
  ansible_test/__init__.py,sha256=20VPOj11c6Ut1Av9RaurgwJvFhMqkWG3vAvcCbecNKw,66
683
683
  ansible_test/_data/ansible.cfg,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
684
684
  ansible_test/_data/coveragerc,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -751,7 +751,7 @@ ansible_test/_internal/executor.py,sha256=KW5yI-f-giErQ077MTj707fTtFkf_Kr8IV_Nr3
751
751
  ansible_test/_internal/git.py,sha256=njtciWq2DlzZ1DAkQi08HRRP-TgH0mgeGZsWcsJGctI,4366
752
752
  ansible_test/_internal/host_configs.py,sha256=0S6EfSE2QMkOi4-ySxM6A4hlGxfb3aSjJKUHOC4wiwM,18283
753
753
  ansible_test/_internal/host_profiles.py,sha256=vvkstqitZwxE1TCShJmsot_trcmWl45TyG5sBazpFrE,65489
754
- ansible_test/_internal/http.py,sha256=27EGOIWupvFXPo8abJ-3DScE2V2fyMMwAJ_3g0eL7O4,4123
754
+ ansible_test/_internal/http.py,sha256=ENuIPnBXIuvgDSxC-r5eOxfGzscxB6MOVJzT4OQXQSA,3864
755
755
  ansible_test/_internal/init.py,sha256=f2ZN7F-FyjMgN73SUgxwbVtWNhkJv7BIlZ-q4ALHyjM,505
756
756
  ansible_test/_internal/inventory.py,sha256=c79s-xc1uv2nD7rPISv0JKkKspY-X2-kHoozF2R4e1Q,5408
757
757
  ansible_test/_internal/io.py,sha256=e7ccixoPL5lrAPLUx50vOGYpcELWHhs0R3a5Sh6b5hs,2807
@@ -979,9 +979,9 @@ ansible_test/config/cloud-config-vultr.ini.template,sha256=XLKHk3lg_8ReQMdWfZzhh
979
979
  ansible_test/config/config.yml,sha256=wb3knoBmZewG3GWOMnRHoVPQWW4vPixKLPMNS6vJmTc,2620
980
980
  ansible_test/config/inventory.networking.template,sha256=bFNSk8zNQOaZ_twaflrY0XZ9mLwUbRLuNT0BdIFwvn4,1335
981
981
  ansible_test/config/inventory.winrm.template,sha256=1QU8W-GFLnYEw8yY9bVIvUAVvJYPM3hyoijf6-M7T00,1098
982
- ansible_core-2.17.8rc1.dist-info/COPYING,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
983
- ansible_core-2.17.8rc1.dist-info/METADATA,sha256=fDjbC2YhphjLqWL333Jizv7XMXQLe2U5_NAgYJTqfHo,6968
984
- ansible_core-2.17.8rc1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
985
- ansible_core-2.17.8rc1.dist-info/entry_points.txt,sha256=0mpmsrIhODChxKl3eS-NcVQCaMetBn8KdPLtVxQgR64,453
986
- ansible_core-2.17.8rc1.dist-info/top_level.txt,sha256=IFbRLjAvih1DYzJWg3_F6t4sCzEMxRO7TOMNs6GkYHo,21
987
- ansible_core-2.17.8rc1.dist-info/RECORD,,
982
+ ansible_core-2.17.9.dist-info/COPYING,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
983
+ ansible_core-2.17.9.dist-info/METADATA,sha256=L5UTqj7vQTGgFkk_li2JAjiAPsY6Pb4bodd9yTFzmuM,6965
984
+ ansible_core-2.17.9.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
985
+ ansible_core-2.17.9.dist-info/entry_points.txt,sha256=0mpmsrIhODChxKl3eS-NcVQCaMetBn8KdPLtVxQgR64,453
986
+ ansible_core-2.17.9.dist-info/top_level.txt,sha256=IFbRLjAvih1DYzJWg3_F6t4sCzEMxRO7TOMNs6GkYHo,21
987
+ ansible_core-2.17.9.dist-info/RECORD,,
@@ -1,36 +1,29 @@
1
- """
2
- Primitive replacement for requests to avoid extra dependency.
3
- Avoids use of urllib2 due to lack of SNI support.
4
- """
1
+ """A simple HTTP client."""
5
2
  from __future__ import annotations
6
3
 
4
+ import http.client
7
5
  import json
8
6
  import time
9
7
  import typing as t
8
+ import urllib.error
9
+ import urllib.request
10
10
 
11
11
  from .util import (
12
12
  ApplicationError,
13
- SubprocessError,
14
13
  display,
15
14
  )
16
15
 
17
16
  from .util_common import (
18
17
  CommonConfig,
19
- run_command,
20
18
  )
21
19
 
22
20
 
23
21
  class HttpClient:
24
- """Make HTTP requests via curl."""
22
+ """Make HTTP requests."""
25
23
 
26
- def __init__(self, args: CommonConfig, always: bool = False, insecure: bool = False, proxy: t.Optional[str] = None) -> None:
24
+ def __init__(self, args: CommonConfig, always: bool = False) -> None:
27
25
  self.args = args
28
26
  self.always = always
29
- self.insecure = insecure
30
- self.proxy = proxy
31
-
32
- self.username = None
33
- self.password = None
34
27
 
35
28
  def get(self, url: str) -> HttpResponse:
36
29
  """Perform an HTTP GET and return the response."""
@@ -46,74 +39,65 @@ class HttpClient:
46
39
 
47
40
  def request(self, method: str, url: str, data: t.Optional[str] = None, headers: t.Optional[dict[str, str]] = None) -> HttpResponse:
48
41
  """Perform an HTTP request and return the response."""
49
- cmd = ['curl', '-s', '-S', '-i', '-X', method]
50
-
51
- if self.insecure:
52
- cmd += ['--insecure']
53
-
54
42
  if headers is None:
55
43
  headers = {}
56
44
 
57
- headers['Expect'] = '' # don't send expect continue header
58
-
59
- if self.username:
60
- if self.password:
61
- display.sensitive.add(self.password)
62
- cmd += ['-u', '%s:%s' % (self.username, self.password)]
63
- else:
64
- cmd += ['-u', self.username]
65
-
66
- for header in headers.keys():
67
- cmd += ['-H', '%s: %s' % (header, headers[header])]
68
-
69
- if data is not None:
70
- cmd += ['-d', data]
45
+ data_bytes = data.encode() if data else None
71
46
 
72
- if self.proxy:
73
- cmd += ['-x', self.proxy]
47
+ request = urllib.request.Request(method=method, url=url, data=data_bytes, headers=headers)
48
+ response: http.client.HTTPResponse
74
49
 
75
- cmd += [url]
50
+ display.info(f'HTTP {method} {url}', verbosity=2)
76
51
 
77
52
  attempts = 0
78
53
  max_attempts = 3
79
54
  sleep_seconds = 3
80
55
 
81
- # curl error codes which are safe to retry (request never sent to server)
82
- retry_on_status = (
83
- 6, # CURLE_COULDNT_RESOLVE_HOST
84
- )
85
-
86
- stdout = ''
56
+ status_code = 200
57
+ reason = 'OK'
58
+ body_bytes = b''
87
59
 
88
60
  while True:
89
61
  attempts += 1
90
62
 
91
- try:
92
- stdout = run_command(self.args, cmd, capture=True, always=self.always, cmd_verbosity=2)[0]
63
+ start = time.monotonic()
64
+
65
+ if self.args.explain and not self.always:
93
66
  break
94
- except SubprocessError as ex:
95
- if ex.status in retry_on_status and attempts < max_attempts:
96
- display.warning('%s' % ex)
97
- time.sleep(sleep_seconds)
98
- continue
99
67
 
100
- raise
68
+ try:
69
+ try:
70
+ with urllib.request.urlopen(request) as response:
71
+ status_code = response.status
72
+ reason = response.reason
73
+ body_bytes = response.read()
74
+ except urllib.error.HTTPError as ex:
75
+ status_code = ex.status
76
+ reason = ex.reason
77
+ body_bytes = ex.read()
78
+ except Exception as ex: # pylint: disable=broad-exception-caught
79
+ if attempts >= max_attempts:
80
+ raise
81
+
82
+ # all currently implemented methods are idempotent, so retries are unconditionally supported
83
+ duration = time.monotonic() - start
84
+ display.warning(f'{type(ex).__module__}.{type(ex).__name__}: {ex} [{duration:.2f} seconds]')
85
+ time.sleep(sleep_seconds)
86
+
87
+ continue
101
88
 
102
- if self.args.explain and not self.always:
103
- return HttpResponse(method, url, 200, '')
89
+ break
104
90
 
105
- header, body = stdout.split('\r\n\r\n', 1)
91
+ duration = time.monotonic() - start
92
+ display.info(f'HTTP {method} {url} -> HTTP {status_code} ({reason}) [{len(body_bytes)} bytes, {duration:.2f} seconds]', verbosity=3)
106
93
 
107
- response_headers = header.split('\r\n')
108
- first_line = response_headers[0]
109
- http_response = first_line.split(' ')
110
- status_code = int(http_response[1])
94
+ body = body_bytes.decode()
111
95
 
112
96
  return HttpResponse(method, url, status_code, body)
113
97
 
114
98
 
115
99
  class HttpResponse:
116
- """HTTP response from curl."""
100
+ """HTTP response."""
117
101
 
118
102
  def __init__(self, method: str, url: str, status_code: int, response: str) -> None:
119
103
  self.method = method