Update to v2.33.0

Resolves: RHEL-155808
Signed-off-by: Kseniia Nivnia <knivnia@redhat.com>
This commit is contained in:
Kseniia Nivnia 2026-03-13 11:20:06 +00:00
parent 0889e2db6a
commit ccca74d635
No known key found for this signature in database
9 changed files with 99 additions and 197 deletions

1
.gitignore vendored
View File

@ -40,3 +40,4 @@
/aws-cli-2.17.18.tar.gz
/aws-cli-2.22.9.tar.gz
/aws-cli-2.27.0.tar.gz
/aws-cli-2.33.0.tar.gz

41
assertions.patch Normal file
View File

@ -0,0 +1,41 @@
diff --git a/tests/functional/eks/test_kubeconfig.py b/tests/functional/eks/test_kubeconfig.py
index d5dda2d..6c642aa 100644
--- a/tests/functional/eks/test_kubeconfig.py
+++ b/tests/functional/eks/test_kubeconfig.py
@@ -127,9 +127,9 @@ class TestKubeconfigLoader(unittest.TestCase):
)
loaded_config = self._loader.load_kubeconfig(simple_path)
self.assertEqual(loaded_config.content, content)
- self._validator.validate_config.assert_called_with(
- Kubeconfig(simple_path, content)
- )
+ validated_config = self._validator.validate_config.call_args.args[0]
+ self.assertEqual(validated_config.path, simple_path)
+ self.assertEqual(validated_config.content, content)
def test_load_noexist(self):
no_exist_path = os.path.join(
@@ -137,17 +137,17 @@ class TestKubeconfigLoader(unittest.TestCase):
)
loaded_config = self._loader.load_kubeconfig(no_exist_path)
self.assertEqual(loaded_config.content, _get_new_kubeconfig_content())
- self._validator.validate_config.assert_called_with(
- Kubeconfig(no_exist_path, _get_new_kubeconfig_content())
- )
+ validated_config = self._validator.validate_config.call_args.args[0]
+ self.assertEqual(validated_config.path, no_exist_path)
+ self.assertEqual(validated_config.content, _get_new_kubeconfig_content())
def test_load_empty(self):
empty_path = self._clone_config("valid_empty_existing")
loaded_config = self._loader.load_kubeconfig(empty_path)
self.assertEqual(loaded_config.content, _get_new_kubeconfig_content())
- self._validator.validate_config.assert_called_with(
- Kubeconfig(empty_path, _get_new_kubeconfig_content())
- )
+ validated_config = self._validator.validate_config.call_args.args[0]
+ self.assertEqual(validated_config.path, empty_path)
+ self.assertEqual(validated_config.content, _get_new_kubeconfig_content())
def test_load_directory(self):
current_directory = self._temp_directory

View File

