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

#plone #zope

#plone #zope

Вопрос:

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

Вручную это означало бы переходить на каждый сайт Plone portal_quickinstaller , отмечать продукты, нажимать обновить. Это не очень выполнимо, если мы говорим о десятках сайтов, поэтому я пытаюсь это автоматизировать. По сути, на данный момент у меня есть следующее, живущее как скрипт (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, но, боюсь, обновлений продуктов собственной разработки избежать невозможно.)

Ответ №1:

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

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

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

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

Комментарии:

1. Спасибо, похоже, это может быть магический вызов, который я искал, я попробую это утром. Поскольку у меня есть определенный контроль над многими продуктами, для которых это будет использоваться, любые проблемы, по крайней мере, будут опытом обучения. 😉

Ответ №2:

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

В любом случае, вы можете сделать это с помощью 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'
  

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

 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 не предназначен для использования таким образом, и могут быть оговорки. Используйте с осторожностью.

Ответ №3:

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

 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'])
  

Комментарии:

1. Боюсь, что в версии 4.0.5 все та же ошибка, но спасибо, что посмотрели ее.

Ответ №4:

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

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

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

Комментарии:

1. Без настройки сайта вручную api quickinstaller работает только при вызове изнутри сайта Plone, это как раз и было моим камнем преткновения. 😉