From 2cf702de0b65fe132ec32b6abfffe4c2c976dca0 Mon Sep 17 00:00:00 2001 From: herbert Date: Sat, 14 Dec 2019 00:36:01 +0100 Subject: Add netconfnode-state-service v2 add new service to devicemanager Issue-ID: SDNC-1006 Signed-off-by: herbert Change-Id: Iaba3d02e0ef6078cba57a33e03c2b2ad7aa0bacd Signed-off-by: herbert --- .../impl/NetconfNodeStateServiceImpl.java | 586 +++++++++++++++++++++ .../impl/conf/odlAkka/AkkaConfig.java | 86 +++ .../impl/conf/odlAkka/ClusterConfig.java | 137 +++++ .../impl/conf/odlAkka/ClusterNodeInfo.java | 81 +++ .../impl/conf/odlGeo/ClusterRoleInfo.java | 91 ++++ .../conf/odlGeo/ClusterRoleInfoCollection.java | 45 ++ .../impl/conf/odlGeo/GeoConfig.java | 162 ++++++ .../rpc/NetconfnodeStateServiceRpcApiImpl.java | 126 +++++ .../impl/rpc/RpcApigetStateCallback.java | 27 + .../org/opendaylight/blueprint/impl-blueprint.xml | 56 ++ .../provider/src/main/resources/version.properties | 3 + 11 files changed, 1400 insertions(+) create mode 100644 sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/NetconfNodeStateServiceImpl.java create mode 100644 sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlAkka/AkkaConfig.java create mode 100644 sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlAkka/ClusterConfig.java create mode 100644 sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlAkka/ClusterNodeInfo.java create mode 100644 sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlGeo/ClusterRoleInfo.java create mode 100644 sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlGeo/ClusterRoleInfoCollection.java create mode 100644 sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlGeo/GeoConfig.java create mode 100644 sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/rpc/NetconfnodeStateServiceRpcApiImpl.java create mode 100644 sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/rpc/RpcApigetStateCallback.java create mode 100644 sdnr/wt/netconfnode-state-service/provider/src/main/resources/org/opendaylight/blueprint/impl-blueprint.xml create mode 100644 sdnr/wt/netconfnode-state-service/provider/src/main/resources/version.properties (limited to 'sdnr/wt/netconfnode-state-service/provider/src/main') diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/NetconfNodeStateServiceImpl.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/NetconfNodeStateServiceImpl.java new file mode 100644 index 000000000..0af35e569 --- /dev/null +++ b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/NetconfNodeStateServiceImpl.java @@ -0,0 +1,586 @@ +/******************************************************************************* + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt + * ================================================================================================= + * Copyright (C) 2019 highstreet technologies GmbH 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.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl; + +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CopyOnWriteArrayList; + +import javax.annotation.Nullable; + +import org.eclipse.jdt.annotation.NonNull; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfNodeConnectListener; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfNodeStateListener; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfNodeStateService; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.VesNotificationListener; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf.odlAkka.AkkaConfig; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf.odlGeo.GeoConfig; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.rpc.NetconfnodeStateServiceRpcApiImpl; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.rpc.RpcApigetStateCallback; +import org.opendaylight.mdsal.binding.api.ClusteredDataTreeChangeListener; +import org.opendaylight.mdsal.binding.api.DataBroker; +import org.opendaylight.mdsal.binding.api.DataObjectModification; +import org.opendaylight.mdsal.binding.api.DataObjectModification.ModificationType; +import org.opendaylight.mdsal.binding.api.DataTreeChangeListener; +import org.opendaylight.mdsal.binding.api.DataTreeIdentifier; +import org.opendaylight.mdsal.binding.api.DataTreeModification; +import org.opendaylight.mdsal.binding.api.MountPoint; +import org.opendaylight.mdsal.binding.api.MountPointService; +import org.opendaylight.mdsal.binding.api.NotificationPublishService; +import org.opendaylight.mdsal.binding.api.RpcProviderService; +import org.opendaylight.mdsal.common.api.LogicalDatastoreType; +import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider; +import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus.ConnectionStatus; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.ClusteredConnectionStatus; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.network.topology.topology.topology.types.TopologyNetconf; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.GetStatusInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.GetStatusOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NetconfNodeStateServiceImpl implements NetconfNodeStateService, RpcApigetStateCallback, AutoCloseable { + + private static final Logger LOG = LoggerFactory.getLogger(NetconfNodeStateServiceImpl.class); + private static final String APPLICATION_NAME = "NetconfNodeStateService"; + @SuppressWarnings("unused") + private static final String CONFIGURATIONFILE = "etc/netconfnode-status-service.properties"; + + + private static final InstanceIdentifier NETCONF_TOPO_IID = + InstanceIdentifier.create(NetworkTopology.class).child(Topology.class, + new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName()))); + + private static final InstanceIdentifier NETCONF_NODE_TOPO_IID = + InstanceIdentifier.create(NetworkTopology.class) + .child(Topology.class, new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName()))) + .child(Node.class); + + private static final DataTreeIdentifier NETCONF_NODE_TOPO_TREE_ID = + DataTreeIdentifier.create(LogicalDatastoreType.OPERATIONAL, NETCONF_NODE_TOPO_IID); + + // Name of ODL controller NETCONF instance + private static final NodeId CONTROLLER = new NodeId("controller-config"); + + // -- OSGi services, provided + private DataBroker dataBroker; + private MountPointService mountPointService; + private RpcProviderService rpcProviderRegistry; + @SuppressWarnings("unused") + private NotificationPublishService notificationPublishService; + @SuppressWarnings("unused") + private ClusterSingletonServiceProvider clusterSingletonServiceProvider; + + // -- Parameter + private ListenerRegistration listenerL1; + private ListenerRegistration listenerL2; + @SuppressWarnings("unused") + private ClusterSingletonServiceRegistration cssRegistration; + + private NetconfnodeStateServiceRpcApiImpl rpcApiService; + + /** Indication if init() function called and fully executed **/ + private Boolean initializationSuccessful; + + /** List of all registered listeners **/ + private final List netconfNodeConnectListenerList; + + /** List of all registered listeners **/ + private final List netconfNodeStateListenerList; + + /** List of all registered listeners **/ + private final List vesNotificationListenerList; + + /** Indicates if running in cluster configuration **/ + private boolean isCluster; + + /** Indicates the name of the cluster **/ + private String clusterName; + + /** Blueprint **/ + public NetconfNodeStateServiceImpl() { + LOG.info("Creating provider for {}", APPLICATION_NAME); + + this.dataBroker = null; + this.mountPointService = null; + this.rpcProviderRegistry = null; + this.notificationPublishService = null; + this.clusterSingletonServiceProvider = null; + + this.listenerL1 = null; + this.listenerL2 = null; + this.initializationSuccessful= false; + this.netconfNodeConnectListenerList = new CopyOnWriteArrayList<>(); + this.netconfNodeStateListenerList = new CopyOnWriteArrayList<>(); + this.vesNotificationListenerList = new CopyOnWriteArrayList<>(); + } + + public void setDataBroker(DataBroker dataBroker) { + this.dataBroker = dataBroker; + } + + public void setRpcProviderRegistry(RpcProviderService rpcProviderRegistry) { + this.rpcProviderRegistry = rpcProviderRegistry; + } + + public void setNotificationPublishService(NotificationPublishService notificationPublishService) { + this.notificationPublishService = notificationPublishService; + } + + public void setMountPointService(MountPointService mountPointService) { + this.mountPointService = mountPointService; + } + public void setClusterSingletonService(ClusterSingletonServiceProvider clusterSingletonService) { + this.clusterSingletonServiceProvider = clusterSingletonService; + } + + /** Blueprint initialization **/ + public void init() { + + LOG.info("Session Initiated start {}", APPLICATION_NAME); + + // Start RPC Service + this.rpcApiService = new NetconfnodeStateServiceRpcApiImpl(rpcProviderRegistry, vesNotificationListenerList); + + // Get configuration + // ConfigurationFileRepresentation config = new ConfigurationFileRepresentation(CONFIGURATIONFILE); + // Akka setup + AkkaConfig akkaConfig = getAkkaConfig(); + this.isCluster = akkaConfig == null ? false : akkaConfig.isCluster(); + this.clusterName = akkaConfig == null ? "" : akkaConfig.getClusterConfig().getClusterSeedNodeName("abc"); + + // RPC Service for specific services + this.rpcApiService.setStatusCallback(this); + + LOG.debug("start NetconfSubscriptionManager Service"); + //this.netconfChangeListener = new NetconfChangeListener(this, dataBroker); + //this.netconfChangeListener.register(); + //DataTreeIdentifier treeId = new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL, NETCONF_NODE_TOPO_IID); + + listenerL1 = dataBroker.registerDataTreeChangeListener(NETCONF_NODE_TOPO_TREE_ID, new L1()); + listenerL2 = dataBroker.registerDataTreeChangeListener(NETCONF_NODE_TOPO_TREE_ID, new L2()); + + this.initializationSuccessful = true; + + LOG.info("Session Initiated end. Initialization done {}", initializationSuccessful); + + } + /** Blueprint destroy-method method */ + public void destroy() { + close(); + } + + /** + * Getter + * @return NetconfnodeStateServiceRpcApiImpl + */ + public NetconfnodeStateServiceRpcApiImpl getNetconfnodeStateServiceRpcApiImpl() { + return rpcApiService; + } + + @Override + public GetStatusOutputBuilder getStatus(GetStatusInput input) { + return new GetStatusOutputBuilder(); + } + + @Override + public @NonNull ListenerRegistration registerNetconfNodeConnectListener( + final @NonNull L netconfNodeConnectListener) { + LOG.info("Register connect listener {}",netconfNodeConnectListener.getClass().getName()); + netconfNodeConnectListenerList.add(netconfNodeConnectListener); + + return new ListenerRegistration() { + @Override + public @NonNull L getInstance() { + return netconfNodeConnectListener; + } + + @Override + public void close() { + LOG.info("Remove connect listener {}",netconfNodeConnectListener); + netconfNodeConnectListenerList.remove(netconfNodeConnectListener); + } + }; + } + + @Override + public @NonNull ListenerRegistration registerNetconfNodeStateListener( + @NonNull L netconfNodeStateListener) { + LOG.info("Register state listener {}",netconfNodeStateListener.getClass().getName()); + netconfNodeStateListenerList.add(netconfNodeStateListener); + + return new ListenerRegistration() { + @Override + public @NonNull L getInstance() { + return netconfNodeStateListener; + } + + @Override + public void close() { + LOG.info("Remove state listener {}",netconfNodeStateListener); + netconfNodeStateListenerList.remove(netconfNodeStateListener); + } + }; + } + + @Override + public @NonNull ListenerRegistration registerVesNotifications( + @NonNull L vesNotificationListener) { + LOG.info("Register Ves notification listener {}",vesNotificationListener.getClass().getName()); + vesNotificationListenerList.add(vesNotificationListener); + + return new ListenerRegistration() { + @Override + public @NonNull L getInstance() { + return vesNotificationListener; + } + + @Override + public void close() { + LOG.info("Remove Ves notification listener {}",vesNotificationListener); + vesNotificationListenerList.remove(vesNotificationListener); + } + }; + } + + @Override + public void close() { + LOG.info("Closing start ..."); + try { + close(rpcApiService, listenerL1, listenerL2); + } catch (Exception e) { + LOG.debug("Closing", e); + } + LOG.info("Closing done"); + } + + /** + * Used to close all Services, that should support AutoCloseable Pattern + * + * @param toClose + * @throws Exception + */ + private void close(AutoCloseable... toCloseList) throws Exception { + for (AutoCloseable element : toCloseList) { + if (element != null) { + element.close(); + } + } + } + + /** + * Indication if init() of this bundle successfully done. + * @return true if init() was successful. False if not done or not successful. + */ + public boolean isInitializationSuccessful() { + return this.initializationSuccessful; + } + + /*------------------------------------------------------------------------------------------- + * Functions for interface DeviceManagerService + */ + + /** + * For each mounted device a mountpoint is created and this listener is called. + * Mountpoint was created or existing. Managed device is now fully connected to node/mountpoint. + * @param nNodeId id of the mountpoint + * @param netconfNode mountpoint contents + */ + private void enterConnectedState(NodeId nNodeId, NetconfNode netconfNode) { + + String mountPointNodeName = nNodeId.getValue(); + LOG.info("Starting Event listener on Netconf for mountpoint {}", mountPointNodeName); + + boolean preConditionMissing = false; + if (mountPointService == null) { + preConditionMissing = true; + LOG.warn("No mountservice available."); + } + if (!initializationSuccessful) { + preConditionMissing = true; + LOG.warn("Devicemanager initialization still pending."); + } + if (preConditionMissing) { + return; + } + + if (isNetconfNodeMaster(netconfNode)) { + + InstanceIdentifier instanceIdentifier = NETCONF_TOPO_IID.child(Node.class, + new NodeKey(new NodeId(mountPointNodeName))); + + Optional optionalMountPoint = null; + int timeout = 10000; + while (!(optionalMountPoint = mountPointService.getMountPoint(instanceIdentifier)).isPresent() + && timeout > 0) { + LOG.info("Event listener waiting for mount point for Netconf device :: Name : {}", mountPointNodeName); + sleepMs(1000); + timeout -= 1000; + } + + if (!optionalMountPoint.isPresent()) { + LOG.warn("Event listener timeout while waiting for mount point for Netconf device :: Name : {} ", + mountPointNodeName); + } else { + // Mountpoint is present for sure + MountPoint mountPoint = optionalMountPoint.get(); + // BindingDOMDataBrokerAdapter.BUILDER_FACTORY; + LOG.info("Mountpoint with id: {}", mountPoint.getIdentifier()); + + Optional optionalNetconfNodeDatabroker = mountPoint.getService(DataBroker.class); + + if (!optionalNetconfNodeDatabroker.isPresent()) { + LOG.info("Slave mountpoint {} without databroker", mountPointNodeName); + } else { + LOG.info("Master mountpoint {}", mountPointNodeName); + DataBroker netconfNodeDataBroker = optionalNetconfNodeDatabroker.get(); + + /* + * --> Call Listers for onConnect() Indication + for (all) + */ + netconfNodeConnectListenerList.forEach(item -> { + try { + item.onEnterConnected(nNodeId, netconfNode, netconfNodeDataBroker); + } catch (Exception e) { + LOG.info("Exception during onEnterConnected listener call", e); + } + }); + + LOG.info("Connect indication forwarded for {}", mountPointNodeName); + } + } + } + } + + /** + * Leave the connected status to a non connected or removed status + * @param action that occurred + * @param nNodeId id of the mountpoint + * @param nNode mountpoint contents + */ + private void leaveConnectedState(NodeId nNodeId) { + LOG.info("netconfNode id {}", nNodeId); + netconfNodeConnectListenerList.forEach(item -> { + try { + if (item != null) { + item.onLeaveConnected(nNodeId); + } else { + LOG.warn("Unexpeced null item during onleave"); + } + } catch (Exception e) { + LOG.info("Exception during onLeaveConnected listener call", e); + } + }); + } + + // ---- subclasses for listeners + + /** + * Clustered listener function to select the right node from + * DataObjectModification + */ + private class L1 implements ClusteredDataTreeChangeListener { + @Override + public void onDataTreeChanged(@NonNull Collection> changes) { + LOG.info("L1 TreeChange, changes:{}", changes.size()); + + for (final DataTreeModification change : changes) { + + final DataObjectModification root = change.getRootNode(); + if (LOG.isTraceEnabled()) { + LOG.trace("Handle this modificationType:{} path:{} root:{}", root.getModificationType(), + change.getRootPath(), root); + } + + // Catch potential nullpointer exceptions .. + try { + ModificationType modificationTyp = root.getModificationType(); + Node node = modificationTyp == ModificationType.DELETE ? root.getDataBefore() + : root.getDataAfter(); + NodeId nodeId = node != null ? node.getNodeId() : null; + if (nodeId != null) { + if (nodeId.equals(CONTROLLER)) { + // Do not forward any controller related events to devicemanager + LOG.debug("Stop processing for [{}]", nodeId); + } else { + if (modificationTyp != null) { + switch (modificationTyp) { + case SUBTREE_MODIFIED: // Create or modify sub level node + case WRITE: // Create or modify top level node + // Treat an overwrite as an update + // leaveconnected state.before = connected; state.after != connected + // enterConnected state.after == connected + // => Here create or update by checking root.getDataBefore() != null + + boolean connectedBefore, connectedAfter; + NetconfNode nNodeAfter = getNetconfNode(root.getDataAfter()); + connectedAfter = isConnected(nNodeAfter); + if (root.getDataBefore() != null) { + // It is an update + NetconfNode nodeBefore = getNetconfNode(root.getDataBefore()); + connectedBefore = isConnected(nodeBefore); + } else { + // It is a create + connectedBefore = false; + } + + LOG.info( + "L1 NETCONF Node change with id {} ConnectedBefore {} connectedAfter {} cluster status {} akkaIsCluster", + nodeId, connectedBefore, connectedAfter, + getClusteredConnectionStatus(nNodeAfter), isCluster); + + if (!connectedBefore && connectedAfter) { + netconfNodeStateListenerList.forEach(item -> { + try { + item.onCreated(nodeId, nNodeAfter); + } catch (Exception e) { + LOG.info("Exception during onCreated listener call", e); + } + }); + enterConnectedState(nodeId, nNodeAfter); + } else { + LOG.debug("State change {} {}", connectedBefore, connectedAfter); + if (connectedBefore && !connectedAfter) { + leaveConnectedState(nodeId); + } + netconfNodeStateListenerList.forEach(item -> { + try { + item.onStateChange(nodeId, nNodeAfter); + } catch (Exception e) { + LOG.info("Exception during onStateChange listener call", e); + } + }); + } + // doProcessing(update ? Action.UPDATE : Action.CREATE, nodeId, root); + break; + case DELETE: + // Node removed + // leaveconnected state.before = connected; + leaveConnectedState(nodeId); + netconfNodeStateListenerList.forEach(item -> { + try { + item.onRemoved(nodeId); + } catch (Exception e) { + LOG.info("Exception during onRemoved listener call", e); + } + }); + // doProcessing(Action.REMOVE, nodeId, root); + break; + } + } + } + } + } catch (NullPointerException e) { + LOG.info("Data not available at ", e); + } + } + } + } + + private static @Nullable NetconfNode getNetconfNode(Node node) { + return node != null ? node.augmentation(NetconfNode.class) : null; + } + + private static boolean isConnected(NetconfNode nNode) { + return nNode != null ? ConnectionStatus.Connected.equals(nNode.getConnectionStatus()) : false; + } + + private static @Nullable ClusteredConnectionStatus getClusteredConnectionStatus(NetconfNode node) { + return node != null ? node.getClusteredConnectionStatus() : null; + } + /** + * Normal listener function to select the right node from DataObjectModification + */ + private class L2 implements DataTreeChangeListener { + + @Override + public void onDataTreeChanged(@NonNull Collection> changes) { + LOG.info("L2 TreeChange, changes:{}", changes.size()); + } + } + + /* -- LOG related functions -- */ + + /** Analyze configuration **/ + private static @Nullable AkkaConfig getAkkaConfig() { + AkkaConfig akkaConfig; + try { + akkaConfig = AkkaConfig.load(); + LOG.debug("akka.conf loaded: " + akkaConfig.toString()); + } catch (Exception e1) { + akkaConfig = null; + LOG.warn("problem loading akka.conf: " + e1.getMessage()); + } + if (akkaConfig != null && akkaConfig.isCluster()) { + LOG.info("cluster mode detected"); + if (GeoConfig.fileExists()) { + try { + LOG.debug("try to load geoconfig"); + GeoConfig.load(); + } catch (Exception err) { + LOG.warn("problem loading geoconfig: " + err.getMessage()); + } + } else { + LOG.debug("no geoconfig file found"); + } + } else { + LOG.info("single node mode detected"); + } + return akkaConfig; + } + + private boolean isNetconfNodeMaster(NetconfNode nNode) { + if (this.isCluster) { + LOG.debug("check if me is responsible for node"); + ClusteredConnectionStatus ccs = nNode.getClusteredConnectionStatus(); + @SuppressWarnings("null") + @NonNull String masterNodeName = ccs == null || ccs.getNetconfMasterNode() == null ? "null" : ccs.getNetconfMasterNode(); + LOG.debug("sdnMasterNode=" + masterNodeName + " and sdnMyNode=" + this.clusterName); + if (!masterNodeName.equals(this.clusterName)) { + LOG.debug("netconf change but me is not master for this node"); + return false; + } + } + return true; + } + + + private void sleepMs(int milliseconds) { + try { + Thread.sleep(milliseconds); + } catch (InterruptedException e) { + LOG.debug("Interrupted sleep"); + // Restore interrupted state... + Thread.currentThread().interrupt(); + } + } + + +} diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlAkka/AkkaConfig.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlAkka/AkkaConfig.java new file mode 100644 index 000000000..d0ea0eb69 --- /dev/null +++ b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlAkka/AkkaConfig.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt + * ================================================================================================= + * Copyright (C) 2019 highstreet technologies GmbH 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.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf.odlAkka; + +import java.io.File; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.typesafe.config.Config; +import com.typesafe.config.ConfigFactory; + +public class AkkaConfig { + + @SuppressWarnings("unused") + private static final Logger LOG = LoggerFactory.getLogger(AkkaConfig.class); + + private static final String DEFAULT_FILENAME = "configuration/initial/akka.conf"; + private final String filename; + private ClusterConfig cluserConfig; + + public ClusterConfig getClusterConfig() { + return this.cluserConfig; + } + + private AkkaConfig(String filename) { + this.filename = filename; + } + + public AkkaConfig() { + this(null); + } + + @Override + public String toString() { + return "AkkaConfig [filename=" + filename + ", cluserConfig=" + cluserConfig + "]"; + } + + private void loadFromFile() throws Exception { + Config cfg = ConfigFactory.parseFile(new File(this.filename)); + this.cluserConfig = new ClusterConfig(cfg.getConfig("odl-cluster-data").getConfig("akka").getConfig("cluster")); + } + + public boolean isCluster() { + return this.cluserConfig != null ? this.cluserConfig.isCluster() : false; + } + + public boolean isClusterAndFirstNode() { + return isSingleNode() || isCluster() && getClusterConfig().getRoleMemberIndex() == 1; + } + + public static AkkaConfig load() throws Exception { + return load(DEFAULT_FILENAME); + } + + public static AkkaConfig load(String filename) throws Exception { + AkkaConfig cfg = new AkkaConfig(filename); + cfg.loadFromFile(); + return cfg; + } + + public boolean isSingleNode() { + return !this.isCluster(); + } + public static AkkaConfig parse(String content) throws Exception { + Config cfg = ConfigFactory.parseString(content); + AkkaConfig c = new AkkaConfig(); + c.cluserConfig=new ClusterConfig(cfg.getConfig("odl-cluster-data").getConfig("akka").getConfig("cluster")); + return c; + } +} diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlAkka/ClusterConfig.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlAkka/ClusterConfig.java new file mode 100644 index 000000000..bdde30828 --- /dev/null +++ b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlAkka/ClusterConfig.java @@ -0,0 +1,137 @@ +/******************************************************************************* + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt + * ================================================================================================= + * Copyright (C) 2019 highstreet technologies GmbH 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.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf.odlAkka; + +import java.util.ArrayList; +import java.util.List; + +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf.odlGeo.ClusterRoleInfo; +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf.odlGeo.ClusterRoleInfoCollection; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.typesafe.config.Config; + +public class ClusterConfig { + + private static final Logger LOG = LoggerFactory.getLogger(ClusterConfig.class); + + private final List seedNodes; + private final ClusterRoleInfoCollection roles; + private ClusterNodeInfo ismeInfo; + + public static ClusterConfig defaultSingleNodeConfig() + { + ClusterConfig cfg=new ClusterConfig(); + cfg.ismeInfo=ClusterNodeInfo.defaultSingleNodeInfo(); + cfg.seedNodes.add(cfg.ismeInfo); + cfg.roles.add(ClusterRoleInfo.defaultSingleNodeRole()); + return cfg; + } + public ClusterConfig() + { + this.seedNodes = new ArrayList<>(); + this.roles = new ClusterRoleInfoCollection(); + + } + public ClusterConfig(Config o) throws Exception { + { + this.seedNodes = new ArrayList<>(); + this.roles = new ClusterRoleInfoCollection(); + List a = o.getStringList("seed-nodes"); + for (int i = 0; i < a.size(); i++) { + ClusterNodeInfo info = new ClusterNodeInfo(a.get(i)); + this.seedNodes.add(info); + } + a = o.getStringList("roles"); + for (int i = 0; i < a.size(); i++) { + ClusterRoleInfo s = new ClusterRoleInfo(a.get(i)); + this.roles.add(s); + } + int idx = this.roles.get(0).getIndex() - 1; + if (idx >= 0 && idx < this.seedNodes.size()) { + this.ismeInfo = this.seedNodes.get(idx); + } else { + this.ismeInfo = null; + } + } + + } + + public boolean isCluster() { + return this.seedNodes != null ? this.seedNodes.size() > 1 : false; + } + + public boolean isMe(ClusterNodeInfo i) { + return this.ismeInfo != null ? this.ismeInfo.equals(i) : false; + } + + public List getSeedNodes() { + return this.seedNodes; + } + + public String getHostName(String defaultValue) { + if (getRoleMemberIndex() > 0 && getRoleMemberIndex() <= seedNodes.size()) { + return this.seedNodes.get(getRoleMemberIndex()-1).getRemoteAddress(); + } else { + LOG.warn("Seednode not available for roleMemberIndex {}. Using default {}",getRoleMember(), defaultValue); + return defaultValue; + } + } + + public String getDBClusterName(String defaultValue) { + String r = null; + if (this.seedNodes != null && this.seedNodes.size() > 0) { + r = String.format("cluster-%s.%d", this.seedNodes.get(0).getRemoteAddress(), this.seedNodes.get(0).getPort()); + } + if (r == null || r.isEmpty()) { + r = defaultValue; + } + return r; + } + public String getClusterSeedNodeName() { + return this.getClusterSeedNodeName(""); + } + public String getClusterSeedNodeName(String defaultValue) { + int idx=this.getRoleMemberIndex()-1; + String r=null; + if(this.seedNodes!=null && idx>=0 && this.seedNodes.size()>0 && this.seedNodes.size()>idx) + { + r=this.seedNodes.get(idx).getSeedNodeName(); + } + if (r == null || r.isEmpty()) { + r = defaultValue; + } + return r; + } + public int getRoleMemberIndex() { + + ClusterRoleInfo role=this.roles.get("member"); + return role!=null?role.getIndex():0; + } + public ClusterRoleInfo getRoleMember() { + return this.roles.get("member"); + } + + @Override + public String toString() { + return "ClusterConfig [seedNodes=" + seedNodes + ", roles=" + roles + ", ismeInfo=" + ismeInfo + "]"; + } + + +} diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlAkka/ClusterNodeInfo.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlAkka/ClusterNodeInfo.java new file mode 100644 index 000000000..ef161ad12 --- /dev/null +++ b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlAkka/ClusterNodeInfo.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt + * ================================================================================================= + * Copyright (C) 2019 highstreet technologies GmbH 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.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf.odlAkka; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class ClusterNodeInfo { + private final String protocol; + private final String clusterName; + private final String remoteAdr; + private final int port; + private final String seedNodeName; + + public static ClusterNodeInfo defaultSingleNodeInfo() { + return new ClusterNodeInfo("akka.tcp","opendaylight-cluster-data","127.0.0.1",2550); + } + + public ClusterNodeInfo(String s) throws Exception { + final String regex = "([a-z.]*):\\/\\/([a-zA-Z0-9-]*)@([a-zA-Z0-9.-]*):([0-9]*)"; + final Pattern pattern = Pattern.compile(regex); + final Matcher matcher = pattern.matcher(s); + if (!matcher.find()) { + throw new Exception("invalid seedNode format"); + } + this.seedNodeName = matcher.group(); + this.protocol = matcher.group(1); + this.clusterName = matcher.group(2); + this.remoteAdr = matcher.group(3); + this.port = Integer.parseInt(matcher.group(4)); + } + + public ClusterNodeInfo(String protocol, String clustername, String remoteadr, int port) { + this.protocol=protocol; + this.clusterName=clustername; + this.remoteAdr=remoteadr; + this.port=port; + this.seedNodeName=this.protocol+"://"+this.clusterName+"@"+this.remoteAdr+":"+this.port; + } + + public String getProtocol() { + return protocol; + } + + public String getClusterName() { + return clusterName; + } + + public String getRemoteAddress() { + return remoteAdr; + } + public String getSeedNodeName() { + return seedNodeName; + } + + public int getPort() { + return port; + } + + @Override + public String toString() { + return "ClusterNodeInfo [protocol=" + protocol + ", clusterName=" + clusterName + ", remoteAdr=" + remoteAdr + + ", port=" + port + ", seedNodeName=" + seedNodeName + "]"; + } + +} diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlGeo/ClusterRoleInfo.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlGeo/ClusterRoleInfo.java new file mode 100644 index 000000000..994ef548b --- /dev/null +++ b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlGeo/ClusterRoleInfo.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt + * ================================================================================================= + * Copyright (C) 2019 highstreet technologies GmbH 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.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf.odlGeo; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class ClusterRoleInfo { + private final String Role; + private final int Index; + + public ClusterRoleInfo(String s) throws Exception { + final String regex = "([a-zA-Z]*)-([0-9]*)"; + final Pattern pattern = Pattern.compile(regex); + final Matcher matcher = pattern.matcher(s); + if (!matcher.find()) { + throw new Exception("unexpected role format:"+s); + } + this.Role = matcher.group(1); + this.Index = Integer.parseInt(matcher.group(2)); + } + + private ClusterRoleInfo(String role, int idx) { + this.Role=role; + this.Index=idx; + } + + public static ClusterRoleInfo defaultSingleNodeRole() { + return new ClusterRoleInfo("member",1); + } + + public String getRole() { + return Role; + } + public int getIndex() { + return Index; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + Index; + result = prime * result + (Role == null ? 0 : Role.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + ClusterRoleInfo other = (ClusterRoleInfo) obj; + if (Index != other.Index) { + return false; + } + if (Role == null) { + if (other.Role != null) { + return false; + } + } else if (!Role.equals(other.Role)) { + return false; + } + return true; + } + @Override + public String toString() { + return "ClusterRoleInfo [Role=" + Role + ", Index=" + Index + "]"; + } +} diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlGeo/ClusterRoleInfoCollection.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlGeo/ClusterRoleInfoCollection.java new file mode 100644 index 000000000..478ed8394 --- /dev/null +++ b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlGeo/ClusterRoleInfoCollection.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt + * ================================================================================================= + * Copyright (C) 2019 highstreet technologies GmbH 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.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf.odlGeo; + +import java.util.ArrayList; + +public class ClusterRoleInfoCollection extends ArrayList { + private static final long serialVersionUID = 1L; + + public ClusterRoleInfo get(String role) { + for (ClusterRoleInfo info : this) { + if (info.getRole().equals(role)) { + return info; + } + } + return null; + } + + public boolean contains(ClusterRoleInfo info) { + if (info == null) { + return false; + } + for (ClusterRoleInfo i : this) { + if (i.equals(info)) { + return true; + } + } + return false; + } +} diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlGeo/GeoConfig.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlGeo/GeoConfig.java new file mode 100644 index 000000000..c25f3264b --- /dev/null +++ b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/odlGeo/GeoConfig.java @@ -0,0 +1,162 @@ +/******************************************************************************* + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt + * ================================================================================================= + * Copyright (C) 2019 highstreet technologies GmbH 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.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf.odlGeo; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import com.typesafe.config.Config; +import com.typesafe.config.ConfigFactory; + +public class GeoConfig { + + private static final String DEFAULT_FILENAME = "configuration/initial/geo.conf"; + private static final String LUMINA_ROOTNODENAME = "lumina-geo-cluster"; + private final String filename; + private final String rootNodename; + private ClusterRoleInfoCollection primaryRoles; + private ClusterRoleInfoCollection secondayRoles; + private RolesTable rolesTable; + + private GeoConfig() { + this(null); + } + + private GeoConfig(String filename) { + this(filename, LUMINA_ROOTNODENAME); + } + + private GeoConfig(String filename, String rootNodeName) { + this.filename = filename; + this.rootNodename = rootNodeName; + } + + public static boolean fileExists() { + File f = new File(DEFAULT_FILENAME); + return f.exists(); + } + + public static GeoConfig load() throws Exception { + return load(DEFAULT_FILENAME); + } + + public static GeoConfig load(String filename) throws Exception { + GeoConfig cfg = new GeoConfig(filename); + cfg._load(); + return cfg; + } + + private void _load() throws Exception { + this._load(ConfigFactory.parseFile(new File(this.filename))); + } + + private void _load(Config cfg) throws Exception { + this.primaryRoles = new ClusterRoleInfoCollection(); + List a = cfg.getConfig(this.rootNodename).getStringList("primary_roles"); + + for (int i = 0; i < a.size(); i++) { + ClusterRoleInfo s = new ClusterRoleInfo(a.get(i)); + this.primaryRoles.add(s); + } + this.secondayRoles = new ClusterRoleInfoCollection(); + a = cfg.getConfig(this.rootNodename).getStringList("secondary_roles"); + for (int i = 0; i < a.size(); i++) { + ClusterRoleInfo s = new ClusterRoleInfo(a.get(i)); + this.secondayRoles.add(s); + } + this.checkDuplicateRoleEntries(); + this.rolesTable = new RolesTable(cfg.getConfig(this.rootNodename).getConfigList("ip_roles_table")); + } + + private void checkDuplicateRoleEntries() throws Exception { + ClusterRoleInfoCollection duplicateEntries = new ClusterRoleInfoCollection(); + for (ClusterRoleInfo primaryRole : this.primaryRoles) { + if (this.secondayRoles.contains(primaryRole)) { + duplicateEntries.add(primaryRole); + } + } + if (duplicateEntries.size() > 0) { + throw new Exception("duplicate entries found: " + duplicateEntries.toString()); + } + + } + + public static GeoConfig parse(String content) throws Exception { + GeoConfig cfg = new GeoConfig(); + cfg._load(ConfigFactory.parseString(content)); + return cfg; + } + + public ClusterRoleInfoCollection getPrimaryRoles() { + return this.primaryRoles; + } + + public ClusterRoleInfoCollection getSecondaryRoles() { + return this.secondayRoles; + } + + public boolean isPrimary(ClusterRoleInfo roleMember) { + return !this.isSecondary(roleMember); + } + + private boolean isSecondary(ClusterRoleInfo roleMember) { + if (roleMember == null) { + return false; + } + for (ClusterRoleInfo info : this.secondayRoles) { + if (info.equals(roleMember)) { + return true; + } + } + return false; + } + + @Override + public String toString() { + return "GeoConfig [filename=" + filename + ", rootNodename=" + rootNodename + ", primaryRoles=" + primaryRoles + + ", secondayRoles=" + secondayRoles + ", rolesTable=" + rolesTable + "]"; + } + + public static class RolesTableEntry { + private final ClusterRoleInfo role; + private final String ip; + + public RolesTableEntry(Config c) throws Exception { + this.role = new ClusterRoleInfo(c.getString("role")); + this.ip = c.getString("ip"); + } + + @Override + public String toString() { + return "RolesTableEntry [role=" + role + ", ip=" + ip + "]"; + } + } + public static class RolesTable extends ArrayList { + private static final long serialVersionUID = -9146218864237487506L; + + public RolesTable(List configList) throws Exception { + for (Config c : configList) { + this.add(new RolesTableEntry(c)); + } + } + + } + + +} diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/rpc/NetconfnodeStateServiceRpcApiImpl.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/rpc/NetconfnodeStateServiceRpcApiImpl.java new file mode 100644 index 000000000..9215887ff --- /dev/null +++ b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/rpc/NetconfnodeStateServiceRpcApiImpl.java @@ -0,0 +1,126 @@ +/******************************************************************************* + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt + * ================================================================================================= + * Copyright (C) 2019 highstreet technologies GmbH 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.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.rpc; + +import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.VesNotificationListener; +import org.opendaylight.mdsal.binding.api.RpcProviderService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.AttributeChangeNotificationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.FaultNotificationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.GetStatusInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.GetStatusOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.GetStatusOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.NetconfnodeStateService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.PushAttributeChangeNotificationInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.PushAttributeChangeNotificationOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.PushFaultNotificationInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.PushFaultNotificationOutput; +import org.opendaylight.yangtools.concepts.ObjectRegistration; +import org.opendaylight.yangtools.yang.common.RpcError.ErrorType; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.common.RpcResultBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.util.concurrent.ListenableFuture; +import java.util.List; + +public class NetconfnodeStateServiceRpcApiImpl implements NetconfnodeStateService, AutoCloseable { + + private static final Logger LOG = LoggerFactory.getLogger(NetconfnodeStateServiceRpcApiImpl.class); + + private final ObjectRegistration rpcReg; + private RpcApigetStateCallback getStatusCallback; + private final List vesNotificationListenerList; + + public NetconfnodeStateServiceRpcApiImpl(final RpcProviderService rpcProviderRegistry, + List vesNotificationListenerList) { + + this.vesNotificationListenerList = vesNotificationListenerList; + + // Register ourselves as the REST API RPC implementation + LOG.info("Register RPC Service " + NetconfnodeStateService.class.getSimpleName()); + rpcReg = rpcProviderRegistry.registerRpcImplementation(NetconfnodeStateService.class, this); + this.getStatusCallback = null; + } + + public NetconfnodeStateServiceRpcApiImpl setStatusCallback(RpcApigetStateCallback getStatusCallback) { + this.getStatusCallback = getStatusCallback; + return this; + } + + @Override + public void close() throws Exception { + LOG.info("Close RPC Service"); + if (rpcReg != null) { + rpcReg.close(); + } + } + + /*------------------------------- + * Interfaces for getting information + */ + @Override + public ListenableFuture> getStatus(GetStatusInput input) { + + LOG.info("RPC Request: getStatus input: {}", input); + RpcResultBuilder result; + + try { + GetStatusOutputBuilder outputBuilder = new GetStatusOutputBuilder(); + getStatusCallback.getStatus(input); + result = RpcResultBuilder.success(outputBuilder); + } catch (Exception e) { + result = RpcResultBuilder.failed(); + result.withError(ErrorType.APPLICATION, "Exception", e); + } + return result.buildFuture(); + } + + @Override + public ListenableFuture> pushFaultNotification( + PushFaultNotificationInput input) { + + RpcResultBuilder result; + try { + FaultNotificationBuilder faultNotificationBuilder = new FaultNotificationBuilder(); + faultNotificationBuilder.fieldsFrom(input); + vesNotificationListenerList.forEach(item -> item.onNotification(faultNotificationBuilder.build())); + result = RpcResultBuilder.success(); + } catch (Exception e) { + result = RpcResultBuilder.failed(); + result.withError(ErrorType.APPLICATION, "Exception", e); + } + return result.buildFuture(); + } + + @Override + public ListenableFuture> pushAttributeChangeNotification( + PushAttributeChangeNotificationInput input) { + RpcResultBuilder result; + try { + AttributeChangeNotificationBuilder attributeChangeNotificationBuilder = new AttributeChangeNotificationBuilder(); + attributeChangeNotificationBuilder.fieldsFrom(input); + vesNotificationListenerList.forEach(item -> item.onNotification(attributeChangeNotificationBuilder.build())); + result = RpcResultBuilder.success(); + } catch (Exception e) { + result = RpcResultBuilder.failed(); + result.withError(ErrorType.APPLICATION, "Exception", e); + } + return result.buildFuture(); + } +} diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/rpc/RpcApigetStateCallback.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/rpc/RpcApigetStateCallback.java new file mode 100644 index 000000000..1434cf41a --- /dev/null +++ b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/rpc/RpcApigetStateCallback.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt + * ================================================================================================= + * Copyright (C) 2019 highstreet technologies GmbH 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.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.rpc; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.GetStatusInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.GetStatusOutputBuilder; + +public interface RpcApigetStateCallback { + + GetStatusOutputBuilder getStatus(GetStatusInput input); +} diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/resources/org/opendaylight/blueprint/impl-blueprint.xml b/sdnr/wt/netconfnode-state-service/provider/src/main/resources/org/opendaylight/blueprint/impl-blueprint.xml new file mode 100644 index 000000000..46930ac9e --- /dev/null +++ b/sdnr/wt/netconfnode-state-service/provider/src/main/resources/org/opendaylight/blueprint/impl-blueprint.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/resources/version.properties b/sdnr/wt/netconfnode-state-service/provider/src/main/resources/version.properties new file mode 100644 index 000000000..80373399e --- /dev/null +++ b/sdnr/wt/netconfnode-state-service/provider/src/main/resources/version.properties @@ -0,0 +1,3 @@ +# Proberties filled in by maven during build process +version = ${project.version} +build = ${buildtime} -- cgit 1.2.3-korg