Bug 2196523

Summary: cloud-init fails to build with Python 3.12: TimeoutError: 2 (of 2) futures unfinished
Product: [Fedora] Fedora Reporter: Tomáš Hrnčiar <thrnciar>
Component: cloud-initAssignee: Major Hayden 🤠 <mhayden>
Status: CLOSED RAWHIDE QA Contact: Fedora Extras Quality Assurance <extras-qa>
Severity: unspecified Docs Contact:
Priority: unspecified    
Version: rawhideCC: apevec, dustymabe, eterrell, gholms, lars, mhayden, mhroncok, python-packagers-sig, rominf, shardy, thrnciar
Target Milestone: ---   
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2023-07-24 18:38:45 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On:    
Bug Blocks: 2135404    

Description Tomáš Hrnčiar 2023-05-09 11:58:19 UTC
cloud-init fails to build with Python 3.12.0a7.

=================================== FAILURES ===================================
_________ TestDualStack.test_dual_stack[<lambda>-addresses1-1-0-None] __________

self = <tests.unittests.test_url_helper.TestDualStack object at 0x7ffa61d6a2d0>
func = <function TestDualStack.<lambda> at 0x7ffa61947380>
addresses = ('one', 'two'), stagger_delay = 1, timeout = 0, expected_val = None

    @pytest.mark.parametrize(
        ["func", "addresses", "stagger_delay", "timeout", "expected_val"],
        [
            # Assert order based on timeout
            (lambda x, _: x, ("one", "two"), 1, 1, "one"),
            # Assert timeout results in (None, None)
            (lambda _a, _b: event.wait(1), ("one", "two"), 1, 0, None),
            (
                lambda a, _b: 1 / 0 if a == "one" else a,
                ("one", "two"),
                0,
                1,
                "two",
            ),
            # Assert that exception in func is only raised
            # if neither thread gets a valid result
            (
                lambda a, _b: 1 / 0 if a == "two" else a,
                ("one", "two"),
                0,
                1,
                "one",
            ),
            # simulate a slow response to verify correct order
            (
                lambda x, _: event.wait(1) if x != "two" else x,
                ("one", "two"),
                0,
                1,
                "two",
            ),
            # simulate a slow response to verify correct order
            (
                lambda x, _: event.wait(1) if x != "tri" else x,
                ("one", "two", "tri"),
                0,
                1,
                "tri",
            ),
        ],
    )
    def test_dual_stack(
        self,
        func,
        addresses,
        stagger_delay,
        timeout,
        expected_val,
    ):
        """Assert various failure modes behave as expected"""
        event.clear()
    
        gen = partial(
            dual_stack,
            func,
            addresses,
            stagger_delay=stagger_delay,
            timeout=timeout,
        )
>       _, result = assert_time(gen)

tests/unittests/test_url_helper.py:363: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
tests/unittests/test_url_helper.py:289: in assert_time
    out = func()
cloudinit/url_helper.py:469: in dual_stack
    executor.shutdown(wait=False)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

fs = {<Future at 0x7ffa5f5496a0 state=running>, <Future at 0x7ffa5f5488c0 state=running>}
timeout = 0

    def as_completed(fs, timeout=None):
        """An iterator over the given futures that yields each as it completes.
    
        Args:
            fs: The sequence of Futures (possibly created by different Executors) to
                iterate over.
            timeout: The maximum number of seconds to wait. If None, then there
                is no limit on the wait time.
    
        Returns:
            An iterator that yields the given Futures as they complete (finished or
            cancelled). If any given Futures are duplicated, they will be returned
            once.
    
        Raises:
            TimeoutError: If the entire result iterator could not be generated
                before the given timeout.
        """
        if timeout is not None:
            end_time = timeout + time.monotonic()
    
        fs = set(fs)
        total_futures = len(fs)
        with _AcquireFutures(fs):
            finished = set(
                    f for f in fs
                    if f._state in [CANCELLED_AND_NOTIFIED, FINISHED])
            pending = fs - finished
            waiter = _create_and_install_waiters(fs, _AS_COMPLETED)
        finished = list(finished)
        try:
            yield from _yield_finished_futures(finished, waiter,
                                               ref_collect=(fs,))
    
            while pending:
                if timeout is None:
                    wait_timeout = None
                else:
                    wait_timeout = end_time - time.monotonic()
                    if wait_timeout < 0:
>                       raise TimeoutError(
                                '%d (of %d) futures unfinished' % (
                                len(pending), total_futures))
E                               TimeoutError: 2 (of 2) futures unfinished

/usr/lib64/python3.12/concurrent/futures/_base.py:239: TimeoutError
__________________ TestUdevadmSettle.test_udevadm_not_present __________________

