Как запустить форму portal_quickinstaller.reinstallProducts за пределами сайта Plone?

Мы используем сервер Zope с большим количеством сайтов Plone (4). Время от времени появляется обновление продукта расширения, которое требует переустановки, чтобы принять изменения в настройках профиля, например. новые типы контента.

Вручную это означало бы щелкнуть portal_quickinstaller каждого сайта Plone, отметить продукты, нажать обновить. Это не очень осуществимо, если мы говорим о десятках сайтов, поэтому я пытаюсь автоматизировать это. По сути, до сих пор у меня есть следующий сценарий (Python) в корне Zope:

a = context.restrictedTraverse('/')

p = a['Plone']
print p.getSiteManager()
qi = p.restrictedTraverse('portal_quickinstaller')
print qi
qi.reinstallProducts('LinguaPlone')

(Упрощенно; на самом деле у меня есть более длинный список вместо одного экземпляра Plone, и я мог бы захотеть переустановить более длинный список продуктов.) Это приводит к следующему сбою:

  Module Products.CMFQuickInstallerTool.QuickInstallerTool, line 613, in uninstallProducts
  Module Products.CMFQuickInstallerTool.InstalledProduct, line 272, in uninstall
  Module Products.CMFQuickInstallerTool.InstalledProduct, line 351, in _cascadeRemove
AttributeError: 'BaseGlobalComponents' object has no attribute 'objectItems'

Судя по моим попыткам отладки, BaseGlobalComponents — это Zope SiteManager, возвращаемый zope.component.getSiteManager. Как мне убедить quickinstaller выбрать правильный, т.е. тот, который находится на сайте Plone?

В качестве альтернативы, как мне автоматизировать переустановку продуктов таким образом, чтобы это было неосуществимо для более крупных установок? (ETA: я знаю, что это не то, что вы делаете автоматически с помощью cronjob, но, боюсь, нельзя избежать обновлений продуктов собственной разработки.)


person Ulrich Schwarz    schedule 28.04.2011    source источник


Ответы (4)


Вот как изменить активного локального менеджера сайта. Вы не сможете сделать это в Restricted Python, поэтому вам нужно будет превратить свой скрипт Python во внешний метод или представление браузера.

from zope.app.component.hooks import setHooks, setSite
setHooks()
setSite(site)

Вызов setHooks нужно сделать только один раз. В Zope 2.12 эти вызовы следует импортировать из zope.site.hooks, а в Zope 2.13 — из zope.component.hooks.

Имейте в виду, что вызов reinstallProducts подходит не для всех дополнительных продуктов и не рекомендуется, если вы тщательно не проверили, что делает переустановка, и не уверены, что это не вызовет проблем. Некоторые продукты предоставляют этапы обновления, которые выполняют действия более избирательно.

person David Glick    schedule 28.04.2011
comment
Спасибо, похоже, это и есть тот магический призыв, который я искал, попробую утром. Поскольку у меня есть определенный контроль над многими продуктами, для которых это будет использоваться, любые проблемы будут, по крайней мере, обучающим опытом. ;) - person Ulrich Schwarz; 28.04.2011

Отказ от ответственности: вы уверены, что хотите это сделать? Автоматическая переустановка и обновление продуктов до последней версии вслепую и без какого-либо тестирования на промежуточном экземпляре вызывает проблемы.

Во всяком случае, вы можете сделать это с помощью XML-RPC и небольшой настройки. Вот как вы устанавливаете продукт на работающий экземпляр с помощью XML-RPC:

>>> import xmlrpclib
>>> proxy = xmlrpclib.ServerProxy(
        "http://admin:passwd@localhost:8080/Plone/portal_quickinstaller"
    )
>>> proxy.getProductVersion('Marshall')
'2.0'
>>> proxy.isProductInstalled('Marshall')
'False'
>>> proxy.installProduct('Marshall')
'Registry installed sucessfully.\n'
>>> proxy.isProductInstalled('Marshall')
'True'

Для переустановки вам потребуется подкласс Products.CMFQuickInstallerTool.QuickInstallerTool.py и предоставить вам пользовательский QuickInstallerTool с методом, в котором аргумент ключевого слова «переустановить» установлен как «Истина» по умолчанию; что-то типа:

442c442
<                        swallowExceptions=None, reinstall=False,
---
>                        swallowExceptions=None, reinstall=True,
452,457c452,457
<         if self.isProductInstalled(p):
<             prod = self._getOb(p)
<             msg = ('This product is already installed, '
<                    'please uninstall before reinstalling it.')
<             prod.log(msg)
<             return msg
---
>         #if self.isProductInstalled(p):
>         #    prod = self._getOb(p)
>         #    msg = ('This product is already installed, '
>         #           'please uninstall before reinstalling it.')
>         #    prod.log(msg)
>         #    return msg

Еще лучше: предоставьте свой собственный метод сбора информации о версиях и переустановки продукта, совместимый с протоколом XML-RPC (поскольку вы не можете передавать аргументы с ключевыми словами).

Возможно, существуют более чистые способы сделать это с помощью XML-RPC, но portal_quickinstaller не предназначен для использования таким образом, и могут быть предостережения. Используйте с осторожностью.

person Rigel Di Scala    schedule 28.04.2011

У меня есть этот скрипт Python в корне Zope экземпляра с 7 сайтами Plone. Выглядит примерно так же, как у вас. Возможно, он работает только на этом сайте Plone 2.5 (да, старом), но я думаю, что он должен работать и на 3.x и 4.x. Возможно, невинная разница (которую я упускаю из виду) вызывает ошибку в вашем сценарии; может быть, ограничения Traverses, которые вы делаете, сбивают с толку. (Сценарий отредактирован для ясности.)

SITES = ['site-1', 'site-2']
for site in SITES:
    print "Reinstalling LinguaPlone in %s." % site
    portal = context[site]
    qi = portal.portal_quickinstaller
    qi.reinstallProducts(['LinguaPlone'])
person maurits    schedule 28.04.2011
comment
Боюсь, все та же ошибка на 4.0.5, но спасибо за поиск. - person Ulrich Schwarz; 29.04.2011

Во-первых, не делайте переустановку, это может привести к поломке вашего сайта во многих случаях.

Далее вы должны учитывать, что надстройки могут предоставлять шаг обновления (обычно так и есть). Используйте API быстрой установки, чтобы добиться этого в PythonScript. Это хорошо, но этого можно добиться и скриптом в файловой системе. Посмотрите примеры здесь: http://svn.plone.org/svn/plone/plone.org/Products.PloneOrg/trunk/scripts/

Другим решением может быть использование Selenium IDE для записи материалов быстрой установки на одном сайте и копирования результатов этих тестов для запуска на другом веб-сайте (очень странно, не так ли?)

person toutpt    schedule 28.04.2011
comment
Без настройки сайта вручную API quickinstaller работает только при вызове изнутри сайта Plone, именно это и было моим камнем преткновения. ;) - person Ulrich Schwarz; 29.04.2011