Creare un pacchetto policy autoconfigurante per Plone
medio
In questo how-to vedremo in pochi passi come sia possibile creare un pacchetto di tipo policy che installa automaticamente tutte le dipendenze del nostro ambiente o prodotto ed effettua delle configurazioni, il tutto selezionando ed installando un unico pacchetto auto-configurante nella sezione dei prodotti aggiuntivi!
Scopo
Spesso è molto utile avere dei prodotti nel proprio Plone che configurano automaticamente un'applicazione molto complessa e modulare, determinando un notevole risparmio di tempo nella messa in produzione ed evitando di compiere lunghe e noiose operazioni manuali.
Ecco i principali svantaggi di una configurazione effettuata manualmente:
- non sono replicabili e documentate;
- non sono testabili automaticamente;
- ... se dovessi riperetere la stessa cosa su decine di portali?!
- tra qualche mese mi ricorderò cos'ho fatto esattamente?
Per esempio potrei voler prepopolare dei contenuti, installare altri prodotti, installare ATVocabularyManager e prepopolare dei vocabolari da utilizzare nei miei oggetti Archetype, creare degli utenti con ruoli diversi per una demo di applicazione, ecc., tutte operazioni lunghe e sensibili ad errori di distrazione.
In questa breve guida quindi illustreremo in maniera efficace come creare dei prodotti per Plone che, con un solo click del mouse, vengono installati automaticamente con tutte le proprie dipendenze ed effettuano delle configurazioni!
Prerequisiti
Se si crea un prodotto ex-novo può essere utile creare un nuovo pacchetto con l'utility paster (se non è presente basta seguire la guida dettagliata: gestire progetti con paster e buildout).
Paster ci consente di creare automaticamente lo scheletro dei nostri pacchetti, essere più produttivi e generare automaticamente delle python egg che potranno essere rilasciate con un semplice comando, rendendo così disponibile il nostro software a tutta la comunità open source. E' anche possibile specificare eventuali dipendenze del nostro pacchetto per scaricarle automaticamente dalla rete con easy_install.
Se invece abbiamo già un prodotto esistente su cui lavorare, bastano pochi passi.
Passo passo...
Creare una cartella Extensions nel nostro prodotto o egg, ad esempio, in questo caso, esempio.policy:
esempio.policy/esempio/policy$ mkdir Extensions
esempio.policy/esempio/policy$ touch Extensions/__init__.py
Creare un file profiles.zcml nel proprio pacchetto o egg al fine di registrare i nostri profili di installazione
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:genericsetup="http://namespaces.zope.org/genericsetup"
i18n_domain="esempio.policy">
<genericsetup:registerProfile
name="default"
title="esempio.policy install"
directory="profiles/default"
description='Extension profile for esempio.policy.'
provides="Products.GenericSetup.interfaces.EXTENSION"
/>
<genericsetup:registerProfile
name="dependencies"
title="Mandatory dependencies for esempio.policy"
directory="profiles/dependencies"
description="Load all profiles from other packages/products that are needed for esempio.policy."
provides="Products.GenericSetup.interfaces.EXTENSION"
/>
</configure>
ed includerlo nel configure.zml nel seguente modo:
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:five="http://namespaces.zope.org/five"
xmlns:cmf="http://namespaces.zope.org/cmf"
i18n_domain="esempio.policy">
<!-- Include direct package dependencies -->
<include package="dipendenza.dip1" />
<include package="dipendenza.dip2" />
.... elenco l'elenco dei pacchetti da cui dipendo...
<five:registerPackage package="." initialize=".initialize" />
<include file="profiles.zcml" />
....
</configure>
A questo punto basta creare la seguente alberatura di cartella dei profili richiamati durante l'installazione dei prodotti:
- profiles
- default
- dependencies
In profiles/dependencies creiamo un file metadata.xml contenente l'elenco dei prodotti da installare automaticamente:
<?xml version="1.0"?>
<metadata>
<version>3.1.2</version>
<dependencies>
<dependency>profile-dipendenza.dip1:default</dependency>
<dependency>profile-dipendenza.dip2:default</dependency>
</dependencies>
</metadata>
Infine creare un file Install.py all'interno della cartella Extensions, in cui andremo a definire tutte le dipendenze di altri prodotti o profili di altri pacchetti:
import transaction
from Products.CMFCore.utils import getToolByName
PRODUCT_DEPENDENCIES = ['Prodotto1', 'Prodotto2',]
EXTENSION_PROFILES = ('esempio.policy:dependencies', 'esempio.policy:default',)
def install(self, reinstall=False):
portal_quickinstaller = getToolByName(self, 'portal_quickinstaller')
portal_setup = getToolByName(self, 'portal_setup')
for product in PRODUCT_DEPENDENCIES:
if reinstall and portal_quickinstaller.isProductInstalled(product):
portal_quickinstaller.reinstallProducts([product])
transaction.savepoint()
elif not portal_quickinstaller.isProductInstalled(product):
portal_quickinstaller.installProduct(product)
transaction.savepoint()
for extension_id in EXTENSION_PROFILES:
portal_setup.runAllImportStepsFromProfile('profile-%s' % extension_id, purge_old=False)
product_name = extension_id.split(':')[0]
portal_quickinstaller.notifyInstalled(product_name)
transaction.savepoint()
Da notare la posizione di esempio.policy:dependencies in testa alla tupla EXTENSION_PROFILES: verrà eseguita prima del profilo del nostro prodotto esempio.policy.
A questo punto è possibile procedere nel modo consueto aggiungendo dei profili in profiles/default, che verranno resi effettivi all'installazione del pacchetto esempio.policy, ed eventualmente aggiungere un modulo setuphandlers.py per gestire operazioni non direttamente supportate da GenericSetup.
Per concludere, inserendo il proprio pacchetto esempio.policy in un buildout e specificando le eventuali dipendenze nei metadata del nostro Python egg, siamo in grado di creare automaticamente degli ambienti Zope/Plone perfettamente configurati, facilmente replicabili, ottenendo così, con pochi comandi, un ambiente complesso completamente configurato.
Ulteriori informazioni
Per qualsiasi infomazione o suggerimento non esitate a contattarmi:
- Davide Moro, davide.moro <AT> redomino.com