restconf kotlin script support 58/78558/2
authorMuthuramalingam, Brinda Santh <brindasanth@in.ibm.com>
Fri, 15 Feb 2019 14:15:35 +0000 (09:15 -0500)
committerAlexis de Talhouët <adetalhouet89@gmail.com>
Sun, 17 Feb 2019 14:46:44 +0000 (09:46 -0500)
Change-Id: I07eaa4a2422b461e1b7eb13ec04bf7d10ea08770
Issue-ID: CCSDK-1080
Signed-off-by: Muthuramalingam, Brinda Santh <brindasanth@in.ibm.com>
12 files changed:
components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Definitions/node_types.json
components/model-catalog/definition-type/starter-type/node_type/component-netconf-executor.json
components/model-catalog/definition-type/starter-type/node_type/component-restconf-executor.json
ms/blueprintsprocessor/functions/restconf-executor/pom.xml
ms/blueprintsprocessor/functions/restconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/restconf/executor/ComponentRestconfExecutor.kt
ms/blueprintsprocessor/functions/restconf-executor/src/main/kotlin/scripts/InternalSimpleRestconf.cba.kts [new file with mode: 0644]
ms/blueprintsprocessor/functions/restconf-executor/src/test/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/restconf/executor/ComponentRestconfExecutorTest.kt
ms/blueprintsprocessor/parent/pom.xml
ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/apps/controllerblueprints/core/BluePrintConstants.kt
ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/apps/controllerblueprints/core/interfaces/BluePrintScriptsService.kt
ms/controllerblueprints/modules/blueprint-scripts/src/main/kotlin/org/onap/ccsdk/apps/controllerblueprints/scripts/BluePrintCompilerProxy.kt
ms/controllerblueprints/modules/blueprint-scripts/src/main/kotlin/org/onap/ccsdk/apps/controllerblueprints/scripts/BluePrintScriptsServiceImpl.kt

index 5273070..6527183 100644 (file)
@@ -89,7 +89,7 @@
           }
         }
       },
