diff options
Diffstat (limited to 'sliapi/provider/src/main/java/org/openecomp/sdnc/sliapi/sliapiProvider.java')
-rw-r--r-- | sliapi/provider/src/main/java/org/openecomp/sdnc/sliapi/sliapiProvider.java | 557 |
1 files changed, 557 insertions, 0 deletions
diff --git a/sliapi/provider/src/main/java/org/openecomp/sdnc/sliapi/sliapiProvider.java b/sliapi/provider/src/main/java/org/openecomp/sdnc/sliapi/sliapiProvider.java new file mode 100644 index 00000000..705277c6 --- /dev/null +++ b/sliapi/provider/src/main/java/org/openecomp/sdnc/sliapi/sliapiProvider.java @@ -0,0 +1,557 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights + * reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdnc.sliapi; + +import java.util.Enumeration; +import java.util.LinkedList; +import java.util.Properties; +import java.util.concurrent.Future; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.controller.md.sal.binding.impl.AbstractForwardedDataBroker; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.OptimisticLockFailedException; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; +import org.opendaylight.controller.sal.binding.api.NotificationProviderService; +import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; +import org.opendaylight.yang.gen.v1.org.openecomp.sdnc.sliapi.rev161110.ExecuteGraphInput; +import org.opendaylight.yang.gen.v1.org.openecomp.sdnc.sliapi.rev161110.ExecuteGraphInput.Mode; +import org.opendaylight.yang.gen.v1.org.openecomp.sdnc.sliapi.rev161110.ExecuteGraphInputBuilder; +import org.opendaylight.yang.gen.v1.org.openecomp.sdnc.sliapi.rev161110.ExecuteGraphOutput; +import org.opendaylight.yang.gen.v1.org.openecomp.sdnc.sliapi.rev161110.ExecuteGraphOutputBuilder; +import org.opendaylight.yang.gen.v1.org.openecomp.sdnc.sliapi.rev161110.HealthcheckOutput; +import org.opendaylight.yang.gen.v1.org.openecomp.sdnc.sliapi.rev161110.HealthcheckOutputBuilder; +import org.opendaylight.yang.gen.v1.org.openecomp.sdnc.sliapi.rev161110.SLIAPIService; +import org.opendaylight.yang.gen.v1.org.openecomp.sdnc.sliapi.rev161110.TestResults; +import org.opendaylight.yang.gen.v1.org.openecomp.sdnc.sliapi.rev161110.execute.graph.input.SliParameter; +import org.opendaylight.yang.gen.v1.org.openecomp.sdnc.sliapi.rev161110.test.results.TestResult; +import org.opendaylight.yang.gen.v1.org.openecomp.sdnc.sliapi.rev161110.test.results.TestResultBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.common.RpcResultBuilder; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue; +import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode; +import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode; +import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; +import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetEntryNodeBuilder; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetNodeBuilder; +import org.openecomp.sdnc.sli.provider.SvcLogicService; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.ServiceReference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.util.concurrent.Futures; + + +/** + * Defines a base implementation for your provider. This class extends from a helper class + * which provides storage for the most commonly used components of the MD-SAL. Additionally the + * base class provides some basic logging and initialization / clean up methods. + * + * To use this, copy and paste (overwrite) the following method into the TestApplicationProviderModule + * class which is auto generated under src/main/java in this project + * (created only once during first compilation): + * + * <pre> + + @Override + public java.lang.AutoCloseable createInstance() { + + final sliapiProvider provider = new sliapiProvider(); + provider.setDataBroker( getDataBrokerDependency() ); + provider.setNotificationService( getNotificationServiceDependency() ); + provider.setRpcRegistry( getRpcRegistryDependency() ); + provider.initialize(); + return new AutoCloseable() { + + @Override + public void close() throws Exception { + //TODO: CLOSE ANY REGISTRATION OBJECTS CREATED USING ABOVE BROKER/NOTIFICATION + //SERVIE/RPC REGISTRY + provider.close(); + } + }; + } + + + </pre> + */ +public class sliapiProvider implements AutoCloseable, SLIAPIService{ + + private final Logger LOG = LoggerFactory.getLogger( sliapiProvider.class ); + private final String appName = "slitester"; + + protected DataBroker dataBroker; + protected DOMDataBroker domDataBroker; + protected NotificationProviderService notificationService; + protected RpcProviderRegistry rpcRegistry; + + protected BindingAwareBroker.RpcRegistration<SLIAPIService> rpcRegistration; + + private static String SLIAPI_NAMESPACE = "org:openecomp:sdnc:sliapi"; + private static String SLIAPI_REVISION = "2016-11-10"; + + private static QName TEST_RESULTS_QNAME = null; + private static QName TEST_RESULT_QNAME = null; + private static QName TEST_ID_QNAME = null; + private static QName RESULTS_QNAME = null; + + static { + + TEST_RESULTS_QNAME = QName.create(SLIAPI_NAMESPACE, SLIAPI_REVISION, "test-results"); + TEST_RESULT_QNAME = QName.create(TEST_RESULTS_QNAME, "test-result"); + TEST_ID_QNAME = QName.create(TEST_RESULT_QNAME, "test-identifier"); + RESULTS_QNAME = QName.create(TEST_RESULT_QNAME, "results"); + } + + + public sliapiProvider() { + this.LOG.info( "Creating provider for " + appName ); + } + + public void initialize(){ + LOG.info( "Initializing provider for " + appName ); + //initialization code goes here. + + rpcRegistration = rpcRegistry.addRpcImplementation(SLIAPIService.class, this); + LOG.info( "Initialization complete for " + appName ); + } + + protected void initializeChild() { + //Override if you have custom initialization intelligence + } + + @Override + public void close() throws Exception { + LOG.info( "Closing provider for " + appName ); + //closing code goes here + + rpcRegistration.close(); + LOG.info( "Successfully closed provider for " + appName ); + } + + public void setDataBroker(DataBroker dataBroker) { + this.dataBroker = dataBroker; + if (dataBroker instanceof AbstractForwardedDataBroker) { + domDataBroker = ((AbstractForwardedDataBroker) dataBroker).getDelegate(); + } + if( LOG.isDebugEnabled() ){ + LOG.debug( "DataBroker set to " + (dataBroker==null?"null":"non-null") + "." ); + } + } + + public void setNotificationService( + NotificationProviderService notificationService) { + this.notificationService = notificationService; + if( LOG.isDebugEnabled() ){ + LOG.debug( "Notification Service set to " + (notificationService==null?"null":"non-null") + "." ); + } + } + + public void setRpcRegistry(RpcProviderRegistry rpcRegistry) { + this.rpcRegistry = rpcRegistry; + if( LOG.isDebugEnabled() ){ + LOG.debug( "RpcRegistry set to " + (rpcRegistry==null?"null":"non-null") + "." ); + } + } + + @Override + public Future<RpcResult<ExecuteGraphOutput>> executeGraph(ExecuteGraphInput input) { + RpcResult<ExecuteGraphOutput> rpcResult = null; + + SvcLogicService svcLogic = getSvcLogicService(); + ExecuteGraphOutputBuilder respBuilder = new ExecuteGraphOutputBuilder(); + + String calledModule = input.getModuleName(); + String calledRpc = input.getRpcName(); + Mode calledMode = input.getMode(); + String modeStr = "sync"; + + if (calledMode == Mode.Async) { + modeStr = "async"; + } + + if (svcLogic == null) { + respBuilder.setResponseCode("500"); + respBuilder.setResponseMessage("Could not locate OSGi SvcLogicService service"); + respBuilder.setAckFinalIndicator("Y"); + + rpcResult = RpcResultBuilder.<ExecuteGraphOutput> status(true).withResult(respBuilder.build()).build(); + return(Futures.immediateFuture(rpcResult)); + } + + + try { + if (!svcLogic.hasGraph(calledModule, calledRpc, null, modeStr)) { + respBuilder.setResponseCode("404"); + respBuilder.setResponseMessage("Directed graph for "+calledModule+"/"+calledRpc+"/"+modeStr+" not found"); + respBuilder.setAckFinalIndicator("Y"); + + rpcResult = RpcResultBuilder.<ExecuteGraphOutput> status(true).withResult(respBuilder.build()).build(); + return(Futures.immediateFuture(rpcResult)); + } + } catch (Exception e) { + LOG.error("Caught exception looking for directed graph for "+calledModule+"/"+calledRpc+"/"+modeStr, e); + + respBuilder.setResponseCode("500"); + respBuilder.setResponseMessage("Internal error : could not determine if target graph exists"); + respBuilder.setAckFinalIndicator("Y"); + + rpcResult = RpcResultBuilder.<ExecuteGraphOutput> status(true).withResult(respBuilder.build()).build(); + return(Futures.immediateFuture(rpcResult)); + } + + // Load properties + Properties parms = new Properties(); + + // Pass properties using names from sli-parameters + for (SliParameter sliParm : input.getSliParameter()) { + + String propValue = ""; + + Boolean boolval = sliParm.isBooleanValue(); + + if (boolval != null) { + propValue = boolval.toString(); + } else { + Integer intval = sliParm.getIntValue(); + if (intval != null) { + propValue = intval.toString(); + } else { + propValue = sliParm.getStringValue(); + if (propValue == null) { + propValue = ""; + } + } + } + parms.setProperty(sliParm.getParameterName(), propValue); + } + + // Also, pass "meta" properties (i.e. pass SliParameter objects themselves) + ExecuteGraphInputBuilder inputBuilder = new ExecuteGraphInputBuilder(input); + + SliapiHelper.toProperties(parms, "input", inputBuilder); + + try { + LOG.info("Calling directed graph for "+calledModule+"/"+calledRpc+"/"+modeStr); + + if (LOG.isTraceEnabled()) { + StringBuffer argList = new StringBuffer(); + argList.append("Parameters : {"); + Enumeration e = parms.propertyNames(); + while (e.hasMoreElements()) { + String propName = (String) e.nextElement(); + argList.append(" ("+propName+","+parms.getProperty(propName)+") "); + } + argList.append("}"); + LOG.trace(argList.toString()); + argList = null; + } + + + + Properties respProps = svcLogic.execute(calledModule, calledRpc, + null, modeStr, parms, domDataBroker); + + StringBuilder sb = new StringBuilder("{"); + + for (Object key : respProps.keySet()) { + String keyValue = (String) key; + if (keyValue != null && !"".equals(keyValue) && !keyValue.contains("input.sli-parameter")) { + sb.append("\"").append(keyValue).append("\": \"").append(respProps.getProperty(keyValue)).append("\","); + } + } + + sb.setLength(sb.length() - 1); + sb.append("}"); + + respBuilder.setResponseCode(respProps.getProperty("error-code", "0")); + respBuilder.setResponseMessage(respProps.getProperty("error-message", ""));// TODO change response-text to response-message to match other BVC APIs + respBuilder.setAckFinalIndicator(respProps.getProperty("ack-final", "Y")); + respBuilder.setContextMemoryJson(sb.toString()); + + TestResultBuilder testResultBuilder = new TestResultBuilder(); + + SliapiHelper.toBuilder(respProps, testResultBuilder); + + String testIdentifier = testResultBuilder.getTestIdentifier(); + + if ((testIdentifier != null) && (testIdentifier.length() > 0)) { + + // Add test results to config tree + LOG.debug("Saving test results for test id "+testIdentifier); + + DomSaveTestResult(testResultBuilder.build(), true, LogicalDatastoreType.CONFIGURATION); + + } + + } catch (Exception e) { + LOG.error("Caught exception executing directed graph for" + + calledModule + ":" + calledRpc + "," + modeStr + ">", e); + + respBuilder.setResponseCode("500"); + respBuilder + .setResponseMessage("Internal error : caught exception executing directed graph " + + calledModule + + "/" + + calledRpc + + "/" + + modeStr); + respBuilder.setAckFinalIndicator("Y"); + + } + + rpcResult = RpcResultBuilder.<ExecuteGraphOutput> status(true) + .withResult(respBuilder.build()).build(); + return (Futures.immediateFuture(rpcResult)); + } + + + private SvcLogicService getSvcLogicService() { + BundleContext bctx = FrameworkUtil.getBundle(SvcLogicService.class).getBundleContext(); + + SvcLogicService svcLogic = null; + + // Get SvcLogicService reference + ServiceReference sref = bctx.getServiceReference(SvcLogicService.NAME); + if (sref != null) + { + svcLogic = (SvcLogicService) bctx.getService(sref); + + } + else + { + LOG.warn("Cannot find service reference for "+SvcLogicService.NAME); + + } + + return(svcLogic); + } + + @Override + public Future<RpcResult<HealthcheckOutput>> healthcheck() { + + RpcResult<HealthcheckOutput> rpcResult = null; + SvcLogicService svcLogic = getSvcLogicService(); + + HealthcheckOutputBuilder respBuilder = new HealthcheckOutputBuilder(); + + String calledModule = "sli"; + String calledRpc = "healthcheck"; + String modeStr = "sync"; + + if (svcLogic == null) { + respBuilder.setResponseCode("500"); + respBuilder.setResponseMessage("Could not locate OSGi SvcLogicService service"); + respBuilder.setAckFinalIndicator("Y"); + + rpcResult = RpcResultBuilder.<HealthcheckOutput> failed().withResult(respBuilder.build()).build(); + return(Futures.immediateFuture(rpcResult)); + } + + try { + if (!svcLogic.hasGraph(calledModule, calledRpc, null, modeStr)) { + respBuilder.setResponseCode("404"); + respBuilder.setResponseMessage("Directed graph for "+calledModule+"/"+calledRpc+"/"+modeStr+" not found"); + + respBuilder.setAckFinalIndicator("Y"); + + rpcResult = RpcResultBuilder.<HealthcheckOutput> status(true).withResult(respBuilder.build()).build(); + return(Futures.immediateFuture(rpcResult)); + } + } catch (Exception e) { + LOG.error("Caught exception looking for directed graph for "+calledModule+"/"+calledRpc+"/"+modeStr, e); + + respBuilder.setResponseCode("500"); + respBuilder.setResponseMessage("Internal error : could not determine if target graph exists"); + respBuilder.setAckFinalIndicator("Y"); + + rpcResult = RpcResultBuilder.<HealthcheckOutput> failed().withResult(respBuilder.build()).build(); + return(Futures.immediateFuture(rpcResult)); + } + + try { + LOG.info("Calling directed graph for "+calledModule+"/"+calledRpc+"/"+modeStr); + + Properties parms = new Properties(); + + Properties respProps = svcLogic.execute(calledModule, calledRpc, + null, modeStr, parms); + + respBuilder.setResponseCode(respProps.getProperty("error-code", "0")); + respBuilder.setResponseMessage(respProps.getProperty("error-message", "")); + respBuilder.setAckFinalIndicator(respProps.getProperty("ack-final", "Y")); + + } catch (Exception e) { + LOG.error("Caught exception executing directed graph for" + + calledModule + ":" + calledRpc + "," + modeStr + ">", e); + + respBuilder.setResponseCode("500"); + respBuilder + .setResponseMessage("Internal error : caught exception executing directed graph " + + calledModule + + "/" + + calledRpc + + "/" + + modeStr); + respBuilder.setAckFinalIndicator("Y"); + + } + + rpcResult = RpcResultBuilder.<HealthcheckOutput> status(true) + .withResult(respBuilder.build()).build(); + return (Futures.immediateFuture(rpcResult)); + } + + private void DomSaveTestResult(final TestResult entry, boolean merge, LogicalDatastoreType storeType) { + + + if (domDataBroker == null) { + LOG.error("domDataBroker unset - cannot save test result using DOMDataBroker"); + return; + } + + MapEntryNode resultNode = null; + + try { + resultNode = toMapEntryNode(entry); + } catch (Exception e) { + LOG.error("Caught exception trying to create map entry node", e); + } + + if (resultNode == null) { + LOG.error("Could not convert entry to MapEntryNode"); + return; + } + + + YangInstanceIdentifier testResultsPid = YangInstanceIdentifier.builder().node(TEST_RESULTS_QNAME).node(QName.create(TEST_RESULTS_QNAME, "test-result")).build(); + YangInstanceIdentifier testResultPid = testResultsPid.node(new NodeIdentifierWithPredicates(TEST_RESULT_QNAME, resultNode.getIdentifier().getKeyValues())); + + + + int tries = 2; + while(true) { + try { + DOMDataWriteTransaction wtx = domDataBroker.newWriteOnlyTransaction(); + if (merge) { + LOG.info("Merging test identifier "+entry.getTestIdentifier()); + wtx.merge(storeType, testResultPid, resultNode); + } else { + LOG.info("Putting test identifier "+entry.getTestIdentifier()); + wtx.put(storeType, testResultPid, resultNode); + } + wtx.submit().checkedGet(); + LOG.trace("Update DataStore succeeded"); + break; + } catch (final TransactionCommitFailedException e) { + if(e instanceof OptimisticLockFailedException) { + if(--tries <= 0) { + LOG.trace("Got OptimisticLockFailedException on last try - failing "); + throw new IllegalStateException(e); + } + LOG.trace("Got OptimisticLockFailedException - trying again "); + } else { + LOG.trace("Update DataStore failed"); + throw new IllegalStateException(e); + } + } + } + + } + + private void SaveTestResult(final TestResult entry, boolean merge, LogicalDatastoreType storeType) throws IllegalStateException + { + // Each entry will be identifiable by a unique key, we have to create that identifier + InstanceIdentifier.InstanceIdentifierBuilder<TestResult> testResultIdBuilder = + InstanceIdentifier.<TestResults>builder(TestResults.class) + .child(TestResult.class, entry.getKey()); + InstanceIdentifier<TestResult> path = testResultIdBuilder.toInstance(); + int tries = 2; + while(true) { + try { + WriteTransaction tx = dataBroker.newWriteOnlyTransaction(); + if (merge) { + tx.merge(storeType, path, entry); + } else { + tx.put(storeType, path, entry); + } + tx.submit().checkedGet(); + LOG.trace("Update DataStore succeeded"); + break; + } catch (final TransactionCommitFailedException e) { + if(e instanceof OptimisticLockFailedException) { + if(--tries <= 0) { + LOG.trace("Got OptimisticLockFailedException on last try - failing "); + throw new IllegalStateException(e); + } + LOG.trace("Got OptimisticLockFailedException - trying again "); + } else { + LOG.trace("Update DataStore failed"); + throw new IllegalStateException(e); + } + } + } + } + + private MapEntryNode toMapEntryNode(TestResult testResult) { + + + YangInstanceIdentifier testResultId = YangInstanceIdentifier.builder().node(TEST_RESULTS_QNAME).node(TEST_RESULT_QNAME).build(); + + // Construct results list + LinkedList<LeafSetEntryNode<Object>> entryList = new LinkedList<LeafSetEntryNode<Object>>(); + for (String result : testResult.getResults()) { + LeafSetEntryNode<Object> leafSetEntryNode = ImmutableLeafSetEntryNodeBuilder.create() + .withNodeIdentifier(new NodeWithValue(RESULTS_QNAME, result)) + .withValue(result) + .build(); + entryList.add(leafSetEntryNode); + } + // Construct results LeafSetNode + LeafSetNode<?> resultsNode = ImmutableLeafSetNodeBuilder.create().withNodeIdentifier(new NodeIdentifier(RESULTS_QNAME)).withValue(entryList).build(); + + + + // Construct test result ContainerNode with 2 children - test-identifier leaf and results leaf-set + MapEntryNode testResultNode = ImmutableNodes.mapEntryBuilder() + .withNodeIdentifier(new NodeIdentifierWithPredicates(TEST_RESULT_QNAME, TEST_ID_QNAME, testResult.getTestIdentifier())) + .withChild(ImmutableNodes.leafNode(TEST_ID_QNAME, testResult.getTestIdentifier())) + .withChild(resultsNode) + .build(); + + return(testResultNode); + + } + +} |