Add grpc execution service 36/85236/3
authorBrinda Santh <brindasanth@in.ibm.com>
Wed, 10 Apr 2019 22:14:44 +0000 (18:14 -0400)
committerAlexis de Talhouët <adetalhouet89@gmail.com>
Tue, 16 Apr 2019 14:38:50 +0000 (10:38 -0400)
Change-Id: Icfbd9cef8775f2f72329ec726309d14377b9188a
Issue-ID: CCSDK-1215
Signed-off-by: Brinda Santh <brindasanth@in.ibm.com>
17 files changed:
components/model-catalog/proto-definition/proto/CommandExecutor.proto
ms/blueprintsprocessor/application/src/main/resources/application-dev.properties
ms/blueprintsprocessor/application/src/main/resources/application.properties
ms/blueprintsprocessor/application/src/test/resources/application.properties
ms/blueprintsprocessor/functions/python-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/python/executor/ComponentRemotePythonExecutor.kt
ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/BluePrintGrpcLibConfiguration.kt
ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/BluePrintGrpcLibData.kt
ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/BasicAuthGrpcClientService.kt [new file with mode: 0644]
ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/BluePrintGrpcClientService.kt [new file with mode: 0644]
ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/BluePrintGrpcLibPropertyService.kt
ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/TokenAuthGrpcClientService.kt [new file with mode: 0644]
ms/blueprintsprocessor/modules/commons/processor-core/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/core/api/data/BlueprintRemoteProcessorData.kt
ms/blueprintsprocessor/modules/services/execution-service/pom.xml
ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/ExecutionServiceConfiguration.kt [new file with mode: 0644]
ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/RemoteScriptExecutionService.kt
ms/blueprintsprocessor/parent/pom.xml
ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/CustomFunctions.kt

