#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, это как раз и было моим камнем преткновения. 😉