Commit a2f0cf6b authored by Rafael Monnerat's avatar Rafael Monnerat

Create API for Memcache usage on SlapOS master

See merge request nexedi/slapos.core!359
parents 307e1012 c647aab4
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2005-2010 Nexedi SA and Contributors. All Rights Reserved.
# Romain Courteaud <romain@nexedi.com>
#
# 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 adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions
from DateTime import DateTime
from App.Common import rfc1123_date
from Products.ERP5Type.Cache import DEFAULT_CACHE_SCOPE
import json
class SlapOSCacheMixin:
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
def _getAccessStatusCacheFactory(self):
return self.getPortalObject().portal_caches\
.getRamCacheRoot().get('access_status_data_cache_factory')
def _getAccessStatusPlugin(self):
return self._getAccessStatusCacheFactory().getCachePluginList()[0]
def _getAccessStatusCacheKey(self):
return "%s-ACCESS" % self.getReference()
def _getCachedAccessInfo(self):
if not self.getReference():
return None
try:
entry = self._getAccessStatusPlugin().get(
self._getAccessStatusCacheKey(), DEFAULT_CACHE_SCOPE)
except KeyError:
entry = None
else:
entry = entry.getValue()
return entry
def getAccessStatus(self):
data_json = self._getCachedAccessInfo()
last_modified = rfc1123_date(DateTime())
if data_json is None:
data_dict = {
"user": "SlapOS Master",
'created_at': '%s' % last_modified,
'since': '%s' % last_modified,
'state': "",
"text": "#error no data found for %s" % self.getReference(),
"no_data": 1
}
# Prepare for xml marshalling
#data_dict["text"] = data_dict["text"].decode("UTF-8")
#data_dict["user"] = data_dict["user"].decode("UTF-8")
return data_dict
data_dict = json.loads(data_json)
last_contact = DateTime(data_dict.get('created_at'))
data_dict["no_data_since_15_minutes"] = 0
data_dict["no_data_since_5_minutes"] = 0
if (DateTime() - last_contact) > 0.005:
data_dict["no_data_since_15_minutes"] = 1
data_dict["no_data_since_5_minutes"] = 1
elif (DateTime() - last_contact) > 0.0025:
data_dict["no_data_since_5_minutes"] = 1
return data_dict
def setAccessStatus(self, text, state=""):
user_reference = self.getPortalObject().portal_membership.getAuthenticatedMember()\
.getUserName()
previous = self._getCachedAccessInfo()
created_at = rfc1123_date(DateTime())
since = created_at
status_changed = True
if previous is not None:
previous_json = json.loads(previous)
if text.split(" ")[0] == previous_json.get("text", "").split(" ")[0]:
since = previous_json.get("since",
previous_json.get("created_at", rfc1123_date(DateTime())))
status_changed = False
if state == "":
state = previous_json.get("state", "")
value = json.dumps({
'user': '%s' % user_reference,
'created_at': '%s' % created_at,
'text': '%s' % text,
'since': '%s' % since,
'state': state
})
cache_duration = self._getAccessStatusCacheFactory().cache_duration
self._getAccessStatusPlugin().set(self._getAccessStatusCacheKey(),
DEFAULT_CACHE_SCOPE, value, cache_duration=cache_duration)
return status_changed
def getTextAccessStatus(self):
return self.getAccessStatus()['text']
def getLastAccessDate(self):
data_dict = self.getAccessStatus()
if data_dict.get("no_data") == 1:
return "%s didn't contact the server" % self.getPortalType()
date = DateTime(data_dict['created_at'])
return date.strftime('%Y/%m/%d %H:%M')
#####################
# SlapOS Last Data
#####################
def _getLastDataCacheFactory(self):
return self.getPortalObject().portal_caches\
.getRamCacheRoot().get('last_stored_data_cache_factory')
def _getLastDataPlugin(self):
return self._getLastDataCacheFactory().getCachePluginList()[0]
def setLastData(self, value, key=None):
cache_key = self.getReference()
if key is not None:
cache_key = key
cache_duration = self._getLastDataCacheFactory().cache_duration
self._getLastDataPlugin().set(cache_key, DEFAULT_CACHE_SCOPE,
value, cache_duration=cache_duration)
def getLastData(self, key=None):
cache_key = self.getReference()
if key is not None:
cache_key = key
try:
entry = self._getLastDataPlugin().get(cache_key, DEFAULT_CACHE_SCOPE)
except KeyError:
entry = None
else:
entry = entry.getValue()
return entry
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Mixin Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_recorded_property_dict</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>SlapOSCacheMixin</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.SlapOSCacheMixin</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>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Cache Factory" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_count</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>_mt_index</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>_tree</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
<item>
<key> <string>cache_duration</string> </key>
<value> <int>86400</int> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>Stores last transmitted values in order to avoid multiple writes on repetitive calls to request and set connection dict.</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>access_status_data_cache_factory</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Cache Factory</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Access Status data Cache Factory</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Length" module="BTrees.Length"/>
</pickle>
<pickle> <int>0</int> </pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="OOBTree" module="BTrees.OOBTree"/>
</pickle>
<pickle>
<none/>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="OOBTree" module="BTrees.OOBTree"/>
</pickle>
<pickle>
<none/>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Distributed Ram Cache" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>specialise/portal_memcached/default_memcached_plugin</string>
</tuple>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>volatile_cache_plugin</string> </value>
</item>
<item>
<key> <string>int_index</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Distributed Ram Cache</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Volatile Distributed Ram Cache</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -107,7 +107,9 @@
<item>
<key> <string>type_mixin</string> </key>
<value>
<tuple/>
<tuple>
<string>SlapOSCacheMixin</string>
</tuple>
</value>
</item>
</dictionary>
......
......@@ -74,7 +74,9 @@
<item>
<key> <string>type_mixin</string> </key>
<value>
<tuple/>
<tuple>
<string>SlapOSCacheMixin</string>
</tuple>
</value>
</item>
</dictionary>
......
......@@ -105,7 +105,9 @@
<item>
<key> <string>type_mixin</string> </key>
<value>
<tuple/>
<tuple>
<string>SlapOSCacheMixin</string>
</tuple>
</value>
</item>
</dictionary>
......
<type_mixin>
<portal_type id="Compute Node">
<item>SlapOSCacheMixin</item>
</portal_type>
<portal_type id="Compute Partition">
<item>SlapOSCacheMixin</item>
</portal_type>
<portal_type id="Person">
<item>SlapOSCacheMixin</item>
</portal_type>
</type_mixin>
\ No newline at end of file
import json
from DateTime import DateTime
memcached_dict = context.Base_getSlapToolMemcachedDict()
try:
d = memcached_dict[document.getReference()]
except (KeyError, TypeError):
d = {
"user": "SlapOS Master",
"text": "#error no data found for %s" % document.getReference(),
"no_data": 1
}
else:
d = json.loads(d)
last_contact = DateTime(d.get('created_at'))
d["no_data_since_15_minutes"] = 0
d["no_data_since_5_minutes"] = 0
if (DateTime() - last_contact) > 0.005:
d["no_data_since_15_minutes"] = 1
d["no_data_since_5_minutes"] = 1
elif (DateTime() - last_contact) > 0.0025:
d["no_data_since_5_minutes"] = 1
return d
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>document</string> </value>
</item>
<item>
<key> <string>_proxy_roles</string> </key>
<value>
<tuple>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Base_getNewsDict</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
from zExceptions import Unauthorized
if REQUEST is not None:
raise Unauthorized
return context.getPortalObject().portal_memcached.getMemcachedDict(
key_prefix='slap_tool',
plugin_path='portal_memcached/default_memcached_plugin')
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>REQUEST=None</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Base_getSlapToolMemcachedDict</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
import json
compute_node = context
portal = context.getPortalObject()
from zExceptions import Unauthorized
......@@ -22,14 +21,11 @@ comment = ''
if can_allocate:
# Check if compute_node has error reported
memcached_dict = context.Base_getSlapToolMemcachedDict()
try:
d = memcached_dict[compute_node.getReference()]
except KeyError:
log_dict = compute_node.getAccessStatus()
if log_dict.get("no_data") == 1:
can_allocate = False
comment = "Compute Node didn't contact the server"
else:
log_dict = json.loads(d)
if '#error' in log_dict.get('text', '#error'):
can_allocate = False
comment = 'Compute Node reported an error'
......
from DateTime import DateTime
import json
memcached_dict = context.Base_getSlapToolMemcachedDict()
try:
d = memcached_dict[context.getReference()]
except KeyError:
return "Compute Node didn't contact the server"
else:
log_dict = json.loads(d)
date = DateTime(log_dict['created_at'])
return date.strftime('%Y/%m/%d %H:%M')
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>ComputeNode_getLastContactDate</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -125,7 +125,7 @@
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>python: context.ComputeNode_getLastContactDate()</string> </value>
<value> <string>python: context.getLastAccessDate()</string> </value>
</item>
</dictionary>
</pickle>
......
from DateTime import DateTime
import json
partition = context
memcached_dict = context.Base_getSlapToolMemcachedDict()
result = ""
date = None
for si in partition.getAggregateRelatedValueList(portal_type=["Software Instance", "Slave Instance"]):
for si in context.getAggregateRelatedValueList(portal_type=["Software Instance"]):
obj = si.getObject()
if obj.getValidationState() != "validated":
......@@ -15,13 +6,6 @@ for si in partition.getAggregateRelatedValueList(portal_type=["Software Instance
if obj.getSlapState() == "destroy_requested":
continue
try:
d = memcached_dict[obj.getReference()]
except KeyError:
result = "#missing no data found for %s" % obj.getReference()
else:
d = json.loads(d)
date = DateTime(d['created_at'])
result = date.strftime('%Y/%m/%d %H:%M')
return obj.getLastAccessDate()
return result
return ""
......@@ -134,7 +134,7 @@
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>cell/ComputeNode_getLastContactDate</string> </value>
<value> <string>cell/getLastAccessDate</string> </value>
</item>
</dictionary>
</pickle>
......
"""Dirty script to return Software Instance state"""
import json
state = context.getSlapState()
has_partition = context.getAggregate(portal_type="Compute Partition")
result = 'Unable to calculate the status...'
if has_partition:
try:
memcached_dict = context.Base_getSlapToolMemcachedDict()
try:
d = memcached_dict[context.getReference()]
except KeyError:
d = context.getAccessStatus()
if d.get("no_data") == 1:
result = context.getSlapStateTitle()
else:
d = json.loads(d)
result = d['text']
if result.startswith('#access '):
result = result[len('#access '):]
except Exception:
raise
# result = 'There is system issue, please try again later.'
else:
if state in ["start_requested", "stop_requested"]:
result = 'Looking for a free partition'
......
from DateTime import DateTime
portal = context.getPortalObject()
import json
error_style = 'background-color: red; display: block; height: 2em; width: 2em; float: left; margin: 5px;'
access_style = 'background-color: green; display: block; height: 2em; width: 2em; float: left; margin: 5px;'
......@@ -14,20 +13,17 @@ software_installation = portal.portal_catalog.getResultValue(
if not software_installation or software_installation.getSlapState() == "destroy_requested":
return '<span" style="%s" title="Information not available"></a>' % error_style
memcached_dict = context.Base_getSlapToolMemcachedDict()
try:
d = memcached_dict[software_installation.getReference()]
except KeyError:
d = software_installation.getAccessStatus()
if d.get("no_data") == 1:
return "<a href='%s' style='%s'></a>" % (software_installation.getRelativeUrl(),
error_style)
else:
d = json.loads(d)
result = d['text']
date = DateTime(d['created_at'])
limit_date = DateTime() - 0.084
if result.startswith('#error ') or (date - limit_date) < 0:
result = d['text']
date = DateTime(d['created_at'])
limit_date = DateTime() - 0.084
if result.startswith('#error ') or (date - limit_date) < 0:
access_style = error_style
return "<a href='%s' style='%s' title='%s at %s'></a>" % (
return "<a href='%s' style='%s' title='%s at %s'></a>" % (
software_installation.getRelativeUrl(),
access_style, result, d['created_at'])
......@@ -7,12 +7,10 @@
from erp5.component.test.testSlapOSCloudSecurityGroup import TestSlapOSSecurityMixin
from erp5.component.test.SlapOSTestCaseMixin import changeSkin
import json
import re
import xml_marshaller
from AccessControl.SecurityManagement import getSecurityManager, \
setSecurityManager
from DateTime import DateTime
class DefaultScenarioMixin(TestSlapOSSecurityMixin):
......@@ -103,14 +101,7 @@ class DefaultScenarioMixin(TestSlapOSSecurityMixin):
return []
def setAccessToMemcached(self, agent):
memcached_dict = self.portal.portal_memcached.getMemcachedDict(
key_prefix='slap_tool',
plugin_path='portal_memcached/default_memcached_plugin')
access_date = DateTime()
memcached_dict[agent.getReference()] = json.dumps(
{"created_at":"%s" % access_date, "text": "#access "}
)
agent.setAccessStatus("#access ")
def requestComputeNode(self, title):
requestXml = self.portal.portal_slap.requestComputer(title)
......
......@@ -2,12 +2,10 @@
import transaction
from erp5.component.test.SlapOSTestCaseMixin import SlapOSTestCaseMixin
from Products.ERP5Type.tests.utils import createZODBPythonScript
import json
import time
from zExceptions import Unauthorized
from DateTime import DateTime
from erp5.component.module.DateUtils import addToDate
from App.Common import rfc1123_date
class TestSlapOSCoreSlapOSAssertInstanceTreeSuccessorAlarm(
SlapOSTestCaseMixin):
......@@ -443,13 +441,7 @@ class TestSlapOSUpdateComputeNodeCapacityScopeAlarm(SlapOSTestCaseMixin):
)
self.compute_node.edit(capacity_scope='open')
self.compute_node.validate()
memcached_dict = self.portal.portal_memcached.getMemcachedDict(
key_prefix='slap_tool',
plugin_path='portal_memcached/default_memcached_plugin')
memcached_dict[self.compute_node.getReference()] = json.dumps({
'text': '#access ok',
'created_at': rfc1123_date(DateTime())
})
self.compute_node.setAccessStatus("#access ok")
transaction.commit()
def test_ComputeNode_checkAndUpdateCapacityScope(self):
......@@ -517,14 +509,12 @@ class TestSlapOSUpdateComputeNodeCapacityScopeAlarm(SlapOSTestCaseMixin):
self.compute_node.getCapacityQuantity())
def test_ComputeNode_checkAndUpdateCapacityScope_with_old_access(self):
memcached_dict = self.portal.portal_memcached.getMemcachedDict(
key_prefix='slap_tool',
plugin_path='portal_memcached/default_memcached_plugin')
memcached_dict[self.compute_node.getReference()] = json.dumps({
'text': '#access ok',
'created_at': rfc1123_date(addToDate(DateTime(),
to_add={'minute': -11}))
})
try:
self.pinDateTime(addToDate(DateTime(),to_add={'minute': -11}))
self.compute_node.setAccessStatus("#access ok")
finally:
self.unpinDateTime()
self.compute_node.ComputeNode_checkAndUpdateCapacityScope()
self.assertEqual('close', self.compute_node.getCapacityScope())
self.assertEqual("Compute Node didn't contact for more than 10 minutes",
......@@ -552,24 +542,14 @@ class TestSlapOSUpdateComputeNodeCapacityScopeAlarm(SlapOSTestCaseMixin):
self.assertEqual('open', self.compute_node.getCapacityScope())
def test_ComputeNode_checkAndUpdateCapacityScope_with_error(self):
memcached_dict = self.portal.portal_memcached.getMemcachedDict(
key_prefix='slap_tool',
plugin_path='portal_memcached/default_memcached_plugin')
memcached_dict[self.compute_node.getReference()] = json.dumps({
'text': '#error not ok'
})
self.compute_node.setAccessStatus('#error not ok')
self.compute_node.ComputeNode_checkAndUpdateCapacityScope()
self.assertEqual('close', self.compute_node.getCapacityScope())
self.assertEqual("Compute Node reported an error",
self.compute_node.workflow_history['edit_workflow'][-1]['comment'])
def test_ComputeNode_checkAndUpdateCapacityScope_with_error_non_public(self):
memcached_dict = self.portal.portal_memcached.getMemcachedDict(
key_prefix='slap_tool',
plugin_path='portal_memcached/default_memcached_plugin')
memcached_dict[self.compute_node.getReference()] = json.dumps({
'text': '#error not ok'
})
self.compute_node.setAccessStatus('#error not ok')
self.compute_node.edit(allocation_scope='open/personal')
self.compute_node.ComputeNode_checkAndUpdateCapacityScope()
self.assertEqual('open', self.compute_node.getCapacityScope())
......
mixin.erp5.SlapOSCacheMixin
\ No newline at end of file
acl_users/slapos_access_token_extraction
acl_users/slapos_machine
acl_users/slapos_shadow
computer_model_module/template_computer_model
computer_model_module/template_computer_model/**
compute_node_module/template_compute_node
compute_node_module/template_compute_node/**
computer_model_module/template_computer_model
computer_model_module/template_computer_model/**
instance_tree_module/template_instance_tree
person_module/template_member
person_module/template_member/**
......@@ -17,6 +17,10 @@ portal_alarms/slapos_garbage_collect_destroyed_root_tree
portal_alarms/slapos_garbage_collect_non_allocated_root_tree
portal_alarms/slapos_stop_collect_instance
portal_alarms/slapos_update_compute_node_capacity_scope
portal_caches/access_status_data_cache_factory
portal_caches/access_status_data_cache_factory/volatile_cache_plugin
portal_caches/last_stored_data_cache_factory
portal_caches/last_stored_data_cache_factory/volatile_cache_plugin
product_module/compute_node
software_installation_module/template_software_installation
software_instance_module/template_slave_instance
......
Compute Node | SlapOSCacheMixin
Compute Partition | SlapOSCacheMixin
Person | SlapOSCacheMixin
\ No newline at end of file
from DateTime import DateTime
import json
portal = context.getPortalObject()
from Products.ERP5Type.Document import newTempBase
......@@ -19,26 +18,11 @@ show_all = False
if "show_all" in kw:
show_all = kw.pop("omit_zero_ticket")
memcached_dict = context.getPortalObject().portal_memcached.getMemcachedDict(
key_prefix='slap_tool',
plugin_path='portal_memcached/default_memcached_plugin')
def checkForError(reference):
try:
d = memcached_dict[reference]
except KeyError:
return 1
d = json.loads(d)
result = d['text']
#last_contact = DateTime(d.get('created_at'))
# Optimise by checking memcache information first.
result = context.getAccessStatusText()
if result.startswith('#error '):
return 1
for compute_node in portal.portal_catalog(
default_allocation_scope_uid = [personal_category_uid, public_category_uid, friend_category_uid],
select_list={"reference": None},
......
from DateTime import DateTime
import json
portal = context.getPortalObject()
if portal.ERP5Site_isSupportRequestCreationClosed():
......@@ -22,7 +20,6 @@ compute_node_reference = context.getReference()
compute_node_title = context.getTitle()
should_notify = True
memcached_dict = context.Base_getSlapToolMemcachedDict()
tolerance = DateTime()-0.5
for software_installation in software_installation_list:
should_notify = False
......@@ -31,9 +28,12 @@ for software_installation in software_installation_list:
continue
reference = software_installation.getReference()
try:
d = memcached_dict[reference]
d = json.loads(d)
d = software_installation.getAccessStatus()
if d.get("no_data", None) == 1:
ticket_title = "[MONITORING] No information for %s on %s" % (reference, compute_node_reference)
description = "The software release %s did not started to build on %s since %s" % \
(software_installation.getUrlString(), compute_node_title, software_installation.getCreationDate())
else:
last_contact = DateTime(d.get('created_at'))
if d.get("text").startswith("building"):
should_notify = True
......@@ -49,13 +49,7 @@ for software_installation in software_installation_list:
description = "The software release %s is failing to build for too long on %s, started on %s" % \
(software_installation.getUrlString(), compute_node_title, software_installation.getCreationDate())
except KeyError:
ticket_title = "[MONITORING] No information for %s on %s" % (reference, compute_node_reference)
description = "The software release %s did not started to build on %s since %s" % \
(software_installation.getUrlString(), compute_node_title, software_installation.getCreationDate())
if should_notify:
support_request = context.Base_generateSupportRequestForSlapOS(
ticket_title,
description,
......
from DateTime import DateTime
import json
portal = context.getPortalObject()
if portal.ERP5Site_isSupportRequestCreationClosed():
......@@ -18,50 +16,49 @@ reference = context.getReference()
compute_node_title = context.getTitle()
ticket_title = "[MONITORING] Lost contact with compute_node %s" % reference
description = ""
should_notify = True
last_contact = "No Contact Information"
memcached_dict = context.Base_getSlapToolMemcachedDict()
try:
d = memcached_dict[reference]
d = json.loads(d)
d = context.getAccessStatus()
# Ignore if data isn't present.
if d.get("no_data") == 1:
description = "The Compute Node %s (%s) has not contacted the server (No Contact Information)" % (
compute_node_title, reference)
else:
last_contact = DateTime(d.get('created_at'))
if (DateTime() - last_contact) > 0.01:
description = "The Compute Node %s (%s) has not contacted the server for more than 30 minutes" \
"(last contact date: %s)" % (compute_node_title, reference, last_contact)
else:
should_notify = False
except KeyError:
description = "The Compute Node %s (%s) has not contacted the server (No Contact Information)" % (
compute_node_title, reference)
# Nothing to notify.
return
if should_notify:
support_request = context.Base_generateSupportRequestForSlapOS(
support_request = context.Base_generateSupportRequestForSlapOS(
ticket_title,
description,
context.getRelativeUrl()
)
)
person = context.getSourceAdministrationValue(portal_type="Person")
if not person:
person = context.getSourceAdministrationValue(portal_type="Person")
if not person:
return support_request
# Send Notification message
notification_reference = 'slapos-crm-compute_node_check_state.notification'
notification_message = portal.portal_notifications.getDocumentValue(
# Send Notification message
notification_reference = 'slapos-crm-compute_node_check_state.notification'
notification_message = portal.portal_notifications.getDocumentValue(
reference=notification_reference)
if notification_message is None:
if notification_message is None:
message = """%s""" % description
else:
else:
mapping_dict = {'compute_node_title':context.getTitle(),
'compute_node_id':reference,
'last_contact':last_contact}
message = notification_message.asText(
substitution_method_parameter_dict={'mapping_dict':mapping_dict})
support_request.SupportRequest_trySendNotificationMessage(
support_request.SupportRequest_trySendNotificationMessage(
ticket_title,
message, person.getRelativeUrl())
return support_request
return support_request
import json
portal = context.getPortalObject()
compute_node = context
now_date = DateTime()
......@@ -7,20 +6,16 @@ if (now_date - compute_node.getCreationDate()) < maximum_days:
# This compute_node was created recently skip
return True
memcached_dict = context.Base_getSlapToolMemcachedDict()
# Check if there is some information in memcached
try:
d = memcached_dict[compute_node.getReference()]
except KeyError:
message_dict = context.getAccessStatus()
# Ignore if data isn't present.
if message_dict.get("no_data", None) == 1:
message_dict = {}
else:
message_dict = json.loads(d)
if message_dict.has_key('created_at'):
contact_date = DateTime(message_dict.get('created_at').encode('utf-8'))
return (now_date - contact_date) < maximum_days
# If no memcached, check in consumption report
# If no access status information, check in consumption report
for sale_packing_list in portal.portal_catalog(
portal_type="Sale Packing List Line",
simulation_state="delivered",
......
from DateTime import DateTime
import json
memcached_dict = context.Base_getSlapToolMemcachedDict()
try:
d = memcached_dict[context.getReference()]
except KeyError:
# Information not available
return None
d = context.getAccessStatus()
# Ignore if data isn't present.
if d.get("no_data", None) == 1:
return
d = json.loads(d)
result = d['text']
last_contact = DateTime(d.get('created_at'))
# Optimise by checking memcache information first.
if result.startswith('#error '):
return last_contact
return None
if d['text'].startswith('#error '):
return DateTime(d.get('created_at'))
from DateTime import DateTime
import json
if context.getAggregateValue(portal_type="Compute Partition") is not None:
memcached_dict = context.Base_getSlapToolMemcachedDict()
try:
d = memcached_dict[context.getReference()]
except KeyError:
d = context.getAccessStatus()
# Ignore if data isn't present.
if d.get("no_data", None) == 1:
if include_message:
return "Not possible to connect"
return
d = json.loads(d)
result = d['text']
last_contact = DateTime(d.get('created_at'))
since = DateTime(d.get('since'))
# Optimise by checking memcache information first.
if result.startswith('#error '):
if ((DateTime()-since)*24*60) > tolerance:
if include_created_at and not include_since:
......@@ -24,7 +20,6 @@ if context.getAggregateValue(portal_type="Compute Partition") is not None:
return result, last_contact, since
return result
# XXX time limit of 48 hours for run at least once.
if include_message and include_created_at and not include_since:
return result, last_contact
elif include_message and include_created_at and include_since:
......
......@@ -6,7 +6,6 @@
#
from DateTime import DateTime
import json
if context.getSimulationState() == "invalidated":
return "Closed Ticket"
......@@ -18,21 +17,19 @@ if document is None:
aggregate_portal_type = document.getPortalType()
memcached_dict = context.Base_getSlapToolMemcachedDict()
if aggregate_portal_type == "Compute Node":
if document.getMonitorScope() == "disabled":
return "Monitor is disabled to the related %s." % document.getPortalType()
try:
d = memcached_dict[document.getReference()]
d = json.loads(d)
d = context.getAccessStatus()
if d.get("no_data", None) == 1:
return "No Contact Information"
last_contact = DateTime(d.get('created_at'))
if (DateTime() - last_contact) < 0.01:
return "All OK, latest contact: %s " % last_contact
else:
return "Problem, latest contact: %s" % last_contact
except KeyError:
return "No Contact Information"
if aggregate_portal_type == "Software Installation":
compute_node_title = document.getAggregateTitle()
......@@ -42,9 +39,11 @@ if aggregate_portal_type == "Software Installation":
if document.getSlapState() not in ["start_requested", "stop_requested"]:
return "Software Installation is Destroyed."
try:
d = memcached_dict[document.getReference()]
d = json.loads(d)
d = context.getAccessStatus()
if d.get("no_data", None) == 1:
return "The software release %s did not started to build on %s since %s" % \
(document.getUrlString(), compute_node_title, document.getCreationDate())
last_contact = DateTime(d.get('created_at'))
if d.get("text").startswith("building"):
return "The software release %s is building for mode them 12 hours on %s, started on %s" % \
......@@ -55,11 +54,6 @@ if aggregate_portal_type == "Software Installation":
return "The software release %s is failing to build for too long on %s, started on %s" % \
(document.getUrlString(), compute_node_title, document.getCreationDate())
except KeyError:
return "The software release %s did not started to build on %s since %s" % \
(document.getUrlString(), compute_node_title, document.getCreationDate())
if aggregate_portal_type == "Instance Tree":
if document.getMonitorScope() == "disabled":
return "Monitor is disabled to the related %s." % document.getPortalType()
......
......@@ -25,6 +25,9 @@ import transaction
from erp5.component.test.SlapOSTestCaseMixin import \
SlapOSTestCaseMixin,SlapOSTestCaseMixinWithAbort, simulate
from DateTime import DateTime
from App.Common import rfc1123_date
from Products.ERP5Type.Cache import DEFAULT_CACHE_SCOPE
from Products.ERP5Type.tests.utils import createZODBPythonScript
import json
......@@ -826,13 +829,7 @@ class TestComputeNode_hasContactedRecently(SlapOSTestCaseMixinWithAbort):
@simulate('ComputeNode_getCreationDate', '*args, **kwargs','return DateTime() - 32')
def test_ComputeNode_hasContactedRecently_memcached(self):
compute_node = self._makeComputeNode()[0]
memcached_dict = self.portal.portal_memcached.getMemcachedDict(
key_prefix='slap_tool',
plugin_path='portal_memcached/default_memcached_plugin')
memcached_dict[compute_node.getReference()] = json.dumps({
"created_at": DateTime().strftime("%Y/%m/%d %H:%M")
})
compute_node.setAccessStatus("#access ")
self.tic()
compute_node.getCreationDate = self.portal.ComputeNode_getCreationDate
......@@ -843,13 +840,12 @@ class TestComputeNode_hasContactedRecently(SlapOSTestCaseMixinWithAbort):
@simulate('ComputeNode_getCreationDate', '*args, **kwargs','return DateTime() - 32')
def test_ComputeNode_hasContactedRecently_memcached_oudated_no_spl(self):
compute_node = self._makeComputeNode()[0]
memcached_dict = self.portal.portal_memcached.getMemcachedDict(
key_prefix='slap_tool',
plugin_path='portal_memcached/default_memcached_plugin')
try:
self.pinDateTime(DateTime()-32)
compute_node.setAccessStatus("#access ")
finally:
self.unpinDateTime()
memcached_dict[compute_node.getReference()] = json.dumps({
"created_at": (DateTime() - 32).strftime("%Y/%m/%d %H:%M")
})
self.tic()
compute_node.getCreationDate = self.portal.ComputeNode_getCreationDate
......@@ -860,13 +856,12 @@ class TestComputeNode_hasContactedRecently(SlapOSTestCaseMixinWithAbort):
@simulate('ComputeNode_getCreationDate', '*args, **kwargs','return DateTime() - 32')
def test_ComputeNode_hasContactedRecently_memcached_oudated_with_spl(self):
compute_node = self._makeComputeNode()[0]
memcached_dict = self.portal.portal_memcached.getMemcachedDict(
key_prefix='slap_tool',
plugin_path='portal_memcached/default_memcached_plugin')
try:
self.pinDateTime(DateTime()-32)
compute_node.setAccessStatus("#access ")
finally:
self.unpinDateTime()
memcached_dict[compute_node.getReference()] = json.dumps({
"created_at": (DateTime() - 32).strftime("%Y/%m/%d %H:%M")
})
self.createSPL(compute_node)
self.tic()
......@@ -1224,13 +1219,11 @@ class TestSlapOSComputeNode_CheckState(TestCRMSkinsMixin):
@simulate('ERP5Site_isSupportRequestCreationClosed', '*args, **kwargs','return 0')
def test_ComputeNode_checkState_call_support_request(self):
compute_node = self._makeComputeNode(owner=self.makePerson(user=0))[0]
memcached_dict = self.portal.portal_memcached.getMemcachedDict(
key_prefix='slap_tool',
plugin_path='portal_memcached/default_memcached_plugin')
memcached_dict[compute_node.getReference()] = json.dumps(
{"created_at":"%s" % (DateTime() - 1.1)}
)
try:
self.pinDateTime(DateTime()-1.1)
compute_node.setAccessStatus("#access ")
finally:
self.unpinDateTime()
self._simulateBase_generateSupportRequestForSlapOS()
support_request = self._makeSupportRequest()
......@@ -1279,14 +1272,11 @@ class TestSlapOSComputeNode_CheckState(TestCRMSkinsMixin):
compute_node = self._makeComputeNode(owner=self.makePerson(user=0))[0]
person = compute_node.getSourceAdministrationValue()
memcached_dict = self.portal.portal_memcached.getMemcachedDict(
key_prefix='slap_tool',
plugin_path='portal_memcached/default_memcached_plugin')
memcached_dict[compute_node.getReference()] = json.dumps(
{"created_at":"%s" % (DateTime() - 0.1)}
)
try:
self.pinDateTime(DateTime()-1.1)
compute_node.setAccessStatus("#access ")
finally:
self.unpinDateTime()
self.portal.REQUEST['test_ComputeNode_checkState_notify'] = \
self._makeNotificationMessage(compute_node.getReference())
......@@ -1524,14 +1514,7 @@ class TestSlapOSHasError(SlapOSTestCaseMixin):
self._makeComputeNode()
self._makeComputePartitionList()
memcached_dict = self.portal.portal_memcached.getMemcachedDict(
key_prefix='slap_tool',
plugin_path='portal_memcached/default_memcached_plugin')
error_date = DateTime()
memcached_dict[instance.getReference()] = json.dumps(
{"created_at":"%s" % error_date, "text": "#error "}
)
instance.setAccessStatus("#error ")
self.assertEqual(instance.SoftwareInstance_hasReportedError(), None)
......@@ -1539,10 +1522,7 @@ class TestSlapOSHasError(SlapOSTestCaseMixin):
self.assertEqual(str(instance.SoftwareInstance_hasReportedError()), '#error ')
memcached_dict[instance.getReference()] = json.dumps(
{"created_at":"%s" % error_date, "text": "#access "}
)
instance.setAccessStatus("#access ")
self.assertEqual(instance.SoftwareInstance_hasReportedError(), None)
def test_SoftwareInstallation_hasReportedError(self):
......@@ -1552,22 +1532,19 @@ class TestSlapOSHasError(SlapOSTestCaseMixin):
software_release.getUrlString()
)
memcached_dict = self.portal.portal_memcached.getMemcachedDict(
key_prefix='slap_tool',
plugin_path='portal_memcached/default_memcached_plugin')
self.assertEqual(installation.SoftwareInstallation_hasReportedError(), None)
error_date = DateTime()
memcached_dict[installation.getReference()] = json.dumps(
{"created_at":"%s" % error_date, "text": "#error "}
)
self.assertEqual(installation.SoftwareInstallation_hasReportedError(), error_date)
try:
self.pinDateTime(error_date)
installation.setAccessStatus("#error ")
finally:
self.unpinDateTime()
memcached_dict[installation.getReference()] = json.dumps(
{"created_at":"%s" % error_date, "text": "#building "}
)
self.assertEqual(
rfc1123_date(installation.SoftwareInstallation_hasReportedError()),
rfc1123_date(error_date))
installation.setAccessStatus("#building ")
self.assertEqual(installation.SoftwareInstallation_hasReportedError(), None)
......@@ -1600,14 +1577,13 @@ class TestSlapOSHasError(SlapOSTestCaseMixin):
self._makeComputePartitionList()
instance.setAggregateValue(self.compute_node.partition1)
memcached_dict = self.portal.portal_memcached.getMemcachedDict(
key_prefix='slap_tool',
plugin_path='portal_memcached/default_memcached_plugin')
error_date = DateTime()
memcached_dict[instance.getReference()] = json.dumps(
value = json.dumps(
{"created_at":"%s" % error_date, "text": "#error ", "since": "%s" % (error_date - 2)}
)
cache_duration = instance._getAccessStatusCacheFactory().cache_duration
instance._getAccessStatusPlugin().set(instance._getAccessStatusCacheKey(),
DEFAULT_CACHE_SCOPE, value, cache_duration=cache_duration)
self.assertEqual(
'Visited by InstanceTree_createSupportRequestEvent %s %s' % \
......@@ -1615,9 +1591,7 @@ class TestSlapOSHasError(SlapOSTestCaseMixin):
"slapos-crm-instance-tree-instance-state.notification"),
instance_tree.InstanceTree_checkSoftwareInstanceState())
memcached_dict[instance.getReference()] = json.dumps(
{"created_at":"%s" % error_date, "text": "#access "}
)
instance.setAccessStatus("#access ")
self.assertEqual(None,
instance_tree.InstanceTree_checkSoftwareInstanceState())
......@@ -1720,13 +1694,7 @@ class TestSlapOSHasError(SlapOSTestCaseMixin):
instance.requestInstance(**kw)
self.tic()
memcached_dict = self.portal.portal_memcached.getMemcachedDict(
key_prefix='slap_tool',
plugin_path='portal_memcached/default_memcached_plugin')
error_date = DateTime()
memcached_dict[instance.getReference()] = json.dumps(
{"created_at":"%s" % error_date, "text": "#access "}
)
instance.setAccessStatus("#access ")
self.assertEqual(
'Visited by InstanceTree_createSupportRequestEvent %s %s' % \
......@@ -1761,15 +1729,7 @@ class TestSlapOSHasError(SlapOSTestCaseMixin):
self._makeComputePartitionList()
instance.setAggregateValue(self.compute_node.partition1)
memcached_dict = self.portal.portal_memcached.getMemcachedDict(
key_prefix='slap_tool',
plugin_path='portal_memcached/default_memcached_plugin')
error_date = DateTime()
memcached_dict[instance.getReference()] = json.dumps(
{"created_at":"%s" % error_date, "text": "#error "}
)
instance.setAccessStatus("#error ")
self.assertEqual(
None,
instance_tree.InstanceTree_checkSoftwareInstanceState())
......
......@@ -3,12 +3,12 @@ if REQUEST is not None:
raise Unauthorized
def get_compute_partition_dict(reference):
compute_node_dict = context.Base_getNewsDict(context)
compute_node_dict = context.getAccessStatus()
compute_partition_dict = { }
for compute_partition in context.objectValues(portal_type="Compute Partition"):
software_instance = compute_partition.getAggregateRelatedValue(portal_type="Software Instance")
if software_instance is not None:
compute_partition_dict[compute_partition.getTitle()] = context.Base_getNewsDict(software_instance)
compute_partition_dict[compute_partition.getTitle()] = software_instance.getAccessStatus()
return {"compute_node": compute_node_dict,
"partition": compute_partition_dict}
......
......@@ -2,4 +2,4 @@ from zExceptions import Unauthorized
if REQUEST is not None:
raise Unauthorized
return context.Base_getNewsDict(context)
return context.getAccessStatus()
......@@ -25,4 +25,4 @@ if portal_type == "Software Instance" and slap_state == "destroy_requested":
"is_destroyed": 1
}
return context.Base_getNewsDict(context)
return context.getAccessStatus()
......@@ -3,10 +3,7 @@ if REQUEST is not None:
raise Unauthorized
from DateTime import DateTime
import json
slap_state = context.getSlapState()
_translate = context.Base_translateString
NOT_ALLOCATED = _translate("Searching for partition")
......@@ -26,13 +23,10 @@ if compute_partition is not None:
if instance.getPortalType() == "Slave Instance":
instance = compute_partition.getAggregateRelatedValue(portal_type="Software Instance")
memcached_dict = instance.Base_getSlapToolMemcachedDict()
try:
d = memcached_dict[instance.getReference()]
except KeyError:
d = instance.getAccessStatus()
if d.get("no_data") == 1:
return _translate(instance.getSlapStateTitle())
d = json.loads(d)
result = d['text']
reported_state = d.get("state", "")
if reported_state == "":
......
......@@ -24,6 +24,7 @@ from erp5.component.test.SlapOSTestCaseMixin import \
SlapOSTestCaseMixinWithAbort, simulate
from zExceptions import Unauthorized
from App.Common import rfc1123_date
from Products.ERP5Type.Cache import DEFAULT_CACHE_SCOPE
from DateTime import DateTime
import json
......@@ -38,10 +39,18 @@ class TestSlapOSHalJsonStyleMixin(SlapOSTestCaseMixinWithAbort):
maxDiff = None
def afterSetUp(self):
SlapOSTestCaseMixinWithAbort.afterSetUp(self)
self.created_at = rfc1123_date(DateTime())
d = DateTime()
self.pinDateTime(d)
self.created_at = rfc1123_date(d)
self.changeSkin('Hal')
def _logFakeAccess(self, reference, text="#access OK", state='start_requested'):
def beforeTearDown(self):
SlapOSTestCaseMixinWithAbort.beforeTearDown(self)
self.unpinDateTime()
def _logFakeAccess(self, document, text="#access OK", state='start_requested'):
value = json.dumps({
'user': 'SlapOS Master',
'created_at': '%s' % self.created_at,
......@@ -49,8 +58,9 @@ class TestSlapOSHalJsonStyleMixin(SlapOSTestCaseMixinWithAbort):
'since': '%s' % self.created_at,
'state': state
})
memcached_dict = self.portal.Base_getSlapToolMemcachedDict()
memcached_dict[reference] = value
cache_duration = document._getAccessStatusCacheFactory().cache_duration
document._getAccessStatusPlugin().set(document._getAccessStatusCacheKey(),
DEFAULT_CACHE_SCOPE, value, cache_duration=cache_duration)
def _makePerson(self, **kw):
person_user = self.makePerson(**kw)
......@@ -71,8 +81,8 @@ class TestSlapOSHalJsonStyleMixin(SlapOSTestCaseMixinWithAbort):
.template_software_instance.Base_createCloneDocument(batch_mode=1)
instance.edit(reference="TESTSOFTINST-%s" % instance.getId())
instance.validate()
self.changeSkin('Hal')
self.tic()
self.changeSkin('Hal')
return instance
def _makeSlaveInstance(self):
......@@ -80,6 +90,7 @@ class TestSlapOSHalJsonStyleMixin(SlapOSTestCaseMixinWithAbort):
.template_slave_instance.Base_createCloneDocument(batch_mode=1)
instance.validate()
self.tic()
self.changeSkin('Hal')
return instance
def _makeComputeNode(self, owner=None, allocation_scope='open/public'):
......@@ -179,7 +190,10 @@ class TestInstanceTree_getNewsDict(TestSlapOSHalJsonStyleMixin):
self.tic()
self.changeSkin('Hal')
news_dict = instance_tree.InstanceTree_getNewsDict()
expected_news_dict = {'instance': [{'no_data': 1,
expected_news_dict = {'instance': [{'created_at': self.created_at,
'no_data': 1,
'since': self.created_at,
'state': '',
'text': '#error no data found for %s' % instance.getReference(),
'user': 'SlapOS Master'}]}
self.assertEqual(news_dict, expected_news_dict)
......@@ -208,10 +222,16 @@ class TestInstanceTree_getNewsDict(TestSlapOSHalJsonStyleMixin):
self.tic()
self.changeSkin('Hal')
news_dict = instance_tree.InstanceTree_getNewsDict()
expected_news_dict = {'instance': [{'no_data': 1,
expected_news_dict = {'instance': [{'created_at': self.created_at,
'no_data': 1,
'since': self.created_at,
'state': '',
'text': '#error no data found for %s' % instance0.getReference(),
'user': 'SlapOS Master'},
{'no_data': 1,
{'created_at': self.created_at,
'no_data': 1,
'since': self.created_at,
'state': '',
'text': '#error no data found for %s' % instance.getReference(),
'user': 'SlapOS Master'}]}
self.assertEqual(news_dict["instance"], expected_news_dict["instance"])
......@@ -222,15 +242,15 @@ class TestSoftwareInstance_getNewsDict(TestSlapOSHalJsonStyleMixin):
def test(self):
instance = self._makeInstance()
self._logFakeAccess(instance.getReference())
self._logFakeAccess(instance)
news_dict = instance.SoftwareInstance_getNewsDict()
expected_news_dict = {u'created_at': self.created_at,
expected_news_dict = {'created_at': self.created_at,
'no_data_since_15_minutes': 0,
'no_data_since_5_minutes': 0,
'since': self.created_at,
'state': 'start_requested',
'text': u'#access OK',
u'user': u'SlapOS Master'}
'text': '#access OK',
'user': 'SlapOS Master'}
self.assertEqual(news_dict, expected_news_dict)
# Ensure it don't raise error when converting to JSON
json.dumps(news_dict)
......@@ -238,8 +258,13 @@ class TestSoftwareInstance_getNewsDict(TestSlapOSHalJsonStyleMixin):
def test_no_data(self):
instance = self._makeInstance()
self.changeSkin('Hal')
news_dict = instance.SoftwareInstance_getNewsDict()
expected_news_dict = {'no_data': 1,
expected_news_dict = {'created_at': self.created_at,
'no_data': 1,
'since': self.created_at,
'state': '',
'text': '#error no data found for %s' % instance.getReference(),
'user': 'SlapOS Master'}
self.assertEqual(news_dict, expected_news_dict)
......@@ -286,51 +311,51 @@ class TestSoftwareInstallation_getNewsDict(TestSlapOSHalJsonStyleMixin):
def test(self):
installation = self._makeSoftwareInstallation()
self._logFakeAccess(installation.getReference())
self._logFakeAccess(installation)
news_dict = installation.SoftwareInstallation_getNewsDict()
expected_news_dict = {u'created_at': self.created_at,
expected_news_dict = {'created_at': self.created_at,
'no_data_since_15_minutes': 0,
'no_data_since_5_minutes': 0,
'since': self.created_at,
'state': 'start_requested',
'text': u'#access OK',
u'user': u'SlapOS Master'}
'text': '#access OK',
'user': 'SlapOS Master'}
self.assertEqual(news_dict, expected_news_dict)
# Ensure it don't raise error when converting to JSON
json.dumps(news_dict)
def test_stopped(self):
installation = self._makeSoftwareInstallation()
self._logFakeAccess(installation.getReference(),
self._logFakeAccess(installation,
state='stop_requested')
news_dict = installation.SoftwareInstallation_getNewsDict()
installation.getSlapState = fakeStopRequestedSlapState
expected_news_dict = {u'created_at': self.created_at,
expected_news_dict = {'created_at': self.created_at,
'no_data_since_15_minutes': 0,
'no_data_since_5_minutes': 0,
'since': self.created_at,
'state': 'stop_requested',
'text': u'#access OK',
u'user': u'SlapOS Master'}
'text': '#access OK',
'user': 'SlapOS Master'}
self.assertEqual(news_dict, expected_news_dict)
# Ensure it don't raise error when converting to JSON
json.dumps(news_dict)
def test_destroyed(self):
installation = self._makeSoftwareInstallation()
self._logFakeAccess(installation.getReference(),
self._logFakeAccess(installation,
state='destroy_requested')
news_dict = installation.SoftwareInstallation_getNewsDict()
installation.getSlapState = fakeDestroyRequestedSlapState
expected_news_dict = {u'created_at': self.created_at,
expected_news_dict = {'created_at': self.created_at,
'no_data_since_15_minutes': 0,
'no_data_since_5_minutes': 0,
'since': self.created_at,
'state': 'destroy_requested',
'text': u'#access OK',
u'user': u'SlapOS Master'}
'text': '#access OK',
'user': 'SlapOS Master'}
self.assertEqual(news_dict, expected_news_dict)
# Ensure it don't raise error when converting to JSON
json.dumps(news_dict)
......@@ -338,7 +363,10 @@ class TestSoftwareInstallation_getNewsDict(TestSlapOSHalJsonStyleMixin):
def test_no_data(self):
installation = self._makeSoftwareInstallation()
news_dict = installation.SoftwareInstallation_getNewsDict()
expected_news_dict = {'no_data': 1,
expected_news_dict = {'created_at': self.created_at,
'no_data': 1,
'since': self.created_at,
'state': '',
'text': '#error no data found for %s' % installation.getReference(),
'user': 'SlapOS Master'}
self.assertEqual(news_dict, expected_news_dict)
......@@ -349,16 +377,16 @@ class TestComputeNode_getNewsDict(TestSlapOSHalJsonStyleMixin):
def test(self):
compute_node = self._makeComputeNode()
self._logFakeAccess(compute_node.getReference())
self._logFakeAccess(compute_node)
news_dict = compute_node.ComputeNode_getNewsDict()
expected_news_dict = {'compute_node':
{u'created_at': self.created_at,
{'created_at': self.created_at,
'no_data_since_15_minutes': 0,
'no_data_since_5_minutes': 0,
'since': self.created_at,
'state': 'start_requested',
'text': u'#access OK',
u'user': u'SlapOS Master'},
'text': '#access OK',
'user': 'SlapOS Master'},
'partition': {}
}
self.assertEqual(news_dict, expected_news_dict)
......@@ -367,7 +395,7 @@ class TestComputeNode_getNewsDict(TestSlapOSHalJsonStyleMixin):
def test_stopped(self):
compute_node = self._makeComputeNode()
self._logFakeAccess(compute_node.getReference(),
self._logFakeAccess(compute_node,
state='stop_requested')
news_dict = compute_node.ComputeNode_getNewsDict()
compute_node.getSlapState = fakeStopRequestedSlapState
......@@ -388,7 +416,7 @@ class TestComputeNode_getNewsDict(TestSlapOSHalJsonStyleMixin):
def test_destroyed(self):
compute_node = self._makeComputeNode()
self._logFakeAccess(compute_node.getReference(),
self._logFakeAccess(compute_node,
state='destroy_requested')
news_dict = compute_node.ComputeNode_getNewsDict()
compute_node.getSlapState = fakeDestroyRequestedSlapState
......@@ -399,8 +427,8 @@ class TestComputeNode_getNewsDict(TestSlapOSHalJsonStyleMixin):
'no_data_since_5_minutes': 0,
'since': self.created_at,
'state': 'destroy_requested',
'text': u'#access OK',
'user': u'SlapOS Master'},
'text': '#access OK',
'user': 'SlapOS Master'},
'partition': {}
}
self.assertEqual(news_dict, expected_news_dict)
......@@ -411,7 +439,10 @@ class TestComputeNode_getNewsDict(TestSlapOSHalJsonStyleMixin):
compute_node = self._makeComputeNode()
news_dict = compute_node.ComputeNode_getNewsDict()
expected_news_dict = {'compute_node':
{'no_data': 1,
{'created_at': self.created_at,
'no_data': 1,
'since': self.created_at,
'state': '',
'text': '#error no data found for %s' % compute_node.getReference(),
'user': 'SlapOS Master'},
'partition': {}
......@@ -426,17 +457,20 @@ class TestComputeNode_getNewsDict(TestSlapOSHalJsonStyleMixin):
instance.setAggregateValue(compute_node.slappart0)
self.tic()
self._logFakeAccess(compute_node.getReference())
self._logFakeAccess(compute_node)
news_dict = compute_node.ComputeNode_getNewsDict()
expected_news_dict = {'compute_node':
{'created_at': self.created_at,
{u'created_at': u'%s' % self.created_at,
'no_data_since_15_minutes': 0,
'no_data_since_5_minutes': 0,
u'since': u'%s' % self.created_at,
u'state': u'start_requested',
u'text': u'#access OK',
u'user': u'SlapOS Master'},
'partition': {'slappart0': {'created_at': self.created_at,
'no_data': 1,
'since': self.created_at,
'state': 'start_requested',
'text': '#access OK',
'user': 'SlapOS Master'},
'partition': {'slappart0': {'no_data': 1,
'state': '',
'text': '#error no data found for %s' % (instance.getReference()),
'user': 'SlapOS Master'}}
}
......@@ -454,34 +488,36 @@ class TestComputerNetwork_getNewsDict(TestSlapOSHalJsonStyleMixin):
compute_node.setSubordinationValue(network)
self.tic()
self._logFakeAccess(compute_node.getReference())
self._logFakeAccess(compute_node)
news_dict = network.ComputerNetwork_getNewsDict()
expected_news_dict = {'compute_node':
{ compute_node.getReference():
{'created_at': self.created_at,
{u'created_at': u'%s' % self.created_at,
'no_data_since_15_minutes': 0,
'no_data_since_5_minutes': 0,
'since': self.created_at,
'state': 'start_requested',
'text': '#access OK',
'user': 'SlapOS Master'}
},
u'since': u'%s' % self.created_at,
u'state': u'start_requested',
u'text': u'#access OK',
u'user': u'SlapOS Master'}},
'partition':
{ compute_node.getReference():
{'slappart0': {'no_data': 1,
{'slappart0': {'created_at': self.created_at,
'no_data': 1,
'since': self.created_at,
'state': '',
'text': '#error no data found for %s' % (instance.getReference()),
'user': 'SlapOS Master'}
}
}
}
self.assertEqual(news_dict, expected_news_dict)
# Ensure it don't raise error when converting to JSON
json.dumps(news_dict)
def test_no_data(self):
network = self._makeComputerNetwork()
self._logFakeAccess(network.getReference())
news_dict = network.ComputerNetwork_getNewsDict()
expected_news_dict = {'compute_node': {}, 'partition': {}}
self.assertEqual(news_dict, expected_news_dict)
......@@ -500,27 +536,30 @@ class TestOrganisation_getNewsDict(TestSlapOSHalJsonStyleMixin):
organisation.fake_compute_node_list = [compute_node]
self.tic()
self._logFakeAccess(compute_node.getReference())
self._logFakeAccess(compute_node)
news_dict = organisation.Organisation_getNewsDict()
expected_news_dict = {'compute_node':
{ compute_node.getReference():
{'created_at': self.created_at,
{u'created_at': u'%s' % self.created_at,
'no_data_since_15_minutes': 0,
'no_data_since_5_minutes': 0,
'since': self.created_at,
'state': 'start_requested',
'text': '#access OK',
'user': 'SlapOS Master'}
},
u'since': u'%s' % self.created_at,
u'state': u'start_requested',
u'text': u'#access OK',
u'user': u'SlapOS Master'}},
'partition':
{ compute_node.getReference():
{'slappart0': {'no_data': 1,
{'slappart0': {'created_at': self.created_at,
'no_data': 1,
'since': self.created_at,
'state': '',
'text': '#error no data found for %s' % (instance.getReference()),
'user': 'SlapOS Master'}
}
}
}
self.assertEqual(news_dict, expected_news_dict)
# Ensure it don't raise error when converting to JSON
json.dumps(news_dict)
......@@ -545,27 +584,30 @@ class TestProject_getNewsDict(TestSlapOSHalJsonStyleMixin):
project.fake_compute_node_list = [compute_node]
self.tic()
self._logFakeAccess(compute_node.getReference())
self._logFakeAccess(compute_node)
news_dict = project.Project_getNewsDict()
expected_news_dict = {'compute_node':
{ compute_node.getReference():
{'created_at': self.created_at,
{u'created_at': u'%s' % self.created_at,
'no_data_since_15_minutes': 0,
'no_data_since_5_minutes': 0,
'since': self.created_at,
'state': 'start_requested',
'text': '#access OK',
'user': 'SlapOS Master'}
},
u'since': u'%s' % self.created_at,
u'state': u'start_requested',
u'text': u'#access OK',
u'user': u'SlapOS Master'}},
'partition':
{ compute_node.getReference():
{'slappart0': {'no_data': 1,
{'slappart0': {'created_at': self.created_at,
'no_data': 1,
'since': self.created_at,
'state': '',
'text': '#error no data found for %s' % (instance.getReference()),
'user': 'SlapOS Master'}
}
}
}
self.assertEqual(news_dict, expected_news_dict)
# Ensure it don't raise error when converting to JSON
json.dumps(news_dict)
......@@ -1158,11 +1200,3 @@ class TestInstanceTree_edit(TestSlapOSHalJsonStyleMixin):
self.assertEqual(new_parameter,
self.instance_tree.getTextContent())
\ No newline at end of file
......@@ -36,6 +36,6 @@ if len(full_software_installation_list) > 0 and \
len(full_software_installation_list) == len(set(compute_node_list)):
# Software is available for the root instance
software_installation = full_software_installation_list[0]
message = software_installation.Base_getNewsDict(software_installation)['text']
message = software_installation.getAccessStatusText()
if message.startswith("#access"):
return True
......@@ -297,7 +297,7 @@ class TestSlapOSSlapToolComputeNodeAccess(TestSlapOSSlapToolMixin):
</tuple>
<dictionary id='i8'>
<string>_access_status</string>
<string>%(access_status)s</string>
<string>#error no data found for %(partition_3_instance_guid)s</string>
<string>_computer_id</string>
<string>%(compute_node_id)s</string>
<string>_connection_dict</string>
......@@ -373,7 +373,7 @@ class TestSlapOSSlapToolComputeNodeAccess(TestSlapOSSlapToolMixin):
</tuple>
<dictionary id='i19'>
<string>_access_status</string>
<string>%(access_status)s</string>
<string>#error no data found for %(partition_2_instance_guid)s</string>
<string>_computer_id</string>
<string>%(compute_node_id)s</string>
<string>_connection_dict</string>
......@@ -449,7 +449,7 @@ class TestSlapOSSlapToolComputeNodeAccess(TestSlapOSSlapToolMixin):
</tuple>
<dictionary id='i30'>
<string>_access_status</string>
<string>%(access_status)s</string>
<string>#error no data found for %(partition_1_instance_guid)s</string>
<string>_computer_id</string>
<string>%(compute_node_id)s</string>
<string>_connection_dict</string>
......@@ -642,6 +642,8 @@ class TestSlapOSSlapToolComputeNodeAccess(TestSlapOSSlapToolMixin):
<dictionary id='i2'>
<string>created_at</string>
<string>%(created_at)s</string>
<string>no_data</string>
<int>1</int>
<string>since</string>
<string>%(since)s</string>
<string>state</string>
......@@ -690,6 +692,10 @@ class TestSlapOSSlapToolComputeNodeAccess(TestSlapOSSlapToolMixin):
<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>
......@@ -743,6 +749,10 @@ class TestSlapOSSlapToolComputeNodeAccess(TestSlapOSSlapToolMixin):
<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>
......@@ -830,6 +840,8 @@ class TestSlapOSSlapToolComputeNodeAccess(TestSlapOSSlapToolMixin):
<dictionary id='i2'>
<string>created_at</string>
<string>%(created_at)s</string>
<string>no_data</string>
<int>1</int>
<string>since</string>
<string>%(since)s</string>
<string>state</string>
......@@ -898,6 +910,10 @@ class TestSlapOSSlapToolComputeNodeAccess(TestSlapOSSlapToolMixin):
<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>
......@@ -943,6 +959,10 @@ class TestSlapOSSlapToolComputeNodeAccess(TestSlapOSSlapToolMixin):
<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>
......@@ -988,6 +1008,10 @@ class TestSlapOSSlapToolComputeNodeAccess(TestSlapOSSlapToolMixin):
<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>
......@@ -1290,7 +1314,7 @@ class TestSlapOSSlapToolInstanceAccess(TestSlapOSSlapToolMixin):
slave_1_software_type=self.start_requested_slave_instance.getSourceReference(),
slave_1_instance_guid=self.start_requested_slave_instance.getReference(),
slave_1_title=self.start_requested_slave_instance.getTitle(),
access_status="#error no data found!",
access_status="#error no data found for %s" % self.start_requested_software_instance.getReference(),
)
self.assertEqual(expected_xml, got_xml,
'\n'.join([q for q in difflib.unified_diff(expected_xml.split('\n'), got_xml.split('\n'))]))
......@@ -1325,6 +1349,8 @@ class TestSlapOSSlapToolInstanceAccess(TestSlapOSSlapToolMixin):
<dictionary id='i2'>
<string>created_at</string>
<string>%(created_at)s</string>
<string>no_data</string>
<int>1</int>
<string>since</string>
<string>%(since)s</string>
<string>state</string>
......@@ -1374,6 +1400,8 @@ class TestSlapOSSlapToolInstanceAccess(TestSlapOSSlapToolMixin):
<dictionary id='i2'>
<string>created_at</string>
<string>%(created_at)s</string>
<string>no_data</string>
<int>1</int>
<string>since</string>
<string>%(since)s</string>
<string>state</string>
......@@ -1744,6 +1772,10 @@ class TestSlapOSSlapToolInstanceAccess(TestSlapOSSlapToolMixin):
<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>
......@@ -1788,6 +1820,10 @@ class TestSlapOSSlapToolInstanceAccess(TestSlapOSSlapToolMixin):
<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>
......@@ -1834,6 +1870,10 @@ class TestSlapOSSlapToolInstanceAccess(TestSlapOSSlapToolMixin):
<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>
......@@ -1890,6 +1930,10 @@ class TestSlapOSSlapToolInstanceAccess(TestSlapOSSlapToolMixin):
<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>
......@@ -2206,6 +2250,10 @@ class TestSlapOSSlapToolInstanceAccess(TestSlapOSSlapToolMixin):
<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>
......@@ -2249,6 +2297,10 @@ class TestSlapOSSlapToolInstanceAccess(TestSlapOSSlapToolMixin):
<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>
......@@ -2493,6 +2545,8 @@ class TestSlapOSSlapToolPersonAccess(TestSlapOSSlapToolMixin):
<dictionary id='i2'>
<string>created_at</string>
<string>%(created_at)s</string>
<string>no_data</string>
<int>1</int>
<string>since</string>
<string>%(since)s</string>
<string>state</string>
......@@ -2541,6 +2595,10 @@ class TestSlapOSSlapToolPersonAccess(TestSlapOSSlapToolMixin):
<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>
......@@ -2593,6 +2651,10 @@ class TestSlapOSSlapToolPersonAccess(TestSlapOSSlapToolMixin):
<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>
......@@ -2646,6 +2708,8 @@ class TestSlapOSSlapToolPersonAccess(TestSlapOSSlapToolMixin):
<dictionary id='i2'>
<string>created_at</string>
<string>%(created_at)s</string>
<string>no_data</string>
<int>1</int>
<string>since</string>
<string>%(since)s</string>
<string>state</string>
......@@ -2697,6 +2761,8 @@ class TestSlapOSSlapToolPersonAccess(TestSlapOSSlapToolMixin):
<dictionary id='i2'>
<string>created_at</string>
<string>%(created_at)s</string>
<string>no_data</string>
<int>1</int>
<string>since</string>
<string>%(since)s</string>
<string>state</string>
......@@ -3004,6 +3070,10 @@ class TestSlapOSSlapToolPersonAccess(TestSlapOSSlapToolMixin):
<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>
......
......@@ -79,7 +79,6 @@ except ImportError:
from zLOG import LOG, INFO
import StringIO
import pkg_resources
import json
from DateTime import DateTime
from App.Common import rfc1123_date
class SoftwareInstanceNotReady(Exception):
......@@ -119,6 +118,25 @@ def convertToREST(function):
wrapper.__doc__ = function.__doc__
return wrapper
def convertToStatus(function):
def wrapper(self, *args, **kwd):
data_dict = function(self, *args, **kwd)
last_modified = rfc1123_date(DateTime())
# Keep in cache server for 7 days
self.REQUEST.response.setStatus(200)
self.REQUEST.response.setHeader('Cache-Control',
'public, max-age=60, stale-if-error=604800')
self.REQUEST.response.setHeader('Vary',
'REMOTE_USER')
self.REQUEST.response.setHeader('Last-Modified', last_modified)
self.REQUEST.response.setHeader('Content-Type', 'text/xml; charset=utf-8')
self.REQUEST.response.setBody(dumps(data_dict))
return self.REQUEST.response
return wrapper
def _assertACI(document):
sm = getSecurityManager()
if sm.checkPermission(access_contents_information,
......@@ -216,25 +234,6 @@ class SlapTool(BaseTool):
# called on site
pass
def _storeLastData(self, key, value):
cache_plugin = self.getPortalObject().portal_caches\
.getRamCacheRoot().get('last_stored_data_cache_factory')\
.getCachePluginList()[0]
cache_plugin.set(key, DEFAULT_CACHE_SCOPE, value,
cache_duration=self.getPortalObject().portal_caches\
.getRamCacheRoot().get('last_stored_data_cache_factory').cache_duration)
def _getLastData(self, key):
cache_plugin = self.getPortalObject().portal_caches\
.getRamCacheRoot().get('last_stored_data_cache_factory')\
.getCachePluginList()[0]
try:
entry = cache_plugin.get(key, DEFAULT_CACHE_SCOPE)
except KeyError:
entry = None
else:
entry = entry.getValue()
return entry
def _activateFillComputeNodeInformationCache(self, compute_node_id, user):
tag = 'compute_node_information_cache_fill_%s_%s' % (compute_node_id, user)
......@@ -380,7 +379,8 @@ class SlapTool(BaseTool):
"""
user = self.getPortalObject().portal_membership.getAuthenticatedMember().getUserName()
if str(user) == computer_id:
self._logAccess(user, user, '#access %s' % computer_id)
compute_node = self.getPortalObject().portal_membership.getAuthenticatedMember().getUserValue()
compute_node.setAccessStatus('#access %s' % computer_id)
refresh_etag = self._calculateRefreshEtag()
body, etag = self._getComputeNodeInformation(computer_id, user, refresh_etag)
......@@ -448,6 +448,7 @@ class SlapTool(BaseTool):
security.declareProtected(Permissions.AccessContentsInformation,
'getComputerPartitionStatus')
@convertToStatus
def getComputerPartitionStatus(self, computer_id, computer_partition_id):
"""
Get the connection status of the partition
......@@ -459,10 +460,11 @@ class SlapTool(BaseTool):
except NotFound:
return self._getAccessStatus(None)
else:
return self._getAccessStatus(instance.getReference())
return instance.getAccessStatus()
security.declareProtected(Permissions.AccessContentsInformation,
'getComputerStatus')
@convertToStatus
def getComputerStatus(self, computer_id):
"""
Get the connection status of the partition
......@@ -472,10 +474,11 @@ class SlapTool(BaseTool):
validation_state="validated")[0].getObject()
# Be sure to prevent accessing information to disallowed users
compute_node = _assertACI(compute_node)
return self._getAccessStatus(computer_id)
return compute_node.getAccessStatus()
security.declareProtected(Permissions.AccessContentsInformation,
'getSoftwareInstallationStatus')
@convertToStatus
def getSoftwareInstallationStatus(self, url, computer_id):
"""
Get the connection status of the software installation
......@@ -492,7 +495,7 @@ class SlapTool(BaseTool):
except NotFound:
return self._getAccessStatus(None)
else:
return self._getAccessStatus(software_installation.getReference())
return software_installation.getAccessStatus()
security.declareProtected(Permissions.AccessContentsInformation,
'getSoftwareReleaseListFromSoftwareProduct')
......@@ -771,11 +774,9 @@ class SlapTool(BaseTool):
"""
Fire up bung on Compute Node
"""
user = self.getPortalObject().portal_membership.getAuthenticatedMember()\
.getUserName()
self._logAccess(user, compute_node_id, '#error bang')
return self._getComputeNodeDocument(compute_node_id).reportComputeNodeBang(
comment=message)
compute_node = self._getComputeNodeDocument(compute_node_id)
compute_node.setAccessStatus('#error bang')
return compute_node.reportComputeNodeBang(comment=message)
security.declareProtected(Permissions.AccessContentsInformation,
'computerBang')
......@@ -925,34 +926,6 @@ class SlapTool(BaseTool):
# Internal methods
####################################################
def _logAccess(self, user_reference, context_reference, text, state=""):
memcached_dict = self.Base_getSlapToolMemcachedDict()
previous = self._getCachedAccessInfo(context_reference)
created_at = rfc1123_date(DateTime())
since = created_at
status_changed = True
if previous is not None:
previous_json = json.loads(previous)
if text.split(" ")[0] == previous_json.get("text", "").split(" ")[0]:
since = previous_json.get("since",
previous_json.get("created_at", rfc1123_date(DateTime())))
status_changed = False
if state == "":
state = previous_json.get("state", "")
value = json.dumps({
'user': '%s' % user_reference,
'created_at': '%s' % created_at,
'text': '%s' % text,
'since': '%s' % since,
'state': state
})
memcached_dict[context_reference] = value
return status_changed
def _validateXML(self, to_be_validated, xsd_model):
"""Will validate the xml file"""
#We parse the XSD model
......@@ -1015,8 +988,7 @@ class SlapTool(BaseTool):
slap_partition._requested_state = 'stopped'
if state == "start_requested":
slap_partition._requested_state = 'started'
slap_partition._access_status = self._getTextAccessStatus(
software_instance.getReference())
slap_partition._access_status = software_instance.getTextAccessStatus()
slap_partition._software_release_document = SoftwareRelease(
software_release=software_instance.getUrlString().decode("UTF-8"),
......@@ -1061,11 +1033,9 @@ class SlapTool(BaseTool):
Log the software release status
"""
compute_node_document = self._getComputeNodeDocument(compute_node_id)
software_installation_reference = self._getSoftwareInstallationReference(url,
software_installation = self._getSoftwareInstallationForComputeNode(url,
compute_node_document)
user = self.getPortalObject().portal_membership.\
getAuthenticatedMember().getUserName()
self._logAccess(user, software_installation_reference,
software_installation.setAccessStatus(
'#building software release %s' % url, "building")
@convertToREST
......@@ -1074,11 +1044,9 @@ class SlapTool(BaseTool):
Log the software release status
"""
compute_node_document = self._getComputeNodeDocument(compute_node_id)
software_installation_reference = self._getSoftwareInstallationReference(url,
software_installation = self._getSoftwareInstallationForComputeNode(url,
compute_node_document)
user = self.getPortalObject().portal_membership.\
getAuthenticatedMember().getUserName()
self._logAccess(user, software_installation_reference,
software_installation.setAccessStatus(
'#access software release %s available' % url, "available")
@convertToREST
......@@ -1108,9 +1076,8 @@ class SlapTool(BaseTool):
instance = self._getSoftwareInstanceForComputePartition(
compute_node_id,
compute_partition_id)
user = self.getPortalObject().portal_membership.getAuthenticatedMember()\
.getUserName()
status_changed = self._logAccess(user, instance.getReference(),
status_changed = instance.setAccessStatus(
'#error while instanciating: %s' % error_log[-80:])
if status_changed:
......@@ -1126,7 +1093,7 @@ class SlapTool(BaseTool):
for name in [software_instance.getTitle(), new_name]:
# reset request cache
key = '_'.join([hosting, name])
self._storeLastData(key, {})
software_instance.setLastData({}, key=key)
return software_instance.rename(new_name=new_name,
comment="Rename %s into %s" % (software_instance.title, new_name))
......@@ -1140,79 +1107,19 @@ class SlapTool(BaseTool):
software_instance = self._getSoftwareInstanceForComputePartition(
compute_node_id,
compute_partition_id)
user = self.getPortalObject().portal_membership.\
getAuthenticatedMember().getUserName()
self._logAccess(user, software_instance.getReference(),
'#error bang called')
software_instance.setAccessStatus('#error bang called')
timestamp = str(int(software_instance.getModificationDate()))
key = "%s_bangstamp" % software_instance.getReference()
self.getPortalObject().portal_workflow.getInfoFor(
software_instance, 'action', wf_id='instance_slap_interface_workflow')
if (self._getLastData(key) != timestamp):
if (software_instance.getLastData(key) != timestamp):
software_instance.bang(bang_tree=True, comment=message)
self._storeLastData(key, str(int(software_instance.getModificationDate())))
software_instance.setLastData(key, str(int(software_instance.getModificationDate())))
return "OK"
def _getCachedAccessInfo(self, context_reference):
memcached_dict = self.Base_getSlapToolMemcachedDict()
try:
if context_reference is None:
raise KeyError
else:
data = memcached_dict[context_reference]
except KeyError:
return None
return data
def _getTextAccessStatus(self, context_reference):
status_string = self._getCachedAccessInfo(context_reference)
access_status = "#error no data found!"
if status_string is not None:
try:
access_status = json.loads(status_string)['text']
except ValueError:
pass
return access_status
def _getAccessStatus(self, context_reference):
d = self._getCachedAccessInfo(context_reference)
last_modified = rfc1123_date(DateTime())
if d is None:
if context_reference is None:
d = {
"user": "SlapOS Master",
'created_at': '%s' % last_modified,
'since': '%s' % last_modified,
'state': "",
"text": "#error no data found"
}
else:
d = {
"user": "SlapOS Master",
'created_at': '%s' % last_modified,
'since': '%s' % last_modified,
'state': "",
"text": "#error no data found for %s" % context_reference
}
# Prepare for xml marshalling
d["user"] = d["user"].decode("UTF-8")
d["text"] = d["text"].decode("UTF-8")
else:
d = json.loads(d)
# Keep in cache server for 7 days
self.REQUEST.response.setStatus(200)
self.REQUEST.response.setHeader('Cache-Control',
'public, max-age=60, stale-if-error=604800')
self.REQUEST.response.setHeader('Vary',
'REMOTE_USER')
self.REQUEST.response.setHeader('Last-Modified', last_modified)
self.REQUEST.response.setHeader('Content-Type', 'text/xml; charset=utf-8')
self.REQUEST.response.setBody(dumps(d))
return self.REQUEST.response
@convertToREST
def _startedComputePartition(self, compute_node_id, compute_partition_id):
"""
......@@ -1221,10 +1128,7 @@ class SlapTool(BaseTool):
instance = self._getSoftwareInstanceForComputePartition(
compute_node_id,
compute_partition_id)
user = self.getPortalObject().portal_membership.getAuthenticatedMember()\
.getUserName()
status_changed = self._logAccess(user, instance.getReference(),
'#access Instance correctly started', "started")
status_changed = instance.setAccessStatus('#access Instance correctly started', "started")
if status_changed:
instance.reindexObject()
......@@ -1236,10 +1140,7 @@ class SlapTool(BaseTool):
instance = self._getSoftwareInstanceForComputePartition(
compute_node_id,
compute_partition_id)
user = self.getPortalObject().portal_membership.getAuthenticatedMember()\
.getUserName()
status_changed = self._logAccess(user, instance.getReference(),
'#access Instance correctly stopped', "stopped")
status_changed = instance.setAccessStatus('#access Instance correctly stopped', "stopped")
if status_changed:
instance.reindexObject()
......@@ -1288,12 +1189,11 @@ class SlapTool(BaseTool):
compute_partition_id,
slave_reference)
connection_xml = dict2xml(loads(connection_xml))
reference = software_instance.getReference()
if self._getLastData(reference) != connection_xml:
if software_instance.getLastData() != connection_xml:
software_instance.updateConnection(
connection_xml=connection_xml,
)
self._storeLastData(reference, connection_xml)
software_instance.setLastData(connection_xml)
@convertToREST
def _requestComputePartition(self, compute_node_id, compute_partition_id,
......@@ -1368,7 +1268,7 @@ class SlapTool(BaseTool):
value = dict(
hash='_'.join([software_instance_document.getRelativeUrl(), str(kw)]),
)
last_data = self._getLastData(key)
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(
......@@ -1381,7 +1281,7 @@ class SlapTool(BaseTool):
if requested_software_instance is not None:
value['request_instance'] = requested_software_instance\
.getRelativeUrl()
self._storeLastData(key, value)
software_instance_document.setLastData(value, key=key)
else:
# requested as root, so done by human
person = portal.portal_membership.getAuthenticatedMember().getUserValue()
......@@ -1396,7 +1296,7 @@ class SlapTool(BaseTool):
value = dict(
hash=str(kw)
)
last_data = self._getLastData(key)
last_data = person.getLastData(key)
if last_data is not None and isinstance(last_data, dict):
requested_software_instance = portal.restrictedTraverse(
last_data.get('request_instance'), None)
......@@ -1408,7 +1308,7 @@ class SlapTool(BaseTool):
if requested_software_instance is not None:
value['request_instance'] = requested_software_instance\
.getRelativeUrl()
self._storeLastData(key, value)
requested_software_instance.setLastData(value, key=key)
if requested_software_instance is None:
raise SoftwareInstanceNotReady
......@@ -1452,7 +1352,7 @@ class SlapTool(BaseTool):
compute_partition_id)
cache_reference = '%s-PREDLIST' % software_instance_document.getReference()
if self._getLastData(cache_reference) != 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(
......@@ -1470,7 +1370,7 @@ class SlapTool(BaseTool):
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')
self._storeLastData(cache_reference, instance_reference_xml)
software_instance_document.setLastData(instance_reference_xml, key=cache_reference)
####################################################
# Internals methods
......@@ -1678,7 +1578,7 @@ class SlapTool(BaseTool):
else:
software_release_response._requested_state = 'available'
known_state = self._getTextAccessStatus(software_installation.getReference())
known_state = software_installation.getTextAccessStatus()
if known_state.startswith("#access"):
software_release_response._known_state = 'available'
elif known_state.startswith("#building"):
......@@ -1695,11 +1595,8 @@ class SlapTool(BaseTool):
Log the compute_node status
"""
compute_node_document = self._getComputeNodeDocument(compute_node_id)
software_installation_reference = self._getSoftwareInstallationReference(url,
software_installation = self._getSoftwareInstallationForComputeNode(url,
compute_node_document)
user = self.getPortalObject().portal_membership.\
getAuthenticatedMember().getUserName()
self._logAccess(user, software_installation_reference,
'#error while installing %s' % url)
software_installation.setAccessStatus('#error while installing %s' % url)
InitializeClass(SlapTool)
portal_caches/last_stored_data_cache_factory
portal_caches/last_stored_data_cache_factory/volatile_cache_plugin
\ No newline at end of file
portal_caches/compute_node_information_cache_factory
portal_caches/compute_node_information_cache_factory/persistent_cache_plugin
portal_caches/last_stored_data_cache_factory
portal_caches/last_stored_data_cache_factory/volatile_cache_plugin
portal_caches/slap_cache_factory
portal_caches/slap_cache_factory/persistent_cache_plugin
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