Commit b97349ec authored by Łukasz Nowak's avatar Łukasz Nowak

Merge branch 'master' into external_buildout

parents b376d945 1b1b35c6
0.3 (unreleased) 0.4 (unreleased)
================ ================
* Do not use buildout internally, but rather call bootstrap command of any * Do not use buildout internally, but rather call bootstrap command of any
provided buildout binary. [Łukasz Nowak] provided buildout binary. [Łukasz Nowak]
0.3 (2011-06-14)
================
* slap: Implement SLA by filter_kw in OpenOrder.request. [Łukasz Nowak]
* slap: Timeout network operations. [Łukasz Nowak]
* slapformat: Make slapsoft and slapuser* system users. [Kazuhiko Shiozaki]
* slapgrid: Add more tolerance with supervisord. [Łukasz Nowak]
0.2 (2011-06-01) 0.2 (2011-06-01)
================ ================
......
...@@ -55,27 +55,6 @@ from AccessControl import getSecurityManager\n ...@@ -55,27 +55,6 @@ from AccessControl import getSecurityManager\n
from Products.ERP5Type.Log import log\n from Products.ERP5Type.Log import log\n
\n \n
portal = context.getPortalObject()\n portal = context.getPortalObject()\n
bt = portal.portal_templates.getInstalledBusinessTemplate("erp5_demo_maxma_sample")\n
isTransitionPossible = portal.portal_workflow.isTransitionPossible\n
\n
for obj in portal.portal_catalog(path=["%%/%s" % i.replace("**", "%") for i in bt.getTemplatePathList()]):\n
obj.activate().updateLocalRolesOnSecurityGroups()\n
\n
for document in portal.portal_catalog(portal_type=bt.getTemplatePortalTypeRoleList()):\n
document.updateLocalRolesOnSecurityGroups()\n
\n
conversion_server_hostname = portal.portal_preferences.getPreferredOoodocServerAddress()\n
conversion_server_port = portal.portal_preferences.getPreferredOoodocServerPortNumber()\n
for preference_id in ["default_configurator_preference", "default_configurator_system_preference"]:\n
preference = getattr(portal.portal_preferences, preference_id)\n
if preference.getPortalType() == "System Preference":\n
preference.setPreferredOoodocServerPortNumber(conversion_server_port)\n
preference.setPreferredOoodocServerAddress(conversion_server_hostname)\n
\n
if isTransitionPossible(preference, "enable"):\n
preference.enable()\n
preference.updateLocalRolesOnSecurityGroups()\n
\n
for gadget in portal.portal_gadgets.objectValues():\n for gadget in portal.portal_gadgets.objectValues():\n
if gadget.getValidationState() == \'invisible\':\n if gadget.getValidationState() == \'invisible\':\n
gadget.visible()\n gadget.visible()\n
......
...@@ -95,10 +95,10 @@ bt5_installation_list = ( \n ...@@ -95,10 +95,10 @@ bt5_installation_list = ( \n
\'vifib_crm\', \n \'vifib_crm\', \n
\'vifib_forge_release\', \n \'vifib_forge_release\', \n
\'vifib_software_pdm\', \n \'vifib_software_pdm\', \n
\'vifib_web\', \n \'vifib_web\',\n
\'vifib_open_trade\', \n \'vifib_open_trade\', \n
\'vifib_l10n_fr\'\n \'vifib_l10n_fr\',\n
\'vifib_datas\'\n \'vifib_datas\',\n
\'vifib_erp5\'\n \'vifib_erp5\'\n
)\n )\n
\n \n
......
...@@ -29,42 +29,61 @@ from Products.ERP5Configurator.tests.ConfiguratorTestMixin import \ ...@@ -29,42 +29,61 @@ from Products.ERP5Configurator.tests.ConfiguratorTestMixin import \
TestLiveConfiguratorWorkflowMixin TestLiveConfiguratorWorkflowMixin
from Products.ERP5Type.tests.Sequence import SequenceList from Products.ERP5Type.tests.Sequence import SequenceList
class TestMaxmaDemoConfiguratorWorkflow(TestLiveConfiguratorWorkflowMixin): class TestVifibConfiguratorWorkflow(TestLiveConfiguratorWorkflowMixin):
""" """
Configurator Mixin Class Configurator Mixin Class
""" """
# The list of standard business templates that the configurator should force # The list of standard business templates that the configurator should force
# to install # to install
user_reference = "demo" user_reference = "demo"
standard_bt5_list = ('erp5_simulation', standard_bt5_list = (
'erp5_dhtml_style', 'erp5_simulation',
'erp5_jquery', 'erp5_administration',
'erp5_jquery_ui', 'erp5_pdm',
'erp5_xhtml_jquery_style', 'erp5_trade',
'erp5_simulation_test',
'erp5_item',
'erp5_open_trade',
'erp5_forge',
'erp5_ingestion_mysql_innodb_catalog', 'erp5_ingestion_mysql_innodb_catalog',
'erp5_ingestion', 'erp5_ingestion',
'erp5_web',
'erp5_dms',
'erp5_crm', 'erp5_crm',
'erp5_pdm', 'erp5_jquery',
'erp5_trade', 'erp5_jquery_ui',
'erp5_knowledge_pad', 'erp5_knowledge_pad',
'erp5_web',
'erp5_dms',
'erp5_l10n_fr',
'erp5_content_translation',
'erp5_software_pdm',
'erp5_computer_immobilisation',
'erp5_accounting', 'erp5_accounting',
'erp5_accounting_l10n_fr',
'erp5_tax_resource', 'erp5_tax_resource',
'erp5_discount_resource', 'erp5_discount_resource',
'erp5_invoicing', 'erp5_invoicing',
'erp5_configurator_standard_categories',
'erp5_trade_knowledge_pad',
'erp5_crm_knowledge_pad',
'erp5_simulation_test',
'erp5_simplified_invoicing',
'erp5_ods_style', 'erp5_ods_style',
'erp5_odt_style', 'erp5_odt_style',
'erp5_ooo_import', 'erp5_ooo_import',
'erp5_accounting_l10n_fr', 'erp5_simplified_invoicing',
'erp5_l10n_fr', 'erp5_legacy_tax_system',
'erp5_l10n_pt-BR', 'erp5_commerce',
'erp5_demo_maxma_rule') 'erp5_project',
'erp5_credential',
'erp5_km',
'erp5_web_download_theme',
'vifib_mysql_innodb_catalog',
'vifib_core',
'vifib_base',
'vifib_slap',
'vifib_crm',
'vifib_forge_release',
'vifib_software_pdm',
'vifib_web',
'vifib_open_trade',
'vifib_l10n_fr',
'vifib_datas',
'vifib_erp5')
def getBusinessTemplateList(self): def getBusinessTemplateList(self):
return ('erp5_core_proxy_field_legacy', return ('erp5_core_proxy_field_legacy',
...@@ -72,7 +91,7 @@ class TestMaxmaDemoConfiguratorWorkflow(TestLiveConfiguratorWorkflowMixin): ...@@ -72,7 +91,7 @@ class TestMaxmaDemoConfiguratorWorkflow(TestLiveConfiguratorWorkflowMixin):
'erp5_base', 'erp5_base',
'erp5_workflow', 'erp5_workflow',
'erp5_configurator', 'erp5_configurator',
'erp5_configurator_maxma_demo',) 'erp5_configurator_vifib',)
def stepCreateBusinessConfiguration(self, sequence=None,\ def stepCreateBusinessConfiguration(self, sequence=None,\
sequence_list=None, **kw): sequence_list=None, **kw):
...@@ -80,7 +99,7 @@ class TestMaxmaDemoConfiguratorWorkflow(TestLiveConfiguratorWorkflowMixin): ...@@ -80,7 +99,7 @@ class TestMaxmaDemoConfiguratorWorkflow(TestLiveConfiguratorWorkflowMixin):
module = self.portal.business_configuration_module module = self.portal.business_configuration_module
business_configuration = module.newContent( business_configuration = module.newContent(
portal_type="Business Configuration", portal_type="Business Configuration",
title='Test Configurator Maxma Demo Workflow') title='Test Configurator Vifib Workflow')
next_dict = {} next_dict = {}
sequence.edit(business_configuration=business_configuration, sequence.edit(business_configuration=business_configuration,
next_dict=next_dict) next_dict=next_dict)
...@@ -94,43 +113,12 @@ class TestMaxmaDemoConfiguratorWorkflow(TestLiveConfiguratorWorkflowMixin): ...@@ -94,43 +113,12 @@ class TestMaxmaDemoConfiguratorWorkflow(TestLiveConfiguratorWorkflowMixin):
self.assertEquals('show', response_dict['command']) self.assertEquals('show', response_dict['command'])
self.assertEquals('Install', response_dict['next']) self.assertEquals('Install', response_dict['next'])
def stepSetMaxmaDemoWorkflow(self, sequence=None, sequence_list=None, **kw): def stepSetVifibWorkflow(self, sequence=None, sequence_list=None, **kw):
""" Set Consulting Workflow into Business Configuration """ """ Set Consulting Workflow into Business Configuration """
business_configuration = sequence.get("business_configuration") business_configuration = sequence.get("business_configuration")
self.setBusinessConfigurationWorkflow(business_configuration, self.setBusinessConfigurationWorkflow(business_configuration,
"workflow_module/maxma_demo_configuration_workflow") "workflow_module/vifib_configuration_workflow")
def stepViewCreatedPersons(self, sequence=None, sequence_list=None, **kw):
self.login(user_name='test_configurator_user')
person_list = self.portal.person_module.searchFolder()
self.assertNotEquals(0, len(person_list))
for entity in person_list:
for username in self.all_username_list:
self.failUnlessUserCanAccessDocument(username, entity)
self.failUnlessUserCanViewDocument(username, entity)
def stepViewCreatedOrganisations(self, sequence=None, sequence_list=None, **kw):
self.login(user_name='test_configurator_user')
organisation_list = self.portal.organisation_module.searchFolder()
self.assertNotEquals(0, len(organisation_list))
for entity in organisation_list:
for username in self.all_username_list:
self.failUnlessUserCanAccessDocument(username, entity)
self.failUnlessUserCanViewDocument(username, entity)
def stepViewCreatedAssignemnts(self, sequence=None, sequence_list=None, **kw):
self.login(user_name='test_configurator_user')
person_list = self.portal_person_module.searchFolder()
self.assertNotEquals(0, len(person_list))
for person in person_list:
for assignment in person.contentValues(portal_type='Assignment'):
for username in self.all_username_list:
self.failUnlessUserCanAccessDocument(username, assignment)
self.failUnlessUserCanViewDocument(username, assignment)
def stepCheckMaxmaDemoSampleObjectList(self, sequence=None, sequence_list=None, **kw): def stepCheckMaxmaDemoSampleObjectList(self, sequence=None, sequence_list=None, **kw):
...@@ -143,22 +131,11 @@ class TestMaxmaDemoConfiguratorWorkflow(TestLiveConfiguratorWorkflowMixin): ...@@ -143,22 +131,11 @@ class TestMaxmaDemoConfiguratorWorkflow(TestLiveConfiguratorWorkflowMixin):
gadget.getValidationState())) gadget.getValidationState()))
gadget.Base_checkConsistency() gadget.Base_checkConsistency()
# Check if demo user is working.
user = self.portal.portal_catalog.getResultValue(portal_type="Person",
reference=self.user_reference)
self.assertNotEquals(user.Person_getAvailableAssignmentValueList(), [])
self.assertEquals(user.getTitle(), "Jack Vale")
self.assertEquals(user.getValidationState(), "validated")
self.assertEquals(user.getSubordination(),
'organisation_module/myorganisation')
self.assertEquals(user.getSubordinationTitle(), "Maxma Co")
### STEPS ### STEPS
DEFAULT_SEQUENCE_LIST = """ DEFAULT_SEQUENCE_LIST = """
stepCreateBusinessConfiguration stepCreateBusinessConfiguration
stepTic stepTic
stepSetMaxmaDemoWorkflow stepSetVifibWorkflow
stepTic stepTic
stepConfiguratorNext stepConfiguratorNext
stepTic stepTic
...@@ -171,61 +148,9 @@ class TestMaxmaDemoConfiguratorWorkflow(TestLiveConfiguratorWorkflowMixin): ...@@ -171,61 +148,9 @@ class TestMaxmaDemoConfiguratorWorkflow(TestLiveConfiguratorWorkflowMixin):
stepStartConfigurationInstallation stepStartConfigurationInstallation
stepTic stepTic
stepCheckInstanceIsConfigured%(country)s stepCheckInstanceIsConfigured%(country)s
stepCheckMaxmaDemoSampleObjectList
stepTic
stepViewAddGadget
stepViewEventModule
stepAddEvent
stepSentEventWorkflow
stepViewAccountModule
stepAddAccountModule
stepViewAccount
stepCopyPasteAccount
stepViewEntityModules
stepAddEntityModules
stepCopyAndPastePerson
stepCopyAndPasteOrganisation
stepEntityWorkflow
stepViewCreatedPersons
stepViewCreatedOrganisations
stepViewCreatedAssignemnts
stepAddAccoutingPeriod
stepValidatedAccountingPeriods
stepViewBankAccount
stepViewCreditCard
stepValidateAndModifyBankAccount
stepValidateAndModifyCreditCard
stepAddPaymentNodeInPerson
stepAddPaymentNodeInOrganisation
stepCopyAndPasteBankAccountInPerson
stepCopyAndPasteBankAccountInOrganisation
stepViewAccountingTransactionModule
stepAddAccountingTransactionModule
stepCopyAndPasteAccountingTransactions
stepTic
stepAccountingTransaction
stepTic
stepSaleInvoiceTransaction
stepTic
stepPurchaseInvoiceTransaction
stepTic
stepPaymentTransaction
stepTic
stepBalanceTransaction
stepTic
stepAccountingTransaction_getCausalityGroupedAccountingTransactionList
stepAddAssignments
stepAssignmentTI
stepEditAssignments
stepViewAcessAddPurchaseTradeCondition
stepViewAccessAddSaleTradeCondition
stepViewAccessAddSaleOrder
stepViewAccessAddSalePackingList
stepViewAccessPurchaseOrder
stepPurchasePackingList
""" """
def test_maxma_demo_workflow(self): def test_vifib_workflow(self):
""" Test the consulting workflow configuration""" """ Test the consulting workflow configuration"""
self.all_username_list = ["demo"] self.all_username_list = ["demo"]
self.accountant_username_list = self.all_username_list self.accountant_username_list = self.all_username_list
...@@ -241,5 +166,5 @@ class TestMaxmaDemoConfiguratorWorkflow(TestLiveConfiguratorWorkflowMixin): ...@@ -241,5 +166,5 @@ class TestMaxmaDemoConfiguratorWorkflow(TestLiveConfiguratorWorkflowMixin):
import unittest import unittest
def test_suite(): def test_suite():
suite = unittest.TestSuite() suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestMaxmaDemoConfiguratorWorkflow)) suite.addTest(unittest.makeSuite(TestVifibConfiguratorWorkflow))
return suite return suite
8 11
\ No newline at end of file \ No newline at end of file
testMaxmaDemoConfigurationWorkflow testVifibConfigurationWorkflow
\ No newline at end of file \ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ActionInformation" module="Products.CMFCore.ActionInformation"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/object_action</string>
</tuple>
</value>
</item>
<item>
<key> <string>category</string> </key>
<value> <string>object_action</string> </value>
</item>
<item>
<key> <string>condition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>get_certificate</string> </value>
</item>
<item>
<key> <string>permissions</string> </key>
<value>
<tuple>
<string>Modify portal content</string>
</tuple>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Action Information</string> </value>
</item>
<item>
<key> <string>priority</string> </key>
<value> <float>10.0</float> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Get Certificate</string> </value>
</item>
<item>
<key> <string>visible</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/Person_getCertificate</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ActionInformation" module="Products.CMFCore.ActionInformation"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/object_action</string>
</tuple>
</value>
</item>
<item>
<key> <string>category</string> </key>
<value> <string>object_action</string> </value>
</item>
<item>
<key> <string>condition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>revoke_certificate</string> </value>
</item>
<item>
<key> <string>permissions</string> </key>
<value>
<tuple>
<string>Modify portal content</string>
</tuple>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Action Information</string> </value>
</item>
<item>
<key> <string>priority</string> </key>
<value> <float>11.0</float> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Revoke Certificate</string> </value>
</item>
<item>
<key> <string>visible</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/Person_revokeCertificate</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
from AccessControl import ClassSecurityInfo, Unauthorized, getSecurityManager
from Products.ERP5.Document.Person import Person as ERP5Person
class Person(ERP5Person):
security = ClassSecurityInfo()
security.declarePublic('getCertificate')
def _checkCertificateRequest(self):
try:
self.checkUserCanChangePassword()
except Unauthorized:
# in ERP5 user has no SetOwnPassword permission on Person document
# referring himself, so implement "security" by checking that currently
# logged in user is trying to get/revoke his own certificate
reference = self.getReference()
if not reference:
raise
if getSecurityManager().getUser().getId() != reference:
raise
def _getCertificate(self):
return self.getPortalObject().portal_certificate_authority\
.getNewCertificate(self.getReference())
def _revokeCertificate(self):
return self.getPortalObject().portal_certificate_authority\
.revokeCertificateByCommonName(self.getReference())
def getCertificate(self):
"""Returns new SSL certificate"""
self._checkCertificateRequest()
return self._getCertificate()
security.declarePublic('revokeCertificate')
def revokeCertificate(self):
"""Revokes existing certificate"""
self._checkCertificateRequest()
self._revokeCertificate()
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions from Products.ERP5Type import Permissions
from Products.ERP5.Document.Item import Item from Products.ERP5.Document.Item import Item
from lxml import etree
class SoftwareInstance(Item): class SoftwareInstance(Item):
""" """
...@@ -42,3 +43,20 @@ class SoftwareInstance(Item): ...@@ -42,3 +43,20 @@ class SoftwareInstance(Item):
security.declareObjectProtected(Permissions.AccessContentsInformation) security.declareObjectProtected(Permissions.AccessContentsInformation)
security.declareProtected(Permissions.AccessContentsInformation,
'getSlaXmlAsDict')
def getSlaXmlAsDict(self):
"""Returns SLA XML as python dictionary"""
result_dict = {}
xml = self.getSlaXml()
if xml is not None and xml != '':
tree = etree.fromstring(xml.encode('utf-8'))
for element in tree.findall('parameter'):
key = element.get('id')
value = result_dict.get(key, None)
if value is not None:
value = value + ' ' + element.text
else:
value = element.text
result_dict[key] = value
return result_dict
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Standard Property" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_local_properties</string> </key>
<value>
<tuple>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>mode</string> </value>
</item>
<item>
<key> <string>type</string> </key>
<value> <string>string</string> </value>
</item>
</dictionary>
</tuple>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>elementary_type/text</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>XML Service Level Agreement parameters</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>sla_xml_property</string> </value>
</item>
<item>
<key> <string>mode</string> </key>
<value> <string>w</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Standard Property</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>certificate = context.getCertificate()\n
request = context.REQUEST\n
request.set(\'your_certificate\', certificate[\'certificate\'])\n
request.set(\'your_key\', certificate[\'key\'])\n
return context.Person_getCertificateForm()\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>dialog_id=None, form_id=None, **kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Person_getCertificate</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ERP5Form" module="Products.ERP5Form.Form"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>action</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>edit_order</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>encoding</string> </key>
<value> <string>UTF-8</string> </value>
</item>
<item>
<key> <string>enctype</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>group_list</string> </key>
<value>
<list>
<string>left</string>
<string>right</string>
<string>center</string>
<string>bottom</string>
<string>hidden</string>
</list>
</value>
</item>
<item>
<key> <string>groups</string> </key>
<value>
<dictionary>
<item>
<key> <string>bottom</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>center</string> </key>
<value>
<list>
<string>your_certificate</string>
<string>your_key</string>
</list>
</value>
</item>
<item>
<key> <string>hidden</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>left</string> </key>
<value>
<list>
<string>your_tip</string>
</list>
</value>
</item>
<item>
<key> <string>right</string> </key>
<value>
<list/>
</value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Person_getCertificateForm</string> </value>
</item>
<item>
<key> <string>method</string> </key>
<value> <string>POST</string> </value>
</item>
<item>
<key> <string>name</string> </key>
<value> <string>Person_getCertificateForm</string> </value>
</item>
<item>
<key> <string>pt</string> </key>
<value> <string>form_dialog</string> </value>
</item>
<item>
<key> <string>row_length</string> </key>
<value> <int>4</int> </value>
</item>
<item>
<key> <string>stored_encoding</string> </key>
<value> <string>UTF-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Certificate Request</string> </value>
</item>
<item>
<key> <string>unicode_mode</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>update_action</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>update_action_title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="TextAreaField" module="Products.Formulator.StandardFields"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>your_certificate</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
<item>
<key> <string>line_too_long</string> </key>
<value> <string>A line was too long.</string> </value>
</item>
<item>
<key> <string>required_not_found</string> </key>
<value> <string>Input is required but no input given.</string> </value>
</item>
<item>
<key> <string>too_long</string> </key>
<value> <string>You entered too many characters.</string> </value>
</item>
<item>
<key> <string>too_many_lines</string> </key>
<value> <string>You entered too many lines.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>height</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_length</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_linelength</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_lines</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>width</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>height</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_length</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_linelength</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_lines</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>width</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>height</string> </key>
<value> <int>5</int> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>max_length</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_linelength</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_lines</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Certificate</string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>width</string> </key>
<value> <int>40</int> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="TextAreaField" module="Products.Formulator.StandardFields"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>your_key</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
<item>
<key> <string>line_too_long</string> </key>
<value> <string>A line was too long.</string> </value>
</item>
<item>
<key> <string>required_not_found</string> </key>
<value> <string>Input is required but no input given.</string> </value>
</item>
<item>
<key> <string>too_long</string> </key>
<value> <string>You entered too many characters.</string> </value>
</item>
<item>
<key> <string>too_many_lines</string> </key>
<value> <string>You entered too many lines.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>height</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_length</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_linelength</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_lines</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>width</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>height</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_length</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_linelength</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_lines</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>width</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>height</string> </key>
<value> <int>5</int> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>max_length</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_linelength</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_lines</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Key</string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>width</string> </key>
<value> <int>40</int> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="TextAreaField" module="Products.Formulator.StandardFields"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>your_tip</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
<item>
<key> <string>line_too_long</string> </key>
<value> <string>A line was too long.</string> </value>
</item>
<item>
<key> <string>required_not_found</string> </key>
<value> <string>Input is required but no input given.</string> </value>
</item>
<item>
<key> <string>too_long</string> </key>
<value> <string>You entered too many characters.</string> </value>
</item>
<item>
<key> <string>too_many_lines</string> </key>
<value> <string>You entered too many lines.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>height</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_length</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_linelength</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_lines</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>width</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>height</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_length</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_linelength</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_lines</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>width</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string>Please copy both key and certificate.\n
\n
They are NOT stored anywhere for security reason.</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>height</string> </key>
<value> <int>5</int> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>max_length</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_linelength</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_lines</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Information</string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>width</string> </key>
<value> <int>40</int> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>context.revokeCertificate()\n
return context.Base_redirect(form_id, keep_items = {\'portal_status_message\' : \'Certificate revoked.\'}, **kw)\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>dialog_id=None, form_id=None, **kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Person_revokeCertificate</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -86,6 +86,7 @@ ...@@ -86,6 +86,7 @@
<string>my_ssl_key</string> <string>my_ssl_key</string>
<string>my_ssl_certificate</string> <string>my_ssl_certificate</string>
<string>my_description</string> <string>my_description</string>
<string>my_sla_xml</string>
</list> </list>
</value> </value>
</item> </item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>editable</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_sla_xml</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>editable</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_text_area_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Service Level Agreement XML</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -68,20 +68,22 @@ sale_packing_list = sale_packing_list_module.newContent(\n ...@@ -68,20 +68,22 @@ sale_packing_list = sale_packing_list_module.newContent(\n
source=instance_setup_sale_packing_list.getSource(),\n source=instance_setup_sale_packing_list.getSource(),\n
source_section=instance_setup_sale_packing_list.getSourceSection(),\n source_section=instance_setup_sale_packing_list.getSourceSection(),\n
price_currency=instance_setup_sale_packing_list.getPriceCurrency(),\n price_currency=instance_setup_sale_packing_list.getPriceCurrency(),\n
start_date=DateTime())\n start_date=DateTime(),\n
activate_kw={\'tag\': tag})\n
\n \n
instance_hosting_sale_packing_list_line = sale_packing_list.newContent(\n instance_hosting_sale_packing_list_line = sale_packing_list.newContent(\n
portal_type=\'Sale Packing List Line\',\n portal_type=\'Sale Packing List Line\',\n
resource=service_relative_url,\n resource=service_relative_url,\n
quantity=instance_setup_sale_packing_list_line.getQuantity(),\n quantity=instance_setup_sale_packing_list_line.getQuantity(),\n
aggregate_list=instance_setup_sale_packing_list_line.getAggregateList(),\n aggregate_list=instance_setup_sale_packing_list_line.getAggregateList(),\n
activate_kw={\'tag\': tag}\n
)\n )\n
return sale_packing_list\n return sale_packing_list\n
</string> </value> </string> </value>
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>state_change, service_relative_url</string> </value> <value> <string>state_change, service_relative_url, tag=None</string> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
......
...@@ -61,7 +61,7 @@ hosting_subscription_uid = state_change.kwargs[\'hosting_subscription_uid\']\n ...@@ -61,7 +61,7 @@ hosting_subscription_uid = state_change.kwargs[\'hosting_subscription_uid\']\n
shared = state_change.kwargs[\'shared\']\n shared = state_change.kwargs[\'shared\']\n
software_type = state_change.kwargs["software_type"]\n software_type = state_change.kwargs["software_type"]\n
tag = state_change.kwargs[\'tag\']\n tag = state_change.kwargs[\'tag\']\n
filter_kw = state_change.kwargs["filter_kw"]\n filter_kw = software_instance.getSlaXmlAsDict()\n
\n \n
# Assertion: No packing list line should be related to this software instance\n # Assertion: No packing list line should be related to this software instance\n
packing_list_line = software_instance.getAggregateRelatedValue(portal_type=\'Sale Packing List Line\')\n packing_list_line = software_instance.getAggregateRelatedValue(portal_type=\'Sale Packing List Line\')\n
......
...@@ -50,12 +50,22 @@ ...@@ -50,12 +50,22 @@
</item> </item>
<item> <item>
<key> <string>_body</string> </key> <key> <string>_body</string> </key>
<value> <string>software_instance = state_change[\'object\']\n <value> <string encoding="cdata"><![CDATA[
software_instance = state_change[\'object\']\n
tag = "%s_destroyInProgress" % software_instance.getUid()\n
portal = context.getPortalObject()\n
if (portal.portal_activities.countMessageWithTag(tag) > 0):\n
raise ValueError("Software Instance is currently being destroyed.")\n
# lock software instance in transaction\n
software_instance.serialize()\n
service_relative_url = software_instance.portal_preferences.\\\n service_relative_url = software_instance.portal_preferences.\\\n
getPreferredInstanceCleanupResource()\n getPreferredInstanceCleanupResource()\n
sale_packing_list = context.SoftwareInstance_createSalePackingList(state_change, service_relative_url)\n sale_packing_list = context.SoftwareInstance_createSalePackingList(state_change, service_relative_url, tag=tag)\n
sale_packing_list.confirm()\n sale_packing_list.confirm(activate_kw={\'tag\':tag})\n
</string> </value>
]]></string> </value>
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
......
...@@ -61,7 +61,7 @@ requested_partition_reference = kwargs["partition_reference"]\n ...@@ -61,7 +61,7 @@ requested_partition_reference = kwargs["partition_reference"]\n
shared = kwargs["shared"]\n shared = kwargs["shared"]\n
software_type = kwargs["software_type"]\n software_type = kwargs["software_type"]\n
instance_xml = kwargs["instance_xml"]\n instance_xml = kwargs["instance_xml"]\n
filter_kw = kwargs["filter_kw"]\n sla_xml = kwargs["sla_xml"]\n
\n \n
# Get root software instance\n # Get root software instance\n
predecessor_software_instance = software_instance\n predecessor_software_instance = software_instance\n
...@@ -97,6 +97,7 @@ if (request_software_instance is None):\n ...@@ -97,6 +97,7 @@ if (request_software_instance is None):\n
title=requested_partition_reference,\n title=requested_partition_reference,\n
source_reference=software_type,\n source_reference=software_type,\n
text_content=instance_xml,\n text_content=instance_xml,\n
sla_xml=sla_xml,\n
activate_kw={\'tag\': tag},\n activate_kw={\'tag\': tag},\n
**portal.Base_getNewSoftwareInstanceCoordinate()\n **portal.Base_getNewSoftwareInstanceCoordinate()\n
)\n )\n
...@@ -108,13 +109,13 @@ if (request_software_instance is None):\n ...@@ -108,13 +109,13 @@ if (request_software_instance is None):\n
hosting_subscription_uid=hosting_subscription_uid,\n hosting_subscription_uid=hosting_subscription_uid,\n
shared=shared,\n shared=shared,\n
software_type=software_type,\n software_type=software_type,\n
tag=tag,\n tag=tag)\n
filter_kw=filter_kw)\n
else:\n else:\n
# Update existing software instance\n # Update existing software instance\n
# Sale Packing List interaction has to be requested automatically with an interaction workflow\n # Sale Packing List interaction has to be requested automatically with an interaction workflow\n
request_software_instance.edit(\n request_software_instance.edit(\n
text_content=instance_xml,\n text_content=instance_xml,\n
sla_xml=sla_xml,\n
activate_kw={\'tag\': tag},\n activate_kw={\'tag\': tag},\n
)\n )\n
# Update the predecessor category of the original caller\n # Update the predecessor category of the original caller\n
......
...@@ -50,7 +50,9 @@ ...@@ -50,7 +50,9 @@
</item> </item>
<item> <item>
<key> <string>_body</string> </key> <key> <string>_body</string> </key>
<value> <string>software_instance = state_change[\'object\']\n <value> <string encoding="cdata"><![CDATA[
software_instance = state_change[\'object\']\n
service_relative_url = software_instance.portal_preferences.\\\n service_relative_url = software_instance.portal_preferences.\\\n
getPreferredInstanceHostingResource()\n getPreferredInstanceHostingResource()\n
need_to_create_packing_list = False\n need_to_create_packing_list = False\n
...@@ -63,10 +65,18 @@ else:\n ...@@ -63,10 +65,18 @@ else:\n
if sale_packing_list_line.getSimulationState() == \'delivered\':\n if sale_packing_list_line.getSimulationState() == \'delivered\':\n
need_to_create_packing_list = True\n need_to_create_packing_list = True\n
\n \n
portal = context.getPortalObject()\n
if need_to_create_packing_list:\n if need_to_create_packing_list:\n
sale_packing_list = context.SoftwareInstance_createSalePackingList(state_change, service_relative_url)\n tag = "%s_startInProgress" % software_instance.getUid()\n
sale_packing_list.confirm()\n if (portal.portal_activities.countMessageWithTag(tag) > 0):\n
</string> </value> raise ValueError("Software Instance is currently being started.")\n
# lock software instance in transaction\n
software_instance.serialize()\n
sale_packing_list = context.SoftwareInstance_createSalePackingList(state_change, service_relative_url, tag)\n
sale_packing_list.confirm(activate_kw={\'tag\':tag})\n
]]></string> </value>
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
......
230 243
\ No newline at end of file \ No newline at end of file
Person | get_certificate
Person | revoke_certificate
Software Instance Module | view Software Instance Module | view
Software Instance | jump_to_software_instance Software Instance | jump_to_software_instance
Software Instance | view Software Instance | view
\ No newline at end of file
SoftwareInstance SoftwareInstance
Person
\ No newline at end of file
...@@ -41,109 +41,46 @@ class TestVifibCredential(testVifibMixin): ...@@ -41,109 +41,46 @@ class TestVifibCredential(testVifibMixin):
result_list.append("vifib_credential") result_list.append("vifib_credential")
return result_list return result_list
def createCredentialRequest(self, def stepSetCredentialRequestAutomaticApprovalPreferences(self):
first_name="Gabriel", self.setSystemPreference()
last_name="Monnerat", default_system_preference = self.portal.portal_preferences.restrictedTraverse(self.getDefaultSitePreferenceId())
reference="gabriel", self.login("ERP5TypeTestCase")
password="123", default_system_preference.edit(preferred_credential_request_automatic_approval=True)
default_email_text="gabriel@test.com"): self.logout()
def stepValidateNotificationMessage(self):
module = self.portal.notification_message_module
reference = "crendential_request-confirmation-without-password"
search_result = module.searchFolder(reference=reference)
[notification.getObject().validate() for notification in search_result]
def testBase_getDefaultAssignmentArgumentDict(self):
self.stepValidateNotificationMessage()
self.stepSetCredentialRequestAutomaticApprovalPreferences()
self.logout() self.logout()
self.portal.ERP5Site_registerCredentialRequest(first_name=first_name, portal_catalog = self.portal.portal_catalog
last_name=last_name, self.portal.ERP5Site_registerCredentialRequest(first_name="Vifib",
reference=reference, last_name="Test",
password=password, reference="vifib_test",
password="vifib",
career_subordination_title="", career_subordination_title="",
default_email_text=default_email_text, default_email_text="vifib@vifib.com",
default_telephone_text="223344", default_telephone_text="223344",
default_address_street_address="Test Street", default_address_street_address="Test Street",
default_address_city="Campos", default_address_city="My Street",
default_address_zip_code="28024030") default_address_zip_code="28024030")
self.login("ERP5TypeTestCase") self.login("ERP5TypeTestCase")
self.stepTic() self.stepTic()
def createSystemPreference(self):
""" """
portal_preferences = self.getPreferenceTool()
preference = portal_preferences.newContent(portal_type='System Preference',
title='Default Site Preference',
id='test_site_preference')
self.stepTic()
return preference
def afterSetUp(self):
""" """
portal_preferences = self.getPreferenceTool()
preference = getattr(portal_preferences, 'test_site_preference', None)
if preference is None:
preference = self.createSystemPreference()
if preference.getPreferenceState() == 'disabled':
preference.enable()
preference.edit(preferred_credential_request_automatic_approval=True,
preferred_credential_recovery_automatic_approval=True,
preferred_organisation_credential_update_automatic_approval=True,
preferred_person_credential_update_automatic_approval=True)
self.portal.email_from_address = 'site@example.invalid'
oldMailHost = getattr(self.portal, 'MailHost', None)
if oldMailHost is not None:
self.portal.manage_delObjects(['MailHost'])
self.portal._setObject('MailHost', DummyMailHost('MailHost'))
self.stepTic()
def testMailMessagePosted(self):
""" Test if the Mail Message was posted correctly """
self.createCredentialRequest(reference="vifibtest")
portal_catalog = self.portal.portal_catalog
credential_request = portal_catalog.getResultValue(portal_type="Credential Request", credential_request = portal_catalog.getResultValue(portal_type="Credential Request",
reference="vifibtest") reference="vifib_test")
mail_message = portal_catalog.getResultValue(portal_type="Mail Message",
follow_up=credential_request)
self.assertEquals(mail_message.getSimulationState(), "started")
self.assertTrue("key=%s" % mail_message.getReference() in mail_message.getTextContent())
def test_MailFromMailMessageEvent(self):
""" """
self.createCredentialRequest(first_name="Vifib",
last_name="Test",
reference="vifibtest")
portal_catalog = self.portal.portal_catalog
credential_request = portal_catalog.getResultValue(portal_type="Credential Request",
reference="vifibtest",
first_name="Vifib",
last_name="Test")
mail_message = portal_catalog.getResultValue(portal_type="Mail Message",
follow_up=credential_request)
last_message = self.portal.MailHost._last_message
self.assertNotEquals((), last_message)
mfrom, mto, message_text = last_message
self.assertEquals(mfrom, 'Portal Administrator <site@example.invalid>')
self.assertEquals(['Vifib Test <gabriel@test.com>'], mto)
self.assertNotEquals(re.search("Subject\:.*Welcome_to_Vifib", message_text), None)
self.assertNotEquals(re.search("Hello\ Vifib\ Test\,", message_text), None)
self.assertNotEquals(re.search("key\=..%s" % mail_message.getReference(), message_text), None)
def testERP5Site_activeLogin(self):
""" Test if the script WebSection_activeLogin will create one user
correctly """
self.createCredentialRequest()
portal_catalog = self.portal.portal_catalog
credential_request = portal_catalog.getResultValue(portal_type="Credential Request",
reference="gabriel")
mail_message = portal_catalog.getResultValue(portal_type="Mail Message", mail_message = portal_catalog.getResultValue(portal_type="Mail Message",
follow_up=credential_request) follow_up=credential_request)
self.logout() self.logout()
self.portal.ERP5Site_activeLogin(mail_message.getReference()) self.portal.ERP5Site_activeLogin(mail_message.getReference())
self.login("ERP5TypeTestCase") self.login("ERP5TypeTestCase")
self.stepTic() self.stepTic()
person = portal_catalog.getResultValue(reference="gabriel", portal_type="Person") person = portal_catalog.getResultValue(reference="vifib_test", portal_type="Person")
self.assertEquals(person.getValidationState(), "validated") assignment_list = person.objectValues(portal_type="Assignment")
assignment = assignment_list[0]
def testERP5Site_registerCredentialRequest(self): self.assertEquals(assignment.getFunction(), "customer")
""" Test if the script ERP5Site_registerCredentialRequest will create one self.assertEquals(assignment.getRole(), "client")
Credential Request correctly """
self.createCredentialRequest()
portal_catalog = self.portal.portal_catalog
credential_request = portal_catalog.getResultValue(portal_type="Credential Request",
reference="gabriel")
self.assertEquals(credential_request.getFirstName(), "Gabriel")
self.assertEquals(credential_request.getDefaultEmailText(), "gabriel@test.com")
27 28
\ No newline at end of file \ No newline at end of file
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="TradeModelPath" module="Products.ERP5Type.Document.TradeModelPath"/> <global name="Trade Model Path" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="Computer" module="Products.ERP5Type.Document.Computer"/> <global name="Computer" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="ComputerPartition" module="Products.ERP5Type.Document.ComputerPartition"/> <global name="Computer Partition" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="Supply" module="Products.ERP5Type.Document.Supply"/> <global name="Open Sale Order" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="SupplyLine" module="Products.ERP5Type.Document.SupplyLine"/> <global name="Open Sale Order Line" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="Organisation" module="Products.ERP5Type.Document.Organisation"/> <global name="Organisation" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="Organisation" module="Products.ERP5Type.Document.Organisation"/> <global name="Organisation" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="AccountingTransaction" module="Products.ERP5Type.Document.AccountingTransaction"/> <global name="Accounting Period" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="GeographicAddress" module="Products.ERP5Type.Document.GeographicAddress"/> <global name="Address" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="Url" module="Products.ERP5Type.Document.Url"/> <global name="Email" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="Telephone" module="Products.ERP5Type.Document.Telephone"/> <global name="Telephone" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="SubscriptionItemRootSimulationRule" module="Products.ERP5Type.Document.SubscriptionItemRootSimulationRule"/> <global name="Subscription Item Root Simulation Rule" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="CategoryMembershipEquivalenceTester" module="Products.ERP5Type.Document.CategoryMembershipEquivalenceTester"/> <global name="Category Membership Divergence Tester" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="CategoryMembershipEquivalenceTester" module="Products.ERP5Type.Document.CategoryMembershipEquivalenceTester"/> <global name="Category Membership Divergence Tester" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="CategoryMembershipEquivalenceTester" module="Products.ERP5Type.Document.CategoryMembershipEquivalenceTester"/> <global name="Category Membership Divergence Tester" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="CategoryMembershipEquivalenceTester" module="Products.ERP5Type.Document.CategoryMembershipEquivalenceTester"/> <global name="Category Membership Divergence Tester" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="CategoryMembershipEquivalenceTester" module="Products.ERP5Type.Document.CategoryMembershipEquivalenceTester"/> <global name="Category Membership Divergence Tester" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="CategoryMembershipEquivalenceTester" module="Products.ERP5Type.Document.CategoryMembershipEquivalenceTester"/> <global name="Category Membership Divergence Tester" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="CategoryMembershipEquivalenceTester" module="Products.ERP5Type.Document.CategoryMembershipEquivalenceTester"/> <global name="Category Membership Divergence Tester" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="CategoryMembershipEquivalenceTester" module="Products.ERP5Type.Document.CategoryMembershipEquivalenceTester"/> <global name="Category Membership Divergence Tester" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="CategoryMembershipEquivalenceTester" module="Products.ERP5Type.Document.CategoryMembershipEquivalenceTester"/> <global name="Category Membership Divergence Tester" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="CategoryMembershipEquivalenceTester" module="Products.ERP5Type.Document.CategoryMembershipEquivalenceTester"/> <global name="Category Membership Divergence Tester" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="CategoryMembershipEquivalenceTester" module="Products.ERP5Type.Document.CategoryMembershipEquivalenceTester"/> <global name="Category Membership Divergence Tester" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="CategoryMembershipEquivalenceTester" module="Products.ERP5Type.Document.CategoryMembershipEquivalenceTester"/> <global name="Category Membership Divergence Tester" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="CategoryMembershipEquivalenceTester" module="Products.ERP5Type.Document.CategoryMembershipEquivalenceTester"/> <global name="Category Membership Divergence Tester" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="CategoryMembershipEquivalenceTester" module="Products.ERP5Type.Document.CategoryMembershipEquivalenceTester"/> <global name="Category Membership Divergence Tester" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="FloatEquivalenceTester" module="Products.ERP5Type.Document.FloatEquivalenceTester"/> <global name="Float Divergence Tester" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="NetConvertedQuantityEquivalenceTester" module="Products.ERP5Type.Document.NetConvertedQuantityEquivalenceTester"/> <global name="Net Converted Quantity Divergence Tester" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="CategoryMembershipEquivalenceTester" module="Products.ERP5Type.Document.CategoryMembershipEquivalenceTester"/> <global name="Category Membership Divergence Tester" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="CategoryMembershipEquivalenceTester" module="Products.ERP5Type.Document.CategoryMembershipEquivalenceTester"/> <global name="Category Membership Divergence Tester" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="CategoryMembershipEquivalenceTester" module="Products.ERP5Type.Document.CategoryMembershipEquivalenceTester"/> <global name="Category Membership Divergence Tester" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="CategoryMembershipEquivalenceTester" module="Products.ERP5Type.Document.CategoryMembershipEquivalenceTester"/> <global name="Category Membership Divergence Tester" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="CategoryMembershipEquivalenceTester" module="Products.ERP5Type.Document.CategoryMembershipEquivalenceTester"/> <global name="Category Membership Divergence Tester" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="CategoryMembershipEquivalenceTester" module="Products.ERP5Type.Document.CategoryMembershipEquivalenceTester"/> <global name="Category Membership Divergence Tester" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="CategoryMembershipEquivalenceTester" module="Products.ERP5Type.Document.CategoryMembershipEquivalenceTester"/> <global name="Category Membership Divergence Tester" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="CategoryMembershipEquivalenceTester" module="Products.ERP5Type.Document.CategoryMembershipEquivalenceTester"/> <global name="Category Membership Divergence Tester" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="CategoryMembershipEquivalenceTester" module="Products.ERP5Type.Document.CategoryMembershipEquivalenceTester"/> <global name="Category Membership Divergence Tester" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="DateTimeEquivalenceTester" module="Products.ERP5Type.Document.DateTimeEquivalenceTester"/> <global name="DateTime Divergence Tester" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="DateTimeEquivalenceTester" module="Products.ERP5Type.Document.DateTimeEquivalenceTester"/> <global name="DateTime Divergence Tester" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="VariationEquivalenceTester" module="Products.ERP5Type.Document.VariationEquivalenceTester"/> <global name="Variation Divergence Tester" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="PackingList" module="Products.ERP5Type.Document.PackingList"/> <global name="Purchase Packing List" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="DeliveryLine" module="Products.ERP5Type.Document.DeliveryLine"/> <global name="Purchase Packing List Line" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="TradeCondition" module="Products.ERP5Type.Document.TradeCondition"/> <global name="Sale Trade Condition" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="TradeCondition" module="Products.ERP5Type.Document.TradeCondition"/> <global name="Sale Trade Condition" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="SoftwareProduct" module="Products.ERP5Type.Document.SoftwareProduct"/> <global name="Software Product" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
<key> <string>_Access_contents_information_Permission</string> </key> <key> <string>_Access_contents_information_Permission</string> </key>
<value> <value>
<tuple> <tuple>
<string>Anonymous</string>
<string>Assignee</string> <string>Assignee</string>
<string>Assignor</string> <string>Assignor</string>
<string>Associate</string> <string>Associate</string>
...@@ -44,6 +45,7 @@ ...@@ -44,6 +45,7 @@
<key> <string>_View_Permission</string> </key> <key> <string>_View_Permission</string> </key>
<value> <value>
<tuple> <tuple>
<string>Anonymous</string>
<string>Assignee</string> <string>Assignee</string>
<string>Assignor</string> <string>Assignor</string>
<string>Associate</string> <string>Associate</string>
...@@ -84,7 +86,127 @@ ...@@ -84,7 +86,127 @@
<key> <string>title</string> </key> <key> <string>title</string> </key>
<value> <string>test_software_product</string> </value> <value> <string>test_software_product</string> </value>
</item> </item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>commerce_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary> </dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/>
</pickle>
<pickle>
<tuple>
<none/>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>publish_action</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <string>zope</string> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global id="3.1" name="DateTime" module="DateTime.DateTime"/>
</klass>
<tuple>
<none/>
</tuple>
<state>
<tuple>
<float>1307981928.46</float>
<string>GMT+2</string>
</tuple>
</state>
</object>
</value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>draft</string> </value>
</item>
</dictionary>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>publish</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <string>zope</string> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass> <reference id="3.1"/> </klass>
<tuple>
<none/>
</tuple>
<state>
<tuple>
<float>1307981928.46</float>
<string>GMT+2</string>
</tuple>
</state>
</object>
</value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>published</string> </value>
</item>
</dictionary>
</list>
</tuple>
</pickle> </pickle>
</record> </record>
</ZopeData> </ZopeData>
...@@ -66,13 +66,16 @@ for order_line in order.getMovementList():\n ...@@ -66,13 +66,16 @@ for order_line in order.getMovementList():\n
computer_partition = None\n computer_partition = None\n
\n \n
# XXX Duplicated from request method...\n # XXX Duplicated from request method...\n
\n
query_kw = {\n query_kw = {\n
\'software_release_url\': software_release.getUrlString(),\n \'software_release_url\': software_release.getUrlString(),\n
\'portal_type\': \'Computer Partition\',\n \'portal_type\': \'Computer Partition\',\n
# \'relative_url\': \'computer_module/20110126-E2AE/%\',\n # \'relative_url\': \'computer_module/20110126-E2AE/%\',\n
\'free_for_request\': 1,\n \'free_for_request\': 1,\n
}\n }\n
# support SLA\n
filter_kw = software_instance.getSlaXmlAsDict()\n
if "computer_guid" in filter_kw:\n
query_kw["parent_reference"] = filter_kw["computer_guid"]\n
\n \n
result_count = software_instance.portal_catalog.countResults(**query_kw)[0][0]\n result_count = software_instance.portal_catalog.countResults(**query_kw)[0][0]\n
offset = max(0, result_count-1)\n offset = max(0, result_count-1)\n
......
85 88
\ No newline at end of file \ No newline at end of file
software_release_module/test_software_release software_release_module/test_software_release
software_product_module/test_software_product
\ No newline at end of file
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="Alarm" module="Products.ERP5Type.Document.Alarm"/> <global name="Alarm" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -59,7 +59,7 @@ ...@@ -59,7 +59,7 @@
</item> </item>
<item> <item>
<key> <string>type_class</string> </key> <key> <string>type_class</string> </key>
<value> <string>Folder</string> </value> <value> <string>Products.Vifib.Tool.SlapTool.SlapTool</string> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="SlapTool" module="Products.Vifib.Tool.SlapTool"/> <global name="Slap Tool" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
......
...@@ -59,8 +59,9 @@ portal = person.getPortalObject()\n ...@@ -59,8 +59,9 @@ portal = person.getPortalObject()\n
kwargs = state_change.kwargs\n kwargs = state_change.kwargs\n
software_release_url_string = state_change.kwargs[\'software_release\']\n software_release_url_string = state_change.kwargs[\'software_release\']\n
software_title = kwargs["software_title"]\n software_title = kwargs["software_title"]\n
software_type = "RootSoftwareInstance"\n software_type = kwargs.get("software_type") or "RootSoftwareInstance"\n
instance_xml = kwargs["instance_xml"]\n instance_xml = kwargs["instance_xml"]\n
sla_xml = kwargs.get("sla_xml") or ""\n
\n \n
sale_order_portal_type = "Sale Order"\n sale_order_portal_type = "Sale Order"\n
sale_order_line_portal_type = "Sale Order Line"\n sale_order_line_portal_type = "Sale Order Line"\n
...@@ -96,6 +97,7 @@ if (request_software_instance is None):\n ...@@ -96,6 +97,7 @@ if (request_software_instance is None):\n
source_reference=software_type,\n source_reference=software_type,\n
title=software_title,\n title=software_title,\n
text_content=instance_xml,\n text_content=instance_xml,\n
sla_xml=sla_xml,\n
activate_kw={\'tag\': tag},\n activate_kw={\'tag\': tag},\n
**portal.Base_getNewSoftwareInstanceCoordinate()\n **portal.Base_getNewSoftwareInstanceCoordinate()\n
)\n )\n
...@@ -168,6 +170,7 @@ else:\n ...@@ -168,6 +170,7 @@ else:\n
# Update existing software instance\n # Update existing software instance\n
request_software_instance.edit(\n request_software_instance.edit(\n
text_content=instance_xml,\n text_content=instance_xml,\n
sla_xml=sla_xml,\n
activate_kw={\'tag\': tag},\n activate_kw={\'tag\': tag},\n
)\n )\n
......
372 378
\ No newline at end of file \ No newline at end of file
...@@ -180,7 +180,8 @@ class CertificateAuthorityTool(BaseTool): ...@@ -180,7 +180,8 @@ class CertificateAuthorityTool(BaseTool):
security.declareProtected(Permissions.AccessContentsInformation, 'getNewCertificate') security.declareProtected(Permissions.AccessContentsInformation, 'getNewCertificate')
def getNewCertificate(self, common_name): def getNewCertificate(self, common_name):
"""Returns certificate for passed common name, as dictionary of {key, certificate, id, common_name}""" # No docstring in order to make this method non publishable
# Returns certificate for passed common name, as dictionary of {key, certificate, id, common_name}
self._checkCertificateAuthority() self._checkCertificateAuthority()
self._lockCertificateAuthority() self._lockCertificateAuthority()
try: try:
...@@ -215,7 +216,8 @@ class CertificateAuthorityTool(BaseTool): ...@@ -215,7 +216,8 @@ class CertificateAuthorityTool(BaseTool):
security.declareProtected(Permissions.AccessContentsInformation, 'revokeCertificate') security.declareProtected(Permissions.AccessContentsInformation, 'revokeCertificate')
def revokeCertificate(self, serial): def revokeCertificate(self, serial):
"""Revokes certificate with serial, returns dictionary {crl}""" # No docstring in order to make this method non publishable
# Revokes certificate with serial, returns dictionary {crl}
self._checkCertificateAuthority() self._checkCertificateAuthority()
self._lockCertificateAuthority() self._lockCertificateAuthority()
try: try:
...@@ -247,4 +249,19 @@ class CertificateAuthorityTool(BaseTool): ...@@ -247,4 +249,19 @@ class CertificateAuthorityTool(BaseTool):
finally: finally:
self._unlockCertificateAuthority() self._unlockCertificateAuthority()
def _getValidSerial(self, common_name):
index = open(self.index).read().splitlines()
valid_line_list = [q for q in index if q.startswith('V') and
('CN=%s' % common_name in q)]
if len(valid_line_list) != 1:
raise ValueError('No certificate for %r' % common_name)
return valid_line_list[0].split('\t')[3]
security.declareProtected(Permissions.AccessContentsInformation,
'revokeCertificate')
def revokeCertificateByCommonName(self, common_name):
self._checkCertificateAuthority()
serial = self._getValidSerial(common_name)
self.revokeCertificate(serial)
InitializeClass(CertificateAuthorityTool) InitializeClass(CertificateAuthorityTool)
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
############################################################################## ##############################################################################
# #
# Copyright (c) 2010 Nexedi SA and Contributors. All Rights Reserved. # Copyright (c) 2010-2011 Nexedi SA and Contributors. All Rights Reserved.
# Łukasz Nowak <luke@nexedi.com> # Łukasz Nowak <luke@nexedi.com>
# Romain Courteaud <romain@nexedi.com> # Romain Courteaud <romain@nexedi.com>
# #
...@@ -73,7 +73,7 @@ def convertToREST(function): ...@@ -73,7 +73,7 @@ def convertToREST(function):
""" """
try: try:
retval = function(self, *args, **kwd) retval = function(self, *args, **kwd)
except ValueError, log: except (ValueError, AttributeError), log:
LOG('SlapTool', INFO, 'Converting ValueError to NotFound, real error:', LOG('SlapTool', INFO, 'Converting ValueError to NotFound, real error:',
error=True) error=True)
raise NotFound(log) raise NotFound(log)
...@@ -81,7 +81,8 @@ def convertToREST(function): ...@@ -81,7 +81,8 @@ def convertToREST(function):
self.REQUEST.response.setStatus(408) self.REQUEST.response.setStatus(408)
return self.REQUEST.response return self.REQUEST.response
except ValidationFailed: except ValidationFailed:
LOG('SlapTool', INFO, 'Converting ValidationFailed to ValidationFailed, real error:', LOG('SlapTool', INFO, 'Converting ValidationFailed to ValidationFailed,'\
' real error:',
error=True) error=True)
raise ValidationFailed raise ValidationFailed
...@@ -123,7 +124,8 @@ class SlapTool(BaseTool): ...@@ -123,7 +124,8 @@ class SlapTool(BaseTool):
# Public GET methods # Public GET methods
#################################################### ####################################################
security.declareProtected(Permissions.AccessContentsInformation, 'getComputerInformation') security.declareProtected(Permissions.AccessContentsInformation,
'getComputerInformation')
def getComputerInformation(self, computer_id): def getComputerInformation(self, computer_id):
"""Returns marshalled XML of all needed information for computer """Returns marshalled XML of all needed information for computer
...@@ -149,7 +151,8 @@ class SlapTool(BaseTool): ...@@ -149,7 +151,8 @@ class SlapTool(BaseTool):
self._convertToSlapPartition(slave_partition_document, computer_id)) self._convertToSlapPartition(slave_partition_document, computer_id))
return xml_marshaller.xml_marshaller.dumps(slap_computer) return xml_marshaller.xml_marshaller.dumps(slap_computer)
security.declareProtected(Permissions.AccessContentsInformation, 'getComputerPartitionCertificate') security.declareProtected(Permissions.AccessContentsInformation,
'getComputerPartitionCertificate')
def getComputerPartitionCertificate(self, computer_id, computer_partition_id): def getComputerPartitionCertificate(self, computer_id, computer_partition_id):
"""Method to fetch certificate""" """Method to fetch certificate"""
self.REQUEST.response.setHeader('Content-Type', 'text/xml') self.REQUEST.response.setHeader('Content-Type', 'text/xml')
...@@ -165,7 +168,8 @@ class SlapTool(BaseTool): ...@@ -165,7 +168,8 @@ class SlapTool(BaseTool):
# Public POST methods # Public POST methods
#################################################### ####################################################
security.declareProtected(Permissions.AccessContentsInformation, 'setComputerPartitionConnectionXml') security.declareProtected(Permissions.AccessContentsInformation,
'setComputerPartitionConnectionXml')
def setComputerPartitionConnectionXml(self, computer_id, def setComputerPartitionConnectionXml(self, computer_id,
computer_partition_id, computer_partition_id,
connection_xml): connection_xml):
...@@ -176,42 +180,48 @@ class SlapTool(BaseTool): ...@@ -176,42 +180,48 @@ class SlapTool(BaseTool):
computer_partition_id, computer_partition_id,
connection_xml) connection_xml)
security.declareProtected(Permissions.AccessContentsInformation, 'buildingSoftwareRelease') security.declareProtected(Permissions.AccessContentsInformation,
'buildingSoftwareRelease')
def buildingSoftwareRelease(self, url, computer_id): def buildingSoftwareRelease(self, url, computer_id):
""" """
Reports that Software Release is being build Reports that Software Release is being build
""" """
return self._buildingSoftwareRelease(url, computer_id) return self._buildingSoftwareRelease(url, computer_id)
security.declareProtected(Permissions.AccessContentsInformation, 'availableSoftwareRelease') security.declareProtected(Permissions.AccessContentsInformation,
'availableSoftwareRelease')
def availableSoftwareRelease(self, url, computer_id): def availableSoftwareRelease(self, url, computer_id):
""" """
Reports that Software Release is available Reports that Software Release is available
""" """
return self._availableSoftwareRelease(url, computer_id) return self._availableSoftwareRelease(url, computer_id)
security.declareProtected(Permissions.AccessContentsInformation, 'softwareReleaseError') security.declareProtected(Permissions.AccessContentsInformation,
'softwareReleaseError')
def softwareReleaseError(self, url, computer_id, error_log): def softwareReleaseError(self, url, computer_id, error_log):
""" """
Add an error for a software Release workflow Add an error for a software Release workflow
""" """
return self._softwareReleaseError(url, computer_id, error_log) return self._softwareReleaseError(url, computer_id, error_log)
security.declareProtected(Permissions.AccessContentsInformation, 'buildingComputerPartition') security.declareProtected(Permissions.AccessContentsInformation,
'buildingComputerPartition')
def buildingComputerPartition(self, computer_id, computer_partition_id): def buildingComputerPartition(self, computer_id, computer_partition_id):
""" """
Reports that Computer Partition is being build Reports that Computer Partition is being build
""" """
return self._buildingComputerPartition(computer_id, computer_partition_id) return self._buildingComputerPartition(computer_id, computer_partition_id)
security.declareProtected(Permissions.AccessContentsInformation, 'availableComputerPartition') security.declareProtected(Permissions.AccessContentsInformation,
'availableComputerPartition')
def availableComputerPartition(self, computer_id, computer_partition_id): def availableComputerPartition(self, computer_id, computer_partition_id):
""" """
Reports that Computer Partition is available Reports that Computer Partition is available
""" """
return self._availableComputerPartition(computer_id, computer_partition_id) return self._availableComputerPartition(computer_id, computer_partition_id)
security.declareProtected(Permissions.AccessContentsInformation, 'softwareInstanceError') security.declareProtected(Permissions.AccessContentsInformation,
'softwareInstanceError')
def softwareInstanceError(self, computer_id, def softwareInstanceError(self, computer_id,
computer_partition_id, error_log): computer_partition_id, error_log):
""" """
...@@ -220,31 +230,36 @@ class SlapTool(BaseTool): ...@@ -220,31 +230,36 @@ class SlapTool(BaseTool):
return self._softwareInstanceError(computer_id, computer_partition_id, return self._softwareInstanceError(computer_id, computer_partition_id,
error_log) error_log)
security.declareProtected(Permissions.AccessContentsInformation, 'startedComputerPartition') security.declareProtected(Permissions.AccessContentsInformation,
'startedComputerPartition')
def startedComputerPartition(self, computer_id, computer_partition_id): def startedComputerPartition(self, computer_id, computer_partition_id):
""" """
Reports that Computer Partition is started Reports that Computer Partition is started
""" """
return self._startedComputerPartition(computer_id, computer_partition_id) return self._startedComputerPartition(computer_id, computer_partition_id)
security.declareProtected(Permissions.AccessContentsInformation, 'stoppedComputerPartition') security.declareProtected(Permissions.AccessContentsInformation,
'stoppedComputerPartition')
def stoppedComputerPartition(self, computer_id, computer_partition_id): def stoppedComputerPartition(self, computer_id, computer_partition_id):
""" """
Reports that Computer Partition is stopped Reports that Computer Partition is stopped
""" """
return self._stoppedComputerPartition(computer_id, computer_partition_id) return self._stoppedComputerPartition(computer_id, computer_partition_id)
security.declareProtected(Permissions.AccessContentsInformation, 'destroyedComputerPartition') security.declareProtected(Permissions.AccessContentsInformation,
'destroyedComputerPartition')
def destroyedComputerPartition(self, computer_id, computer_partition_id): def destroyedComputerPartition(self, computer_id, computer_partition_id):
""" """
Reports that Computer Partition is destroyed Reports that Computer Partition is destroyed
""" """
return self._destroyedComputerPartition(computer_id, computer_partition_id) return self._destroyedComputerPartition(computer_id, computer_partition_id)
security.declareProtected(Permissions.AccessContentsInformation, 'requestComputerPartition') security.declareProtected(Permissions.AccessContentsInformation,
def requestComputerPartition(self, computer_id, computer_partition_id, 'requestComputerPartition')
software_release, software_type, partition_reference, def requestComputerPartition(self, computer_id=None,
shared_xml, partition_parameter_xml, filter_xml): computer_partition_id=None, software_release=None, software_type=None,
partition_reference=None, shared_xml=None, partition_parameter_xml=None,
filter_xml=None):
""" """
Asynchronously requests creation of computer partition for assigned Asynchronously requests creation of computer partition for assigned
parameters parameters
...@@ -260,7 +275,8 @@ class SlapTool(BaseTool): ...@@ -260,7 +275,8 @@ class SlapTool(BaseTool):
software_release, software_type, partition_reference, software_release, software_type, partition_reference,
shared_xml, partition_parameter_xml, filter_xml) shared_xml, partition_parameter_xml, filter_xml)
security.declareProtected(Permissions.AccessContentsInformation, 'useComputer') security.declareProtected(Permissions.AccessContentsInformation,
'useComputer')
def useComputer(self, computer_id, use_string): def useComputer(self, computer_id, use_string):
"""Entry point to reporting usage of a computer.""" """Entry point to reporting usage of a computer."""
#computer_document = self._getComputerDocument(computer_id) #computer_document = self._getComputerDocument(computer_id)
...@@ -283,7 +299,8 @@ class SlapTool(BaseTool): ...@@ -283,7 +299,8 @@ class SlapTool(BaseTool):
return 'Content properly posted.' return 'Content properly posted.'
security.declareProtected(Permissions.AccessContentsInformation, 'loadComputerConfigurationFromXML') security.declareProtected(Permissions.AccessContentsInformation,
'loadComputerConfigurationFromXML')
def loadComputerConfigurationFromXML(self, xml): def loadComputerConfigurationFromXML(self, xml):
"Load the given xml as configuration for the computer object" "Load the given xml as configuration for the computer object"
computer_dict = xml_marshaller.xml_marshaller.loads(xml) computer_dict = xml_marshaller.xml_marshaller.loads(xml)
...@@ -291,8 +308,10 @@ class SlapTool(BaseTool): ...@@ -291,8 +308,10 @@ class SlapTool(BaseTool):
computer.Computer_updateFromDict(computer_dict) computer.Computer_updateFromDict(computer_dict)
return 'Content properly posted.' return 'Content properly posted.'
security.declareProtected(Permissions.AccessContentsInformation, 'useComputerPartition') security.declareProtected(Permissions.AccessContentsInformation,
def useComputerPartition(self, computer_id, computer_partition_id, use_string): 'useComputerPartition')
def useComputerPartition(self, computer_id, computer_partition_id,
use_string):
"""Warning : deprecated method.""" """Warning : deprecated method."""
computer_document = self._getComputerDocument(computer_id) computer_document = self._getComputerDocument(computer_id)
computer_partition_document = self._getComputerPartitionDocument( computer_partition_document = self._getComputerPartitionDocument(
...@@ -303,7 +322,8 @@ class SlapTool(BaseTool): ...@@ -303,7 +322,8 @@ class SlapTool(BaseTool):
return """Content properly posted. return """Content properly posted.
WARNING : this method is deprecated. Please use useComputer.""" WARNING : this method is deprecated. Please use useComputer."""
security.declareProtected(Permissions.AccessContentsInformation, 'registerComputerPartition') security.declareProtected(Permissions.AccessContentsInformation,
'registerComputerPartition')
def registerComputerPartition(self, computer_reference, def registerComputerPartition(self, computer_reference,
computer_partition_reference): computer_partition_reference):
""" """
...@@ -326,8 +346,7 @@ class SlapTool(BaseTool): ...@@ -326,8 +346,7 @@ class SlapTool(BaseTool):
result_dict = {} result_dict = {}
if xml is not None and xml != '': if xml is not None and xml != '':
tree = etree.fromstring(xml.encode('utf-8')) tree = etree.fromstring(xml.encode('utf-8'))
for element in tree.iter(tag=etree.Element): for element in tree.findall('parameter'):
if element.tag == 'parameter':
key = element.get('id') key = element.get('id')
value = result_dict.get(key, None) value = result_dict.get(key, None)
if value is not None: if value is not None:
...@@ -414,7 +433,8 @@ class SlapTool(BaseTool): ...@@ -414,7 +433,8 @@ class SlapTool(BaseTool):
elif movement.getResource() == \ elif movement.getResource() == \
portal_preferences.getPreferredInstanceCleanupResource(): portal_preferences.getPreferredInstanceCleanupResource():
if movement.getSimulationState() in ('confirmed', 'started', 'stopped'): if movement.getSimulationState() in ('confirmed', 'started',
'stopped'):
slap_partition._need_modification = 1 slap_partition._need_modification = 1
else: else:
...@@ -440,7 +460,8 @@ class SlapTool(BaseTool): ...@@ -440,7 +460,8 @@ class SlapTool(BaseTool):
Reports that Software Release is being build Reports that Software Release is being build
""" """
computer_document = self._getComputerDocument(computer_id) computer_document = self._getComputerDocument(computer_id)
computer_document.startSoftwareReleaseInstallation(software_release_url=url) computer_document.startSoftwareReleaseInstallation(
software_release_url=url)
@convertToREST @convertToREST
def _availableSoftwareRelease(self, url, computer_id): def _availableSoftwareRelease(self, url, computer_id):
...@@ -552,7 +573,8 @@ class SlapTool(BaseTool): ...@@ -552,7 +573,8 @@ class SlapTool(BaseTool):
Returns XML representation of partition with HTTP code 200 OK Returns XML representation of partition with HTTP code 200 OK
In case if this request is still being processed data contain In case if this request is still being processed data contain
"Computer Partition is being processed" and HTTP code is 408 Request Timeout "Computer Partition is being processed" and HTTP code is 408 Request
Timeout
In any other case returns not important data and HTTP code is 403 Forbidden In any other case returns not important data and HTTP code is 403 Forbidden
""" """
...@@ -579,8 +601,19 @@ class SlapTool(BaseTool): ...@@ -579,8 +601,19 @@ class SlapTool(BaseTool):
instance_xml = etree.tostring(instance, pretty_print=True, instance_xml = etree.tostring(instance, pretty_print=True,
xml_declaration=True, encoding='utf-8') xml_declaration=True, encoding='utf-8')
software_instance_document = self._getSoftwareInstanceForComputerPartition( instance = etree.Element('instance')
computer_id, for parameter_id, parameter_value in filter_kw.iteritems():
# cast everything to string
parameter_value = str(parameter_value)
etree.SubElement(instance, "parameter",
attrib={'id':parameter_id}).text = parameter_value
sla_xml = etree.tostring(instance, pretty_print=True,
xml_declaration=True, encoding='utf-8')
if computer_id and computer_partition_id:
# requested by Software Instance, there is already top part of tree
software_instance_document = self.\
_getSoftwareInstanceForComputerPartition(computer_id,
computer_partition_id) computer_partition_id)
software_instance_document.requestSoftwareInstance( software_instance_document.requestSoftwareInstance(
software_release=software_release, software_release=software_release,
...@@ -588,7 +621,7 @@ class SlapTool(BaseTool): ...@@ -588,7 +621,7 @@ class SlapTool(BaseTool):
partition_reference=partition_reference, partition_reference=partition_reference,
shared=shared, shared=shared,
instance_xml=instance_xml, instance_xml=instance_xml,
filter_kw=filter_kw) sla_xml=sla_xml)
# Get requested software instance # Get requested software instance
requested_software_instance = software_instance_document.portal_catalog.\ requested_software_instance = software_instance_document.portal_catalog.\
...@@ -601,12 +634,33 @@ class SlapTool(BaseTool): ...@@ -601,12 +634,33 @@ class SlapTool(BaseTool):
predecessor_related_uid=software_instance_document.getUid(), predecessor_related_uid=software_instance_document.getUid(),
title=partition_reference, title=partition_reference,
) )
else:
# requested as root, so done by human
person = self.getPortalObject()\
.ERP5Site_getAuthenticatedMemberPersonValue()
person.requestSoftwareInstance(software_release=software_release,
software_type=software_type,
software_title=partition_reference,
shared=shared,
instance_xml=instance_xml,
sla_xml=sla_xml)
requested_software_instance = person.portal_catalog.\
getResultValue(
portal_type="Software Instance",
# In order be in sync with defaults of person.
# requestSoftwareInstance it is required to default here
# too
source_reference=software_type or 'RootSoftwareInstance',
title=partition_reference,
)
if requested_software_instance is None: if requested_software_instance is None:
raise SoftwareInstanceNotReady raise SoftwareInstanceNotReady
else: else:
movement = self._getSalePackingListLineForComputerPartition( movement = self._getSalePackingListLineForComputerPartition(
requested_software_instance) requested_software_instance)
if movement is None:
raise SoftwareInstanceNotReady
software_instance = SoftwareInstance( software_instance = SoftwareInstance(
**self._getSalePackingListLineAsSoftwareInstance( **self._getSalePackingListLineAsSoftwareInstance(
movement)) movement))
...@@ -676,8 +730,8 @@ class SlapTool(BaseTool): ...@@ -676,8 +730,8 @@ class SlapTool(BaseTool):
software_instance = packing_list_line.getAggregateValue( software_instance = packing_list_line.getAggregateValue(
portal_type="Software Instance") portal_type="Software Instance")
if software_instance is None: if software_instance is None:
raise NotFound, "No software instance found for: %s - %s" % (computer_id, raise NotFound, "No software instance found for: %s - %s" % (
computer_partition_id) computer_id, computer_partition_id)
else: else:
return software_instance return software_instance
...@@ -773,7 +827,8 @@ class SlapTool(BaseTool): ...@@ -773,7 +827,8 @@ class SlapTool(BaseTool):
usage_report_sale_packing_list_document.start() usage_report_sale_packing_list_document.start()
# Adds a new SPL line for each Computer Partition # Adds a new SPL line for each Computer Partition
for computer_partition_usage in unmarshalled_usage.computer_partition_usage_list: for computer_partition_usage in unmarshalled_usage\
.computer_partition_usage_list:
#Get good packing list line for a computer_partition #Get good packing list line for a computer_partition
computer_partition_document = self.\ computer_partition_document = self.\
_getComputerPartitionDocument( _getComputerPartitionDocument(
......
...@@ -47,6 +47,7 @@ from Products.ERP5Security.ERP5GroupManager import ConsistencyError, NO_CACHE_MO ...@@ -47,6 +47,7 @@ from Products.ERP5Security.ERP5GroupManager import ConsistencyError, NO_CACHE_MO
from Products.ERP5Type.ERP5Type \ from Products.ERP5Type.ERP5Type \
import ERP5TYPE_SECURITY_GROUP_ID_GENERATION_SCRIPT import ERP5TYPE_SECURITY_GROUP_ID_GENERATION_SCRIPT
from Products.ERP5Type.Cache import CachingMethod from Products.ERP5Type.Cache import CachingMethod
from Products.ZSQLCatalog.SQLCatalog import Query, ComplexQuery
#Form for new plugin in ZMI #Form for new plugin in ZMI
manage_addVifibMachineAuthenticationPluginForm = PageTemplateFile( manage_addVifibMachineAuthenticationPluginForm = PageTemplateFile(
...@@ -70,11 +71,14 @@ def addVifibMachineAuthenticationPlugin(dispatcher, id, title=None, REQUEST=None ...@@ -70,11 +71,14 @@ def addVifibMachineAuthenticationPlugin(dispatcher, id, title=None, REQUEST=None
def getUserByLogin(portal, login): def getUserByLogin(portal, login):
if isinstance(login, basestring): if isinstance(login, basestring):
login = login, login = login,
result = portal.portal_catalog.unrestrictedSearchResults( machine_query = Query(portal_type=["Computer", "Software Instance"],
select_expression='reference',
portal_type=["Computer", "Software Instance"],
validation_state="validated", validation_state="validated",
reference=dict(query=login, key='ExactMatch')) reference=dict(query=login, key='ExactMatch'))
person_query = Query(portal_type=["Person"],
reference=dict(query=login, key='ExactMatch'))
result = portal.portal_catalog.unrestrictedSearchResults(
query=ComplexQuery(machine_query, person_query, operator="OR"),
select_expression='reference')
# XXX: Here, we filter catalog result list ALTHOUGH we did pass # XXX: Here, we filter catalog result list ALTHOUGH we did pass
# parameters to unrestrictedSearchResults to restrict result set. # parameters to unrestrictedSearchResults to restrict result set.
# This is done because the following values can match person with # This is done because the following values can match person with
...@@ -92,7 +96,6 @@ def getUserByLogin(portal, login): ...@@ -92,7 +96,6 @@ def getUserByLogin(portal, login):
# by default (feature). # by default (feature).
return [x.getObject() for x in result if x['reference'] in login] return [x.getObject() for x in result if x['reference'] in login]
class VifibMachineAuthenticationPlugin(BasePlugin): class VifibMachineAuthenticationPlugin(BasePlugin):
""" """
Plugin to authenicate as machines. Plugin to authenicate as machines.
......
...@@ -86,6 +86,7 @@ class TestVifibSlapWebService(testVifibMixin): ...@@ -86,6 +86,7 @@ class TestVifibSlapWebService(testVifibMixin):
purchase_packing_list_line_portal_type = "Purchase Packing List Line" purchase_packing_list_line_portal_type = "Purchase Packing List Line"
purchase_packing_list_portal_type = "Purchase Packing List" purchase_packing_list_portal_type = "Purchase Packing List"
sale_packing_list_line_portal_type = "Sale Packing List Line" sale_packing_list_line_portal_type = "Sale Packing List Line"
sale_order_line_portal_type = "Sale Order Line"
sale_packing_list_portal_type = "Sale Packing List" sale_packing_list_portal_type = "Sale Packing List"
service_portal_type = "Service" service_portal_type = "Service"
slave_partition_portal_type = "Slave Partition" slave_partition_portal_type = "Slave Partition"
...@@ -122,7 +123,7 @@ class TestVifibSlapWebService(testVifibMixin): ...@@ -122,7 +123,7 @@ class TestVifibSlapWebService(testVifibMixin):
self.assertEqual(got, {}) self.assertEqual(got, {})
######################################## ########################################
# Ĥelpers # Helpers
######################################## ########################################
def _softwareInstance_getComputerPartition(self, software_instance): def _softwareInstance_getComputerPartition(self, software_instance):
sale_packing_list_line = software_instance\ sale_packing_list_line = software_instance\
...@@ -367,10 +368,18 @@ class TestVifibSlapWebService(testVifibMixin): ...@@ -367,10 +368,18 @@ class TestVifibSlapWebService(testVifibMixin):
self.portal.portal_catalog.getResultValue( self.portal.portal_catalog.getResultValue(
uid=sequence['software_instance_uid']).requestDestroyComputerPartition() uid=sequence['software_instance_uid']).requestDestroyComputerPartition()
def stepRequestSoftwareInstanceDestroyRaisesValueError(self, sequence, **kw):
self.assertRaises(ValueError, self.portal.portal_catalog.getResultValue(
uid=sequence['software_instance_uid']).requestDestroyComputerPartition)
def stepRequestSoftwareInstanceStart(self, sequence, **kw): def stepRequestSoftwareInstanceStart(self, sequence, **kw):
self.portal.portal_catalog.getResultValue( self.portal.portal_catalog.getResultValue(
uid=sequence['software_instance_uid']).requestStartComputerPartition() uid=sequence['software_instance_uid']).requestStartComputerPartition()
def stepRequestSoftwareInstanceStartRaisesValueError(self, sequence, **kw):
self.assertRaises(ValueError, self.portal.portal_catalog.getResultValue(
uid=sequence['software_instance_uid']).requestStartComputerPartition)
def stepRequestSoftwareInstanceStop(self, sequence, **kw): def stepRequestSoftwareInstanceStop(self, sequence, **kw):
self.portal.portal_catalog.getResultValue( self.portal.portal_catalog.getResultValue(
uid=sequence['software_instance_uid']).requestStopComputerPartition() uid=sequence['software_instance_uid']).requestStopComputerPartition()
...@@ -561,6 +570,10 @@ class TestVifibSlapWebService(testVifibMixin): ...@@ -561,6 +570,10 @@ class TestVifibSlapWebService(testVifibMixin):
global REMOTE_USER global REMOTE_USER
REMOTE_USER = sequence['software_instance_reference'] REMOTE_USER = sequence['software_instance_reference']
def stepSlapLoginTestVifibCustomer(self, sequence, **kw):
global REMOTE_USER
REMOTE_USER = 'test_vifib_customer'
######################################## ########################################
# Typical sequences for scenarios # Typical sequences for scenarios
######################################## ########################################
...@@ -1470,6 +1483,56 @@ class TestVifibSlapWebService(testVifibMixin): ...@@ -1470,6 +1483,56 @@ class TestVifibSlapWebService(testVifibMixin):
partition_reference=requested_reference, partition_reference=requested_reference,
partition_parameter_kw=requested_parameter_dict) partition_parameter_kw=requested_parameter_dict)
def stepRequestSoftwareInstanceStartCheckSerializeIsCalled(self, sequence):
# check that on being_requested serialise is being called
# code stolen from testERP5Security:test_MultiplePersonReferenceConcurrentTransaction
class DummyTestException(Exception):
pass
def verify_serialize_call(self):
# it is checking that anything below computer_module raises exception
# thanks to this this test do not have to be destructive
if self.getPortalType() == "Software Instance":
raise DummyTestException
else:
return self.serialize_call()
from Products.ERP5Type.Base import Base
Base.serialize_call = Base.serialize
Base.serialize = verify_serialize_call
try:
self.assertRaises(DummyTestException,
self.portal.portal_catalog.getResultValue(
uid=sequence['software_instance_uid']).requestStartComputerPartition)
finally:
Base.serialize = Base.serialize_call
def stepRequestSoftwareInstanceDestroyCheckSerializeIsCalled(self, sequence):
# check that on being_requested serialise is being called
# code stolen from testERP5Security:test_MultiplePersonReferenceConcurrentTransaction
class DummyTestException(Exception):
pass
def verify_serialize_call(self):
# it is checking that anything below computer_module raises exception
# thanks to this this test do not have to be destructive
if self.getPortalType() == "Software Instance":
raise DummyTestException
else:
return self.serialize_call()
from Products.ERP5Type.Base import Base
Base.serialize_call = Base.serialize
Base.serialize = verify_serialize_call
try:
self.assertRaises(DummyTestException,
self.portal.portal_catalog.getResultValue(
uid=sequence['software_instance_uid']).requestDestroyComputerPartition)
finally:
Base.serialize = Base.serialize_call
def stepRequestComputerComputerPartitionCheckSerializeCalledOnSelected( def stepRequestComputerComputerPartitionCheckSerializeCalledOnSelected(
self, sequence, **kw): self, sequence, **kw):
software_release_uri = sequence['software_release_uri'] software_release_uri = sequence['software_release_uri']
...@@ -1504,7 +1567,8 @@ class TestVifibSlapWebService(testVifibMixin): ...@@ -1504,7 +1567,8 @@ class TestVifibSlapWebService(testVifibMixin):
software_type=requested_reference, software_type=requested_reference,
shared=False, shared=False,
filter_kw={}, filter_kw={},
instance_xml=self.minimal_correct_xml) instance_xml=self.minimal_correct_xml,
sla_xml=self.minimal_correct_xml)
finally: finally:
Base.serialize = Base.serialize_call Base.serialize = Base.serialize_call
...@@ -2951,6 +3015,51 @@ class TestVifibSlapWebService(testVifibMixin): ...@@ -2951,6 +3015,51 @@ class TestVifibSlapWebService(testVifibMixin):
portal_type=self.sale_packing_list_line_portal_type) portal_type=self.sale_packing_list_line_portal_type)
self.assertEqual(1, len(computer_partition_sale_packing_list_line_list)) self.assertEqual(1, len(computer_partition_sale_packing_list_line_list))
def stepCheckPersonRequestedSoftwareInstanceAndRelatedComputerPartition(self,
sequence, **kw):
software_instance = self.portal.portal_catalog.getResultValue(
uid=sequence['software_instance_uid'])
# in this test it is required to assume that requested_reference
computer_partition = self._softwareInstance_getComputerPartition(
software_instance)
# There should be only one Sale Packing List Line
sale_packing_list_line_list = software_instance\
.getAggregateRelatedValueList(
portal_type=self.sale_packing_list_line_portal_type)
self.assertEqual(1, len(sale_packing_list_line_list))
sale_packing_list_line = sale_packing_list_line_list[0]
# This Sale Packing List Line shall have only one Computer Partition
computer_partition_list = sale_packing_list_line.getAggregateValueList(
portal_type='Computer Partition')
self.assertEqual(1, len(computer_partition_list))
computer_partition = computer_partition_list[0]
# This Computer Partition shall have only Sale Packing List Line related
computer_partition_sale_packing_list_line_list = computer_partition\
.getAggregateRelatedValueList(
portal_type=self.sale_packing_list_line_portal_type)
self.assertEqual(1, len(computer_partition_sale_packing_list_line_list))
# There should be only one Sale Order Line
sale_order_line_list = software_instance\
.getAggregateRelatedValueList(
portal_type=self.sale_order_line_portal_type)
self.assertEqual(1, len(sale_order_line_list))
sale_order_line = sale_order_line_list[0]
# This Sale Order Line shall have only one Computer Partition
computer_partition_list = sale_order_line.getAggregateValueList(
portal_type='Computer Partition')
self.assertEqual(1, len(computer_partition_list))
computer_partition = computer_partition_list[0]
# This Computer Partition shall have only Sale Order Line related
computer_partition_sale_order_line_list = computer_partition\
.getAggregateRelatedValueList(
portal_type=self.sale_order_line_portal_type)
self.assertEqual(1, len(computer_partition_sale_order_line_list))
def stepCheckSoftwareInstanceAndRelatedComputerPartition(self, def stepCheckSoftwareInstanceAndRelatedComputerPartition(self,
sequence, **kw): sequence, **kw):
software_instance_uid = sequence['software_instance_uid'] software_instance_uid = sequence['software_instance_uid']
...@@ -4007,12 +4116,6 @@ class TestVifibSlapWebService(testVifibMixin): ...@@ -4007,12 +4116,6 @@ class TestVifibSlapWebService(testVifibMixin):
sequence['requested_filter_dict'] = dict( sequence['requested_filter_dict'] = dict(
computer_guid=sequence['computer_reference']) computer_guid=sequence['computer_reference'])
def test_ComputerPartition_request_filter_computer_guid(self):
"""
Check that requesting with filter computer_guid key works as expected
"""
self.computer_partition_amount = 2
sequence_list = SequenceList()
prepare_another_computer_sequence_string = """ prepare_another_computer_sequence_string = """
StoreComputerReference StoreComputerReference
LoginTestVifibAdmin LoginTestVifibAdmin
...@@ -4023,7 +4126,7 @@ class TestVifibSlapWebService(testVifibMixin): ...@@ -4023,7 +4126,7 @@ class TestVifibSlapWebService(testVifibMixin):
SlapLoginCurrentComputer SlapLoginCurrentComputer
FormatComputer FormatComputer
Tic Tic
SlapLogout""" + self.prepare_software_release_confirmed_packing_list + """ SlapLogout""" + prepare_software_release_confirmed_packing_list + """
LoginTestVifibAdmin LoginTestVifibAdmin
RequestSoftwareInstallation RequestSoftwareInstallation
...@@ -4038,12 +4141,19 @@ class TestVifibSlapWebService(testVifibMixin): ...@@ -4038,12 +4141,19 @@ class TestVifibSlapWebService(testVifibMixin):
SetRequestedFilterParameterDict SetRequestedFilterParameterDict
RestoreComputerReference RestoreComputerReference
""" """
def test_ComputerPartition_request_filter_computer_guid(self):
"""
Check that requesting with filter computer_guid key works as expected
"""
self.computer_partition_amount = 2
sequence_list = SequenceList()
# There are two partitions on another computer # There are two partitions on another computer
# so request shall be processed twice correctly, 3rd time it shall # so request shall be processed twice correctly, 3rd time it shall
# fail # fail
sequence_string = \ sequence_string = \
self.prepare_install_requested_computer_partition_sequence_string + \ self.prepare_install_requested_computer_partition_sequence_string + \
prepare_another_computer_sequence_string + '\ self.prepare_another_computer_sequence_string + '\
SlapLoginCurrentSoftwareInstance \ SlapLoginCurrentSoftwareInstance \
RequestComputerPartitionNotReadyResponse \ RequestComputerPartitionNotReadyResponse \
Tic \ Tic \
...@@ -6883,6 +6993,293 @@ class TestVifibSlapWebService(testVifibMixin): ...@@ -6883,6 +6993,293 @@ class TestVifibSlapWebService(testVifibMixin):
sequence_list.addSequenceString(sequence_string) sequence_list.addSequenceString(sequence_string)
sequence_list.play(self) sequence_list.play(self)
########################################
# Person using PKI/Slap interface
########################################
def _safe_revoke_certificate(self, person):
from AccessControl import getSecurityManager
user = getSecurityManager().getUser().getId()
try:
self.login('ERP5TypeTestCase')
person.revokeCertificate()
except ValueError, err:
if 'No certificate for' in err.message:
pass
else:
raise
finally:
self.login(user)
def test_person_request_new_certificate(self):
"""Checks that Person is capable to ask for new certificate"""
self.login()
self.portal.portal_certificate_authority._checkCertificateAuthority()
person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue(
'test_vifib_user_admin')
self._safe_revoke_certificate(person)
self.login('test_vifib_user_admin')
certificate = person.getCertificate()
self.assertTrue('CN=test_vifib_user_admin' in certificate['certificate'])
def test_person_request_revoke_certificate(self):
"""Chekcs that Person is capable to ask for revocation of certificate"""
self.login()
self.portal.portal_certificate_authority._checkCertificateAuthority()
person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue(
'test_vifib_user_admin')
self._safe_revoke_certificate(person)
self.login('test_vifib_user_admin')
certificate = person.getCertificate()
self.assertTrue('CN=test_vifib_user_admin' in certificate['certificate'])
person.revokeCertificate()
def test_person_request_new_certificate_twice(self):
"""Checks that if Person asks twice for a certificate the next call
fails"""
self.login()
self.portal.portal_certificate_authority._checkCertificateAuthority()
person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue(
'test_vifib_user_admin')
self._safe_revoke_certificate(person)
self.login('test_vifib_user_admin')
certificate = person.getCertificate()
self.assertTrue('CN=test_vifib_user_admin' in certificate['certificate'])
self.assertRaises(ValueError, person.getCertificate)
def test_person_request_certificate_for_another_person(self):
"""Checks that if Person tries to request ceritifcate for someone else it
will fail"""
from AccessControl import Unauthorized
self.login()
self.portal.portal_certificate_authority._checkCertificateAuthority()
person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue(
'test_vifib_user_admin')
self._safe_revoke_certificate(person)
self.login('test_hr_admin')
self.assertRaises(Unauthorized, person.getCertificate)
def test_person_request_revoke_certificate_for_another_person(self):
"""Checks that if Person tries to request ceritifcate for someone else it
will fail"""
from AccessControl import Unauthorized
self.login()
self.portal.portal_certificate_authority._checkCertificateAuthority()
person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue(
'test_vifib_user_admin')
self._safe_revoke_certificate(person)
self.login('test_vifib_user_admin')
certificate = person.getCertificate()
self.assertTrue('CN=test_vifib_user_admin' in certificate['certificate'])
self.login('test_hr_admin')
self.assertRaises(Unauthorized, person.revokeCertificate)
def stepPersonRequestSlapSoftwareInstanceNotFoundResponse(self, sequence,
**kw):
software_release = sequence['software_release_uri']
self.slap = slap.slap()
self.slap.initializeConnection(self.server_url)
open_order = self.slap.registerOpenOrder()
self.assertRaises(slap.NotFoundError, open_order.request,
software_release=software_release,
software_type=sequence.get('software_type', 'software_type'),
partition_reference=sequence.get('requested_reference',
'requested_reference'),
partition_parameter_kw=sequence.get('requested_parameter_dict', {}),
filter_kw=sequence.get('requested_filter_dict', {})
)
def stepPersonRequestSlapSoftwareInstanceNotReadyResponse(self, sequence,
**kw):
software_release = sequence['software_release_uri']
self.slap = slap.slap()
self.slap.initializeConnection(self.server_url)
open_order = self.slap.registerOpenOrder()
self.assertRaises(slap.ResourceNotReady, open_order.request,
software_release=software_release,
software_type=sequence.get('software_type', 'software_type'),
partition_reference=sequence.get('requested_reference',
'requested_reference'),
partition_parameter_kw=sequence.get('requested_parameter_dict', {}),
filter_kw=sequence.get('requested_filter_dict', {})
)
def stepSetRandomRequestedReference(self, sequence, **kw):
sequence['requested_reference'] = self.id() + str(random())
def stepSetCurrentPersonSlapRequestedSoftwareInstance(self, sequence, **kw):
software_instance_list = self.portal.portal_catalog(
portal_type=self.software_instance_portal_type,
title=sequence['requested_reference'])
self.assertEqual(1, len(software_instance_list))
software_instance = software_instance_list[0]
sequence.edit(
software_instance_uid=software_instance.getUid(),
software_instance_reference=software_instance.getReference(),
hosting_subscription_uid=software_instance.getAggregateRelatedValue(
portal_type='Sale Order Line').getAggregateValue(
portal_type='Hosting Subscription').getUid())
def stepPersonRequestSlapSoftwareInstance(self, sequence, **kw):
software_release = sequence['software_release_uri']
self.slap = slap.slap()
self.slap.initializeConnection(self.server_url)
open_order = self.slap.registerOpenOrder()
requested_slap_computer_partition = open_order.request(
software_release=software_release,
software_type=sequence.get('software_type', 'software_type'),
partition_reference=sequence['requested_reference'],
partition_parameter_kw=sequence.get('requested_parameter_dict', {}),
filter_kw=sequence.get('requested_filter_dict', {}))
sequence.edit(
requested_slap_computer_partition=requested_slap_computer_partition,
requested_computer_partition_reference=\
requested_slap_computer_partition.getId())
def test_person_request_ComputerPartition(self):
"""Checks that Person using Slap interface is able to request Computer
Partition"""
self.computer_partition_amount = 1
sequence_list = SequenceList()
sequence_string = self.prepare_published_software_release + \
self.prepare_formated_computer + """
LoginTestVifibAdmin
RequestSoftwareInstallation
Tic
Logout
SlapLoginCurrentComputer
ComputerSoftwareReleaseAvailable
Tic
SlapLogout
SetRandomRequestedReference
SlapLoginTestVifibCustomer
PersonRequestSlapSoftwareInstanceNotReadyResponse
Tic
SlapLogout
SlapLoginTestVifibCustomer
PersonRequestSlapSoftwareInstanceNotReadyResponse
Tic
SlapLogout
LoginDefaultUser
ConfirmOrderedSaleOrderActiveSense
Tic
Logout
SlapLoginTestVifibCustomer
PersonRequestSlapSoftwareInstance
Tic
SlapLogout
LoginDefaultUser
SetCurrentPersonSlapRequestedSoftwareInstance
CheckPersonRequestedSoftwareInstanceAndRelatedComputerPartition
Logout
SlapLoginCurrentSoftwareInstance
CheckRequestedComputerPartitionCleanParameterList
SlapLogout
LoginTestVifibCustomer
CheckViewCurrentSoftwareInstance
CheckWriteCurrentSoftwareInstance
Tic
Logout
"""
sequence_list.addSequenceString(sequence_string)
sequence_list.play(self)
def stepSoftwareInstanceSaleOrderConfirmRaisesValueError(self, sequence,
**kw):
"""Checks that current software instance is realted only with sale order
and that this sale order cannot be confirmed
In Vifib implementation sale order which cannot find free computer partition
raises ValueError"""
software_instance = self.portal.portal_catalog.getResultValue(
uid=sequence['software_instance_uid'])
aggregate_value_list = software_instance.getAggregateRelatedValueList(portal_type=[self.sale_packing_list_line_portal_type, self.sale_order_line_portal_type])
self.assertEqual(1, len(aggregate_value_list))
self.assertTrue(self.sale_order_line_portal_type in [q.getPortalType() for\
q in aggregate_value_list])
sale_order_line = aggregate_value_list[0]
sale_order = sale_order_line.getParentValue()
self.assertRaises(ValueError, sale_order.confirm)
def test_person_request_ComputerPartition_filter_computer_guid(self):
"""Check that requesting with computer_guid in filter_kw works as
expected in case of person request"""
self.computer_partition_amount = 1
sequence_list = SequenceList()
# There is only one partition on each computer, which has installed
# software release. But as request has sla parameter, the partition
# on another computer is not selected, as not following SLA.
sequence_string = self.prepare_published_software_release + \
self.prepare_formated_computer + """
LoginTestVifibAdmin
RequestSoftwareInstallation
Tic
Logout
SlapLoginCurrentComputer
ComputerSoftwareReleaseAvailable
Tic
SlapLogout
""" + \
self.prepare_another_computer_sequence_string + """
LoginTestVifibAdmin
RequestSoftwareInstallation
Tic
Logout
SetRandomRequestedReference
SlapLoginTestVifibCustomer
PersonRequestSlapSoftwareInstanceNotReadyResponse
Tic
SlapLogout
SlapLoginTestVifibCustomer
PersonRequestSlapSoftwareInstanceNotReadyResponse
Tic
SlapLogout
LoginDefaultUser
ConfirmOrderedSaleOrderActiveSense
Tic
Logout
SlapLoginTestVifibCustomer
PersonRequestSlapSoftwareInstance
Tic
SlapLogout
LoginDefaultUser
SetCurrentPersonSlapRequestedSoftwareInstance
CheckPersonRequestedSoftwareInstanceAndRelatedComputerPartition
Logout
SelectYetAnotherRequestedReference
SlapLoginTestVifibCustomer
PersonRequestSlapSoftwareInstanceNotReadyResponse
Tic
SlapLogout
LoginDefaultUser
SetCurrentPersonSlapRequestedSoftwareInstance
SoftwareInstanceSaleOrderConfirmRaisesValueError
Logout
"""
sequence_list.addSequenceString(sequence_string)
sequence_list.play(self)
######################################## ########################################
# Bug related tests # Bug related tests
######################################## ########################################
...@@ -6913,6 +7310,59 @@ class TestVifibSlapWebService(testVifibMixin): ...@@ -6913,6 +7310,59 @@ class TestVifibSlapWebService(testVifibMixin):
sequence_list.addSequenceString(sequence_string) sequence_list.addSequenceString(sequence_string)
sequence_list.play(self) sequence_list.play(self)
def test_bug_doubleClickOnStart(self):
sequence_list = SequenceList()
sequence_string = self\
.prepare_stopped_computer_partition_sequence_string + """
LoginTestVifibCustomer
RequestSoftwareInstanceStart
RequestSoftwareInstanceStartRaisesValueError
Tic
Logout
LoginDefaultUser
CheckComputerPartitionInstanceHostingSalePackingListConfirmed
Logout
"""
sequence_list.addSequenceString(sequence_string)
sequence_list.play(self)
def test_bug_doubleClickOnStart_serializeIsCalled(self):
sequence_list = SequenceList()
sequence_string = self\
.prepare_stopped_computer_partition_sequence_string + """
LoginTestVifibCustomer
RequestSoftwareInstanceStartCheckSerializeIsCalled
"""
sequence_list.addSequenceString(sequence_string)
sequence_list.play(self)
def test_bug_doubleClickOnDestroy(self):
sequence_list = SequenceList()
sequence_string = self\
.prepare_installed_computer_partition_sequence_string + """
LoginTestVifibCustomer
RequestSoftwareInstanceDestroy
RequestSoftwareInstanceDestroyRaisesValueError
Tic
Logout
LoginDefaultUser
CheckComputerPartitionInstanceCleanupSalePackingListConfirmed
Logout
"""
sequence_list.addSequenceString(sequence_string)
sequence_list.play(self)
def test_bug_doubleClickOnDestroy_serializeIsCalled(self):
sequence_list = SequenceList()
sequence_string = self\
.prepare_installed_computer_partition_sequence_string + """
LoginTestVifibCustomer
RequestSoftwareInstanceDestroyCheckSerializeIsCalled
"""
sequence_list.addSequenceString(sequence_string)
sequence_list.play(self)
# class IComputerPartition # class IComputerPartition
# def started(): # def started():
......
...@@ -2,7 +2,7 @@ from setuptools import setup, find_packages ...@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
import glob import glob
import os import os
version = '0.3-dev' version = '0.4-dev'
name = 'slapos.core' name = 'slapos.core'
long_description = open("README.txt").read() + "\n" + \ long_description = open("README.txt").read() + "\n" + \
open("CHANGES.txt").read() + "\n" open("CHANGES.txt").read() + "\n"
...@@ -33,7 +33,7 @@ setup(name=name, ...@@ -33,7 +33,7 @@ setup(name=name,
install_requires=[ install_requires=[
'Flask', # used by proxy 'Flask', # used by proxy
'lxml', # needed to play with XML trees 'lxml', # needed to play with XML trees
'netaddr', # to play safely with IPv6 prefixes 'netaddr>=0.7.5', # to play safely with IPv6 prefixes
'netifaces', # to fetch information about network devices 'netifaces', # to fetch information about network devices
'setuptools', # namespaces 'setuptools', # namespaces
'supervisor', # slapgrid uses supervisor to manage processes 'supervisor', # slapgrid uses supervisor to manage processes
......
...@@ -18,4 +18,5 @@ ipv4_local_network = 10.0.0.0/16 ...@@ -18,4 +18,5 @@ ipv4_local_network = 10.0.0.0/16
[slapproxy] [slapproxy]
host = 127.0.0.1 host = 127.0.0.1
port = 5000 port = 5000
database_uri = :memory: # or /path/to/file # You could also specify: /path/to/file
database_uri = :memory:
libnetworkcache
===============
The goal of libnetworkcache python library is to abstract the REST calls.
It works as wrapper of python httplib to use the Networkcache HTTP Server.
API
---
So, it must provide 2 methods:
put(file)
''' Upload the file to Networkcache HTTP Server using PUT as HTTP method.'''
get(key)
''' Download the file from Networkcache HTTP Server using GET as HTTP method.'''
...@@ -27,13 +27,13 @@ ...@@ -27,13 +27,13 @@
############################################################################## ##############################################################################
from optparse import OptionParser, Option from optparse import OptionParser, Option
from xml_marshaller import xml_marshaller from xml_marshaller import xml_marshaller
from pwd import getpwnam
import ConfigParser import ConfigParser
import grp import grp
import logging import logging
import netaddr import netaddr
import netifaces import netifaces
import os import os
import pwd
import random import random
import slapos.slap as slap import slapos.slap as slap
import socket import socket
...@@ -41,6 +41,34 @@ import subprocess ...@@ -41,6 +41,34 @@ import subprocess
import sys import sys
import time import time
class OS(object):
_os = os
def __init__(self, config):
self._dry_run = config.dry_run
self._verbose = config.verbose
self._logger = config.logger
add = self._addWrapper
add('chown')
add('chmod')
add('makedirs')
add('mkdir')
def _addWrapper(self, name):
def wrapper(*args, **kw):
if self._verbose:
arg_list = [repr(x) for x in args] + [
'%s=%r' % (x, y) for x, y in kw.iteritems()]
self._logger.debug('%s(%s)' % (
name,
', '.join(arg_list)
))
if not self._dry_run:
getattr(self._os, name)(*args, **kw)
setattr(self, name, wrapper)
def __getattr__(self, name):
return getattr(self._os, name)
class SlapError(Exception): class SlapError(Exception):
""" """
...@@ -195,6 +223,8 @@ class Computer: ...@@ -195,6 +223,8 @@ class Computer:
slap_instance.initializeConnection(config.master_url, slap_instance.initializeConnection(config.master_url,
**connection_dict) **connection_dict)
slap_computer = slap_instance.registerComputer(self.reference) slap_computer = slap_instance.registerComputer(self.reference)
if config.dry_run:
return
return slap_computer.updateConfiguration( return slap_computer.updateConfiguration(
xml_marshaller.dumps(_getDict(self))) xml_marshaller.dumps(_getDict(self)))
...@@ -280,7 +310,7 @@ class Computer: ...@@ -280,7 +310,7 @@ class Computer:
slapsoft.path = self.software_root slapsoft.path = self.software_root
if alter_user: if alter_user:
slapsoft.create() slapsoft.create()
slapsoft_pw = pwd.getpwnam(slapsoft.name) slapsoft_pw = getpwnam(slapsoft.name)
os.chown(self.software_root, slapsoft_pw.pw_uid, slapsoft_pw.pw_gid) os.chown(self.software_root, slapsoft_pw.pw_uid, slapsoft_pw.pw_gid)
os.chmod(self.software_root, 0755) os.chmod(self.software_root, 0755)
...@@ -365,7 +395,7 @@ class Partition: ...@@ -365,7 +395,7 @@ class Partition:
if not os.path.exists(self.path): if not os.path.exists(self.path):
os.mkdir(self.path, 0750) os.mkdir(self.path, 0750)
if alter_user: if alter_user:
owner_pw = pwd.getpwnam(owner.name) owner_pw = getpwnam(owner.name)
os.chown(self.path, owner_pw.pw_uid, owner_pw.pw_gid) os.chown(self.path, owner_pw.pw_uid, owner_pw.pw_gid)
os.chmod(self.path, 0750) os.chmod(self.path, 0750)
...@@ -402,12 +432,12 @@ class User: ...@@ -402,12 +432,12 @@ class User:
except KeyError: except KeyError:
callAndRead(['groupadd', self.name]) callAndRead(['groupadd', self.name])
user_parameter_list = ['-d', self.path, '-g', self.name] user_parameter_list = ['-d', self.path, '-g', self.name, '-s', '/bin/false']
if self.additional_group_list is not None: if self.additional_group_list is not None:
user_parameter_list.extend(['-G', ','.join(self.additional_group_list)]) user_parameter_list.extend(['-G', ','.join(self.additional_group_list)])
user_parameter_list.append(self.name) user_parameter_list.append(self.name)
try: try:
pwd.getpwnam(self.name) getpwnam(self.name)
except KeyError: except KeyError:
callAndRead(['useradd'] + user_parameter_list) callAndRead(['useradd'] + user_parameter_list)
else: else:
...@@ -425,7 +455,7 @@ class User: ...@@ -425,7 +455,7 @@ class User:
""" """
try: try:
pwd.getpwnam(self.name) getpwnam(self.name)
return True return True
except KeyError: except KeyError:
...@@ -463,7 +493,7 @@ class Tap: ...@@ -463,7 +493,7 @@ class Tap:
owner_id = int(open(check_file).read().strip()) owner_id = int(open(check_file).read().strip())
except Exception: except Exception:
pass pass
if (owner_id is None) or (owner_id != pwd.getpwnam(owner.name).pw_uid): if (owner_id is None) or (owner_id != getpwnam(owner.name).pw_uid):
callAndRead(['tunctl', '-t', self.name, '-u', owner.name]) callAndRead(['tunctl', '-t', self.name, '-u', owner.name])
callAndRead(['ip', 'link', 'set', self.name, 'up']) callAndRead(['ip', 'link', 'set', self.name, 'up'])
...@@ -707,6 +737,10 @@ class Parser(OptionParser): ...@@ -707,6 +737,10 @@ class Parser(OptionParser):
help="Shall slapformat alter user database [default: True]"), help="Shall slapformat alter user database [default: True]"),
Option('--alter_network', choices=['True', 'False'], Option('--alter_network', choices=['True', 'False'],
help="Shall slapformat alter network configuration [default: True]"), help="Shall slapformat alter network configuration [default: True]"),
Option("-d", "--dry-run",
default=False,
action="store_true",
help="Don't actually do anything."),
]) ])
def check_args(self): def check_args(self):
...@@ -831,6 +865,7 @@ def run(config): ...@@ -831,6 +865,7 @@ def run(config):
alter_network=config.alter_network) alter_network=config.alter_network)
# Dumping and sending to the erp5 the current configuration # Dumping and sending to the erp5 the current configuration
if not config.dry_run:
computer.dump(config.computer_xml) computer.dump(config.computer_xml)
config.logger.info('Posting information to %r' % config.master_url) config.logger.info('Posting information to %r' % config.master_url)
computer.send(config) computer.send(config)
...@@ -904,11 +939,17 @@ class Config: ...@@ -904,11 +939,17 @@ class Config:
self.logger.error(message) self.logger.error(message)
raise UsageError(message) raise UsageError(message)
if not self.dry_run:
if self.alter_user: if self.alter_user:
self.checkRequiredBinary(['groupadd', 'useradd', 'usermod']) self.checkRequiredBinary(['groupadd', 'useradd', 'usermod'])
if self.alter_network: if self.alter_network:
self.checkRequiredBinary(['brctl', 'ip', 'tunctl']) self.checkRequiredBinary(['ip', 'tunctl'])
# Required, even for dry run
if self.alter_network:
self.checkRequiredBinary(['brctl'])
if self.dry_run:
root_needed = False
# check root # check root
if root_needed and os.getuid() != 0: if root_needed and os.getuid() != 0:
...@@ -937,6 +978,8 @@ class Config: ...@@ -937,6 +978,8 @@ class Config:
if self.verbose: if self.verbose:
self.logger.setLevel(logging.DEBUG) self.logger.setLevel(logging.DEBUG)
self.logger.debug("Verbose mode enabled.") self.logger.debug("Verbose mode enabled.")
if self.dry_run:
self.logger.info("Dry-run mode enabled.")
# Calculate path once # Calculate path once
self.computer_xml = os.path.abspath(self.computer_xml) self.computer_xml = os.path.abspath(self.computer_xml)
...@@ -944,6 +987,10 @@ class Config: ...@@ -944,6 +987,10 @@ class Config:
def main(): def main():
"Run default configuration." "Run default configuration."
global os
global callAndRead
global getpwnam
real_callAndRead = callAndRead
usage = "usage: %s [options] CONFIGURATION_FILE" % sys.argv[0] usage = "usage: %s [options] CONFIGURATION_FILE" % sys.argv[0]
try: try:
...@@ -951,6 +998,33 @@ def main(): ...@@ -951,6 +998,33 @@ def main():
options, configuration_file_path = Parser(usage=usage).check_args() options, configuration_file_path = Parser(usage=usage).check_args()
config = Config() config = Config()
config.setConfig(options, configuration_file_path) config.setConfig(options, configuration_file_path)
os = OS(config)
if config.dry_run:
def dry_callAndRead(argument_list, raise_on_error=True):
if argument_list == ['brctl', 'show']:
return real_callAndRead(argument_list, raise_on_error)
else:
return 0, ''
callAndRead = dry_callAndRead
real_addSystemAddress = Bridge._addSystemAddress
def fake_addSystemAddress(*args, **kw):
real_addSystemAddress(*args, **kw)
# Fake success
return True
Bridge._addSystemAddress = fake_addSystemAddress
def fake_getpwnam(user):
class result:
pw_uid = 12345
pw_gid = 54321
return result
getpwnam = fake_getpwnam
else:
dry_callAndRead = real_callAndRead
if config.verbose:
def logging_callAndRead(argument_list, raise_on_error=True):
config.logger.debug(' '.join(argument_list))
return dry_callAndRead(argument_list, raise_on_error)
callAndRead = logging_callAndRead
run(config) run(config)
except UsageError, err: except UsageError, err:
print >>sys.stderr, err.msg print >>sys.stderr, err.msg
......
##############################################################################
#
# Copyright (c) 2010 ViFiB SARL and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
import httplib
import os
class NetworkcacheClient(object):
'''
NetworkcacheClient is a wrapper for httplib.
It must implement all the required methods to use the Networkcache HTTP
Server.
- put(file)
- get(key)
'''
def __init__(self, networkcache_url):
# XXX (lucas): Is it required to check if networkcache_url is a valid URL?
self.networkcache_url = networkcache_url
def _start(self):
self.connection = httplib.HTTPConnection(self.networkcache_url)
def _close(self):
self.connection.close()
def put(self, file_content):
'''
Upload the file to the server.
It uses http PUT resquest method.
'''
if file_content is not None:
raise ValueError('File content should not be None.')
self._start()
try:
self.connection.request('PUT', '/', file_content)
result = self.connection.getresponse()
finally:
self._close()
return result
def get(self, key):
'''
Download the file.
It uses http GET request method.
'''
path_info = '/%s' % key
self._start()
try:
self.connection.request('GET', path_info)
result = self.connection.getresponse()
finally:
self._close()
return result
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment