66b68cd87b112256b9d124f758cb9d6eebdb7a06
[genius.git] / cloudscaler / impl / src / test / java / org / opendaylight / genius / cloudscaler / tests / CloudScalerServiceTest.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.tests;
9
10 import static org.junit.Assert.assertTrue;
11 import static org.opendaylight.mdsal.common.api.LogicalDatastoreType.CONFIGURATION;
12 import static org.opendaylight.mdsal.common.api.LogicalDatastoreType.OPERATIONAL;
13
14 import com.google.common.collect.Lists;
15 import com.google.common.collect.Sets;
16 import com.google.common.util.concurrent.ListenableFuture;
17 import java.math.BigInteger;
18 import java.util.HashSet;
19 import java.util.List;
20 import java.util.Set;
21 import java.util.concurrent.ExecutionException;
22 import java.util.concurrent.TimeUnit;
23 import javax.inject.Inject;
24 import org.awaitility.Awaitility;
25 import org.awaitility.core.ConditionFactory;
26 import org.junit.Before;
27 import org.junit.Rule;
28 import org.junit.Test;
29 import org.junit.rules.MethodRule;
30 import org.opendaylight.genius.cloudscaler.api.ScaleInConstants;
31 import org.opendaylight.genius.cloudscaler.rpcservice.CloudscalerRpcServiceImpl;
32 import org.opendaylight.genius.cloudscaler.rpcservice.ComputeNodeManager;
33 import org.opendaylight.genius.cloudscaler.rpcservice.TombstonedNodeManagerImpl;
34 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
35 import org.opendaylight.genius.datastoreutils.testutils.JobCoordinatorTestModule;
36 import org.opendaylight.infrautils.inject.guice.testutils.GuiceRule;
37 import org.opendaylight.infrautils.testutils.LogRule;
38 import org.opendaylight.mdsal.common.api.TransactionCommitFailedException;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.cloudscaler.rpcs.rev171220.ComputeNodes;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.cloudscaler.rpcs.rev171220.ScaleinComputesRecoverInputBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.cloudscaler.rpcs.rev171220.ScaleinComputesRecoverOutput;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.cloudscaler.rpcs.rev171220.ScaleinComputesStartInputBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.cloudscaler.rpcs.rev171220.ScaleinComputesStartOutput;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.cloudscaler.rpcs.rev171220.compute.nodes.ComputeNode;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.cloudscaler.rpcs.rev171220.compute.nodes.ComputeNodeBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.cloudscaler.rpcs.rev171220.compute.nodes.ComputeNodeKey;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.BridgeRefInfo;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntry;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntryBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntryKey;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathId;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentationBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeRef;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.BridgeOtherConfigsBuilder;
57 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
58 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
59 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
60 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
61 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
62 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
63 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
64 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
65 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
66 import org.opendaylight.yangtools.yang.common.RpcResult;
67 import org.opendaylight.yangtools.yang.common.Uint64;
68 import org.slf4j.Logger;
69 import org.slf4j.LoggerFactory;
70
71 public class CloudScalerServiceTest {
72
73     private static final Logger LOG = LoggerFactory.getLogger(CloudScalerServiceTest.class);
74
75     private static final String NODEID1  = "ovsdb://uuid/2de70a99-29a5-4f2a-b87e-96d6ed57e411/bridge/br-int";
76     private static final String NODEID2  = "ovsdb://uuid/2de70a99-29a5-4f2a-b87e-96d6ed57e412/bridge/br-int";
77     private static final String NODEID3  = "ovsdb://uuid/2de70a99-29a5-4f2a-b87e-96d6ed57e413/bridge/br-int";
78
79     private static final Uint64 DPN1 = Uint64.ONE;
80     private static final Uint64 DPN2 = Uint64.valueOf(2);
81     private static final Uint64 DPN3 = Uint64.valueOf(3);
82     private static final Uint64 DPN4 = Uint64.valueOf(4);
83
84     private static final String DPN1_DATAPATHID = new String("00:00:00:00:00:00:00:01");
85     private static final String DPN2_DATAPATHID = new String("00:00:00:00:00:00:00:02");
86     private static final String DPN3_DATAPATHID = new String("00:00:00:00:00:00:00:03");
87     private static final String DPN4_DATAPATHID = new String("00:00:00:00:00:00:00:04");
88
89     private static final String COMPUTE1 = new String("COMPUTE1");
90     private static final String COMPUTE2 = new String("COMPUTE2");
91     private static final String COMPUTE3 = new String("COMPUTE3");
92
93     private static final InstanceIdentifier<BridgeRefEntry> DPN1_BRIDGE_REF
94         = InstanceIdentifier.builder(BridgeRefInfo.class)
95         .child(BridgeRefEntry.class, new BridgeRefEntryKey(DPN1)).build();
96
97     private static final InstanceIdentifier<BridgeRefEntry> DPN2_BRIDGE_REF
98         = InstanceIdentifier.builder(BridgeRefInfo.class)
99         .child(BridgeRefEntry.class, new BridgeRefEntryKey(DPN2)).build();
100
101     private static final InstanceIdentifier<BridgeRefEntry> DPN3_BRIDGE_REF
102         = InstanceIdentifier.builder(BridgeRefInfo.class)
103         .child(BridgeRefEntry.class, new BridgeRefEntryKey(DPN3)).build();
104
105     private static ConditionFactory AWAITER = Awaitility.await("TestableListener")
106         .atMost(30, TimeUnit.SECONDS)
107         .pollInterval(100, TimeUnit.MILLISECONDS);
108
109     public @Rule LogRule logRule = new LogRule();
110     public @Rule MethodRule guice = new GuiceRule(CloudScalerServiceTestModule.class, JobCoordinatorTestModule.class);
111
112     private @Inject CloudscalerRpcServiceImpl scaleInRpcManager;
113     private @Inject TombstonedNodeManagerImpl tombstonedNodeManager;
114     private @Inject SingleTransactionDataBroker dataBroker;
115     private @Inject ComputeNodeManager computeNodeManager;
116
117     public CloudScalerServiceTest() {
118     }
119
120     private static InstanceIdentifier<ComputeNode> buildComputeNodeIid(String computeName) {
121         return InstanceIdentifier.builder(ComputeNodes.class)
122                 .child(ComputeNode.class, new ComputeNodeKey(computeName))
123                 .build();
124     }
125
126     private static InstanceIdentifier<Node> buildNodeId(String nodeId) {
127         return InstanceIdentifier
128                 .create(NetworkTopology.class)
129                 .child(Topology.class, new TopologyKey(new TopologyId("ovsdb:1")))
130                 .child(Node.class, new NodeKey(new NodeId(nodeId)));
131     }
132
133     private static Node buildNode(String nodeId, String computeName, String datapathid) {
134         NodeBuilder nodeBuilder = new NodeBuilder();
135         nodeBuilder.setNodeId(new NodeId(nodeId));
136         OvsdbBridgeAugmentationBuilder bridge = new OvsdbBridgeAugmentationBuilder();
137         BridgeOtherConfigsBuilder otherConfigsBuilder = new BridgeOtherConfigsBuilder();
138         otherConfigsBuilder.setBridgeOtherConfigKey("dp-desc");
139         otherConfigsBuilder.setBridgeOtherConfigValue(computeName);
140         bridge.setDatapathId(new DatapathId(datapathid));
141         bridge.setBridgeOtherConfigs(Lists.newArrayList(otherConfigsBuilder.build()));
142         nodeBuilder.addAugmentation(OvsdbBridgeAugmentation.class,bridge.build());
143         return nodeBuilder.build();
144     }
145
146     private static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node>
147         buildOpenflowNodeIid(Uint64 dpnid) {
148         return InstanceIdentifier.builder(Nodes.class)
149                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
150                         new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey(
151                         new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId(
152                                 "openflow:" + dpnid.toString()))).build();
153     }
154
155     private static org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node buildOpenflowNode(
156             Uint64 dpnId) {
157         org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder nodeBuilder
158                 = new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder();
159         nodeBuilder.setId(new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId(
160                 "openflow:" + dpnId.toString()));
161         return nodeBuilder.build();
162     }
163
164     @Before public void before() throws TransactionCommitFailedException {
165         dataBroker.syncWrite(OPERATIONAL, DPN1_BRIDGE_REF, buildBridgeRefEntry(DPN1, NODEID1));
166         dataBroker.syncWrite(OPERATIONAL, DPN2_BRIDGE_REF, buildBridgeRefEntry(DPN2, NODEID2));
167         dataBroker.syncWrite(OPERATIONAL, DPN3_BRIDGE_REF, buildBridgeRefEntry(DPN3, NODEID3));
168
169         dataBroker.syncWrite(CONFIGURATION, buildNodeId(NODEID1), buildNode(NODEID1, COMPUTE1, DPN1_DATAPATHID));
170         dataBroker.syncWrite(CONFIGURATION, buildNodeId(NODEID2), buildNode(NODEID2, COMPUTE2, DPN2_DATAPATHID));
171         dataBroker.syncWrite(CONFIGURATION, buildNodeId(NODEID3), buildNode(NODEID3, COMPUTE3, DPN3_DATAPATHID));
172
173         dataBroker.syncWrite(CONFIGURATION, buildOpenflowNodeIid(DPN1), buildOpenflowNode(DPN1));
174         dataBroker.syncWrite(CONFIGURATION, buildOpenflowNodeIid(DPN2), buildOpenflowNode(DPN2));
175         dataBroker.syncWrite(CONFIGURATION, buildOpenflowNodeIid(DPN3), buildOpenflowNode(DPN3));
176     }
177
178     @Test public void testBridgeAdd()
179             throws ExecutionException, InterruptedException, TransactionCommitFailedException {
180
181         dataBroker.syncWrite(OPERATIONAL, buildNodeId(NODEID1), buildNode(NODEID1, COMPUTE1, DPN1_DATAPATHID));
182         dataBroker.syncWrite(OPERATIONAL, buildNodeId(NODEID2), buildNode(NODEID2, COMPUTE2, DPN2_DATAPATHID));
183         dataBroker.syncWrite(OPERATIONAL, buildNodeId(NODEID3), buildNode(NODEID3, COMPUTE3, DPN3_DATAPATHID));
184
185         AWAITER.until(() -> dataBroker.syncReadOptional(CONFIGURATION, buildComputeNodeIid(COMPUTE1)).isPresent());
186     }
187
188     @Test public void testScaleinComputesStartRpc()
189             throws ExecutionException, InterruptedException, TransactionCommitFailedException {
190         testBridgeAdd();
191         ListenableFuture<RpcResult<ScaleinComputesStartOutput>> ft = scaleInRpcManager.scaleinComputesStart(
192                 new ScaleinComputesStartInputBuilder().setScaleinComputeNames(
193                         Lists.newArrayList(COMPUTE1, COMPUTE2)).build());
194         assertTrue("Scalein computes start rpc should return success code ", ft.get().isSuccessful());
195
196         AWAITER.until(() -> dataBroker.syncReadOptional(
197                 CONFIGURATION, buildComputeNodeIid(COMPUTE1)).get().isTombstoned());
198         AWAITER.until(() -> dataBroker.syncReadOptional(
199                 CONFIGURATION, buildComputeNodeIid(COMPUTE2)).get().isTombstoned());
200     }
201
202     private static ComputeNode buildComputeNode(String nodeid1, BigInteger dpn1, String compute1) {
203         return new ComputeNodeBuilder()
204                 .setComputeName(compute1)
205                 .setDpnid(dpn1)
206                 .setNodeid(nodeid1)
207                 .build();
208     }
209
210     @Test public void testScaleinComputesRecoverRpc()
211             throws ExecutionException, InterruptedException, TransactionCommitFailedException {
212
213         testScaleinComputesStartRpc();
214
215         ListenableFuture<RpcResult<ScaleinComputesRecoverOutput>> ft = scaleInRpcManager.scaleinComputesRecover(
216                 new ScaleinComputesRecoverInputBuilder().setRecoverComputeNames(Lists.newArrayList(COMPUTE1)).build());
217         assertTrue("scalein computes recover rpc should return success code", ft.get().isSuccessful());
218
219         AWAITER.until(() -> !dataBroker.syncReadOptional(
220                 CONFIGURATION, buildComputeNodeIid(COMPUTE1)).get().isTombstoned());
221         AWAITER.until(() -> dataBroker.syncReadOptional(
222                 CONFIGURATION, buildComputeNodeIid(COMPUTE2)).get().isTombstoned());
223     }
224
225     @Test public void testIsDpnTombstonedApi()
226             throws ExecutionException, InterruptedException, TransactionCommitFailedException {
227
228         testScaleinComputesStartRpc();
229         assertTrue("Dpn 1 should be marked as tombstoned", tombstonedNodeManager.isDpnTombstoned(DPN1));
230         assertTrue("Dpn 2 should be marked as tombstoned", tombstonedNodeManager.isDpnTombstoned(DPN2));
231     }
232
233     @Test public void testfilterTombstoned()
234             throws ExecutionException, InterruptedException, TransactionCommitFailedException {
235
236         testScaleinComputesStartRpc();
237         List<Uint64> filtered = tombstonedNodeManager.filterTombStoned(Lists.newArrayList(DPN1, DPN2, DPN3, DPN4));
238         assertTrue("Dpn 1 and 2 should be filtered ",
239                 Sets.difference(Sets.newHashSet(DPN3, DPN4), Sets.newHashSet(filtered)).isEmpty());
240     }
241
242     @Test public void testRecoveryCallback()
243             throws ExecutionException, InterruptedException, TransactionCommitFailedException {
244
245         Set<Uint64> nodesRecoverd = new HashSet<>();
246         tombstonedNodeManager.addOnRecoveryCallback((dpnId) -> {
247             nodesRecoverd.add(dpnId);
248             return null;
249         });
250         testScaleinComputesRecoverRpc();
251         AWAITER.until(() -> nodesRecoverd.contains(DPN1));
252     }
253
254     private static BridgeRefEntry buildBridgeRefEntry(Uint64 dpnId, String nodeId) {
255         return new BridgeRefEntryBuilder()
256             .setDpid(dpnId)
257             .setBridgeReference(new OvsdbBridgeRef(buildNodeIid(nodeId)))
258             .build();
259     }
260
261     public static InstanceIdentifier<Node> buildNodeIid(String nodeId) {
262         return InstanceIdentifier.builder(NetworkTopology.class)
263                 .child(Topology.class, new TopologyKey(ScaleInConstants.OVSDB_TOPOLOGY_ID))
264                 .child(Node.class, new NodeKey(new NodeId(nodeId))).build();
265     }
266 }