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

Slaptool Major clean up

See merge request nexedi/slapos.core!368
parents 839ac0ef 5804e551
...@@ -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,12 +78,9 @@ class SoftwareInstance(Item): ...@@ -52,12 +78,9 @@ 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) tree = etree.fromstring(xml)
for element in tree.iterfind('parameter'):
for element in tree.findall('parameter'):
key = element.get('id').encode("UTF-8") key = element.get('id').encode("UTF-8")
value = result_dict.get(key, None) value = result_dict.get(key, None)
if value is not None: if value is not None:
...@@ -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,13 +98,15 @@ ...@@ -71,13 +98,15 @@
</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>
<key> <string>_log</string> </key>
<value>
<list> <list>
<dictionary> <dictionary>
<item> <item>
...@@ -90,7 +119,9 @@ ...@@ -90,7 +119,9 @@
</item> </item>
</dictionary> </dictionary>
</list> </list>
</tuple> </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
##################### #####################
...@@ -166,3 +181,6 @@ class SlapOSCacheMixin: ...@@ -166,3 +181,6 @@ class SlapOSCacheMixin:
else: else:
entry = entry.getValue() entry = entry.getValue()
return entry return entry
def isLastData(self, key=None, value=None):
return self.getLastData(key) == value
\ No newline at end of file
# -*- 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 Products.ERP5Type.Cache import DEFAULT_CACHE_SCOPE
from AccessControl import Unauthorized
from AccessControl.Permissions import access_contents_information
from AccessControl import getSecurityManager
from Products.ERP5Type.UnrestrictedMethod import UnrestrictedMethod
from Products.ERP5Type.tests.utils import DummyMailHostMixin
from OFS.Traversable import NotFound
import time
from lxml import etree
from zLOG import LOG, INFO
try:
from slapos.slap.slap import (
Computer as ComputeNode,
ComputerPartition as SlapComputePartition,
SoftwareRelease)
from slapos.util import xml2dict, dumps
except ImportError:
# Do no prevent instance from starting
# 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):
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):
def _getCachePlugin(self):
return self.getPortalObject().portal_caches\
.getRamCacheRoot().get('compute_node_information_cache_factory')\
.getCachePluginList()[0]
@UnrestrictedMethod
def _getSoftwareReleaseValueList(self):
"""Returns list of Software Releases documents for compute_node"""
portal = self.getPortalObject()
software_release_list = []
for software_installation in portal.portal_catalog.unrestrictedSearchResults(
portal_type='Software Installation',
default_aggregate_uid=self.getUid(),
validation_state='validated',
):
software_installation = _assertACI(software_installation.getObject())
software_release_response = SoftwareRelease(
software_release=software_installation.getUrlString().decode('UTF-8'),
computer_guid=self.getReference().decode('UTF-8'))
if software_installation.getSlapState() == 'destroy_requested':
software_release_response._requested_state = 'destroyed'
else:
software_release_response._requested_state = 'available'
known_state = software_installation.getTextAccessStatus()
if known_state.startswith("#access"):
software_release_response._known_state = 'available'
elif known_state.startswith("#building"):
software_release_response._known_state = 'building'
else:
software_release_response._known_state = 'error'
software_release_list.append(software_release_response)
return software_release_list
def _getCacheComputeNodeInformation(self, user):
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 = []
slap_compute_node._software_release_list = self._getSoftwareReleaseValueList()
unrestrictedSearchResults = self.getPortalObject().portal_catalog.unrestrictedSearchResults
compute_partition_list = unrestrictedSearchResults(
parent_uid=self.getUid(),
validation_state="validated",
portal_type="Compute Partition"
)
self._calculateSlapComputeNodeInformation(slap_compute_node, compute_partition_list)
return dumps(slap_compute_node)
def _activateFillComputeNodeInformationCache(self, user):
tag = 'compute_node_information_cache_fill_%s_%s' % (self.getReference(), user)
if self.getPortalObject().portal_activities.countMessageWithTag(tag) == 0:
self.activate(activity='SQLQueue', priority=2, tag=tag)._fillComputeNodeInformationCache(user)
def _fillComputeNodeInformationCache(self, user):
key = '%s_%s' % (self.getReference(), user)
try:
self._getCachePlugin().set(key, DEFAULT_CACHE_SCOPE,
dict (
time=time.time(),
refresh_etag=self._calculateRefreshEtag(),
data=self._getCacheComputeNodeInformation(user),
),
cache_duration=self.getPortalObject().portal_caches\
.getRamCacheRoot().get('compute_node_information_cache_factory'\
).cache_duration
)
except (Unauthorized, IndexError):
# XXX: Unauthorized hack. Race condition of not ready setup delivery which provides
# security information shall not make this method fail, as it will be
# called later anyway
# Note: IndexError ignored, as it happend in case if full reindex is
# called on site
pass
def _calculateRefreshEtag(self):
# check max indexation timestamp
# it is unlikely to get an empty catalog
last_indexed_entry = self.getPortalObject().portal_catalog(
select_list=['indexation_timestamp'],
portal_type=['Compute Node', 'Compute Partition',
'Software Instance', 'Slave Instance',
'Software Installation'],
sort_on=[('indexation_timestamp', 'DESC')],
limit=1,
)[0]
return '%s_%s' % (last_indexed_entry.uid,
last_indexed_entry.indexation_timestamp)
def _isTestRun(self):
if self.REQUEST.get('disable_isTestRun', False):
return False
if issubclass(self.getPortalObject().MailHost.__class__, DummyMailHostMixin) \
or self.REQUEST.get('test_list'):
return True
return False
def _getComputeNodeInformation(self, user, refresh_etag):
portal = self.getPortalObject()
user_document = _assertACI(portal.portal_catalog.unrestrictedGetResultValue(
reference=user, portal_type=['Person', 'Compute Node', 'Software Instance']))
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 not self._isTestRun():
cache_plugin = self._getCachePlugin()
key = '%s_%s' % (self.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
self._activateFillComputeNodeInformationCache(user)
return cached_dict['data'], cached_etag
else:
self._activateFillComputeNodeInformationCache(user)
self.REQUEST.response.setStatus(503)
return self.REQUEST.response, None
else:
return self._getCacheComputeNodeInformation(user), None
else:
slap_compute_node._software_release_list = []
if user_type == 'Software Instance':
compute_partition_list = self.contentValues(
portal_type="Compute Partition",
checked_permission="View")
else:
compute_partition_list = self.getPortalObject().portal_catalog.unrestrictedSearchResults(
parent_uid=self.getUid(),
validation_state="validated",
portal_type="Compute Partition")
self._calculateSlapComputeNodeInformation(slap_compute_node, compute_partition_list)
return dumps(slap_compute_node), None
def _calculateSlapComputeNodeInformation(self, slap_compute_node, compute_partition_list):
if len(compute_partition_list) == 0:
return
unrestrictedSearchResults = self.getPortalObject().portal_catalog.unrestrictedSearchResults
compute_partition_uid_list = [x.uid for x in compute_partition_list]
grouped_software_instance_list = unrestrictedSearchResults(
portal_type="Software Instance",
default_aggregate_uid=compute_partition_uid_list,
validation_state="validated",
group_by_list=['default_aggregate_uid'],
select_list=['default_aggregate_uid', 'count(*)']
)
slave_software_instance_list = unrestrictedSearchResults(
default_aggregate_uid=compute_partition_uid_list,
portal_type='Slave Instance',
validation_state="validated",
select_list=['default_aggregate_uid'],
**{"slapos_item.slap_state": "start_requested"}
)
for compute_partition in compute_partition_list:
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):
software_instance_list = software_instance_list + software_instance_list
slap_compute_node._computer_partition_list.append(
self._getSlapPartitionByPackingList(
_assertACI(compute_partition.getObject()),
software_instance_list,
[x for x in slave_software_instance_list if (x.default_aggregate_uid == compute_partition.getUid())]
)
)
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('SlapOSComputeNodeCacheMixin', INFO, 'Issue during parsing xml:', error=True)
return result_dict
def _getSlapPartitionByPackingList(self, compute_partition_document,
software_instance_list,
shared_instance_sql_list):
compute_node = compute_partition_document
while compute_node.getPortalType() != 'Compute Node':
compute_node = compute_node.getParentValue()
compute_node_id = compute_node.getReference().decode("UTF-8")
slap_partition = SlapComputePartition(compute_node_id,
compute_partition_document.getReference().decode("UTF-8"))
slap_partition._software_release_document = None
slap_partition._requested_state = 'destroyed'
slap_partition._need_modification = 0
software_instance = None
if compute_partition_document.getSlapState() == 'busy':
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 linked to %s" % \
compute_partition_document.getRelativeUrl()
if software_instance is not None:
state = software_instance.getSlapState()
if state == "stop_requested":
slap_partition._requested_state = 'stopped'
if state == "start_requested":
slap_partition._requested_state = 'started'
slap_partition._access_status = software_instance.getTextAccessStatus()
slap_partition._software_release_document = SoftwareRelease(
software_release=software_instance.getUrlString().decode("UTF-8"),
computer_guid=compute_node_id)
slap_partition._need_modification = 1
parameter_dict = software_instance._asParameterDict(
shared_instance_sql_list=shared_instance_sql_list
)
# software instance has to define an xml parameter
slap_partition._parameter_dict = self._instanceXmlToDict(
parameter_dict.pop('xml'))
slap_partition._connection_dict = self._instanceXmlToDict(
parameter_dict.pop('connection_xml'))
slap_partition._filter_dict = self._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"):
slave_instance_dict.update(self._instanceXmlToDict(
slave_instance_dict.pop("connection_xml")))
if slave_instance_dict.has_key("xml"):
slave_instance_dict.update(self._instanceXmlToDict(
slave_instance_dict.pop("xml")))
slap_partition._parameter_dict.update(parameter_dict)
return slap_partition
def _getSoftwareInstallationFromUrl(self, url):
software_installation_list = self.getPortalObject().portal_catalog.unrestrictedSearchResults(
portal_type='Software Installation',
default_aggregate_uid=self.getUid(),
validation_state='validated',
limit=2,
url_string={'query': url, 'key': 'ExactMatch'},
)
l = len(software_installation_list)
if l == 1:
return _assertACI(software_installation_list[0].getObject())
elif l == 0:
raise NotFound('No software release %r found on compute_node %r' % (url,
self.getReference()))
else:
raise ValueError('Wrong list of software releases on %r: %s' % (
self.getReference(), ', '.join([q.getRelativeUrl() for q \
in software_installation_list])
))
<?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>
......
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 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 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 erp5.component.test.SlapOSTestCaseMixin import SlapOSTestCaseMixin
from DateTime import DateTime
from App.Common import rfc1123_date
import json
import hashlib
from binascii import hexlify
def hashData(data):
return hexlify(hashlib.sha1(data).digest())
class TestSlapOSCloudSlapOSCacheMixin(
SlapOSTestCaseMixin):
def afterSetUp(self):
SlapOSTestCaseMixin.afterSetUp(self)
self.pinDateTime(DateTime())
self._makeComputeNode()
self._makeComplexComputeNode(with_slave=True)
self.tic()
def beforeTearDown(self):
self.unpinDateTime()
self._cleaupREQUEST()
def test_LastData(self):
value = "XXX"
self.assertEqual(None, self.compute_node.getLastData())
self.compute_node.setLastData(value)
self.assertEqual(value, self.compute_node.getLastData())
key = "OI"
value_key = "ABC"
self.assertEqual(None, self.compute_node.getLastData(key))
self.compute_node.setLastData(value_key, key=key)
self.assertEqual(value_key, self.compute_node.getLastData(key))
def test_getAccessStatus_no_data(self):
since = rfc1123_date(DateTime())
created_at = since
def getBaseExpectedDict(doc):
return {
"user": "SlapOS Master",
'created_at': '%s' % created_at,
'since': '%s' % since,
'state': "",
"text": "#error no data found for %s" % doc.getReference(),
"no_data": 1
}
# Check Compute Node
self.assertEqual(self.compute_node._getCachedAccessInfo(), None)
self.assertEqual(self.compute_node.getAccessStatus(),
getBaseExpectedDict(self.compute_node))
# Check Software Installation
installation = self.start_requested_software_installation
self.assertEqual(installation._getCachedAccessInfo(), None)
self.assertEqual(installation.getAccessStatus(),
getBaseExpectedDict(installation))
partition = self.compute_node.partition1
self.assertEqual(partition._getCachedAccessInfo(), None)
self.assertEqual(partition.getAccessStatus(),
getBaseExpectedDict(partition))
instance = self.start_requested_software_instance
self.assertEqual(instance._getCachedAccessInfo(), None)
self.assertEqual(instance.getAccessStatus(),
getBaseExpectedDict(instance))
def test_setAccessStatus(self):
since = rfc1123_date(DateTime())
created_at = since
def getExpectedCacheDict(doc):
return json.dumps({
"user": "ERP5TypeTestCase",
'created_at': '%s' % created_at,
'since': '%s' % since,
'state': "",
"text": "#access TEST123 %s" % doc.getUid()
})
def getBaseExpectedDict(doc):
return {
"user": "ERP5TypeTestCase",
'created_at': '%s' % created_at,
u'since': u'%s' % since,
u'state': u"",
u"text": u"#access TEST123 %s" % doc.getUid(),
'no_data_since_15_minutes': 0,
'no_data_since_5_minutes': 0
}
# Check Compute Node
self.assertEqual(True,
self.compute_node.setAccessStatus("TEST123 %s" % self.compute_node.getUid()))
self.assertEqual(self.compute_node._getCachedAccessInfo(),
getExpectedCacheDict(self.compute_node))
self.assertEqual(self.compute_node.getAccessStatus(),
getBaseExpectedDict(self.compute_node))
self.assertEqual(False,
self.compute_node.setAccessStatus("TEST123 %s" % self.compute_node.getUid()))
# Check Software Installation
installation = self.start_requested_software_installation
self.assertEqual(True,
installation.setAccessStatus("TEST123 %s" % installation.getUid()))
self.assertEqual(installation._getCachedAccessInfo(),
getExpectedCacheDict(installation))
self.assertEqual(installation.getAccessStatus(),
getBaseExpectedDict(installation))
self.assertEqual(False,
installation.setAccessStatus("TEST123 %s" % installation.getUid()))
# Compute Partition
partition = self.compute_node.partition1
self.assertEqual(True,
partition.setAccessStatus("TEST123 %s" % partition.getUid()))
self.assertEqual(partition._getCachedAccessInfo(),
getExpectedCacheDict(partition))
self.assertEqual(partition.getAccessStatus(),
getBaseExpectedDict(partition))
self.assertEqual(False,
partition.setAccessStatus("TEST123 %s" % partition.getUid()))
# Software Instance
instance = self.start_requested_software_instance
# This is already called from elsewhere, so it actually changed
self.assertEqual(True,
instance.setAccessStatus("TEST123 %s" % instance.getUid()))
self.assertEqual(instance._getCachedAccessInfo(),
getExpectedCacheDict(instance))
self.assertEqual(instance.getAccessStatus(),
getBaseExpectedDict(instance))
self.assertEqual(False,
instance.setAccessStatus("TEST123 %s" % instance.getUid()))
def test_setAccessStatus_reindex(self):
since = rfc1123_date(DateTime())
created_at = since
def getExpectedCacheDict(doc):
return json.dumps({
"user": "ERP5TypeTestCase",
'created_at': '%s' % created_at,
'since': '%s' % since,
'state': "",
"text": "#access TEST123 %s" % doc.getUid()
})
def getBaseExpectedDict(doc):
return {
"user": "ERP5TypeTestCase",
'created_at': '%s' % created_at,
u'since': u'%s' % since,
u'state': u"",
u"text": u"#access TEST123 %s" % doc.getUid(),
'no_data_since_15_minutes': 0,
'no_data_since_5_minutes': 0
}
self.tic()
# Software Instance
instance = self.start_requested_software_instance
indexation_timestamp = self.portal.portal_catalog(
uid=instance.getUid(),
select_dict={"indexation_timestamp": None}
)[0].indexation_timestamp
# This is already called from elsewhere, so it actually changed
self.assertEqual(True,
instance.setAccessStatus("TEST123 %s" % instance.getUid()))
self.assertEqual(instance._getCachedAccessInfo(),
getExpectedCacheDict(instance))
self.assertEqual(instance.getAccessStatus(),
getBaseExpectedDict(instance))
self.tic()
new_indexation_timestamp = self.portal.portal_catalog(
uid=instance.getUid(),
select_dict={"indexation_timestamp": None}
)[0].indexation_timestamp
self.assertEqual(new_indexation_timestamp, indexation_timestamp)
self.assertEqual(False,
instance.setAccessStatus("TEST123 %s" % instance.getUid()))
self.tic()
new_indexation_timestamp = self.portal.portal_catalog(
uid=instance.getUid(),
select_dict={"indexation_timestamp": None}
)[0].indexation_timestamp
self.assertEqual(new_indexation_timestamp, indexation_timestamp)
self.assertEqual(False,
instance.setAccessStatus("TEST123 %s" % instance.getUid(), reindex=1))
self.tic()
new_indexation_timestamp = self.portal.portal_catalog(
uid=instance.getUid(),
select_dict={"indexation_timestamp": None}
)[0].indexation_timestamp
self.assertEqual(new_indexation_timestamp, indexation_timestamp)
self.assertEqual(True,
instance.setErrorStatus("TEST123 %s" % instance.getUid(), reindex=1))
self.tic()
new_indexation_timestamp = self.portal.portal_catalog(
uid=instance.getUid(),
select_dict={"indexation_timestamp": None}
)[0].indexation_timestamp
self.assertNotEqual(new_indexation_timestamp, indexation_timestamp)
def test_setErrorStatus(self):
since = rfc1123_date(DateTime())
created_at = since
def getExpectedCacheDict(doc):
return json.dumps({
"user": "ERP5TypeTestCase",
'created_at': '%s' % created_at,
'since': '%s' % since,
'state': "",
"text": "#error TEST123 %s" % doc.getUid()
})
def getBaseExpectedDict(doc):
return {
"user": "ERP5TypeTestCase",
'created_at': '%s' % created_at,
u'since': u'%s' % since,
u'state': u"",
u"text": u"#error TEST123 %s" % doc.getUid(),
'no_data_since_15_minutes': 0,
'no_data_since_5_minutes': 0
}
# Check Compute Node
self.assertEqual(True,
self.compute_node.setErrorStatus("TEST123 %s" % self.compute_node.getUid()))
self.assertEqual(self.compute_node._getCachedAccessInfo(),
getExpectedCacheDict(self.compute_node))
self.assertEqual(self.compute_node.getAccessStatus(),
getBaseExpectedDict(self.compute_node))
self.assertEqual(False,
self.compute_node.setErrorStatus("TEST123 %s" % self.compute_node.getUid()))
# Check Software Installation
installation = self.start_requested_software_installation
self.assertEqual(True,
installation.setErrorStatus("TEST123 %s" % installation.getUid()))
self.assertEqual(installation._getCachedAccessInfo(),
getExpectedCacheDict(installation))
self.assertEqual(installation.getAccessStatus(),
getBaseExpectedDict(installation))
self.assertEqual(False,
installation.setErrorStatus("TEST123 %s" % installation.getUid()))
# Compute Partition
partition = self.compute_node.partition1
self.assertEqual(True,
partition.setErrorStatus("TEST123 %s" % partition.getUid()))
self.assertEqual(partition._getCachedAccessInfo(),
getExpectedCacheDict(partition))
self.assertEqual(partition.getAccessStatus(),
getBaseExpectedDict(partition))
self.assertEqual(False,
partition.setErrorStatus("TEST123 %s" % partition.getUid()))
# Software Instance
instance = self.start_requested_software_instance
self.assertEqual(True,
instance.setErrorStatus("TEST123 %s" % instance.getUid()))
self.assertEqual(instance._getCachedAccessInfo(),
getExpectedCacheDict(instance))
self.assertEqual(instance.getAccessStatus(),
getBaseExpectedDict(instance))
self.assertEqual(False,
instance.setErrorStatus("TEST123 %s" % instance.getUid()))
def test_setBuildingStatus(self):
since = rfc1123_date(DateTime())
created_at = since
def getExpectedCacheDict(doc):
return json.dumps({
"user": "ERP5TypeTestCase",
'created_at': '%s' % created_at,
'since': '%s' % since,
'state': "",
"text": "#building TEST123 %s" % doc.getUid()
})
def getBaseExpectedDict(doc):
return {
"user": "ERP5TypeTestCase",
'created_at': '%s' % created_at,
u'since': u'%s' % since,
u'state': u"",
u"text": u"#building TEST123 %s" % doc.getUid(),
'no_data_since_15_minutes': 0,
'no_data_since_5_minutes': 0
}
# Check Software Installation
installation = self.start_requested_software_installation
self.assertEqual(True,
installation.setBuildingStatus("TEST123 %s" % installation.getUid()))
self.assertEqual(installation._getCachedAccessInfo(),
getExpectedCacheDict(installation))
self.assertEqual(installation.getAccessStatus(),
getBaseExpectedDict(installation))
self.assertEqual(False,
installation.setBuildingStatus("TEST123 %s" % installation.getUid()))
class TestSlapOSCloudSoftwareInstance(
SlapOSTestCaseMixin):
def afterSetUp(self):
SlapOSTestCaseMixin.afterSetUp(self)
self._makeTree()
def test_getXmlAsDict(self):
simple_parameter_sample_xml = """<?xml version='1.0' encoding='utf-8'?>
<instance>
<parameter id="p1é">v1é</parameter>
<parameter id="p2é">v2é</parameter>
</instance>
"""
self.assertEqual(
self.software_instance._getXmlAsDict(simple_parameter_sample_xml),
{'p1é': 'v1é', 'p2é': 'v2é'})
def test_getInstanceXmlAsDict(self):
self.software_instance.setTextContent("""<?xml version='1.0' encoding='utf-8'?>
<instance>
<parameter id="p1é">v1é</parameter>
<parameter id="p2é">v2é</parameter>
</instance>
""")
self.assertEqual(
self.software_instance.getInstanceXmlAsDict(),
{'p1é': 'v1é', 'p2é': 'v2é'})
def test_getSlaXmlAsDict(self):
self.software_instance.setSlaXml("""<?xml version='1.0' encoding='utf-8'?>
<instance>
<parameter id="p1é">v1é</parameter>
<parameter id="p2é">v2é</parameter>
</instance>
""")
self.assertEqual(
self.software_instance.getSlaXmlAsDict(),
{'p1é': 'v1é', 'p2é': 'v2é'})
def test_getConnectionXmlAsDict(self):
self.software_instance.setConnectionXml("""<?xml version='1.0' encoding='utf-8'?>
<instance>
<parameter id="p1é">v1é</parameter>
<parameter id="p2é">v2é</parameter>
</instance>
""")
self.assertEqual(
self.software_instance.getConnectionXmlAsDict(),
{'p1é': 'v1é', 'p2é': 'v2é'})
def test_instanceXmlToDict(self):
simple_parameter_sample_xml = """<?xml version='1.0' encoding='utf-8'?>
<instance>
<parameter id="p1é">v1é</parameter>
<parameter id="p2é">v2é</parameter>
</instance>
"""
self.assertEqual(
self.software_instance._instanceXmlToDict(simple_parameter_sample_xml),
# different from getXmlAsDict it don't encode things as utf-8
{u'p1é': u'v1é', u'p2é': u'v2é'})
def test_asParameterDict_not_allocated(self):
self.assertRaises(ValueError,
self.software_instance._asParameterDict)
def test_asParameterDict(self):
self._makeComputeNode()
self._makeComplexComputeNode(with_slave=True)
as_parameter_dict = self.start_requested_software_instance._asParameterDict()
self.assertSameSet(as_parameter_dict.keys(),
['instance_guid', 'instance_title', 'root_instance_title',
'root_instance_short_title', 'xml', 'connection_xml',
'filter_xml', 'slap_computer_id', 'slap_computer_partition_id',
'slap_software_type', 'slap_software_release_url', 'slave_instance_list',
'ip_list', 'full_ip_list', 'timestamp'])
self.assertEqual(as_parameter_dict["instance_guid"],
self.start_requested_software_instance.getReference().decode("UTF-8") )
self.assertEqual(as_parameter_dict["instance_title"],
self.start_requested_software_instance.getTitle().decode("UTF-8") )
self.assertEqual(as_parameter_dict["xml"],
self.start_requested_software_instance.getTextContent() )
self.assertEqual(as_parameter_dict["connection_xml"],
self.start_requested_software_instance.getConnectionXml() )
self.assertEqual(as_parameter_dict["filter_xml"],
self.start_requested_software_instance.getSlaXml() )
self.assertEqual(as_parameter_dict["root_instance_title"],
self.start_requested_software_instance.getSpecialiseTitle().decode("UTF-8"))
self.assertEqual(as_parameter_dict["root_instance_short_title"],
self.start_requested_software_instance.getSpecialiseShortTitle().decode("UTF-8"))
self.assertEqual(as_parameter_dict["slap_computer_id"],
self.compute_node.getReference().decode("UTF-8"))
self.assertEqual(as_parameter_dict["slap_computer_partition_id"],
"partition1")
self.assertEqual(len(as_parameter_dict["slave_instance_list"]), 1)
self.assertSameSet(as_parameter_dict["slave_instance_list"][0].keys(),
['slave_title', 'slap_software_type', 'slave_reference',
'timestamp', 'xml', 'connection_xml'])
self.assertEqual(
self.start_requested_slave_instance.getTitle().decode("UTF-8"),
as_parameter_dict["slave_instance_list"][0]["slave_title"]
)
self.assertEqual(as_parameter_dict["ip_list"], [(u'', u'ip_address_1')])
# Since gateway isn't set both are the same.
self.assertEqual(as_parameter_dict["full_ip_list"], [])
def test_getInstanceTreeIpList(self):
self._makeComputeNode()
self._makeComplexComputeNode(with_slave=True)
self.tic()
self.assertEqual([(u'', u'ip_address_1')],
self.start_requested_software_instance._getInstanceTreeIpList())
class TestSlapOSCloudSlapOSComputeNodeMixin_getCacheComputeNodeInformation(
SlapOSTestCaseMixin):
def afterSetUp(self):
SlapOSTestCaseMixin.afterSetUp(self)
# Prepare compute_node
self.compute_node = self.portal.compute_node_module.template_compute_node\
.Base_createCloneDocument(batch_mode=1)
self.compute_node.edit(
title="Compute Node %s" % self.new_id,
reference="TESTCOMP-%s" % self.new_id
)
if getattr(self, "person", None) is not None:
self.compute_node.edit(
source_administration_value=getattr(self, "person", None),
)
self.compute_node.validate()
self._addERP5Login(self.compute_node)
self.tic()
self.compute_node_id = self.compute_node.getReference()
self.compute_node_user_id = self.compute_node.getUserId()
self.pinDateTime(DateTime())
def beforeTearDown(self):
self.unpinDateTime()
self._cleaupREQUEST()
def test_activate_getCacheComputeNodeInformation_first_access(self):
#
# This is a port of
# TestSlapOSSlapToolgetFullComputerInformation.test_activate_getFullComputerInformation_first_access
#
self._makeComplexComputeNode(with_slave=True)
self.portal.REQUEST['disable_isTestRun'] = True
self.tic()
self.login(self.compute_node_user_id)
user = self.getPortalObject().portal_membership.getAuthenticatedMember().getUserName()
self.compute_node.setAccessStatus(self.compute_node_id)
refresh_etag = self.compute_node._calculateRefreshEtag()
body, etag = self.compute_node._getComputeNodeInformation(user, refresh_etag)
self.commit()
first_etag = self.compute_node._calculateRefreshEtag()
first_body_fingerprint = hashData(
self.compute_node._getCacheComputeNodeInformation(self.compute_node_id)
)
self.assertEqual(first_etag, etag)
self.assertEqual(first_body_fingerprint, hashData(body))
self.assertEqual(0, len(self.portal.portal_activities.getMessageList()))
# Trigger the compute_node reindexation
# This should trigger a new etag, but the body should be the same
self.compute_node.reindexObject()
self.commit()
# Second access
# Check that the result is stable, as the indexation timestamp is not changed yet
current_activity_count = len(self.portal.portal_activities.getMessageList())
self.compute_node.setAccessStatus(self.compute_node_id)
refresh_etag = self.compute_node._calculateRefreshEtag()
body, etag = self.compute_node._getComputeNodeInformation(user, refresh_etag)
self.commit()
self.assertEqual(first_etag, etag)
self.assertEqual(first_body_fingerprint, hashData(body))
self.assertEqual(current_activity_count, len(self.portal.portal_activities.getMessageList()))
self.tic()
# Third access, new calculation expected
# The retrieved informations comes from the cache
# But a new cache modification activity is triggered
self.compute_node.setAccessStatus(self.compute_node_id)
refresh_etag = self.compute_node._calculateRefreshEtag()
body, etag = self.compute_node._getComputeNodeInformation(user, refresh_etag)
self.commit()
second_etag = self.compute_node._calculateRefreshEtag()
second_body_fingerprint = hashData(
self.compute_node._getCacheComputeNodeInformation(self.compute_node_id)
)
self.assertNotEqual(first_etag, second_etag)
# The indexation timestamp does not impact the response body
self.assertEqual(first_body_fingerprint, second_body_fingerprint)
self.assertEqual(first_etag, etag)
self.assertEqual(first_body_fingerprint, hashData(body))
self.assertEqual(1, len(self.portal.portal_activities.getMessageList()))
# Execute the cache modification activity
self.tic()
# 4th access
# The new etag value is now used
self.compute_node.setAccessStatus(self.compute_node_id)
refresh_etag = self.compute_node._calculateRefreshEtag()
body, etag = self.compute_node._getComputeNodeInformation(user, refresh_etag)
self.commit()
self.assertEqual(second_etag, etag)
self.assertEqual(first_body_fingerprint, hashData(body))
self.assertEqual(0, len(self.portal.portal_activities.getMessageList()))
# Edit the instance
# This should trigger a new etag and a new body
self.stop_requested_software_instance.edit(text_content=self.generateSafeXml())
self.commit()
# 5th access
# Check that the result is stable, as the indexation timestamp is not changed yet
current_activity_count = len(self.portal.portal_activities.getMessageList())
# Edition does not impact the etag
self.assertEqual(second_etag, self.compute_node._calculateRefreshEtag())
third_body_fingerprint = hashData(
self.compute_node._getCacheComputeNodeInformation(self.compute_node_id)
)
# The edition impacts the response body
self.assertNotEqual(first_body_fingerprint, third_body_fingerprint)
self.compute_node.setAccessStatus(self.compute_node_id)
refresh_etag = self.compute_node._calculateRefreshEtag()
body, etag = self.compute_node._getComputeNodeInformation(user, refresh_etag)
self.commit()
self.assertEqual(second_etag, etag)
self.assertEqual(first_body_fingerprint, hashData(body))
self.assertEqual(current_activity_count, len(self.portal.portal_activities.getMessageList()))
self.tic()
# 6th, the instance edition triggered an interaction workflow
# which updated the cache
self.compute_node.setAccessStatus(self.compute_node_id)
refresh_etag = self.compute_node._calculateRefreshEtag()
body, etag = self.compute_node._getComputeNodeInformation(user, refresh_etag)
self.commit()
third_etag = self.compute_node._calculateRefreshEtag()
self.assertNotEqual(second_etag, third_etag)
self.assertEqual(third_etag, etag)
self.assertEqual(third_body_fingerprint, hashData(body))
self.assertEqual(0, len(self.portal.portal_activities.getMessageList()))
# Remove the slave link to the partition
# Compute Node should loose permission to access the slave instance
self.start_requested_slave_instance.setAggregate('')
self.commit()
# 7th access
# Check that the result is stable, as the indexation timestamp is not changed yet
current_activity_count = len(self.portal.portal_activities.getMessageList())
# Edition does not impact the etag
self.assertEqual(third_etag, self.compute_node._calculateRefreshEtag())
# The edition does not impact the response body yet, as the aggregate relation
# is not yet unindex
self.assertEqual(third_body_fingerprint, hashData(
self.compute_node._getCacheComputeNodeInformation(self.compute_node_id)
))
self.compute_node.setAccessStatus(self.compute_node_id)
refresh_etag = self.compute_node._calculateRefreshEtag()
body, etag = self.compute_node._getComputeNodeInformation(user, refresh_etag)
self.commit()
self.assertEqual(third_etag, etag)
self.assertEqual(third_body_fingerprint, hashData(body))
self.assertEqual(current_activity_count, len(self.portal.portal_activities.getMessageList()))
self.tic()
# 8th access
# changing the aggregate relation trigger the partition reindexation
# which trigger cache modification activity
# So, we should get the correct cached value
self.compute_node.setAccessStatus(self.compute_node_id)
refresh_etag = self.compute_node._calculateRefreshEtag()
body, etag = self.compute_node._getComputeNodeInformation(user, refresh_etag)
self.commit()
fourth_etag = self.compute_node._calculateRefreshEtag()
fourth_body_fingerprint = hashData(
self.compute_node._getCacheComputeNodeInformation(self.compute_node_id)
)
self.assertNotEqual(third_etag, fourth_etag)
# The indexation timestamp does not impact the response body
self.assertNotEqual(third_body_fingerprint, fourth_body_fingerprint)
self.assertEqual(fourth_etag, etag)
self.assertEqual(fourth_body_fingerprint, hashData(body))
self.assertEqual(0, len(self.portal.portal_activities.getMessageList()))
<?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
......
mixin.erp5.SlapOSCacheMixin mixin.erp5.SlapOSCacheMixin
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
...@@ -14,3 +14,4 @@ test.erp5.testSlapOSCloudUpgrader ...@@ -14,3 +14,4 @@ test.erp5.testSlapOSCloudUpgrader
test.erp5.testSlapOSCloudShadow test.erp5.testSlapOSCloudShadow
test.erp5.SlapOSTestCaseMixin test.erp5.SlapOSTestCaseMixin
test.erp5.SlapOSTestCaseDefaultScenarioMixin test.erp5.SlapOSTestCaseDefaultScenarioMixin
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):
......
...@@ -38,37 +38,20 @@ from Products.DCWorkflow.DCWorkflow import ValidationFailed ...@@ -38,37 +38,20 @@ from Products.DCWorkflow.DCWorkflow import ValidationFailed
from Products.ERP5Type.Globals import InitializeClass 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 DEFAULT_CACHE_SCOPE
from Products.ERP5Type.Cache import CachingMethod from Products.ERP5Type.Cache import CachingMethod
from lxml import etree from lxml import etree
import time
from Products.ERP5Type.tests.utils import DummyMailHostMixin
try: try:
from slapos.slap.slap import ( from slapos.slap.slap import (
Computer as ComputeNode, Computer as ComputeNode)
ComputerPartition as SlapComputePartition, from slapos.util import dict2xml, calculate_dict_hash, loads, dumps
SoftwareInstance,
SoftwareRelease)
from slapos.util import dict2xml, xml2dict, calculate_dict_hash, loads, 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: class ComputeNode:
def __init__(self): def __init__(self):
raise ImportError raise ImportError
class SlapComputePartition:
def __init__(self):
raise ImportError
class SoftwareInstance:
def __init__(self):
raise ImportError
class SoftwareRelease:
def __init__(self):
raise ImportError
def dict2xml(dictionary): def dict2xml(dictionary):
raise ImportError raise ImportError
def xml2dict(dictionary):
raise ImportError
def calculate_dict_hash(dictionary): def calculate_dict_hash(dictionary):
raise ImportError raise ImportError
def loads(*args): def loads(*args):
...@@ -118,6 +101,15 @@ def convertToREST(function): ...@@ -118,6 +101,15 @@ def convertToREST(function):
wrapper.__doc__ = function.__doc__ wrapper.__doc__ = function.__doc__
return wrapper return wrapper
def castToStr(dict_kw):
instance = etree.Element('instance')
for _id, _value in dict_kw.iteritems():
# cast everything to string
etree.SubElement(instance, "parameter",
attrib={'id':_id}).text = str(_value)
return etree.tostring(instance, pretty_print=True,
xml_declaration=True, encoding='utf-8')
def _assertACI(document): def _assertACI(document):
sm = getSecurityManager() sm = getSecurityManager()
...@@ -162,194 +154,6 @@ class SlapTool(BaseTool): ...@@ -162,194 +154,6 @@ class SlapTool(BaseTool):
# Public GET methods # Public GET methods
#################################################### ####################################################
def _isTestRun(self):
if self.REQUEST.get('disable_isTestRun', False):
return False
if issubclass(self.getPortalObject().MailHost.__class__, DummyMailHostMixin) \
or self.REQUEST.get('test_list'):
return True
return False
def _getCachePlugin(self):
return self.getPortalObject().portal_caches\
.getRamCacheRoot().get('compute_node_information_cache_factory')\
.getCachePluginList()[0]
def _getCacheComputeNodeInformation(self, compute_node_id, user):
self.REQUEST.response.setHeader('Content-Type', 'text/xml; charset=utf-8')
slap_compute_node = ComputeNode(compute_node_id.decode("UTF-8"))
parent_uid = self._getComputeNodeUidByReference(compute_node_id)
slap_compute_node._computer_partition_list = []
slap_compute_node._software_release_list = \
self._getSoftwareReleaseValueListForComputeNode(compute_node_id)
unrestrictedSearchResults = self.getPortalObject().portal_catalog.unrestrictedSearchResults
compute_partition_list = unrestrictedSearchResults(
parent_uid=parent_uid,
validation_state="validated",
portal_type="Compute Partition"
)
self._calculateSlapComputeNodeInformation(slap_compute_node, compute_partition_list)
return dumps(slap_compute_node)
def _fillComputeNodeInformationCache(self, compute_node_id, user):
key = '%s_%s' % (compute_node_id, user)
try:
self._getCachePlugin().set(key, DEFAULT_CACHE_SCOPE,
dict (
time=time.time(),
refresh_etag=self._calculateRefreshEtag(),
data=self._getCacheComputeNodeInformation(compute_node_id, user),
),
cache_duration=self.getPortalObject().portal_caches\
.getRamCacheRoot().get('compute_node_information_cache_factory'\
).cache_duration
)
except (Unauthorized, IndexError):
# XXX: Unauthorized hack. Race condition of not ready setup delivery which provides
# security information shall not make this method fail, as it will be
# called later anyway
# Note: IndexError ignored, as it happend in case if full reindex is
# called on site
pass
def _activateFillComputeNodeInformationCache(self, compute_node_id, user):
tag = 'compute_node_information_cache_fill_%s_%s' % (compute_node_id, user)
if self.getPortalObject().portal_activities.countMessageWithTag(tag) == 0:
self.activate(activity='SQLQueue', tag=tag)._fillComputeNodeInformationCache(
compute_node_id, user)
def _calculateSlapComputeNodeInformation(self, slap_compute_node, compute_partition_list):
if len(compute_partition_list) == 0:
return
unrestrictedSearchResults = self.getPortalObject().portal_catalog.unrestrictedSearchResults
compute_partition_uid_list = [x.uid for x in compute_partition_list]
grouped_software_instance_list = unrestrictedSearchResults(
portal_type="Software Instance",
default_aggregate_uid=compute_partition_uid_list,
validation_state="validated",
group_by_list=['default_aggregate_uid'],
select_list=['default_aggregate_uid', 'count(*)']
)
slave_software_instance_list = unrestrictedSearchResults(
default_aggregate_uid=compute_partition_uid_list,
portal_type='Slave Instance',
validation_state="validated",
select_list=['default_aggregate_uid'],
**{"slapos_item.slap_state": "start_requested"}
)
for compute_partition in compute_partition_list:
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):
software_instance_list = software_instance_list + software_instance_list
slap_compute_node._computer_partition_list.append(
self._getSlapPartitionByPackingList(
_assertACI(compute_partition.getObject()),
software_instance_list,
[x for x in slave_software_instance_list if (x.default_aggregate_uid == compute_partition.getUid())]
)
)
def _calculateRefreshEtag(self):
# check max indexation timestamp
# it is unlikely to get an empty catalog
last_indexed_entry = self.getPortalObject().portal_catalog(
select_list=['indexation_timestamp'],
portal_type=['Compute Node', 'Compute Partition',
'Software Instance', 'Slave Instance',
'Software Installation'],
sort_on=[('indexation_timestamp', 'DESC')],
limit=1,
)[0]
return '%s_%s' % (last_indexed_entry.uid,
last_indexed_entry.indexation_timestamp)
def _getComputeNodeInformation(self, compute_node_id, user, refresh_etag):
portal = self.getPortalObject()
user_document = _assertACI(portal.portal_catalog.unrestrictedGetResultValue(
reference=user, portal_type=['Person', 'Compute Node', 'Software Instance']))
user_type = user_document.getPortalType()
self.REQUEST.response.setHeader('Content-Type', 'text/xml; charset=utf-8')
slap_compute_node = ComputeNode(compute_node_id.decode("UTF-8"))
parent_uid = self._getComputeNodeUidByReference(compute_node_id)
slap_compute_node._computer_partition_list = []
if user_type in ('Compute Node', 'Person'):
if not self._isTestRun():
cache_plugin = self._getCachePlugin()
key = '%s_%s' % (compute_node_id, 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
self._activateFillComputeNodeInformationCache(compute_node_id, user)
return cached_dict['data'], cached_etag
else:
self._activateFillComputeNodeInformationCache(compute_node_id, user)
self.REQUEST.response.setStatus(503)
return self.REQUEST.response, None
else:
return self._getCacheComputeNodeInformation(compute_node_id, user), None
else:
slap_compute_node._software_release_list = []
if user_type == 'Software Instance':
compute_node = self.getPortalObject().portal_catalog.unrestrictedSearchResults(
portal_type='Compute Node', reference=compute_node_id,
validation_state="validated")[0].getObject()
compute_partition_list = compute_node.contentValues(
portal_type="Compute Partition",
checked_permission="View")
else:
compute_partition_list = self.getPortalObject().portal_catalog.unrestrictedSearchResults(
parent_uid=parent_uid,
validation_state="validated",
portal_type="Compute Partition")
self._calculateSlapComputeNodeInformation(slap_compute_node, compute_partition_list)
return dumps(slap_compute_node), None
@UnrestrictedMethod
def _getInstanceTreeIpList(self, compute_node_id, compute_partition_id):
software_instance = self._getSoftwareInstanceForComputePartition(
compute_node_id, compute_partition_id)
if software_instance is None or \
software_instance.getSlapState() == 'destroy_requested':
return dumps([])
# Search instance tree
hosting = software_instance.getSpecialiseValue()
while hosting and hosting.getPortalType() != "Instance Tree":
hosting = hosting.getSpecialiseValue()
ip_address_list = []
for instance in hosting.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 dumps(ip_address_list)
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
'getFullComputerInformation') 'getFullComputerInformation')
def getFullComputerInformation(self, computer_id): def getFullComputerInformation(self, computer_id):
...@@ -362,9 +166,16 @@ class SlapTool(BaseTool): ...@@ -362,9 +166,16 @@ class SlapTool(BaseTool):
user = self.getPortalObject().portal_membership.getAuthenticatedMember().getUserName() user = self.getPortalObject().portal_membership.getAuthenticatedMember().getUserName()
if str(user) == computer_id: if str(user) == computer_id:
compute_node = self.getPortalObject().portal_membership.getAuthenticatedMember().getUserValue() compute_node = self.getPortalObject().portal_membership.getAuthenticatedMember().getUserValue()
compute_node.setAccessStatus('#access %s' % computer_id) compute_node.setAccessStatus(computer_id)
refresh_etag = self._calculateRefreshEtag() else:
body, etag = self._getComputeNodeInformation(computer_id, user, refresh_etag) # Don't use getDocument because we don't want use _assertACI here, but
# just call the API on computer.
compute_node = self.getPortalObject().portal_catalog.unrestrictedSearchResults(
portal_type='Compute Node', reference=computer_id,
validation_state="validated")[0].getObject()
refresh_etag = compute_node._calculateRefreshEtag()
body, etag = compute_node._getComputeNodeInformation(user, refresh_etag)
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
...@@ -386,8 +197,12 @@ class SlapTool(BaseTool): ...@@ -386,8 +197,12 @@ class SlapTool(BaseTool):
Search and return all Compute Partition IP address related to one Search and return all Compute Partition IP address related to one
Instance Tree Instance Tree
""" """
result = self._getInstanceTreeIpList(computer_id, software_instance = self._getSoftwareInstanceForComputePartition(
computer_partition_id) computer_id, computer_partition_id)
if software_instance is not None:
result = software_instance._getInstanceTreeIpList()
else:
result = []
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
...@@ -396,7 +211,7 @@ class SlapTool(BaseTool): ...@@ -396,7 +211,7 @@ class SlapTool(BaseTool):
self.REQUEST.response.setHeader('Vary', self.REQUEST.response.setHeader('Vary',
'REMOTE_USER') 'REMOTE_USER')
self.REQUEST.response.setHeader('Last-Modified', rfc1123_date(DateTime())) self.REQUEST.response.setHeader('Last-Modified', rfc1123_date(DateTime()))
self.REQUEST.response.setBody(result) self.REQUEST.response.setBody(dumps(result))
return self.REQUEST.response return self.REQUEST.response
else: else:
return result return result
...@@ -443,15 +258,13 @@ class SlapTool(BaseTool): ...@@ -443,15 +258,13 @@ class SlapTool(BaseTool):
else: else:
data_dict = instance.getAccessStatus() data_dict = instance.getAccessStatus()
last_modified = rfc1123_date(DateTime())
# Keep in cache server for 7 days # Keep in cache server for 7 days
self.REQUEST.response.setStatus(200) self.REQUEST.response.setStatus(200)
self.REQUEST.response.setHeader('Cache-Control', self.REQUEST.response.setHeader('Cache-Control',
'public, max-age=60, stale-if-error=604800') 'public, max-age=60, stale-if-error=604800')
self.REQUEST.response.setHeader('Vary', self.REQUEST.response.setHeader('Vary',
'REMOTE_USER') 'REMOTE_USER')
self.REQUEST.response.setHeader('Last-Modified', last_modified) self.REQUEST.response.setHeader('Last-Modified', rfc1123_date(DateTime()))
self.REQUEST.response.setHeader('Content-Type', 'text/xml; charset=utf-8') self.REQUEST.response.setHeader('Content-Type', 'text/xml; charset=utf-8')
self.REQUEST.response.setBody(dumps(data_dict)) self.REQUEST.response.setBody(dumps(data_dict))
return self.REQUEST.response return self.REQUEST.response
...@@ -462,22 +275,16 @@ class SlapTool(BaseTool): ...@@ -462,22 +275,16 @@ class SlapTool(BaseTool):
""" """
Get the connection status of the partition Get the connection status of the partition
""" """
compute_node = self.getPortalObject().portal_catalog.unrestrictedSearchResults( compute_node = self._getComputeNodeDocument(computer_id)
portal_type='Compute Node', reference=computer_id,
validation_state="validated")[0].getObject()
# Be sure to prevent accessing information to disallowed users
compute_node = _assertACI(compute_node)
data_dict = compute_node.getAccessStatus() data_dict = compute_node.getAccessStatus()
last_modified = rfc1123_date(DateTime())
# Keep in cache server for 7 days # Keep in cache server for 7 days
self.REQUEST.response.setStatus(200) self.REQUEST.response.setStatus(200)
self.REQUEST.response.setHeader('Cache-Control', self.REQUEST.response.setHeader('Cache-Control',
'public, max-age=60, stale-if-error=604800') 'public, max-age=60, stale-if-error=604800')
self.REQUEST.response.setHeader('Vary', self.REQUEST.response.setHeader('Vary',
'REMOTE_USER') 'REMOTE_USER')
self.REQUEST.response.setHeader('Last-Modified', last_modified) self.REQUEST.response.setHeader('Last-Modified', rfc1123_date(DateTime()))
self.REQUEST.response.setHeader('Content-Type', 'text/xml; charset=utf-8') self.REQUEST.response.setHeader('Content-Type', 'text/xml; charset=utf-8')
self.REQUEST.response.setBody(dumps(data_dict)) self.REQUEST.response.setBody(dumps(data_dict))
return self.REQUEST.response return self.REQUEST.response
...@@ -488,15 +295,11 @@ class SlapTool(BaseTool): ...@@ -488,15 +295,11 @@ class SlapTool(BaseTool):
""" """
Get the connection status of the software installation Get the connection status of the software installation
""" """
compute_node = self.getPortalObject().portal_catalog.unrestrictedSearchResults( compute_node = self._getComputeNodeDocument(computer_id)
portal_type='Compute Node', reference=computer_id,
validation_state="validated")[0].getObject()
# 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:
software_installation = self._getSoftwareInstallationForComputeNode( software_installation = compute_node._getSoftwareInstallationFromUrl(url)
url,
compute_node)
except NotFound: except NotFound:
data_dict = self._getAccessStatus(None) data_dict = self._getAccessStatus(None)
else: else:
...@@ -793,7 +596,6 @@ class SlapTool(BaseTool): ...@@ -793,7 +596,6 @@ 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._getComputeNodeDocument(compute_node_id)
compute_node.setAccessStatus('#error bang')
return compute_node.reportComputeNodeBang(comment=message) return compute_node.reportComputeNodeBang(comment=message)
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
...@@ -813,20 +615,6 @@ class SlapTool(BaseTool): ...@@ -813,20 +615,6 @@ class SlapTool(BaseTool):
compute_node.ComputeNode_updateFromDict(compute_node_dict) compute_node.ComputeNode_updateFromDict(compute_node_dict)
return 'Content properly posted.' return 'Content properly posted.'
security.declareProtected(Permissions.AccessContentsInformation,
'useComputerPartition')
def useComputerPartition(self, computer_id, computer_partition_id,
use_string):
"""Warning : deprecated method."""
compute_node_document = self._getComputeNodeDocument(computer_id)
compute_partition_document = self._getComputePartitionDocument(
compute_node_document.getReference(), computer_partition_id)
# easy way to start to store usage messages sent by client in related Web
# Page text_content...
self._reportUsage(compute_partition_document, use_string)
return """Content properly posted.
WARNING : this method is deprecated. Please use useComputer."""
@convertToREST @convertToREST
def _generateComputerCertificate(self, compute_node_id): def _generateComputerCertificate(self, compute_node_id):
self._getComputeNodeDocument(compute_node_id).generateCertificate() self._getComputeNodeDocument(compute_node_id).generateCertificate()
...@@ -862,71 +650,10 @@ class SlapTool(BaseTool): ...@@ -862,71 +650,10 @@ 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
portal = self.getPortalObject()
compute_partition_document = self._getComputePartitionDocument( compute_partition_document = self._getComputePartitionDocument(
computer_reference, computer_partition_reference) computer_reference, computer_partition_reference)
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 compute_partition_document.getSlapState() == 'busy':
software_instance_list = portal.portal_catalog.unrestrictedSearchResults(
portal_type="Software Instance",
default_aggregate_uid=compute_partition_document.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],
compute_partition_document.getRelativeUrl())
if software_instance is not None: slap_compute_partition = compute_partition_document._registerComputePartition()
# 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 = self._getSoftwareInstanceAsParameterDict(
software_instance)
# software instance has to define an xml parameter
slap_partition._parameter_dict = self._instanceXmlToDict(
parameter_dict.pop('xml'))
slap_partition._connection_dict = self._instanceXmlToDict(
parameter_dict.pop('connection_xml'))
slap_partition._filter_dict = self._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 = self._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(self._instanceXmlToDict(
slave_instance_dict.pop("xml")))
slap_partition._parameter_dict.update(parameter_dict)
result = dumps(slap_partition)
# Keep in cache server for 7 days # Keep in cache server for 7 days
self.REQUEST.response.setStatus(200) self.REQUEST.response.setStatus(200)
...@@ -936,7 +663,7 @@ class SlapTool(BaseTool): ...@@ -936,7 +663,7 @@ class SlapTool(BaseTool):
'REMOTE_USER') 'REMOTE_USER')
self.REQUEST.response.setHeader('Last-Modified', rfc1123_date(DateTime())) self.REQUEST.response.setHeader('Last-Modified', rfc1123_date(DateTime()))
self.REQUEST.response.setHeader('Content-Type', 'text/xml; charset=utf-8') self.REQUEST.response.setHeader('Content-Type', 'text/xml; charset=utf-8')
self.REQUEST.response.setBody(result) self.REQUEST.response.setBody(dumps(slap_compute_partition))
return self.REQUEST.response return self.REQUEST.response
...@@ -966,77 +693,6 @@ class SlapTool(BaseTool): ...@@ -966,77 +693,6 @@ class SlapTool(BaseTool):
return False return False
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('SlapTool', INFO, 'Issue during parsing xml:', error=True)
return result_dict
def _getSlapPartitionByPackingList(self, compute_partition_document,
software_instance_list,
slave_instance_sql_list):
compute_node = compute_partition_document
while compute_node.getPortalType() != 'Compute Node':
compute_node = compute_node.getParentValue()
compute_node_id = compute_node.getReference().decode("UTF-8")
slap_partition = SlapComputePartition(compute_node_id,
compute_partition_document.getReference().decode("UTF-8"))
slap_partition._software_release_document = None
slap_partition._requested_state = 'destroyed'
slap_partition._need_modification = 0
software_instance = None
if compute_partition_document.getSlapState() == 'busy':
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 linked to %s" % \
compute_partition_document.getRelativeUrl()
if software_instance is not None:
state = software_instance.getSlapState()
if state == "stop_requested":
slap_partition._requested_state = 'stopped'
if state == "start_requested":
slap_partition._requested_state = 'started'
slap_partition._access_status = software_instance.getTextAccessStatus()
slap_partition._software_release_document = SoftwareRelease(
software_release=software_instance.getUrlString().decode("UTF-8"),
computer_guid=compute_node_id)
slap_partition._need_modification = 1
parameter_dict = self._getSoftwareInstanceAsParameterDict(
software_instance,
slave_instance_sql_list=slave_instance_sql_list
)
# software instance has to define an xml parameter
slap_partition._parameter_dict = self._instanceXmlToDict(
parameter_dict.pop('xml'))
slap_partition._connection_dict = self._instanceXmlToDict(
parameter_dict.pop('connection_xml'))
slap_partition._filter_dict = self._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"):
slave_instance_dict.update(self._instanceXmlToDict(
slave_instance_dict.pop("connection_xml")))
if slave_instance_dict.has_key("xml"):
slave_instance_dict.update(self._instanceXmlToDict(
slave_instance_dict.pop("xml")))
slap_partition._parameter_dict.update(parameter_dict)
return slap_partition
@convertToREST @convertToREST
def _supplySupply(self, url, compute_node_id, state): def _supplySupply(self, url, compute_node_id, state):
""" """
...@@ -1050,31 +706,28 @@ class SlapTool(BaseTool): ...@@ -1050,31 +706,28 @@ class SlapTool(BaseTool):
""" """
Log the software release status Log the software release status
""" """
compute_node_document = self._getComputeNodeDocument(compute_node_id) compute_node = self._getComputeNodeDocument(compute_node_id)
software_installation = self._getSoftwareInstallationForComputeNode(url, software_installation = compute_node._getSoftwareInstallationFromUrl(url)
compute_node_document) software_installation.setBuildingStatus(
software_installation.setAccessStatus( 'software release %s' % url, "building")
'#building software release %s' % url, "building")
@convertToREST @convertToREST
def _availableSoftwareRelease(self, url, compute_node_id): def _availableSoftwareRelease(self, url, compute_node_id):
""" """
Log the software release status Log the software release status
""" """
compute_node_document = self._getComputeNodeDocument(compute_node_id) compute_node = self._getComputeNodeDocument(compute_node_id)
software_installation = self._getSoftwareInstallationForComputeNode(url, software_installation = compute_node._getSoftwareInstallationFromUrl(url)
compute_node_document)
software_installation.setAccessStatus( software_installation.setAccessStatus(
'#access software release %s available' % url, "available") 'software release %s available' % url, "available")
@convertToREST @convertToREST
def _destroyedSoftwareRelease(self, url, compute_node_id): def _destroyedSoftwareRelease(self, url, compute_node_id):
""" """
Reports that Software Release is destroyed Reports that Software Release is destroyed
""" """
compute_node_document = self._getComputeNodeDocument(compute_node_id) compute_node = self._getComputeNodeDocument(compute_node_id)
software_installation = self._getSoftwareInstallationForComputeNode(url, software_installation = compute_node._getSoftwareInstallationFromUrl(url)
compute_node_document)
if software_installation.getSlapState() != 'destroy_requested': if software_installation.getSlapState() != 'destroy_requested':
raise NotFound raise NotFound
if self.getPortalObject().portal_workflow.isTransitionPossible(software_installation, if self.getPortalObject().portal_workflow.isTransitionPossible(software_installation,
...@@ -1088,18 +741,14 @@ class SlapTool(BaseTool): ...@@ -1088,18 +741,14 @@ class SlapTool(BaseTool):
""" """
Add an error for the software Instance Workflow Add an error for the software Instance Workflow
""" """
if error_log is None:
error_log = ""
instance = self._getSoftwareInstanceForComputePartition( instance = self._getSoftwareInstanceForComputePartition(
compute_node_id, compute_node_id,
compute_partition_id) compute_partition_id)
status_changed = instance.setAccessStatus( if error_log is None:
'#error while instanciating: %s' % error_log[-80:]) error_log = ""
instance.setErrorStatus(
if status_changed: 'while instanciating: %s' % error_log[-80:], reindex=1)
instance.reindexObject()
@convertToREST @convertToREST
def _softwareInstanceRename(self, new_name, compute_node_id, def _softwareInstanceRename(self, new_name, compute_node_id,
...@@ -1107,11 +756,7 @@ class SlapTool(BaseTool): ...@@ -1107,11 +756,7 @@ class SlapTool(BaseTool):
software_instance = self._getSoftwareInstanceForComputePartition( software_instance = self._getSoftwareInstanceForComputePartition(
compute_node_id, compute_partition_id, compute_node_id, compute_partition_id,
slave_reference) slave_reference)
hosting = software_instance.getSpecialise()
for name in [software_instance.getTitle(), new_name]:
# reset request cache
key = '_'.join([hosting, name])
software_instance.setLastData({}, key=key)
return software_instance.rename(new_name=new_name, return software_instance.rename(new_name=new_name,
comment="Rename %s into %s" % (software_instance.title, new_name)) comment="Rename %s into %s" % (software_instance.title, new_name))
...@@ -1126,16 +771,12 @@ class SlapTool(BaseTool): ...@@ -1126,16 +771,12 @@ class SlapTool(BaseTool):
compute_node_id, compute_node_id,
compute_partition_id) compute_partition_id)
software_instance.setAccessStatus('#error bang called') software_instance.setErrorStatus('bang called')
timestamp = str(int(software_instance.getModificationDate())) timestamp = str(int(software_instance.getModificationDate()))
key = "%s_bangstamp" % software_instance.getReference() key = "%s_bangstamp" % software_instance.getReference()
self.getPortalObject().portal_workflow.getInfoFor( if not software_instance.isLastData(key, timestamp):
software_instance, 'action', wf_id='instance_slap_interface_workflow')
if (software_instance.getLastData(key) != timestamp):
software_instance.bang(bang_tree=True, comment=message) software_instance.bang(bang_tree=True, comment=message)
software_instance.setLastData(key, str(int(software_instance.getModificationDate())))
return "OK" return "OK"
@convertToREST @convertToREST
...@@ -1146,9 +787,9 @@ class SlapTool(BaseTool): ...@@ -1146,9 +787,9 @@ class SlapTool(BaseTool):
instance = self._getSoftwareInstanceForComputePartition( instance = self._getSoftwareInstanceForComputePartition(
compute_node_id, compute_node_id,
compute_partition_id) compute_partition_id)
status_changed = instance.setAccessStatus('#access Instance correctly started', "started")
if status_changed: instance.setAccessStatus(
instance.reindexObject() 'Instance correctly started', "started", reindex=1)
@convertToREST @convertToREST
def _stoppedComputePartition(self, compute_node_id, compute_partition_id): def _stoppedComputePartition(self, compute_node_id, compute_partition_id):
...@@ -1158,9 +799,8 @@ class SlapTool(BaseTool): ...@@ -1158,9 +799,8 @@ class SlapTool(BaseTool):
instance = self._getSoftwareInstanceForComputePartition( instance = self._getSoftwareInstanceForComputePartition(
compute_node_id, compute_node_id,
compute_partition_id) compute_partition_id)
status_changed = instance.setAccessStatus('#access Instance correctly stopped', "stopped") instance.setAccessStatus(
if status_changed: 'Instance correctly stopped', "stopped", reindex=1)
instance.reindexObject()
@convertToREST @convertToREST
def _destroyedComputePartition(self, compute_node_id, compute_partition_id): def _destroyedComputePartition(self, compute_node_id, compute_partition_id):
...@@ -1170,30 +810,13 @@ class SlapTool(BaseTool): ...@@ -1170,30 +810,13 @@ class SlapTool(BaseTool):
instance = self._getSoftwareInstanceForComputePartition( instance = self._getSoftwareInstanceForComputePartition(
compute_node_id, compute_node_id,
compute_partition_id) compute_partition_id)
if instance.getSlapState() == 'destroy_requested': if instance.getSlapState() == 'destroy_requested':
# remove certificate from SI # remove certificate from SI
if instance.getSslKey() is not None or instance.getSslCertificate() is not None: instance.revokeCertificate()
instance.edit(
ssl_key=None,
ssl_certificate=None,
)
if instance.getValidationState() == 'validated': if instance.getValidationState() == 'validated':
instance.invalidate() instance.invalidate()
# XXX Integrate with REST API
# Code duplication will be needed until SlapTool is removed
# revoke certificate
portal = self.getPortalObject()
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
@convertToREST @convertToREST
def _setComputePartitionConnectionXml(self, compute_node_id, def _setComputePartitionConnectionXml(self, compute_node_id,
compute_partition_id, compute_partition_id,
...@@ -1207,11 +830,11 @@ class SlapTool(BaseTool): ...@@ -1207,11 +830,11 @@ class SlapTool(BaseTool):
compute_partition_id, compute_partition_id,
slave_reference) slave_reference)
connection_xml = dict2xml(loads(connection_xml)) connection_xml = dict2xml(loads(connection_xml))
if software_instance.getLastData() != connection_xml: if not software_instance.isLastData(value=connection_xml):
software_instance.updateConnection( software_instance.updateConnection(
connection_xml=connection_xml, connection_xml=connection_xml,
) )
software_instance.setLastData(connection_xml)
@convertToREST @convertToREST
def _requestComputePartition(self, compute_node_id, compute_partition_id, def _requestComputePartition(self, compute_node_id, compute_partition_id,
...@@ -1248,85 +871,51 @@ class SlapTool(BaseTool): ...@@ -1248,85 +871,51 @@ class SlapTool(BaseTool):
else: else:
filter_kw = dict() filter_kw = dict()
instance = etree.Element('instance') kw = dict(software_release=software_release,
for parameter_id, parameter_value in partition_parameter_kw.iteritems(): software_type=software_type,
# cast everything to string software_title=partition_reference,
parameter_value = str(parameter_value) instance_xml=castToStr(partition_parameter_kw),
etree.SubElement(instance, "parameter", shared=shared,
attrib={'id':parameter_id}).text = parameter_value sla_xml=castToStr(filter_kw),
instance_xml = etree.tostring(instance, pretty_print=True, state=state)
xml_declaration=True, encoding='utf-8')
instance = etree.Element('instance')
for parameter_id, parameter_value in filter_kw.iteritems():
# cast everything to string
parameter_value = str(parameter_value)
etree.SubElement(instance, "parameter",
attrib={'id':parameter_id}).text = parameter_value
sla_xml = etree.tostring(instance, pretty_print=True,
xml_declaration=True, encoding='utf-8')
portal = self.getPortalObject() portal = self.getPortalObject()
if compute_node_id and compute_partition_id: if compute_node_id and compute_partition_id:
# requested by Software Instance, there is already top part of tree requester = self.\
software_instance_document = self.\
_getSoftwareInstanceForComputePartition(compute_node_id, _getSoftwareInstanceForComputePartition(compute_node_id,
compute_partition_id) compute_partition_id)
instance_tree = software_instance_document.getSpecialiseValue() instance_tree = requester.getSpecialiseValue()
if instance_tree is not None and instance_tree.getSlapState() == "stop_requested": if instance_tree is not None and instance_tree.getSlapState() == "stop_requested":
state = 'stopped' kw['state'] = 'stopped'
kw = dict(software_release=software_release, key = '_'.join([instance_tree.getRelativeUrl(), partition_reference])
software_type=software_type,
software_title=partition_reference,
instance_xml=instance_xml,
shared=shared,
sla_xml=sla_xml,
state=state)
key = '_'.join([software_instance_document.getSpecialise(), partition_reference])
value = dict(
hash='_'.join([software_instance_document.getRelativeUrl(), str(kw)]),
)
last_data = software_instance_document.getLastData(key)
requested_software_instance = None
if last_data is not None and isinstance(last_data, dict):
requested_software_instance = portal.restrictedTraverse(
last_data.get('request_instance'), None)
if last_data is None or not isinstance(last_data, type(value)) or \
last_data.get('hash') != value['hash'] or \
requested_software_instance is None:
software_instance_document.requestInstance(**kw)
requested_software_instance = self.REQUEST.get('request_instance')
if requested_software_instance is not None:
value['request_instance'] = requested_software_instance\
.getRelativeUrl()
software_instance_document.setLastData(value, key=key)
else: else:
# requested as root, so done by human # requested as root, so done by human
person = portal.portal_membership.getAuthenticatedMember().getUserValue() requester = portal.portal_membership.getAuthenticatedMember().getUserValue()
kw = dict(software_release=software_release, key = '_'.join([requester.getRelativeUrl(), partition_reference])
software_type=software_type,
software_title=partition_reference, last_data = requester.getLastData(key)
shared=shared, requested_software_instance = None
instance_xml=instance_xml,
sla_xml=sla_xml,
state=state)
key = '_'.join([person.getRelativeUrl(), partition_reference])
value = dict( value = dict(
hash=str(kw) hash='_'.join([requester.getRelativeUrl(), str(kw)]),
) )
last_data = person.getLastData(key)
if last_data is not None and isinstance(last_data, dict): if last_data is not None and isinstance(last_data, type(value)):
requested_software_instance = portal.restrictedTraverse( requested_software_instance = self.restrictedTraverse(
last_data.get('request_instance'), None) last_data.get('request_instance'), None)
if last_data is None or not isinstance(last_data, type(value)) or \ if last_data is None or not isinstance(last_data, type(value)) or \
last_data.get('hash') != value['hash'] or \ last_data.get('hash') != value['hash'] or \
requested_software_instance is None: requested_software_instance is None:
person.requestSoftwareInstance(**kw) if compute_node_id and compute_partition_id:
requester.requestInstance(**kw)
else:
# requester is a person so we use another method
requester.requestSoftwareInstance(**kw)
requested_software_instance = self.REQUEST.get('request_instance') requested_software_instance = self.REQUEST.get('request_instance')
if requested_software_instance is not None: if requested_software_instance is not None:
value['request_instance'] = requested_software_instance\ value['request_instance'] = requested_software_instance\
.getRelativeUrl() .getRelativeUrl()
requested_software_instance.setLastData(value, key=key) requester.setLastData(value, key=key)
if requested_software_instance is None: if requested_software_instance is None:
raise SoftwareInstanceNotReady raise SoftwareInstanceNotReady
...@@ -1334,24 +923,7 @@ class SlapTool(BaseTool): ...@@ -1334,24 +923,7 @@ 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:
parameter_dict = self._getSoftwareInstanceAsParameterDict(requested_software_instance) return dumps(requested_software_instance._asSoftwareInstance())
# 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 = SoftwareInstance(**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 dumps(software_instance)
@UnrestrictedMethod @UnrestrictedMethod
def _updateComputePartitionRelatedInstanceList(self, compute_node_id, def _updateComputePartitionRelatedInstanceList(self, compute_node_id,
...@@ -1369,26 +941,7 @@ class SlapTool(BaseTool): ...@@ -1369,26 +941,7 @@ class SlapTool(BaseTool):
_getSoftwareInstanceForComputePartition(compute_node_id, _getSoftwareInstanceForComputePartition(compute_node_id,
compute_partition_id) compute_partition_id)
cache_reference = '%s-PREDLIST' % software_instance_document.getReference() software_instance_document._updateSucessorList(instance_reference_xml)
if software_instance_document.getLastData(cache_reference) != instance_reference_xml:
instance_reference_list = loads(instance_reference_xml)
current_successor_list = software_instance_document.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('SlapTool', INFO, '%s, %s: Updating successor list to %s' % (
compute_node_id, compute_partition_id, successor_list), error=False)
software_instance_document.edit(successor_list=successor_list,
comment='successor_list edited to unlink non commited instances')
software_instance_document.setLastData(instance_reference_xml, key=cache_reference)
#################################################### ####################################################
# Internals methods # Internals methods
...@@ -1446,31 +999,6 @@ class SlapTool(BaseTool): ...@@ -1446,31 +999,6 @@ class SlapTool(BaseTool):
parent_uid=self._getComputeNodeUidByReference( parent_uid=self._getComputeNodeUidByReference(
compute_node_reference)) compute_node_reference))
def _getSoftwareInstallationForComputeNode(self, url, compute_node_document):
software_installation_list = self.getPortalObject().portal_catalog.unrestrictedSearchResults(
portal_type='Software Installation',
default_aggregate_uid=compute_node_document.getUid(),
validation_state='validated',
limit=2,
url_string={'query': url, 'key': 'ExactMatch'},
)
l = len(software_installation_list)
if l == 1:
return _assertACI(software_installation_list[0].getObject())
elif l == 0:
raise NotFound('No software release %r found on compute_node %r' % (url,
compute_node_document.getReference()))
else:
raise ValueError('Wrong list of software releases on %r: %s' % (
compute_node_document.getReference(), ', '.join([q.getRelativeUrl() for q \
in software_installation_list])
))
def _getSoftwareInstallationReference(self, url, compute_node_document):
return self._getSoftwareInstallationForComputeNode(url,
compute_node_document).getReference()
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._getComputePartitionDocument(
...@@ -1499,122 +1027,13 @@ class SlapTool(BaseTool): ...@@ -1499,122 +1027,13 @@ class SlapTool(BaseTool):
else: else:
return software_instance return software_instance
@UnrestrictedMethod
def _getSoftwareInstanceAsParameterDict(self, software_instance, slave_instance_sql_list=None):
portal = software_instance.getPortalObject()
compute_partition = software_instance.getAggregateValue(portal_type="Compute Partition")
timestamp = int(compute_partition.getModificationDate())
newtimestamp = int(software_instance.getBangTimestamp(int(software_instance.getModificationDate())))
if (newtimestamp > timestamp):
timestamp = newtimestamp
instance_tree = software_instance.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)
slave_instance_list = []
if (software_instance.getPortalType() == "Software Instance"):
append = slave_instance_list.append
if slave_instance_sql_list is None:
slave_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 slave_instance in slave_instance_sql_list:
slave_instance = _assertACI(slave_instance.getObject())
# XXX Use catalog to filter more efficiently
if slave_instance.getSlapState() == "start_requested":
newtimestamp = int(slave_instance.getBangTimestamp(int(slave_instance.getModificationDate())))
append({
'slave_title': slave_instance.getTitle().decode("UTF-8"),
'slap_software_type': \
slave_instance.getSourceReference().decode("UTF-8"),
'slave_reference': slave_instance.getReference().decode("UTF-8"),
'timestamp': newtimestamp,
'xml': slave_instance.getTextContent(),
'connection_xml': slave_instance.getConnectionXml(),
})
if (newtimestamp > timestamp):
timestamp = newtimestamp
return {
'instance_guid': software_instance.getReference().decode("UTF-8"),
'instance_title': software_instance.getTitle().decode("UTF-8"),
'root_instance_title': instance_tree.getTitle().decode("UTF-8"),
'root_instance_short_title': instance_tree.getShortTitle().decode("UTF-8"),
'xml': software_instance.getTextContent(),
'connection_xml': software_instance.getConnectionXml(),
'filter_xml': software_instance.getSlaXml(),
'slap_computer_id': \
compute_partition.getParentValue().getReference().decode("UTF-8"),
'slap_computer_partition_id': \
compute_partition.getReference().decode("UTF-8"),
'slap_software_type': \
software_instance.getSourceReference().decode("UTF-8"),
'slap_software_release_url': \
software_instance.getUrlString().decode("UTF-8"),
'slave_instance_list': slave_instance_list,
'ip_list': ip_list,
'full_ip_list': full_ip_list,
'timestamp': "%i" % timestamp,
}
@UnrestrictedMethod
def _getSoftwareReleaseValueListForComputeNode(self, compute_node_reference):
"""Returns list of Software Releases documentsfor compute_node"""
compute_node_document = self._getComputeNodeDocument(compute_node_reference)
portal = self.getPortalObject()
software_release_list = []
for software_installation in portal.portal_catalog.unrestrictedSearchResults(
portal_type='Software Installation',
default_aggregate_uid=compute_node_document.getUid(),
validation_state='validated',
):
software_installation = _assertACI(software_installation.getObject())
software_release_response = SoftwareRelease(
software_release=software_installation.getUrlString().decode('UTF-8'),
computer_guid=compute_node_reference.decode('UTF-8'))
if software_installation.getSlapState() == 'destroy_requested':
software_release_response._requested_state = 'destroyed'
else:
software_release_response._requested_state = 'available'
known_state = software_installation.getTextAccessStatus()
if known_state.startswith("#access"):
software_release_response._known_state = 'available'
elif known_state.startswith("#building"):
software_release_response._known_state = 'building'
else:
software_release_response._known_state = 'error'
software_release_list.append(software_release_response)
return software_release_list
@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_document = self._getComputeNodeDocument(compute_node_id) compute_node = self._getComputeNodeDocument(compute_node_id)
software_installation = self._getSoftwareInstallationForComputeNode(url, software_installation = compute_node._getSoftwareInstallationFromUrl(url)
compute_node_document) software_installation.setErrorStatus('while installing %s' % url)
software_installation.setAccessStatus('#error while installing %s' % url)
InitializeClass(SlapTool) InitializeClass(SlapTool)
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
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