c924f8749e770b8d246dfed9c02025b8cb695bb5
[bgpcep.git] / pcep / topology / topology-provider / src / main / java / org / opendaylight / bgpcep / pcep / topology / provider / TopologyStatsRpc.java
1 /*
2  * Copyright (c) 2019 Lumina Networks, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.bgpcep.pcep.topology.provider;
9
10 import com.google.common.annotations.VisibleForTesting;
11 import com.google.common.collect.ImmutableClassToInstanceMap;
12 import com.google.common.util.concurrent.Futures;
13 import com.google.common.util.concurrent.ListenableFuture;
14 import java.util.Collection;
15 import java.util.List;
16 import java.util.concurrent.ConcurrentHashMap;
17 import java.util.concurrent.ConcurrentMap;
18 import java.util.stream.Collectors;
19 import org.opendaylight.bgpcep.programming.spi.SuccessfulRpcResult;
20 import org.opendaylight.mdsal.binding.api.ClusteredDataTreeChangeListener;
21 import org.opendaylight.mdsal.binding.api.DataBroker;
22 import org.opendaylight.mdsal.binding.api.DataObjectModification;
23 import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
24 import org.opendaylight.mdsal.binding.api.DataTreeModification;
25 import org.opendaylight.mdsal.binding.api.RpcProviderService;
26 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stateful.stats.rev181109.PcepEntityIdRpcAugBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stateful.stats.rev181109.PcepEntityIdStatsAug;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stateful.stats.rev181109.StatefulCapabilitiesRpcAugBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stateful.stats.rev181109.StatefulCapabilitiesStatsAug;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stateful.stats.rev181109.StatefulMessagesRpcAugBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stateful.stats.rev181109.StatefulMessagesStatsAug;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stats.rev171113.pcep.session.state.LocalPref;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stats.rev171113.pcep.session.state.LocalPrefBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stats.rev171113.pcep.session.state.Messages;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stats.rev171113.pcep.session.state.MessagesBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stats.rev171113.pcep.session.state.PeerCapabilities;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stats.rev171113.pcep.session.state.PeerCapabilitiesBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stats.rev171113.pcep.session.state.grouping.PcepSessionState;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.stats.rev171113.pcep.session.state.grouping.PcepSessionStateBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats.rpc.rev190321.GetStats;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats.rpc.rev190321.GetStatsInput;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats.rpc.rev190321.GetStatsOutput;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats.rpc.rev190321.GetStatsOutputBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.stats.rev181109.PcepTopologyNodeStatsAug;
46 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
47 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
48 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
49 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
50 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
51 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
52 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
53 import org.opendaylight.yangtools.concepts.Registration;
54 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
55 import org.opendaylight.yangtools.yang.binding.util.BindingMap;
56 import org.opendaylight.yangtools.yang.common.RpcResult;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59
60 final class TopologyStatsRpc implements ClusteredDataTreeChangeListener<PcepSessionState>, AutoCloseable {
61     private static final Logger LOG = LoggerFactory.getLogger(TopologyStatsRpc.class);
62
63     private final ConcurrentMap<InstanceIdentifier<PcepSessionState>, PcepSessionState> sessionStateMap =
64             new ConcurrentHashMap<>();
65     private Registration listenerRegistration;
66     private Registration rpcRegistration;
67
68     TopologyStatsRpc(final DataBroker dataBroker, final RpcProviderService rpcProviderService) {
69         LOG.info("Initializing PCEP Topology Stats RPC service.");
70         listenerRegistration = dataBroker.registerDataTreeChangeListener(
71             DataTreeIdentifier.create(LogicalDatastoreType.OPERATIONAL,
72                 InstanceIdentifier.builder(NetworkTopology.class).child(Topology.class).child(Node.class)
73                     .augmentation(PcepTopologyNodeStatsAug.class).child(PcepSessionState.class).build()),
74             this);
75         rpcRegistration = rpcProviderService.registerRpcImplementations(ImmutableClassToInstanceMap.of(
76             GetStats.class, this::getStats));
77     }
78
79     @Override
80     public void onDataTreeChanged(final Collection<DataTreeModification<PcepSessionState>> changes) {
81         changes.forEach(change -> {
82             final InstanceIdentifier<PcepSessionState> iid = change.getRootPath().getRootIdentifier();
83             final DataObjectModification<PcepSessionState> mod = change.getRootNode();
84             switch (mod.getModificationType()) {
85                 case SUBTREE_MODIFIED:
86                 case WRITE:
87                     sessionStateMap.put(iid, mod.getDataAfter());
88                     break;
89                 case DELETE:
90                     sessionStateMap.remove(iid);
91                     break;
92                 default:
93             }
94         });
95     }
96
97     @Override
98     public synchronized void close() {
99         if (rpcRegistration != null) {
100             rpcRegistration.close();
101             rpcRegistration = null;
102         }
103         if (listenerRegistration != null) {
104             LOG.info("Closing PCEP Topology Stats RPC service.");
105             listenerRegistration.close();
106             listenerRegistration = null;
107         }
108     }
109
110     @VisibleForTesting
111     ListenableFuture<RpcResult<GetStatsOutput>> getStats(final GetStatsInput input) {
112         final var iTopologies = input.getTopology();
113         final List<TopologyId> iTopologyIds;
114         if (iTopologies != null) {
115             iTopologyIds = iTopologies.values().stream()
116                     .map(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats.rpc
117                         .rev190321.get.stats.input.Topology::getTopologyId)
118                     .collect(Collectors.toList());
119         } else {
120             iTopologyIds = getAvailableTopologyIds();
121         }
122
123         return Futures.immediateFuture(SuccessfulRpcResult.create(new GetStatsOutputBuilder()
124             .setTopology(iTopologyIds.stream()
125                 .map(iTopologyId -> {
126                     final Collection<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology
127                         .stats.rpc.rev190321.get.stats.input.topology.Node> iNodes;
128                     if (iTopologies != null) {
129                         final var nodes = iTopologies.values().stream()
130                             .filter(t -> iTopologyId.equals(t.getTopologyId()))
131                             .findFirst()
132                             .orElseThrow().getNode();
133                         iNodes = nodes != null ? nodes.values() : null;
134                     } else {
135                         iNodes = null;
136                     }
137
138                     final List<NodeId> iNodeIds;
139                     if (iNodes != null) {
140                         iNodeIds = iNodes.stream()
141                             .map(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats
142                                 .rpc.rev190321.get.stats.input.topology.Node::getNodeId)
143                             .collect(Collectors.toList());
144                     } else {
145                         iNodeIds = getAvailableNodeIds(iTopologyId);
146                     }
147
148                     return new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.topology.stats.rpc
149                         .rev190321.get.stats.output.TopologyBuilder()
150                         .setTopologyId(iTopologyId)
151                         .setNode(iNodeIds.stream()
152                             .map(iNodeId -> {
153                                 final PcepSessionState state = sessionStateMap.get(
154                                     InstanceIdentifier.builder(NetworkTopology.class)
155                                         .child(Topology.class, new TopologyKey(iTopologyId))
156                                         .child(Node.class, new NodeKey(iNodeId))
157                                         .augmentation(PcepTopologyNodeStatsAug.class)
158                                         .child(PcepSessionState.class)
159                                         .build());
160                                 if (state == null) {
161                                     LOG.debug("Pcep session stats not available for node {} in topology {}",
162                                         iNodeId.getValue(), iTopologyId.getValue());
163                                 }
164                                 return new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep
165                                     .topology.stats.rpc.rev190321.get.stats.output.topology.NodeBuilder()
166                                     .setNodeId(iNodeId)
167                                     .setPcepSessionState(transformStatefulAugmentation(state))
168                                     .build();
169                             })
170                             .collect(BindingMap.toOrderedMap()))
171                         .build();
172                 })
173                 .collect(BindingMap.toOrderedMap()))
174             .build()));
175     }
176
177     /*
178      * Replace stateful topology augmentations with ones for rpc in PCEP session
179      * stats data
180      */
181     private static PcepSessionState transformStatefulAugmentation(final PcepSessionState pcepSessionState) {
182         if (pcepSessionState == null) {
183             return null;
184         }
185
186         final PcepSessionStateBuilder sb = new PcepSessionStateBuilder(pcepSessionState);
187
188         final Messages topoMessage = pcepSessionState.getMessages();
189         if (topoMessage != null) {
190             final StatefulMessagesStatsAug messageStatsAug = topoMessage.augmentation(StatefulMessagesStatsAug.class);
191             if (messageStatsAug != null) {
192                 sb.setMessages(new MessagesBuilder(topoMessage)
193                     .removeAugmentation(StatefulMessagesStatsAug.class)
194                         .addAugmentation(new StatefulMessagesRpcAugBuilder()
195                             .setLastReceivedRptMsgTimestamp(messageStatsAug.getLastReceivedRptMsgTimestamp())
196                             .setReceivedRptMsgCount(messageStatsAug.getReceivedRptMsgCount())
197                             .setSentInitMsgCount(messageStatsAug.getSentInitMsgCount())
198                             .setSentUpdMsgCount(messageStatsAug.getSentUpdMsgCount())
199                             .build())
200                         .build());
201             }
202         }
203
204         final PeerCapabilities topoPeerCapability = pcepSessionState.getPeerCapabilities();
205         if (topoPeerCapability != null) {
206             final StatefulCapabilitiesStatsAug capabilityStatsAug =
207                     topoPeerCapability.augmentation(StatefulCapabilitiesStatsAug.class);
208             if (capabilityStatsAug != null) {
209                 sb.setPeerCapabilities(new PeerCapabilitiesBuilder(topoPeerCapability)
210                         .removeAugmentation(StatefulCapabilitiesStatsAug.class)
211                         .addAugmentation(new StatefulCapabilitiesRpcAugBuilder()
212                             .setActive(capabilityStatsAug.getActive())
213                             .setInstantiation(capabilityStatsAug.getInstantiation())
214                             .setStateful(capabilityStatsAug.getStateful())
215                             .build())
216                         .build());
217             }
218         }
219
220         final LocalPref topoLocalPref = pcepSessionState.getLocalPref();
221         if (topoLocalPref != null) {
222             final PcepEntityIdStatsAug entityStatsAug = topoLocalPref.augmentation(PcepEntityIdStatsAug.class);
223             if (entityStatsAug != null) {
224                 sb.setLocalPref(new LocalPrefBuilder(topoLocalPref)
225                     .removeAugmentation(PcepEntityIdStatsAug.class)
226                     .addAugmentation(new PcepEntityIdRpcAugBuilder()
227                             .setSpeakerEntityIdValue(entityStatsAug.getSpeakerEntityIdValue())
228                             .build())
229                     .build());
230             }
231         }
232
233         return sb.build();
234     }
235
236     private List<TopologyId> getAvailableTopologyIds() {
237         return sessionStateMap.keySet().stream().map(iid -> iid.firstKeyOf(Topology.class).getTopologyId()).distinct()
238                 .collect(Collectors.toList());
239     }
240
241     private List<NodeId> getAvailableNodeIds(final TopologyId topologyId) {
242         return sessionStateMap.keySet().stream()
243                 .filter(iid -> iid.firstKeyOf(Topology.class).getTopologyId().equals(topologyId))
244                 .map(iid -> iid.firstKeyOf(Node.class).getNodeId()).collect(Collectors.toList());
245     }
246 }