public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
* [pve-devel] [PATCH v1 master ceph 0/2] Fix Ceph Squid Module Loading
@ 2025-07-16 17:39 Max R. Carrara
  2025-07-16 17:39 ` [pve-devel] [PATCH v1 master ceph 1/2] provide workaround for PyO3 ImportError Max R. Carrara
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Max R. Carrara @ 2025-07-16 17:39 UTC (permalink / raw)
  To: pve-devel

Fix Ceph Squid Module Loading - v1
==================================

The first patch provides a workaround for the PyO3 ImportError that's
being thrown by the `restful` Ceph mgr Python module upon import.
This fixes the following error:

    2025-07-16T17:40:40.932+0200 7c315bc77080  1 mgr[py] Loading python module 'restful'
    2025-07-16T17:40:41.220+0200 7c315bc77080 -1 mgr[py] Module not found: 'restful'
    2025-07-16T17:40:41.220+0200 7c315bc77080 -1 mgr[py] Traceback (most recent call last):
      File "/usr/share/ceph/mgr/restful/__init__.py", line 1, in <module>
        from .module import Module
      File "/usr/share/ceph/mgr/restful/module.py", line 22, in <module>
        from OpenSSL import crypto
      File "/lib/python3/dist-packages/OpenSSL/__init__.py", line 8, in <module>
        from OpenSSL import SSL, crypto
      File "/lib/python3/dist-packages/OpenSSL/SSL.py", line 15, in <module>
        from cryptography import x509
      File "/lib/python3/dist-packages/cryptography/x509/__init__.py", line 7, in <module>
        from cryptography.x509 import certificate_transparency, verification
      File "/lib/python3/dist-packages/cryptography/x509/certificate_transparency.py", line 11, in <module>
        from cryptography.hazmat.bindings._rust import x509 as rust_x509
    ImportError: PyO3 modules compiled for CPython 3.8 or older may only be initialized once per interpreter process

    2025-07-16T17:40:41.222+0200 7c315bc77080 -1 mgr[py] Class not found in module 'restful'
    2025-07-16T17:40:41.222+0200 7c315bc77080 -1 mgr[py] Error loading module 'restful': (2) No such file or directory


The second patch fixes how the Ceph mgr looks up the NOTIFY_TYPES
attribute of the mgr Python modules' classes. This also happens to fix
the `mgr_module` Python module import failure. In total, this fixes
errors like the following:

    2025-07-16T17:40:41.222+0200 7c315bc77080  1 mgr[py] Loading python module 'selftest'
    2025-07-16T17:40:41.377+0200 7c315bc77080 -1 mgr[py] Module selftest has missing NOTIFY_TYPES member
    2025-07-16T17:40:41.377+0200 7c315bc77080 -1 mgr[py] Module not found: 'mgr_module'
    2025-07-16T17:40:41.377+0200 7c315bc77080 -1 mgr[py] AttributeError: type object 'Module' has no attribute 'NOTIFY_TYPES'
    
    2025-07-16T17:40:41.377+0200 7c315bc77080  1 mgr[py] Loading python module 'snap_schedule'
    2025-07-16T17:40:41.497+0200 7c315bc77080 -1 mgr[py] Module snap_schedule has missing NOTIFY_TYPES member
    2025-07-16T17:40:41.497+0200 7c315bc77080 -1 mgr[py] Module not found: 'mgr_module'
    2025-07-16T17:40:41.497+0200 7c315bc77080 -1 mgr[py] AttributeError: type object 'Module' has no attribute 'NOTIFY_TYPES'
    
    2025-07-16T17:40:41.497+0200 7c315bc77080  1 mgr[py] Loading python module 'stats'
    2025-07-16T17:40:41.636+0200 7c315bc77080  1 mgr[py] Loading python module 'status'
    2025-07-16T17:40:41.785+0200 7c315bc77080 -1 mgr[py] Module status has missing NOTIFY_TYPES member
    2025-07-16T17:40:41.785+0200 7c315bc77080 -1 mgr[py] Module not found: 'mgr_module'
    2025-07-16T17:40:41.785+0200 7c315bc77080 -1 mgr[py] AttributeError: type object 'Module' has no attribute 'NOTIFY_TYPES'

Note: These logs can be found inside the ceph-mgr logs in the
/var/log/ceph directory.

The commit messages of the supplied patches elaborate on further
details.

Summary of Changes
------------------

Max R. Carrara (2):
  provide workaround for PyO3 ImportError
  mgr: fix errors regarding module imports and NOTIFY_TYPES attributes

 ...ul-provide-workaround-for-PyO3-Impor.patch | 152 ++++++++++++++++++
 ...mport-by-making-NOTIFY_TYPES-in-py-m.patch |  56 +++++++
 patches/series                                |   2 +
 3 files changed, 210 insertions(+)
 create mode 100644 patches/0058-pybind-mgr-restful-provide-workaround-for-PyO3-Impor.patch
 create mode 100644 patches/0059-mgr-fix-module-import-by-making-NOTIFY_TYPES-in-py-m.patch

-- 
2.39.5



_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [pve-devel] [PATCH v1 master ceph 1/2] provide workaround for PyO3 ImportError
  2025-07-16 17:39 [pve-devel] [PATCH v1 master ceph 0/2] Fix Ceph Squid Module Loading Max R. Carrara
@ 2025-07-16 17:39 ` Max R. Carrara
  2025-07-16 17:39 ` [pve-devel] [PATCH v1 master ceph 2/2] mgr: fix errors regarding module imports and NOTIFY_TYPES attributes Max R. Carrara
  2025-07-16 20:15 ` [pve-devel] applied-series: [PATCH v1 master ceph 0/2] Fix Ceph Squid Module Loading Thomas Lamprecht
  2 siblings, 0 replies; 4+ messages in thread
