From bc95a55c61685694a930d659bef336989a04df2f Mon Sep 17 00:00:00 2001 From: Brinda Santh Date: Wed, 10 Apr 2019 18:14:44 -0400 Subject: Add grpc execution service Change-Id: Icfbd9cef8775f2f72329ec726309d14377b9188a Issue-ID: CCSDK-1215 Signed-off-by: Brinda Santh --- .../proto-definition/proto/CommandExecutor.proto | 27 ++-- .../src/main/resources/application-dev.properties | 8 +- .../src/main/resources/application.properties | 6 + .../src/test/resources/application.properties | 10 +- .../executor/ComponentRemotePythonExecutor.kt | 54 ++++---- .../grpc/BluePrintGrpcLibConfiguration.kt | 1 + .../grpc/BluePrintGrpcLibData.kt | 6 +- .../grpc/service/BasicAuthGrpcClientService.kt | 40 ++++++ .../grpc/service/BluePrintGrpcClientService.kt | 23 ++++ .../service/BluePrintGrpcLibPropertyService.kt | 38 ++++++ .../grpc/service/TokenAuthGrpcClientService.kt | 54 ++++++++ .../core/api/data/BlueprintRemoteProcessorData.kt | 17 ++- .../modules/services/execution-service/pom.xml | 4 + .../execution/ExecutionServiceConfiguration.kt | 29 +++++ .../execution/RemoteScriptExecutionService.kt | 136 ++++++++++++++++++++- ms/blueprintsprocessor/parent/pom.xml | 8 +- .../controllerblueprints/core/CustomFunctions.kt | 4 + 17 files changed, 421 insertions(+), 44 deletions(-) create mode 100644 ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/BasicAuthGrpcClientService.kt create mode 100644 ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/BluePrintGrpcClientService.kt create mode 100644 ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/TokenAuthGrpcClientService.kt create mode 100644 ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/ExecutionServiceConfiguration.kt diff --git a/components/model-catalog/proto-definition/proto/CommandExecutor.proto b/components/model-catalog/proto-definition/proto/CommandExecutor.proto index e95e55521..f488cc1b4 100644 --- a/components/model-catalog/proto-definition/proto/CommandExecutor.proto +++ b/components/model-catalog/proto-definition/proto/CommandExecutor.proto @@ -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 { diff --git a/ms/blueprintsprocessor/application/src/main/resources/application-dev.properties b/ms/blueprintsprocessor/application/src/main/resources/application-dev.properties index 0e2cdf9de..2b90998b1 100755 --- a/ms/blueprintsprocessor/application/src/main/resources/application-dev.properties +++ b/ms/blueprintsprocessor/application/src/main/resources/application-dev.properties @@ -47,4 +47,10 @@ blueprintsprocessor.restconfEnabled=true blueprintsprocessor.restclient.sdncodl.type=basic-auth blueprintsprocessor.restclient.sdncodl.url=http://localhost:8282/ blueprintsprocessor.restclient.sdncodl.username=admin -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 diff --git a/ms/blueprintsprocessor/application/src/main/resources/application.properties b/ms/blueprintsprocessor/application/src/main/resources/application.properties index b34609cd1..57bfdd5d2 100755 --- a/ms/blueprintsprocessor/application/src/main/resources/application.properties +++ b/ms/blueprintsprocessor/application/src/main/resources/application.properties @@ -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 diff --git a/ms/blueprintsprocessor/application/src/test/resources/application.properties b/ms/blueprintsprocessor/application/src/test/resources/application.properties index 307850547..7e462f25d 100644 --- a/ms/blueprintsprocessor/application/src/test/resources/application.properties +++ b/ms/blueprintsprocessor/application/src/test/resources/application.properties @@ -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 diff --git a/ms/blueprintsprocessor/functions/python-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/python/executor/ComponentRemotePythonExecutor.kt b/ms/blueprintsprocessor/functions/python-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/python/executor/ComponentRemotePythonExecutor.kt index d34dbb7e9..31eb38ca4 100644 --- a/ms/blueprintsprocessor/functions/python-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/python/executor/ComponentRemotePythonExecutor.kt +++ b/ms/blueprintsprocessor/functions/python-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/python/executor/ComponentRemotePythonExecutor.kt @@ -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() } } diff --git a/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/BluePrintGrpcLibConfiguration.kt b/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/BluePrintGrpcLibConfiguration.kt index 3fbc42742..1bef3a0f2 100644 --- a/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/BluePrintGrpcLibConfiguration.kt +++ b/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/BluePrintGrpcLibConfiguration.kt @@ -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 diff --git a/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/BluePrintGrpcLibData.kt b/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/BluePrintGrpcLibData.kt index 1e082b408..76e60bd0d 100644 --- a/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/BluePrintGrpcLibData.kt +++ b/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/BluePrintGrpcLibData.kt @@ -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 index 000000000..a175d8b3a --- /dev/null +++ b/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/BasicAuthGrpcClientService.kt @@ -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 index 000000000..016c05035 --- /dev/null +++ b/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/BluePrintGrpcClientService.kt @@ -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 diff --git a/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/BluePrintGrpcLibPropertyService.kt b/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/BluePrintGrpcLibPropertyService.kt index 7510d1d96..088533a71 100644 --- a/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/BluePrintGrpcLibPropertyService.kt +++ b/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/BluePrintGrpcLibPropertyService.kt @@ -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 index 000000000..dbff84211 --- /dev/null +++ b/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/TokenAuthGrpcClientService.kt @@ -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 interceptCall(method: MethodDescriptor, + callOptions: CallOptions, channel: Channel): ClientCall { + + val authHeader = Metadata.Key.of("Authorization", Metadata.ASCII_STRING_MARSHALLER) + + return object : ForwardingClientCall + .SimpleForwardingClientCall(channel.newCall(method, callOptions)) { + + override fun start(responseListener: Listener, headers: Metadata) { + headers.put(authHeader, tokenAuthGrpcClientProperties.token) + super.start(responseListener, headers) + } + } + } +} diff --git a/ms/blueprintsprocessor/modules/commons/processor-core/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/core/api/data/BlueprintRemoteProcessorData.kt b/ms/blueprintsprocessor/modules/commons/processor-core/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/core/api/data/BlueprintRemoteProcessorData.kt index 90eb933f4..da952c034 100644 --- a/ms/blueprintsprocessor/modules/commons/processor-core/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/core/api/data/BlueprintRemoteProcessorData.kt +++ b/ms/blueprintsprocessor/modules/commons/processor-core/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/core/api/data/BlueprintRemoteProcessorData.kt @@ -17,16 +17,22 @@ 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?, var timeOut: Long = 120, diff --git a/ms/blueprintsprocessor/modules/services/execution-service/pom.xml b/ms/blueprintsprocessor/modules/services/execution-service/pom.xml index 9ce5292e8..d366f740d 100644 --- a/ms/blueprintsprocessor/modules/services/execution-service/pom.xml +++ b/ms/blueprintsprocessor/modules/services/execution-service/pom.xml @@ -53,6 +53,10 @@ org.onap.ccsdk.cds.blueprintsprocessor rest-lib + + org.onap.ccsdk.cds.blueprintsprocessor + grpc-lib + org.onap.ccsdk.cds.controllerblueprints resource-dict 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 index 000000000..806c33039 --- /dev/null +++ b/ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/ExecutionServiceConfiguration.kt @@ -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 diff --git a/ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/RemoteScriptExecutionService.kt b/ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/RemoteScriptExecutionService.kt index 5d279ce3f..46969b1c5 100644 --- a/ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/RemoteScriptExecutionService.kt +++ b/ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/RemoteScriptExecutionService.kt @@ -16,12 +16,142 @@ 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.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 diff --git a/ms/blueprintsprocessor/parent/pom.xml b/ms/blueprintsprocessor/parent/pom.xml index c9505cb94..e6901354a 100755 --- a/ms/blueprintsprocessor/parent/pom.xml +++ b/ms/blueprintsprocessor/parent/pom.xml @@ -16,7 +16,8 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> - + 4.0.0 org.onap.ccsdk.cds @@ -310,6 +311,11 @@ dmaap-lib ${project.version} + + org.onap.ccsdk.cds.blueprintsprocessor + grpc-lib + ${project.version} + org.onap.ccsdk.cds.blueprintsprocessor execution-service diff --git a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/CustomFunctions.kt b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/CustomFunctions.kt index d45571cdf..72c2c1df3 100644 --- a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/CustomFunctions.kt +++ b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/CustomFunctions.kt @@ -97,6 +97,10 @@ fun Map.castValue(key: String, valueType: KClass): T { } } +fun ArrayNode.asListOfString(): List { + return JacksonUtils.getListFromJsonNode(this, String::class.java) +} + /** * Convert Json to map of json node, the root fields will be map keys */ -- cgit 1.2.3-korg