Commit f3e287bb authored by Rafael Monnerat's avatar Rafael Monnerat

Improve "Software Instance Check" Support Request

Conflicts:
	master/bt5/slapos_crm/bt/revision
parent 3a989239
......@@ -57,10 +57,18 @@ partition_list = portal.portal_catalog(portal_type = \'Computer Partition\',\n
parent_uid = context.getUid()\n
)\n
\n
hosting_subscription_list = []\n
for partition in partition_list:\n
instance = partition.getAggregateRelatedValue(portal_type=\'Software Instance\')\n
if instance is not None:\n
instance.activate().SoftwareInstance_checkState()\n
software_instance = partition.getAggregateRelatedValue(\n
portal_type=\'Software Instance\')\n
if software_instance:\n
hosting = software_instance.getSpecialiseValue(\n
portal_type=\'Hosting Subscription\')\n
if hosting and not hosting in hosting_subscription_list:\n
hosting_subscription_list.append(hosting)\n
hosting.HostingSubscription_CheckInstanceState()\n
\n
return len(hosting_subscription_list)\n
</string> </value>
</item>
<item>
......
<?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>hosting_subscription = context\n
\n
instance = hosting_subscription.getPredecessorValue()\n
if instance is None:\n
return\n
instance_list = [instance]\n
instance_list.extend(instance.getPredecessorValueList())\n
\n
for sub_instance in instance_list:\n
if sub_instance and \\\n
sub_instance.activate().SoftwareInstance_checkState():\n
# This instance is in failing state\n
# One notification per hosting subscription\n
break\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>HostingSubscription_CheckInstanceState</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -61,7 +61,7 @@ if portal.ERP5Site_isSupportRequestCreationClosed():\n
# Stop ticket creation\n
return\n
\n
if (DateTime() - context.getCreationDate()) < 1:\n
if (DateTime() - context.getCreationDate()) < 2:\n
# Ignore recently created instances.\n
return\n
\n
......@@ -73,19 +73,53 @@ memcached_dict = context.getPortalObject().portal_memcached.getMemcachedDict(\n
try:\n
d = memcached_dict[reference]\n
except KeyError:\n
return \n
\n
return\n
\n
d = json.loads(d)\n
result = d[\'text\']\n
last_contact = DateTime(d.get(\'created_at\'))\n
now = DateTime()\n
\n
# Optimise by checking memcache information first.\n
if result.startswith(\'#error \'):\n
return context.Base_generateSupportRequestForSlapOS(\n
"Instance %s in error state" % reference,\n
"%s has been in error state for more than 2 hours (last contact date: %s)" % (reference, last_contact),\n
context.getRelativeUrl())\n
service = context.getSpecialiseValue(portal_type=\'Hosting Subscription\')\n
hosting_title = service.getTitle()\n
ticket_title = "Service %s in error state" % service.getReference()\n
description = "The instance %s of service %s has been in error state (last contact date: %s)" % (\n
reference, hosting_title, last_contact)\n
support_request_url = context.Base_generateSupportRequestForSlapOS(\n
ticket_title, description, service.getRelativeUrl())\n
\n
if not support_request_url:\n
return\n
\n
support_request = portal.restrictedTraverse(support_request_url, None)\n
person_url = service.getDestinationSection()\n
\n
if support_request is None or not person_url:\n
return support_request_url\n
\n
notification_message = portal.portal_notifications.getDocumentValue(\n
reference=\'slapos-crm-hosting_subscription_state.notification\')\n
if notification_message is None:\n
message = """Dear user,\n
%s.\n
Do not hesitate to visit the web forum (http://community.slapos.org/forum) in case of question.\n
\n
Regards,\n
\n
The slapos team""" % description\n
else:\n
mapping_dict = {\'hosting_title\':hosting_title,\n
\'hosting_url\':service.getRelativeUrl(),\n
\'instance_title\':context.getTitle(),\n
\'last_contact\':last_contact}\n
message = notification_message.asText(\n
substitution_method_parameter_dict={\'mapping_dict\':mapping_dict})\n
\n
support_request.SupportRequest_trySendNotificationMessage(\n
ticket_title, message, person_url, 0)\n
\n
return support_request_url\n
]]></string> </value>
......
......@@ -61,7 +61,7 @@ last_event = context.portal_catalog.getResultValue(\n
follow_up_uid=support_request.getUid(), \n
sort_on=[(\'delivery.start_date\', \'DESC\')],\n
)\n
if last_event and \\\n
if last_event and (interval_of_day > 0) and \\\n
(DateTime() - last_event.getStartDate() < interval_of_day):\n
# User has already been notified this last 24h.\n
return\n
......
......@@ -1987,12 +1987,12 @@ class TestSlapOSComputer_CheckState(testSlapOSMixin):
return notification_message.getRelativeUrl()
def _getGeneratedSupportRequest(self, computer_uid, request_title):
def _getGeneratedSupportRequest(self, source_uid, request_title):
support_request = self.portal.portal_catalog.getResultValue(
portal_type = 'Support Request',
title = request_title,
simulation_state = 'validated',
source_project_uid = computer_uid
source_project_uid = source_uid
)
return support_request
......@@ -2010,6 +2010,35 @@ class TestSlapOSComputer_CheckState(testSlapOSMixin):
computer.validate()
return computer
def _makeHostingSubscription(self, new_id):
person = self.portal.person_module.template_member\
.Base_createCloneDocument(batch_mode=1)
hosting_subscription = self.portal\
.hosting_subscription_module.template_hosting_subscription\
.Base_createCloneDocument(batch_mode=1)
hosting_subscription.validate()
hosting_subscription.edit(
title= "Test hosting sub ticket %s" % new_id,
reference="TESTHST-%s" % new_id,
destination_section_value=person
)
return hosting_subscription
def _makeSoftwareInstance(self, hosting_subscription, software_url):
kw = dict(
software_release=software_url,
software_type=self.generateNewSoftwareType(),
instance_xml=self.generateSafeXml(),
sla_xml=self.generateSafeXml(),
shared=False,
software_title=hosting_subscription.getTitle(),
state='started'
)
hosting_subscription.requestStart(**kw)
hosting_subscription.requestInstance(**kw)
def _simulateBase_generateSupportRequestForSlapOS(self):
script_name = 'Base_generateSupportRequestForSlapOS'
if script_name in self.portal.portal_skins.custom.objectIds():
......@@ -2133,4 +2162,58 @@ class TestSlapOSComputer_CheckState(testSlapOSMixin):
ticket_title.replace('[MONITORING] ', ''),
'Test NM content\n%s\n' % computer.getReference(),
person.getRelativeUrl(), message_interval_per_day),
ticket.workflow_history['edit_workflow'][-1]['comment'])
@simulate('NotificationTool_getDocumentValue',
'reference=None',
'assert reference == "slapos-crm-hosting_subscription_state.notification"\n' \
'return context.restrictedTraverse(' \
'context.REQUEST["test_SoftwareInstance_checkState"])')
@simulate('SupportRequest_trySendNotificationMessage',
'message_title, message, source_relative_url, interval_of_day=1',
'context.portal_workflow.doActionFor(' \
'context, action="edit_action", ' \
'comment="Visited by SupportRequest_trySendNotificationMessage ' \
'%s %s %s %s" % (message_title, message, source_relative_url, interval_of_day))')
def test_SoftwareInstance_checkState(self):
host_sub = self._makeHostingSubscription(self.new_id)
self._makeSoftwareInstance(host_sub,self.generateNewSoftwareReleaseUrl())
instance = host_sub.getPredecessorValue()
person_url = host_sub.getDestinationSection()
instance.workflow_history['edit_workflow'] = [{
'comment':'edit',
'error_message': '',
'actor': 'ERP5TypeTestCase',
'state': 'current',
'time': DateTime('2012/11/30 11:11'),
'action': 'edit'
}]
memcached_dict = self.portal.portal_memcached.getMemcachedDict(
key_prefix='slap_tool',
plugin_path='portal_memcached/default_memcached_plugin')
memcached_dict[instance.getReference()] = json.dumps(
{"created_at":"%s" % DateTime(), "text":"#error "}
)
message_interval_per_day = 0
self.portal.REQUEST['test_SoftwareInstance_checkState'] = \
self._makeNotificationMessage(instance.getReference())
self.tic()
ticket_url = instance.SoftwareInstance_checkState()
self.tic()
self.assertNotEqual(ticket_url, None)
ticket_title = "[MONITORING] Service %s in error state" % host_sub.getReference()
ticket = self._getGeneratedSupportRequest(host_sub.getUid(), ticket_title)
self.assertNotEqual(ticket, None)
self.assertEqual('Visited by SupportRequest_trySendNotificationMessage ' \
'%s %s %s %s' % ( \
ticket_title.replace('[MONITORING] ', ''),
'Test NM content\n%s\n' % instance.getReference(),
person_url, message_interval_per_day),
ticket.workflow_history['edit_workflow'][-1]['comment'])
\ No newline at end of file
......@@ -327,14 +327,16 @@ class TestSlapOSCloudSupportRequestGeneration(testSlapOSMixin):
result)
def test_SupportRequest_trySendNotificationMessage(self):
title = "Test Support Request %s" % self.new_id
text_content='Test NM content<br/>%s<br/>' % self.new_id
computer = self._makeComputer(self.new_id)
support_request_url = computer.Base_generateSupportRequestForSlapOS(
title, title, computer.getRelativeUrl()
)
support_request = self.portal.restrictedTraverse(support_request_url)
person = computer.getSourceAdministrationValue()
title = "Test Support Request %s" % self.new_id
text_content='Test NM content<br/>%s<br/>' % self.new_id
support_request = self.portal.support_request_module.newContent(\
title=title, description=title,
destination_decision=computer.getSourceAdministration(),
source_project_value=computer.getRelativeUrl())
support_request.validate()
time_before_next = 2
self.tic()
......@@ -364,7 +366,7 @@ class TestSlapOSCloudSupportRequestGeneration(testSlapOSMixin):
)
self.assertEqual(event.getTitle(), title)
def test_Computer_checkState_empty_cache(self):
......@@ -599,6 +601,40 @@ portal_workflow.doActionFor(context, action='edit_action', comment='Visited by S
if script_name in self.portal.portal_skins.custom.objectIds():
self.portal.portal_skins.custom.manage_delObjects(script_name)
transaction.commit()
def testHostingSubscription_CheckInstanceState(self):
host_sub = self._makeHostingSubscription(self.new_id)
self._makeSoftwareInstance(host_sub, self.generateNewSoftwareReleaseUrl())
instance = host_sub.getPredecessorValue()
self._simulateSoftwareInstance_checkState()
try:
host_sub.HostingSubscription_CheckInstanceState()
self.tic()
finally:
self._dropSoftwareInstance_checkState()
self.assertEqual('Visited by SoftwareInstance_checkState',
instance.workflow_history['edit_workflow'][-1]['comment'])
def _simulateHostingSubscription_CheckInstanceState(self):
script_name = 'HostingSubscription_CheckInstanceState'
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, **kw',
'# Script body\n'
"""portal_workflow = context.portal_workflow
portal_workflow.doActionFor(context, action='edit_action', comment='Visited by HostingSubscription_CheckInstanceState') """ )
transaction.commit()
def _dropHostingSubscription_CheckInstanceState(self):
script_name = 'HostingSubscription_CheckInstanceState'
if script_name in self.portal.portal_skins.custom.objectIds():
self.portal.portal_skins.custom.manage_delObjects(script_name)
transaction.commit()
def test_Computer_checkSoftwareInstanceState(self):
computer = self._makeComputer(self.new_id)
......@@ -610,15 +646,15 @@ portal_workflow.doActionFor(context, action='edit_action', comment='Visited by S
computer.partition1.markBusy()
self.tic()
self._simulateSoftwareInstance_checkState()
self._simulateHostingSubscription_CheckInstanceState()
try:
computer.Computer_checkSoftwareInstanceState()
self.tic()
finally:
self._dropSoftwareInstance_checkState()
self._dropHostingSubscription_CheckInstanceState()
self.assertEqual('Visited by SoftwareInstance_checkState',
instance.workflow_history['edit_workflow'][-1]['comment'])
self.assertEqual('Visited by HostingSubscription_CheckInstanceState',
host_sub.workflow_history['edit_workflow'][-1]['comment'])
def test_Computer_checkSoftwareInstanceState_instance_not_allocated(self):
computer = self._makeComputer(self.new_id)
......@@ -627,14 +663,14 @@ portal_workflow.doActionFor(context, action='edit_action', comment='Visited by S
instance = host_sub.getPredecessorValue()
self.tic()
self._simulateSoftwareInstance_checkState()
self._simulateHostingSubscription_CheckInstanceState()
try:
computer.Computer_checkSoftwareInstanceState()
self.tic()
finally:
self._dropSoftwareInstance_checkState()
self._dropHostingSubscription_CheckInstanceState()
self.assertNotEqual('Visited by SoftwareInstance_checkState',
self.assertNotEqual('Visited by HostingSubscription_CheckInstanceState',
instance.workflow_history['edit_workflow'][-1]['comment'])
def _simulateComputer_checkState(self):
......
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