self = <tests.unittests.test_util.TestUdevadmSettle testMethod=test_udevadm_not_present>
m_which = <MagicMock name='subp' id='140713320029008'>
m_subp = <MagicMock name='which' id='140713322657360'>

    def test_udevadm_not_present(self, m_which, m_subp):
        """where udevadm program does not exist should not invoke subp."""
        m_which.side_effect = lambda m: m in ("",)
        util.udevadm_settle()
>       m_subp.called_once_with(["which", "udevadm"])

tests/unittests/test_util.py:870: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='which' id='140713322657360'>, name = 'called_once_with'

    def __getattr__(self, name):
        if name in {'_mock_methods', '_mock_unsafe'}:
            raise AttributeError(name)
        elif self._mock_methods is not None:
            if name not in self._mock_methods or name in _all_magics:
                raise AttributeError("Mock object has no attribute %r" % name)
        elif _is_magic(name):
            raise AttributeError(name)
        if not self._mock_unsafe and (not self._mock_methods or name not in self._mock_methods):
            if name.startswith(('assert', 'assret', 'asert', 'aseert', 'assrt')) or name in _ATTRIB_DENY_LIST:
>               raise AttributeError(
                    f"{name!r} is not a valid assertion. Use a spec "
                    f"for the mock if {name!r} is meant to be an attribute.")
E               AttributeError: 'called_once_with' is not a valid assertion. Use a spec for the mock if 'called_once_with' is meant to be an attribute.. Did you mean: 'assert_called_once_with'?

/usr/lib64/python3.12/unittest/mock.py:657: AttributeError
______________ TestUdevadmSettle.test_with_exists_and_file_exists ______________

self = <tests.unittests.test_util.TestUdevadmSettle testMethod=test_with_exists_and_file_exists>
m_which = <MagicMock name='subp' id='140713300180672'>
m_subp = <MagicMock name='which' id='140713300175728'>

    def test_with_exists_and_file_exists(self, m_which, m_subp):
        """with exists=file where file does exist should only invoke subp
        once for 'which' call."""
        m_which.side_effect = lambda m: m in ("udevadm",)
        mydev = self.tmp_path("mydev")
        util.write_file(mydev, "foo\n")
        util.udevadm_settle(exists=mydev)
>       m_subp.called_once_with(["which", "udevadm"])

tests/unittests/test_util.py:888: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='which' id='140713300175728'>, name = 'called_once_with'

    def __getattr__(self, name):
        if name in {'_mock_methods', '_mock_unsafe'}:
            raise AttributeError(name)
        elif self._mock_methods is not None:
            if name not in self._mock_methods or name in _all_magics:
                raise AttributeError("Mock object has no attribute %r" % name)
        elif _is_magic(name):
            raise AttributeError(name)
        if not self._mock_unsafe and (not self._mock_methods or name not in self._mock_methods):
            if name.startswith(('assert', 'assret', 'asert', 'aseert', 'assrt')) or name in _ATTRIB_DENY_LIST:
>               raise AttributeError(
                    f"{name!r} is not a valid assertion. Use a spec "
                    f"for the mock if {name!r} is meant to be an attribute.")
E               AttributeError: 'called_once_with' is not a valid assertion. Use a spec for the mock if 'called_once_with' is meant to be an attribute.. Did you mean: 'assert_called_once_with'?

/usr/lib64/python3.12/unittest/mock.py:657: AttributeError
------------------------------ Captured log call -------------------------------
2023-05-09 11:30:38 DEBUG     cloudinit.util:util.py:2204 Writing to /tmp/ci-TestUdevadmSettle.rb8h1_zm/mydev - wb: [644] 4 bytes
______________ TestUdevadmSettle.test_with_exists_and_not_exists _______________

self = <tests.unittests.test_util.TestUdevadmSettle testMethod=test_with_exists_and_not_exists>
m_which = <MagicMock name='subp' id='140713317827216'>
m_subp = <MagicMock name='which' id='140713317837104'>

    def test_with_exists_and_not_exists(self, m_which, m_subp):
        """with exists=file where file does not exist should invoke subp."""
        m_which.side_effect = lambda m: m in ("udevadm",)
        mydev = self.tmp_path("mydev")
        util.udevadm_settle(exists=mydev)
>       m_subp.called_once_with(
            ["udevadm", "settle", "--exit-if-exists=%s" % mydev]
        )

