Commit 9998c6f4 authored by Rafael Monnerat's avatar Rafael Monnerat

Clean up for the JSON API work

See merge request nexedi/slapos.core!388
parents 1ac3ec59 e36b68d4
...@@ -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>
......
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2010-2022 Nexedi SA and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility 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
# guarantees and support are strongly advised 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 erp5.component.module.SlapOSCloud import _assertACI
from OFS.Traversable import NotFound
from Products.ERP5Type.Cache import CachingMethod
from Products.ERP5Type.UnrestrictedMethod import UnrestrictedMethod
class SlapOSCatalogToolCacheMixin(object):
""" Quering Caching Extension for Catalog for handle specific queries
relying on caching.
The searches also differ NotFound from Unauthorized, by relying into
unrestricted searches and a custom way to assert Access roles.
Be carefull to not rely on it to hack arround security.
"""
def _getNonCachedComputeNode(self, reference):
# No need to get all results if an error is raised when at least 2 objects
# are found
compute_node_list = self.unrestrictedSearchResults(limit=2,
portal_type='Compute Node',
validation_state="validated",
reference=reference)
if len(compute_node_list) != 1:
raise NotFound, "No document found with parameters: %s" % reference
else:
return _assertACI(compute_node_list[0].getObject()).getRelativeUrl()
def getComputeNodeObject(self, reference):
"""
Get the validated compute_node with this reference.
"""
result = CachingMethod(self._getNonCachedComputeNode,
id='_getComputeNodeObject',
cache_factory='slap_cache_factory')(reference)
return self.getPortalObject().restrictedTraverse(result)
@UnrestrictedMethod
def _getComputeNodeUid(self, reference):
"""
Get the validated compute_node with this reference.
"""
return CachingMethod(self._getNonCachedComputeNodeUid,
id='_getNonCachedComputeNodeUid',
cache_factory='slap_cache_factory')(reference)
@UnrestrictedMethod
def _getNonCachedComputeNodeUid(self, reference):
return self.unrestrictedSearchResults(
portal_type='Compute Node', reference=reference,
validation_state="validated")[0].UID
def getComputePartitionObject(self, compute_node_reference,
compute_partition_reference):
"""
Get the compute partition defined in an available compute_node
"""
# Related key might be nice
compute_partition_list = self.unrestrictedSearchResults(limit=2,
portal_type='Compute Partition',
reference=compute_partition_reference,
parent_uid=self._getNonCachedComputeNodeUid(
compute_node_reference))
if len(compute_partition_list) != 1:
raise NotFound, "No document found with parameters: %s %s" % \
(compute_node_reference, compute_partition_reference)
else:
return _assertACI(compute_partition_list[0].getObject())
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Mixin Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>SlapOSCatalogToolCacheMixin</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>mixin.erp5.SlapOSCatalogToolCacheMixin</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Mixin 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>
...@@ -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)
...@@ -133,11 +109,14 @@ class SlapOSComputeNodeMixin(object): ...@@ -133,11 +109,14 @@ class SlapOSComputeNodeMixin(object):
def _fillComputeNodeInformationCache(self, user): def _fillComputeNodeInformationCache(self, user):
key = '%s_%s' % (self.getReference(), user) key = '%s_%s' % (self.getReference(), user)
try: try:
computer_dict = self._getCacheComputeNodeInformation(user)
self._getCachePlugin().set(key, DEFAULT_CACHE_SCOPE, self._getCachePlugin().set(key, DEFAULT_CACHE_SCOPE,
dict ( dict (
time=time.time(), time=time.time(),
refresh_etag=self._calculateRefreshEtag(), refresh_etag=self._calculateRefreshEtag(),
data=self._getCacheComputeNodeInformation(user), data=computer_dict,
# Store the XML while SlapTool Still used
data_xml=self.getPortalObject().portal_slap._getSlapComputeNodeXMLFromDict(computer_dict)
), ),
cache_duration=self.getPortalObject().portal_caches\ cache_duration=self.getPortalObject().portal_caches\
.getRamCacheRoot().get('compute_node_information_cache_factory'\ .getRamCacheRoot().get('compute_node_information_cache_factory'\
...@@ -178,11 +157,7 @@ class SlapOSComputeNodeMixin(object): ...@@ -178,11 +157,7 @@ class SlapOSComputeNodeMixin(object):
user_document = _assertACI(portal.portal_catalog.unrestrictedGetResultValue( user_document = _assertACI(portal.portal_catalog.unrestrictedGetResultValue(
reference=user, portal_type=['Person', 'Compute Node', 'Software Instance'])) reference=user, portal_type=['Person', 'Compute Node', 'Software Instance']))
user_type = user_document.getPortalType() user_type = user_document.getPortalType()
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,22 +182,27 @@ class SlapOSComputeNodeMixin(object): ...@@ -207,22 +182,27 @@ 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(
portal_type="Compute Partition", portal_type="Compute Partition",
checked_permission="View") checked_permission="View")
else: else:
compute_partition_list = self.getPortalObject().portal_catalog.unrestrictedSearchResults( unrestrictedSearchResults = self.getPortalObject().portal_catalog.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), 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 +228,7 @@ class SlapOSComputeNodeMixin(object): ...@@ -248,7 +228,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 +253,13 @@ class SlapOSComputeNodeMixin(object): ...@@ -273,12 +253,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 +275,29 @@ class SlapOSComputeNodeMixin(object): ...@@ -294,28 +275,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 +305,9 @@ class SlapOSComputeNodeMixin(object): ...@@ -323,9 +305,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>
<type_mixin> <type_mixin>
<portal_type id="Catalog Tool">
<item>SlapOSCatalogToolCacheMixin</item>
</portal_type>
<portal_type id="Compute Node"> <portal_type id="Compute Node">
<item>SlapOSCacheMixin</item> <item>SlapOSCacheMixin</item>
<item>SlapOSComputeNodeMixin</item> <item>SlapOSComputeNodeMixin</item>
......
...@@ -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>
......
mixin.erp5.SlapOSCacheMixin mixin.erp5.SlapOSCacheMixin
mixin.erp5.SlapOSComputeNodeMixin mixin.erp5.SlapOSComputeNodeMixin
mixin.erp5.SlapOSComputePartitionMixin mixin.erp5.SlapOSComputePartitionMixin
\ No newline at end of file mixin.erp5.SlapOSCatalogToolCacheMixin
\ No newline at end of file
module.erp5.SlapOSCloud
\ No newline at end of file
Catalog Tool | SlapOSCatalogToolCacheMixin
Compute Node | SlapOSCacheMixin Compute Node | SlapOSCacheMixin
Compute Node | SlapOSComputeNodeMixin Compute Node | SlapOSComputeNodeMixin
Compute Partition | SlapOSCacheMixin Compute Partition | SlapOSCacheMixin
......
...@@ -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:
...@@ -87,7 +88,9 @@ class TestSlapOSSlapToolgetFullComputerInformation(TestSlapOSSlapToolMixin): ...@@ -87,7 +88,9 @@ class TestSlapOSSlapToolgetFullComputerInformation(TestSlapOSSlapToolMixin):
self.commit() self.commit()
first_etag = self.compute_node._calculateRefreshEtag() first_etag = self.compute_node._calculateRefreshEtag()
first_body_fingerprint = hashData( first_body_fingerprint = hashData(
self.compute_node._getCacheComputeNodeInformation(self.compute_node_id) self.portal_slap._getSlapComputeNodeXMLFromDict(
self.compute_node._getCacheComputeNodeInformation(self.compute_node_id)
)
) )
self.assertEqual(200, response.status) self.assertEqual(200, response.status)
self.assertTrue('last-modified' not in response.headers) self.assertTrue('last-modified' not in response.headers)
...@@ -122,7 +125,9 @@ class TestSlapOSSlapToolgetFullComputerInformation(TestSlapOSSlapToolMixin): ...@@ -122,7 +125,9 @@ class TestSlapOSSlapToolgetFullComputerInformation(TestSlapOSSlapToolMixin):
self.assertTrue('last-modified' not in response.headers) self.assertTrue('last-modified' not in response.headers)
second_etag = self.compute_node._calculateRefreshEtag() second_etag = self.compute_node._calculateRefreshEtag()
second_body_fingerprint = hashData( second_body_fingerprint = hashData(
self.compute_node._getCacheComputeNodeInformation(self.compute_node_id) self.portal_slap._getSlapComputeNodeXMLFromDict(
self.compute_node._getCacheComputeNodeInformation(self.compute_node_id)
)
) )
self.assertNotEqual(first_etag, second_etag) self.assertNotEqual(first_etag, second_etag)
# The indexation timestamp does not impact the response body # The indexation timestamp does not impact the response body
...@@ -155,7 +160,9 @@ class TestSlapOSSlapToolgetFullComputerInformation(TestSlapOSSlapToolMixin): ...@@ -155,7 +160,9 @@ class TestSlapOSSlapToolgetFullComputerInformation(TestSlapOSSlapToolMixin):
# Edition does not impact the etag # Edition does not impact the etag
self.assertEqual(second_etag, self.compute_node._calculateRefreshEtag()) self.assertEqual(second_etag, self.compute_node._calculateRefreshEtag())
third_body_fingerprint = hashData( third_body_fingerprint = hashData(
self.compute_node._getCacheComputeNodeInformation(self.compute_node_id) self.portal_slap._getSlapComputeNodeXMLFromDict(
self.compute_node._getCacheComputeNodeInformation(self.compute_node_id)
)
) )
# The edition impacts the response body # The edition impacts the response body
self.assertNotEqual(first_body_fingerprint, third_body_fingerprint) self.assertNotEqual(first_body_fingerprint, third_body_fingerprint)
...@@ -194,7 +201,9 @@ class TestSlapOSSlapToolgetFullComputerInformation(TestSlapOSSlapToolMixin): ...@@ -194,7 +201,9 @@ class TestSlapOSSlapToolgetFullComputerInformation(TestSlapOSSlapToolMixin):
# The edition does not impact the response body yet, as the aggregate relation # The edition does not impact the response body yet, as the aggregate relation
# is not yet unindex # is not yet unindex
self.assertEqual(third_body_fingerprint, hashData( self.assertEqual(third_body_fingerprint, hashData(
self.compute_node._getCacheComputeNodeInformation(self.compute_node_id) self.portal_slap._getSlapComputeNodeXMLFromDict(
self.compute_node._getCacheComputeNodeInformation(self.compute_node_id)
)
)) ))
response = self.portal_slap.getFullComputerInformation(self.compute_node_id) response = self.portal_slap.getFullComputerInformation(self.compute_node_id)
self.commit() self.commit()
...@@ -216,7 +225,9 @@ class TestSlapOSSlapToolgetFullComputerInformation(TestSlapOSSlapToolMixin): ...@@ -216,7 +225,9 @@ class TestSlapOSSlapToolgetFullComputerInformation(TestSlapOSSlapToolMixin):
self.assertTrue('last-modified' not in response.headers) self.assertTrue('last-modified' not in response.headers)
fourth_etag = self.compute_node._calculateRefreshEtag() fourth_etag = self.compute_node._calculateRefreshEtag()
fourth_body_fingerprint = hashData( fourth_body_fingerprint = hashData(
self.compute_node._getCacheComputeNodeInformation(self.compute_node_id) self.portal_slap._getSlapComputeNodeXMLFromDict(
self.compute_node._getCacheComputeNodeInformation(self.compute_node_id)
)
) )
self.assertNotEqual(third_etag, fourth_etag) self.assertNotEqual(third_etag, fourth_etag)
# The indexation timestamp does not impact the response body # The indexation timestamp does not impact the response body
......
...@@ -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,16 @@ from Products.ERP5Type.Globals import InitializeClass ...@@ -39,10 +38,16 @@ 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 Products.ERP5Type.Cache import DEFAULT_CACHE_SCOPE
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 +55,12 @@ except ImportError: ...@@ -50,6 +55,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 +69,10 @@ except ImportError: ...@@ -58,6 +69,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 +126,6 @@ def castToStr(dict_kw): ...@@ -111,13 +126,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()
...@@ -163,20 +171,56 @@ class SlapTool(BaseTool): ...@@ -163,20 +171,56 @@ class SlapTool(BaseTool):
Reuses slap library for easy marshalling. Reuses slap library for easy marshalling.
""" """
user = self.getPortalObject().portal_membership.getAuthenticatedMember().getUserName() portal = self.getPortalObject()
user = portal.portal_membership.getAuthenticatedMember().getUserName()
if str(user) == computer_id: if str(user) == computer_id:
compute_node = self.getPortalObject().portal_membership.getAuthenticatedMember().getUserValue() compute_node = portal.portal_membership.getAuthenticatedMember().getUserValue()
compute_node.setAccessStatus(computer_id) compute_node.setAccessStatus(computer_id)
else: else:
# Don't use getDocument because we don't want use _assertACI here, but # Don't use getDocument because we don't want use _assertACI here, but
# just call the API on computer. # just call the API on computer.
compute_node = self.getPortalObject().portal_catalog.unrestrictedSearchResults( compute_node = portal.portal_catalog.unrestrictedSearchResults(
portal_type='Compute Node', reference=computer_id, portal_type='Compute Node', reference=computer_id,
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)
# Keep compatibility with older clients that relies on marshalling.
# This code is an adaptation of SlapOSComputeNodeMixin._getComputeNodeInformation
# To comply with cache capability.
user_document = _assertACI(portal.portal_catalog.unrestrictedGetResultValue(
reference=user, portal_type=['Person', 'Compute Node', 'Software Instance']))
user_type = user_document.getPortalType()
if user_type in ('Compute Node', 'Person'):
if not compute_node._isTestRun():
cache_plugin = compute_node._getCachePlugin()
key = '%s_%s' % (compute_node.getReference(), user)
try:
entry = cache_plugin.get(key, DEFAULT_CACHE_SCOPE)
except KeyError:
entry = None
if entry is not None and isinstance(entry.getValue(), dict):
cached_dict = entry.getValue()
cached_etag = cached_dict.get('refresh_etag', None)
if (refresh_etag != cached_etag):
# Do not recalculate the compute_node information
# if nothing changed
compute_node._activateFillComputeNodeInformationCache(user)
etag = cached_etag
body = cached_dict['data_xml']
else:
compute_node._activateFillComputeNodeInformationCache(user)
self.REQUEST.response.setStatus(503)
return self.REQUEST.response
else:
computer_dict, etag = compute_node._getComputeNodeInformation(user, refresh_etag)
body = self._getSlapComputeNodeXMLFromDict(computer_dict)
else:
computer_dict, etag = compute_node._getComputeNodeInformation(user, refresh_etag)
body = self._getSlapComputeNodeXMLFromDict(computer_dict)
self.REQUEST.response.setHeader('Content-Type', 'text/xml; charset=utf-8')
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
self.REQUEST.response.setHeader('Cache-Control', self.REQUEST.response.setHeader('Cache-Control',
...@@ -275,7 +319,7 @@ class SlapTool(BaseTool): ...@@ -275,7 +319,7 @@ class SlapTool(BaseTool):
""" """
Get the connection status of the partition Get the connection status of the partition
""" """
compute_node = self._getComputeNodeDocument(computer_id) compute_node = self.portal_catalog.getComputeNodeObject(computer_id)
data_dict = compute_node.getAccessStatus() data_dict = compute_node.getAccessStatus()
# Keep in cache server for 7 days # Keep in cache server for 7 days
...@@ -295,7 +339,7 @@ class SlapTool(BaseTool): ...@@ -295,7 +339,7 @@ class SlapTool(BaseTool):
""" """
Get the connection status of the software installation Get the connection status of the software installation
""" """
compute_node = self._getComputeNodeDocument(computer_id) compute_node = self.portal_catalog.getComputeNodeObject(computer_id)
# Be sure to prevent accessing information to disallowed users # Be sure to prevent accessing information to disallowed users
compute_node = _assertACI(compute_node) compute_node = _assertACI(compute_node)
try: try:
...@@ -574,7 +618,7 @@ class SlapTool(BaseTool): ...@@ -574,7 +618,7 @@ class SlapTool(BaseTool):
'doc/computer_consumption.xsd') 'doc/computer_consumption.xsd')
if self._validateXML(use_string, compute_node_consumption_model): if self._validateXML(use_string, compute_node_consumption_model):
compute_node = self._getComputeNodeDocument(computer_id) compute_node = self.portal_catalog.getComputeNodeObject(computer_id)
tree = etree.fromstring(use_string) tree = etree.fromstring(use_string)
source_reference = \ source_reference = \
tree.find('transaction').find('reference').text or "" tree.find('transaction').find('reference').text or ""
...@@ -595,7 +639,7 @@ class SlapTool(BaseTool): ...@@ -595,7 +639,7 @@ class SlapTool(BaseTool):
""" """
Fire up bung on Compute Node Fire up bung on Compute Node
""" """
compute_node = self._getComputeNodeDocument(compute_node_id) compute_node = self.getPortalObject().portal_catalog.getComputeNodeObject(compute_node_id)
return compute_node.reportComputeNodeBang(comment=message) return compute_node.reportComputeNodeBang(comment=message)
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
...@@ -611,13 +655,13 @@ class SlapTool(BaseTool): ...@@ -611,13 +655,13 @@ class SlapTool(BaseTool):
def loadComputerConfigurationFromXML(self, xml): def loadComputerConfigurationFromXML(self, xml):
"Load the given xml as configuration for the compute_node object" "Load the given xml as configuration for the compute_node object"
compute_node_dict = loads(xml) compute_node_dict = loads(xml)
compute_node = self._getComputeNodeDocument(compute_node_dict['reference']) compute_node = self.getPortalObject().portal_catalog.getComputeNodeObject(compute_node_dict['reference'])
compute_node.ComputeNode_updateFromDict(compute_node_dict) compute_node.ComputeNode_updateFromDict(compute_node_dict)
return 'Content properly posted.' return 'Content properly posted.'
@convertToREST @convertToREST
def _generateComputerCertificate(self, compute_node_id): def _generateComputerCertificate(self, compute_node_id):
self._getComputeNodeDocument(compute_node_id).generateCertificate() self.getPortalObject().portal_catalog.getComputeNodeObject(compute_node_id).generateCertificate()
result = { result = {
'certificate': self.REQUEST.get('compute_node_certificate').decode("UTF-8"), 'certificate': self.REQUEST.get('compute_node_certificate').decode("UTF-8"),
'key': self.REQUEST.get('compute_node_key').decode("UTF-8") 'key': self.REQUEST.get('compute_node_key').decode("UTF-8")
...@@ -632,7 +676,7 @@ class SlapTool(BaseTool): ...@@ -632,7 +676,7 @@ class SlapTool(BaseTool):
@convertToREST @convertToREST
def _revokeComputerCertificate(self, compute_node_id): def _revokeComputerCertificate(self, compute_node_id):
self._getComputeNodeDocument(compute_node_id).revokeCertificate() self.getPortalObject().portal_catalog.getComputeNodeObject(compute_node_id).revokeCertificate()
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
'revokeComputerCertificate') 'revokeComputerCertificate')
...@@ -650,10 +694,28 @@ class SlapTool(BaseTool): ...@@ -650,10 +694,28 @@ class SlapTool(BaseTool):
""" """
# Try to get the compute partition to raise an exception if it doesn't # Try to get the compute partition to raise an exception if it doesn't
# exist # exist
compute_partition_document = self._getComputePartitionDocument( compute_partition_document = self.getPortalObject().portal_catalog.getComputePartitionObject(
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)
...@@ -670,7 +732,6 @@ class SlapTool(BaseTool): ...@@ -670,7 +732,6 @@ class SlapTool(BaseTool):
#################################################### ####################################################
# Internal methods # Internal methods
#################################################### ####################################################
def _validateXML(self, to_be_validated, xsd_model): def _validateXML(self, to_be_validated, xsd_model):
"""Will validate the xml file""" """Will validate the xml file"""
#We parse the XSD model #We parse the XSD model
...@@ -698,7 +759,7 @@ class SlapTool(BaseTool): ...@@ -698,7 +759,7 @@ class SlapTool(BaseTool):
""" """
Request Software Release installation Request Software Release installation
""" """
compute_node_document = self._getComputeNodeDocument(compute_node_id) compute_node_document = self.getPortalObject().portal_catalog.getComputeNodeObject(compute_node_id)
compute_node_document.requestSoftwareRelease(software_release_url=url, state=state) compute_node_document.requestSoftwareRelease(software_release_url=url, state=state)
@convertToREST @convertToREST
...@@ -706,7 +767,7 @@ class SlapTool(BaseTool): ...@@ -706,7 +767,7 @@ class SlapTool(BaseTool):
""" """
Log the software release status Log the software release status
""" """
compute_node = self._getComputeNodeDocument(compute_node_id) compute_node = self.getPortalObject().portal_catalog.getComputeNodeObject(compute_node_id)
software_installation = compute_node._getSoftwareInstallationFromUrl(url) software_installation = compute_node._getSoftwareInstallationFromUrl(url)
software_installation.setBuildingStatus( software_installation.setBuildingStatus(
'software release %s' % url, "building") 'software release %s' % url, "building")
...@@ -716,7 +777,7 @@ class SlapTool(BaseTool): ...@@ -716,7 +777,7 @@ class SlapTool(BaseTool):
""" """
Log the software release status Log the software release status
""" """
compute_node = self._getComputeNodeDocument(compute_node_id) compute_node = self.getPortalObject().portal_catalog.getComputeNodeObject(compute_node_id)
software_installation = compute_node._getSoftwareInstallationFromUrl(url) software_installation = compute_node._getSoftwareInstallationFromUrl(url)
software_installation.setAccessStatus( software_installation.setAccessStatus(
'software release %s available' % url, "available") 'software release %s available' % url, "available")
...@@ -726,7 +787,7 @@ class SlapTool(BaseTool): ...@@ -726,7 +787,7 @@ class SlapTool(BaseTool):
""" """
Reports that Software Release is destroyed Reports that Software Release is destroyed
""" """
compute_node = self._getComputeNodeDocument(compute_node_id) compute_node = self.getPortalObject().portal_catalog.getComputeNodeObject(compute_node_id)
software_installation = compute_node._getSoftwareInstallationFromUrl(url) software_installation = compute_node._getSoftwareInstallationFromUrl(url)
if software_installation.getSlapState() != 'destroy_requested': if software_installation.getSlapState() != 'destroy_requested':
raise NotFound raise NotFound
...@@ -923,7 +984,8 @@ class SlapTool(BaseTool): ...@@ -923,7 +984,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,
...@@ -947,92 +1009,56 @@ class SlapTool(BaseTool): ...@@ -947,92 +1009,56 @@ class SlapTool(BaseTool):
# Internals methods # Internals methods
#################################################### ####################################################
def _getDocument(self, **kwargs): def _getSlapComputeNodeXMLFromDict(self, computer_dict):
# No need to get all results if an error is raised when at least 2 objects slap_compute_node = ComputeNode(computer_dict["_computer_id"])
# are found slap_compute_node._computer_partition_list = []
l = self.getPortalObject().portal_catalog.unrestrictedSearchResults(limit=2, **kwargs) slap_compute_node._software_release_list = []
if len(l) != 1:
raise NotFound, "No document found with parameters: %s" % kwargs for partition_dict in computer_dict["_computer_partition_list"]:
else: slap_compute_partition = SlapComputePartition(
return _assertACI(l[0].getObject()) partition_id=partition_dict["partition_id"],
computer_id=partition_dict['compute_node_id']
def _getNonCachedComputeNodeDocument(self, compute_node_reference): )
return self._getDocument( slap_compute_partition._requested_state = partition_dict["_requested_state"]
portal_type='Compute Node', slap_compute_partition._need_modification = partition_dict["_need_modification"]
# XXX Hardcoded validation state if partition_dict["_software_release_document"] is not None:
validation_state="validated", slap_compute_partition._access_status = partition_dict["_access_status"]
reference=compute_node_reference).getRelativeUrl() slap_compute_partition._parameter_dict = partition_dict["_parameter_dict"]
slap_compute_partition._connection_dict = partition_dict["_connection_dict"]
def _getComputeNodeDocument(self, compute_node_reference): slap_compute_partition._filter_dict = partition_dict["_filter_dict"]
""" slap_compute_partition._instance_guid = partition_dict["_instance_guid"]
Get the validated compute_node with this reference. slap_compute_partition._software_release_document = SoftwareRelease(
""" software_release=partition_dict["_software_release_document"]["software_release"],
result = CachingMethod(self._getNonCachedComputeNodeDocument, computer_guid=partition_dict["_software_release_document"]["computer_guid"])
id='_getComputeNodeDocument', else:
cache_factory='slap_cache_factory')(compute_node_reference) slap_compute_partition._software_release_document = None
return self.getPortalObject().restrictedTraverse(result)
slap_compute_node._computer_partition_list.append(
@UnrestrictedMethod slap_compute_partition
def _getComputeNodeUidByReference(self, compute_node_reference): )
"""
Get the validated compute_node with this reference.
"""
result = CachingMethod(self._getNonCachedComputeNodeUidByReference,
id='_getNonCachedComputeNodeUidByReference',
cache_factory='slap_cache_factory')(compute_node_reference)
return result
@UnrestrictedMethod for software_release_dict in computer_dict['_software_release_list']:
def _getNonCachedComputeNodeUidByReference(self, compute_node_reference): slap_software_release = SoftwareRelease(
return self.getPortalObject().portal_catalog.unrestrictedSearchResults( software_release=software_release_dict["software_release"],
portal_type='Compute Node', reference=compute_node_reference, computer_guid=software_release_dict['computer_guid'])
validation_state="validated")[0].UID 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)
def _getComputePartitionDocument(self, compute_node_reference, return dumps(slap_compute_node)
compute_partition_reference):
"""
Get the compute partition defined in an available compute_node
"""
# Related key might be nice
return self._getDocument(portal_type='Compute Partition',
reference=compute_partition_reference,
parent_uid=self._getComputeNodeUidByReference(
compute_node_reference))
def _getSoftwareInstanceForComputePartition(self, compute_node_id, def _getSoftwareInstanceForComputePartition(self, compute_node_id,
compute_partition_id, slave_reference=None): compute_partition_id, slave_reference=None):
compute_partition_document = self._getComputePartitionDocument( compute_partition_document = self.getPortalObject().portal_catalog.getComputePartitionObject(
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):
""" """
Log the compute_node status Log the compute_node status
""" """
compute_node = self._getComputeNodeDocument(compute_node_id) compute_node = self.getPortalObject().portal_catalog.getComputeNodeObject(compute_node_id)
software_installation = compute_node._getSoftwareInstallationFromUrl(url) software_installation = compute_node._getSoftwareInstallationFromUrl(url)
software_installation.setErrorStatus('while installing %s' % url) software_installation.setErrorStatus('while installing %s' % url)
......
...@@ -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