From: Max R. Carrara @ 2025-07-16 17:39 UTC (permalink / raw)
  To: pve-devel

By moving the self-signed cert generation into a separate module and
consequently running it via `subprocess.run`--so, as a new,
independent Python process--the PyO3 ImportError is successfully
avoided.

Inspired by an upstream PR [0].

[0]: https://github.com/ceph/ceph/pull/62951

Signed-off-by: Max R. Carrara <m.carrara@proxmox.com>
---
 ...ul-provide-workaround-for-PyO3-Impor.patch | 152 ++++++++++++++++++
 patches/series                                |   1 +
 2 files changed, 153 insertions(+)
 create mode 100644 patches/0058-pybind-mgr-restful-provide-workaround-for-PyO3-Impor.patch

diff --git a/patches/0058-pybind-mgr-restful-provide-workaround-for-PyO3-Impor.patch b/patches/0058-pybind-mgr-restful-provide-workaround-for-PyO3-Impor.patch
new file mode 100644
index 0000000000..25fb720410
--- /dev/null
+++ b/patches/0058-pybind-mgr-restful-provide-workaround-for-PyO3-Impor.patch
@@ -0,0 +1,152 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Max R. Carrara" <m.carrara@proxmox.com>
+Date: Wed, 16 Jul 2025 13:14:39 +0200
+Subject: [PATCH 58/59] pybind/mgr/restful: provide workaround for PyO3
+ ImportError
+
+Move the self-signed cert generation into a separate module
+inside python-common/ceph and run the module in a separate Python
+process.
+
+This provides a workaround for the ImportError thrown by PyO3 when
+the `restful` module is loaded in the context of multiple Python
+sub-interpreters being present. In particular, the ImportError is
+thrown by the `crypto` module of the `OpenSSL` package.
+
+Inspired by an upstream PR [0].
+
+[0]: https://github.com/ceph/ceph/pull/62951
+
+Signed-off-by: Max R. Carrara <m.carrara@proxmox.com>
+---
+ src/pybind/mgr/restful/module.py       | 24 +++------
+ src/python-common/ceph/_crypto_wrap.py | 69 ++++++++++++++++++++++++++
+ 2 files changed, 76 insertions(+), 17 deletions(-)
+ create mode 100644 src/python-common/ceph/_crypto_wrap.py
+
+diff --git a/src/pybind/mgr/restful/module.py b/src/pybind/mgr/restful/module.py
+index 0f8c78e0bd8..7f93c41f1e6 100644
+--- a/src/pybind/mgr/restful/module.py
++++ b/src/pybind/mgr/restful/module.py
+@@ -7,6 +7,7 @@ import json
+ import time
+ import errno
+ import inspect
++import subprocess
+ import tempfile
+ import threading
+ import traceback
+@@ -19,7 +20,6 @@ from . import context
+ 
+ from uuid import uuid4
+ from pecan import jsonify, make_app
+-from OpenSSL import crypto
+ from pecan.rest import RestController
+ from werkzeug.serving import make_server, make_ssl_devcert
+ 
+@@ -401,24 +401,14 @@ class Module(MgrModule):
+ 
+ 
+     def create_self_signed_cert(self):
+-        # create a key pair
+-        pkey = crypto.PKey()
+-        pkey.generate_key(crypto.TYPE_RSA, 2048)
+-
+-        # create a self-signed cert
+-        cert = crypto.X509()
+-        cert.get_subject().O = "IT"
+-        cert.get_subject().CN = "ceph-restful"
+-        cert.set_serial_number(int(uuid4()))
+-        cert.gmtime_adj_notBefore(0)
+-        cert.gmtime_adj_notAfter(10*365*24*60*60)
+-        cert.set_issuer(cert.get_subject())
+-        cert.set_pubkey(pkey)
+-        cert.sign(pkey, 'sha512')
++        cmd = ["python3", "-m", "ceph._crypto_wrap", "create_self_signed_cert"]
++
++        response = subprocess.run(cmd, capture_output=True, check=True)
++        response_obj = json.loads(response.stdout)
+ 
+         return (
+-            crypto.dump_certificate(crypto.FILETYPE_PEM, cert),
+-            crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey)
++            response_obj["cert"].encode("utf-8"),
++            response_obj["key"].encode("utf-8"),
+         )
+ 
+ 
+diff --git a/src/python-common/ceph/_crypto_wrap.py b/src/python-common/ceph/_crypto_wrap.py
+new file mode 100644
+index 00000000000..16a19a5345e
+--- /dev/null
++++ b/src/python-common/ceph/_crypto_wrap.py
+@@ -0,0 +1,69 @@
++"""CLI wrapper for cryptographic functions of the :mod:`restful` module.
++
++To be called via :func:`subprocess.run()` as a workaround for
++:class:`ImportError`s related to PyO3's current lack of sub-interpreter
++support.
++
++Note:
++    Since this module is installed as part of the ``ceph`` package,
++    it should be called like so::
++
++        python3 -m ceph._crypto_wrap create_self_signed_cert
++"""
++
++import argparse
++import sys
++import json
++
++from argparse import Namespace
++from typing import Any
++from uuid import uuid4
++
++from OpenSSL import crypto
++
++
++def _respond(data: dict[str, Any]) -> None:
++    json.dump(data, sys.stdout)
++    sys.stdout.flush()
++
++
++def create_self_signed_cert(args: Namespace) -> None:
++    cert_key_pair = _create_self_signed_cert()
++    _respond(cert_key_pair)
++
++
++def _create_self_signed_cert() -> dict[str, str]:
++    # create a key pair
++    pubkey = crypto.PKey()
++    pubkey.generate_key(crypto.TYPE_RSA, 2048)
++
++    # create a self-signed cert
++    cert = crypto.X509()
++    cert.get_subject().O = "IT"
++    cert.get_subject().CN = "ceph-restful"
++    cert.set_serial_number(int(uuid4()))
++    cert.gmtime_adj_notBefore(0)
++    cert.gmtime_adj_notAfter(10 * 365 * 24 * 60 * 60)
++    cert.set_issuer(cert.get_subject())
++    cert.set_pubkey(pubkey)
++    cert.sign(pubkey, "sha512")
++
++    return {
++        "cert": crypto.dump_certificate(crypto.FILETYPE_PEM, cert).decode(),
++        "key": crypto.dump_privatekey(crypto.FILETYPE_PEM, pubkey).decode(),
++    }
++
++
++def main() -> None:
++    parser = argparse.ArgumentParser(prog="_crypto_wrap.py")
++    subparsers = parser.add_subparsers(required=True)
++
++    parser_cssc = subparsers.add_parser("create_self_signed_cert")
++    parser_cssc.set_defaults(func=create_self_signed_cert)
++
++    args = parser.parse_args()
++    args.func(args)
++
++
++if __name__ == "__main__":
++    main()
diff --git a/patches/series b/patches/series
index 728a9f935e..ff23f8b640 100644
--- a/patches/series
+++ b/patches/series
@@ -51,3 +51,4 @@
 0055-python-common-cryptotools-catch-all-failures-to-read.patch
 0056-mgr-cephadm-always-use-the-internal-cryptocaller.patch
 0057-mgr-dashboard-add-an-option-to-control-the-dashboard.patch
