Add component for deleting resources and tempates
[ccsdk/cds.git] / ms / blueprintsprocessor / functions / resource-resolution / src / main / kotlin / org / onap / ccsdk / cds / blueprintsprocessor / functions / resource / resolution / ResourceDeletionComponent.kt
1 /*
2  * Copyright © 2022 Bell Canada
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution
18
19 import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput
20 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.ResourceResolutionConstants.INPUT_ARTIFACT_PREFIX_NAMES
21 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOLUTION_KEY
22 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_ID
23 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_TYPE
24 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.db.ResourceResolutionDBService
25 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.db.TemplateResolutionService
26 import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.AbstractComponentFunction
27 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants
28 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException
29 import org.onap.ccsdk.cds.controllerblueprints.core.asJsonNode
30 import org.onap.ccsdk.cds.controllerblueprints.core.asJsonPrimitive
31 import org.onap.ccsdk.cds.controllerblueprints.core.asObjectNode
32 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
33 import org.springframework.beans.factory.config.ConfigurableBeanFactory
34 import org.springframework.context.annotation.Scope
35 import org.springframework.stereotype.Component
36
37 @Component("component-resource-deletion")
38 @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
39 open class ResourceDeletionComponent(
40     private val resourceResolutionDBService: ResourceResolutionDBService,
41     private val templateResolutionService: TemplateResolutionService
42 ) : AbstractComponentFunction() {
43
44     companion object {
45         const val INPUT_LAST_N_OCCURRENCES = "last-n-occurrences"
46         const val INPUT_FAIL_ON_EMPTY = "fail-on-empty"
47         const val ATTRIBUTE_RESULT = "result"
48         const val ATTRIBUTE_SUCCESS = "success"
49     }
50
51     data class DeletionResult(val nDeletedTemplates: Int, val nDeletedResources: Int)
52
53     override suspend fun processNB(executionRequest: ExecutionServiceInput) {
54         bluePrintRuntimeService.setNodeTemplateAttributeValue(
55             nodeTemplateName, ATTRIBUTE_RESULT, emptyMap<String, Any>().asJsonNode()
56         )
57         bluePrintRuntimeService.setNodeTemplateAttributeValue(
58             nodeTemplateName, ATTRIBUTE_SUCCESS, false.asJsonPrimitive()
59         )
60
61         val resolutionKey = getOptionalOperationInput(RESOURCE_RESOLUTION_INPUT_RESOLUTION_KEY)?.textValue() ?: ""
62         val resourceId = getOptionalOperationInput(RESOURCE_RESOLUTION_INPUT_RESOURCE_ID)?.textValue() ?: ""
63         val resourceType = getOptionalOperationInput(RESOURCE_RESOLUTION_INPUT_RESOURCE_TYPE)?.textValue() ?: ""
64
65         val resultMap = when {
66             resolutionKey.isNotBlank() -> runDelete(byResolutionKey(resolutionKey))
67             resourceType.isNotBlank() && resourceId.isNotBlank() ->
68                 runDelete(byResourceTypeAndId(resourceType, resourceId))
69             else -> throw BluePrintProcessorException(
70                 "Please use resolution-key OR resource-type + resource-id. Values must not be blank"
71             )
72         }
73         bluePrintRuntimeService.setNodeTemplateAttributeValue(
74             nodeTemplateName, ATTRIBUTE_RESULT, resultMap.asObjectNode()
75         )
76
77         getOptionalOperationInput(INPUT_FAIL_ON_EMPTY)?.booleanValue().takeIf { it == true }?.let {
78             resultMap.all { it.value.nDeletedResources == 0 && it.value.nDeletedTemplates == 0 }
79                 .takeIf { it }?.let {
80                     throw BluePrintProcessorException("No templates or resources were deleted")
81                 }
82         }
83
84         bluePrintRuntimeService.setNodeTemplateAttributeValue(
85             nodeTemplateName, ATTRIBUTE_SUCCESS, true.asJsonPrimitive()
86         )
87     }
88
89     private suspend fun runDelete(fn: suspend (String, String, String, Int?) -> DeletionResult):
90         Map<String, DeletionResult> {
91             val metadata = bluePrintRuntimeService.bluePrintContext().metadata!!
92             val blueprintVersion = metadata[BluePrintConstants.METADATA_TEMPLATE_VERSION]!!
93             val blueprintName = metadata[BluePrintConstants.METADATA_TEMPLATE_NAME]!!
94             val artifactPrefixNamesNode = getOperationInput(INPUT_ARTIFACT_PREFIX_NAMES)
95             val artifactPrefixNames = JacksonUtils.getListFromJsonNode(artifactPrefixNamesNode, String::class.java)
96             val lastN = getOptionalOperationInput(INPUT_LAST_N_OCCURRENCES)?.let {
97                 if (it.isInt) it.intValue() else null
98             }
99
100             return artifactPrefixNames.associateWith { fn(blueprintName, blueprintVersion, it, lastN) }
101         }
102
103     private fun byResolutionKey(resolutionKey: String):
104         suspend (String, String, String, Int?) -> DeletionResult = {
105             bpName, bpVersion, artifactName, lastN ->
106             val nDeleteTemplates = templateResolutionService.deleteTemplates(
107                 bpName, bpVersion, artifactName, resolutionKey, lastN
108             )
109             val nDeletedResources = resourceResolutionDBService.deleteResources(
110                 bpName, bpVersion, artifactName, resolutionKey, lastN
111             )
112             DeletionResult(nDeleteTemplates, nDeletedResources)
113         }
114
115     private fun byResourceTypeAndId(resourceType: String, resourceId: String):
116         suspend (String, String, String, Int?) -> DeletionResult = {
117             bpName, bpVersion, artifactName, lastN ->
118             val nDeletedTemplates = templateResolutionService.deleteTemplates(
119                 bpName, bpVersion, artifactName, resourceType, resourceId, lastN
120             )
121             val nDeletedResources = resourceResolutionDBService.deleteResources(
122                 bpName, bpVersion, artifactName, resourceType, resourceId, lastN
123             )
124             DeletionResult(nDeletedTemplates, nDeletedResources)
125         }
126
127     override suspend fun recoverNB(runtimeException: RuntimeException, executionRequest: ExecutionServiceInput) {
128         addError(runtimeException.message ?: "Failed in ResourceDeletionComponent")
129     }
130 }