tests/unittests/test_util.py:877: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='which' id='140713317837104'>, name = 'called_once_with'

    def __getattr__(self, name):
        if name in {'_mock_methods', '_mock_unsafe'}:
            raise AttributeError(name)
        elif self._mock_methods is not None:
            if name not in self._mock_methods or name in _all_magics:
                raise AttributeError("Mock object has no attribute %r" % name)
        elif _is_magic(name):
            raise AttributeError(name)
        if not self._mock_unsafe and (not self._mock_methods or name not in self._mock_methods):
            if name.startswith(('assert', 'assret', 'asert', 'aseert', 'assrt')) or name in _ATTRIB_DENY_LIST:
>               raise AttributeError(
                    f"{name!r} is not a valid assertion. Use a spec "
                    f"for the mock if {name!r} is meant to be an attribute.")
E               AttributeError: 'called_once_with' is not a valid assertion. Use a spec for the mock if 'called_once_with' is meant to be an attribute.. Did you mean: 'assert_called_once_with'?

/usr/lib64/python3.12/unittest/mock.py:657: AttributeError
________________ TestUdevadmSettle.test_with_exists_and_timeout ________________

self = <tests.unittests.test_util.TestUdevadmSettle testMethod=test_with_exists_and_timeout>
m_which = <MagicMock name='subp' id='140713300179664'>
m_subp = <MagicMock name='which' id='140713300166272'>

    def test_with_exists_and_timeout(self, m_which, m_subp):
        """test call with both exists and timeout."""
        m_which.side_effect = lambda m: m in ("udevadm",)
        mydev = self.tmp_path("mydev")
        timeout = "3"
        util.udevadm_settle(exists=mydev)
>       m_subp.called_once_with(
            [
                "udevadm",
                "settle",
                "--exit-if-exists=%s" % mydev,
                "--timeout=%s" % timeout,
            ]
        )

tests/unittests/test_util.py:914: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='which' id='140713300166272'>, name = 'called_once_with'

    def __getattr__(self, name):
        if name in {'_mock_methods', '_mock_unsafe'}:
            raise AttributeError(name)
        elif self._mock_methods is not None:
            if name not in self._mock_methods or name in _all_magics:
                raise AttributeError("Mock object has no attribute %r" % name)
        elif _is_magic(name):
            raise AttributeError(name)
        if not self._mock_unsafe and (not self._mock_methods or name not in self._mock_methods):
            if name.startswith(('assert', 'assret', 'asert', 'aseert', 'assrt')) or name in _ATTRIB_DENY_LIST:
>               raise AttributeError(
                    f"{name!r} is not a valid assertion. Use a spec "
                    f"for the mock if {name!r} is meant to be an attribute.")
E               AttributeError: 'called_once_with' is not a valid assertion. Use a spec for the mock if 'called_once_with' is meant to be an attribute.. Did you mean: 'assert_called_once_with'?

/usr/lib64/python3.12/unittest/mock.py:657: AttributeError
____________________ TestUdevadmSettle.test_with_no_params _____________________

self = <tests.unittests.test_util.TestUdevadmSettle testMethod=test_with_no_params>
m_which = <MagicMock name='subp' id='140713319825184'>
m_subp = <MagicMock name='which' id='140713321133168'>

    def test_with_no_params(self, m_which, m_subp):
        """called with no parameters."""
        m_which.side_effect = lambda m: m in ("udevadm",)
        util.udevadm_settle()
>       m_subp.called_once_with(mock.call(["udevadm", "settle"]))

tests/unittests/test_util.py:864: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='which' id='140713321133168'>, name = 'called_once_with'

    def __getattr__(self, name):
        if name in {'_mock_methods', '_mock_unsafe'}:
            raise AttributeError(name)
        elif self._mock_methods is not None:
            if name not in self._mock_methods or name in _all_magics:
                raise AttributeError("Mock object has no attribute %r" % name)
        elif _is_magic(name):
            raise AttributeError(name)
        if not self._mock_unsafe and (not self._mock_methods or name not in self._mock_methods):
            if name.startswith(('assert', 'assret', 'asert', 'aseert', 'assrt')) or name in _ATTRIB_DENY_LIST:
>               raise AttributeError(
                    f"{name!r} is not a valid assertion. Use a spec "
                    f"for the mock if {name!r} is meant to be an attribute.")
E               AttributeError: 'called_once_with' is not a valid assertion. Use a spec for the mock if 'called_once_with' is meant to be an attribute.. Did you mean: 'assert_called_once_with'?

/usr/lib64/python3.12/unittest/mock.py:657: AttributeError
___________________ TestUdevadmSettle.test_with_timeout_int ____________________

self = <tests.unittests.test_util.TestUdevadmSettle testMethod=test_with_timeout_int>
m_which = <MagicMock name='subp' id='140713300975424'>
m_subp = <MagicMock name='which' id='140713300970336'>

    def test_with_timeout_int(self, m_which, m_subp):
        """timeout can be an integer."""
        m_which.side_effect = lambda m: m in ("udevadm",)
        timeout = 9
        util.udevadm_settle(timeout=timeout)
