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