Commit 88bdb2d7 authored by Rafael Monnerat's avatar Rafael Monnerat

Slaptool Major clean up

See merge request nexedi/slapos.core!368
parents 839ac0ef 5804e551
Pipeline #20575 failed with stage
in 0 seconds
...@@ -31,6 +31,32 @@ from erp5.component.document.Item import Item ...@@ -31,6 +31,32 @@ 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 zLOG import LOG, INFO
try:
from slapos.slap.slap import \
SoftwareInstance as SlapSoftwareInstance
from slapos.util import xml2dict, loads
except ImportError:
def xml2dict(dictionary):
raise ImportError
def loads(*args):
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
...@@ -52,21 +78,18 @@ class SoftwareInstance(Item): ...@@ -52,21 +78,18 @@ class SoftwareInstance(Item):
def _getXmlAsDict(self, xml): def _getXmlAsDict(self, xml):
result_dict = {} result_dict = {}
if xml is None or xml == '': if xml:
return result_dict tree = etree.fromstring(xml)
for element in tree.iterfind('parameter'):
tree = etree.fromstring(xml) key = element.get('id').encode("UTF-8")
value = result_dict.get(key, None)
for element in tree.findall('parameter'): if value is not None:
key = element.get('id').encode("UTF-8") value = (value + ' ' + element.text)
value = result_dict.get(key, None) else:
if value is not None: value = element.text
value = (value + ' ' + element.text) if value is not None:
else: value = value.encode("UTF-8")
value = element.text result_dict[key] = value
if value is not None:
value = value.encode("UTF-8")
result_dict[key] = value
return result_dict return result_dict
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
...@@ -127,3 +150,172 @@ class SoftwareInstance(Item): ...@@ -127,3 +150,172 @@ class SoftwareInstance(Item):
if size != len(visited) + 1: if size != len(visited) + 1:
raise DisconnectedSoftwareTree raise DisconnectedSoftwareTree
return True return True
def _instanceXmlToDict(self, xml):
result_dict = {}
try:
result_dict = xml2dict(xml)
except (etree.XMLSchemaError, etree.XMLSchemaParseError, # pylint: disable=catching-non-exception
etree.XMLSchemaValidateError, etree.XMLSyntaxError): # pylint: disable=catching-non-exception
LOG('SoftwareInstance', INFO, 'Issue during parsing xml:', error=True)
return result_dict
def _asSoftwareInstance(self):
parameter_dict = self._asParameterDict()
requested_state = self.getSlapState()
if requested_state == "stop_requested":
state = 'stopped'
elif requested_state == "start_requested":
state = 'started'
elif requested_state == "destroy_requested":
state = 'destroyed'
else:
raise ValueError("Unknown slap state : %s" % requested_state)
# software instance has to define an xml parameter
xml = self._instanceXmlToDict(
parameter_dict.pop('xml'))
connection_xml = self._instanceXmlToDict(
parameter_dict.pop('connection_xml'))
filter_xml = self._instanceXmlToDict(
parameter_dict.pop('filter_xml'))
instance_guid = parameter_dict.pop('instance_guid')
software_instance = SlapSoftwareInstance(**parameter_dict)
software_instance._parameter_dict = xml
software_instance._connection_dict = connection_xml
software_instance._filter_dict = filter_xml
software_instance._requested_state = state
software_instance._instance_guid = instance_guid
return software_instance
@UnrestrictedMethod
def _asParameterDict(self, shared_instance_sql_list=None):
portal = self.getPortalObject()
compute_partition = self.getAggregateValue(portal_type="Compute Partition")
if compute_partition is None:
raise ValueError("Instance isn't allocated to call _asParamterDict")
timestamp = int(compute_partition.getModificationDate())
newtimestamp = int(self.getBangTimestamp(int(self.getModificationDate())))
if (newtimestamp > timestamp):
timestamp = newtimestamp
instance_tree = self.getSpecialiseValue()
ip_list = []
full_ip_list = []
for internet_protocol_address in compute_partition.contentValues(portal_type='Internet Protocol Address'):
# XXX - There is new values, and we must keep compatibility
address_tuple = (
internet_protocol_address.getNetworkInterface('').decode("UTF-8"),
internet_protocol_address.getIpAddress().decode("UTF-8"))
if internet_protocol_address.getGatewayIpAddress('') and \
internet_protocol_address.getNetmask(''):
address_tuple = address_tuple + (
internet_protocol_address.getGatewayIpAddress().decode("UTF-8"),
internet_protocol_address.getNetmask().decode("UTF-8"),
internet_protocol_address.getNetworkAddress('').decode("UTF-8"))
full_ip_list.append(address_tuple)
else:
ip_list.append(address_tuple)
shared_instance_list = []
if (self.getPortalType() == "Software Instance"):
append = shared_instance_list.append
if shared_instance_sql_list is None:
shared_instance_sql_list = portal.portal_catalog.unrestrictedSearchResults(
default_aggregate_uid=compute_partition.getUid(),
portal_type='Slave Instance',
validation_state="validated",
**{"slapos_item.slap_state": "start_requested"}
)
for shared_instance in shared_instance_sql_list:
shared_instance = _assertACI(shared_instance.getObject())
# XXX Use catalog to filter more efficiently
if shared_instance.getSlapState() == "start_requested":
newtimestamp = int(shared_instance.getBangTimestamp(int(shared_instance.getModificationDate())))
append({
'slave_title': shared_instance.getTitle().decode("UTF-8"),
'slap_software_type': \
shared_instance.getSourceReference().decode("UTF-8"),
'slave_reference': shared_instance.getReference().decode("UTF-8"),
'timestamp': newtimestamp,
'xml': shared_instance.getTextContent(),
'connection_xml': shared_instance.getConnectionXml(),
})
if (newtimestamp > timestamp):
timestamp = newtimestamp
return {
'instance_guid': self.getReference().decode("UTF-8"),
'instance_title': self.getTitle().decode("UTF-8"),
'root_instance_title': instance_tree.getTitle().decode("UTF-8"),
'root_instance_short_title': instance_tree.getShortTitle().decode("UTF-8"),
'xml': self.getTextContent(),
'connection_xml': self.getConnectionXml(),
'filter_xml': self.getSlaXml(),
'slap_computer_id': \
compute_partition.getParentValue().getReference().decode("UTF-8"),
'slap_computer_partition_id': \
compute_partition.getReference().decode("UTF-8"),
'slap_software_type': \
self.getSourceReference().decode("UTF-8"),
'slap_software_release_url': \
self.getUrlString().decode("UTF-8"),
'slave_instance_list': shared_instance_list,
'ip_list': ip_list,
'full_ip_list': full_ip_list,
'timestamp': "%i" % timestamp,
}
@UnrestrictedMethod
def _getInstanceTreeIpList(self):
if self.getSlapState() == 'destroy_requested':
return []
# Search instance tree
instance_tree = self.getSpecialiseValue()
while instance_tree and instance_tree.getPortalType() != "Instance Tree":
instance_tree = instance_tree.getSpecialiseValue()
ip_address_list = []
for instance in instance_tree.getSpecialiseRelatedValueList(
portal_type="Software Instance"):
compute_partition = instance.getAggregateValue(portal_type="Compute Partition")
if not compute_partition:
continue
for internet_protocol_address in compute_partition.contentValues(
portal_type='Internet Protocol Address'):
ip_address_list.append(
(internet_protocol_address.getNetworkInterface('').decode("UTF-8"),
internet_protocol_address.getIpAddress().decode("UTF-8"))
)
return ip_address_list
def _updateSucessorList(self, instance_reference_xml):
"""
Update Software Instance successor list to match the given list. If one
instance was not requested by this compute partition, it should be removed
in the successor_list of this instance.
Once the link is removed, this instance will be trashed by Garbage Collect!
instance_reference_xml contain list of title of sub-instances requested by
this instance.
"""
cache_reference = '%s-PREDLIST' % self.getReference()
if not self.isLastData(cache_reference, instance_reference_xml):
instance_reference_list = loads(instance_reference_xml)
current_successor_list = self.getSuccessorValueList(
portal_type=['Software Instance', 'Slave Instance'])
current_successor_title_list = [i.getTitle() for i in current_successor_list]
# If there are items to remove
if list(set(current_successor_title_list).difference(instance_reference_list)) != []:
successor_list = [instance.getRelativeUrl() for instance in
current_successor_list if instance.getTitle()
in instance_reference_list]
LOG('SoftwareInstance', INFO, '%s : Updating successor list to %s' % (
self.getReference(), successor_list), error=False)
self.edit(successor_list=successor_list,
comment='successor_list edited to unlink non commited instances')
self.setLastData(instance_reference_xml, key=cache_reference)
\ No newline at end of file
...@@ -6,10 +6,22 @@ ...@@ -6,10 +6,22 @@
</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>
</item> </item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>document.erp5.SoftwareInstance</string> </value> <value> <string>document.erp5.SoftwareInstance</string> </value>
...@@ -43,13 +55,28 @@ ...@@ -43,13 +55,28 @@
<item> <item>
<key> <string>workflow_history</string> </key> <key> <string>workflow_history</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAM=</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>
...@@ -62,7 +89,7 @@ ...@@ -62,7 +89,7 @@
<item> <item>
<key> <string>component_validation_workflow</string> </key> <key> <string>component_validation_workflow</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value> </value>
</item> </item>
</dictionary> </dictionary>
...@@ -71,26 +98,30 @@ ...@@ -71,26 +98,30 @@
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="3" aka="AAAAAAAAAAM="> <record id="4" aka="AAAAAAAAAAQ=">
<pickle> <pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/> <global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle> </pickle>
<pickle> <pickle>
<tuple> <dictionary>
<none/> <item>
<list> <key> <string>_log</string> </key>
<dictionary> <value>
<item> <list>
<key> <string>action</string> </key> <dictionary>
<value> <string>validate</string> </value> <item>
</item> <key> <string>action</string> </key>
<item> <value> <string>validate</string> </value>
<key> <string>validation_state</string> </key> </item>
<value> <string>validated</string> </value> <item>
</item> <key> <string>validation_state</string> </key>
</dictionary> <value> <string>validated</string> </value>
</list> </item>
</tuple> </dictionary>
</list>
</value>
</item>
</dictionary>
</pickle> </pickle>
</record> </record>
</ZopeData> </ZopeData>
...@@ -35,6 +35,10 @@ from Products.ERP5Type.Cache import DEFAULT_CACHE_SCOPE ...@@ -35,6 +35,10 @@ from Products.ERP5Type.Cache import DEFAULT_CACHE_SCOPE
import json import json
ACCESS = "#access"
ERROR = "#error"
BUILDING = "#building"
class SlapOSCacheMixin: class SlapOSCacheMixin:
# Declarative security # Declarative security
...@@ -93,7 +97,16 @@ class SlapOSCacheMixin: ...@@ -93,7 +97,16 @@ class SlapOSCacheMixin:
return data_dict return data_dict
def setAccessStatus(self, text, state=""): def setAccessStatus(self, text, state="", reindex=0):
return self._setAccessStatus("%s %s" % (ACCESS, text), state, reindex)
def setErrorStatus(self, text, state="", reindex=0):
return self._setAccessStatus("%s %s" % (ERROR, text), state, reindex)
def setBuildingStatus(self, text, state="", reindex=0):
return self._setAccessStatus("%s %s" % (BUILDING, text), state, reindex)
def _setAccessStatus(self, text, state="", reindex=0):
user_reference = self.getPortalObject().portal_membership.getAuthenticatedMember()\ user_reference = self.getPortalObject().portal_membership.getAuthenticatedMember()\
.getUserName() .getUserName()
...@@ -121,6 +134,9 @@ class SlapOSCacheMixin: ...@@ -121,6 +134,9 @@ class SlapOSCacheMixin:
cache_duration = self._getAccessStatusCacheFactory().cache_duration cache_duration = self._getAccessStatusCacheFactory().cache_duration
self._getAccessStatusPlugin().set(self._getAccessStatusCacheKey(), self._getAccessStatusPlugin().set(self._getAccessStatusCacheKey(),
DEFAULT_CACHE_SCOPE, value, cache_duration=cache_duration) DEFAULT_CACHE_SCOPE, value, cache_duration=cache_duration)
if status_changed and reindex:
self.reindexObject()
return status_changed return status_changed
def getTextAccessStatus(self): def getTextAccessStatus(self):
...@@ -134,7 +150,6 @@ class SlapOSCacheMixin: ...@@ -134,7 +150,6 @@ class SlapOSCacheMixin:
date = DateTime(data_dict['created_at']) date = DateTime(data_dict['created_at'])
return date.strftime('%Y/%m/%d %H:%M') return date.strftime('%Y/%m/%d %H:%M')
##################### #####################
# SlapOS Last Data # SlapOS Last Data
##################### #####################
...@@ -165,4 +180,7 @@ class SlapOSCacheMixin: ...@@ -165,4 +180,7 @@ class SlapOSCacheMixin:
entry = None entry = None
else: else:
entry = entry.getValue() entry = entry.getValue()
return entry return entry
\ No newline at end of file
def isLastData(self, key=None, value=None):
return self.getLastData(key) == value
\ No newline at end of file
<?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>_recorded_property_dict</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>SlapOSComputeNodeMixin</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>mixin.erp5.SlapOSComputeNodeMixin</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">AAAAAAAAAAM=</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/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<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">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<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>error_message</string> </key>
<value>
<list>
<persistent> <string encoding="base64">AAAAAAAAAAU=</string> </persistent>
</list>
</value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="5" aka="AAAAAAAAAAU=">
<pickle>
<global name="Message" module="Products.ERP5Type.Message"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default</string> </key>
<value> <string>Class ${reference} must be defined</string> </value>
</item>
<item>
<key> <string>domain</string> </key>
<value> <string>erp5_ui</string> </value>
</item>
<item>
<key> <string>mapping</string> </key>
<value>
<dictionary>
<item>
<key> <string>reference</string> </key>
<value> <string>SlapOSComputeNodeCacheMixin</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>message</string> </key>
<value> <string>Class ${reference} must be defined</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
# -*- 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 AccessControl.Permissions import access_contents_information
from AccessControl import getSecurityManager
from AccessControl import Unauthorized
try:
from slapos.slap.slap import (
ComputerPartition as SlapComputePartition,
SoftwareRelease)
from slapos.util import calculate_dict_hash
except ImportError:
# Do no prevent instance from starting
# if libs are not installed
class SlapComputePartition:
def __init__(self):
raise ImportError
class SoftwareRelease:
def __init__(self):
raise ImportError
def calculate_dict_hash(*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 SlapOSComputePartitionMixin(object):
def _registerComputePartition(self):
portal = self.getPortalObject()
computer_reference = self.getParentValue().getReference()
computer_partition_reference = self.getReference()
slap_partition = SlapComputePartition(computer_reference.decode("UTF-8"),
computer_partition_reference.decode("UTF-8"))
slap_partition._software_release_document = None
slap_partition._requested_state = 'destroyed'
slap_partition._need_modification = 0
software_instance = None
if self.getSlapState() == 'busy':
software_instance_list = portal.portal_catalog.unrestrictedSearchResults(
portal_type="Software Instance",
default_aggregate_uid=self.getUid(),
validation_state="validated",
limit=2,
)
software_instance_count = len(software_instance_list)
if software_instance_count == 1:
software_instance = _assertACI(software_instance_list[0].getObject())
elif software_instance_count > 1:
# XXX do not prevent the system to work if one partition is broken
raise NotImplementedError, "Too many instances %s linked to %s" % \
([x.path for x in software_instance_list],
self.getRelativeUrl())
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()
if state == "stop_requested":
slap_partition._requested_state = 'stopped'
if state == "start_requested":
slap_partition._requested_state = 'started'
slap_partition._software_release_document = SoftwareRelease(
software_release=software_instance.getUrlString().decode("UTF-8"),
computer_guid=computer_reference.decode("UTF-8"))
slap_partition._need_modification = 1
parameter_dict = software_instance._asParameterDict()
# software instance has to define an xml parameter
slap_partition._parameter_dict = software_instance._instanceXmlToDict(
parameter_dict.pop('xml'))
slap_partition._connection_dict = software_instance._instanceXmlToDict(
parameter_dict.pop('connection_xml'))
slap_partition._filter_dict = software_instance._instanceXmlToDict(
parameter_dict.pop('filter_xml'))
slap_partition._instance_guid = parameter_dict.pop('instance_guid')
for slave_instance_dict in parameter_dict.get("slave_instance_list", []):
if slave_instance_dict.has_key("connection_xml"):
connection_dict = software_instance._instanceXmlToDict(
slave_instance_dict.pop("connection_xml"))
slave_instance_dict.update(connection_dict)
slave_instance_dict['connection-parameter-hash'] = \
calculate_dict_hash(connection_dict)
if slave_instance_dict.has_key("xml"):
slave_instance_dict.update(software_instance._instanceXmlToDict(
slave_instance_dict.pop("xml")))
slap_partition._parameter_dict.update(parameter_dict)
return slap_partition
<?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>_recorded_property_dict</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>SlapOSComputePartitionMixin</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.SlapOSComputePartitionMixin</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">AAAAAAAAAAM=</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/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<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">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<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="Compute Node"> <portal_type id="Compute Node">
<item>SlapOSCacheMixin</item> <item>SlapOSCacheMixin</item>
<item>SlapOSComputeNodeMixin</item>
</portal_type> </portal_type>
<portal_type id="Compute Partition"> <portal_type id="Compute Partition">
<item>SlapOSCacheMixin</item> <item>SlapOSCacheMixin</item>
<item>SlapOSComputePartitionMixin</item>
</portal_type> </portal_type>
<portal_type id="Person"> <portal_type id="Person">
<item>SlapOSCacheMixin</item> <item>SlapOSCacheMixin</item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Test Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_recorded_property_dict</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>testSlapOSCloud</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>test.erp5.testSlapOSCloud</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Test 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">AAAAAAAAAAM=</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/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<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">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<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>
...@@ -11,3 +11,5 @@ for compute_partition in [x for x in compute_node.contentValues(portal_type='Com ...@@ -11,3 +11,5 @@ for compute_partition in [x for x in compute_node.contentValues(portal_type='Com
relative_url=instance.getRelativeUrl(), relative_url=instance.getRelativeUrl(),
reference=instance.getReference(), reference=instance.getReference(),
comment=state_change.kwargs.get('comment', '')) comment=state_change.kwargs.get('comment', ''))
compute_node.setErrorStatus('bang')
...@@ -52,6 +52,12 @@ ...@@ -52,6 +52,12 @@
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>state_change</string> </value> <value> <string>state_change</string> </value>
</item> </item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>script_ComputeNode_reportBang</string> </value> <value> <string>script_ComputeNode_reportBang</string> </value>
......
...@@ -3,6 +3,9 @@ instance = state_change['object'] ...@@ -3,6 +3,9 @@ instance = state_change['object']
assert instance.getPortalType() in ["Slave Instance", "Software Instance"] assert instance.getPortalType() in ["Slave Instance", "Software Instance"]
instance.edit(bang_timestamp=int(DateTime())) instance.edit(bang_timestamp=int(DateTime()))
key = "%s_bangstamp" % instance.getReference()
instance.setLastData(key, str(int(instance.getModificationDate())))
comment = state_change.kwargs['comment'] # comment is required to pass the transition comment = state_change.kwargs['comment'] # comment is required to pass the transition
if state_change.kwargs['bang_tree']: if state_change.kwargs['bang_tree']:
from Products.ZSQLCatalog.SQLCatalog import Query, NegatedQuery from Products.ZSQLCatalog.SQLCatalog import Query, NegatedQuery
......
...@@ -60,6 +60,12 @@ ...@@ -60,6 +60,12 @@
</tuple> </tuple>
</value> </value>
</item> </item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>script_RequestedInstance_bangInstanceTree</string> </value> <value> <string>script_RequestedInstance_bangInstanceTree</string> </value>
......
instance = state_change['object']
if instance.getDestinationReference() is not None:
raise ValueError("Certificate still active.")
if instance.getPortalType() != "Software Instance":
# Skip if the instance isn't a Software Instance,
# since Shared Instances cannot find the object.
return
ca = context.getPortalObject().portal_certificate_authority
certificate_dict = ca.getNewCertificate(instance.getReference())
edit_kw = {'destination_reference' : certificate_dict['id'],
'ssl_key' : certificate_dict['key'],
'ssl_certificate': certificate_dict['certificate']
}
instance.edit(**edit_kw)
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Workflow Script" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>state_change</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>script_RequestedInstance_generateCertificate</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Workflow Script</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value>
<none/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -29,4 +29,12 @@ if len(request_software_instance_list) == 1: ...@@ -29,4 +29,12 @@ if len(request_software_instance_list) == 1:
raise ValueError, "Too many instances '%s' found: %s" % (software_title, [x.path for x in request_software_instance_list]) raise ValueError, "Too many instances '%s' found: %s" % (software_title, [x.path for x in request_software_instance_list])
# Change the title # Change the title
previous_title = instance.getTitle()
instance.edit(title=software_title, activate_kw={'tag': tag}) instance.edit(title=software_title, activate_kw={'tag': tag})
# Ensure that the latest date is reset for both new and old instance
hosting = instance.getSpecialise()
for name in [previous_title, software_title]:
# reset request cache
key = '_'.join([hosting, name])
instance.setLastData({}, key=key)
...@@ -52,6 +52,12 @@ ...@@ -52,6 +52,12 @@
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>state_change</string> </value> <value> <string>state_change</string> </value>
</item> </item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>script_RequestedInstance_rename</string> </value> <value> <string>script_RequestedInstance_rename</string> </value>
......
instance = state_change['object']
portal = instance.getPortalObject()
if instance.getSslKey() is not None or instance.getSslCertificate() is not None:
instance.edit(ssl_key=None, ssl_certificate=None)
destination_reference = instance.getDestinationReference()
if destination_reference is None:
raise ValueError('No certificate')
try:
portal.portal_certificate_authority\
.revokeCertificate(instance.getDestinationReference())
except ValueError:
# Ignore already revoked certificates, as OpenSSL backend is
# non transactional, so it is ok to allow multiple tries to destruction
# even if certificate was already revoked
pass
instance.setDestinationReference(None)
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Workflow Script" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>state_change</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>script_RequestedInstance_revokeCertificate</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Workflow Script</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value>
<none/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -13,3 +13,5 @@ edit_kw = { ...@@ -13,3 +13,5 @@ edit_kw = {
instance.edit(**edit_kw) instance.edit(**edit_kw)
# Prevent storing broken XML in text content (which prevent to update parameters after) # Prevent storing broken XML in text content (which prevent to update parameters after)
context.Instance_checkConsistency(state_change) context.Instance_checkConsistency(state_change)
instance.setLastData(connection_xml)
...@@ -52,6 +52,12 @@ ...@@ -52,6 +52,12 @@
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>state_change</string> </value> <value> <string>state_change</string> </value>
</item> </item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>script_RequestedInstance_updateConnectionInformation</string> </value> <value> <string>script_RequestedInstance_updateConnectionInformation</string> </value>
......
...@@ -79,15 +79,10 @@ if (request_software_instance is None): ...@@ -79,15 +79,10 @@ if (request_software_instance is None):
id_group='slap_software_instance_reference', id_group='slap_software_instance_reference',
id_generator='uid') id_generator='uid')
new_content_kw = {}
if is_slave == True: if is_slave == True:
software_instance_portal_type = "Slave Instance" software_instance_portal_type = "Slave Instance"
else: else:
software_instance_portal_type = "Software Instance" software_instance_portal_type = "Software Instance"
certificate_dict = portal.portal_certificate_authority.getNewCertificate(reference)
new_content_kw['destination_reference'] = certificate_dict['id']
new_content_kw['ssl_key'] = certificate_dict['key']
new_content_kw['ssl_certificate'] = certificate_dict['certificate']
module = portal.getDefaultModule(portal_type="Software Instance") module = portal.getDefaultModule(portal_type="Software Instance")
request_software_instance = module.newContent( request_software_instance = module.newContent(
...@@ -95,9 +90,9 @@ if (request_software_instance is None): ...@@ -95,9 +90,9 @@ if (request_software_instance is None):
title=software_title, title=software_title,
specialise_value=instance_tree, specialise_value=instance_tree,
reference=reference, reference=reference,
activate_kw={'tag': tag}, activate_kw={'tag': tag}
**new_content_kw
) )
request_software_instance.generateCertificate()
request_software_instance.validate() request_software_instance.validate()
if software_instance_portal_type == "Software Instance": if software_instance_portal_type == "Software Instance":
# Include Certificate Login so Instance become a User # Include Certificate Login so Instance become a User
......
...@@ -52,6 +52,12 @@ ...@@ -52,6 +52,12 @@
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>state_change</string> </value> <value> <string>state_change</string> </value>
</item> </item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>script_RequesterInstance_request</string> </value> <value> <string>script_RequesterInstance_request</string> </value>
......
...@@ -17,9 +17,11 @@ ...@@ -17,9 +17,11 @@
<value> <value>
<tuple> <tuple>
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_bang</string> <string>destination/portal_workflow/instance_slap_interface_workflow/transition_bang</string>
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_generate_certificate</string>
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_report_compute_partition_error</string> <string>destination/portal_workflow/instance_slap_interface_workflow/transition_report_compute_partition_error</string>
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_request_instance</string> <string>destination/portal_workflow/instance_slap_interface_workflow/transition_request_instance</string>
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_request_transfer</string> <string>destination/portal_workflow/instance_slap_interface_workflow/transition_request_transfer</string>
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_revoke_certificate</string>
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_unallocate_partition</string> <string>destination/portal_workflow/instance_slap_interface_workflow/transition_unallocate_partition</string>
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_update_connection</string> <string>destination/portal_workflow/instance_slap_interface_workflow/transition_update_connection</string>
</tuple> </tuple>
......
...@@ -17,9 +17,11 @@ ...@@ -17,9 +17,11 @@
<value> <value>
<tuple> <tuple>
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_bang</string> <string>destination/portal_workflow/instance_slap_interface_workflow/transition_bang</string>
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_generate_certificate</string>
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_request_start</string> <string>destination/portal_workflow/instance_slap_interface_workflow/transition_request_start</string>
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_request_stop</string> <string>destination/portal_workflow/instance_slap_interface_workflow/transition_request_stop</string>
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_request_transfer</string> <string>destination/portal_workflow/instance_slap_interface_workflow/transition_request_transfer</string>
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_revoke_certificate</string>
</tuple> </tuple>
</value> </value>
</item> </item>
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
<tuple> <tuple>
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_allocate_partition</string> <string>destination/portal_workflow/instance_slap_interface_workflow/transition_allocate_partition</string>
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_bang</string> <string>destination/portal_workflow/instance_slap_interface_workflow/transition_bang</string>
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_generate_certificate</string>
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_rename</string> <string>destination/portal_workflow/instance_slap_interface_workflow/transition_rename</string>
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_report_compute_partition_error</string> <string>destination/portal_workflow/instance_slap_interface_workflow/transition_report_compute_partition_error</string>
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_request_destroy</string> <string>destination/portal_workflow/instance_slap_interface_workflow/transition_request_destroy</string>
...@@ -25,6 +26,7 @@ ...@@ -25,6 +26,7 @@
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_request_start</string> <string>destination/portal_workflow/instance_slap_interface_workflow/transition_request_start</string>
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_request_stop</string> <string>destination/portal_workflow/instance_slap_interface_workflow/transition_request_stop</string>
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_request_transfer</string> <string>destination/portal_workflow/instance_slap_interface_workflow/transition_request_transfer</string>
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_revoke_certificate</string>
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_update_connection</string> <string>destination/portal_workflow/instance_slap_interface_workflow/transition_update_connection</string>
</tuple> </tuple>
</value> </value>
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
<tuple> <tuple>
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_allocate_partition</string> <string>destination/portal_workflow/instance_slap_interface_workflow/transition_allocate_partition</string>
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_bang</string> <string>destination/portal_workflow/instance_slap_interface_workflow/transition_bang</string>
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_generate_certificate</string>
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_rename</string> <string>destination/portal_workflow/instance_slap_interface_workflow/transition_rename</string>
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_report_compute_partition_error</string> <string>destination/portal_workflow/instance_slap_interface_workflow/transition_report_compute_partition_error</string>
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_request_destroy</string> <string>destination/portal_workflow/instance_slap_interface_workflow/transition_request_destroy</string>
...@@ -25,6 +26,7 @@ ...@@ -25,6 +26,7 @@
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_request_start</string> <string>destination/portal_workflow/instance_slap_interface_workflow/transition_request_start</string>
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_request_stop</string> <string>destination/portal_workflow/instance_slap_interface_workflow/transition_request_stop</string>
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_request_transfer</string> <string>destination/portal_workflow/instance_slap_interface_workflow/transition_request_transfer</string>
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_revoke_certificate</string>
<string>destination/portal_workflow/instance_slap_interface_workflow/transition_update_connection</string> <string>destination/portal_workflow/instance_slap_interface_workflow/transition_update_connection</string>
</tuple> </tuple>
</value> </value>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Workflow Transition" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>action_name</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/workflow</string>
<string>after_script/portal_workflow/instance_slap_interface_workflow/script_RequestedInstance_generateCertificate</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>guard_permission</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>transition_generate_certificate</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Workflow Transition</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Generate Certificate</string> </value>
</item>
<item>
<key> <string>trigger_type</string> </key>
<value> <int>2</int> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Workflow Transition" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>action_name</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/workflow</string>
<string>after_script/portal_workflow/instance_slap_interface_workflow/script_RequestedInstance_revokeCertificate</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>guard_permission</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>transition_revoke_certificate</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Workflow Transition</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Revoke Certificate</string> </value>
</item>
<item>
<key> <string>trigger_type</string> </key>
<value> <int>2</int> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
Computer Model | view_capacity
Computer Network | view_compute_node_list
Computer Network | view_software_release
Compute Partition | unfiltered_tracking_list
Compute Node | compute_node_usage Compute Node | compute_node_usage
Compute Node | tracking Compute Node | tracking
Compute Node | view_capacity Compute Node | view_capacity
Compute Partition | unfiltered_tracking_list
Computer Model | view_capacity
Computer Network | view_compute_node_list
Computer Network | view_software_release
Hosting Subscription Module | view Hosting Subscription Module | view
Hosting Subscription | view Hosting Subscription | view
Instance Tree Module | view Instance Tree Module | view
...@@ -34,4 +34,4 @@ Software Instance | view_rename_and_request_stop ...@@ -34,4 +34,4 @@ Software Instance | view_rename_and_request_stop
Software Release | usable_compute_node Software Release | usable_compute_node
Software Release | usable_network Software Release | usable_network
Software Release | view_capacity Software Release | view_capacity
System Preference | slapos_system_preference System Preference | slapos_system_preference
\ No newline at end of file
mixin.erp5.SlapOSCacheMixin mixin.erp5.SlapOSCacheMixin
\ No newline at end of file mixin.erp5.SlapOSComputeNodeMixin
mixin.erp5.SlapOSComputePartitionMixin
\ No newline at end of file
...@@ -19,6 +19,8 @@ portal_alarms/slapos_stop_collect_instance ...@@ -19,6 +19,8 @@ portal_alarms/slapos_stop_collect_instance
portal_alarms/slapos_update_compute_node_capacity_scope portal_alarms/slapos_update_compute_node_capacity_scope
portal_caches/access_status_data_cache_factory portal_caches/access_status_data_cache_factory
portal_caches/access_status_data_cache_factory/volatile_cache_plugin portal_caches/access_status_data_cache_factory/volatile_cache_plugin
portal_caches/compute_node_information_cache_factory
portal_caches/compute_node_information_cache_factory/persistent_cache_plugin
portal_caches/last_stored_data_cache_factory portal_caches/last_stored_data_cache_factory
portal_caches/last_stored_data_cache_factory/volatile_cache_plugin portal_caches/last_stored_data_cache_factory/volatile_cache_plugin
product_module/compute_node product_module/compute_node
......
Computer Model | source_administration
Computer Network | source_administration
Compute Node | destination_section Compute Node | destination_section
Compute Node | source_administration Compute Node | source_administration
Computer Model | source_administration
Computer Network | source_administration
Instance Tree Module | business_application Instance Tree Module | business_application
Instance Tree | destination_section Instance Tree | destination_section
Slave Instance | aggregate Slave Instance | aggregate
......
Compute Node | SlapOSCacheMixin Compute Node | SlapOSCacheMixin
Compute Node | SlapOSComputeNodeMixin
Compute Partition | SlapOSCacheMixin Compute Partition | SlapOSCacheMixin
Compute Partition | SlapOSComputePartitionMixin
Person | SlapOSCacheMixin Person | SlapOSCacheMixin
\ No newline at end of file
...@@ -13,4 +13,5 @@ test.erp5.testSlapOSCloudConstraint ...@@ -13,4 +13,5 @@ test.erp5.testSlapOSCloudConstraint
test.erp5.testSlapOSCloudUpgrader test.erp5.testSlapOSCloudUpgrader
test.erp5.testSlapOSCloudShadow test.erp5.testSlapOSCloudShadow
test.erp5.SlapOSTestCaseMixin test.erp5.SlapOSTestCaseMixin
test.erp5.SlapOSTestCaseDefaultScenarioMixin test.erp5.SlapOSTestCaseDefaultScenarioMixin
\ No newline at end of file test.erp5.testSlapOSCloud
\ No newline at end of file
...@@ -814,7 +814,7 @@ class TestComputeNode_hasContactedRecently(SlapOSTestCaseMixinWithAbort): ...@@ -814,7 +814,7 @@ class TestComputeNode_hasContactedRecently(SlapOSTestCaseMixinWithAbort):
@simulate('ComputeNode_getCreationDate', '*args, **kwargs','return DateTime() - 32') @simulate('ComputeNode_getCreationDate', '*args, **kwargs','return DateTime() - 32')
def test_ComputeNode_hasContactedRecently_memcached(self): def test_ComputeNode_hasContactedRecently_memcached(self):
compute_node = self._makeComputeNode()[0] compute_node = self._makeComputeNode()[0]
compute_node.setAccessStatus("#access ") compute_node.setAccessStatus("")
self.tic() self.tic()
compute_node.getCreationDate = self.portal.ComputeNode_getCreationDate compute_node.getCreationDate = self.portal.ComputeNode_getCreationDate
...@@ -827,7 +827,7 @@ class TestComputeNode_hasContactedRecently(SlapOSTestCaseMixinWithAbort): ...@@ -827,7 +827,7 @@ class TestComputeNode_hasContactedRecently(SlapOSTestCaseMixinWithAbort):
compute_node = self._makeComputeNode()[0] compute_node = self._makeComputeNode()[0]
try: try:
self.pinDateTime(DateTime()-32) self.pinDateTime(DateTime()-32)
compute_node.setAccessStatus("#access ") compute_node.setAccessStatus("")
finally: finally:
self.unpinDateTime() self.unpinDateTime()
...@@ -843,7 +843,7 @@ class TestComputeNode_hasContactedRecently(SlapOSTestCaseMixinWithAbort): ...@@ -843,7 +843,7 @@ class TestComputeNode_hasContactedRecently(SlapOSTestCaseMixinWithAbort):
compute_node = self._makeComputeNode()[0] compute_node = self._makeComputeNode()[0]
try: try:
self.pinDateTime(DateTime()-32) self.pinDateTime(DateTime()-32)
compute_node.setAccessStatus("#access ") compute_node.setAccessStatus("")
finally: finally:
self.unpinDateTime() self.unpinDateTime()
...@@ -1008,7 +1008,7 @@ class TestSlapOSComputeNode_CheckState(TestCRMSkinsMixin): ...@@ -1008,7 +1008,7 @@ class TestSlapOSComputeNode_CheckState(TestCRMSkinsMixin):
try: try:
d = DateTime() - 1.1 d = DateTime() - 1.1
self.pinDateTime(d) self.pinDateTime(d)
compute_node.setAccessStatus("#access ") compute_node.setAccessStatus("")
finally: finally:
self.unpinDateTime() self.unpinDateTime()
...@@ -1045,7 +1045,7 @@ class TestSlapOSComputeNode_CheckState(TestCRMSkinsMixin): ...@@ -1045,7 +1045,7 @@ class TestSlapOSComputeNode_CheckState(TestCRMSkinsMixin):
try: try:
self.pinDateTime(DateTime()-1.1) self.pinDateTime(DateTime()-1.1)
compute_node.setAccessStatus("#access ") compute_node.setAccessStatus("")
finally: finally:
self.unpinDateTime() self.unpinDateTime()
...@@ -1275,7 +1275,7 @@ class TestSlapOSHasError(SlapOSTestCaseMixin): ...@@ -1275,7 +1275,7 @@ class TestSlapOSHasError(SlapOSTestCaseMixin):
self._makeComputeNode() self._makeComputeNode()
self._makeComputePartitionList() self._makeComputePartitionList()
instance.setAccessStatus("#error ") instance.setErrorStatus("")
self.assertEqual(instance.SoftwareInstance_hasReportedError(), None) self.assertEqual(instance.SoftwareInstance_hasReportedError(), None)
...@@ -1283,7 +1283,7 @@ class TestSlapOSHasError(SlapOSTestCaseMixin): ...@@ -1283,7 +1283,7 @@ class TestSlapOSHasError(SlapOSTestCaseMixin):
self.assertEqual(str(instance.SoftwareInstance_hasReportedError()), '#error ') self.assertEqual(str(instance.SoftwareInstance_hasReportedError()), '#error ')
instance.setAccessStatus("#access ") instance.setAccessStatus("")
self.assertEqual(instance.SoftwareInstance_hasReportedError(), None) self.assertEqual(instance.SoftwareInstance_hasReportedError(), None)
def test_SoftwareInstallation_hasReportedError(self): def test_SoftwareInstallation_hasReportedError(self):
...@@ -1298,14 +1298,14 @@ class TestSlapOSHasError(SlapOSTestCaseMixin): ...@@ -1298,14 +1298,14 @@ class TestSlapOSHasError(SlapOSTestCaseMixin):
error_date = DateTime() error_date = DateTime()
try: try:
self.pinDateTime(error_date) self.pinDateTime(error_date)
installation.setAccessStatus("#error ") installation.setErrorStatus("")
finally: finally:
self.unpinDateTime() self.unpinDateTime()
self.assertEqual( self.assertEqual(
rfc1123_date(installation.SoftwareInstallation_hasReportedError()), rfc1123_date(installation.SoftwareInstallation_hasReportedError()),
rfc1123_date(error_date)) rfc1123_date(error_date))
installation.setAccessStatus("#building ") installation.setBuildingStatus("")
self.assertEqual(installation.SoftwareInstallation_hasReportedError(), None) self.assertEqual(installation.SoftwareInstallation_hasReportedError(), None)
...@@ -1352,7 +1352,7 @@ class TestSlapOSHasError(SlapOSTestCaseMixin): ...@@ -1352,7 +1352,7 @@ class TestSlapOSHasError(SlapOSTestCaseMixin):
"slapos-crm-instance-tree-instance-state.notification"), "slapos-crm-instance-tree-instance-state.notification"),
instance_tree.InstanceTree_checkSoftwareInstanceState()) instance_tree.InstanceTree_checkSoftwareInstanceState())
instance.setAccessStatus("#access ") instance.setAccessStatus("")
self.assertEqual(None, self.assertEqual(None,
instance_tree.InstanceTree_checkSoftwareInstanceState()) instance_tree.InstanceTree_checkSoftwareInstanceState())
...@@ -1455,7 +1455,7 @@ class TestSlapOSHasError(SlapOSTestCaseMixin): ...@@ -1455,7 +1455,7 @@ class TestSlapOSHasError(SlapOSTestCaseMixin):
instance.requestInstance(**kw) instance.requestInstance(**kw)
self.tic() self.tic()
instance.setAccessStatus("#access ") instance.setAccessStatus("")
self.assertEqual( self.assertEqual(
'Visited by InstanceTree_createSupportRequestEvent %s %s' % \ 'Visited by InstanceTree_createSupportRequestEvent %s %s' % \
...@@ -1490,7 +1490,7 @@ class TestSlapOSHasError(SlapOSTestCaseMixin): ...@@ -1490,7 +1490,7 @@ class TestSlapOSHasError(SlapOSTestCaseMixin):
self._makeComputePartitionList() self._makeComputePartitionList()
instance.setAggregateValue(self.compute_node.partition1) instance.setAggregateValue(self.compute_node.partition1)
instance.setAccessStatus("#error ") instance.setErrorStatus("")
self.assertEqual( self.assertEqual(
None, None,
instance_tree.InstanceTree_checkSoftwareInstanceState()) instance_tree.InstanceTree_checkSoftwareInstanceState())
......
...@@ -17,30 +17,29 @@ def getComputeNodeReferenceAndUserId(item): ...@@ -17,30 +17,29 @@ def getComputeNodeReferenceAndUserId(item):
compute_node = partition.getParentValue() compute_node = partition.getParentValue()
if compute_node is not None and compute_node.getValidationState() == 'validated': if compute_node is not None and compute_node.getValidationState() == 'validated':
return compute_node.getReference(), compute_node.getUserId() return compute_node, compute_node.getReference(), compute_node.getUserId()
return None, None return None, None, None
def Item_activateFillComputeNodeInformationCache(state_change): def Item_activateFillComputeNodeInformationCache(state_change):
item = state_change['object'] item = state_change['object']
portal = item.getPortalObject() portal = item.getPortalObject()
compute_node_reference, user_id = getComputeNodeReferenceAndUserId(item) compute_node, compute_node_reference, user_id = getComputeNodeReferenceAndUserId(item)
if compute_node_reference is None: if compute_node is None:
return None return None
if user_id is None: if user_id is None:
return None return None
user = portal.acl_users.getUserById(user_id) user = portal.acl_users.getUserById(user_id)
if user is None: if user is None:
raise ValueError("User %s not found" % user_id) raise ValueError("User %s not found" % user_id)
sm = getSecurityManager() sm = getSecurityManager()
try: try:
newSecurityManager(None, user) newSecurityManager(None, user)
portal.portal_slap._activateFillComputeNodeInformationCache( compute_node._activateFillComputeNodeInformationCache(
compute_node_reference, compute_node_reference) compute_node_reference)
finally: finally:
setSecurityManager(sm) setSecurityManager(sm)
......
...@@ -78,16 +78,16 @@ class TestSlapOSSlapToolgetFullComputerInformation(TestSlapOSSlapToolMixin): ...@@ -78,16 +78,16 @@ class TestSlapOSSlapToolgetFullComputerInformation(TestSlapOSSlapToolMixin):
self.tic() self.tic()
self.login(self.compute_node_user_id) self.login(self.compute_node_user_id)
self.portal_slap.getFullComputerInformation(self.compute_node_id)
# First access. # First access.
# Cache has been filled by interaction workflow # Cache has been filled by interaction workflow
# (luckily, it seems the cache is filled after everything is indexed) # (luckily, it seems the cache is filled after everything is indexed)
response = self.portal_slap.getFullComputerInformation(self.compute_node_id) response = self.portal_slap.getFullComputerInformation(self.compute_node_id)
self.commit() self.commit()
first_etag = self.portal_slap._calculateRefreshEtag() first_etag = self.compute_node._calculateRefreshEtag()
first_body_fingerprint = hashData( first_body_fingerprint = hashData(
self.portal_slap._getCacheComputeNodeInformation(self.compute_node_id, self.compute_node._getCacheComputeNodeInformation(self.compute_node_id)
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)
...@@ -120,10 +120,9 @@ class TestSlapOSSlapToolgetFullComputerInformation(TestSlapOSSlapToolMixin): ...@@ -120,10 +120,9 @@ class TestSlapOSSlapToolgetFullComputerInformation(TestSlapOSSlapToolMixin):
self.commit() self.commit()
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)
second_etag = self.portal_slap._calculateRefreshEtag() second_etag = self.compute_node._calculateRefreshEtag()
second_body_fingerprint = hashData( second_body_fingerprint = hashData(
self.portal_slap._getCacheComputeNodeInformation(self.compute_node_id, self.compute_node._getCacheComputeNodeInformation(self.compute_node_id)
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
...@@ -154,10 +153,9 @@ class TestSlapOSSlapToolgetFullComputerInformation(TestSlapOSSlapToolMixin): ...@@ -154,10 +153,9 @@ class TestSlapOSSlapToolgetFullComputerInformation(TestSlapOSSlapToolMixin):
# Check that the result is stable, as the indexation timestamp is not changed yet # Check that the result is stable, as the indexation timestamp is not changed yet
current_activity_count = len(self.portal.portal_activities.getMessageList()) current_activity_count = len(self.portal.portal_activities.getMessageList())
# Edition does not impact the etag # Edition does not impact the etag
self.assertEqual(second_etag, self.portal_slap._calculateRefreshEtag()) self.assertEqual(second_etag, self.compute_node._calculateRefreshEtag())
third_body_fingerprint = hashData( third_body_fingerprint = hashData(
self.portal_slap._getCacheComputeNodeInformation(self.compute_node_id, self.compute_node._getCacheComputeNodeInformation(self.compute_node_id)
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)
...@@ -177,7 +175,7 @@ class TestSlapOSSlapToolgetFullComputerInformation(TestSlapOSSlapToolMixin): ...@@ -177,7 +175,7 @@ class TestSlapOSSlapToolgetFullComputerInformation(TestSlapOSSlapToolMixin):
self.commit() self.commit()
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)
third_etag = self.portal_slap._calculateRefreshEtag() third_etag = self.compute_node._calculateRefreshEtag()
self.assertNotEqual(second_etag, third_etag) self.assertNotEqual(second_etag, third_etag)
self.assertEqual(third_etag, response.headers.get('etag')) self.assertEqual(third_etag, response.headers.get('etag'))
self.assertEqual(third_body_fingerprint, hashData(response.body)) self.assertEqual(third_body_fingerprint, hashData(response.body))
...@@ -192,12 +190,11 @@ class TestSlapOSSlapToolgetFullComputerInformation(TestSlapOSSlapToolMixin): ...@@ -192,12 +190,11 @@ class TestSlapOSSlapToolgetFullComputerInformation(TestSlapOSSlapToolMixin):
# Check that the result is stable, as the indexation timestamp is not changed yet # Check that the result is stable, as the indexation timestamp is not changed yet
current_activity_count = len(self.portal.portal_activities.getMessageList()) current_activity_count = len(self.portal.portal_activities.getMessageList())
# Edition does not impact the etag # Edition does not impact the etag
self.assertEqual(third_etag, self.portal_slap._calculateRefreshEtag()) self.assertEqual(third_etag, self.compute_node._calculateRefreshEtag())
# 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.portal_slap._getCacheComputeNodeInformation(self.compute_node_id, self.compute_node._getCacheComputeNodeInformation(self.compute_node_id)
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()
...@@ -217,10 +214,9 @@ class TestSlapOSSlapToolgetFullComputerInformation(TestSlapOSSlapToolMixin): ...@@ -217,10 +214,9 @@ class TestSlapOSSlapToolgetFullComputerInformation(TestSlapOSSlapToolMixin):
self.commit() self.commit()
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)
fourth_etag = self.portal_slap._calculateRefreshEtag() fourth_etag = self.compute_node._calculateRefreshEtag()
fourth_body_fingerprint = hashData( fourth_body_fingerprint = hashData(
self.portal_slap._getCacheComputeNodeInformation(self.compute_node_id, self.compute_node._getCacheComputeNodeInformation(self.compute_node_id)
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
...@@ -733,43 +729,9 @@ class TestSlapOSSlapToolComputeNodeAccess(TestSlapOSSlapToolMixin): ...@@ -733,43 +729,9 @@ class TestSlapOSSlapToolComputeNodeAccess(TestSlapOSSlapToolMixin):
response = self.portal_slap.computerBang(self.compute_node_id, response = self.portal_slap.computerBang(self.compute_node_id,
error_log) error_log)
self.assertEqual('None', response) self.assertEqual('None', response)
created_at = rfc1123_date(DateTime()) # We do not assert getComputerStatus on this test, since
since = created_at # the change of the timestamp is part of reportComputeNodeBang
response = self.portal_slap.getComputerStatus(self.compute_node_id)
# check returned XML
xml_fp = StringIO.StringIO()
xml.dom.ext.PrettyPrint(xml.dom.ext.reader.Sax.FromXml(response.body),
stream=xml_fp)
xml_fp.seek(0)
got_xml = xml_fp.read()
expected_xml = """\
<?xml version='1.0' encoding='UTF-8'?>
<marshal>
<dictionary id='i2'>
<string>created_at</string>
<string>%(created_at)s</string>
<string>no_data_since_15_minutes</string>
<int>0</int>
<string>no_data_since_5_minutes</string>
<int>0</int>
<string>since</string>
<string>%(since)s</string>
<string>state</string>
<string/>
<string>text</string>
<string>#error bang</string>
<string>user</string>
<string>%(compute_node_id)s</string>
</dictionary>
</marshal>
""" % dict(
created_at=created_at,
since=since,
compute_node_id=self.compute_node_id,
)
self.assertEqual(expected_xml, got_xml,
'\n'.join([q for q in difflib.unified_diff(expected_xml.split('\n'), got_xml.split('\n'))]))
self.assertComputeNodeBangSimulator((), {'comment': error_log}) self.assertComputeNodeBangSimulator((), {'comment': error_log})
finally: finally:
if os.path.exists(self.compute_node_bang_simulator): if os.path.exists(self.compute_node_bang_simulator):
...@@ -2635,43 +2597,9 @@ class TestSlapOSSlapToolPersonAccess(TestSlapOSSlapToolMixin): ...@@ -2635,43 +2597,9 @@ class TestSlapOSSlapToolPersonAccess(TestSlapOSSlapToolMixin):
response = self.portal_slap.computerBang(self.compute_node_id, response = self.portal_slap.computerBang(self.compute_node_id,
error_log) error_log)
self.assertEqual('None', response) self.assertEqual('None', response)
created_at = rfc1123_date(DateTime()) # We do not assert getComputerStatus on this test, since
since = created_at # the change of the timestamp is part of reportComputeNodeBang
response = self.portal_slap.getComputerStatus(self.compute_node_id)
# check returned XML
xml_fp = StringIO.StringIO()
xml.dom.ext.PrettyPrint(xml.dom.ext.reader.Sax.FromXml(response.body),
stream=xml_fp)
xml_fp.seek(0)
got_xml = xml_fp.read()
expected_xml = """\
<?xml version='1.0' encoding='UTF-8'?>
<marshal>
<dictionary id='i2'>
<string>created_at</string>
<string>%(created_at)s</string>
<string>no_data_since_15_minutes</string>
<int>0</int>
<string>no_data_since_5_minutes</string>
<int>0</int>
<string>since</string>
<string>%(since)s</string>
<string>state</string>
<string/>
<string>text</string>
<string>#error bang</string>
<string>user</string>
<string>%(person_reference)s</string>
</dictionary>
</marshal>
""" % dict(
created_at=created_at,
since=since,
person_reference=self.person_reference,
)
self.assertEqual(expected_xml, got_xml,
'\n'.join([q for q in difflib.unified_diff(expected_xml.split('\n'), got_xml.split('\n'))]))
self.assertComputeNodeBangSimulator((), {'comment': error_log}) self.assertComputeNodeBangSimulator((), {'comment': error_log})
finally: finally:
if os.path.exists(self.compute_node_bang_simulator): if os.path.exists(self.compute_node_bang_simulator):
......
portal_caches/last_stored_data_cache_factory portal_caches/last_stored_data_cache_factory
portal_caches/last_stored_data_cache_factory/volatile_cache_plugin portal_caches/last_stored_data_cache_factory/volatile_cache_plugin
\ No newline at end of file portal_caches/compute_node_information_cache_factory
portal_caches/compute_node_information_cache_factory/persistent_cache_plugin
\ No newline at end of file
portal_caches/compute_node_information_cache_factory
portal_caches/compute_node_information_cache_factory/persistent_cache_plugin
portal_caches/slap_cache_factory portal_caches/slap_cache_factory
portal_caches/slap_cache_factory/persistent_cache_plugin portal_caches/slap_cache_factory/persistent_cache_plugin
web_site_module/slapos_hateoas web_site_module/slapos_hateoas
......
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