From afde732d7244f4016248cc080e63fe4e29465396 Mon Sep 17 00:00:00 2001 From: Alexis de Talhouët Date: Fri, 18 Jan 2019 15:14:23 -0500 Subject: Client for BluePrintProcessingServiceGrpc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I32d3bd80b9004d98c3c34f73081c156192fb4432 Issue-ID: CCSDK-947 Signed-off-by: Alexis de Talhouët --- .../onap/ccsdk/sli/adaptors/grpc/GrpcClient.java | 21 +-- .../ccsdk/sli/adaptors/grpc/GrpcProperties.java | 114 ++++++++++++++++ .../org/onap/ccsdk/sli/adaptors/grpc/Utils.java | 34 +++++ .../grpc/cds/BlueprintProcessingClient.java | 76 +++++++++++ .../grpc/cds/BlueprintProcessingHandler.java | 152 +++++++++++++++++++++ .../provider/src/main/resources/grpc.properties | 15 ++ .../org/opendaylight/blueprint/grpc-client.xml | 13 +- .../ccsdk/sli/adaptors/grpc/GrpcClientTest.java | 20 --- .../sli/adaptors/grpc/cds/GrpcClientTest.java | 20 +++ 9 files changed, 435 insertions(+), 30 deletions(-) create mode 100644 grpc-resource/provider/src/main/java/org/onap/ccsdk/sli/adaptors/grpc/GrpcProperties.java create mode 100644 grpc-resource/provider/src/main/java/org/onap/ccsdk/sli/adaptors/grpc/Utils.java create mode 100644 grpc-resource/provider/src/main/java/org/onap/ccsdk/sli/adaptors/grpc/cds/BlueprintProcessingClient.java create mode 100644 grpc-resource/provider/src/main/java/org/onap/ccsdk/sli/adaptors/grpc/cds/BlueprintProcessingHandler.java create mode 100755 grpc-resource/provider/src/main/resources/grpc.properties delete mode 100644 grpc-resource/provider/src/test/java/org/onap/ccsdk/sli/adaptors/grpc/GrpcClientTest.java create mode 100644 grpc-resource/provider/src/test/java/org/onap/ccsdk/sli/adaptors/grpc/cds/GrpcClientTest.java (limited to 'grpc-resource/provider/src') diff --git a/grpc-resource/provider/src/main/java/org/onap/ccsdk/sli/adaptors/grpc/GrpcClient.java b/grpc-resource/provider/src/main/java/org/onap/ccsdk/sli/adaptors/grpc/GrpcClient.java index c70bcec4..91788274 100644 --- a/grpc-resource/provider/src/main/java/org/onap/ccsdk/sli/adaptors/grpc/GrpcClient.java +++ b/grpc-resource/provider/src/main/java/org/onap/ccsdk/sli/adaptors/grpc/GrpcClient.java @@ -15,15 +15,18 @@ */ package org.onap.ccsdk.sli.adaptors.grpc; -public class GrpcClient { +import java.util.Map; +import org.onap.ccsdk.sli.core.sli.SvcLogicContext; +import org.onap.ccsdk.sli.core.sli.SvcLogicJavaPlugin; +import org.onap.ccsdk.sli.core.sli.SvcLogicResource.QueryStatus; -// ManagedChannel channel = ManagedChannelBuilder -// .forAddress("localhost", 8080) -// .executor(Executors.newSingleThreadExecutor()) -// .intercept() -// .userAgent("CCSDK gRPC Client") -// .usePlaintext() -// //.useTransportSecurity() -// .build(); +public interface GrpcClient extends SvcLogicJavaPlugin { + /** + * Send a request to process to a gRPC server. + * + * @param parameters HashMap of parameters passed by the DG to this function. + * Required parameters are defined in implemention. + */ + QueryStatus sendRequest(Map parameters, SvcLogicContext ctx); } diff --git a/grpc-resource/provider/src/main/java/org/onap/ccsdk/sli/adaptors/grpc/GrpcProperties.java b/grpc-resource/provider/src/main/java/org/onap/ccsdk/sli/adaptors/grpc/GrpcProperties.java new file mode 100644 index 00000000..fef1a596 --- /dev/null +++ b/grpc-resource/provider/src/main/java/org/onap/ccsdk/sli/adaptors/grpc/GrpcProperties.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2018 Bell Canada. + * + * 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.sli.adaptors.grpc; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.HashSet; +import java.util.Optional; +import java.util.Properties; +import java.util.Set; +import org.onap.ccsdk.sli.core.utils.JREFileResolver; +import org.onap.ccsdk.sli.core.utils.KarafRootFileResolver; +import org.onap.ccsdk.sli.core.utils.PropertiesFileResolver; +import org.onap.ccsdk.sli.core.utils.common.BundleContextFileResolver; +import org.onap.ccsdk.sli.core.utils.common.SdncConfigEnvVarFileResolver; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Responsible for determining the properties file to use. + * + *
    + *
  1. A directory identified by the system environment variable SDNC_CONFIG_DIR
  2. + *
  3. A directory identified by the JRE argument grpc.properties
  4. + *
  5. A grpc.properties file located in the karaf root directory
  6. + *
+ * + * Partial copy and adaptation of org.onap.ccsdk.sli.adaptors.aai.AAIServiceProvider + */ +public class GrpcProperties { + + private static final Logger LOG = LoggerFactory.getLogger(GrpcProperties.class); + + private static final String GRPC_PROPERTY_FILE_NAME = "grpc.properties"; + private static final String MISSING_PROPERTY_FILE = + "Missing configuration properties resource for GRPC: " + GRPC_PROPERTY_FILE_NAME; + private static final String BLUEPRINT_PROCESSOR_URL_PROP = "org.onap.ccsdk.sli.adaptors.grpc.blueprint.processor.url"; + private static final String BLUEPRINT_PROCESSOR_PORT_PROP = "org.onap.ccsdk.sli.adaptors.grpc.blueprint.processor.port"; + + private Set fileResolvers = new HashSet<>(); + private Properties properties; + + public GrpcProperties() { + fileResolvers.add(new SdncConfigEnvVarFileResolver("Using property file (1) from environment variable")); + fileResolvers.add(new BundleContextFileResolver("Using property file (2) from BundleContext property", + GrpcProperties.class)); + fileResolvers.add(new JREFileResolver("Using property file (3) from JRE argument", GrpcProperties.class)); + fileResolvers.add(new KarafRootFileResolver("Using property file (4) from karaf root", this)); + + loadProps(); + } + + public String getUrl() { + checkArgument(properties != null); + return properties.getProperty(BLUEPRINT_PROCESSOR_URL_PROP); + } + + public int getPort() { + checkArgument(properties != null); + return Integer.parseInt(properties.getProperty(BLUEPRINT_PROCESSOR_PORT_PROP)); + } + + private void checkArgument(final boolean argument) { + if (!argument) { + LOG.info("Propety file {} was missing, trying to reload it", GRPC_PROPERTY_FILE_NAME); + loadProps(); + if (properties == null) { + throw new IllegalArgumentException(MISSING_PROPERTY_FILE); + } + } + } + + private void loadProps() { + // determines properties file as according to the priority described in the class header comment + final File propertiesFile = determinePropertiesFile(); + if (propertiesFile != null) { + try (FileInputStream fileInputStream = new FileInputStream(propertiesFile)) { + properties = new Properties(); + properties.load(fileInputStream); + } catch (final IOException e) { + String errorMsg = "Failed to load properties for file: " + propertiesFile.toString(); + LOG.error(errorMsg, errorMsg); + } + } + } + + private File determinePropertiesFile() { + for (final PropertiesFileResolver resolver : fileResolvers) { + final Optional fileOptional = resolver.resolveFile(GRPC_PROPERTY_FILE_NAME); + if (fileOptional.isPresent()) { + final File file = fileOptional.get(); + LOG.info("{} {}", resolver.getSuccessfulResolutionMessage(), file.getPath()); + return file; + } + } + + LOG.error(MISSING_PROPERTY_FILE); + return null; + } +} diff --git a/grpc-resource/provider/src/main/java/org/onap/ccsdk/sli/adaptors/grpc/Utils.java b/grpc-resource/provider/src/main/java/org/onap/ccsdk/sli/adaptors/grpc/Utils.java new file mode 100644 index 00000000..831f09ea --- /dev/null +++ b/grpc-resource/provider/src/main/java/org/onap/ccsdk/sli/adaptors/grpc/Utils.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2019 Bell Canada. + * + * 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.sli.adaptors.grpc; + +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; + +public final class Utils { + + private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); + + private Utils() { + throw new AssertionError("Utility class"); + } + + public static String timestamp() { + LocalDateTime now = LocalDateTime.now(ZoneId.systemDefault()); + return formatter.format(now); + } +} diff --git a/grpc-resource/provider/src/main/java/org/onap/ccsdk/sli/adaptors/grpc/cds/BlueprintProcessingClient.java b/grpc-resource/provider/src/main/java/org/onap/ccsdk/sli/adaptors/grpc/cds/BlueprintProcessingClient.java new file mode 100644 index 00000000..33fb8fa2 --- /dev/null +++ b/grpc-resource/provider/src/main/java/org/onap/ccsdk/sli/adaptors/grpc/cds/BlueprintProcessingClient.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2019 Bell Canada. + * + * 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.sli.adaptors.grpc.cds; + +import io.grpc.ManagedChannel; +import io.grpc.internal.DnsNameResolverProvider; +import io.grpc.netty.NettyChannelBuilder; +import java.util.Map; +import org.onap.ccsdk.sli.adaptors.grpc.GrpcClient; +import org.onap.ccsdk.sli.adaptors.grpc.GrpcProperties; +import org.onap.ccsdk.sli.core.sli.SvcLogicContext; +import org.onap.ccsdk.sli.core.sli.SvcLogicResource.QueryStatus; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class BlueprintProcessingClient implements GrpcClient { + + private static final Logger log = LoggerFactory.getLogger(BlueprintProcessingClient.class); + + private ManagedChannel channel; + private BlueprintProcessingHandler handler; + + public BlueprintProcessingClient(BlueprintProcessingHandler handler, GrpcProperties props) { + this.channel = NettyChannelBuilder + .forAddress(props.getUrl(), props.getPort()) + .usePlaintext() + .nameResolverFactory(new DnsNameResolverProvider()) + .build(); + this.handler = handler; + } + + // Used by blueprint + public void start() { + log.info("BlueprintProcessingClient started"); + } + + // Used by blueprint + public void stop() { + if (channel != null) { + channel.shutdown(); + } + log.info("BlueprintProcessingClient stopped"); + } + + /* + * @param parameters HashMap of parameters passed by the DG to this function. + * + * + * + * + * + * + * + * + * + * + *
parameterMandatory/Optionaldescription
is_forceOptionalWhether to force or not the request.
ttlOptionalDuration of the request.
blueprint_nameMandatoryName of the blueprint to process.
blueprint_versionMandatoryVersion of the blueprint to process.
actionMandatoryAction of the blueprint to process.
modeMandatoryMode to operate the transaction.
+ */ + @Override + public QueryStatus sendRequest(Map parameters, SvcLogicContext ctx) { + return handler.process(parameters, channel); + } +} \ No newline at end of file diff --git a/grpc-resource/provider/src/main/java/org/onap/ccsdk/sli/adaptors/grpc/cds/BlueprintProcessingHandler.java b/grpc-resource/provider/src/main/java/org/onap/ccsdk/sli/adaptors/grpc/cds/BlueprintProcessingHandler.java new file mode 100644 index 00000000..6a618fb3 --- /dev/null +++ b/grpc-resource/provider/src/main/java/org/onap/ccsdk/sli/adaptors/grpc/cds/BlueprintProcessingHandler.java @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2019 Bell Canada. + * + * 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.sli.adaptors.grpc.cds; + +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Struct; +import io.grpc.ManagedChannel; +import io.grpc.Status; +import io.grpc.stub.StreamObserver; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import org.onap.ccsdk.apps.controllerblueprints.common.api.ActionIdentifiers; +import org.onap.ccsdk.apps.controllerblueprints.common.api.CommonHeader; +import org.onap.ccsdk.apps.controllerblueprints.common.api.Flag; +import org.onap.ccsdk.apps.controllerblueprints.processing.api.BluePrintProcessingServiceGrpc; +import org.onap.ccsdk.apps.controllerblueprints.processing.api.BluePrintProcessingServiceGrpc.BluePrintProcessingServiceStub; +import org.onap.ccsdk.apps.controllerblueprints.processing.api.ExecutionServiceInput; +import org.onap.ccsdk.apps.controllerblueprints.processing.api.ExecutionServiceOutput; +import org.onap.ccsdk.sli.adaptors.grpc.Utils; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.core.sli.SvcLogicResource.QueryStatus; +import org.onap.ccsdk.sli.core.slipluginutils.SliPluginUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class BlueprintProcessingHandler { + + private static final Logger log = LoggerFactory.getLogger(BlueprintProcessingHandler.class); + + private static final String CCSDK_ORIGINATOR = "CCSDK"; + private static final String IS_FORCE_PROP = "is_force"; + private static final String TTL_PROP = "ttl"; + private static final String BLUEPRINT_NAME_PROP = "blueprint_name"; + private static final String BLUEPRINT_VERSION_PROP = "blueprint_version"; + private static final String ACTION_PROP = "action"; + private static final String MODE_PROP = "mode"; + private static final String PAYLOAD_PROP = "payload"; + + QueryStatus process(final Map parameters, final ManagedChannel channel) { + try { + SliPluginUtils.checkParameters(parameters, + new String[]{BLUEPRINT_NAME_PROP, BLUEPRINT_VERSION_PROP, ACTION_PROP, MODE_PROP}, log); + } catch (SvcLogicException e) { + return QueryStatus.FAILURE; + } + + final boolean isForce = Boolean.getBoolean(parameters.get(IS_FORCE_PROP)); + final int ttl = Integer.parseInt(parameters.get(TTL_PROP)); + final String blueprintName = parameters.get(BLUEPRINT_NAME_PROP); + final String blueprintVersion = parameters.get(BLUEPRINT_VERSION_PROP); + final String action = parameters.get(ACTION_PROP); + final String mode = parameters.get(MODE_PROP); + final String payload = parameters.get(PAYLOAD_PROP); + + log.info("Processing blueprint({}:{}) for action({})", blueprintVersion, blueprintName, action); + + final AtomicReference responseStatus = new AtomicReference<>(); + final CountDownLatch finishLatch = new CountDownLatch(1); + + final BluePrintProcessingServiceStub asyncStub = BluePrintProcessingServiceGrpc.newStub(channel); + + final StreamObserver responseObserver = new StreamObserver() { + @Override + public void onNext(ExecutionServiceOutput output) { + log.info("onNext: {}", output); + } + + @Override + public void onError(Throwable t) { + Status status = Status.fromThrowable(t); + log.error("Failed processing blueprint({}:{}) for action({}). {}", blueprintVersion, blueprintName, + action, status); + responseStatus.compareAndSet(null, QueryStatus.FAILURE); + finishLatch.countDown(); + } + + @Override + public void onCompleted() { + log.info("Completed blueprint({}:{}) for action({})", blueprintVersion, blueprintName, action); + responseStatus.compareAndSet(null, QueryStatus.SUCCESS); + finishLatch.countDown(); + } + }; + + final CommonHeader commonHeader = CommonHeader.newBuilder() + .setOriginatorId(CCSDK_ORIGINATOR) + .setRequestId(UUID.randomUUID().toString()) + .setTimestamp(Utils.timestamp()) + .setFlag(Flag.newBuilder() + .setIsForce(isForce) + .setTtl(ttl) + .build()) + .build(); + final ActionIdentifiers actionIdentifiers = ActionIdentifiers.newBuilder() + .setActionName(action) + .setBlueprintName(blueprintName) + .setBlueprintVersion(blueprintVersion) + .setMode(mode) + .build(); + + Struct struct; + try { + struct = Struct.newBuilder().mergeFrom(payload.getBytes()).build(); + } catch (InvalidProtocolBufferException e) { + log.error("Failed converting payload for blueprint({}:{}) for action({}). {}", blueprintVersion, + blueprintName, action, e); + return QueryStatus.FAILURE; + } + + final ExecutionServiceInput request = ExecutionServiceInput.newBuilder() + .setActionIdentifiers(actionIdentifiers) + .setPayload(struct) + .setCommonHeader(commonHeader).build(); + + final StreamObserver requestObserver = asyncStub.process(responseObserver); + + try { + requestObserver.onNext(request); + } catch (RuntimeException e) { + requestObserver.onError(e); + return QueryStatus.FAILURE; + } + + requestObserver.onCompleted(); + try { + finishLatch.await(1, TimeUnit.MINUTES); + } catch (InterruptedException e) { + log.error("Failed processing blueprint({}:{}) for action({}). {}", blueprintVersion, blueprintName, action, + e); + Thread.currentThread().interrupt(); + return QueryStatus.FAILURE; + } + + return responseStatus.get(); + } +} \ No newline at end of file diff --git a/grpc-resource/provider/src/main/resources/grpc.properties b/grpc-resource/provider/src/main/resources/grpc.properties new file mode 100755 index 00000000..2d4e795e --- /dev/null +++ b/grpc-resource/provider/src/main/resources/grpc.properties @@ -0,0 +1,15 @@ +# Copyright (C) 2019 Bell Canada +# +# 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. +org.onap.ccsdk.sli.adaptors.grpc.blueprint.processor.url=blueprint-processor +org.onap.ccsdk.sli.adaptors.grpc.blueprint.processor.port=9111 \ No newline at end of file diff --git a/grpc-resource/provider/src/main/resources/org/opendaylight/blueprint/grpc-client.xml b/grpc-resource/provider/src/main/resources/org/opendaylight/blueprint/grpc-client.xml index 5e9d5c80..e6e75159 100644 --- a/grpc-resource/provider/src/main/resources/org/opendaylight/blueprint/grpc-client.xml +++ b/grpc-resource/provider/src/main/resources/org/opendaylight/blueprint/grpc-client.xml @@ -17,6 +17,17 @@ - + + + + + + + + + + + diff --git a/grpc-resource/provider/src/test/java/org/onap/ccsdk/sli/adaptors/grpc/GrpcClientTest.java b/grpc-resource/provider/src/test/java/org/onap/ccsdk/sli/adaptors/grpc/GrpcClientTest.java deleted file mode 100644 index f56736a5..00000000 --- a/grpc-resource/provider/src/test/java/org/onap/ccsdk/sli/adaptors/grpc/GrpcClientTest.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2019 Bell Canada. - * - * 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.sli.adaptors.grpc; - -public class GrpcClientTest { - -} \ No newline at end of file diff --git a/grpc-resource/provider/src/test/java/org/onap/ccsdk/sli/adaptors/grpc/cds/GrpcClientTest.java b/grpc-resource/provider/src/test/java/org/onap/ccsdk/sli/adaptors/grpc/cds/GrpcClientTest.java new file mode 100644 index 00000000..2b1a42ba --- /dev/null +++ b/grpc-resource/provider/src/test/java/org/onap/ccsdk/sli/adaptors/grpc/cds/GrpcClientTest.java @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2019 Bell Canada. + * + * 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.sli.adaptors.grpc.cds; + +public class GrpcClientTest { + +} \ No newline at end of file -- cgit 1.2.3-korg