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 ...@@ -6,6 +6,8 @@ from Products.ERP5Type.tests.utils import createZODBPythonScript
from Products.ERP5Type.tests.backportUnittest import skip from Products.ERP5Type.tests.backportUnittest import skip
import json import json
from zExceptions import Unauthorized from zExceptions import Unauthorized
from DateTime import DateTime
from Products.ERP5Type.DateUtils import addToDate
class TestSlapOSCorePromiseSlapOSModuleIdGeneratorAlarm(testSlapOSMixin): class TestSlapOSCorePromiseSlapOSModuleIdGeneratorAlarm(testSlapOSMixin):
def test_Module_assertIdGenerator(self): def test_Module_assertIdGenerator(self):
...@@ -1302,3 +1304,206 @@ portal_workflow.doActionFor(context, action='edit_action', comment='Visited by I ...@@ -1302,3 +1304,206 @@ portal_workflow.doActionFor(context, action='edit_action', comment='Visited by I
'Visited by Instance_tryToStopCollect', 'Visited by Instance_tryToStopCollect',
instance.workflow_history['edit_workflow'][-1]['comment']) 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 267
\ No newline at end of file \ No newline at end of file
...@@ -11,6 +11,7 @@ portal_alarms/slapos_allocate_instance ...@@ -11,6 +11,7 @@ portal_alarms/slapos_allocate_instance
portal_alarms/slapos_assert_hosting_subscription_predecessor portal_alarms/slapos_assert_hosting_subscription_predecessor
portal_alarms/slapos_free_computer_partition portal_alarms/slapos_free_computer_partition
portal_alarms/slapos_garbage_collect_destroyed_root_tree 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_stop_collect_instance
portal_alarms/slapos_update_computer_capacity_scope portal_alarms/slapos_update_computer_capacity_scope
software_installation_module/template_software_installation 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