index e95e555..f488cc1 100644 (file)
@@ -6,27 +6,30 @@ package org.onap.ccsdk.cds.controllerblueprints.command.api;
 
 message ExecutionInput {
     string requestId = 1;
+    // Optional Id used to correlate multiple requests so that it can identify previous request information.
+    string correlationId = 2;
     // Optional Blueprint Information used to identify CBA content information in shared file structure environment.
-    Identifiers identifiers = 2;
-    ScriptType scriptType = 3;
+    Identifiers identifiers = 3;
+    ScriptType scriptType = 4;
     // Actual Command to Execute in Scripting Environment
-    string command = 4;
-    int32 timeOut = 5;
+    string command = 5;
+    int32 timeOut = 6;
     // Extra Dynamic Properties for Command processing in JSON format
-    google.protobuf.Struct properties = 6;
+    google.protobuf.Struct properties = 7;
     // Request Time Stamp
-    google.protobuf.Timestamp timestamp = 7;
+    google.protobuf.Timestamp timestamp = 8;
 }
 
 message PrepareEnvInput {
     Identifiers identifiers = 1;
+    string requestId = 2;
     // Optional Id used to correlate multiple requests so that it can identify previous request information.
-    string correlationId = 2;
-    ScriptType scriptType = 3;
-    repeated string packages = 4;
-    int32 timeOut = 5;
-    google.protobuf.Struct properties = 6;
-    google.protobuf.Timestamp timestamp = 7;
+    string correlationId = 3;
+    ScriptType scriptType = 4;
+    repeated string packages = 5;
+    int32 timeOut = 6;
+    google.protobuf.Struct properties = 7;
+    google.protobuf.Timestamp timestamp = 8;
 }
 
 message Identifiers {
index 0e2cdf9..2b90998 100755 (executable)
@@ -47,4 +47,10 @@ blueprintsprocessor.restconfEnabled=true
 blueprintsprocessor.restclient.sdncodl.type=basic-auth\r
 blueprintsprocessor.restclient.sdncodl.url=http://localhost:8282/\r
 blueprintsprocessor.restclient.sdncodl.username=admin\r
-blueprintsprocessor.restclient.sdncodl.password=Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U
\ No newline at end of file
+blueprintsprocessor.restclient.sdncodl.password=Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U
+
+# Executor Options
+blueprintprocessor.resourceResolution.enabled=true
+blueprintprocessor.netconfExecutor.enabled=true
+blueprintprocessor.restConfExecutor.enabled=true
+blueprintprocessor.remoteScriptCommand.enabled=false
\ No newline at end of file
index b34609c..57bfdd5 100755 (executable)
@@ -49,3 +49,9 @@ blueprintsprocessor.restclient.sdncodl.type=basic-auth
 blueprintsprocessor.restclient.sdncodl.url=http://sdnc:8282/
 blueprintsprocessor.restclient.sdncodl.username=admin
 blueprintsprocessor.restclient.sdncodl.password=Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U
+
+# Executor Options
+blueprintprocessor.resourceResolution.enabled=true
+blueprintprocessor.netconfExecutor.enabled=true
+blueprintprocessor.restConfExecutor.enabled=true
+blueprintprocessor.remoteScriptCommand.enabled=false
\ No newline at end of file
index 3078505..7e462f2 100644 (file)
@@ -37,5 +37,11 @@ blueprintsprocessor.db.primary.hibernateDialect=org.hibernate.dialect.H2Dialect
 blueprints.processor.functions.python.executor.executionPath=/opt/app/onap/scripts/jython/ccsdk_blueprints
 blueprints.processor.functions.python.executor.modulePaths=/opt/app/onap/scripts/jython/ccsdk_blueprints
 
-security.user.password: {bcrypt}$2a$10$duaUzVUVW0YPQCSIbGEkQOXwafZGwQ/b32/Ys4R1iwSSawFgz7QNu
-security.user.name: ccsdkapps
+security.user.password:{bcrypt}$2a$10$duaUzVUVW0YPQCSIbGEkQOXwafZGwQ/b32/Ys4R1iwSSawFgz7QNu
+security.user.name:ccsdkapps
+
+# Executor Options
+blueprintprocessor.resourceResolution.enabled=true
+blueprintprocessor.netconfExecutor.enabled=true
+blueprintprocessor.restConfExecutor.enabled=true
+blueprintprocessor.remoteScriptCommand.enabled=false
index d34dbb7..31eb38c 100644 (file)
@@ -18,6 +18,7 @@ package org.onap.ccsdk.cds.blueprintsprocessor.functions.python.executor
 
 import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.*
 import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.AbstractComponentFunction
+import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.ExecutionServiceConstant
 import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.RemoteScriptExecutionService
 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException
 import org.onap.ccsdk.cds.controllerblueprints.core.checkFileExists
@@ -26,16 +27,17 @@ import org.onap.ccsdk.cds.controllerblueprints.core.data.OperationAssignment
 import org.onap.ccsdk.cds.controllerblueprints.core.normalizedFile
 import org.slf4j.LoggerFactory
 import org.springframework.beans.factory.config.ConfigurableBeanFactory
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean
 import org.springframework.context.annotation.Scope
 import org.springframework.stereotype.Component
 
-
+@ConditionalOnBean(name = [ExecutionServiceConstant.SERVICE_GRPC_REMOTE_SCRIPT_EXECUTION])
 @Component("component-remote-python-executor")
 @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
 open class ComponentRemotePythonExecutor(private val remoteScriptExecutionService: RemoteScriptExecutionService)
     : AbstractComponentFunction() {
 
-    private val log = LoggerFactory.getLogger(ComponentRemotePythonExecutor::class.java)
+    private val log = LoggerFactory.getLogger(ComponentRemotePythonExecutor::class.java)!!
 
     companion object {
         const val INPUT_ENDPOINT_SELECTOR = "endpoint-selector"
@@ -63,34 +65,44 @@ open class ComponentRemotePythonExecutor(private val remoteScriptExecutionServic
         val pythonScript = normalizedFile(bluePrintContext.rootPath, artifactDefinition.file)
 
         checkFileExists(pythonScript) { "python script(${pythonScript.absolutePath}) doesn't exists" }
-        //TODO ("Get the ENDPOINT SELECTOR and resolve the Remote Server")
+
         val endPointSelector = getOperationInput(INPUT_ENDPOINT_SELECTOR)
         val dynamicProperties = getOperationInput(INPUT_DYNAMIC_PROPERTIES)
 
         // TODO("Python execution command and Resolve some expressions with dynamic properties")
         val scriptCommand: String = "python ${pythonScript.absolutePath}"
 
-        val packages = operationAssignment.implementation?.dependencies
-        // If dependencies are defined, then install in remote server
-        if (packages != null && !packages.isEmpty()) {
-            val prepareEnvInput = PrepareRemoteEnvInput(requestId = processId,
+        val dependencies = operationAssignment.implementation?.dependencies
+
+        try {
+            // Open GRPC Connection
+            remoteScriptExecutionService.init(endPointSelector.asText())
+
+            // If dependencies are defined, then install in remote server
+            if (dependencies != null && !dependencies.isEmpty()) {
+                val prepareEnvInput = PrepareRemoteEnvInput(
+                    requestId = processId,
+                    remoteIdentifier = RemoteIdentifier(blueprintName = blueprintName, blueprintVersion = blueprintVersion),
                     remoteScriptType = RemoteScriptType.PYTHON,
-                    packages = arrayListOf()
-            )
-            val prepareEnvOutput = remoteScriptExecutionService.prepareEnv(prepareEnvInput)
-            checkNotNull(prepareEnvOutput) {
-                "failed to get prepare remote env response for requestId(${prepareEnvInput.requestId})"
+                    packages = dependencies
+                )
+                val prepareEnvOutput = remoteScriptExecutionService.prepareEnv(prepareEnvInput)
+                checkNotNull(prepareEnvOutput) {
+                    "failed to get prepare remote env response for requestId(${prepareEnvInput.requestId})"
+                }
             }
-        }
 
-        val remoteExecutionInput = RemoteScriptExecutionInput(
-                requestId = processId,
-                remoteIdentifier = RemoteIdentifier(blueprintName = blueprintName, blueprintVersion = blueprintVersion),
-                remoteScriptType = RemoteScriptType.PYTHON,
-                command = scriptCommand)
-        val remoteExecutionOutput = remoteScriptExecutionService.executeCommand(remoteExecutionInput)
-        checkNotNull(remoteExecutionOutput) {
-            "failed to get prepare remote command response for requestId(${remoteExecutionOutput.requestId})"
+            val remoteExecutionInput = RemoteScriptExecutionInput(
+                    requestId = processId,
+                    remoteIdentifier = RemoteIdentifier(blueprintName = blueprintName, blueprintVersion = blueprintVersion),
+                    remoteScriptType = RemoteScriptType.PYTHON,
+                    command = scriptCommand)
+            val remoteExecutionOutput = remoteScriptExecutionService.executeCommand(remoteExecutionInput)
+            checkNotNull(remoteExecutionOutput) {
+                "failed to get prepare remote command response for requestId(${remoteExecutionOutput.requestId})"
+            }
+        } finally {
+            remoteScriptExecutionService.close()
         }
     }
 
index 3fbc427..1bef3a0 100644 (file)
@@ -26,6 +26,7 @@ open class BluePrintGrpcLibConfiguration
 class GRPCLibConstants {
     companion object {
         const val SERVICE_BLUEPRINT_GRPC_LIB_PROPERTY = "blueprint-grpc-lib-property-service"
+        const val TYPE_TOKEN_AUTH = "token-auth"
         const val TYPE_BASIC_AUTH = "basic-auth"
     }
 }
\ No newline at end of file
index 1e082b4..76e60bd 100644 (file)
@@ -22,7 +22,11 @@ open class GrpcClientProperties {
     var port: Int = -1
 }
 
+open class TokenAuthGrpcClientProperties : GrpcClientProperties() {
+    lateinit var token: String
+}
+
 open class BasicAuthGrpcClientProperties : GrpcClientProperties() {
     lateinit var username: String
     lateinit var password: String
-}
+}
\ No newline at end of file
diff --git a/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/BasicAuthGrpcClientService.kt b/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/BasicAuthGrpcClientService.kt
new file mode 100644 (file)
index 0000000..a175d8b
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ *  Copyright © 2019 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.
+ */
+
+package org.onap.ccsdk.cds.blueprintsprocessor.grpc.service
+
+import io.grpc.ManagedChannel
+import io.grpc.internal.DnsNameResolverProvider
+import io.grpc.internal.PickFirstLoadBalancerProvider
+import io.grpc.netty.NettyChannelBuilder
+import org.onap.ccsdk.cds.blueprintsprocessor.grpc.BasicAuthGrpcClientProperties
+
+
+open class BasicAuthGrpcClientService(private val basicAuthGrpcClientProperties: BasicAuthGrpcClientProperties)
+    : BluePrintGrpcClientService {
+
+    override suspend fun channel(): ManagedChannel {
+        val managedChannel = NettyChannelBuilder
+                .forAddress(basicAuthGrpcClientProperties.host, basicAuthGrpcClientProperties.port)
+                .nameResolverFactory(DnsNameResolverProvider())
+                .loadBalancerFactory(PickFirstLoadBalancerProvider())
+                // .intercept(BasicAuthClientInterceptor(basicAuthGrpcClientProperties)).usePlaintext()
+                .build()
+        return managedChannel
+    }
+
+
+}
diff --git a/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/BluePrintGrpcClientService.kt b/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/BluePrintGrpcClientService.kt
new file mode 100644 (file)
index 0000000..016c050
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ *  Copyright © 2019 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.
+ */
+
+package org.onap.ccsdk.cds.blueprintsprocessor.grpc.service
+
+import io.grpc.ManagedChannel
+
+interface BluePrintGrpcClientService {
+    suspend fun channel(): ManagedChannel
+}
\ No newline at end of file
index 7510d1d..088533a 100644 (file)
@@ -21,6 +21,7 @@ import org.onap.ccsdk.cds.blueprintsprocessor.core.BluePrintProperties
 import org.onap.ccsdk.cds.blueprintsprocessor.grpc.BasicAuthGrpcClientProperties
 import org.onap.ccsdk.cds.blueprintsprocessor.grpc.GRPCLibConstants
 import org.onap.ccsdk.cds.blueprintsprocessor.grpc.GrpcClientProperties
+import org.onap.ccsdk.cds.blueprintsprocessor.grpc.TokenAuthGrpcClientProperties
 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException
 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
 import org.springframework.stereotype.Service
@@ -28,9 +29,24 @@ import org.springframework.stereotype.Service
 @Service(GRPCLibConstants.SERVICE_BLUEPRINT_GRPC_LIB_PROPERTY)
 open class BluePrintGrpcLibPropertyService(private var bluePrintProperties: BluePrintProperties) {
 
+    fun blueprintGrpcClientService(jsonNode: JsonNode): BluePrintGrpcClientService {
+        val restClientProperties = grpcClientProperties(jsonNode)
+        return blueprintGrpcClientService(restClientProperties)
+    }
+
+    fun blueprintGrpcClientService(selector: String): BluePrintGrpcClientService {
+        val prefix = "blueprintsprocessor.grpcclient.$selector"
+        val restClientProperties = grpcClientProperties(prefix)
+        return blueprintGrpcClientService(restClientProperties)
+    }
+
+
     fun grpcClientProperties(jsonNode: JsonNode): GrpcClientProperties {
         val type = jsonNode.get("type").textValue()
         return when (type) {
+            GRPCLibConstants.TYPE_TOKEN_AUTH -> {
+                JacksonUtils.readValue(jsonNode, TokenAuthGrpcClientProperties::class.java)!!
+            }
             GRPCLibConstants.TYPE_BASIC_AUTH -> {
                 JacksonUtils.readValue(jsonNode, BasicAuthGrpcClientProperties::class.java)!!
             }
@@ -44,6 +60,9 @@ open class BluePrintGrpcLibPropertyService(private var bluePrintProperties: Blue
         val type = bluePrintProperties.propertyBeanType(
                 "$prefix.type", String::class.java)
         return when (type) {
+            GRPCLibConstants.TYPE_TOKEN_AUTH -> {
+                tokenAuthGrpcClientProperties(prefix)
+            }
             GRPCLibConstants.TYPE_BASIC_AUTH -> {
                 basicAuthGrpcClientProperties(prefix)
             }
@@ -54,6 +73,25 @@ open class BluePrintGrpcLibPropertyService(private var bluePrintProperties: Blue
         }
     }
 
+    private fun blueprintGrpcClientService(grpcClientProperties: GrpcClientProperties):
+            BluePrintGrpcClientService {
+        when (grpcClientProperties) {
+            is TokenAuthGrpcClientProperties -> {
+                return TokenAuthGrpcClientService(grpcClientProperties)
+            }
+            is BasicAuthGrpcClientProperties -> {
+                return BasicAuthGrpcClientService(grpcClientProperties)
+            }
+            else -> {
+                throw BluePrintProcessorException("couldn't get grpc service for type(${grpcClientProperties.type})")
+            }
+        }
+    }
+
+    private fun tokenAuthGrpcClientProperties(prefix: String): TokenAuthGrpcClientProperties {
+        return bluePrintProperties.propertyBeanType(prefix, TokenAuthGrpcClientProperties::class.java)
+    }
+
     private fun basicAuthGrpcClientProperties(prefix: String): BasicAuthGrpcClientProperties {
         return bluePrintProperties.propertyBeanType(prefix, BasicAuthGrpcClientProperties::class.java)
     }
diff --git a/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/TokenAuthGrpcClientService.kt b/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/TokenAuthGrpcClientService.kt
new file mode 100644 (file)
index 0000000..dbff842
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ *  Copyright © 2019 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.
+ */
+
+package org.onap.ccsdk.cds.blueprintsprocessor.grpc.service
+
+import io.grpc.*
+import io.grpc.internal.DnsNameResolverProvider
+import io.grpc.internal.PickFirstLoadBalancerProvider
+import io.grpc.netty.NettyChannelBuilder
+import org.onap.ccsdk.cds.blueprintsprocessor.grpc.TokenAuthGrpcClientProperties
+
+class TokenAuthGrpcClientService(private val tokenAuthGrpcClientProperties: TokenAuthGrpcClientProperties)
+    : BluePrintGrpcClientService {
+
+    override suspend fun channel(): ManagedChannel {
+        val managedChannel = NettyChannelBuilder
+                .forAddress(tokenAuthGrpcClientProperties.host, tokenAuthGrpcClientProperties.port)
+                .nameResolverFactory(DnsNameResolverProvider())
+                .loadBalancerFactory(PickFirstLoadBalancerProvider())
+                .intercept(TokenAuthClientInterceptor(tokenAuthGrpcClientProperties)).usePlaintext().build()
+        return managedChannel
+    }
+}
+
+class TokenAuthClientInterceptor(private val tokenAuthGrpcClientProperties: TokenAuthGrpcClientProperties) : ClientInterceptor {
+
+    override fun <ReqT, RespT> interceptCall(method: MethodDescriptor<ReqT, RespT>,
+                                             callOptions: CallOptions, channel: Channel): ClientCall<ReqT, RespT> {
+
+        val authHeader = Metadata.Key.of("Authorization", Metadata.ASCII_STRING_MARSHALLER)
+
+        return object : ForwardingClientCall
+        .SimpleForwardingClientCall<ReqT, RespT>(channel.newCall(method, callOptions)) {
+
+            override fun start(responseListener: Listener<RespT>, headers: Metadata) {
+                headers.put(authHeader, tokenAuthGrpcClientProperties.token)
+                super.start(responseListener, headers)
+            }
+        }
+    }
+}
index 90eb933..da952c0 100644 (file)
 package org.onap.ccsdk.cds.blueprintsprocessor.core.api.data
 
 import com.fasterxml.jackson.databind.JsonNode
+import java.util.*
 
 enum class RemoteScriptType {
     PYTHON, ANSIBLE, KOTLIN, SH
 }
 
-data class RemoteIdentifier(var blueprintName: String? = null,
-                            var blueprintVersion: String? = null)
+enum class StatusType {
+    SUCCESS, FAILURE
+}
+
+data class RemoteIdentifier(var blueprintName: String,
+                            var blueprintVersion: String)
 
 
 data class RemoteScriptExecutionInput(var requestId: String,
+                                      var correlationId: String? = null,
                                       var remoteIdentifier: RemoteIdentifier? = null,
                                       var remoteScriptType: RemoteScriptType,
                                       var command: String,
@@ -35,9 +41,14 @@ data class RemoteScriptExecutionInput(var requestId: String,
 )
 
 
-data class RemoteScriptExecutionOutput(var requestId: String, var response: String)
+data class RemoteScriptExecutionOutput(var requestId: String,
+                                       var response: String,
+                                       var status: StatusType = StatusType.SUCCESS,
+                                       var timestamp: Date = Date())
 
 data class PrepareRemoteEnvInput(var requestId: String,
+                                 var correlationId: String? = null,
+                                 var remoteIdentifier: RemoteIdentifier? = null,
                                  var remoteScriptType: RemoteScriptType,
                                  var packages: MutableList<String>?,
                                  var timeOut: Long = 120,
index 9ce5292..d366f74 100644 (file)
             <groupId>org.onap.ccsdk.cds.blueprintsprocessor</groupId>
             <artifactId>rest-lib</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.onap.ccsdk.cds.blueprintsprocessor</groupId>
+            <artifactId>grpc-lib</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.onap.ccsdk.cds.controllerblueprints</groupId>
             <artifactId>resource-dict</artifactId>
diff --git a/ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/ExecutionServiceConfiguration.kt b/ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/ExecutionServiceConfiguration.kt
new file mode 100644 (file)
index 0000000..806c330
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ *  Copyright © 2019 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.
+ */
+
+package org.onap.ccsdk.cds.blueprintsprocessor.services.execution
+
+import org.springframework.context.annotation.ComponentScan
+import org.springframework.context.annotation.Configuration
+
+@Configuration
+@ComponentScan
+open class ExecutionServiceConfiguration
+
+
+object ExecutionServiceConstant {
+    const val SERVICE_GRPC_REMOTE_SCRIPT_EXECUTION = "grpc-remote-script-execution-service"
+}
\ No newline at end of file
index 5d279ce..46969b1 100644 (file)
 
 package org.onap.ccsdk.cds.blueprintsprocessor.services.execution
 
-import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.PrepareRemoteEnvInput
-import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.RemoteScriptExecutionInput
-import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.RemoteScriptExecutionOutput
+import com.fasterxml.jackson.databind.JsonNode
+import com.google.protobuf.Struct
+import com.google.protobuf.Timestamp
+import com.google.protobuf.util.JsonFormat
+import io.grpc.ManagedChannel
+import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.*
+import org.onap.ccsdk.cds.blueprintsprocessor.grpc.service.BluePrintGrpcLibPropertyService
+import org.onap.ccsdk.cds.controllerblueprints.command.api.*
+import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
+import org.slf4j.LoggerFactory
+import org.springframework.beans.factory.config.ConfigurableBeanFactory
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
+import org.springframework.context.annotation.Scope
+import org.springframework.stereotype.Service
 
 
 interface RemoteScriptExecutionService {
+    suspend fun init(selector: String)
     suspend fun prepareEnv(prepareEnvInput: PrepareRemoteEnvInput): RemoteScriptExecutionOutput
     suspend fun executeCommand(remoteExecutionInput: RemoteScriptExecutionInput): RemoteScriptExecutionOutput
+    suspend fun close()
+}
+
+@Service(ExecutionServiceConstant.SERVICE_GRPC_REMOTE_SCRIPT_EXECUTION)
+@ConditionalOnProperty(prefix = "blueprintprocessor.remoteScriptCommand", name = arrayOf("enabled"),
+    havingValue = "true", matchIfMissing = false)
+@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+class GrpcRemoteScriptExecutionService(private val bluePrintGrpcLibPropertyService: BluePrintGrpcLibPropertyService)
+    : RemoteScriptExecutionService {
+
+    private val log = LoggerFactory.getLogger(GrpcRemoteScriptExecutionService::class.java)!!
+
+    lateinit var channel: ManagedChannel
+    lateinit var commandExecutorServiceGrpc: CommandExecutorServiceGrpc.CommandExecutorServiceFutureStub
+
+    override suspend fun init(selector: String) {
+        // Get the GRPC Client Service based on selector
+        val grpcClientService = bluePrintGrpcLibPropertyService.blueprintGrpcClientService(selector)
+        // Get the GRPC Channel
+        channel = grpcClientService.channel()
+        // Create Non Blocking Stub
+        commandExecutorServiceGrpc = CommandExecutorServiceGrpc.newFutureStub(channel)
+
+        checkNotNull(commandExecutorServiceGrpc) {
+            "failed to create command executor grpc client for selector($selector)"
+        }
+    }
+
+    override suspend fun prepareEnv(prepareEnvInput: PrepareRemoteEnvInput)
+            : RemoteScriptExecutionOutput {
+        val grpResponse = commandExecutorServiceGrpc.prepareEnv(prepareEnvInput.asGrpcData()).get()
+
+        checkNotNull(grpResponse.status) {
+            "failed to get GRPC prepare env response status for requestId($prepareEnvInput.requestId)"
+        }
+
+        val remoteScriptExecutionOutput = grpResponse.asJavaData()
+        log.debug("Received prepare env response from command server for requestId($prepareEnvInput.requestId)")
+
+        return remoteScriptExecutionOutput
+    }
+
+    override suspend fun executeCommand(remoteExecutionInput: RemoteScriptExecutionInput)
+            : RemoteScriptExecutionOutput {
+
+        val grpResponse = commandExecutorServiceGrpc.executeCommand(remoteExecutionInput.asGrpcData()).get()
+
+        checkNotNull(grpResponse.status) {
+            "failed to get GRPC response status for requestId($remoteExecutionInput.requestId)"
+        }
+
+        val remoteScriptExecutionOutput = grpResponse.asJavaData()
+        log.debug("Received response from command server for requestId($remoteExecutionInput.requestId)")
+
+        return remoteScriptExecutionOutput
+    }
+
+    override suspend fun close() {
+        // TODO('Verify the correct way to close the client conncetion")
+        if (channel != null) {
+            channel.shutdownNow()
+        }
+    }
+
+
+    fun PrepareRemoteEnvInput.asGrpcData(): PrepareEnvInput {
+        val correlationId = this.correlationId ?: this.requestId
+
+        return PrepareEnvInput.newBuilder()
+            .setIdentifiers(this.remoteIdentifier.asGrpcData())
+            .setRequestId(this.requestId)
+            .setCorrelationId(correlationId)
+            .setScriptType(ScriptType.valueOf(this.remoteScriptType.name))
+            .setTimeOut(this.timeOut.toInt())
+            .addAllPackages(this.packages)
+            .setProperties(this.properties.asGrpcData())
+            .build()
+    }
+
+    fun RemoteScriptExecutionInput.asGrpcData(): ExecutionInput {
+        val correlationId = this.correlationId ?: this.requestId
+        return ExecutionInput.newBuilder()
+            .setRequestId(this.requestId)
+            .setCorrelationId(correlationId)
+            .setIdentifiers(this.remoteIdentifier.asGrpcData())
+            .setScriptType(ScriptType.valueOf(this.remoteScriptType.name))
+            .setCommand(this.command)
+            .setTimeOut(this.timeOut.toInt())
+            .setProperties(this.properties.asGrpcData())
+            .setTimestamp(Timestamp.getDefaultInstance())
+            .build()
+    }
+
+    fun RemoteIdentifier?.asGrpcData(): Identifiers? {
+        return if (this != null) {
+            Identifiers.newBuilder()
+                .setBlueprintName(this.blueprintName)
+                .setBlueprintVersion(this.blueprintVersion)
+                .build()
+        } else {
+            null
+        }
+    }
+
+    fun Map<String, JsonNode>.asGrpcData(): Struct {
+        val struct = Struct.newBuilder()
+        JsonFormat.parser().merge(JacksonUtils.getJson(this), struct)
+        return struct.build()
+    }
+
+    fun ExecutionOutput.asJavaData(): RemoteScriptExecutionOutput {
+        return RemoteScriptExecutionOutput(
+            requestId = this.requestId,
+            response = this.response,
+            status = StatusType.valueOf(this.status.name)
+        )
+    }
+
 }
\ No newline at end of file
index c9505cb..e690135 100755 (executable)
@@ -16,7 +16,8 @@
   ~  See the License for the specific language governing permissions and
   ~  limitations under the License.
   -->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <parent>
         <groupId>org.onap.ccsdk.cds</groupId>
                 <artifactId>dmaap-lib</artifactId>
                 <version>${project.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.onap.ccsdk.cds.blueprintsprocessor</groupId>
+                <artifactId>grpc-lib</artifactId>
+                <version>${project.version}</version>
+            </dependency>
             <dependency>
                 <groupId>org.onap.ccsdk.cds.blueprintsprocessor</groupId>
                 <artifactId>execution-service</artifactId>
index d45571c..72c2c1d 100644 (file)
@@ -97,6 +97,10 @@ fun <T : Any> Map<String, *>.castValue(key: String, valueType: KClass<T>): T {
     }
 }
 
+fun ArrayNode.asListOfString(): List<String> {
+    return JacksonUtils.getListFromJsonNode(this, String::class.java)
+}
+
 /**
  * Convert Json to map of json node, the root fields will be map keys
  */