2 * Copyright © 2019 IBM.
3 * Modifications Copyright © 2020 Bell Canada.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 package org.onap.ccsdk.cds.blueprintsprocessor.services.execution
20 import com.fasterxml.jackson.databind.JsonNode
21 import com.google.protobuf.Struct
22 import com.google.protobuf.Timestamp
23 import com.google.protobuf.util.JsonFormat
24 import io.grpc.ManagedChannel
25 import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.PrepareRemoteEnvInput
26 import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.RemoteIdentifier
27 import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.RemoteScriptExecutionInput
28 import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.RemoteScriptExecutionOutput
29 import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.StatusType
30 import org.onap.ccsdk.cds.blueprintsprocessor.grpc.service.BlueprintGrpcClientService
31 import org.onap.ccsdk.cds.blueprintsprocessor.grpc.service.BlueprintGrpcLibPropertyService
32 import org.onap.ccsdk.cds.controllerblueprints.command.api.CommandExecutorServiceGrpc
33 import org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionInput
34 import org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionOutput
35 import org.onap.ccsdk.cds.controllerblueprints.command.api.Identifiers
36 import org.onap.ccsdk.cds.controllerblueprints.command.api.Packages
37 import org.onap.ccsdk.cds.controllerblueprints.command.api.PrepareEnvInput
38 import org.onap.ccsdk.cds.controllerblueprints.core.jsonAsJsonType
39 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
40 import org.slf4j.LoggerFactory
41 import org.springframework.beans.factory.config.ConfigurableBeanFactory
42 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
43 import org.springframework.context.annotation.Scope
44 import org.springframework.stereotype.Service
45 import java.util.concurrent.TimeUnit
47 interface RemoteScriptExecutionService {
49 suspend fun init(selector: Any)
50 suspend fun prepareEnv(prepareEnvInput: PrepareRemoteEnvInput): RemoteScriptExecutionOutput
51 suspend fun executeCommand(remoteExecutionInput: RemoteScriptExecutionInput): RemoteScriptExecutionOutput
55 @Service(ExecutionServiceConstant.SERVICE_GRPC_REMOTE_SCRIPT_EXECUTION)
56 @ConditionalOnProperty(
57 prefix = "blueprintprocessor.remoteScriptCommand", name = arrayOf("enabled"),
58 havingValue = "true", matchIfMissing = false
60 @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
61 class GrpcRemoteScriptExecutionService(private val bluePrintGrpcLibPropertyService: BlueprintGrpcLibPropertyService) :
62 RemoteScriptExecutionService {
64 private val log = LoggerFactory.getLogger(GrpcRemoteScriptExecutionService::class.java)!!
66 private var channel: ManagedChannel? = null
67 private lateinit var commandExecutorServiceGrpc: CommandExecutorServiceGrpc.CommandExecutorServiceBlockingStub
69 override suspend fun init(selector: Any) {
70 // Get the GRPC Client Service based on selector
71 val grpcClientService: BlueprintGrpcClientService = if (selector is JsonNode) {
72 bluePrintGrpcLibPropertyService.blueprintGrpcClientService(selector)
74 bluePrintGrpcLibPropertyService.blueprintGrpcClientService(selector.toString())
77 // Get the GRPC Channel
78 channel = grpcClientService.channel()
79 // Create Non Blocking Stub
80 commandExecutorServiceGrpc = CommandExecutorServiceGrpc.newBlockingStub(channel)
82 checkNotNull(commandExecutorServiceGrpc) {
83 "failed to create command executor grpc client for selector($selector)"
87 override suspend fun prepareEnv(prepareEnvInput: PrepareRemoteEnvInput): RemoteScriptExecutionOutput {
88 val grpResponse = commandExecutorServiceGrpc
89 .withDeadlineAfter(prepareEnvInput.timeOut * 1000, TimeUnit.MILLISECONDS)
90 .prepareEnv(prepareEnvInput.asGrpcData())
92 checkNotNull(grpResponse.status) {
93 "failed to get GRPC prepare env response status for requestId(${prepareEnvInput.requestId})"
96 val remoteScriptExecutionOutput = grpResponse.asJavaData()
97 log.debug("Received prepare env response from command server for requestId(${prepareEnvInput.requestId})")
99 return remoteScriptExecutionOutput
102 override suspend fun executeCommand(remoteExecutionInput: RemoteScriptExecutionInput): RemoteScriptExecutionOutput {
104 commandExecutorServiceGrpc
105 .withDeadlineAfter(remoteExecutionInput.timeOut * 1000, TimeUnit.MILLISECONDS)
106 .executeCommand(remoteExecutionInput.asGrpcData())
108 checkNotNull(grpResponse.status) {
109 "failed to get GRPC response status for requestId(${remoteExecutionInput.requestId})"
112 log.debug("Received response from command server for requestId(${remoteExecutionInput.requestId})")
113 return grpResponse.asJavaData()
116 override suspend fun close() {
117 channel?.shutdownNow()
120 fun PrepareRemoteEnvInput.asGrpcData(): PrepareEnvInput {
121 val correlationId = this.correlationId ?: this.requestId
123 val packageList = mutableListOf<Packages>()
125 this.packages.toList().forEach {
126 val pckage = Packages.newBuilder()
127 JsonFormat.parser().merge(it.toString(), pckage)
128 packageList.add(pckage.build())
131 return PrepareEnvInput.newBuilder()
132 .setIdentifiers(this.remoteIdentifier!!.asGrpcData())
133 .setRequestId(this.requestId)
134 .setSubRequestId(this.subRequestId)
135 .setOriginatorId(this.originatorId)
136 .setCorrelationId(correlationId)
137 .setTimeOut(this.timeOut.toInt())
138 .addAllPackages(packageList)
139 .setProperties(this.properties.asGrpcData())
143 fun RemoteScriptExecutionInput.asGrpcData(): ExecutionInput {
144 val correlationId = this.correlationId ?: this.requestId
145 return ExecutionInput.newBuilder()
146 .setRequestId(this.requestId)
147 .setSubRequestId(this.subRequestId)
148 .setOriginatorId(this.originatorId)
149 .setCorrelationId(correlationId)
150 .setIdentifiers(this.remoteIdentifier!!.asGrpcData())
151 .setCommand(this.command)
152 .setTimeOut(this.timeOut.toInt())
153 .setProperties(this.properties.asGrpcData())
154 .setTimestamp(Timestamp.getDefaultInstance())
158 fun RemoteIdentifier.asGrpcData(): Identifiers? {
159 return Identifiers.newBuilder()
160 .setBlueprintName(this.blueprintName)
161 .setBlueprintVersion(this.blueprintVersion)
165 fun Map<String, JsonNode>.asGrpcData(): Struct {
166 val struct = Struct.newBuilder()
167 JsonFormat.parser().merge(JacksonUtils.getJson(this), struct)
168 return struct.build()
171 fun ExecutionOutput.asJavaData(): RemoteScriptExecutionOutput {
172 return RemoteScriptExecutionOutput(
173 requestId = this.requestId,
174 response = this.responseList,
175 status = StatusType.valueOf(this.status.name),
176 payload = payload.jsonAsJsonType()