From 3579d15b41d9f786650f76c3b6a98d28f0052f1a Mon Sep 17 00:00:00 2001 From: Jozsef Csongvai Date: Mon, 15 Jun 2020 08:42:08 -0400 Subject: Implement nodetemplate locking feature Enables locking execution of a nodetemplate using a lock key and lock acquire timeout. Issue-ID: CCSDK-2460 Change-Id: I308d4d89dab44b7f7a766d5b62258e67b051eab1 Signed-off-by: Jozsef Csongvai --- .../execution/AbstractComponentFunction.kt | 33 ++++- .../scripts/AbstractComponentFunctionTest.kt | 135 +++++++++++++++++---- .../workflow/NodeTemplateExecutionService.kt | 6 +- .../BluePrintWorkflowExecutionServiceImplTest.kt | 5 + .../services/workflow/BlueprintServiceLogicTest.kt | 5 + .../workflow/DGWorkflowExecutionServiceTest.kt | 5 + .../ImperativeWorkflowExecutionServiceTest.kt | 3 +- .../workflow/NodeTemplateExecutionServiceTest.kt | 7 +- 8 files changed, 171 insertions(+), 28 deletions(-) (limited to 'ms/blueprintsprocessor/modules/services') diff --git a/ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/AbstractComponentFunction.kt b/ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/AbstractComponentFunction.kt index aa39a1dd0..211bf76fb 100644 --- a/ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/AbstractComponentFunction.kt +++ b/ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/AbstractComponentFunction.kt @@ -23,9 +23,14 @@ import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInpu import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceOutput import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.Status import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.StepData +import org.onap.ccsdk.cds.blueprintsprocessor.core.cluster.executeWithLock +import org.onap.ccsdk.cds.blueprintsprocessor.core.service.BluePrintClusterService +import org.onap.ccsdk.cds.blueprintsprocessor.core.service.CDS_LOCK_GROUP import org.onap.ccsdk.cds.controllerblueprints.common.api.EventType import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException +import org.onap.ccsdk.cds.controllerblueprints.core.asJsonType +import org.onap.ccsdk.cds.controllerblueprints.core.checkNotBlank import org.onap.ccsdk.cds.controllerblueprints.core.checkNotEmpty import org.onap.ccsdk.cds.controllerblueprints.core.data.Implementation import org.onap.ccsdk.cds.controllerblueprints.core.getAsString @@ -49,6 +54,7 @@ abstract class AbstractComponentFunction : BlueprintFunctionNode + lateinit var bluePrintClusterService: BluePrintClusterService lateinit var implementation: Implementation lateinit var processId: String lateinit var workflowName: String @@ -95,6 +101,22 @@ abstract class AbstractComponentFunction : BlueprintFunctionNode= 0) { + "Failed to resolve lock acquireTimeout - must be a positive integer" + } + } + check(this::implementation.isInitialized) { "failed to prepare implementation" } val operationResolvedProperties = bluePrintRuntimeService @@ -131,8 +153,17 @@ abstract class AbstractComponentFunction : BlueprintFunctionNode() + bluePrintRuntimeService = mockk() + blueprintContext = mockk() + blueprintClusterService = mockk() + every { bluePrintRuntimeService.bluePrintContext() } returns blueprintContext + every { blueprintContext.rootPath } returns normalizedPathName("target") every { blueprintContext.nodeTemplateOperationImplementation( @@ -80,15 +92,14 @@ class AbstractComponentFunctionTest { @Test fun testAbstractComponent() { runBlocking { - val bluePrintRuntime = mockk("1234") val samp = SampleComponent() val comp = samp as AbstractComponentFunction - comp.bluePrintRuntimeService = bluePrintRuntime + comp.bluePrintRuntimeService = bluePrintRuntimeService comp.stepName = "sample-step" assertNotNull(comp, "failed to get kotlin instance") - val input = getMockedInput(bluePrintRuntime) + val input = getMockedInput(bluePrintRuntimeService) val output = comp.applyNB(input) @@ -115,16 +126,14 @@ class AbstractComponentFunctionTest { @Test fun testAbstractScriptComponent() { runBlocking { - val bluePrintRuntime = mockk("1234") val samp = SampleRestconfComponent(compSvc) val comp = samp as AbstractComponentFunction - comp.bluePrintRuntimeService = bluePrintRuntime + comp.bluePrintRuntimeService = bluePrintRuntimeService comp.stepName = "sample-step" assertNotNull(comp, "failed to get kotlin instance") - val input = getMockedInput(bluePrintRuntime) - val inp = getMockedContext() + val input = getMockedInput(bluePrintRuntimeService) val output = comp.applyNB(input) @@ -135,17 +144,103 @@ class AbstractComponentFunctionTest { } } - /** - * Mocked input for abstract function test. - */ - private fun getMockedContext() { - val operationOutputs = hashMapOf() + @Test + fun testComponentScriptExecutorNodeType() { + val componentScriptExecutor = BluePrintTypes.nodeTypeComponentScriptExecutor() + assertNotNull(componentScriptExecutor.interfaces, "failed to get interface operations") + } + + @Test + fun `prepareRequestNB should resolve lock properties`() { + val implementation = Implementation().apply { + this.lock = LockAssignment().apply { + this.key = """ {"get_input": "lock-key"} """.asJsonPrimitive() + } + } every { - blueprintContext.name() - } returns "SampleTest" + blueprintContext.nodeTemplateOperationImplementation(any(), any(), any()) + } returns implementation + every { - blueprintContext.version() - } returns "SampleScriptComponent" + bluePrintRuntimeService.resolvePropertyAssignments(any(), any(), any()) + } returns mutableMapOf( + "key" to "abc-123-def-456".asJsonType(), + "acquireTimeout" to implementation.lock!!.acquireTimeout + ) + + val component: AbstractComponentFunction = SampleComponent() + component.bluePrintRuntimeService = bluePrintRuntimeService + component.bluePrintClusterService = blueprintClusterService + + runBlocking { + component.prepareRequestNB(getMockedInput(bluePrintRuntimeService)) + } + + val resolvedLock = component.implementation.lock!! + + assertEquals("abc-123-def-456", resolvedLock.key.textValue()) + // default value + assertEquals(180, resolvedLock.acquireTimeout.intValue()) + } + + @Test(expected = Exception::class) + fun `prepareRequestNB should throw exception if it fails to resolve lock key`() { + every { + blueprintContext.nodeTemplateOperationImplementation(any(), any(), any()) + } returns Implementation().apply { this.lock = LockAssignment() } + + every { + bluePrintRuntimeService.resolvePropertyAssignments(any(), any(), any()) + } returns mutableMapOf("key" to "".asJsonType(), + "acquireTimeout" to Integer(360).asJsonType()) + + val component: AbstractComponentFunction = SampleComponent() + component.bluePrintRuntimeService = bluePrintRuntimeService + component.bluePrintClusterService = blueprintClusterService + + runBlocking { + component.prepareRequestNB(getMockedInput(bluePrintRuntimeService)) + } + } + + @Test + fun `applyNB - when lock is present use ClusterLock`() { + + val lockName = "testing-lock" + + every { + blueprintContext.nodeTemplateOperationImplementation(any(), any(), any()) + } returns Implementation().apply { + this.lock = LockAssignment().apply { this.key = lockName.asJsonType() } + } + + every { + bluePrintRuntimeService.resolvePropertyAssignments(any(), any(), any()) + } returns mutableMapOf("key" to lockName.asJsonType(), + "acquireTimeout" to Integer(180).asJsonType()) + + val clusterLock: ClusterLock = mockk() + + every { clusterLock.name() } returns lockName + every { runBlocking { clusterLock.tryLock(any()) } } returns true + every { runBlocking { clusterLock.unLock() } } returns Unit + + every { + runBlocking { blueprintClusterService.clusterLock(any()) } + } returns clusterLock + + val component: AbstractComponentFunction = SampleComponent() + component.bluePrintRuntimeService = bluePrintRuntimeService + component.bluePrintClusterService = blueprintClusterService + + runBlocking { + component.applyNB(getMockedInput(bluePrintRuntimeService)) + } + + verify { + runBlocking { blueprintClusterService.clusterLock("$lockName@$CDS_LOCK_GROUP") } + } + verify { runBlocking { clusterLock.unLock() } } } /** @@ -199,10 +294,4 @@ class AbstractComponentFunctionTest { return executionServiceInput } - - @Test - fun testComponentScriptExecutorNodeType() { - val componentScriptExecutor = BluePrintTypes.nodeTypeComponentScriptExecutor() - assertNotNull(componentScriptExecutor.interfaces, "failed to get interface operations") - } } diff --git a/ms/blueprintsprocessor/modules/services/workflow-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/NodeTemplateExecutionService.kt b/ms/blueprintsprocessor/modules/services/workflow-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/NodeTemplateExecutionService.kt index 6a304e0c7..c703deb37 100644 --- a/ms/blueprintsprocessor/modules/services/workflow-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/NodeTemplateExecutionService.kt +++ b/ms/blueprintsprocessor/modules/services/workflow-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/NodeTemplateExecutionService.kt @@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.JsonNode import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceOutput import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.StepData +import org.onap.ccsdk.cds.blueprintsprocessor.core.service.BluePrintClusterService import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.AbstractComponentFunction import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants import org.onap.ccsdk.cds.controllerblueprints.core.asJsonPrimitive @@ -30,7 +31,7 @@ import org.slf4j.LoggerFactory import org.springframework.stereotype.Service @Service -open class NodeTemplateExecutionService { +open class NodeTemplateExecutionService(private val bluePrintClusterService: BluePrintClusterService) { private val log = LoggerFactory.getLogger(NodeTemplateExecutionService::class.java)!! @@ -62,8 +63,9 @@ open class NodeTemplateExecutionService { // Get the Component Instance val plugin = BluePrintDependencyService.instance(componentName) - // Set the Blueprint Service + // Set the Blueprint Services plugin.bluePrintRuntimeService = bluePrintRuntimeService + plugin.bluePrintClusterService = bluePrintClusterService plugin.stepName = nodeTemplateName // Parent request shouldn't tamper, so need to clone the request and send to the actual component. diff --git a/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/BluePrintWorkflowExecutionServiceImplTest.kt b/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/BluePrintWorkflowExecutionServiceImplTest.kt index 330056221..90b7200c9 100644 --- a/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/BluePrintWorkflowExecutionServiceImplTest.kt +++ b/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/BluePrintWorkflowExecutionServiceImplTest.kt @@ -26,6 +26,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceOutput +import org.onap.ccsdk.cds.blueprintsprocessor.core.service.BluePrintClusterService import org.onap.ccsdk.cds.blueprintsprocessor.services.workflow.mock.MockComponentFunction import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException @@ -34,6 +35,7 @@ import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintDependencyS import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintMetadataUtils import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.mock.mockito.MockBean import org.springframework.test.context.ContextConfiguration import org.springframework.test.context.junit4.SpringRunner import kotlin.test.assertEquals @@ -47,6 +49,9 @@ class BluePrintWorkflowExecutionServiceImplTest { @Autowired lateinit var bluePrintWorkflowExecutionService: BluePrintWorkflowExecutionService + @MockBean + lateinit var bluePrintClusterService: BluePrintClusterService + @Before fun init() { mockkObject(BluePrintDependencyService) diff --git a/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/BlueprintServiceLogicTest.kt b/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/BlueprintServiceLogicTest.kt index 3d44894ee..d391050a6 100644 --- a/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/BlueprintServiceLogicTest.kt +++ b/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/BlueprintServiceLogicTest.kt @@ -22,6 +22,7 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput +import org.onap.ccsdk.cds.blueprintsprocessor.core.service.BluePrintClusterService import org.onap.ccsdk.cds.blueprintsprocessor.services.workflow.executor.ComponentExecuteNodeExecutor import org.onap.ccsdk.cds.blueprintsprocessor.services.workflow.mock.PrototypeComponentFunction import org.onap.ccsdk.cds.blueprintsprocessor.services.workflow.mock.SingletonComponentFunction @@ -30,6 +31,7 @@ import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintDependencyS import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintMetadataUtils import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonReactorUtils import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.mock.mockito.MockBean import org.springframework.context.ApplicationContext import org.springframework.test.context.ContextConfiguration import org.springframework.test.context.junit4.SpringRunner @@ -46,6 +48,9 @@ class BlueprintServiceLogicTest { @Autowired lateinit var dgWorkflowExecutionService: DGWorkflowExecutionService + @MockBean + lateinit var bluePrintClusterService: BluePrintClusterService + @Before fun init() { BluePrintDependencyService.inject(applicationContext) diff --git a/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/DGWorkflowExecutionServiceTest.kt b/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/DGWorkflowExecutionServiceTest.kt index 86d3be26b..cc1bfee7f 100644 --- a/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/DGWorkflowExecutionServiceTest.kt +++ b/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/DGWorkflowExecutionServiceTest.kt @@ -22,12 +22,14 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput +import org.onap.ccsdk.cds.blueprintsprocessor.core.service.BluePrintClusterService import org.onap.ccsdk.cds.blueprintsprocessor.services.workflow.executor.ComponentExecuteNodeExecutor import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintDependencyService import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintMetadataUtils import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonReactorUtils import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.mock.mockito.MockBean import org.springframework.context.ApplicationContext import org.springframework.test.context.ContextConfiguration import org.springframework.test.context.junit4.SpringRunner @@ -44,6 +46,9 @@ class DGWorkflowExecutionServiceTest { @Autowired lateinit var dgWorkflowExecutionService: DGWorkflowExecutionService + @MockBean + lateinit var bluePrintClusterService: BluePrintClusterService + @Before fun init() { BluePrintDependencyService.inject(applicationContext) diff --git a/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/ImperativeWorkflowExecutionServiceTest.kt b/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/ImperativeWorkflowExecutionServiceTest.kt index 415f11d58..1d4738c8d 100644 --- a/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/ImperativeWorkflowExecutionServiceTest.kt +++ b/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/ImperativeWorkflowExecutionServiceTest.kt @@ -17,6 +17,7 @@ package org.onap.ccsdk.cds.blueprintsprocessor.services.workflow import io.mockk.every +import io.mockk.mockk import io.mockk.mockkObject import io.mockk.unmockkAll import kotlinx.coroutines.runBlocking @@ -118,7 +119,7 @@ class ImperativeWorkflowExecutionServiceTest { ExecutionServiceInput::class.java )!! - val bluePrintWorkFlowService = ImperativeBluePrintWorkflowService(NodeTemplateExecutionService()) + val bluePrintWorkFlowService = ImperativeBluePrintWorkflowService(NodeTemplateExecutionService(mockk())) val imperativeWorkflowExecutionService = ImperativeWorkflowExecutionService(bluePrintWorkFlowService) val output = imperativeWorkflowExecutionService .executeBluePrintWorkflow(bluePrintRuntimeService, executionServiceInput, hashMapOf()) diff --git a/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/NodeTemplateExecutionServiceTest.kt b/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/NodeTemplateExecutionServiceTest.kt index 1f51a6aae..f30086596 100644 --- a/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/NodeTemplateExecutionServiceTest.kt +++ b/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/NodeTemplateExecutionServiceTest.kt @@ -24,11 +24,13 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput +import org.onap.ccsdk.cds.blueprintsprocessor.core.service.BluePrintClusterService import org.onap.ccsdk.cds.blueprintsprocessor.services.workflow.mock.MockComponentFunction import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintDependencyService import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintMetadataUtils import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils +import org.springframework.boot.test.mock.mockito.MockBean import org.springframework.test.context.ContextConfiguration import org.springframework.test.context.junit4.SpringRunner import kotlin.test.assertEquals @@ -39,6 +41,9 @@ import kotlin.test.assertNotNull class NodeTemplateExecutionServiceTest { + @MockBean + lateinit var bluePrintClusterService: BluePrintClusterService + @Before fun init() { mockkObject(BluePrintDependencyService) @@ -68,7 +73,7 @@ class NodeTemplateExecutionServiceTest { bluePrintRuntimeService.assignWorkflowInputs("resource-assignment", input) val nodeTemplate = "resource-assignment" - val nodeTemplateExecutionService = NodeTemplateExecutionService() + val nodeTemplateExecutionService = NodeTemplateExecutionService(bluePrintClusterService) val executionServiceOutput = nodeTemplateExecutionService .executeNodeTemplate(bluePrintRuntimeService, nodeTemplate, executionServiceInput) -- cgit 1.2.3-korg