Commit 7ab14f7d authored by Alain Takoudjou's avatar Alain Takoudjou

Slapos_pdm: Alarm create upgrade decision for software release

parent faf2b0b5
<?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_computerCheckUpgradeSoftwareRelease</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>Create Upgrade Decision for computers to upgrade Software Releases to a newer version.</string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>slapos_pdm_computer_create_upgrade_decision</string> </value>
</item>
<item>
<key> <string>periodicity_hour</string> </key>
<value>
<tuple>
<int>0</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>0</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>
<int>1</int>
</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>1406073600.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>Create Upgrade Decision for computers</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
\n
public_scope_uid = portal.restrictedTraverse(\n
"portal_categories/allocation_scope/open/public", None).getUid()\n
friend_scope_uid = portal.restrictedTraverse(\n
"portal_categories/allocation_scope/open/friend", None).getUid()\n
\n
if public_scope_uid and friend_scope_uid:\n
portal.portal_catalog.searchAndActivate(\n
portal_type=\'Computer\',\n
validation_state = \'validated\',\n
default_allocation_scope_uid=[public_scope_uid, friend_scope_uid],\n
method_id = \'Computer_checkAndCreateUpgradeDecision\',\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_computerCheckUpgradeSoftwareRelease</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>computer = context\n
portal = context.getPortalObject()\n
\n
full_software_release_list = [si.getUrlString() for si in \n
portal.portal_catalog(\n
portal_type=\'Software Installation\',\n
default_aggregate_uid=computer.getUid(),\n
validation_state=\'validated\'\n
) if si.getSlapState() == \'start_requested\']\n
\n
if len(full_software_release_list) == 0:\n
return\n
# group SR by Software Product to avoid two upgrade Decision for the same product\n
software_release_list = portal.portal_catalog(\n
portal_type=\'Software Release\',\n
url_string=full_software_release_list,\n
group_by=\'default_aggregate_uid\'\n
)\n
\n
for software_release in software_release_list:\n
software_product_reference = software_release.getAggregateReference()\n
sorted_list = portal.SoftwareProduct_getSortedSoftwareReleaseList(\n
software_product_reference=software_product_reference)\n
\n
# Check if there is a new version of this software Product\n
if sorted_list and \\\n
sorted_list[0].getUrlString() not in full_software_release_list:\n
\n
newer_release = sorted_list[0]\n
title = \'A new software release is available for %s\' % \\\n
software_product_reference\n
# Search if exist upgrade decision for this software product (by title)\n
is_decision_in_progress = newer_release.\\\n
SoftwareRelease_isUpgradeDecisionInProgress(title=title)\n
if is_decision_in_progress:\n
continue\n
\n
return newer_release.SoftwareRelease_createUpgradeDecision(\n
computer_url=computer.getRelativeUrl(), title=title\n
)\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Computer_checkAndCreateUpgradeDecision</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 DateTime import DateTime\n
\n
portal = context.getPortalObject()\n
\n
software_release = context\n
computer = portal.restrictedTraverse(computer_url, None)\n
if not computer:\n
return\n
\n
person_url = computer.getSourceAdministration()\n
if not person_url:\n
return\n
\n
upgrade_decision = portal.upgrade_decision_module.\\\n
template_upgrade_decision.Base_createCloneDocument(batch_mode=1) \n
upgrade_decision.edit(\n
title=title,\n
destination_section=person_url,\n
destination_decision=person_url,\n
start_date=DateTime()\n
)\n
upgrade_decision.confirm()\n
decision_line_list = upgrade_decision.contentValues(\n
portal_type=\'Upgrade Decision Line\')\n
if len(decision_line_list) > 0:\n
decision_line = decision_line_list[0]\n
else:\n
decision_line = upgrade_decision.newContent(\n
portal_type=\'Upgrade Decision Line\')\n
\n
decision_line.edit(\n
title=\'Request decision upgrade for %s on computer %s\' % (\n
software_release.getTitle(), computer.getReference()),\n
aggregate=[computer_url, software_release.getRelativeUrl()])\n
\n
return upgrade_decision\n
]]></string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>computer_url, title</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>SoftwareRelease_createUpgradeDecision</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>url_string = context.getUrlString()\n
portal = context.getPortalObject()\n
\n
# Check if there is an upgrade decision in progress\n
kw[\'portal_type\'] = \'Upgrade Decision\'\n
upgrade_decision_in_progress = portal.portal_catalog(**kw)\n
\n
if len(upgrade_decision_in_progress) == 0:\n
return False\n
\n
in_progress = False\n
for decision_in_progress in upgrade_decision_in_progress:\n
found_url = decision_in_progress.\\\n
UpgradeDecision_getSoftwareRelease().getUrlString()\n
if found_url == url_string:\n
in_progress = True\n
break\n
\n
return in_progress\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>**kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>SoftwareRelease_isUpgradeDecisionInProgress</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -21,6 +21,21 @@ class TestSlapOSUpgradeDecisionProcess(testSlapOSMixin): ...@@ -21,6 +21,21 @@ class TestSlapOSUpgradeDecisionProcess(testSlapOSMixin):
upgrade_decision.confirm() upgrade_decision.confirm()
return upgrade_decision return upgrade_decision
def _makeComputer(self,new_id):
# Clone computer document
person = self.portal.person_module.template_member\
.Base_createCloneDocument(batch_mode=1)
computer = self.portal.computer_module\
.template_computer.Base_createCloneDocument(batch_mode=1)
computer.edit(
title="computer ticket %s" % (new_id, ),
reference="TESTCOMPT-%s" % (new_id, ),
source_administration_value=person
)
computer.validate()
return computer
def _simulateUpgradeDecision_upgradeHostingSubscription(self, fake_return="True"): def _simulateUpgradeDecision_upgradeHostingSubscription(self, fake_return="True"):
self._simulateScript('UpgradeDecision_upgradeHostingSubscription', fake_return) self._simulateScript('UpgradeDecision_upgradeHostingSubscription', fake_return)
...@@ -84,11 +99,42 @@ return %s ...@@ -84,11 +99,42 @@ return %s
upgrade_decision.workflow_history['edit_workflow'][-1]['comment']) upgrade_decision.workflow_history['edit_workflow'][-1]['comment'])
def _simulateComputer_checkAndCreateUpgradeDecision(self):
script_name = 'Computer_checkAndCreateUpgradeDecision'
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 Computer_checkAndCreateUpgradeDecision') """ )
transaction.commit()
def _dropComputer_checkAndCreateUpgradeDecision(self):
script_name = 'Computer_checkAndCreateUpgradeDecision'
if script_name in self.portal.portal_skins.custom.objectIds():
self.portal.portal_skins.custom.manage_delObjects(script_name)
transaction.commit()
def test_Alarm_computerCheckUpgradeSoftwareRelease(self):
computer = self._makeComputer(self.new_id)
computer.edit(allocation_scope = 'open/public')
computer2 = self._makeComputer(self.generateNewId())
computer2.edit(allocation_scope = 'open/personal')
self._simulateComputer_checkAndCreateUpgradeDecision()
try:
self.portal.portal_alarms.slapos_pdm_computer_create_upgrade_decision.\
activeSense()
self.tic()
finally:
self._dropComputer_checkAndCreateUpgradeDecision()
self.assertEqual('Visited by Computer_checkAndCreateUpgradeDecision',
computer.workflow_history['edit_workflow'][-1]['comment'])
self.assertNotEqual('Visited by Computer_checkAndCreateUpgradeDecision',
computer2.workflow_history['edit_workflow'][-1]['comment'])
...@@ -29,11 +29,20 @@ ...@@ -29,11 +29,20 @@
import transaction import transaction
from Products.SlapOS.tests.testSlapOSMixin import testSlapOSMixin from Products.SlapOS.tests.testSlapOSMixin import testSlapOSMixin
from Products.ERP5Type.tests.utils import createZODBPythonScript from Products.ERP5Type.tests.utils import createZODBPythonScript
from DateTime import DateTime
class TestSlapOSPDMSkins(testSlapOSMixin): class TestSlapOSPDMSkins(testSlapOSMixin):
def afterSetUp(self): def afterSetUp(self):
super(TestSlapOSPDMSkins, self).afterSetUp() super(TestSlapOSPDMSkins, self).afterSetUp()
self.new_id = self.generateNewId() self.new_id = self.generateNewId()
self.request_kw = dict(
software_title=self.generateNewSoftwareTitle(),
software_type=self.generateNewSoftwareType(),
instance_xml=self.generateSafeXml(),
sla_xml=self.generateEmptyXml(),
shared=False,
state="started"
)
def generateNewId(self): def generateNewId(self):
return "%sTEST" % self.portal.portal_ids.generateNewId( return "%sTEST" % self.portal.portal_ids.generateNewId(
...@@ -81,6 +90,12 @@ class TestSlapOSPDMSkins(testSlapOSMixin): ...@@ -81,6 +90,12 @@ class TestSlapOSPDMSkins(testSlapOSMixin):
p.markFree() p.markFree()
p.validate() p.validate()
def _markComputerPartitionBusy(self, computer, software_instance):
for partition in computer.contentValues(portal_type='Computer Partition'):
if partition.getSlapState() == 'free':
software_instance.edit(aggregate=partition.getRelativeUrl())
break;
def _makeSoftwareProduct(self, new_id): def _makeSoftwareProduct(self, new_id):
software_product = self.portal.software_product_module\ software_product = self.portal.software_product_module\
.template_software_product.Base_createCloneDocument(batch_mode=1) .template_software_product.Base_createCloneDocument(batch_mode=1)
...@@ -89,6 +104,7 @@ class TestSlapOSPDMSkins(testSlapOSMixin): ...@@ -89,6 +104,7 @@ class TestSlapOSPDMSkins(testSlapOSMixin):
title='Test software product %s' % new_id title='Test software product %s' % new_id
) )
software_product.validate() software_product.validate()
software_product.publish()
return software_product return software_product
...@@ -104,6 +120,17 @@ class TestSlapOSPDMSkins(testSlapOSMixin): ...@@ -104,6 +120,17 @@ class TestSlapOSPDMSkins(testSlapOSMixin):
return software_release return software_release
def _requestSoftwareRelease(self, new_id, software_product_url, effective_date=None):
software_release = self._makeSoftwareRelease(new_id)
if not effective_date:
effective_date = DateTime()
software_release.edit(
aggregate_value=software_product_url,
effective_date=effective_date
)
software_release.publish()
return software_release
def _makeSoftwareInstallation(self, new_id, computer, software_release_url): def _makeSoftwareInstallation(self, new_id, computer, software_release_url):
software_installation = self.portal\ software_installation = self.portal\
.software_installation_module.template_software_installation\ .software_installation_module.template_software_installation\
...@@ -145,6 +172,49 @@ class TestSlapOSPDMSkins(testSlapOSMixin): ...@@ -145,6 +172,49 @@ class TestSlapOSPDMSkins(testSlapOSMixin):
hosting_subscription.requestStart(**kw) hosting_subscription.requestStart(**kw)
hosting_subscription.requestInstance(**kw) hosting_subscription.requestInstance(**kw)
def _makeFullHostingSubscription(self, new_id, software_url="", person=None):
if not person:
person = self._makePerson(new_id)
hosting_subscription = self.portal\
.hosting_subscription_module.template_hosting_subscription\
.Base_createCloneDocument(batch_mode=1)
hosting_subscription.edit(
title=self.request_kw['software_title'],
reference="TESTHS-%s" % new_id,
url_string=software_url,
source_reference=self.request_kw['software_type'],
text_content=self.request_kw['instance_xml'],
sla_xml=self.request_kw['sla_xml'],
root_slave=self.request_kw['shared'],
destination_section=person.getRelativeUrl()
)
hosting_subscription.validate()
self.portal.portal_workflow._jumpToStateFor(hosting_subscription, 'start_requested')
return hosting_subscription
def _makeFullSoftwareInstance(self, hosting_subscription, software_url):
software_instance = self.portal.software_instance_module\
.template_software_instance.Base_createCloneDocument(batch_mode=1)
software_instance.edit(
title=self.request_kw['software_title'],
reference="TESTSI-%s" % self.generateNewId(),
url_string=software_url,
source_reference=self.request_kw['software_type'],
text_content=self.request_kw['instance_xml'],
sla_xml=self.request_kw['sla_xml'],
specialise=hosting_subscription.getRelativeUrl()
)
hosting_subscription.edit(
predecessor=software_instance.getRelativeUrl()
)
self.portal.portal_workflow._jumpToStateFor(software_instance, 'start_requested')
software_instance.validate()
return software_instance
def _makeUpgradeDecision(self): def _makeUpgradeDecision(self):
return self.portal.\ return self.portal.\
upgrade_decision_module.newContent( upgrade_decision_module.newContent(
...@@ -432,3 +502,103 @@ class TestSlapOSPDMSkins(testSlapOSMixin): ...@@ -432,3 +502,103 @@ class TestSlapOSPDMSkins(testSlapOSMixin):
self.assertEqual('validated', software_installation.getValidationState()) self.assertEqual('validated', software_installation.getValidationState())
self.assertEqual('stopped', upgrade_decision.getSimulationState()) self.assertEqual('stopped', upgrade_decision.getSimulationState())
def testSoftwareRelease_createUpgradeDecision(self):
person = self._makePerson(self.new_id)
computer = self._makeComputer(self.new_id)
computer.edit(source_administration_value=person)
software_release = self._makeSoftwareRelease(self.new_id)
upgrade_decision = software_release.SoftwareRelease_createUpgradeDecision(
computer_url=computer.getRelativeUrl(),
title="TEST-SRUPDE-%s" % self.new_id)
self.tic()
self.assertEqual(upgrade_decision.getSimulationState(), 'confirmed')
self.assertEqual(upgrade_decision.getDestinationSection(),
person.getRelativeUrl())
decision_line = upgrade_decision.contentValues(
portal_type='Upgrade Decision Line')[0]
self.assertEqual(decision_line.getTitle(),
'Request decision upgrade for %s on computer %s' % (
software_release.getTitle(), computer.getReference())
)
self.assertEqual(decision_line.getAggregate(portal_type='Computer'),
computer.getRelativeUrl())
self.assertEqual(decision_line.getAggregate(portal_type='Software Release'),
software_release.getRelativeUrl())
def testSoftwareRelease_isUpgradeDecisionInProgress(self):
computer = self._makeComputer(self.new_id)
software_release = self._makeSoftwareRelease(self.new_id)
upgrade_decision = self._makeUpgradeDecision()
upgrade_decision_line = self._makeUpgradeDecisionLine(upgrade_decision)
upgrade_decision_line.setAggregateValueList([software_release, computer])
software_release2 = self._makeSoftwareRelease(self.generateNewId())
upgrade_decision.confirm()
self.tic()
in_progress = software_release.SoftwareRelease_isUpgradeDecisionInProgress(
title=upgrade_decision.getTitle()
)
self.assertEqual(in_progress, True)
in_progress = software_release.SoftwareRelease_isUpgradeDecisionInProgress()
self.assertEqual(in_progress, True)
in_progress = software_release.SoftwareRelease_isUpgradeDecisionInProgress(
title=upgrade_decision.getTitle(),
simulation_state='stopped'
)
self.assertEqual(in_progress, False)
in_progress = software_release2.SoftwareRelease_isUpgradeDecisionInProgress(
title=upgrade_decision.getTitle()
)
self.assertEqual(in_progress, False)
def testComputer_checkAndCreateUpgradeDecision(self):
person = self._makePerson(self.new_id)
computer = self._makeComputer(self.new_id)
computer.edit(source_administration_value=person)
software_product = self._makeSoftwareProduct(self.new_id)
software_release = self._requestSoftwareRelease(self.new_id,
software_product.getRelativeUrl())
self._makeSoftwareInstallation(self.new_id,
computer, software_release.getUrlString())
self.tic()
upgrade_decision = computer.Computer_checkAndCreateUpgradeDecision()
self.assertEqual(upgrade_decision, None)
software_release2 = self._requestSoftwareRelease(self.generateNewId(),
software_product.getRelativeUrl())
# Should be ignored, Publication Date is for tomorrow
self._requestSoftwareRelease(self.generateNewId(),
software_product.getRelativeUrl(),
(DateTime() + 1))
self.tic()
upgrade_decision = computer.Computer_checkAndCreateUpgradeDecision()
self.assertNotEqual(upgrade_decision, None)
self.assertEqual(upgrade_decision.getSimulationState(), 'confirmed')
computer_aggregate = upgrade_decision.UpgradeDecision_getComputer()
self.assertEqual(computer_aggregate.getReference(),
computer.getReference())
url_string = upgrade_decision.UpgradeDecision_getSoftwareRelease()
self.assertEqual(url_string.getUrlString(),
software_release2.getUrlString())
self.tic()
upgrade_decision2 = computer.Computer_checkAndCreateUpgradeDecision()
self.assertEqual(upgrade_decision2, None)
\ No newline at end of file
15 16
\ No newline at end of file \ No newline at end of file
portal_alarms/slapos_manage_software_catalog portal_alarms/slapos_manage_software_catalog
portal_alarms/slapos_pdm_computer_create_upgrade_decision
portal_alarms/slapos_upgrade_decision_process portal_alarms/slapos_upgrade_decision_process
software_product_module/template_software_product software_product_module/template_software_product
software_release_module/template_software_release software_release_module/template_software_release
\ No newline at end of file
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