>       m_subp.called_once_with(
            ["udevadm", "settle", "--timeout=%s" % timeout]
        )

tests/unittests/test_util.py:895: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='which' id='140713300970336'>, name = 'called_once_with'

    def __getattr__(self, name):
        if name in {'_mock_methods', '_mock_unsafe'}:
            raise AttributeError(name)
        elif self._mock_methods is not None:
            if name not in self._mock_methods or name in _all_magics:
                raise AttributeError("Mock object has no attribute %r" % name)
        elif _is_magic(name):
            raise AttributeError(name)
        if not self._mock_unsafe and (not self._mock_methods or name not in self._mock_methods):
            if name.startswith(('assert', 'assret', 'asert', 'aseert', 'assrt')) or name in _ATTRIB_DENY_LIST:
>               raise AttributeError(
                    f"{name!r} is not a valid assertion. Use a spec "
                    f"for the mock if {name!r} is meant to be an attribute.")
E               AttributeError: 'called_once_with' is not a valid assertion. Use a spec for the mock if 'called_once_with' is meant to be an attribute.. Did you mean: 'assert_called_once_with'?

/usr/lib64/python3.12/unittest/mock.py:657: AttributeError
__________________ TestUdevadmSettle.test_with_timeout_string __________________

self = <tests.unittests.test_util.TestUdevadmSettle testMethod=test_with_timeout_string>
m_which = <MagicMock name='subp' id='140713317872896'>
m_subp = <MagicMock name='which' id='140713317903504'>

    def test_with_timeout_string(self, m_which, m_subp):
        """timeout can be a string."""
        m_which.side_effect = lambda m: m in ("udevadm",)
        timeout = "555"
        util.udevadm_settle(timeout=timeout)
>       m_subp.called_once_with(
            ["udevadm", "settle", "--timeout=%s" % timeout]
        )

tests/unittests/test_util.py:904: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='which' id='140713317903504'>, name = 'called_once_with'

    def __getattr__(self, name):
        if name in {'_mock_methods', '_mock_unsafe'}:
            raise AttributeError(name)
        elif self._mock_methods is not None:
            if name not in self._mock_methods or name in _all_magics:
                raise AttributeError("Mock object has no attribute %r" % name)
        elif _is_magic(name):
            raise AttributeError(name)
        if not self._mock_unsafe and (not self._mock_methods or name not in self._mock_methods):
            if name.startswith(('assert', 'assret', 'asert', 'aseert', 'assrt')) or name in _ATTRIB_DENY_LIST:
>               raise AttributeError(
                    f"{name!r} is not a valid assertion. Use a spec "
                    f"for the mock if {name!r} is meant to be an attribute.")
E               AttributeError: 'called_once_with' is not a valid assertion. Use a spec for the mock if 'called_once_with' is meant to be an attribute.. Did you mean: 'assert_called_once_with'?

/usr/lib64/python3.12/unittest/mock.py:657: AttributeError
_ TestEphemeralDhcpNoNetworkSetup.test_ephemeral_dhcp_setup_network_if_url_connectivity _

self = <tests.unittests.net.test_dhcp.TestEphemeralDhcpNoNetworkSetup testMethod=test_ephemeral_dhcp_setup_network_if_url_connectivity>
m_dhcp = <MagicMock name='maybe_perform_dhcp_discovery' id='140713283780144'>
m_subp = <MagicMock name='subp' id='140713287435424'>

    @mock.patch("cloudinit.net.dhcp.subp.subp")
    @mock.patch("cloudinit.net.ephemeral.maybe_perform_dhcp_discovery")
    def test_ephemeral_dhcp_setup_network_if_url_connectivity(
        self, m_dhcp, m_subp
    ):
        """No EphemeralDhcp4 network setup when connectivity_url succeeds."""
        url = "http://example.org/index.html"
        fake_lease = {
            "interface": "eth9",
            "fixed-address": "192.168.2.2",
            "subnet-mask": "255.255.0.0",
        }
        m_dhcp.return_value = [fake_lease]
        m_subp.return_value = ("", "")
    
        self.responses.add(responses.GET, url, body=b"", status=404)
        with EphemeralDHCPv4(
            connectivity_url_data={"url": url},
        ) as lease:
            self.assertEqual(fake_lease, lease)
        # Ensure that dhcp discovery occurs
>       m_dhcp.called_once_with()

