MRI version bump for Aluminium
[genius.git] / cloudscaler / impl / src / main / java / org / opendaylight / genius / cloudscaler / rpcservice / ComputeNodeManager.java
1 /*
2  * Copyright (c) 2019 Ericsson India Global Services Pvt Ltd. 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.genius.cloudscaler.rpcservice;
9
10 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
11 import java.util.Map;
12 import java.util.Objects;
13 import java.util.Optional;
14 import java.util.concurrent.ConcurrentHashMap;
15 import java.util.concurrent.ExecutionException;
16 import java.util.concurrent.ExecutorService;
17 import javax.inject.Inject;
18 import javax.inject.Singleton;
19 import org.eclipse.jdt.annotation.NonNull;
20 import org.opendaylight.genius.mdsalutil.cache.InstanceIdDataObjectCache;
21 import org.opendaylight.infrautils.caches.CacheProvider;
22 import org.opendaylight.infrautils.utils.concurrent.Executors;
23 import org.opendaylight.mdsal.binding.api.DataBroker;
24 import org.opendaylight.mdsal.binding.api.ReadWriteTransaction;
25 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
26 import org.opendaylight.mdsal.common.api.ReadFailedException;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.cloudscaler.rpcs.rev171220.ComputeNodes;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.cloudscaler.rpcs.rev171220.compute.nodes.ComputeNode;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.cloudscaler.rpcs.rev171220.compute.nodes.ComputeNodeBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.cloudscaler.rpcs.rev171220.compute.nodes.ComputeNodeKey;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.BridgeOtherConfigs;
33 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
34 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
35 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
36 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
37 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
38 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
39 import org.opendaylight.yangtools.yang.common.Uint64;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43 @Singleton
44 public class ComputeNodeManager {
45
46     private static final Logger LOG = LoggerFactory.getLogger("GeniusEventLogger");
47
48     private final DataBroker dataBroker;
49
50     private final InstanceIdDataObjectCache<ComputeNode> computeNodeCache;
51     private final InstanceIdDataObjectCache<Node> ovsdbTopologyNodeCache;
52     private final Map<Uint64, ComputeNode> dpnIdVsComputeNode;
53     // FIXME: this service is never shut down
54     private final ExecutorService executorService = Executors.newSingleThreadExecutor("compute-node-manager", LOG);
55
56     @Inject
57     @SuppressFBWarnings({"URF_UNREAD_FIELD", "NP_LOAD_OF_KNOWN_NULL_VALUE"})
58     public ComputeNodeManager(DataBroker dataBroker,
59                               CacheProvider cacheProvider) {
60         this.dataBroker = dataBroker;
61         this.dpnIdVsComputeNode = new ConcurrentHashMap<>();
62         this.computeNodeCache = new InstanceIdDataObjectCache<>(ComputeNode.class, dataBroker,
63                 LogicalDatastoreType.CONFIGURATION,
64                 InstanceIdentifier.builder(ComputeNodes.class).child(ComputeNode.class).build(),
65                 cacheProvider) {
66             @Override
67             protected void added(InstanceIdentifier<ComputeNode> path, ComputeNode computeNode) {
68                 LOG.info("ComputeNodeManager add compute {}", computeNode);
69                 dpnIdVsComputeNode.put(computeNode.getDpnid(), computeNode);
70             }
71
72             @Override
73             protected void removed(InstanceIdentifier<ComputeNode> path, ComputeNode computeNode) {
74                 LOG.info("ComputeNodeManager remove compute {}", computeNode);
75                 dpnIdVsComputeNode.remove(computeNode.getDpnid());
76             }
77         };
78         this.ovsdbTopologyNodeCache = new InstanceIdDataObjectCache<>(Node.class, dataBroker,
79                 LogicalDatastoreType.OPERATIONAL,
80                 getWildcardPath(),
81                 cacheProvider) {
82             @Override
83             @SuppressWarnings("checkstyle:IllegalCatch")
84             protected void added(InstanceIdentifier<Node> path, Node dataObject) {
85                 executorService.execute(() -> {
86                     try {
87                         add(dataObject);
88                     } catch (Exception e) {
89                         LOG.error("ComputeNodeManager Failed to handle ovsdb node add", e);
90                     }
91                 });
92             }
93         };
94         //LOG.info("Compute node manager is initialized ");
95     }
96
97     public ComputeNode getComputeNodeFromName(String computeName) throws ReadFailedException {
98         InstanceIdentifier<ComputeNode> computeIid = buildComputeNodeIid(computeName);
99         return computeNodeCache.get(computeIid).orElse(null);
100     }
101
102     public void deleteComputeNode(ReadWriteTransaction tx, ComputeNode computeNode) {
103         tx.delete(LogicalDatastoreType.CONFIGURATION, buildComputeNodeIid(computeNode.getComputeName()));
104     }
105
106     public void add(@NonNull Node node) throws ExecutionException, InterruptedException {
107         OvsdbBridgeAugmentation bridgeAugmentation = node.augmentation(OvsdbBridgeAugmentation.class);
108         if (bridgeAugmentation != null && bridgeAugmentation.getBridgeOtherConfigs() != null) {
109             Uint64 datapathid = getDpnIdFromBridge(bridgeAugmentation);
110             Optional<BridgeOtherConfigs> otherConfigOptional = bridgeAugmentation.getBridgeOtherConfigs().values()
111                     .stream()
112                     .filter(otherConfig -> otherConfig.getBridgeOtherConfigKey().equals("dp-desc"))
113                     .findFirst();
114             if (!otherConfigOptional.isPresent()) {
115                 LOG.debug("ComputeNodeManager Compute node name is not present in bridge {}", node.getNodeId());
116                 return;
117             }
118             String computeName = otherConfigOptional.get().getBridgeOtherConfigValue();
119             String nodeId = node.getNodeId().getValue();
120             InstanceIdentifier<ComputeNode> computeIid = buildComputeNodeIid(computeName);
121             ComputeNode computeNode = new ComputeNodeBuilder()
122                     .setComputeName(computeName)
123                     .setDpnid(datapathid)
124                     .setNodeid(nodeId)
125                     .build();
126             Optional<ComputeNode> computeNodeOptional = Optional.empty();
127             try {
128                 computeNodeOptional = computeNodeCache.get(computeIid);
129             } catch (ReadFailedException e) {
130                 LOG.error("ComputeNodeManager Failed to read {}", computeIid);
131             }
132             if (computeNodeOptional.isPresent()) {
133                 logErrorIfComputeNodeIsAlreadyTaken(datapathid, nodeId, computeNodeOptional);
134             } else {
135                 LOG.info("ComputeNodeManager add ovsdb node {}", node.getNodeId());
136                 putComputeDetailsInConfigDatastore(computeIid, computeNode);
137             }
138         }
139     }
140
141     public InstanceIdentifier<ComputeNode> buildComputeNodeIid(String computeName) {
142         return InstanceIdentifier.builder(ComputeNodes.class)
143                 .child(ComputeNode.class, new ComputeNodeKey(computeName))
144                 .build();
145     }
146
147     private Uint64 getDpnIdFromBridge(OvsdbBridgeAugmentation bridgeAugmentation) {
148         if (bridgeAugmentation.getDatapathId() == null) {
149             return Uint64.ZERO;
150         }
151         String datapathIdStr = bridgeAugmentation.getDatapathId().getValue() != null
152                 ? bridgeAugmentation.getDatapathId().getValue().replace(":", "") : null;
153         return datapathIdStr != null ? Uint64.valueOf(datapathIdStr, 16) : Uint64.ZERO;
154     }
155
156     public void putComputeDetailsInConfigDatastore(InstanceIdentifier<ComputeNode> computeIid,
157                                                     ComputeNode computeNode)
158             throws ExecutionException, InterruptedException {
159         ReadWriteTransaction tx = dataBroker.newReadWriteTransaction();
160         tx.put(LogicalDatastoreType.CONFIGURATION, computeIid, computeNode);
161         tx.commit().get();
162         dpnIdVsComputeNode.put(computeNode.getDpnid(), computeNode);
163         //LOG.info("Write comute node details {}", computeNode);
164     }
165
166
167     private void logErrorIfComputeNodeIsAlreadyTaken(Uint64 datapathid, String nodeId, Optional<ComputeNode> optional) {
168         ComputeNode existingNode = optional.get();
169         if (!Objects.equals(existingNode.getNodeid(), nodeId)) {
170             LOG.error("ComputeNodeManager Compute is already connected by compute {}", existingNode);
171             return;
172         }
173         if (!Objects.equals(existingNode.getDpnid(), datapathid)) {
174             LOG.error("ComputeNodeManager Compute is already connected by compute {}", existingNode);
175         }
176     }
177
178     private InstanceIdentifier<Node> getWildcardPath() {
179         return InstanceIdentifier
180                 .create(NetworkTopology.class)
181                 .child(Topology.class, new TopologyKey(new TopologyId("ovsdb:1")))
182                 .child(Node.class);
183     }
184
185     public ComputeNode getComputeNode(Uint64 dpnId) {
186         return dpnIdVsComputeNode.get(dpnId);
187     }
188 }