+0058-pybind-mgr-restful-provide-workaround-for-PyO3-Impor.patch
-- 
2.39.5



_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [pve-devel] [PATCH v1 master ceph 2/2] mgr: fix errors regarding module imports and NOTIFY_TYPES attributes
  2025-07-16 17:39 [pve-devel] [PATCH v1 master ceph 0/2] Fix Ceph Squid Module Loading Max R. Carrara
  2025-07-16 17:39 ` [pve-devel] [PATCH v1 master ceph 1/2] provide workaround for PyO3 ImportError Max R. Carrara
@ 2025-07-16 17:39 ` Max R. Carrara
  2025-07-16 20:15 ` [pve-devel] applied-series: [PATCH v1 master ceph 0/2] Fix Ceph Squid Module Loading Thomas Lamprecht
  2 siblings, 0 replies; 4+ messages in thread
From: Max R. Carrara @ 2025-07-16 17:39 UTC (permalink / raw)
  To: pve-devel

By handling the AttributeError that is thrown internally, the import
of several mgr modules also works again.

See the patch's message for all details.

Signed-off-by: Max R. Carrara <m.carrara@proxmox.com>
---
 ...mport-by-making-NOTIFY_TYPES-in-py-m.patch | 56 +++++++++++++++++++
 patches/series                                |  1 +
 2 files changed, 57 insertions(+)
 create mode 100644 patches/0059-mgr-fix-module-import-by-making-NOTIFY_TYPES-in-py-m.patch

diff --git a/patches/0059-mgr-fix-module-import-by-making-NOTIFY_TYPES-in-py-m.patch b/patches/0059-mgr-fix-module-import-by-making-NOTIFY_TYPES-in-py-m.patch
new file mode 100644
index 0000000000..5595c96c9e
--- /dev/null
+++ b/patches/0059-mgr-fix-module-import-by-making-NOTIFY_TYPES-in-py-m.patch
@@ -0,0 +1,56 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Max R. Carrara" <m.carrara@proxmox.com>
+Date: Wed, 16 Jul 2025 16:31:43 +0200
+Subject: [PATCH 59/59] mgr: fix module import by making NOTIFY_TYPES in py
+ modules optional
+
+If NOTIFY_TYPES isn't an attribute of the passed class, the Python
+(sub-)interpreter raises an AttributeError that must be handled or cleared
+explicitly via the Python C-API. Unfortunately, this isn't done here,
+which means that the exception sticks around until handled.
+
+This caused a call to PyModule::load_subclass_of() to fail and
+incorrectly report the AttributeError as cause.
+
+Checking whether the class has NOTIFY_TYPES as attribute in the first
+place fixes this.
+
+Note that there's an upstream PR [0] that wasn't backported that aimed
+to fix this, but does so incorrectly, as the exception is still not
+cleared there. The warnings regarding NOTIFY_TYPES missing also occurs
+on Reef but doesn't cause any module imports to fail there. As the
+affected Ceph code has stayed mostly the same between bookworm and
+trixie releases, this suggests that some behavior between Python 3.11
+and 3.13 likely changed.
+
+Either way, avoiding the AttributeError altogether fixes this.
+
+[0]: https://github.com/ceph/ceph/pull/57106
+
+Signed-off-by: Max R. Carrara <m.carrara@proxmox.com>
+---
+ src/mgr/PyModule.cc | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/src/mgr/PyModule.cc b/src/mgr/PyModule.cc
+index 084cf3ffc1e..e6fd269dca5 100644
+--- a/src/mgr/PyModule.cc
++++ b/src/mgr/PyModule.cc
+@@ -513,11 +513,13 @@ int PyModule::register_options(PyObject *cls)
+ 
+ int PyModule::load_notify_types()
+ {
+-  PyObject *ls = PyObject_GetAttrString(pClass, "NOTIFY_TYPES");
+-  if (ls == nullptr) {
+-    derr << "Module " << get_name() << " has missing NOTIFY_TYPES member" << dendl;
+-    return -EINVAL;
++  if (!PyObject_HasAttrString(pClass, "NOTIFY_TYPES")) {
++    dout(10) << "Module " << get_name() << " has no NOTIFY_TYPES member" << dendl;
++    return 0;
+   }
++
++  PyObject *ls = PyObject_GetAttrString(pClass, "NOTIFY_TYPES");
++
+   if (!PyObject_TypeCheck(ls, &PyList_Type)) {
+     // Relatively easy mistake for human to make, e.g. defining COMMANDS
+     // as a {} instead of a []
diff --git a/patches/series b/patches/series
index ff23f8b640..b820614566 100644
--- a/patches/series
+++ b/patches/series
@@ -52,3 +52,4 @@
 0056-mgr-cephadm-always-use-the-internal-cryptocaller.patch
 0057-mgr-dashboard-add-an-option-to-control-the-dashboard.patch
 0058-pybind-mgr-restful-provide-workaround-for-PyO3-Impor.patch
+0059-mgr-fix-module-import-by-making-NOTIFY_TYPES-in-py-m.patch
-- 
2.39.5



_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [pve-devel] applied-series: [PATCH v1 master ceph 0/2] Fix Ceph Squid Module Loading
  2025-07-16 17:39 [pve-devel] [PATCH v1 master ceph 0/2] Fix Ceph Squid Module Loading Max R. Carrara
  2025-07-16 17:39 ` [pve-devel] [PATCH v1 master ceph 1/2] provide workaround for PyO3 ImportError Max R. Carrara
  2025-07-16 17:39 ` [pve-devel] [PATCH v1 master ceph 2/2] mgr: fix errors regarding module imports and NOTIFY_TYPES attributes Max R. Carrara
@ 2025-07-16 20:15 ` Thomas Lamprecht
  2 siblings, 0 replies; 4+ messages in thread