tests/unittests/net/test_dhcp.py:708: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='maybe_perform_dhcp_discovery' id='140713283780144'>
name = 'called_once_with'

    def __getattr__(self, name):
        if name in {'_mock_methods', '_mock_unsafe'}:
            raise AttributeError(name)
        elif self._mock_methods is not None:
            if name not in self._mock_methods or name in _all_magics:
                raise AttributeError("Mock object has no attribute %r" % name)
        elif _is_magic(name):
            raise AttributeError(name)
        if not self._mock_unsafe and (not self._mock_methods or name not in self._mock_methods):
            if name.startswith(('assert', 'assret', 'asert', 'aseert', 'assrt')) or name in _ATTRIB_DENY_LIST:
>               raise AttributeError(
                    f"{name!r} is not a valid assertion. Use a spec "
                    f"for the mock if {name!r} is meant to be an attribute.")
E               AttributeError: 'called_once_with' is not a valid assertion. Use a spec for the mock if 'called_once_with' is meant to be an attribute.. Did you mean: 'assert_called_once_with'?

/usr/lib64/python3.12/unittest/mock.py:657: AttributeError
----------------------------- Captured stdout call -----------------------------
FALLBACK: 2023-05-09 11:30:49,910 - url_helper.py[DEBUG]: [0/1] open 'http://example.org/index.html' with {'url': 'http://example.org/index.html', 'stream': False, 'allow_redirects': True, 'method': 'GET', 'timeout': 5.0, 'headers': {'User-Agent': 'Cloud-Init/23.1.2'}} configuration
FALLBACK: 2023-05-09 11:30:49,910 - url_helper.py[DEBUG]: [0/1] open 'http://example.org/index.html' with {'url': 'http://example.org/index.html', 'stream': False, 'allow_redirects': True, 'method': 'GET', 'timeout': 5.0, 'headers': {'User-Agent': 'Cloud-Init/23.1.2'}} configuration
FALLBACK: 2023-05-09 11:30:49,910 - url_helper.py[DEBUG]: [0/1] open 'http://example.org/index.html' with {'url': 'http://example.org/index.html', 'stream': False, 'allow_redirects': True, 'method': 'GET', 'timeout': 5.0, 'headers': {'User-Agent': 'Cloud-Init/23.1.2'}} configuration
FALLBACK: 2023-05-09 11:30:49,910 - url_helper.py[DEBUG]: [0/1] open 'http://example.org/index.html' with {'url': 'http://example.org/index.html', 'stream': False, 'allow_redirects': True, 'method': 'GET', 'timeout': 5.0, 'headers': {'User-Agent': 'Cloud-Init/23.1.2'}} configuration
FALLBACK: 2023-05-09 11:30:49,910 - url_helper.py[DEBUG]: [0/1] open 'http://example.org/index.html' with {'url': 'http://example.org/index.html', 'stream': False, 'allow_redirects': True, 'method': 'GET', 'timeout': 5.0, 'headers': {'User-Agent': 'Cloud-Init/23.1.2'}} configuration
2023-05-09 11:30:49,910 - url_helper.py[DEBUG]: [0/1] open 'http://example.org/index.html' with {'url': 'http://example.org/index.html', 'stream': False, 'allow_redirects': True, 'method': 'GET', 'timeout': 5.0, 'headers': {'User-Agent': 'Cloud-Init/23.1.2'}} configuration
DEBUG: [0/1] open 'http://example.org/index.html' with {'url': 'http://example.org/index.html', 'stream': False, 'allow_redirects': True, 'method': 'GET', 'timeout': 5.0, 'headers': {'User-Agent': 'Cloud-Init/23.1.2'}} configuration
DEBUG: [0/1] open 'http://example.org/index.html' with {'url': 'http://example.org/index.html', 'stream': False, 'allow_redirects': True, 'method': 'GET', 'timeout': 5.0, 'headers': {'User-Agent': 'Cloud-Init/23.1.2'}} configuration
FALLBACK: 2023-05-09 11:30:49,911 - ephemeral.py[DEBUG]: Received dhcp lease on eth9 for 192.168.2.2/255.255.0.0
FALLBACK: 2023-05-09 11:30:49,911 - ephemeral.py[DEBUG]: Received dhcp lease on eth9 for 192.168.2.2/255.255.0.0
FALLBACK: 2023-05-09 11:30:49,911 - ephemeral.py[DEBUG]: Received dhcp lease on eth9 for 192.168.2.2/255.255.0.0
FALLBACK: 2023-05-09 11:30:49,911 - ephemeral.py[DEBUG]: Received dhcp lease on eth9 for 192.168.2.2/255.255.0.0
FALLBACK: 2023-05-09 11:30:49,911 - ephemeral.py[DEBUG]: Received dhcp lease on eth9 for 192.168.2.2/255.255.0.0
2023-05-09 11:30:49,911 - ephemeral.py[DEBUG]: Received dhcp lease on eth9 for 192.168.2.2/255.255.0.0
DEBUG: Received dhcp lease on eth9 for 192.168.2.2/255.255.0.0
DEBUG: Received dhcp lease on eth9 for 192.168.2.2/255.255.0.0
FALLBACK: 2023-05-09 11:30:49,911 - url_helper.py[DEBUG]: [0/1] open 'http://example.org/index.html' with {'url': 'http://example.org/index.html', 'stream': False, 'allow_redirects': True, 'method': 'GET', 'timeout': 5.0, 'headers': {'User-Agent': 'Cloud-Init/23.1.2'}} configuration
FALLBACK: 2023-05-09 11:30:49,911 - url_helper.py[DEBUG]: [0/1] open 'http://example.org/index.html' with {'url': 'http://example.org/index.html', 'stream': False, 'allow_redirects': True, 'method': 'GET', 'timeout': 5.0, 'headers': {'User-Agent': 'Cloud-Init/23.1.2'}} configuration
FALLBACK: 2023-05-09 11:30:49,911 - url_helper.py[DEBUG]: [0/1] open 'http://example.org/index.html' with {'url': 'http://example.org/index.html', 'stream': False, 'allow_redirects': True, 'method': 'GET', 'timeout': 5.0, 'headers': {'User-Agent': 'Cloud-Init/23.1.2'}} configuration
FALLBACK: 2023-05-09 11:30:49,911 - url_helper.py[DEBUG]: [0/1] open 'http://example.org/index.html' with {'url': 'http://example.org/index.html', 'stream': False, 'allow_redirects': True, 'method': 'GET', 'timeout': 5.0, 'headers': {'User-Agent': 'Cloud-Init/23.1.2'}} configuration
FALLBACK: 2023-05-09 11:30:49,911 - url_helper.py[DEBUG]: [0/1] open 'http://example.org/index.html' with {'url': 'http://example.org/index.html', 'stream': False, 'allow_redirects': True, 'method': 'GET', 'timeout': 5.0, 'headers': {'User-Agent': 'Cloud-Init/23.1.2'}} configuration
2023-05-09 11:30:49,911 - url_helper.py[DEBUG]: [0/1] open 'http://example.org/index.html' with {'url': 'http://example.org/index.html', 'stream': False, 'allow_redirects': True, 'method': 'GET', 'timeout': 5.0, 'headers': {'User-Agent': 'Cloud-Init/23.1.2'}} configuration
DEBUG: [0/1] open 'http://example.org/index.html' with {'url': 'http://example.org/index.html', 'stream': False, 'allow_redirects': True, 'method': 'GET', 'timeout': 5.0, 'headers': {'User-Agent': 'Cloud-Init/23.1.2'}} configuration
DEBUG: [0/1] open 'http://example.org/index.html' with {'url': 'http://example.org/index.html', 'stream': False, 'allow_redirects': True, 'method': 'GET', 'timeout': 5.0, 'headers': {'User-Agent': 'Cloud-Init/23.1.2'}} configuration
FALLBACK: 2023-05-09 11:30:49,912 - ephemeral.py[DEBUG]: Attempting setup of ephemeral network on eth9 with 192.168.2.2/16 brd 192.168.255.255
FALLBACK: 2023-05-09 11:30:49,912 - ephemeral.py[DEBUG]: Attempting setup of ephemeral network on eth9 with 192.168.2.2/16 brd 192.168.255.255
FALLBACK: 2023-05-09 11:30:49,912 - ephemeral.py[DEBUG]: Attempting setup of ephemeral network on eth9 with 192.168.2.2/16 brd 192.168.255.255
FALLBACK: 2023-05-09 11:30:49,912 - ephemeral.py[DEBUG]: Attempting setup of ephemeral network on eth9 with 192.168.2.2/16 brd 192.168.255.255
FALLBACK: 2023-05-09 11:30:49,912 - ephemeral.py[DEBUG]: Attempting setup of ephemeral network on eth9 with 192.168.2.2/16 brd 192.168.255.255
2023-05-09 11:30:49,912 - ephemeral.py[DEBUG]: Attempting setup of ephemeral network on eth9 with 192.168.2.2/16 brd 192.168.255.255
DEBUG: Attempting setup of ephemeral network on eth9 with 192.168.2.2/16 brd 192.168.255.255
DEBUG: Attempting setup of ephemeral network on eth9 with 192.168.2.2/16 brd 192.168.255.255
------------------------------ Captured log call -------------------------------
2023-05-09 11:30:49 DEBUG     cloudinit.url_helper:url_helper.py:305 [0/1] open 'http://example.org/index.html' with {'url': 'http://example.org/index.html', 'stream': False, 'allow_redirects': True, 'method': 'GET', 'timeout': 5.0, 'headers': {'User-Agent': 'Cloud-Init/23.1.2'}} configuration
2023-05-09 11:30:49 DEBUG     cloudinit.net.ephemeral:ephemeral.py:369 Received dhcp lease on eth9 for 192.168.2.2/255.255.0.0
2023-05-09 11:30:49 DEBUG     cloudinit.url_helper:url_helper.py:305 [0/1] open 'http://example.org/index.html' with {'url': 'http://example.org/index.html', 'stream': False, 'allow_redirects': True, 'method': 'GET', 'timeout': 5.0, 'headers': {'User-Agent': 'Cloud-Init/23.1.2'}} configuration
2023-05-09 11:30:49 DEBUG     cloudinit.net.ephemeral:ephemeral.py:129 Attempting setup of ephemeral network on eth9 with 192.168.2.2/16 brd 192.168.255.255
=============================== warnings summary ===============================
../../../../usr/lib/python3.12/site-packages/_pytest/config/__init__.py:1248
  /usr/lib/python3.12/site-packages/_pytest/config/__init__.py:1248: PytestRemovedIn8Warning: The --strict option is deprecated, use --strict-markers instead.
    self.issue_config_time_warning(

cloudinit/sources/DataSourceAzure.py:8
  /builddir/build/BUILD/cloud-init-23.1.2/cloudinit/sources/DataSourceAzure.py:8: DeprecationWarning: 'crypt' is deprecated and slated for removal in Python 3.13
    import crypt

cloudinit/distros/parsers/sys_conf.py:7
  /builddir/build/BUILD/cloud-init-23.1.2/cloudinit/distros/parsers/sys_conf.py:7: DeprecationWarning: 'pipes' is deprecated and slated for removal in Python 3.13
    import pipes

tests/unittests/test_ds_identify.py::TestDsIdentify::test_ibmcloud_template_no_userdata_in_provisioning
  /usr/lib64/python3.12/unittest/case.py:690: DeprecationWarning: It is deprecated to return a value that is not None from a test case (<bound method TestDsIdentify.test_ibmcloud_template_no_userdata_in_provisioning of <tests.unittests.test_ds_identify.TestDsIdentify testMethod=test_ibmcloud_template_no_userdata_in_provisioning>>)
    return self.run(*args, **kwds)

tests/unittests/test_ds_identify.py::TestDsIdentify::test_ibmcloud_template_userdata_in_provisioning
  /usr/lib64/python3.12/unittest/case.py:690: DeprecationWarning: It is deprecated to return a value that is not None from a test case (<bound method TestDsIdentify.test_ibmcloud_template_userdata_in_provisioning of <tests.unittests.test_ds_identify.TestDsIdentify testMethod=test_ibmcloud_template_userdata_in_provisioning>>)
    return self.run(*args, **kwds)

tests/unittests/test_ds_identify.py::TestDsIdentify::test_vmware_on_vmware_open_vm_tools_64
  /usr/lib64/python3.12/unittest/case.py:690: DeprecationWarning: It is deprecated to return a value that is not None from a test case (<bound method TestDsIdentify.test_vmware_on_vmware_open_vm_tools_64 of <tests.unittests.test_ds_identify.TestDsIdentify testMethod=test_vmware_on_vmware_open_vm_tools_64>>)
    return self.run(*args, **kwds)

tests/unittests/test_ds_identify.py::TestDsIdentify::test_vmware_on_vmware_open_vm_tools_aarch64_linux_gnu
  /usr/lib64/python3.12/unittest/case.py:690: DeprecationWarning: It is deprecated to return a value that is not None from a test case (<bound method TestDsIdentify.test_vmware_on_vmware_open_vm_tools_aarch64_linux_gnu of <tests.unittests.test_ds_identify.TestDsIdentify testMethod=test_vmware_on_vmware_open_vm_tools_aarch64_linux_gnu>>)
    return self.run(*args, **kwds)

tests/unittests/test_ds_identify.py::TestDsIdentify::test_vmware_on_vmware_open_vm_tools_x86_64_linux_gnu
  /usr/lib64/python3.12/unittest/case.py:690: DeprecationWarning: It is deprecated to return a value that is not None from a test case (<bound method TestDsIdentify.test_vmware_on_vmware_open_vm_tools_x86_64_linux_gnu of <tests.unittests.test_ds_identify.TestDsIdentify testMethod=test_vmware_on_vmware_open_vm_tools_x86_64_linux_gnu>>)
    return self.run(*args, **kwds)

tests/unittests/cmd/test_main.py: 8 warnings
tests/unittests/config/test_cc_apt_pipelining.py: 4 warnings
tests/unittests/config/test_cc_bootcmd.py: 1 warning
tests/unittests/config/test_cc_growpart.py: 1 warning
tests/unittests/config/test_cc_grub_dpkg.py: 1 warning
tests/unittests/config/test_cc_mcollective.py: 2 warnings
tests/unittests/config/test_cc_mounts.py: 12 warnings
tests/unittests/config/test_cc_power_state_change.py: 5 warnings
tests/unittests/config/test_cc_runcmd.py: 9 warnings
tests/unittests/config/test_cc_scripts_vendor.py: 2 warnings
tests/unittests/config/test_cc_set_passwords.py: 3 warnings
tests/unittests/config/test_cc_snap.py: 3 warnings
tests/unittests/config/test_cc_update_etc_hosts.py: 3 warnings
tests/unittests/config/test_cc_users_groups.py: 28 warnings
tests/unittests/config/test_schema.py: 163 warnings
tests/unittests/reporting/test_reporting.py: 19 warnings
  /builddir/build/BUILD/cloud-init-23.1.2/cloudinit/config/schema.py:375: DeprecationWarning: Passing a schema to Validator.iter_errors is deprecated and will be removed in a future release. Call validator.evolve(schema=new_schema).iter_errors(...) instead.
    return next(errors, None) is None

tests/unittests/sources/test_azure.py: 71 warnings
tests/unittests/sources/test_azure_helper.py: 17 warnings
  /builddir/build/BUILD/cloud-init-23.1.2/cloudinit/sources/helpers/azure.py:1152: DeprecationWarning: Testing an element's truth value will raise an exception in future versions.  Use specific 'len(elem)' or 'elem is not None' test instead.
    if not root.find("./wa:ProvisioningSection", cls.NAMESPACES):

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/unittests/test_url_helper.py::TestDualStack::test_dual_stack[<lambda>-addresses1-1-0-None]
FAILED tests/unittests/test_util.py::TestUdevadmSettle::test_udevadm_not_present
FAILED tests/unittests/test_util.py::TestUdevadmSettle::test_with_exists_and_file_exists
FAILED tests/unittests/test_util.py::TestUdevadmSettle::test_with_exists_and_not_exists
FAILED tests/unittests/test_util.py::TestUdevadmSettle::test_with_exists_and_timeout
FAILED tests/unittests/test_util.py::TestUdevadmSettle::test_with_no_params
FAILED tests/unittests/test_util.py::TestUdevadmSettle::test_with_timeout_int
FAILED tests/unittests/test_util.py::TestUdevadmSettle::test_with_timeout_string
FAILED tests/unittests/net/test_dhcp.py::TestEphemeralDhcpNoNetworkSetup::test_ephemeral_dhcp_setup_network_if_url_connectivity
=========== 9 failed, 4571 passed, 5 skipped, 360 warnings in 40.42s ===========

All test failures except for test_dual_stack can be fixed with this commit: https://github.com/canonical/cloud-init/commit/e3f1ec3f57cc1f5eacff9506d285007966414481

https://docs.python.org/3.12/whatsnew/3.12.html

For the build logs, see:
https://copr-be.cloud.fedoraproject.org/results/@python/python3.12/fedora-rawhide-x86_64/05900415-cloud-init/

For all our attempts to build cloud-init with Python 3.12, see:
https://copr.fedorainfracloud.org/coprs/g/python/python3.12/package/cloud-init/

Testing and mass rebuild of packages is happening in copr. You can follow these instructions to test locally in mock if your package builds with Python 3.12:
https://copr.fedorainfracloud.org/coprs/g/python/python3.12/

Let us know here if you have any questions.

Python 3.12 is planned to be included in Fedora 39. To make that update smoother, we're building Fedora packages with all pre-releases of Python 3.12.
A build failure prevents us from testing all dependent packages (transitive [Build]Requires), so if this package is required a lot, it's important for us to get it fixed soon.
We'd appreciate help from the people who know this package best, but if you don't want to work on this now, let us know so we can try to work around it on our side.

Comment 1 Major Hayden 🤠 2023-05-17 13:37:03 UTC
Tomáš: Thanks for the ticket, but I'm a bit lost on how to get this fixed. I'm happy to open an issue with upstream, though.

Comment 2 Major Hayden 🤠 2023-06-22 15:44:12 UTC
@

Comment 4 Tomáš Hrnčiar 2023-06-22 17:20:13 UTC
Thank you! I've tried to do a scratch build in f39-python side-tag, but it seems like some deps are not yet ready. We will submit the build once they are.

Comment 5 Major Hayden 🤠 2023-07-24 18:38:45 UTC
This one is good to go now.