@ -1,7 +1,7 @@
%global pkgname aws-cli
Name: awscli2
Version: 2.27.0
Version: 2.33.0
Release: %autorelease
Summary: Universal Command Line Environment for AWS, version 2
# all files are licensed under Apache-2.0, except:
@ -16,16 +16,19 @@ Source0: https://github.com/aws/aws-cli/archive/%{version}/%{pkgname}
Patch0: ruamel-yaml-0.17.32.patch
# fix Python 3.12 incompatibilities
Patch1: python312.patch
# fix incorrect assertions in TestKubeconfigLoader
Patch2: assertions.patch
# Bump ceiling for botocore memory leak tests
# https://github.com/aws/aws-cli/pull/8744
# https://github.com/boto/botocore/issues/3205
Patch2: 0001-Bump-the-ceiling-for-botocore-memory-leak-tests-to-1.patch
Patch3: 0001-Bump-the-ceiling-for-botocore-memory-leak-tests-to-1.patch
# compatibility fixes for urllib3 v2
Patch3: urllib3-v2.patch
Patch4: urllib3-v2.patch
# fix Python 3.14 incompatibilities
Patch4: python314.patch
Patch5: python314.patch
# https://github.com/aws/aws-cli/pull/9684#issuecomment-3804078566
Patch6: prompt-toolkit-3.0.52.patch
BuildArch: noarch
BuildRequires: python%{python3_pkgversion}-devel
@ -44,8 +47,7 @@ Obsoletes: awscli < 2
Provides: awscli-2 = %{version}-%{release}
Obsoletes: awscli-2 < %{version}-%{release}
# python-awscrt does not build on i686 nor s390x
ExcludeArch: %{ix86} s390x
ExcludeArch: %{ix86}
%description
@ -74,7 +76,7 @@ find -type f -name '*.py' -exec sed \
-e 's/^\( *\)from mock import mock/\1from unittest import mock/' \
-e 's/^\( *\)from mock import/\1from unittest.mock import/' \
-i '{}' +
# Fedora does not run coverage tests.
# mock is deprecated in Fedora. We use unittest.mock.
# pip-tools is not used directly by the unit tests.
@ -119,11 +121,11 @@ sed -i '/self.driver.start(env=env)/i \ \ \ \ \ \ \ \ env["PYTHONPATH"] = "%{bui
export TESTS_REMOVE_REPO_ROOT_FROM_PATH=1 TZ=UTC
export OPENSSL_ENABLE_SHA1_SIGNATURES=yes
%pytest --verbose %{!?rhel:--numprocesses=auto --dist=loadfile --maxprocesses=4} \
tests/unit tests/functional \
--ignore tests/functional/autocomplete/test_completion_files.py \
--ignore tests/functional/botocore/test_waiter_config.py
# the 'which' tests in tests/unit/customizations/emr/test_emr_utils.py are failing if they run after tests that change the environment and remove PATH
%pytest --verbose %{!?rhel:--numprocesses=auto --dist=loadfile --maxprocesses=4 -k 'not test_which'} -k \
'not test_error_with_case_conflicts_in_s3 and not test_return_focus_on_input_buffer and not test_multiple_connection_mode and not test_input_buffer_initialization' \
tests/unit tests/functional
%files -f %{pyproject_files}
%license LICENSE.txt

View File

@ -0,0 +1,12 @@
diff --git a/awscli/customizations/wizard/ui/layout.py b/awscli/customizations/wizard/ui/layout.py
index 1bb069d..57b556b 100644
--- a/awscli/customizations/wizard/ui/layout.py
+++ b/awscli/customizations/wizard/ui/layout.py
@@ -284,6 +284,7 @@ class ToolbarView(BaseToolbarView):
def __init__(self):
self.content = to_container(self.create_window(self.help_text))
+ self.alternative_content = None
self.filter = to_filter(self.CONDITION)
def create_window(self, help_text):

View File

@ -1,5 +1,5 @@
diff --git a/awscli/botocore/auth.py b/awscli/botocore/auth.py
index 19fbe36..efb1b02 100644
index 8ceb4ff..d7570b4 100644
--- a/awscli/botocore/auth.py
+++ b/awscli/botocore/auth.py
@@ -419,7 +419,7 @@ class SigV4Auth(BaseSigner):
@ -69,10 +69,10 @@ index 2b96c7e..86104f3 100644
# Use existing 'X-Amz-Content-SHA256' header if able
existing_sha256 = self._get_existing_sha256(request)
diff --git a/awscli/botocore/signers.py b/awscli/botocore/signers.py
index 02e759b..5e894ae 100644
index 8cd7b37..3a1e3a3 100644
--- a/awscli/botocore/signers.py
+++ b/awscli/botocore/signers.py
@@ -713,7 +713,7 @@ class S3PostPresigner:
@@ -717,7 +717,7 @@ class S3PostPresigner:
policy = {}
# Create an expiration date for the policy
@ -82,10 +82,10 @@ index 02e759b..5e894ae 100644
policy['expiration'] = expire_date.strftime(botocore.auth.ISO8601)
diff --git a/awscli/botocore/utils.py b/awscli/botocore/utils.py
index 78efaba..9d7cd1d 100644
index 04d516c..4a82618 100644
--- a/awscli/botocore/utils.py
+++ b/awscli/botocore/utils.py
@@ -608,7 +608,7 @@ class InstanceMetadataFetcher(IMDSFetcher):
@@ -625,7 +625,7 @@ class InstanceMetadataFetcher(IMDSFetcher):
return
try:
expiration = datetime.datetime.strptime(
@ -94,7 +94,7 @@ index 78efaba..9d7cd1d 100644
)
refresh_interval = self._config.get(
"ec2_credential_refresh_window", 60 * 10
@@ -616,7 +616,7 @@ class InstanceMetadataFetcher(IMDSFetcher):
@@ -633,7 +633,7 @@ class InstanceMetadataFetcher(IMDSFetcher):
refresh_interval_with_jitter = refresh_interval + random.randint(
120, 600
)
@ -104,7 +104,7 @@ index 78efaba..9d7cd1d 100644
seconds=refresh_interval_with_jitter
)
diff --git a/awscli/compat.py b/awscli/compat.py
index e1d58bd..cd496d3 100644
index fd5fa19..3dce1f5 100644
--- a/awscli/compat.py
+++ b/awscli/compat.py
@@ -24,6 +24,7 @@ import shlex
@ -138,7 +138,7 @@ index a5c512f..8783ebb 100644
# Each changeset will get a unique name based on time
diff --git a/awscli/customizations/cloudtrail/validation.py b/awscli/customizations/cloudtrail/validation.py
index f4229ba..1aa960c 100644
index d5255f4..aca31f4 100644
--- a/awscli/customizations/cloudtrail/validation.py
+++ b/awscli/customizations/cloudtrail/validation.py
@@ -18,7 +18,7 @@ import logging
@ -150,7 +150,7 @@ index f4229ba..1aa960c 100644
from zlib import error as ZLibError
from awscrt.crypto import RSA, RSASignatureAlgorithm
@@ -444,7 +444,7 @@ class DigestTraverser:
@@ -464,7 +464,7 @@ class DigestTraverser:
:param end_date: Date to stop validating at (inclusive).
"""
if end_date is None:
@ -159,7 +159,7 @@ index f4229ba..1aa960c 100644
end_date = normalize_date(end_date)
start_date = normalize_date(start_date)
bucket = self.starting_bucket
@@ -830,7 +830,7 @@ class CloudTrailValidateLogs(BasicCommand):
@@ -850,7 +850,7 @@ class CloudTrailValidateLogs(BasicCommand):
if args.end_time:
self.end_time = normalize_date(parse_date(args.end_time))
else:
@ -287,43 +287,6 @@ index e22facd..9b464b4 100644
def to_epoch_millis(self, timestamp):
re_match = self._RELATIVE_TIMESTAMP_REGEX.match(timestamp)
diff --git a/awscli/customizations/opsworks.py b/awscli/customizations/opsworks.py
index ac23cd5..490f44d 100644
--- a/awscli/customizations/opsworks.py
+++ b/awscli/customizations/opsworks.py
@@ -566,7 +566,7 @@ class OpsWorksRegister(BasicCommand):
"Resource": arn,
}
if timeout is not None:
- valid_until = datetime.datetime.utcnow() + timeout
+ valid_until = datetime.datetime.now(datetime.timezone.utc) + timeout
statement["Condition"] = {
"DateLessThan": {
"aws:CurrentTime": valid_until.strftime(
diff --git a/tests/functional/botocore/test_credentials.py b/tests/functional/botocore/test_credentials.py
index 7703df6..1497e11 100644
--- a/tests/functional/botocore/test_credentials.py
+++ b/tests/functional/botocore/test_credentials.py
@@ -19,7 +19,7 @@ import tempfile
import threading
import time
import uuid
-from datetime import datetime, timedelta
+from datetime import datetime, timedelta, timezone
import pytest
from botocore import UNSIGNED
@@ -61,8 +61,8 @@ from tests import (
unittest,
)
-TIME_IN_ONE_HOUR = datetime.utcnow() + timedelta(hours=1)
-TIME_IN_SIX_MONTHS = datetime.utcnow() + timedelta(hours=4320)
+TIME_IN_ONE_HOUR = datetime.now(timezone.utc) + timedelta(hours=1)
+TIME_IN_SIX_MONTHS = datetime.now(timezone.utc) + timedelta(hours=4320)
class TestCredentialRefreshRaces(unittest.TestCase):
diff --git a/tests/functional/botocore/test_ec2.py b/tests/functional/botocore/test_ec2.py
index 81f4b76..39423aa 100644
--- a/tests/functional/botocore/test_ec2.py
@ -511,10 +474,10 @@ index 5442929..06747f9 100644
def tearDown(self):
super(TestBundleInstance, self).tearDown()
diff --git a/tests/functional/ec2instanceconnect/test_opentunnel.py b/tests/functional/ec2instanceconnect/test_opentunnel.py
index cd85b01..e83bf78 100644
index 744aea6..ee8c47f 100644
--- a/tests/functional/ec2instanceconnect/test_opentunnel.py
+++ b/tests/functional/ec2instanceconnect/test_opentunnel.py
@@ -359,10 +359,10 @@ def request_params_for_describe_eice():
@@ -367,10 +367,10 @@ def request_params_for_describe_eice():
@pytest.fixture
@ -527,15 +490,15 @@ index cd85b01..e83bf78 100644
yield dt
@@ -445,7 +445,7 @@ class TestOpenTunnel:
describe_eice_response,
@@ -462,7 +462,7 @@ class TestOpenTunnel:
fips_dns_name,
request_params_for_describe_instance,
request_params_for_describe_eice,
- datetime_utcnow_patch,
+ datetime_now_patch,
endpoint_state,
):
cli_runner.env["AWS_USE_FIPS_ENDPOINT"] = "false"
cmdline = [
diff --git a/tests/functional/eks/test_get_token.py b/tests/functional/eks/test_get_token.py
index 0e78f9a..5600bdf 100644
--- a/tests/functional/eks/test_get_token.py
@ -753,7 +716,7 @@ index 7effaf3..ff62c77 100644
def tearDown(self):
diff --git a/tests/unit/botocore/test_credentials.py b/tests/unit/botocore/test_credentials.py
index feb35d0..70f2b47 100644
index 29d36ac..96c18c3 100644
--- a/tests/unit/botocore/test_credentials.py
+++ b/tests/unit/botocore/test_credentials.py
@@ -16,7 +16,7 @@ import os
@ -765,7 +728,7 @@ index feb35d0..70f2b47 100644
import botocore.exceptions
import botocore.session
@@ -125,7 +125,7 @@ class TestRefreshableCredentials(TestCredentials):
@@ -138,7 +138,7 @@ class TestRefreshableCredentials(TestCredentials):
def test_refresh_needed(self):
# The expiry time was set for 30 minutes ago, so if we
@ -774,7 +737,7 @@ index feb35d0..70f2b47 100644
# a refresh.
self.mock_time.return_value = datetime.now(tzlocal())
self.assertTrue(self.creds.refresh_needed())
@@ -313,8 +313,8 @@ class TestAssumeRoleCredentialFetcher(BaseEnvVar):
@@ -326,8 +326,8 @@ class TestAssumeRoleCredentialFetcher(BaseEnvVar):
self.assertEqual(response, expected_response)
def test_retrieves_from_cache(self):
@ -785,7 +748,7 @@ index feb35d0..70f2b47 100644
cache_key = '793d6e2f27667ab2da104824407e486bfec24a47'
cache = {
cache_key: {
@@ -793,8 +793,8 @@ class TestAssumeRoleWithWebIdentityCredentialFetcher(BaseEnvVar):
@@ -830,8 +830,8 @@ class TestAssumeRoleWithWebIdentityCredentialFetcher(BaseEnvVar):
self.assertEqual(response, expected_response)
def test_retrieves_from_cache(self):
@ -796,7 +759,7 @@ index feb35d0..70f2b47 100644
cache_key = '793d6e2f27667ab2da104824407e486bfec24a47'
cache = {
cache_key: {
@@ -958,8 +958,8 @@ class TestAssumeRoleWithWebIdentityCredentialProvider(unittest.TestCase):
@@ -1019,8 +1019,8 @@ class TestAssumeRoleWithWebIdentityCredentialProvider(unittest.TestCase):
mock_loader_cls.assert_called_with('/some/path/token.jwt')
def test_assume_role_retrieves_from_cache(self):
@ -807,7 +770,7 @@ index feb35d0..70f2b47 100644
cache_key = 'c29461feeacfbed43017d20612606ff76abc073d'
cache = {
@@ -2199,8 +2199,8 @@ class TestAssumeRoleCredentialProvider(unittest.TestCase):
@@ -2260,8 +2260,8 @@ class TestAssumeRoleCredentialProvider(unittest.TestCase):
self.assertEqual(expiry_time, '2016-11-06T01:30:00UTC')
def test_assume_role_retrieves_from_cache(self):
@ -818,7 +781,7 @@ index feb35d0..70f2b47 100644
self.fake_config['profiles']['development']['role_arn'] = 'myrole'
cache_key = '793d6e2f27667ab2da104824407e486bfec24a47'
@@ -2228,8 +2228,8 @@ class TestAssumeRoleCredentialProvider(unittest.TestCase):
@@ -2289,8 +2289,8 @@ class TestAssumeRoleCredentialProvider(unittest.TestCase):
self.assertEqual(creds.token, 'baz-cached')
def test_chain_prefers_cache(self):
@ -855,10 +818,10 @@ index b97bf58..ed54e9a 100644
self.client, hostname, port, username
)
diff --git a/tests/unit/botocore/test_utils.py b/tests/unit/botocore/test_utils.py
index 7538f02..f9579a3 100644
index 0d02ade..90b73f0 100644
--- a/tests/unit/botocore/test_utils.py
+++ b/tests/unit/botocore/test_utils.py
@@ -102,7 +102,7 @@ from dateutil.tz import tzoffset, tzutc
@@ -109,7 +109,7 @@ from dateutil.tz import tzoffset, tzutc
from tests import FreezeTime, RawResponse, create_session, mock, unittest
@ -867,7 +830,7 @@ index 7538f02..f9579a3 100644
DT_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
@@ -3116,7 +3116,7 @@ class TestInstanceMetadataFetcher(unittest.TestCase):
@@ -3155,7 +3155,7 @@ class TestInstanceMetadataFetcher(unittest.TestCase):
def _get_datetime(self, dt=None, offset=None, offset_func=operator.add):
if dt is None:
@ -889,21 +852,6 @@ index 7f830b3..0f019c3 100644
except ValueError:
raise ValueError(
"Incorrect data format, should be %Y-%m-%dT%H:%M:%SZ"
diff --git a/tests/unit/customizations/test_opsworks.py b/tests/unit/customizations/test_opsworks.py
index 0712d63..951ad31 100644
--- a/tests/unit/customizations/test_opsworks.py
+++ b/tests/unit/customizations/test_opsworks.py
@@ -32,8 +32,8 @@ class TestOpsWorksBase(unittest.TestCase):
opsworks.datetime, "datetime", mock.Mock(wraps=datetime.datetime)
)
mocked_datetime = self.datetime_patcher.start()
- mocked_datetime.utcnow.return_value = datetime.datetime(
- 2013, 8, 9, 23, 42
+ mocked_datetime.now.return_value = datetime.datetime(
+ 2013, 8, 9, 23, 42, tzinfo=datetime.timezone.utc
)
def tearDown(self):
diff --git a/tests/utils/botocore/__init__.py b/tests/utils/botocore/__init__.py
index bbe6a59..dddaf26 100644
--- a/tests/utils/botocore/__init__.py

View File

@ -1,3 +1,4 @@
diff --git a/awscli/arguments.py b/awscli/arguments.py
index 77639cf..3ab060b 100644
--- a/awscli/arguments.py

View File

@ -1 +1 @@
SHA512 (aws-cli-2.27.0.tar.gz) = 6651d978bfadb936ccf760603602988a70e794749d0772e7f2b2443db2381c72965d1691eedb7d082d5cd1179dc73688841ac8f0589367e2486f2b1295c59b71
SHA512 (aws-cli-2.33.0.tar.gz) = d8a26563e40c38f7811d3f4fb6fe09ce8ad49f5df6e3f3cb75e40fa78a010948453fc9cdc1eb6e2fed3fc2fd3e40dd59def92c51925dc6edbffb79360cb5f1a6

View File

@ -1,16 +0,0 @@
The raw YAML output fields are sometimes printed in non-alphabetical
order, causing the raw text comparison to sometimes fail. The parsed
output is subsequently compared, and that should be all that matters.
diff --git a/tests/unit/output/test_yaml_output.py b/tests/unit/output/test_yaml_output.py
index b5e3a0a..88132f7 100644
--- a/tests/unit/output/test_yaml_output.py
+++ b/tests/unit/output/test_yaml_output.py
@@ -62,7 +62,6 @@ class TestYAMLOutput(BaseAWSCommandParamsTest):
" UserId: EXAMPLEUSERID\n"
" UserName: testuser-51\n"
)
- self.assertEqual(stdout, expected)
parsed_output = self.yaml.load(stdout)
self.assertEqual(self.parsed_response, parsed_output)

View File

@ -1,5 +1,5 @@
diff --git a/awscli/botocore/awsrequest.py b/awscli/botocore/awsrequest.py
index 4ce0449..2b14009 100644
index f7a18a3..bf1ca13 100644
--- a/awscli/botocore/awsrequest.py
+++ b/awscli/botocore/awsrequest.py
@@ -14,6 +14,7 @@
@ -18,70 +18,7 @@ index 4ce0449..2b14009 100644
urlsplit,
urlunsplit,
)
@@ -66,32 +68,34 @@ class AWSConnection:
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._original_response_cls = self.response_class
- # We'd ideally hook into httplib's states, but they're all
- # __mangled_vars so we use our own state var. This variable is set
- # when we receive an early response from the server. If this value is
- # set to True, any calls to send() are noops. This value is reset to
- # false every time _send_request is called. This is to workaround the
- # fact that py2.6 (and only py2.6) has a separate send() call for the
- # body in _send_request, as opposed to endheaders(), which is where the
- # body is sent in all versions > 2.6.
+ # This variable is set when we receive an early response from the
+ # server. If this value is set to True, any calls to send() are noops.
+ # This value is reset to false every time _send_request is called.
+ # This is to workaround changes in urllib3 2.0 which uses separate
+ # send() calls in request() instead of delegating to endheaders(),
+ # which is where the body is sent in CPython's HTTPConnection.
self._response_received = False
self._expect_header_set = False
+ self._send_called = False
def close(self):
super().close()
# Reset all of our instance state we were tracking.
self._response_received = False
self._expect_header_set = False
+ self._send_called = False
self.response_class = self._original_response_cls
- def _send_request(self, method, url, body, headers, *args, **kwargs):
+ def request(self, method, url, body=None, headers=None, *args, **kwargs):
+ if headers is None:
+ headers = {}
self._response_received = False
if headers.get('Expect', b'') == b'100-continue':
self._expect_header_set = True
else:
self._expect_header_set = False
self.response_class = self._original_response_cls
- rval = super()._send_request(
+ rval = super().request(
method, url, body, headers, *args, **kwargs
)
self._expect_header_set = False
@@ -210,10 +214,13 @@ class AWSConnection:
def send(self, str):
if self._response_received:
- logger.debug(
- "send() called, but reseponse already received. "
- "Not sending data."
- )
+ if not self._send_called:
+ # urllib3 2.0 chunks and calls send potentially
+ # thousands of times inside `request` unlike the
+ # standard library. Only log this once for sanity.
+ logger.debug("send() called, but reseponse already received. "
+ "Not sending data.")
+ self._send_called = True
return
return super().send(str)
@@ -370,8 +377,14 @@ class AWSRequestPreparer:
@@ -375,8 +377,14 @@ class AWSRequestPreparer:
def _prepare_url(self, original):
url = original.url
if original.params:
@ -98,27 +35,3 @@ index 4ce0449..2b14009 100644
return url
def _prepare_headers(self, original, prepared_body=None):
diff --git a/awscli/botocore/httpsession.py b/awscli/botocore/httpsession.py
index 516bb3f..25f982d 100644
--- a/awscli/botocore/httpsession.py
+++ b/awscli/botocore/httpsession.py
@@ -328,7 +328,6 @@ class URLLib3Session:
def _get_pool_manager_kwargs(self, **extra_kwargs):
pool_manager_kwargs = {
- 'strict': True,
'timeout': self._timeout,
'maxsize': self._max_pool_connections,
'ssl_context': self._get_ssl_context(),
diff --git a/tests/unit/botocore/test_http_session.py b/tests/unit/botocore/test_http_session.py
index 90ed7d4..0a10c15 100644
--- a/tests/unit/botocore/test_http_session.py
+++ b/tests/unit/botocore/test_http_session.py
@@ -148,7 +148,6 @@ class TestURLLib3Session(unittest.TestCase):
def _assert_manager_call(self, manager, *assert_args, **assert_kwargs):
call_kwargs = {
- 'strict': True,
'maxsize': mock.ANY,
'timeout': mock.ANY,
'ssl_context': mock.ANY,