Commit 6623f7e3 authored by Rafael Monnerat's avatar Rafael Monnerat

slapos_cloud: Refactor SlapTool&Mixins to drop internal slap lib usage

   The internal API only store dict, rather them store xml.

   slapos.slap.slap is only used on SlapTool context, releasing the
internal API on having it.

   The approach is deprecate the usage of it as soon clients relies on
  a different API.
parent 1ac3ec59
...@@ -31,31 +31,18 @@ from erp5.component.document.Item import Item ...@@ -31,31 +31,18 @@ from erp5.component.document.Item import Item
from lxml import etree from lxml import etree
import collections import collections
from AccessControl import Unauthorized
from AccessControl.Permissions import access_contents_information
from AccessControl import getSecurityManager
from Products.ERP5Type.UnrestrictedMethod import UnrestrictedMethod from Products.ERP5Type.UnrestrictedMethod import UnrestrictedMethod
from erp5.component.module.SlapOSCloud import _assertACI
from zLOG import LOG, INFO from zLOG import LOG, INFO
try: try:
from slapos.slap.slap import \
SoftwareInstance as SlapSoftwareInstance
from slapos.util import xml2dict, loads from slapos.util import xml2dict, loads
except ImportError: except ImportError:
def xml2dict(dictionary): def xml2dict(dictionary):
raise ImportError raise ImportError
def loads(*args): def loads(*args):
raise ImportError raise ImportError
class SlapSoftwareInstance:
def __init__(self):
raise ImportError
def _assertACI(document):
sm = getSecurityManager()
if sm.checkPermission(access_contents_information,
document):
return document
raise Unauthorized('User %r has no access to %r' % (sm.getUser(), document))
class DisconnectedSoftwareTree(Exception): class DisconnectedSoftwareTree(Exception):
pass pass
...@@ -160,7 +147,7 @@ class SoftwareInstance(Item): ...@@ -160,7 +147,7 @@ class SoftwareInstance(Item):
LOG('SoftwareInstance', INFO, 'Issue during parsing xml:', error=True) LOG('SoftwareInstance', INFO, 'Issue during parsing xml:', error=True)
return result_dict return result_dict
def _asSoftwareInstance(self): def _asSoftwareInstanceDict(self):
parameter_dict = self._asParameterDict() parameter_dict = self._asParameterDict()
requested_state = self.getSlapState() requested_state = self.getSlapState()
...@@ -182,13 +169,13 @@ class SoftwareInstance(Item): ...@@ -182,13 +169,13 @@ class SoftwareInstance(Item):
parameter_dict.pop('filter_xml')) parameter_dict.pop('filter_xml'))
instance_guid = parameter_dict.pop('instance_guid') instance_guid = parameter_dict.pop('instance_guid')
software_instance = SlapSoftwareInstance(**parameter_dict) software_instance_dict = parameter_dict
software_instance._parameter_dict = xml software_instance_dict['_parameter_dict'] = xml
software_instance._connection_dict = connection_xml software_instance_dict['_connection_dict'] = connection_xml
software_instance._filter_dict = filter_xml software_instance_dict['_filter_dict'] = filter_xml
software_instance._requested_state = state software_instance_dict['_requested_state'] = state
software_instance._instance_guid = instance_guid software_instance_dict['_instance_guid'] = instance_guid
return software_instance return software_instance_dict
@UnrestrictedMethod @UnrestrictedMethod
def _asParameterDict(self, shared_instance_sql_list=None): def _asParameterDict(self, shared_instance_sql_list=None):
......
...@@ -6,12 +6,6 @@ ...@@ -6,12 +6,6 @@
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
<item>
<key> <string>_recorded_property_dict</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item> <item>
<key> <string>default_reference</string> </key> <key> <string>default_reference</string> </key>
<value> <string>SoftwareInstance</string> </value> <value> <string>SoftwareInstance</string> </value>
...@@ -55,28 +49,13 @@ ...@@ -55,28 +49,13 @@
<item> <item>
<key> <string>workflow_history</string> </key> <key> <string>workflow_history</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="2" aka="AAAAAAAAAAI="> <record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle> <pickle>
<global name="PersistentMapping" module="Persistence.mapping"/> <global name="PersistentMapping" module="Persistence.mapping"/>
</pickle> </pickle>
...@@ -89,7 +68,7 @@ ...@@ -89,7 +68,7 @@
<item> <item>
<key> <string>component_validation_workflow</string> </key> <key> <string>component_validation_workflow</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value> </value>
</item> </item>
</dictionary> </dictionary>
...@@ -98,7 +77,7 @@ ...@@ -98,7 +77,7 @@
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="4" aka="AAAAAAAAAAQ="> <record id="3" aka="AAAAAAAAAAM=">
<pickle> <pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/> <global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle> </pickle>
......
...@@ -28,46 +28,22 @@ ...@@ -28,46 +28,22 @@
from Products.ERP5Type.Cache import DEFAULT_CACHE_SCOPE from Products.ERP5Type.Cache import DEFAULT_CACHE_SCOPE
from AccessControl import Unauthorized from AccessControl import Unauthorized
from AccessControl.Permissions import access_contents_information
from AccessControl import getSecurityManager
from Products.ERP5Type.UnrestrictedMethod import UnrestrictedMethod from Products.ERP5Type.UnrestrictedMethod import UnrestrictedMethod
from Products.ERP5Type.tests.utils import DummyMailHostMixin from Products.ERP5Type.tests.utils import DummyMailHostMixin
from OFS.Traversable import NotFound from OFS.Traversable import NotFound
from erp5.component.module.SlapOSCloud import _assertACI
import time import time
from lxml import etree from lxml import etree
from zLOG import LOG, INFO from zLOG import LOG, INFO
try: try:
from slapos.slap.slap import ( from slapos.util import xml2dict
Computer as ComputeNode,
ComputerPartition as SlapComputePartition,
SoftwareRelease)
from slapos.util import xml2dict, dumps
except ImportError: except ImportError:
# Do no prevent instance from starting # Do no prevent instance from starting
# if libs are not installed # if libs are not installed
class ComputeNode:
def __init__(self):
raise ImportError
class SlapComputePartition:
def __init__(self):
raise ImportError
class SoftwareRelease:
def __init__(self):
raise ImportError
def xml2dict(dictionary): def xml2dict(dictionary):
raise ImportError raise ImportError
def dumps(*args):
raise ImportError
def _assertACI(document):
sm = getSecurityManager()
if sm.checkPermission(access_contents_information,
document):
return document
raise Unauthorized('User %r has no access to %r' % (sm.getUser(), document))
class SlapOSComputeNodeMixin(object): class SlapOSComputeNodeMixin(object):
...@@ -87,42 +63,42 @@ class SlapOSComputeNodeMixin(object): ...@@ -87,42 +63,42 @@ class SlapOSComputeNodeMixin(object):
validation_state='validated', validation_state='validated',
): ):
software_installation = _assertACI(software_installation.getObject()) software_installation = _assertACI(software_installation.getObject())
software_release_response = SoftwareRelease( software_release_dict = {
software_release=software_installation.getUrlString().decode('UTF-8'), "software_release": software_installation.getUrlString().decode('UTF-8'),
computer_guid=self.getReference().decode('UTF-8')) "computer_guid": self.getReference().decode('UTF-8')
}
if software_installation.getSlapState() == 'destroy_requested': if software_installation.getSlapState() == 'destroy_requested':
software_release_response._requested_state = 'destroyed' software_release_dict["_requested_state"] = 'destroyed'
else: else:
software_release_response._requested_state = 'available' software_release_dict["_requested_state"] = 'available'
known_state = software_installation.getTextAccessStatus() known_state = software_installation.getTextAccessStatus()
if known_state.startswith("#access"): if known_state.startswith("#access"):
software_release_response._known_state = 'available' software_release_dict["_known_state"] = 'available'
elif known_state.startswith("#building"): elif known_state.startswith("#building"):
software_release_response._known_state = 'building' software_release_dict["_known_state"] = 'building'
else: else:
software_release_response._known_state = 'error' software_release_dict["_known_state"] = 'error'
software_release_list.append(software_release_response) software_release_list.append(software_release_dict)
return software_release_list return software_release_list
def _getCacheComputeNodeInformation(self, user): def _getCacheComputeNodeInformation(self, user):
self.REQUEST.response.setHeader('Content-Type', 'text/xml; charset=utf-8') compute_node_dict = {
slap_compute_node = ComputeNode(self.getReference().decode("UTF-8")) "_computer_id": self.getReference().decode("UTF-8"),
"_computer_partition_list": [],
slap_compute_node._computer_partition_list = [] "_software_release_list": self._getSoftwareReleaseValueList()
slap_compute_node._software_release_list = self._getSoftwareReleaseValueList() }
unrestrictedSearchResults = self.getPortalObject().portal_catalog.unrestrictedSearchResults unrestrictedSearchResults = self.getPortalObject().portal_catalog.unrestrictedSearchResults
compute_partition_list = unrestrictedSearchResults( compute_partition_list = unrestrictedSearchResults(
parent_uid=self.getUid(), parent_uid=self.getUid(),
validation_state="validated", validation_state="validated",
portal_type="Compute Partition" portal_type="Compute Partition"
) )
self._calculateSlapComputeNodeInformation(slap_compute_node, compute_partition_list) self._calculateSlapComputeNodeInformation(compute_node_dict, compute_partition_list)
return dumps(slap_compute_node) return compute_node_dict
def _activateFillComputeNodeInformationCache(self, user): def _activateFillComputeNodeInformationCache(self, user):
tag = 'compute_node_information_cache_fill_%s_%s' % (self.getReference(), user) tag = 'compute_node_information_cache_fill_%s_%s' % (self.getReference(), user)
...@@ -180,9 +156,6 @@ class SlapOSComputeNodeMixin(object): ...@@ -180,9 +156,6 @@ class SlapOSComputeNodeMixin(object):
user_type = user_document.getPortalType() user_type = user_document.getPortalType()
self.REQUEST.response.setHeader('Content-Type', 'text/xml; charset=utf-8') self.REQUEST.response.setHeader('Content-Type', 'text/xml; charset=utf-8')
slap_compute_node = ComputeNode(self.getReference().decode("UTF-8"))
slap_compute_node._computer_partition_list = []
if user_type in ('Compute Node', 'Person'): if user_type in ('Compute Node', 'Person'):
if not self._isTestRun(): if not self._isTestRun():
cache_plugin = self._getCachePlugin() cache_plugin = self._getCachePlugin()
...@@ -207,7 +180,11 @@ class SlapOSComputeNodeMixin(object): ...@@ -207,7 +180,11 @@ class SlapOSComputeNodeMixin(object):
else: else:
return self._getCacheComputeNodeInformation(user), None return self._getCacheComputeNodeInformation(user), None
else: else:
slap_compute_node._software_release_list = [] compute_node_dict = {
"_computer_id": self.getReference().decode("UTF-8"),
"_computer_partition_list": [],
"_software_release_list": []
}
if user_type == 'Software Instance': if user_type == 'Software Instance':
compute_partition_list = self.contentValues( compute_partition_list = self.contentValues(
...@@ -219,10 +196,10 @@ class SlapOSComputeNodeMixin(object): ...@@ -219,10 +196,10 @@ class SlapOSComputeNodeMixin(object):
validation_state="validated", validation_state="validated",
portal_type="Compute Partition") portal_type="Compute Partition")
self._calculateSlapComputeNodeInformation(slap_compute_node, compute_partition_list) self._calculateSlapComputeNodeInformation(compute_node_dict, compute_partition_list)
return dumps(slap_compute_node), None return compute_node_dict, None
def _calculateSlapComputeNodeInformation(self, slap_compute_node, compute_partition_list): def _calculateSlapComputeNodeInformation(self, compute_node_dict, compute_partition_list):
if len(compute_partition_list) == 0: if len(compute_partition_list) == 0:
return return
...@@ -248,7 +225,7 @@ class SlapOSComputeNodeMixin(object): ...@@ -248,7 +225,7 @@ class SlapOSComputeNodeMixin(object):
software_instance_list = [x for x in grouped_software_instance_list if (x.default_aggregate_uid == compute_partition.getUid())] software_instance_list = [x for x in grouped_software_instance_list if (x.default_aggregate_uid == compute_partition.getUid())]
if (len(software_instance_list) == 1) and (software_instance_list[0]['count(*)'] > 1): if (len(software_instance_list) == 1) and (software_instance_list[0]['count(*)'] > 1):
software_instance_list = software_instance_list + software_instance_list software_instance_list = software_instance_list + software_instance_list
slap_compute_node._computer_partition_list.append( compute_node_dict['_computer_partition_list'].append(
self._getSlapPartitionByPackingList( self._getSlapPartitionByPackingList(
_assertACI(compute_partition.getObject()), _assertACI(compute_partition.getObject()),
software_instance_list, software_instance_list,
...@@ -273,12 +250,13 @@ class SlapOSComputeNodeMixin(object): ...@@ -273,12 +250,13 @@ class SlapOSComputeNodeMixin(object):
while compute_node.getPortalType() != 'Compute Node': while compute_node.getPortalType() != 'Compute Node':
compute_node = compute_node.getParentValue() compute_node = compute_node.getParentValue()
compute_node_id = compute_node.getReference().decode("UTF-8") compute_node_id = compute_node.getReference().decode("UTF-8")
slap_partition = SlapComputePartition(compute_node_id, partition_dict = {
compute_partition_document.getReference().decode("UTF-8")) "compute_node_id": compute_node_id,
"partition_id": compute_partition_document.getReference().decode("UTF-8"),
slap_partition._software_release_document = None "_software_release_document": None,
slap_partition._requested_state = 'destroyed' "_requested_state": 'destroyed',
slap_partition._need_modification = 0 "_need_modification": 0
}
software_instance = None software_instance = None
...@@ -294,28 +272,29 @@ class SlapOSComputeNodeMixin(object): ...@@ -294,28 +272,29 @@ class SlapOSComputeNodeMixin(object):
if software_instance is not None: if software_instance is not None:
state = software_instance.getSlapState() state = software_instance.getSlapState()
if state == "stop_requested": if state == "stop_requested":
slap_partition._requested_state = 'stopped' partition_dict['_requested_state'] = 'stopped'
if state == "start_requested": if state == "start_requested":
slap_partition._requested_state = 'started' partition_dict['_requested_state'] = 'started'
slap_partition._access_status = software_instance.getTextAccessStatus() partition_dict['_access_status'] = software_instance.getTextAccessStatus()
slap_partition._software_release_document = SoftwareRelease( partition_dict['_software_release_document'] = {
software_release=software_instance.getUrlString().decode("UTF-8"), "software_release": software_instance.getUrlString().decode("UTF-8"),
computer_guid=compute_node_id) "computer_guid": compute_node_id
}
slap_partition._need_modification = 1 partition_dict["_need_modification"] = 1
parameter_dict = software_instance._asParameterDict( parameter_dict = software_instance._asParameterDict(
shared_instance_sql_list=shared_instance_sql_list shared_instance_sql_list=shared_instance_sql_list
) )
# software instance has to define an xml parameter # software instance has to define an xml parameter
slap_partition._parameter_dict = self._instanceXmlToDict( partition_dict["_parameter_dict"] = self._instanceXmlToDict(
parameter_dict.pop('xml')) parameter_dict.pop('xml'))
slap_partition._connection_dict = self._instanceXmlToDict( partition_dict['_connection_dict'] = self._instanceXmlToDict(
parameter_dict.pop('connection_xml')) parameter_dict.pop('connection_xml'))
slap_partition._filter_dict = self._instanceXmlToDict( partition_dict['_filter_dict'] = self._instanceXmlToDict(
parameter_dict.pop('filter_xml')) parameter_dict.pop('filter_xml'))
slap_partition._instance_guid = parameter_dict.pop('instance_guid') partition_dict['_instance_guid'] = parameter_dict.pop('instance_guid')
for slave_instance_dict in parameter_dict.get("slave_instance_list", []): for slave_instance_dict in parameter_dict.get("slave_instance_list", []):
if slave_instance_dict.has_key("connection_xml"): if slave_instance_dict.has_key("connection_xml"):
slave_instance_dict.update(self._instanceXmlToDict( slave_instance_dict.update(self._instanceXmlToDict(
...@@ -323,9 +302,9 @@ class SlapOSComputeNodeMixin(object): ...@@ -323,9 +302,9 @@ class SlapOSComputeNodeMixin(object):
if slave_instance_dict.has_key("xml"): if slave_instance_dict.has_key("xml"):
slave_instance_dict.update(self._instanceXmlToDict( slave_instance_dict.update(self._instanceXmlToDict(
slave_instance_dict.pop("xml"))) slave_instance_dict.pop("xml")))
slap_partition._parameter_dict.update(parameter_dict) partition_dict['_parameter_dict'].update(parameter_dict)
return slap_partition return partition_dict
def _getSoftwareInstallationFromUrl(self, url): def _getSoftwareInstallationFromUrl(self, url):
software_installation_list = self.getPortalObject().portal_catalog.unrestrictedSearchResults( software_installation_list = self.getPortalObject().portal_catalog.unrestrictedSearchResults(
......
...@@ -6,12 +6,6 @@ ...@@ -6,12 +6,6 @@
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
<item>
<key> <string>_recorded_property_dict</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item> <item>
<key> <string>default_reference</string> </key> <key> <string>default_reference</string> </key>
<value> <string>SlapOSComputeNodeMixin</string> </value> <value> <string>SlapOSComputeNodeMixin</string> </value>
...@@ -55,28 +49,13 @@ ...@@ -55,28 +49,13 @@
<item> <item>
<key> <string>workflow_history</string> </key> <key> <string>workflow_history</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="2" aka="AAAAAAAAAAI="> <record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle> <pickle>
<global name="PersistentMapping" module="Persistence.mapping"/> <global name="PersistentMapping" module="Persistence.mapping"/>
</pickle> </pickle>
...@@ -89,7 +68,7 @@ ...@@ -89,7 +68,7 @@
<item> <item>
<key> <string>component_validation_workflow</string> </key> <key> <string>component_validation_workflow</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value> </value>
</item> </item>
</dictionary> </dictionary>
...@@ -98,7 +77,7 @@ ...@@ -98,7 +77,7 @@
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="4" aka="AAAAAAAAAAQ="> <record id="3" aka="AAAAAAAAAAM=">
<pickle> <pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/> <global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle> </pickle>
......
...@@ -25,14 +25,11 @@ ...@@ -25,14 +25,11 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# #
############################################################################## ##############################################################################
from AccessControl.Permissions import access_contents_information from erp5.component.module.SlapOSCloud import _assertACI
from AccessControl import getSecurityManager from zLOG import LOG, INFO
from AccessControl import Unauthorized from OFS.Traversable import NotFound
try: try:
from slapos.slap.slap import (
ComputerPartition as SlapComputePartition,
SoftwareRelease)
from slapos.util import calculate_dict_hash from slapos.util import calculate_dict_hash
except ImportError: except ImportError:
# Do no prevent instance from starting # Do no prevent instance from starting
...@@ -46,27 +43,48 @@ except ImportError: ...@@ -46,27 +43,48 @@ except ImportError:
def calculate_dict_hash(*args): def calculate_dict_hash(*args):
raise ImportError raise ImportError
def _assertACI(document): class SlapOSComputePartitionMixin(object):
sm = getSecurityManager()
if sm.checkPermission(access_contents_information,
document):
return document
raise Unauthorized('User %r has no access to %r' % (sm.getUser(), document))
def _getSoftwareInstance(self, slave_reference=None):
if self.getSlapState() != 'busy':
LOG('SlapOSComputePartitionMixin::_getSoftwareInstance', INFO,
'Compute partition %s shall be busy, is free' %
self.getRelativeUrl())
raise NotFound("No software instance found for: %s - %s" % (
self.getParentValue().getTitle(), self.getTitle()))
else:
query_kw = {
'validation_state': 'validated',
'portal_type': 'Slave Instance',
'default_aggregate_uid': self.getUid(),
}
if slave_reference is None:
query_kw['portal_type'] = "Software Instance"
else:
query_kw['reference'] = slave_reference
class SlapOSComputePartitionMixin(object): software_instance = _assertACI(
self.getPortalObject().portal_catalog.unrestrictedGetResultValue(**query_kw))
if software_instance is None:
raise NotFound("No software instance found for: %s - %s" % (
self.getParentValue().getTitle(), self.getTitle()))
else:
return software_instance
def _registerComputePartition(self): def _registerComputePartition(self):
portal = self.getPortalObject() portal = self.getPortalObject()
computer_reference = self.getParentValue().getReference() compute_node = self
computer_partition_reference = self.getReference() while compute_node.getPortalType() != 'Compute Node':
compute_node = compute_node.getParentValue()
compute_node_id = compute_node.getReference().decode("UTF-8")
slap_partition = SlapComputePartition(computer_reference.decode("UTF-8"), partition_dict = {
computer_partition_reference.decode("UTF-8")) "compute_node_id": compute_node_id,
slap_partition._software_release_document = None "partition_id": self.getReference().decode("UTF-8"),
slap_partition._requested_state = 'destroyed' "_software_release_document": None,
slap_partition._need_modification = 0 "_requested_state": 'destroyed',
software_instance = None "_need_modification": 0
}
if self.getSlapState() == 'busy': if self.getSlapState() == 'busy':
software_instance_list = portal.portal_catalog.unrestrictedSearchResults( software_instance_list = portal.portal_catalog.unrestrictedSearchResults(
...@@ -85,31 +103,31 @@ class SlapOSComputePartitionMixin(object): ...@@ -85,31 +103,31 @@ class SlapOSComputePartitionMixin(object):
self.getRelativeUrl()) self.getRelativeUrl())
if software_instance is not None: if software_instance is not None:
# trick client side, that data has been synchronised already for given
# document
slap_partition._synced = True
state = software_instance.getSlapState() state = software_instance.getSlapState()
if state == "stop_requested": if state == "stop_requested":
slap_partition._requested_state = 'stopped' partition_dict['_requested_state'] = 'stopped'
if state == "start_requested": if state == "start_requested":
slap_partition._requested_state = 'started' partition_dict['_requested_state'] = 'started'
slap_partition._software_release_document = SoftwareRelease( partition_dict['_software_release_document'] = {
software_release=software_instance.getUrlString().decode("UTF-8"), "software_release": software_instance.getUrlString().decode("UTF-8"),
computer_guid=computer_reference.decode("UTF-8")) "computer_guid": compute_node_id
}
slap_partition._need_modification = 1 partition_dict['_access_status'] = software_instance.getTextAccessStatus()
partition_dict["_need_modification"] = 1
# trick client side, that data has been synchronised already for given
# document
partition_dict["_synced"] = True
parameter_dict = software_instance._asParameterDict() parameter_dict = software_instance._asParameterDict()
# software instance has to define an xml parameter # software instance has to define an xml parameter
slap_partition._parameter_dict = software_instance._instanceXmlToDict( partition_dict["_parameter_dict"] = software_instance._instanceXmlToDict(
parameter_dict.pop('xml')) parameter_dict.pop('xml'))
slap_partition._connection_dict = software_instance._instanceXmlToDict( partition_dict['_connection_dict'] = software_instance._instanceXmlToDict(
parameter_dict.pop('connection_xml')) parameter_dict.pop('connection_xml'))
slap_partition._filter_dict = software_instance._instanceXmlToDict( partition_dict['_filter_dict'] = software_instance._instanceXmlToDict(
parameter_dict.pop('filter_xml')) parameter_dict.pop('filter_xml'))
slap_partition._instance_guid = parameter_dict.pop('instance_guid') partition_dict['_instance_guid'] = parameter_dict.pop('instance_guid')
for slave_instance_dict in parameter_dict.get("slave_instance_list", []): for slave_instance_dict in parameter_dict.get("slave_instance_list", []):
if slave_instance_dict.has_key("connection_xml"): if slave_instance_dict.has_key("connection_xml"):
connection_dict = software_instance._instanceXmlToDict( connection_dict = software_instance._instanceXmlToDict(
...@@ -120,6 +138,6 @@ class SlapOSComputePartitionMixin(object): ...@@ -120,6 +138,6 @@ class SlapOSComputePartitionMixin(object):
if slave_instance_dict.has_key("xml"): if slave_instance_dict.has_key("xml"):
slave_instance_dict.update(software_instance._instanceXmlToDict( slave_instance_dict.update(software_instance._instanceXmlToDict(
slave_instance_dict.pop("xml"))) slave_instance_dict.pop("xml")))
slap_partition._parameter_dict.update(parameter_dict) partition_dict['_parameter_dict'].update(parameter_dict)
return slap_partition return partition_dict
...@@ -6,12 +6,6 @@ ...@@ -6,12 +6,6 @@
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
<item>
<key> <string>_recorded_property_dict</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item> <item>
<key> <string>default_reference</string> </key> <key> <string>default_reference</string> </key>
<value> <string>SlapOSComputePartitionMixin</string> </value> <value> <string>SlapOSComputePartitionMixin</string> </value>
...@@ -61,28 +55,13 @@ ...@@ -61,28 +55,13 @@
<item> <item>
<key> <string>workflow_history</string> </key> <key> <string>workflow_history</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="2" aka="AAAAAAAAAAI="> <record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle> <pickle>
<global name="PersistentMapping" module="Persistence.mapping"/> <global name="PersistentMapping" module="Persistence.mapping"/>
</pickle> </pickle>
...@@ -95,7 +74,7 @@ ...@@ -95,7 +74,7 @@
<item> <item>
<key> <string>component_validation_workflow</string> </key> <key> <string>component_validation_workflow</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value> </value>
</item> </item>
</dictionary> </dictionary>
...@@ -104,7 +83,7 @@ ...@@ -104,7 +83,7 @@
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="4" aka="AAAAAAAAAAQ="> <record id="3" aka="AAAAAAAAAAM=">
<pickle> <pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/> <global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle> </pickle>
......
##############################################################################
#
# Copyright (c) 2021 Nexedi SA and Contributors. All Rights Reserved.
#
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from AccessControl import getSecurityManager
from zExceptions import Unauthorized
from AccessControl.Permissions import access_contents_information
def _assertACI(document):
sm = getSecurityManager()
if sm.checkPermission(access_contents_information,
document):
return document
raise Unauthorized('User %r has no access to %r' % (sm.getUser(), document))
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Module Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>SlapOSCloud</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>module.erp5.SlapOSCloud</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Module Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</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>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -35,7 +35,7 @@ import hashlib ...@@ -35,7 +35,7 @@ import hashlib
from binascii import hexlify from binascii import hexlify
def hashData(data): def hashData(data):
return hexlify(hashlib.sha1(data).digest()) return hexlify(hashlib.sha1(json.dumps(data, sort_keys=True)).digest())
class TestSlapOSCloudSlapOSCacheMixin( class TestSlapOSCloudSlapOSCacheMixin(
SlapOSTestCaseMixin): SlapOSTestCaseMixin):
......
...@@ -6,12 +6,6 @@ ...@@ -6,12 +6,6 @@
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
<item>
<key> <string>_recorded_property_dict</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item> <item>
<key> <string>default_reference</string> </key> <key> <string>default_reference</string> </key>
<value> <string>testSlapOSCloud</string> </value> <value> <string>testSlapOSCloud</string> </value>
...@@ -61,28 +55,13 @@ ...@@ -61,28 +55,13 @@
<item> <item>
<key> <string>workflow_history</string> </key> <key> <string>workflow_history</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="2" aka="AAAAAAAAAAI="> <record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle> <pickle>
<global name="PersistentMapping" module="Persistence.mapping"/> <global name="PersistentMapping" module="Persistence.mapping"/>
</pickle> </pickle>
...@@ -95,7 +74,7 @@ ...@@ -95,7 +74,7 @@
<item> <item>
<key> <string>component_validation_workflow</string> </key> <key> <string>component_validation_workflow</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value> </value>
</item> </item>
</dictionary> </dictionary>
...@@ -104,7 +83,7 @@ ...@@ -104,7 +83,7 @@
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="4" aka="AAAAAAAAAAQ="> <record id="3" aka="AAAAAAAAAAM=">
<pickle> <pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/> <global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle> </pickle>
......
module.erp5.SlapOSCloud
\ No newline at end of file
...@@ -15,12 +15,13 @@ import xml.dom.ext ...@@ -15,12 +15,13 @@ import xml.dom.ext
import StringIO import StringIO
import difflib import difflib
import hashlib import hashlib
import json
from binascii import hexlify from binascii import hexlify
from OFS.Traversable import NotFound from OFS.Traversable import NotFound
def hashData(data): def hashData(data):
return hexlify(hashlib.sha1(data).digest()) return hexlify(hashlib.sha1(json.dumps(data, sort_keys=True)).digest())
class Simulator: class Simulator:
......
...@@ -6,12 +6,6 @@ ...@@ -6,12 +6,6 @@
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
<item>
<key> <string>_recorded_property_dict</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item> <item>
<key> <string>default_reference</string> </key> <key> <string>default_reference</string> </key>
<value> <string>testSlapOSSlapTool</string> </value> <value> <string>testSlapOSSlapTool</string> </value>
...@@ -55,28 +49,13 @@ ...@@ -55,28 +49,13 @@
<item> <item>
<key> <string>workflow_history</string> </key> <key> <string>workflow_history</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="2" aka="AAAAAAAAAAI="> <record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle> <pickle>
<global name="PersistentMapping" module="Persistence.mapping"/> <global name="PersistentMapping" module="Persistence.mapping"/>
</pickle> </pickle>
...@@ -89,7 +68,7 @@ ...@@ -89,7 +68,7 @@
<item> <item>
<key> <string>component_validation_workflow</string> </key> <key> <string>component_validation_workflow</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value> </value>
</item> </item>
</dictionary> </dictionary>
...@@ -98,7 +77,7 @@ ...@@ -98,7 +77,7 @@
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="4" aka="AAAAAAAAAAQ="> <record id="3" aka="AAAAAAAAAAM=">
<pickle> <pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/> <global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle> </pickle>
......
...@@ -28,10 +28,9 @@ ...@@ -28,10 +28,9 @@
# #
############################################################################## ##############################################################################
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from AccessControl import Unauthorized from AccessControl import Unauthorized
from AccessControl.Permissions import access_contents_information
from AccessControl import getSecurityManager
from Products.ERP5Type.UnrestrictedMethod import UnrestrictedMethod from Products.ERP5Type.UnrestrictedMethod import UnrestrictedMethod
from OFS.Traversable import NotFound from OFS.Traversable import NotFound
from Products.DCWorkflow.DCWorkflow import ValidationFailed from Products.DCWorkflow.DCWorkflow import ValidationFailed
...@@ -39,10 +38,14 @@ from Products.ERP5Type.Globals import InitializeClass ...@@ -39,10 +38,14 @@ from Products.ERP5Type.Globals import InitializeClass
from Products.ERP5Type.Tool.BaseTool import BaseTool from Products.ERP5Type.Tool.BaseTool import BaseTool
from Products.ERP5Type import Permissions from Products.ERP5Type import Permissions
from Products.ERP5Type.Cache import CachingMethod from Products.ERP5Type.Cache import CachingMethod
from erp5.component.module.SlapOSCloud import _assertACI
from lxml import etree from lxml import etree
try: try:
from slapos.slap.slap import ( from slapos.slap.slap import (
Computer as ComputeNode) Computer as ComputeNode,
ComputerPartition as SlapComputePartition,
SoftwareInstance as SlapSoftwareInstance,
SoftwareRelease)
from slapos.util import dict2xml, calculate_dict_hash, loads, dumps from slapos.util import dict2xml, calculate_dict_hash, loads, dumps
except ImportError: except ImportError:
# Do no prevent instance from starting # Do no prevent instance from starting
...@@ -50,6 +53,12 @@ except ImportError: ...@@ -50,6 +53,12 @@ except ImportError:
class ComputeNode: class ComputeNode:
def __init__(self): def __init__(self):
raise ImportError raise ImportError
class SlapComputePartition:
def __init__(self):
raise ImportError
class SoftwareRelease:
def __init__(self):
raise ImportError
def dict2xml(dictionary): def dict2xml(dictionary):
raise ImportError raise ImportError
def calculate_dict_hash(dictionary): def calculate_dict_hash(dictionary):
...@@ -58,6 +67,10 @@ except ImportError: ...@@ -58,6 +67,10 @@ except ImportError:
raise ImportError raise ImportError
def dumps(*args): def dumps(*args):
raise ImportError raise ImportError
class SlapSoftwareInstance:
def __init__(self):
raise ImportError
from zLOG import LOG, INFO from zLOG import LOG, INFO
import StringIO import StringIO
...@@ -111,13 +124,6 @@ def castToStr(dict_kw): ...@@ -111,13 +124,6 @@ def castToStr(dict_kw):
xml_declaration=True, encoding='utf-8') xml_declaration=True, encoding='utf-8')
def _assertACI(document):
sm = getSecurityManager()
if sm.checkPermission(access_contents_information,
document):
return document
raise Unauthorized('User %r has no access to %r' % (sm.getUser(), document))
_MARKER = object() _MARKER = object()
...@@ -175,7 +181,47 @@ class SlapTool(BaseTool): ...@@ -175,7 +181,47 @@ class SlapTool(BaseTool):
validation_state="validated")[0].getObject() validation_state="validated")[0].getObject()
refresh_etag = compute_node._calculateRefreshEtag() refresh_etag = compute_node._calculateRefreshEtag()
body, etag = compute_node._getComputeNodeInformation(user, refresh_etag) computer_dict, etag = compute_node._getComputeNodeInformation(user, refresh_etag)
## Horrible code starts
# Convert computer node into SlapComputer
slap_compute_node = ComputeNode(computer_dict["_computer_id"])
slap_compute_node._computer_partition_list = []
slap_compute_node._software_release_list = []
for partition_dict in computer_dict["_computer_partition_list"]:
slap_compute_partition = SlapComputePartition(
partition_id=partition_dict["partition_id"],
computer_id=partition_dict['compute_node_id']
)
slap_compute_partition._requested_state = partition_dict["_requested_state"]
slap_compute_partition._need_modification = partition_dict["_need_modification"]
if partition_dict["_software_release_document"] is not None:
slap_compute_partition._access_status = partition_dict["_access_status"]
slap_compute_partition._parameter_dict = partition_dict["_parameter_dict"]
slap_compute_partition._connection_dict = partition_dict["_connection_dict"]
slap_compute_partition._filter_dict = partition_dict["_filter_dict"]
slap_compute_partition._instance_guid = partition_dict["_instance_guid"]
slap_compute_partition._software_release_document = SoftwareRelease(
software_release=partition_dict["_software_release_document"]["software_release"],
computer_guid=partition_dict["_software_release_document"]["computer_guid"])
else:
slap_compute_partition._software_release_document = None
slap_compute_node._computer_partition_list.append(
slap_compute_partition
)
for software_release_dict in computer_dict['_software_release_list']:
slap_software_release = SoftwareRelease(
software_release=software_release_dict["software_release"],
computer_guid=software_release_dict['computer_guid'])
slap_software_release._requested_state = software_release_dict['_requested_state']
slap_software_release._known_state = software_release_dict['_known_state']
slap_compute_node._software_release_list.append(slap_software_release)
body = dumps(slap_compute_node)
## Horrible code ends
if self.REQUEST.response.getStatus() == 200: if self.REQUEST.response.getStatus() == 200:
# Keep in cache server for 7 days # Keep in cache server for 7 days
...@@ -653,7 +699,25 @@ class SlapTool(BaseTool): ...@@ -653,7 +699,25 @@ class SlapTool(BaseTool):
compute_partition_document = self._getComputePartitionDocument( compute_partition_document = self._getComputePartitionDocument(
computer_reference, computer_partition_reference) computer_reference, computer_partition_reference)
slap_compute_partition = compute_partition_document._registerComputePartition() partition_dict = compute_partition_document._registerComputePartition()
slap_compute_partition = SlapComputePartition(
partition_id=partition_dict["partition_id"],
computer_id=partition_dict['compute_node_id']
)
slap_compute_partition._requested_state = partition_dict["_requested_state"]
slap_compute_partition._need_modification = partition_dict["_need_modification"]
if partition_dict["_software_release_document"] is not None:
slap_compute_partition._parameter_dict = partition_dict["_parameter_dict"]
slap_compute_partition._connection_dict = partition_dict["_connection_dict"]
slap_compute_partition._filter_dict = partition_dict["_filter_dict"]
slap_compute_partition._instance_guid = partition_dict["_instance_guid"]
slap_compute_partition._software_release_document = SoftwareRelease(
software_release=partition_dict["_software_release_document"]["software_release"],
computer_guid=partition_dict["_software_release_document"]["computer_guid"])
slap_compute_partition._synced = partition_dict["_synced"]
else:
slap_compute_partition._software_release_document = None
# Keep in cache server for 7 days # Keep in cache server for 7 days
self.REQUEST.response.setStatus(200) self.REQUEST.response.setStatus(200)
...@@ -923,7 +987,8 @@ class SlapTool(BaseTool): ...@@ -923,7 +987,8 @@ class SlapTool(BaseTool):
if not requested_software_instance.getAggregate(portal_type="Compute Partition"): if not requested_software_instance.getAggregate(portal_type="Compute Partition"):
raise SoftwareInstanceNotReady raise SoftwareInstanceNotReady
else: else:
return dumps(requested_software_instance._asSoftwareInstance()) return dumps(SlapSoftwareInstance(
**requested_software_instance._asSoftwareInstanceDict()))
@UnrestrictedMethod @UnrestrictedMethod
def _updateComputePartitionRelatedInstanceList(self, compute_node_id, def _updateComputePartitionRelatedInstanceList(self, compute_node_id,
...@@ -1003,29 +1068,7 @@ class SlapTool(BaseTool): ...@@ -1003,29 +1068,7 @@ class SlapTool(BaseTool):
compute_partition_id, slave_reference=None): compute_partition_id, slave_reference=None):
compute_partition_document = self._getComputePartitionDocument( compute_partition_document = self._getComputePartitionDocument(
compute_node_id, compute_partition_id) compute_node_id, compute_partition_id)
if compute_partition_document.getSlapState() != 'busy': return compute_partition_document._getSoftwareInstance(slave_reference)
LOG('SlapTool::_getSoftwareInstanceForComputePartition', INFO,
'Compute partition %s shall be busy, is free' %
compute_partition_document.getRelativeUrl())
raise NotFound, "No software instance found for: %s - %s" % (compute_node_id,
compute_partition_id)
else:
query_kw = {
'validation_state': 'validated',
'portal_type': 'Slave Instance',
'default_aggregate_uid': compute_partition_document.getUid(),
}
if slave_reference is None:
query_kw['portal_type'] = "Software Instance"
else:
query_kw['reference'] = slave_reference
software_instance = _assertACI(self.getPortalObject().portal_catalog.unrestrictedGetResultValue(**query_kw))
if software_instance is None:
raise NotFound, "No software instance found for: %s - %s" % (
compute_node_id, compute_partition_id)
else:
return software_instance
@convertToREST @convertToREST
def _softwareReleaseError(self, url, compute_node_id, error_log): def _softwareReleaseError(self, url, compute_node_id, error_log):
......
...@@ -6,12 +6,6 @@ ...@@ -6,12 +6,6 @@
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
<item>
<key> <string>_recorded_property_dict</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item> <item>
<key> <string>default_reference</string> </key> <key> <string>default_reference</string> </key>
<value> <string>SlapTool</string> </value> <value> <string>SlapTool</string> </value>
...@@ -55,28 +49,13 @@ ...@@ -55,28 +49,13 @@
<item> <item>
<key> <string>workflow_history</string> </key> <key> <string>workflow_history</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="2" aka="AAAAAAAAAAI="> <record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle> <pickle>
<global name="PersistentMapping" module="Persistence.mapping"/> <global name="PersistentMapping" module="Persistence.mapping"/>
</pickle> </pickle>
...@@ -89,7 +68,7 @@ ...@@ -89,7 +68,7 @@
<item> <item>
<key> <string>component_validation_workflow</string> </key> <key> <string>component_validation_workflow</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value> </value>
</item> </item>
</dictionary> </dictionary>
...@@ -98,7 +77,7 @@ ...@@ -98,7 +77,7 @@
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="4" aka="AAAAAAAAAAQ="> <record id="3" aka="AAAAAAAAAAM=">
<pickle> <pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/> <global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle> </pickle>
......
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