From: Thomas Lamprecht @ 2025-07-16 20:15 UTC (permalink / raw)
  To: pve-devel, Max R. Carrara

On Wed, 16 Jul 2025 19:39:54 +0200, Max R. Carrara wrote:
> Fix Ceph Squid Module Loading - v1
> ==================================
> 
> The first patch provides a workaround for the PyO3 ImportError that's
> being thrown by the `restful` Ceph mgr Python module upon import.
> This fixes the following error:
> 
> [...]

Patches seem relatively straight forward and I saw no new crash reports about
mgr modules in my test cluster, so:

Applied, thanks!

[1/2] provide workaround for PyO3 ImportError
      commit: 51c4e16ffa4d46944b03b376e14aa92c7ca758ab
[2/2] mgr: fix errors regarding module imports and NOTIFY_TYPES attributes
      commit: 099772ef89be90332860fc9606b70ee5ad6b6d38


_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2025-07-16 20:14 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-07-16 17:39 [pve-devel] [PATCH v1 master ceph 0/2] Fix Ceph Squid Module Loading Max R. Carrara
2025-07-16 17:39 ` [pve-devel] [PATCH v1 master ceph 1/2] provide workaround for PyO3 ImportError Max R. Carrara
2025-07-16 17:39 ` [pve-devel] [PATCH v1 master ceph 2/2] mgr: fix errors regarding module imports and NOTIFY_TYPES attributes Max R. Carrara
2025-07-16 20:15 ` [pve-devel] applied-series: [PATCH v1 master ceph 0/2] Fix Ceph Squid Module Loading Thomas Lamprecht

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal