diff --git a/master/bt5/slapos_pdm/PathTemplateItem/portal_alarms/slapos_pdm_destroy_software_installation_with_archived_software_release.xml b/master/bt5/slapos_pdm/PathTemplateItem/portal_alarms/slapos_pdm_destroy_software_installation_with_archived_software_release.xml
new file mode 100644
index 0000000000000000000000000000000000000000..cfe5b8da15c80a987146da6aef04a3fffae1d8cd
--- /dev/null
+++ b/master/bt5/slapos_pdm/PathTemplateItem/portal_alarms/slapos_pdm_destroy_software_installation_with_archived_software_release.xml
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+
+
+ -
+ active_sense_method_id
+ Alarm_destroySoftwareInstallationWithArchivedSoftwareRelease
+
+ -
+ automatic_solve
+ 0
+
+ -
+ description
+
+
+
+
+ -
+ enabled
+ 1
+
+ -
+ id
+ slapos_pdm_destroy_software_installation_with_archived_software_release
+
+ -
+ periodicity_hour
+
+
+
+
+ -
+ periodicity_hour_frequency
+ 2
+
+ -
+ periodicity_minute
+
+
+ 0
+
+
+
+ -
+ periodicity_month
+
+
+
+
+ -
+ periodicity_month_day
+
+
+
+
+ -
+ periodicity_start_date
+
+
+
+
+ -
+ periodicity_week
+
+
+
+
+ -
+ portal_type
+ Alarm
+
+ -
+ title
+ Destroy Software Installation related to archived Software Releases
+
+
+
+
+
diff --git a/master/bt5/slapos_pdm/PortalTypeWorkflowChainTemplateItem/workflow_chain_type.xml b/master/bt5/slapos_pdm/PortalTypeWorkflowChainTemplateItem/workflow_chain_type.xml
index 239e6c011a1199eb33466dbb61718595b39d9cc4..a826fc0dc78ee79ab1b6b0330ededeaa6ad7922e 100644
--- a/master/bt5/slapos_pdm/PortalTypeWorkflowChainTemplateItem/workflow_chain_type.xml
+++ b/master/bt5/slapos_pdm/PortalTypeWorkflowChainTemplateItem/workflow_chain_type.xml
@@ -3,6 +3,10 @@
Software Product
-validation_workflow, commerce_validation_workflow
+
+ Software Release
+ slapos_software_release_cleanup_workflow
+
Upgrade Decision
edit_workflow, ticket_interaction_workflow, upgrade_decision_workflow
diff --git a/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/Alarm_destroySoftwareInstallationWithArchivedSoftwareRelease.py b/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/Alarm_destroySoftwareInstallationWithArchivedSoftwareRelease.py
new file mode 100644
index 0000000000000000000000000000000000000000..72bd399eae7ea9360655484cb70c91c54d82f97f
--- /dev/null
+++ b/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/Alarm_destroySoftwareInstallationWithArchivedSoftwareRelease.py
@@ -0,0 +1,12 @@
+portal = context.getPortalObject()
+
+portal.portal_catalog.searchAndActivate(
+ portal_type='Software Release',
+ validation_state = 'archived',
+ simulation_state = 'draft',
+ method_id = 'SoftwareRelease_findAndDestroySoftwareInstallation',
+ method_kw = {'tag': tag},
+ activate_kw = {'tag':tag}
+)
+
+context.activate(after_tag=tag).getId()
diff --git a/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/Alarm_destroySoftwareInstallationWithArchivedSoftwareRelease.xml b/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/Alarm_destroySoftwareInstallationWithArchivedSoftwareRelease.xml
new file mode 100644
index 0000000000000000000000000000000000000000..aecaf4550d0e0283ca02938b0ebc24b5fdf91865
--- /dev/null
+++ b/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/Alarm_destroySoftwareInstallationWithArchivedSoftwareRelease.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+ -
+ Script_magic
+ 3
+
+ -
+ _bind_names
+
+
+
+
+ -
+ _params
+ tag, fixit, params
+
+ -
+ id
+ Alarm_destroySoftwareInstallationWithArchivedSoftwareRelease
+
+
+
+
+
diff --git a/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/SoftwareInstallation_destroyWithSoftwareReleaseArchived.py b/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/SoftwareInstallation_destroyWithSoftwareReleaseArchived.py
new file mode 100644
index 0000000000000000000000000000000000000000..65468fc6a4427344c8d15b3893fc4f4a87a69d4f
--- /dev/null
+++ b/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/SoftwareInstallation_destroyWithSoftwareReleaseArchived.py
@@ -0,0 +1,24 @@
+software_installation = context
+url_string = software_installation.getUrlString()
+
+if software_installation.getValidationState() != 'validated':
+ return
+if software_installation.getSlapState() != 'start_requested':
+ return
+
+software_release = software_installation.portal_catalog.getResultValue(
+ portal_type='Software Release',
+ validation_state='archived',
+ url_string=url_string
+)
+if software_release is None:
+ return
+
+computer = software_installation.getAggregateValue(portal_type='Computer')
+if computer is None:
+ return
+if computer.Computer_getSoftwareReleaseUsage(url_string) != 0:
+ return
+
+software_installation.requestDestroy(
+ comment='Destroyed by %s as %s is archived.' % (script.id, software_release.getRelativeUrl(),))
diff --git a/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/SoftwareInstallation_destroyWithSoftwareReleaseArchived.xml b/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/SoftwareInstallation_destroyWithSoftwareReleaseArchived.xml
new file mode 100644
index 0000000000000000000000000000000000000000..729c058cadefe72981bca00008f63c3925b57747
--- /dev/null
+++ b/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/SoftwareInstallation_destroyWithSoftwareReleaseArchived.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+ -
+ Script_magic
+ 3
+
+ -
+ _bind_names
+
+
+
+
+ -
+ _params
+
+
+ -
+ id
+ SoftwareInstallation_destroyWithSoftwareReleaseArchived
+
+
+
+
+
diff --git a/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/SoftwareRelease_findAndDestroySoftwareInstallation.py b/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/SoftwareRelease_findAndDestroySoftwareInstallation.py
new file mode 100644
index 0000000000000000000000000000000000000000..2161ad79346d0dce0e25a0f660d1f22588a4ceb7
--- /dev/null
+++ b/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/SoftwareRelease_findAndDestroySoftwareInstallation.py
@@ -0,0 +1,24 @@
+if context.getValidationState() != 'archived':
+ return
+if context.getSimulationState() == 'cleaned':
+ return
+portal = context.getPortalObject()
+
+catalog_kw = dict(
+ portal_type='Software Installation',
+ validation_state='validated',
+ url_string=context.getUrlString()
+)
+
+count = portal.portal_catalog.countResults(
+ **catalog_kw
+)
+
+if count[0][0] == 0:
+ context.cleanup(comment='No more validated Software Installations found')
+else:
+ portal.portal_catalog.searchAndActivate(
+ method_id = 'SoftwareInstallation_destroyWithSoftwareReleaseArchived',
+ activate_kw = {'tag':tag},
+ **catalog_kw
+ )
diff --git a/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/SoftwareRelease_findAndDestroySoftwareInstallation.xml b/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/SoftwareRelease_findAndDestroySoftwareInstallation.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b02b1f5c1e7ad84c5b2acd7be1ae197959598948
--- /dev/null
+++ b/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/SoftwareRelease_findAndDestroySoftwareInstallation.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+ -
+ Script_magic
+ 3
+
+ -
+ _bind_names
+
+
+
+
+ -
+ _params
+ tag
+
+ -
+ id
+ SoftwareRelease_findAndDestroySoftwareInstallation
+
+
+
+
+
diff --git a/master/bt5/slapos_pdm/TestTemplateItem/portal_components/test.erp5.testSlapOSPDMDestroySoftwareInstallationWithArchivedSoftwareReleaseAlarm.py b/master/bt5/slapos_pdm/TestTemplateItem/portal_components/test.erp5.testSlapOSPDMDestroySoftwareInstallationWithArchivedSoftwareReleaseAlarm.py
new file mode 100644
index 0000000000000000000000000000000000000000..bb6586d61f9ec95edcb8c7e15db9ec3c728d2494
--- /dev/null
+++ b/master/bt5/slapos_pdm/TestTemplateItem/portal_components/test.erp5.testSlapOSPDMDestroySoftwareInstallationWithArchivedSoftwareReleaseAlarm.py
@@ -0,0 +1,240 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (c) 2019 Nexedi SA and Contributors. All Rights Reserved.
+#
+##############################################################################
+
+from erp5.component.test.SlapOSTestCaseMixin import SlapOSTestCaseMixin
+from erp5.component.test.testSlapOSAccountingAlarm import simulateByEditWorkflowMark
+
+class TestSlapOSDestroySoftwareInstallationWithArchivedSoftwareReleaseAlarm(SlapOSTestCaseMixin):
+ def createInstance(self, url_string):
+ hosting_subscription = self.portal.hosting_subscription_module\
+ .template_hosting_subscription.Base_createCloneDocument(batch_mode=1)
+ hosting_subscription.edit(
+ )
+ hosting_subscription.validate()
+ hosting_subscription.edit(
+ title=self.generateNewSoftwareTitle(),
+ reference="TESTHS-%s" % self.generateNewId(),
+ )
+ request_kw = dict(
+ software_release=url_string,
+ 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()
+ self.tic()
+ return instance
+
+ def test(self):
+ preference = self.portal.portal_preferences.getActiveSystemPreference()
+ preference.setPreferredCloudContractEnabled(True)
+ self.tic()
+ computer, partition = self._makeComputer()
+ archived_url_string = self.generateNewSoftwareReleaseUrl()
+ # create software release
+ archived_software_release = self.portal.software_release_module.newContent(
+ portal_type='Software Release',
+ version='1',
+ url_string=archived_url_string
+ )
+ archived_software_release.publish()
+ archived_software_release.archive()
+ self.assertEqual('draft', archived_software_release.getSimulationState())
+ # install an software release
+ archived_software_installation = self.portal.software_installation_module\
+ .newContent(portal_type='Software Installation',
+ url_string=archived_url_string,
+ aggregate=computer.getRelativeUrl())
+ archived_software_installation.validate()
+ archived_software_installation.requestStart()
+
+ archived_used_url_string = self.generateNewSoftwareReleaseUrl()
+ # create software release
+ archived_used_software_release = self.portal.software_release_module.newContent(
+ portal_type='Software Release',
+ version='1',
+ url_string=archived_used_url_string
+ )
+ archived_used_software_release.publish()
+ archived_used_software_release.archive()
+ self.assertEqual('draft', archived_used_software_release.getSimulationState())
+ # install an software release
+ archived_used_software_installation = self.portal.software_installation_module\
+ .newContent(portal_type='Software Installation',
+ url_string=archived_used_url_string,
+ aggregate=computer.getRelativeUrl())
+ archived_used_software_installation.validate()
+ archived_used_software_installation.requestStart()
+
+ # use the software release
+ instance = self.createInstance(archived_used_url_string)
+ instance.setAggregate(partition.getRelativeUrl())
+ partition.markBusy()
+ self.tic()
+
+ published_url_string = self.generateNewSoftwareReleaseUrl()
+ # create software release
+ published_software_release = self.portal.software_release_module.newContent(
+ portal_type='Software Release',
+ version='1',
+ url_string=published_url_string
+ )
+ published_software_release.publish()
+ self.assertEqual('draft', published_software_release.getSimulationState())
+ # install an software release
+ published_software_installation = self.portal.software_installation_module\
+ .newContent(portal_type='Software Installation',
+ url_string=published_url_string,
+ aggregate=computer.getRelativeUrl())
+ published_software_installation.validate()
+ published_software_installation.requestStart()
+
+
+ self.tic()
+
+ # first run touches software installation
+ self.stepCallSlaposPdmDestroySoftwareInstallationWithArchivedSoftwareReleaseAlarm()
+ self.tic()
+ self.assertEqual('destroy_requested', archived_software_installation.getSlapState())
+ self.assertEqual('validated', archived_software_installation.getValidationState())
+
+ self.assertEqual('start_requested', published_software_installation.getSlapState())
+ self.assertEqual('validated', published_software_installation.getValidationState())
+
+ self.assertEqual('start_requested', archived_used_software_installation.getSlapState())
+ self.assertEqual('validated', archived_used_software_installation.getValidationState())
+
+ # second run, but it is still not reported that software installation is destroyed
+ self.stepCallSlaposPdmDestroySoftwareInstallationWithArchivedSoftwareReleaseAlarm()
+ self.tic()
+ self.assertEqual('draft', archived_software_release.getSimulationState())
+ self.assertEqual('draft', published_software_release.getSimulationState())
+ self.assertEqual('start_requested', published_software_installation.getSlapState())
+ self.assertEqual('validated', archived_used_software_installation.getValidationState())
+ self.assertEqual('start_requested', archived_used_software_installation.getSlapState())
+
+ # simulate the computer run
+ archived_software_installation.invalidate()
+ self.tic()
+ self.stepCallSlaposPdmDestroySoftwareInstallationWithArchivedSoftwareReleaseAlarm()
+ self.tic()
+ self.assertEqual('cleaned', archived_software_release.getSimulationState())
+ self.assertEqual('draft', published_software_release.getSimulationState())
+ self.assertEqual('start_requested', published_software_installation.getSlapState())
+ self.assertEqual('validated', archived_used_software_installation.getValidationState())
+ self.assertEqual('start_requested', archived_used_software_installation.getSlapState())
+
+ @simulateByEditWorkflowMark('SoftwareRelease_findAndDestroySoftwareInstallation')
+ def test_no_op_run_software_release(self):
+ archived_software_release = self.portal.software_release_module.newContent(
+ portal_type='Software Release',
+ version='1',
+ url_string=self.generateNewSoftwareReleaseUrl(),
+ )
+ archived_software_release.publish()
+ archived_software_release.archive()
+ self.assertEqual('draft', archived_software_release.getSimulationState())
+
+ archived_cleaned_software_release = self.portal.software_release_module.newContent(
+ portal_type='Software Release',
+ version='1',
+ url_string=self.generateNewSoftwareReleaseUrl(),
+ )
+ archived_cleaned_software_release.publish()
+ archived_cleaned_software_release.archive()
+ archived_cleaned_software_release.cleanup()
+ self.assertEqual('cleaned', archived_cleaned_software_release.getSimulationState())
+
+ published_software_release = self.portal.software_release_module.newContent(
+ portal_type='Software Release',
+ version='1',
+ url_string=self.generateNewSoftwareReleaseUrl(),
+ )
+ published_software_release.publish()
+ self.assertEqual('draft', published_software_release.getSimulationState())
+ self.tic()
+
+ self.stepCallSlaposPdmDestroySoftwareInstallationWithArchivedSoftwareReleaseAlarm()
+ self.tic()
+
+ v = 'Visited by SoftwareRelease_findAndDestroySoftwareInstallation'
+ self.assertFalse(v in
+ [q['comment'] for q in published_software_release.workflow_history['edit_workflow']])
+ self.assertFalse(v in
+ [q['comment'] for q in archived_cleaned_software_release.workflow_history['edit_workflow']])
+ self.assertTrue(v in
+ [q['comment'] for q in archived_software_release.workflow_history['edit_workflow']])
+
+ @simulateByEditWorkflowMark('SoftwareInstallation_destroyWithSoftwareReleaseArchived')
+ def test_no_op_run_software_installation(self):
+ preference = self.portal.portal_preferences.getActiveSystemPreference()
+ preference.setPreferredCloudContractEnabled(True)
+ self.tic()
+
+ computer, partition = self._makeComputer()
+ partition.invalidate()
+ partition.markBusy()
+
+ url_string = self.generateNewSoftwareReleaseUrl()
+ archived_software_release = self.portal.software_release_module.newContent(
+ portal_type='Software Release',
+ version='1',
+ url_string=url_string,
+ )
+ archived_software_release.publish()
+ archived_software_release.archive()
+ self.assertEqual('draft', archived_software_release.getSimulationState())
+
+ software_installation_validated_request_start = self.portal.software_installation_module\
+ .newContent(portal_type='Software Installation',
+ url_string=url_string,
+ aggregate=computer.getRelativeUrl())
+ software_installation_validated_request_start.validate()
+ software_installation_validated_request_start.requestStart()
+
+ software_installation_validated_request_destroy = self.portal.software_installation_module\
+ .newContent(portal_type='Software Installation',
+ url_string=url_string,
+ aggregate=computer.getRelativeUrl())
+ software_installation_validated_request_destroy.validate()
+ software_installation_validated_request_destroy.requestStart()
+ software_installation_validated_request_destroy.requestDestroy()
+
+ software_installation_invalidated_request_destroy = self.portal.software_installation_module\
+ .newContent(portal_type='Software Installation',
+ url_string=url_string,
+ aggregate=computer.getRelativeUrl())
+ software_installation_invalidated_request_destroy.validate()
+ software_installation_invalidated_request_destroy.requestStart()
+ software_installation_invalidated_request_destroy.requestDestroy()
+ software_installation_invalidated_request_destroy.invalidate()
+ self.tic()
+
+ # sanity check
+ self.assertEqual('validated', software_installation_validated_request_start.getValidationState())
+ self.assertEqual('start_requested', software_installation_validated_request_start.getSlapState())
+ self.assertEqual('validated', software_installation_validated_request_destroy.getValidationState())
+ self.assertEqual('destroy_requested', software_installation_validated_request_destroy.getSlapState())
+ self.assertEqual('invalidated', software_installation_invalidated_request_destroy.getValidationState())
+ self.assertEqual('destroy_requested', software_installation_invalidated_request_destroy.getSlapState())
+
+ self.stepCallSlaposPdmDestroySoftwareInstallationWithArchivedSoftwareReleaseAlarm()
+ self.tic()
+
+ v = 'Visited by SoftwareInstallation_destroyWithSoftwareReleaseArchived'
+ self.assertTrue(v in
+ [q['comment'] for q in software_installation_validated_request_start.workflow_history['edit_workflow']])
+ self.assertTrue(v in
+ [q['comment'] for q in software_installation_validated_request_destroy.workflow_history['edit_workflow']])
+ self.assertFalse(v in
+ [q['comment'] for q in software_installation_invalidated_request_destroy.workflow_history['edit_workflow']])
\ No newline at end of file
diff --git a/master/bt5/slapos_pdm/TestTemplateItem/portal_components/test.erp5.testSlapOSPDMDestroySoftwareInstallationWithArchivedSoftwareReleaseAlarm.xml b/master/bt5/slapos_pdm/TestTemplateItem/portal_components/test.erp5.testSlapOSPDMDestroySoftwareInstallationWithArchivedSoftwareReleaseAlarm.xml
new file mode 100644
index 0000000000000000000000000000000000000000..cc2d08e65538763933c840efd00a71408a002c08
--- /dev/null
+++ b/master/bt5/slapos_pdm/TestTemplateItem/portal_components/test.erp5.testSlapOSPDMDestroySoftwareInstallationWithArchivedSoftwareReleaseAlarm.xml
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+ -
+ _recorded_property_dict
+
+ AAAAAAAAAAI=
+
+
+ -
+ default_reference
+ testSlapOSPDMDestroySoftwareInstallationWithArchivedSoftwareReleaseAlarm
+
+ -
+ description
+
+
+
+
+ -
+ id
+ test.erp5.testSlapOSPDMDestroySoftwareInstallationWithArchivedSoftwareReleaseAlarm
+
+ -
+ portal_type
+ Test Component
+
+ -
+ sid
+
+
+
+
+ -
+ text_content_error_message
+
+
+
+
+ -
+ text_content_warning_message
+
+
+
+
+ -
+ version
+ erp5
+
+ -
+ workflow_history
+
+ AAAAAAAAAAM=
+
+
+
+
+
+
+
+
+
+
+
+ -
+ data
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+ data
+
+
+
-
+ component_validation_workflow
+
+ AAAAAAAAAAQ=
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+ action
+ validate
+
+ -
+ validation_state
+ validated
+
+
+
+
+
+
+
diff --git a/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow.xml b/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b307e115a3d2fadaef779d4cd69cb82f80c1513d
--- /dev/null
+++ b/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+ -
+ _objects
+
+
+
+
+ -
+ creation_guard
+
+
+
+
+ -
+ description
+
+
+ -
+ groups
+
+
+
+
+ -
+ id
+ slapos_software_release_cleanup_workflow
+
+ -
+ initial_state
+ draft
+
+ -
+ manager_bypass
+ 0
+
+ -
+ permissions
+
+
+ Access contents information
+ View
+ Add portal content
+ Modify portal content
+ Delete objects
+
+
+
+ -
+ state_var
+ simulation_state
+
+ -
+ title
+ Software Release Cleanup Workflow
+
+
+
+
+
diff --git a/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/scripts.xml b/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/scripts.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a703b14c4ca0bde0a51a531783d85f8be1ccd853
--- /dev/null
+++ b/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/scripts.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+ -
+ _mapping
+
+
+
+
+ -
+ id
+ scripts
+
+
+
+
+
diff --git a/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/states.xml b/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/states.xml
new file mode 100644
index 0000000000000000000000000000000000000000..27ec9069024e0f59bf4b612113789f37da98879b
--- /dev/null
+++ b/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/states.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+ -
+ _mapping
+
+
+
+
+ -
+ _objects
+
+
+
+
+ -
+ id
+ states
+
+
+
+
+
diff --git a/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/states/cleaned.xml b/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/states/cleaned.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e5d1e971c48706adf8b8db1521a1e5b610eb58f8
--- /dev/null
+++ b/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/states/cleaned.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+ -
+ description
+
+
+ -
+ id
+ cleaned
+
+ -
+ title
+ Cleaned
+
+ -
+ transitions
+
+
+
+
+ -
+ type_list
+
+
+
+
+
+
+
+
diff --git a/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/states/draft.xml b/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/states/draft.xml
new file mode 100644
index 0000000000000000000000000000000000000000..acfdb537594008e2fa9f20a3ba8292966fe5a95b
--- /dev/null
+++ b/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/states/draft.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+ -
+ description
+
+
+ -
+ id
+ draft
+
+ -
+ title
+ Draft
+
+ -
+ transitions
+
+
+ cleanup
+
+
+
+ -
+ type_list
+
+
+
+
+
+
+
+
diff --git a/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/transitions.xml b/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/transitions.xml
new file mode 100644
index 0000000000000000000000000000000000000000..aa36144efed916b804f5f80df9452b1e3166bdec
--- /dev/null
+++ b/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/transitions.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+ -
+ _mapping
+
+
+
+
+ -
+ _objects
+
+
+
+
+ -
+ id
+ transitions
+
+
+
+
+
diff --git a/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/transitions/cleanup.xml b/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/transitions/cleanup.xml
new file mode 100644
index 0000000000000000000000000000000000000000..db21d98fa1a3173dc835dc325e66c13db05049bb
--- /dev/null
+++ b/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/transitions/cleanup.xml
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+ -
+ actbox_category
+ workflow
+
+ -
+ actbox_icon
+
+
+ -
+ actbox_name
+
+
+ -
+ actbox_url
+
+
+ -
+ after_script_name
+
+
+ -
+ description
+
+
+ -
+ guard
+
+ AAAAAAAAAAI=
+
+
+ -
+ id
+ cleanup
+
+ -
+ new_state_id
+ cleaned
+
+ -
+ script_name
+
+
+ -
+ title
+
+
+ -
+ trigger_type
+ 2
+
+
+
+
+
+
+
+
+
+
+ -
+ permissions
+
+
+ Modify portal content
+
+
+
+
+
+
+
diff --git a/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/variables.xml b/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/variables.xml
new file mode 100644
index 0000000000000000000000000000000000000000..bb12bef805f190ec50e023368d6ee5c6c990b816
--- /dev/null
+++ b/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/variables.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+ -
+ _mapping
+
+
+
+
+ -
+ _objects
+
+
+
+
+ -
+ id
+ variables
+
+
+
+
+
diff --git a/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/variables/action.xml b/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/variables/action.xml
new file mode 100644
index 0000000000000000000000000000000000000000..bb5af22d393b9d5705b4db17eab482f3c69afa35
--- /dev/null
+++ b/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/variables/action.xml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+ -
+ default_expr
+
+ AAAAAAAAAAI=
+
+
+ -
+ default_value
+
+
+ -
+ description
+ Transition id
+
+ -
+ for_catalog
+ 0
+
+ -
+ for_status
+ 1
+
+ -
+ id
+ action
+
+ -
+ info_guard
+
+
+
+
+ -
+ update_always
+ 1
+
+
+
+
+
+
+
+
+
+
+ -
+ text
+ transition/getId|nothing
+
+
+
+
+
diff --git a/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/variables/actor.xml b/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/variables/actor.xml
new file mode 100644
index 0000000000000000000000000000000000000000..fd10331a7a0afa069e0ae18222e2c7b7fd2045fd
--- /dev/null
+++ b/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/variables/actor.xml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+ -
+ default_expr
+
+ AAAAAAAAAAI=
+
+
+ -
+ default_value
+
+
+ -
+ description
+ Name of the user who performed transition
+
+ -
+ for_catalog
+ 0
+
+ -
+ for_status
+ 1
+
+ -
+ id
+ actor
+
+ -
+ info_guard
+
+
+
+
+ -
+ update_always
+ 1
+
+
+
+
+
+
+
+
+
+
+ -
+ text
+ user/getIdOrUserName
+
+
+
+
+
diff --git a/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/variables/comment.xml b/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/variables/comment.xml
new file mode 100644
index 0000000000000000000000000000000000000000..fda919ee8613b8374150500ddfd080ca5d68d7bd
--- /dev/null
+++ b/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/variables/comment.xml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+ -
+ default_expr
+
+ AAAAAAAAAAI=
+
+
+ -
+ default_value
+
+
+ -
+ description
+ Comment about transition
+
+ -
+ for_catalog
+ 0
+
+ -
+ for_status
+ 1
+
+ -
+ id
+ comment
+
+ -
+ info_guard
+
+
+
+
+ -
+ update_always
+ 1
+
+
+
+
+
+
+
+
+
+
+ -
+ text
+ python:state_change.kwargs.get(\'comment\', \'\')
+
+
+
+
+
diff --git a/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/variables/error_message.xml b/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/variables/error_message.xml
new file mode 100644
index 0000000000000000000000000000000000000000..535863de2a26221cff2a356674852ea83bcee061
--- /dev/null
+++ b/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/variables/error_message.xml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+ -
+ default_expr
+
+
+
+
+ -
+ default_value
+
+
+ -
+ description
+ Error message if validation failed
+
+ -
+ for_catalog
+ 0
+
+ -
+ for_status
+ 1
+
+ -
+ id
+ error_message
+
+ -
+ info_guard
+
+
+
+
+ -
+ update_always
+ 1
+
+
+
+
+
diff --git a/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/variables/history.xml b/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/variables/history.xml
new file mode 100644
index 0000000000000000000000000000000000000000..44306b76d7460536661dc87f7786d58d071917d2
--- /dev/null
+++ b/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/variables/history.xml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+ -
+ default_expr
+
+ AAAAAAAAAAI=
+
+
+ -
+ default_value
+
+
+ -
+ description
+ Provides access to workflow history
+
+ -
+ for_catalog
+ 0
+
+ -
+ for_status
+ 0
+
+ -
+ id
+ history
+
+ -
+ info_guard
+
+
+
+
+ -
+ update_always
+ 0
+
+
+
+
+
+
+
+
+
+
+ -
+ text
+ state_change/getHistory
+
+
+
+
+
diff --git a/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/variables/portal_type.xml b/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/variables/portal_type.xml
new file mode 100644
index 0000000000000000000000000000000000000000..89576a7a56ae4e16ceb1cf44e2f9ff9e2ff85f3f
--- /dev/null
+++ b/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/variables/portal_type.xml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+ -
+ default_expr
+
+
+
+
+ -
+ default_value
+
+
+ -
+ description
+ Portal type (used as filter for worklists)
+
+ -
+ for_catalog
+ 1
+
+ -
+ for_status
+ 0
+
+ -
+ id
+ portal_type
+
+ -
+ info_guard
+
+
+
+
+ -
+ update_always
+ 0
+
+
+
+
+
diff --git a/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/variables/time.xml b/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/variables/time.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0d2d8d7e22159b7b4db1fe60eea58cb239a5105a
--- /dev/null
+++ b/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/variables/time.xml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+ -
+ default_expr
+
+ AAAAAAAAAAI=
+
+
+ -
+ default_value
+
+
+ -
+ description
+ Transition timestamp
+
+ -
+ for_catalog
+ 0
+
+ -
+ for_status
+ 1
+
+ -
+ id
+ time
+
+ -
+ info_guard
+
+
+
+
+ -
+ update_always
+ 1
+
+
+
+
+
+
+
+
+
+
+ -
+ text
+ state_change/getDateTime
+
+
+
+
+
diff --git a/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/worklists.xml b/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/worklists.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c3432aa051eac2d67ec0692a384adb38d1b6bac8
--- /dev/null
+++ b/master/bt5/slapos_pdm/WorkflowTemplateItem/portal_workflow/slapos_software_release_cleanup_workflow/worklists.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+ -
+ _mapping
+
+
+
+
+ -
+ id
+ worklists
+
+
+
+
+
diff --git a/master/bt5/slapos_pdm/bt/template_path_list b/master/bt5/slapos_pdm/bt/template_path_list
index ed9f646fcb23662230cc60674b1f65903e882889..afa8b2ccf913c60b113b4e33a80b39a9de0750e6 100644
--- a/master/bt5/slapos_pdm/bt/template_path_list
+++ b/master/bt5/slapos_pdm/bt/template_path_list
@@ -5,6 +5,7 @@ notification_message_module/slapos_upgrade_hosting_subscription_notification
portal_alarms/slapos_manage_software_catalog
portal_alarms/slapos_pdm_auto_cancel_upgrade_decision
portal_alarms/slapos_pdm_computer_create_upgrade_decision
+portal_alarms/slapos_pdm_destroy_software_installation_with_archived_software_release
portal_alarms/slapos_pdm_hosting_subscription_create_upgrade_decision
portal_alarms/slapos_pdm_upgrade_decision_process_planned
portal_alarms/slapos_pdm_upgrade_decision_process_started
diff --git a/master/bt5/slapos_pdm/bt/template_portal_type_workflow_chain_list b/master/bt5/slapos_pdm/bt/template_portal_type_workflow_chain_list
index b1703064a6a0ee5711d5a066e5e65902a7ab91a6..7637bb12a1ce5e170fd672dc9e5999e5b5ecf463 100644
--- a/master/bt5/slapos_pdm/bt/template_portal_type_workflow_chain_list
+++ b/master/bt5/slapos_pdm/bt/template_portal_type_workflow_chain_list
@@ -1,5 +1,6 @@
Software Product | -validation_workflow
Software Product | commerce_validation_workflow
+Software Release | slapos_software_release_cleanup_workflow
Upgrade Decision | edit_workflow
Upgrade Decision | ticket_interaction_workflow
Upgrade Decision | upgrade_decision_workflow
\ No newline at end of file
diff --git a/master/bt5/slapos_pdm/bt/template_test_id_list b/master/bt5/slapos_pdm/bt/template_test_id_list
index 8d1f91994fe4c434e47ea938f3fe79ce60a7fe64..d430b51e7ac65903dcd344825154c91cd1d157b3 100644
--- a/master/bt5/slapos_pdm/bt/template_test_id_list
+++ b/master/bt5/slapos_pdm/bt/template_test_id_list
@@ -1,2 +1,3 @@
test.erp5.testSlapOSPDMAlarm
-test.erp5.testSlapOSPDMSkins
\ No newline at end of file
+test.erp5.testSlapOSPDMSkins
+test.erp5.testSlapOSPDMDestroySoftwareInstallationWithArchivedSoftwareReleaseAlarm
\ No newline at end of file
diff --git a/master/bt5/slapos_pdm/bt/template_workflow_id_list b/master/bt5/slapos_pdm/bt/template_workflow_id_list
index 00d4175090e13c024d9499553849be03b8822ef7..7c4398bc8b69ae687414f921910175a2ab99832e 100644
--- a/master/bt5/slapos_pdm/bt/template_workflow_id_list
+++ b/master/bt5/slapos_pdm/bt/template_workflow_id_list
@@ -1 +1,2 @@
+slapos_software_release_cleanup_workflow
upgrade_decision_workflow
\ No newline at end of file