-      "derived_from": "tosca.nodes.component.Jython"
+      "derived_from": "tosca.nodes.Component"
     },
     "component-resource-resolution": {
       "description": "This is Resource Assignment Component API",
index 884be5d..192ed25 100644 (file)
@@ -1,5 +1,5 @@
 {
-  "description": "This is Netconf Transaction Configuration Component API",
+  "description": "This is Restconf Transaction Configuration Component API",
   "version": "1.0.0",
   "capabilities": {
     "component-node": {
       "operations": {
         "process": {
           "inputs": {
+            "script-type": {
+              "description": "Script type, kotlin type is supported",
+              "required": true,
+              "type": "string",
+              "default": "internal",
+              "constraints": [
+                {
+                  "valid_values": [
+                    "kotlin",
+                    "jython",
+                    "internal"
+                  ]
+                }
+              ]
+            },
+            "script-class-reference": {
+              "description": "Kotlin Script class name or jython script name.",
+              "required": true,
+              "type": "string"
+            },
             "instance-dependencies": {
               "required": true,
-              "description": "Instance Names to Inject to Jython Script.",
+              "description": "Instance names to inject to Jython or Kotlin Script.",
               "type": "list",
               "entry_schema": {
                 "type": "string"
index 5fdae5e..dea3a8a 100644 (file)
             <groupId>org.onap.ccsdk.apps.blueprintsprocessor.functions</groupId>
             <artifactId>python-executor</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.onap.ccsdk.apps.controllerblueprints</groupId>
+            <artifactId>blueprint-scripts</artifactId>
+        </dependency>
+
+        <!--Testing dependencies-->
+        <dependency>
+            <groupId>org.jetbrains.kotlin</groupId>
+            <artifactId>kotlin-test-junit</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.mockk</groupId>
+            <artifactId>mockk</artifactId>
+        </dependency>
     </dependencies>
 
 
index 67202df..e91b95f 100644 (file)
@@ -20,6 +20,10 @@ import org.onap.ccsdk.apps.blueprintsprocessor.core.api.data.ExecutionServiceInp
 import org.onap.ccsdk.apps.blueprintsprocessor.functions.python.executor.BlueprintJythonService
 import org.onap.ccsdk.apps.blueprintsprocessor.rest.service.BluePrintRestLibPropertyService
 import org.onap.ccsdk.apps.blueprintsprocessor.services.execution.AbstractComponentFunction
+import org.onap.ccsdk.apps.controllerblueprints.core.BluePrintConstants
+import org.onap.ccsdk.apps.controllerblueprints.core.BluePrintProcessorException
+import org.onap.ccsdk.apps.controllerblueprints.core.getAsString
+import org.onap.ccsdk.apps.controllerblueprints.core.interfaces.BluePrintScriptsService
 import org.slf4j.LoggerFactory
 import org.springframework.beans.factory.config.ConfigurableBeanFactory
 import org.springframework.context.ApplicationContext
@@ -30,16 +34,28 @@ import org.springframework.stereotype.Component
 @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
 open class ComponentRestconfExecutor(private var applicationContext: ApplicationContext,
                                      private val blueprintJythonService: BlueprintJythonService,
-                                     var bluePrintRestLibPropertyService: BluePrintRestLibPropertyService) :
+                                     private val bluePrintScriptsService: BluePrintScriptsService,
+                                     private var bluePrintRestLibPropertyService: BluePrintRestLibPropertyService) :
         AbstractComponentFunction() {
 
     private val log = LoggerFactory.getLogger(ComponentRestconfExecutor::class.java)
 
     lateinit var scriptComponent: RestconfComponentFunction
 
+    companion object {
+        const val SCRIPT_TYPE = "script-type"
+        const val SCRIPT_CLASS_REFERENCE = "script-class-reference"
+    }
+
     override fun process(executionRequest: ExecutionServiceInput) {
-        scriptComponent = blueprintJythonService.jythonComponentInstance(this) as RestconfComponentFunction
-        checkNotNull(scriptComponent) { "failed to get netconf script component" }
+
+        val scriptType = operationInputs.getAsString(SCRIPT_TYPE)
+        val scriptClassReference = operationInputs.getAsString(SCRIPT_CLASS_REFERENCE)
+        /**
+         * Populate the Script Instance based on the Type
+         */
+        restconfComponentFunction(scriptType, scriptClassReference)
+        checkNotNull(scriptComponent) { "failed to get restconf script component" }
 
         scriptComponent.bluePrintRuntimeService = bluePrintRuntimeService
         scriptComponent.processId = processId
@@ -59,4 +75,24 @@ open class ComponentRestconfExecutor(private var applicationContext: Application
     override fun recover(runtimeException: RuntimeException, executionRequest: ExecutionServiceInput) {
         scriptComponent.recover(runtimeException, executionRequest)
     }
+
+    fun restconfComponentFunction(scriptType: String, scriptClassReference: String): RestconfComponentFunction {
+        log.info("processing restconf script type($scriptType), reference name($scriptClassReference)")
+        when (scriptType) {
+            BluePrintConstants.SCRIPT_INTERNAL -> {
+                scriptComponent = bluePrintScriptsService.scriptInstance<RestconfComponentFunction>(scriptClassReference)
+            }
+            BluePrintConstants.SCRIPT_KOTLIN -> {
+                scriptComponent = bluePrintScriptsService.scriptInstance<RestconfComponentFunction>(bluePrintRuntimeService
+                        .bluePrintContext(), scriptClassReference, false)
+            }
+            BluePrintConstants.SCRIPT_JYTHON -> {
+                scriptComponent = blueprintJythonService.jythonComponentInstance(this) as RestconfComponentFunction
+            }
+            else -> {
+                throw BluePrintProcessorException("script type($scriptType) is not supported")
+            }
+        }
+        return scriptComponent
+    }
 }
\ No newline at end of file
diff --git a/ms/blueprintsprocessor/functions/restconf-executor/src/main/kotlin/scripts/InternalSimpleRestconf.cba.kts b/ms/blueprintsprocessor/functions/restconf-executor/src/main/kotlin/scripts/InternalSimpleRestconf.cba.kts
new file mode 100644 (file)
index 0000000..1c4ba9b
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ *  Copyright © 2018 IBM.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+import org.onap.ccsdk.apps.blueprintsprocessor.core.api.data.ExecutionServiceInput
+import org.onap.ccsdk.apps.blueprintsprocessor.functions.restconf.executor.RestconfComponentFunction
+import org.slf4j.LoggerFactory
+
+open class EditConfigure : RestconfComponentFunction() {
+
+    val log = LoggerFactory.getLogger(EditConfigure::class.java)!!
+
+    override fun getName(): String {
+        return "EditConfigure"
+    }
+
+    override fun process(executionRequest: ExecutionServiceInput) {
+        val webClientService = restClientService("odlparent")
+        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+    }
+
+    override fun recover(runtimeException: RuntimeException, executionRequest: ExecutionServiceInput) {
+        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+    }
+}
+
+open class MountNEditConfigure : RestconfComponentFunction() {
+
+    val log = LoggerFactory.getLogger(MountNEditConfigure::class.java)!!
+
+    override fun getName(): String {
+        return "MountNEditConfigure"
+    }
+
+    override fun process(executionRequest: ExecutionServiceInput) {
+        val webClientService = restClientService("odlparent")
+        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+    }
+
+    override fun recover(runtimeException: RuntimeException, executionRequest: ExecutionServiceInput) {
+        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+    }
+}
+
+/**
+ * This is for used for Testing only
+ */
+open class TestRestconfConfigure : RestconfComponentFunction() {
+
+    val log = LoggerFactory.getLogger(TestRestconfConfigure::class.java)!!
+
+    override fun getName(): String {
+        return "TestRestconfConfigure"
+    }
+
+    override fun process(executionRequest: ExecutionServiceInput) {
+        log.info("processing request..")
+    }
+
+    override fun recover(runtimeException: RuntimeException, executionRequest: ExecutionServiceInput) {
+        log.info("recovering..")
+    }
+}
\ No newline at end of file
index b195fe0..77d4691 100644 (file)
 
 package org.onap.ccsdk.apps.blueprintsprocessor.functions.restconf.executor
 
+import com.fasterxml.jackson.databind.JsonNode
+import com.fasterxml.jackson.databind.node.ObjectNode
+import io.mockk.every
+import io.mockk.mockk
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.onap.ccsdk.apps.blueprintsprocessor.core.BluePrintProperties
 import org.onap.ccsdk.apps.blueprintsprocessor.core.BlueprintPropertyConfiguration
+import org.onap.ccsdk.apps.blueprintsprocessor.core.api.data.ActionIdentifiers
+import org.onap.ccsdk.apps.blueprintsprocessor.core.api.data.CommonHeader
+import org.onap.ccsdk.apps.blueprintsprocessor.core.api.data.ExecutionServiceInput
 import org.onap.ccsdk.apps.blueprintsprocessor.functions.python.executor.BlueprintJythonService
 import org.onap.ccsdk.apps.blueprintsprocessor.functions.python.executor.PythonExecutorProperty
 import org.onap.ccsdk.apps.blueprintsprocessor.rest.service.BluePrintRestLibPropertyService
+import org.onap.ccsdk.apps.controllerblueprints.core.BluePrintConstants
+import org.onap.ccsdk.apps.controllerblueprints.core.asJsonNode
+import org.onap.ccsdk.apps.controllerblueprints.core.asJsonPrimitive
+import org.onap.ccsdk.apps.controllerblueprints.core.service.DefaultBluePrintRuntimeService
+import org.onap.ccsdk.apps.controllerblueprints.core.utils.JacksonUtils
+import org.onap.ccsdk.apps.controllerblueprints.scripts.BluePrintScriptsServiceImpl
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.test.context.ContextConfiguration
 import org.springframework.test.context.TestPropertySource
@@ -33,7 +46,7 @@ import kotlin.test.assertNotNull
 @RunWith(SpringRunner::class)
 @ContextConfiguration(classes = [RestconfExecutorConfiguration::class, ComponentRestconfExecutor::class,
     BlueprintJythonService::class, PythonExecutorProperty::class, BluePrintRestLibPropertyService::class,
-    BlueprintPropertyConfiguration::class,BluePrintProperties::class])
+    BlueprintPropertyConfiguration::class, BluePrintProperties::class, BluePrintScriptsServiceImpl::class])
 @TestPropertySource(properties =
 ["server.port=9111",
     "blueprintsprocessor.restconfEnabled=true",
@@ -48,9 +61,40 @@ class ComponentRestconfExecutorTest {
 
     @Test
     fun `test Restconf Component Instance`() {
-
         assertNotNull(componentRestconfExecutor, "failed to get ComponentRestconfExecutor instance")
-    }
+        val executionServiceInput = ExecutionServiceInput().apply {
+            commonHeader = CommonHeader().apply {
+                requestId = "1234"
+            }
+            actionIdentifiers = ActionIdentifiers().apply {
+                actionName = "activate"
+            }
+            payload = JacksonUtils.jsonNode("{}") as ObjectNode
+        }
+        val bluePrintRuntime = mockk<DefaultBluePrintRuntimeService>("1234")
+        componentRestconfExecutor.bluePrintRuntimeService = bluePrintRuntime
+        componentRestconfExecutor.stepName = "sample-step"
+
+        val operationInputs = hashMapOf<String, JsonNode>()
+        operationInputs[BluePrintConstants.PROPERTY_CURRENT_NODE_TEMPLATE] = "activate-restconf".asJsonPrimitive()
+        operationInputs[BluePrintConstants.PROPERTY_CURRENT_INTERFACE] = "interfaceName".asJsonPrimitive()
+        operationInputs[BluePrintConstants.PROPERTY_CURRENT_OPERATION] = "operationName".asJsonPrimitive()
+        operationInputs[ComponentRestconfExecutor.SCRIPT_TYPE] = BluePrintConstants.SCRIPT_INTERNAL.asJsonPrimitive()
+        operationInputs[ComponentRestconfExecutor.SCRIPT_CLASS_REFERENCE] = "InternalSimpleRestconf_cba\$TestRestconfConfigure".asJsonPrimitive()
 
+        every { bluePrintRuntime.get("sample-step-step-inputs") } returns operationInputs.asJsonNode()
+        every {
+            bluePrintRuntime.resolveNodeTemplateInterfaceOperationInputs("activate-restconf",
+                    "interfaceName", "operationName")
+        } returns operationInputs
 
+        val operationOutputs = hashMapOf<String, JsonNode>()
+        every {
+            bluePrintRuntime.resolveNodeTemplateInterfaceOperationOutputs("activate-restconf",
+                    "interfaceName", "operationName")
+        } returns operationOutputs
+        every { bluePrintRuntime.put("sample-step-step-outputs", any()) } returns Unit
+
+        componentRestconfExecutor.apply(executionServiceInput)
+    }
 }
\ No newline at end of file
index 5fe7641..6b16a7f 100755 (executable)
@@ -46,6 +46,7 @@
         <h2database.version>1.4.197</h2database.version>
         <onap.logger.slf4j>1.2.2</onap.logger.slf4j>
         <powermock.version>1.7.4</powermock.version>
+        <mockk.version>1.9</mockk.version>
     </properties>
     <dependencyManagement>
         <dependencies>
                 <scope>test</scope>
             </dependency>
             <!-- Test Dependency -->
+            <dependency>
+                <groupId>io.mockk</groupId>
+                <artifactId>mockk</artifactId>
+                <version>${mockk.version}</version>
+                <scope>test</scope>
+            </dependency>
             <dependency>
                 <groupId>org.powermock</groupId>
                 <artifactId>powermock-api-mockito2</artifactId>
                 <version>${kotlin.version}</version>
                 <scope>test</scope>
             </dependency>
+            <dependency>
+                <groupId>org.jetbrains.kotlinx</groupId>
+                <artifactId>kotlinx-coroutines-test</artifactId>
+                <version>${kotlin.couroutines.version}</version>
+                <scope>test</scope>
+            </dependency>
             <dependency>
                 <groupId>io.grpc</groupId>
                 <artifactId>grpc-testing</artifactId>
index 0c8209f..8724a9f 100644 (file)
@@ -46,6 +46,10 @@ object BluePrintConstants {
     const val DATA_TYPE_MAP: String = "map"
     const val DATA_TYPE_JSON: String = "json"
 
+    const val SCRIPT_KOTLIN = "kotlin"
+    const val SCRIPT_JYTHON = "jython"
+    const val SCRIPT_INTERNAL = "internal"
+
     const val USER_SYSTEM: String = "System"
 
     const val PATH_DIVIDER: String = "/"
index 124c167..ac68255 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright © 2017-2018 AT&T Intellectual Property.
+ * Modifications Copyright © 2018 IBM.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,8 +19,10 @@ package org.onap.ccsdk.apps.controllerblueprints.core.interfaces
 
 import org.onap.ccsdk.apps.controllerblueprints.core.service.BluePrintContext
 
-interface BluePrintScriptsService{
+interface BluePrintScriptsService {
 
     fun <T> scriptInstance(blueprintContext: BluePrintContext, scriptClassName: String,
                            reCompile: Boolean): T
+
+    fun <T> scriptInstance(scriptClassName: String): T
 }
\ No newline at end of file
index ce9553c..572724d 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright © 2017-2018 AT&T Intellectual Property.
+ * Modifications Copyright © 2018 IBM.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -65,40 +66,45 @@ open class BluePrintsCompilerProxy(private val hostConfiguration: ScriptingHostC
 
                 val rootDisposable = Disposer.newDisposable()
 
-                val compilerConfiguration = CompilerConfiguration().apply {
+                try {
 
-                    put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector)
-                    put(CommonConfigurationKeys.MODULE_NAME, blueprintSourceCode.moduleName)
-                    put(JVMConfigurationKeys.OUTPUT_JAR, compiledJarFile)
-                    put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, false)
+                    val compilerConfiguration = CompilerConfiguration().apply {
 
-                    // Load Current Class loader to Compilation Class loader
-                    val currentClassLoader = classpathFromClasspathProperty()
-                    currentClassLoader?.forEach {
-                        add(CLIConfigurationKeys.CONTENT_ROOTS, JvmClasspathRoot(it))
-                    }
+                        put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector)
+                        put(CommonConfigurationKeys.MODULE_NAME, blueprintSourceCode.moduleName)
+                        put(JVMConfigurationKeys.OUTPUT_JAR, compiledJarFile)
+                        put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, false)
 
-                    // Add all Kotlin Sources
-                    addKotlinSourceRoots(blueprintSourceCode.blueprintKotlinSources)
+                        // Load Current Class loader to Compilation Class loader
+                        val currentClassLoader = classpathFromClasspathProperty()
+                        currentClassLoader?.forEach {
+                            add(CLIConfigurationKeys.CONTENT_ROOTS, JvmClasspathRoot(it))
+                        }
 
-                    languageVersionSettings = LanguageVersionSettingsImpl(
-                            LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE, mapOf(AnalysisFlags.skipMetadataVersionCheck to true)
-                    )
-                }
+                        // Add all Kotlin Sources
+                        addKotlinSourceRoots(blueprintSourceCode.blueprintKotlinSources)
 
-                //log.info("Executing with compiler configuration : $compilerConfiguration")
+                        languageVersionSettings = LanguageVersionSettingsImpl(
+                                LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE, mapOf(AnalysisFlags.skipMetadataVersionCheck to true)
+                        )
+                    }
 
-                environment = KotlinCoreEnvironment.createForProduction(rootDisposable, compilerConfiguration,
-                        EnvironmentConfigFiles.JVM_CONFIG_FILES)
+                    //log.info("Executing with compiler configuration : $compilerConfiguration")
 
-                // Compile Kotlin Sources
-                val compiled = KotlinToJVMBytecodeCompiler.compileBunchOfSources(environment)
+                    environment = KotlinCoreEnvironment.createForProduction(rootDisposable, compilerConfiguration,
+                            EnvironmentConfigFiles.JVM_CONFIG_FILES)
 
-                val analyzerWithCompilerReport = AnalyzerWithCompilerReport(messageCollector,
-                        environment.configuration.languageVersionSettings)
+                    // Compile Kotlin Sources
+                    val compiled = KotlinToJVMBytecodeCompiler.compileBunchOfSources(environment)
 
-                if (analyzerWithCompilerReport.hasErrors()) {
-                    return ResultWithDiagnostics.Failure(messageCollector.diagnostics)
+                    val analyzerWithCompilerReport = AnalyzerWithCompilerReport(messageCollector,
+                            environment.configuration.languageVersionSettings)
+
+                    if (analyzerWithCompilerReport.hasErrors()) {
+                        return ResultWithDiagnostics.Failure(messageCollector.diagnostics)
+                    }
+                } finally {
+                    rootDisposable.dispose()
                 }
             }
 
index e136552..4840fc9 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright © 2017-2018 AT&T Intellectual Property.
+ * Modifications Copyright © 2018 IBM.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -21,6 +22,7 @@ import org.onap.ccsdk.apps.controllerblueprints.core.interfaces.BluePrintScripts
 import org.onap.ccsdk.apps.controllerblueprints.core.service.BluePrintContext
 import org.springframework.stereotype.Service
 import java.io.File
+import java.util.*
 import kotlin.script.experimental.api.ResultValue
 import kotlin.script.experimental.api.resultOrNull
 import kotlin.script.experimental.jvmhost.createJvmCompilationConfigurationFromTemplate
@@ -57,6 +59,11 @@ open class BluePrintScriptsServiceImpl : BluePrintScriptsService {
         return returnValue?.value!! as T
     }
 
+    override fun <T> scriptInstance(scriptClassName: String): T {
+        val args = ArrayList<Any?>()
+        return Thread.currentThread().contextClassLoader.loadClass(scriptClassName).constructors
+                .single().newInstance(*args.toArray()) as T
+    }
 }
 
 fun getBluePrintScriptsJarName(blueprintContext: BluePrintContext): String {