Commit 7b57aa0e authored by Romain Courteaud's avatar Romain Courteaud

Garbage collect non allocated simple tree.

parent 119da8a6
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Alarm" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>active_sense_method_id</string> </key>
<value> <string>Alarm_garbageCollectNonAllocatedRootTree</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>slapos_garbage_collect_non_allocated_root_tree</string> </value>
</item>
<item>
<key> <string>periodicity_day_frequency</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>periodicity_hour</string> </key>
<value>
<tuple>
<int>5</int>
</tuple>
</value>
</item>
<item>
<key> <string>periodicity_hour_frequency</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>periodicity_minute</string> </key>
<value>
<tuple>
<int>26</int>
</tuple>
</value>
</item>
<item>
<key> <string>periodicity_minute_frequency</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>periodicity_month</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>periodicity_month_day</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>periodicity_start_date</string> </key>
<value>
<object>
<klass>
<global name="DateTime" module="DateTime.DateTime"/>
</klass>
<tuple>
<none/>
</tuple>
<state>
<tuple>
<float>1355314320.0</float>
<string>GMT</string>
</tuple>
</state>
</object>
</value>
</item>
<item>
<key> <string>periodicity_week</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Alarm</string> </value>
</item>
<item>
<key> <string>sense_method_id</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Garbage Collect Non Allocated Root Tree</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?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>_body</string> </key>
<value> <string>portal = context.getPortalObject()\n
select_dict= {\'default_aggregate_uid\': None}\n
portal.portal_catalog.searchAndActivate(\n
portal_type=(\'Slave Instance\', \'Software Instance\'),\n
validation_state=\'validated\',\n
default_aggregate_uid=None,\n
select_dict=select_dict,\n
left_join_list=select_dict.keys(),\n
\n
method_id=\'Instance_tryToGarbageCollectNonAllocatedRootTree\',\n
activate_kw={\'tag\': tag}\n
)\n
\n
context.activate(after_tag=tag).getId()\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>tag, fixit, params</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Alarm_garbageCollectNonAllocatedRootTree</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?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>_body</string> </key>
<value> <string encoding="cdata"><![CDATA[
from zExceptions import Unauthorized\n
if REQUEST is not None:\n
raise Unauthorized\n
\n
instance = context\n
portal = context.getPortalObject()\n
\n
if instance.getValidationState() != \'validated\' \\\n
or instance.getSlapState() not in (\'start_requested\', \'stop_requested\') \\\n
or instance.getAggregateValue(portal_type=\'Computer Partition\') is not None:\n
return\n
\n
latest_comment = portal.portal_workflow.getInfoFor(instance, \'comment\', wf_id=\'edit_workflow\')\n
if latest_comment != \'Allocation failed: no free Computer Partition\':\n
# No nothing if allocation alarm didn\'t run on it\n
return\n
\n
latest_edit_time = portal.portal_workflow.getInfoFor(instance, \'time\', wf_id=\'edit_workflow\')\n
if (int(DateTime()) - int(latest_edit_time)) < 604800:\n
# Allow 1 week gap betweeb latest allocation try and deletion\n
return\n
\n
# Only destroy if the instance is the only one in the tree\n
hosting_subscription = instance.getSpecialiseValue("Hosting Subscription")\n
if (hosting_subscription.getPredecessor() != instance.getRelativeUrl()):\n
return\n
if (len(hosting_subscription.getPredecessorList()) != 1):\n
return\n
instance_list = portal.portal_catalog(\n
portal_type=["Software Instance", "Slave Instance"],\n
default_specialise_uid=hosting_subscription.getUid(),\n
limit=2)\n
if len(instance_list) != 1:\n
return\n
\n
# OK, destroy hosting subscription\n
hosting_subscription.requestDestroy(\n
software_release=hosting_subscription.getUrlString(),\n
software_title=hosting_subscription.getTitle(),\n
software_type=hosting_subscription.getSourceReference(),\n
instance_xml=hosting_subscription.getTextContent(),\n
sla_xml=hosting_subscription.getSlaXml(),\n
shared=hosting_subscription.isRootSlave(),\n
state=\'destroyed\',\n
comment="Garbage collect %s not allocated for more than 1 week" % instance.getRelativeUrl(),\n
)\n
]]></string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>REQUEST=None</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Instance_tryToGarbageCollectNonAllocatedRootTree</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -6,6 +6,8 @@ from Products.ERP5Type.tests.utils import createZODBPythonScript
from Products.ERP5Type.tests.backportUnittest import skip
import json
from zExceptions import Unauthorized
from DateTime import DateTime
from Products.ERP5Type.DateUtils import addToDate
class TestSlapOSCorePromiseSlapOSModuleIdGeneratorAlarm(testSlapOSMixin):
def test_Module_assertIdGenerator(self):
......@@ -1302,3 +1304,206 @@ portal_workflow.doActionFor(context, action='edit_action', comment='Visited by I
'Visited by Instance_tryToStopCollect',
instance.workflow_history['edit_workflow'][-1]['comment'])
class TestSlapOSGarbageCollectNonAllocatedRootTreeAlarm(testSlapOSMixin):
def createInstance(self):
hosting_subscription = self.portal.hosting_subscription_module\
.template_hosting_subscription.Base_createCloneDocument(batch_mode=1)
hosting_subscription.validate()
hosting_subscription.edit(
title=self.generateNewSoftwareTitle(),
reference="TESTHS-%s" % self.generateNewId(),
)
request_kw = dict(
software_release=\
self.generateNewSoftwareReleaseUrl(),
software_type=self.generateNewSoftwareType(),
instance_xml=self.generateSafeXml(),
sla_xml=self.generateSafeXml(),
shared=False,
software_title=hosting_subscription.getTitle(),
state='started'
)
hosting_subscription.requestStart(**request_kw)
hosting_subscription.requestInstance(**request_kw)
instance = hosting_subscription.getPredecessorValue()
return instance
def createComputerPartition(self):
computer = self.portal.computer_module\
.template_computer.Base_createCloneDocument(batch_mode=1)
computer.validate()
computer.edit(
title=self.generateNewSoftwareTitle(),
reference="TESTCOMP-%s" % self.generateNewId(),
)
partition = computer.newContent(portal_type="Computer Partition")
return partition
def test_tryToGarbageCollect_REQUEST_disallowed(self):
self.assertRaises(
Unauthorized,
self.portal.Instance_tryToGarbageCollectNonAllocatedRootTree,
REQUEST={})
def test_tryToGarbageCollect_invalidated_instance(self):
instance = self.createInstance()
instance.invalidate()
self.tic()
instance.Instance_tryToGarbageCollectNonAllocatedRootTree()
self.assertEqual('start_requested', instance.getSlapState())
hosting_subscription = instance.getSpecialiseValue()
self.assertEqual('start_requested', hosting_subscription.getSlapState())
def test_tryToGarbageCollect_destroyed_instance(self):
instance = self.createInstance()
self.portal.portal_workflow._jumpToStateFor(instance, 'destroy_requested')
self.tic()
instance.Instance_tryToGarbageCollectNonAllocatedRootTree()
self.assertEqual('destroy_requested', instance.getSlapState())
hosting_subscription = instance.getSpecialiseValue()
self.assertEqual('start_requested', hosting_subscription.getSlapState())
def test_tryToGarbageCollect_allocated_instance(self):
instance = self.createInstance()
partition = self.createComputerPartition()
instance.edit(aggregate_value=partition)
self.tic()
instance.Instance_tryToGarbageCollectNonAllocatedRootTree()
self.assertEqual('start_requested', instance.getSlapState())
hosting_subscription = instance.getSpecialiseValue()
self.assertEqual('start_requested', hosting_subscription.getSlapState())
def test_tryToGarbageCollect_no_allocation_try_found(self):
instance = self.createInstance()
self.tic()
instance.Instance_tryToGarbageCollectNonAllocatedRootTree()
self.assertEqual('start_requested', instance.getSlapState())
hosting_subscription = instance.getSpecialiseValue()
self.assertEqual('start_requested', hosting_subscription.getSlapState())
def test_tryToGarbageCollect_recent_allocation_try_found(self):
instance = self.createInstance()
self.tic()
instance.workflow_history['edit_workflow'].append({
'comment':'Allocation failed: no free Computer Partition',
'error_message': '',
'actor': 'ERP5TypeTestCase',
'slap_state': '',
'time': addToDate(DateTime(), to_add={'day': -6}),
'action': 'edit'
})
instance.Instance_tryToGarbageCollectNonAllocatedRootTree()
self.assertEqual('start_requested', instance.getSlapState())
hosting_subscription = instance.getSpecialiseValue()
self.assertEqual('start_requested', hosting_subscription.getSlapState())
def test_tryToGarbageCollect_complex_tree(self):
instance = self.createInstance()
hosting_subscription = instance.getSpecialiseValue()
request_kw = dict(
software_release=\
self.generateNewSoftwareReleaseUrl(),
software_type=self.generateNewSoftwareType(),
instance_xml=self.generateSafeXml(),
sla_xml=self.generateSafeXml(),
shared=False,
software_title="another %s" % hosting_subscription.getTitle(),
state='started'
)
instance.requestInstance(**request_kw)
sub_instance = instance.getPredecessorValue()
self.tic()
sub_instance.workflow_history['edit_workflow'].append({
'comment':'Allocation failed: no free Computer Partition',
'error_message': '',
'actor': 'ERP5TypeTestCase',
'slap_state': '',
'time': addToDate(DateTime(), to_add={'day': -8}),
'action': 'edit'
})
sub_instance.Instance_tryToGarbageCollectNonAllocatedRootTree()
self.assertEqual('start_requested', hosting_subscription.getSlapState())
def test_tryToGarbageCollect_old_allocation_try_found(self):
instance = self.createInstance()
hosting_subscription = instance.getSpecialiseValue()
self.tic()
instance.workflow_history['edit_workflow'].append({
'comment':'Allocation failed: no free Computer Partition',
'error_message': '',
'actor': 'ERP5TypeTestCase',
'slap_state': '',
'time': addToDate(DateTime(), to_add={'day': -8}),
'action': 'edit'
})
instance.Instance_tryToGarbageCollectNonAllocatedRootTree()
self.assertEqual('destroy_requested', hosting_subscription.getSlapState())
def _simulateInstance_tryToGarbageCollectNonAllocatedRootTree(self):
script_name = 'Instance_tryToGarbageCollectNonAllocatedRootTree'
if script_name in self.portal.portal_skins.custom.objectIds():
raise ValueError('Precondition failed: %s exists in custom' % script_name)
createZODBPythonScript(self.portal.portal_skins.custom,
script_name,
'*args, **kwargs',
'# Script body\n'
"""portal_workflow = context.portal_workflow
portal_workflow.doActionFor(context, action='edit_action', comment='Visited by Instance_tryToGarbageCollectNonAllocatedRootTree') """ )
transaction.commit()
def _dropInstance_tryToGarbageCollectNonAllocatedRootTree(self):
script_name = 'Instance_tryToGarbageCollectNonAllocatedRootTree'
if script_name in self.portal.portal_skins.custom.objectIds():
self.portal.portal_skins.custom.manage_delObjects(script_name)
transaction.commit()
def test_alarm(self):
instance = self.createInstance()
self.tic()
self._simulateInstance_tryToGarbageCollectNonAllocatedRootTree()
try:
self.portal.portal_alarms.slapos_garbage_collect_non_allocated_root_tree.activeSense()
self.tic()
finally:
self._dropInstance_tryToGarbageCollectNonAllocatedRootTree()
self.assertEqual(
'Visited by Instance_tryToGarbageCollectNonAllocatedRootTree',
instance.workflow_history['edit_workflow'][-1]['comment'])
def test_alarm_invalidated(self):
instance = self.createInstance()
instance.invalidate()
self.tic()
self._simulateInstance_tryToGarbageCollectNonAllocatedRootTree()
try:
self.portal.portal_alarms.slapos_garbage_collect_non_allocated_root_tree.activeSense()
self.tic()
finally:
self._dropInstance_tryToGarbageCollectNonAllocatedRootTree()
self.assertNotEqual(
'Visited by Instance_tryToGarbageCollectNonAllocatedRootTree',
instance.workflow_history['edit_workflow'][-1]['comment'])
def test_alarm_allocated(self):
instance = self.createInstance()
partition = self.createComputerPartition()
instance.edit(aggregate_value=partition)
self.tic()
self._simulateInstance_tryToGarbageCollectNonAllocatedRootTree()
try:
self.portal.portal_alarms.slapos_garbage_collect_non_allocated_root_tree.activeSense()
self.tic()
finally:
self._dropInstance_tryToGarbageCollectNonAllocatedRootTree()
self.assertNotEqual(
'Visited by Instance_tryToGarbageCollectNonAllocatedRootTree',
instance.workflow_history['edit_workflow'][-1]['comment'])
266
\ No newline at end of file
267
\ No newline at end of file
......@@ -11,6 +11,7 @@ portal_alarms/slapos_allocate_instance
portal_alarms/slapos_assert_hosting_subscription_predecessor
portal_alarms/slapos_free_computer_partition
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_computer_capacity_scope
software_installation_module/template_software_installation
......
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