plone / Products.CMFPlone

The core of the Plone content management system
https://plone.org
GNU General Public License v2.0
246 stars 186 forks source link

overview-controlpanel view do not work with gunicorn #3442

Closed bsuttor closed 2 years ago

bsuttor commented 2 years ago

BUG/PROBLEM REPORT (OR OTHER COMMON ISSUE)

overview-controlpanel view do not work with gunicorn. This view get server_name from SERVER_SOFTWARE environment variable and try to parse this name to get version from pkg_resources. (https://github.com/plone/Products.CMFPlone/blob/master/Products/CMFPlone/controlpanel/browser/overview.py#L55)

As I can see in Gunicorn, SERVER_SOFTWARE variable is equal to "gunicorn/19.9.0" (https://github.com/benoitc/gunicorn/blob/19.x/gunicorn/__init__.py#L8) which is not parsable for pkg_resources.

What I did:

I start buildout coredev with wsgioptions.cfg config file and start gunicorn-instance like that:

./bin/buildout -c wsgioptions.cfg
./bin/gunicorn-instance

then create a Plone site and go to http://localhost:8080/Plone/overview-controlpanel

What I expect to happen:

overview-controlpanel view with all information about server (gunicorn version, plone version, python version, ...)

What actually happened:

a template error

Traceback (innermost last):
  Module ZPublisher.WSGIPublisher, line 167, in transaction_pubevents
  Module ZPublisher.WSGIPublisher, line 376, in publish_module
  Module ZPublisher.WSGIPublisher, line 271, in publish
  Module ZPublisher.mapply, line 85, in mapply
  Module ZPublisher.WSGIPublisher, line 68, in call_object
  Module Products.CMFPlone.controlpanel.browser.overview, line 34, in __call__
  Module Products.Five.browser.pagetemplatefile, line 126, in __call__
  Module Products.Five.browser.pagetemplatefile, line 58, in __call__
  Module zope.pagetemplate.pagetemplate, line 133, in pt_render
  Module Products.PageTemplates.engine, line 365, in __call__
  Module z3c.pt.pagetemplate, line 176, in render
  Module chameleon.zpt.template, line 302, in render
  Module chameleon.template, line 215, in render
  Module chameleon.utils, line 53, in raise_with_traceback
  Module chameleon.template, line 192, in render
  Module 73c1d855834a9decac0c0da98ce48be5, line 1255, in render
  Module 4a6b6042c5725aa6b3a089c76a55dfe1, line 913, in render_master
  Module a990005b16c5c23df8d22e18c41fcf46, line 925, in render_master
  Module 4a6b6042c5725aa6b3a089c76a55dfe1, line 888, in __fill_content
  Module a990005b16c5c23df8d22e18c41fcf46, line 1581, in render_content
  Module 4a6b6042c5725aa6b3a089c76a55dfe1, line 874, in __fill_main
  Module 73c1d855834a9decac0c0da98ce48be5, line 1000, in __fill_prefs_configlet_main
  Module zope.tales.expressions, line 250, in __call__
  Module Products.PageTemplates.Expressions, line 221, in _eval
  Module Products.PageTemplates.Expressions, line 152, in render
  Module Products.CMFPlone.controlpanel.browser.overview, line 61, in server_info
  Module pkg_resources, line 469, in get_distribution
  Module pkg_resources, line 3154, in parse
  Module pkg_resources, line 3099, in parse_requirements
  Module pkg_resources, line 3109, in __init__
  Module pkg_resources.extern.packaging.requirements, line 104, in __init__
pkg_resources.extern.packaging.requirements.InvalidRequirement: pkg_resources.extern.packaging.requirements.InvalidRequirement: Parse error at "'/19.9.0'": Expected stringEnd

What version of Plone/ Addons I am using:

6.0.0a3

ale-rt commented 2 years ago

Thanks for reporting and I see you are already working on this.

What about changing:

            except (
                pkg_resources.DistributionNotFound,
                pkg_resources.RequirementParseError,
            ):
               pass

to

            except Exception:
                warnings.error("Cannot parse version for %r", self.request.get("SERVER_SOFTWARE"))

Goal is to avoid breakage and to make devs aware that something has to be fixed without spamming them

mauritsvanrees commented 2 years ago

A warning helps yes. And I do not use the warnings module often enough. It should be warnings.warn though. error does not exist.

mauritsvanrees commented 2 years ago

What is a bit weird/sad though, is that the InvalidRequirement exception that @bsuttor gets, is not caught by the try/except RequirementParseError. From a pdbpp session it looks like this would be meant to work. Maybe it worked in earlier Python versions.

(Pdb++) pkg_resources.extern.packaging.requirements.InvalidRequirement?
Type:           type
String Form:    <class 'pkg_resources.extern.packaging.requirements.InvalidRequirement'>
File:           /Users/maurits/community/plone-coredev/6.0/lib/python3.9/site-packages/pkg_resources/_vendor/packaging/requirements.py
Docstring:      
    An invalid requirement was found, users should refer to PEP 508.

Constructor information: 
 Docstring:     Initialize self.  See help(type(self)) for accurate signature.
(Pdb++) pkg_resources.RequirementParseError?
Type:           type
String Form:    <class 'pkg_resources.RequirementParseError'>
File:           /Users/maurits/community/plone-coredev/6.0/lib/python3.9/site-packages/pkg_resources/__init__.py
Docstring:      Compatibility wrapper for InvalidRequirement
Constructor information: 
 Docstring:     Initialize self.  See help(type(self)) for accurate signature.
bsuttor commented 2 years ago

Thank you @ale-rt ,

There is another related PR on buildout.coredev, Indeed, I was not able to start buildout ./bin/buildout -c wsgioptions.cfg because of not compatible version of greenlet with python 3.9: https://github.com/plone/buildout.coredev/pull/777

Would you like another PR to use

            except Exception:
                warnings.warn("Cannot parse version for %r", self.request.get("SERVER_SOFTWARE"))

instead of

            except (
                pkg_resources.DistributionNotFound,
                pkg_resources.RequirementParseError,
            ):
               pass

?

ale-rt commented 2 years ago

It would be great if you have time to do that!

bsuttor commented 2 years ago

I'm working on it, but I have one question, for my new test, gunicorn is needed into test eggs. But I don't know where is the best place to add it. Is it in the test section of setup.py of Products.CMFPlone or into buildout.cordev ? I think it's related of Products.CMFPlone, so maybe it's better to put gunicorn in setup.py file ?