blob: 3788d010d7dfebffbf9b1aa3acfa05e393c3447d [file] [log] [blame]
Jian Li5b402c72018-02-27 14:27:34 +09001/*
2 * Copyright 2018-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.openstacknode.codec;
17
18import com.fasterxml.jackson.databind.JsonNode;
19import com.fasterxml.jackson.databind.ObjectMapper;
20import com.fasterxml.jackson.databind.node.ObjectNode;
Jian Lie6312162018-03-21 21:41:00 +090021import com.google.common.collect.ImmutableList;
Jian Li5b402c72018-02-27 14:27:34 +090022import org.hamcrest.MatcherAssert;
23import org.junit.Before;
24import org.junit.Test;
25import org.onlab.packet.IpAddress;
26import org.onosproject.codec.CodecContext;
27import org.onosproject.codec.JsonCodec;
28import org.onosproject.codec.impl.CodecManager;
29import org.onosproject.core.CoreService;
30import org.onosproject.net.DeviceId;
Jian Li789fadb2018-07-10 13:59:47 +090031import org.onosproject.net.behaviour.ControllerInfo;
Daniel Parkd02d7bd2018-08-23 23:04:31 +090032import org.onosproject.openstacknode.api.DefaultOpenstackAuth;
33import org.onosproject.openstacknode.api.DefaultOpenstackNode;
34import org.onosproject.openstacknode.api.DpdkConfig;
35import org.onosproject.openstacknode.api.DpdkInterface;
Jian Lic704b672018-09-04 18:52:53 +090036import org.onosproject.openstacknode.api.KeystoneConfig;
37import org.onosproject.openstacknode.api.NeutronConfig;
Jian Li5b402c72018-02-27 14:27:34 +090038import org.onosproject.openstacknode.api.NodeState;
Jian Li27841662018-04-14 01:59:47 +090039import org.onosproject.openstacknode.api.OpenstackAuth;
Jian Li5b402c72018-02-27 14:27:34 +090040import org.onosproject.openstacknode.api.OpenstackNode;
Jian Lie6312162018-03-21 21:41:00 +090041import org.onosproject.openstacknode.api.OpenstackPhyInterface;
Daniel Parkdeefa702018-07-17 17:55:51 +090042import org.onosproject.openstacknode.api.OpenstackSshAuth;
Daniel Parkd02d7bd2018-08-23 23:04:31 +090043import org.onosproject.openstacknode.impl.DefaultDpdkConfig;
44import org.onosproject.openstacknode.impl.DefaultDpdkInterface;
Jian Lic704b672018-09-04 18:52:53 +090045import org.onosproject.openstacknode.api.DefaultKeystoneConfig;
46import org.onosproject.openstacknode.api.DefaultNeutronConfig;
Jian Lie6312162018-03-21 21:41:00 +090047import org.onosproject.openstacknode.impl.DefaultOpenstackPhyInterface;
Daniel Parkdeefa702018-07-17 17:55:51 +090048import org.onosproject.openstacknode.impl.DefaultOpenstackSshAuth;
Jian Li5b402c72018-02-27 14:27:34 +090049
50import java.io.IOException;
51import java.io.InputStream;
Daniel Parkd02d7bd2018-08-23 23:04:31 +090052import java.util.ArrayList;
53import java.util.Collection;
Jian Li5b402c72018-02-27 14:27:34 +090054import java.util.HashMap;
55import java.util.Map;
56
57import static org.easymock.EasyMock.createMock;
58import static org.easymock.EasyMock.expect;
59import static org.easymock.EasyMock.replay;
60import static org.hamcrest.MatcherAssert.assertThat;
61import static org.hamcrest.Matchers.is;
62import static org.hamcrest.Matchers.notNullValue;
Daniel Parkd02d7bd2018-08-23 23:04:31 +090063import static org.junit.Assert.assertEquals;
Jian Li5b402c72018-02-27 14:27:34 +090064import static org.onosproject.net.NetTestTools.APP_ID;
65import static org.onosproject.openstacknode.codec.OpenstackNodeJsonMatcher.matchesOpenstackNode;
66
67/**
68 * Unit tests for OpenstackNode codec.
69 */
70public class OpenstackNodeCodecTest {
71 MockCodecContext context;
Jian Lic704b672018-09-04 18:52:53 +090072
Jian Li5b402c72018-02-27 14:27:34 +090073 JsonCodec<OpenstackNode> openstackNodeCodec;
Jian Lie6312162018-03-21 21:41:00 +090074 JsonCodec<OpenstackPhyInterface> openstackPhyIntfJsonCodec;
Jian Li789fadb2018-07-10 13:59:47 +090075 JsonCodec<ControllerInfo> openstackControllerJsonCodec;
Jian Li27841662018-04-14 01:59:47 +090076 JsonCodec<OpenstackAuth> openstackAuthJsonCodec;
Daniel Parkdeefa702018-07-17 17:55:51 +090077 JsonCodec<OpenstackSshAuth> openstackSshAuthJsonCodec;
Daniel Parkd02d7bd2018-08-23 23:04:31 +090078 JsonCodec<DpdkConfig> dpdkConfigJsonCodec;
79 JsonCodec<DpdkInterface> dpdkInterfaceJsonCodec;
Jian Lic704b672018-09-04 18:52:53 +090080 JsonCodec<KeystoneConfig> keystoneConfigJsonCodec;
81 JsonCodec<NeutronConfig> neutronConfigJsonCodec;
Daniel Parkdeefa702018-07-17 17:55:51 +090082
Jian Li5b402c72018-02-27 14:27:34 +090083 final CoreService mockCoreService = createMock(CoreService.class);
84 private static final String REST_APP_ID = "org.onosproject.rest";
85
86 @Before
87 public void setUp() {
88 context = new MockCodecContext();
89 openstackNodeCodec = new OpenstackNodeCodec();
Jian Lie6312162018-03-21 21:41:00 +090090 openstackPhyIntfJsonCodec = new OpenstackPhyInterfaceCodec();
Jian Li789fadb2018-07-10 13:59:47 +090091 openstackControllerJsonCodec = new OpenstackControllerCodec();
Jian Li27841662018-04-14 01:59:47 +090092 openstackAuthJsonCodec = new OpenstackAuthCodec();
Daniel Parkdeefa702018-07-17 17:55:51 +090093 openstackSshAuthJsonCodec = new OpenstackSshAuthCodec();
Daniel Parkd02d7bd2018-08-23 23:04:31 +090094 dpdkConfigJsonCodec = new DpdkConfigCodec();
95 dpdkInterfaceJsonCodec = new DpdkInterfaceCodec();
Jian Lic704b672018-09-04 18:52:53 +090096 keystoneConfigJsonCodec = new KeystoneConfigCodec();
97 neutronConfigJsonCodec = new NeutronConfigCodec();
Jian Lie6312162018-03-21 21:41:00 +090098
Jian Li5b402c72018-02-27 14:27:34 +090099 assertThat(openstackNodeCodec, notNullValue());
Jian Lie6312162018-03-21 21:41:00 +0900100 assertThat(openstackPhyIntfJsonCodec, notNullValue());
Jian Li789fadb2018-07-10 13:59:47 +0900101 assertThat(openstackControllerJsonCodec, notNullValue());
Jian Li27841662018-04-14 01:59:47 +0900102 assertThat(openstackAuthJsonCodec, notNullValue());
Daniel Parkdeefa702018-07-17 17:55:51 +0900103 assertThat(openstackSshAuthJsonCodec, notNullValue());
Daniel Parkd02d7bd2018-08-23 23:04:31 +0900104 assertThat(dpdkConfigJsonCodec, notNullValue());
105 assertThat(dpdkInterfaceJsonCodec, notNullValue());
Jian Lic704b672018-09-04 18:52:53 +0900106 assertThat(keystoneConfigJsonCodec, notNullValue());
107 assertThat(neutronConfigJsonCodec, notNullValue());
Jian Li5b402c72018-02-27 14:27:34 +0900108
109 expect(mockCoreService.registerApplication(REST_APP_ID))
110 .andReturn(APP_ID).anyTimes();
111 replay(mockCoreService);
112 context.registerService(CoreService.class, mockCoreService);
113 }
114
Jian Li27841662018-04-14 01:59:47 +0900115 /**
116 * Tests the openstack compute node encoding.
117 */
Jian Li5b402c72018-02-27 14:27:34 +0900118 @Test
Jian Li27841662018-04-14 01:59:47 +0900119 public void testOpenstackComputeNodeEncode() {
Jian Lie6312162018-03-21 21:41:00 +0900120
121 OpenstackPhyInterface phyIntf1 = DefaultOpenstackPhyInterface.builder()
122 .network("mgmtnetwork")
123 .intf("eth3")
124 .build();
125 OpenstackPhyInterface phyIntf2 = DefaultOpenstackPhyInterface.builder()
126 .network("oamnetwork")
127 .intf("eth4")
128 .build();
129
Daniel Parkdeefa702018-07-17 17:55:51 +0900130 OpenstackSshAuth sshAuth = DefaultOpenstackSshAuth.builder()
131 .id("sdn")
132 .password("sdn")
133 .build();
134
Jian Li789fadb2018-07-10 13:59:47 +0900135 ControllerInfo controller1 =
136 new ControllerInfo(IpAddress.valueOf("10.10.10.2"), 6653, "tcp");
137 ControllerInfo controller2 =
138 new ControllerInfo(IpAddress.valueOf("10.10.10.3"), 6663, "tcp");
139
Jian Li5b402c72018-02-27 14:27:34 +0900140 OpenstackNode node = DefaultOpenstackNode.builder()
141 .hostname("compute")
142 .type(OpenstackNode.NodeType.COMPUTE)
143 .state(NodeState.INIT)
144 .managementIp(IpAddress.valueOf("10.10.10.1"))
145 .intgBridge(DeviceId.deviceId("br-int"))
Daniel Parkd02d7bd2018-08-23 23:04:31 +0900146 .vlanIntf("vlan")
Jian Li5b402c72018-02-27 14:27:34 +0900147 .dataIp(IpAddress.valueOf("20.20.20.2"))
Jian Lie6312162018-03-21 21:41:00 +0900148 .phyIntfs(ImmutableList.of(phyIntf1, phyIntf2))
Jian Li789fadb2018-07-10 13:59:47 +0900149 .controllers(ImmutableList.of(controller1, controller2))
Daniel Parkdeefa702018-07-17 17:55:51 +0900150 .sshAuthInfo(sshAuth)
Jian Li5b402c72018-02-27 14:27:34 +0900151 .build();
152
153 ObjectNode nodeJson = openstackNodeCodec.encode(node, context);
154 assertThat(nodeJson, matchesOpenstackNode(node));
155 }
156
Jian Li27841662018-04-14 01:59:47 +0900157 /**
158 * Tests the openstack compute node decoding.
159 *
Daniel Parkd02d7bd2018-08-23 23:04:31 +0900160 * @throws IOException io exception
Jian Li27841662018-04-14 01:59:47 +0900161 */
Jian Li5b402c72018-02-27 14:27:34 +0900162 @Test
Jian Li27841662018-04-14 01:59:47 +0900163 public void testOpenstackComputeNodeDecode() throws IOException {
164 OpenstackNode node = getOpenstackNode("OpenstackComputeNode.json");
Jian Li5b402c72018-02-27 14:27:34 +0900165
166 assertThat(node.hostname(), is("compute-01"));
167 assertThat(node.type().name(), is("COMPUTE"));
168 assertThat(node.managementIp().toString(), is("172.16.130.4"));
169 assertThat(node.dataIp().toString(), is("172.16.130.4"));
170 assertThat(node.intgBridge().toString(), is("of:00000000000000a1"));
171 assertThat(node.vlanIntf(), is("eth2"));
Jian Lie6312162018-03-21 21:41:00 +0900172 assertThat(node.phyIntfs().size(), is(2));
Jian Li789fadb2018-07-10 13:59:47 +0900173 assertThat(node.controllers().size(), is(2));
Daniel Parkdeefa702018-07-17 17:55:51 +0900174 assertThat(node.sshAuthInfo().id(), is("sdn"));
175 assertThat(node.sshAuthInfo().password(), is("sdn"));
Daniel Parkd02d7bd2018-08-23 23:04:31 +0900176 assertThat(node.datapathType(), is(DpdkConfig.DatapathType.NORMAL));
Daniel Park7e8c4d82018-08-13 23:47:49 +0900177
Jian Lie6312162018-03-21 21:41:00 +0900178
179 node.phyIntfs().forEach(intf -> {
180 if (intf.network().equals("mgmtnetwork")) {
181 assertThat(intf.intf(), is("eth3"));
182 }
183 if (intf.network().equals("oamnetwork")) {
184 assertThat(intf.intf(), is("eth4"));
185 }
186 });
Jian Li789fadb2018-07-10 13:59:47 +0900187
188 node.controllers().forEach(ctrl -> {
189 if (ctrl.ip().toString().equals("10.10.10.2")) {
190 assertThat(ctrl.port(), is(6653));
191 }
192 if (ctrl.ip().toString().equals("10.10.10.3")) {
193 assertThat(ctrl.port(), is(6663));
194 }
195 });
Daniel Parkd02d7bd2018-08-23 23:04:31 +0900196 }
Daniel Park92abf312018-08-08 17:01:35 +0900197
Daniel Parkd02d7bd2018-08-23 23:04:31 +0900198 /**
199 * Tests the openstack compute node encoding with dpdk config.
200 */
201 @Test
202 public void testOpenstackDpdkComputeNodeEncode() {
203 DpdkInterface dpdkInterface1 = DefaultDpdkInterface.builder()
204 .deviceName("br-int")
205 .intf("dpdk0")
206 .mtu(Long.valueOf(1600))
207 .pciAddress("0000:85:00.0")
208 .type(DpdkInterface.Type.DPDK)
209 .build();
Daniel Park92abf312018-08-08 17:01:35 +0900210
Daniel Parkd02d7bd2018-08-23 23:04:31 +0900211 DpdkInterface dpdkInterface2 = DefaultDpdkInterface.builder()
212 .deviceName("br-tun")
213 .intf("dpdk1")
214 .pciAddress("0000:85:00.1")
215 .type(DpdkInterface.Type.DPDK)
216 .build();
217
218 Collection<DpdkInterface> dpdkInterfaceCollection = new ArrayList<>();
219 dpdkInterfaceCollection.add(dpdkInterface1);
220 dpdkInterfaceCollection.add(dpdkInterface2);
221
222
223 DpdkConfig dpdkConfig = DefaultDpdkConfig.builder()
224 .datapathType(DpdkConfig.DatapathType.NETDEV)
225 .dpdkIntfs(dpdkInterfaceCollection)
226 .build();
227
228 OpenstackNode node = DefaultOpenstackNode.builder()
229 .hostname("compute")
230 .type(OpenstackNode.NodeType.COMPUTE)
231 .state(NodeState.INIT)
232 .managementIp(IpAddress.valueOf("10.10.10.1"))
233 .intgBridge(DeviceId.deviceId("br-int"))
234 .vlanIntf("vlan")
235 .dataIp(IpAddress.valueOf("20.20.20.2"))
236 .dpdkConfig(dpdkConfig)
237 .build();
238
239 ObjectNode nodeJson = openstackNodeCodec.encode(node, context);
240 assertThat(nodeJson, matchesOpenstackNode(node));
241 }
242
243 /**
244 * Tests the openstack compute node decoding with dpdk config.
245 *
246 * @throws IOException io exception
247 */
248 @Test
249 public void testOpenstackDpdkComputeNodeDecode() throws IOException {
250 OpenstackNode node = getOpenstackNode("OpenstackDpdkComputeNode.json");
251
252 assertEquals(node.datapathType(), DpdkConfig.DatapathType.NETDEV);
253 assertEquals(node.socketDir(), "/var/lib/libvirt/qemu");
254 assertEquals(node.dpdkConfig().dpdkIntfs().size(), 2);
Jian Li5b402c72018-02-27 14:27:34 +0900255 }
256
257 /**
Jian Li27841662018-04-14 01:59:47 +0900258 * Tests the openstack controller node encoding.
259 */
260 @Test
261 public void testOpenstackControllerNodeEncode() {
262 OpenstackAuth auth = DefaultOpenstackAuth.builder()
263 .version("v2.0")
Jian Li27841662018-04-14 01:59:47 +0900264 .protocol(OpenstackAuth.Protocol.HTTP)
265 .project("admin")
266 .username("admin")
267 .password("nova")
268 .perspective(OpenstackAuth.Perspective.PUBLIC)
269 .build();
270
Jian Lic704b672018-09-04 18:52:53 +0900271 String endpoint = "172.16.130.10:35357/v2.0";
272
273 KeystoneConfig keystoneConfig = DefaultKeystoneConfig.builder()
274 .endpoint(endpoint)
275 .authentication(auth)
276 .build();
277
278 NeutronConfig neutronConfig = DefaultNeutronConfig.builder()
279 .useMetadataProxy(true)
280 .metadataProxySecret("onos")
Jian Li92b6f292018-09-06 10:57:18 +0900281 .novaMetadataIp("172.16.130.10")
282 .novaMetadataPort(8775)
Jian Lic704b672018-09-04 18:52:53 +0900283 .build();
284
Jian Li27841662018-04-14 01:59:47 +0900285 OpenstackNode node = DefaultOpenstackNode.builder()
286 .hostname("controller")
287 .type(OpenstackNode.NodeType.CONTROLLER)
288 .state(NodeState.INIT)
289 .managementIp(IpAddress.valueOf("172.16.130.10"))
Jian Lic704b672018-09-04 18:52:53 +0900290 .keystoneConfig(keystoneConfig)
291 .neutronConfig(neutronConfig)
Jian Li27841662018-04-14 01:59:47 +0900292 .build();
293
294 ObjectNode nodeJson = openstackNodeCodec.encode(node, context);
295 assertThat(nodeJson, matchesOpenstackNode(node));
296 }
297
298 /**
299 * Tests the openstack controller node decoding.
300 */
301 @Test
302 public void testOpenstackControllerNodeDecode() throws IOException {
303 OpenstackNode node = getOpenstackNode("OpenstackControllerNode.json");
304
305 assertThat(node.hostname(), is("controller"));
306 assertThat(node.type().name(), is("CONTROLLER"));
307 assertThat(node.managementIp().toString(), is("172.16.130.10"));
308
Jian Lic704b672018-09-04 18:52:53 +0900309 KeystoneConfig keystoneConfig = node.keystoneConfig();
310 OpenstackAuth auth = keystoneConfig.authentication();
311 String endpoint = keystoneConfig.endpoint();
Jian Li27841662018-04-14 01:59:47 +0900312
313 assertThat(auth.version(), is("v2.0"));
Jian Li27841662018-04-14 01:59:47 +0900314 assertThat(auth.protocol(), is(OpenstackAuth.Protocol.HTTP));
315 assertThat(auth.username(), is("admin"));
316 assertThat(auth.password(), is("nova"));
317 assertThat(auth.project(), is("admin"));
318 assertThat(auth.perspective(), is(OpenstackAuth.Perspective.PUBLIC));
Jian Lic704b672018-09-04 18:52:53 +0900319
320 assertThat(endpoint, is("172.16.130.10:35357/v2.0"));
321
322 NeutronConfig neutronConfig = node.neutronConfig();
323
324 assertThat(neutronConfig.useMetadataProxy(), is(true));
325 assertThat(neutronConfig.metadataProxySecret(), is("onos"));
Jian Li92b6f292018-09-06 10:57:18 +0900326 assertThat(neutronConfig.novaMetadataIp(), is("172.16.130.10"));
327 assertThat(neutronConfig.novaMetadataPort(), is(8775));
Jian Lic704b672018-09-04 18:52:53 +0900328 }
329
330 /**
331 * Tests the openstack obsolete controller node decoding.
332 */
333 @Test
334 public void testOpenstackObsoleteControllerNodeDecode() throws IOException {
335 OpenstackNode node = getOpenstackNode("OpenstackObsoleteControllerNode.json");
336
337 assertThat(node.hostname(), is("controller"));
338 assertThat(node.type().name(), is("CONTROLLER"));
339 assertThat(node.managementIp().toString(), is("172.16.130.10"));
340
341 KeystoneConfig keystoneConfig = node.keystoneConfig();
342 OpenstackAuth auth = keystoneConfig.authentication();
343 String endpoint = keystoneConfig.endpoint();
344
345 assertThat(auth.version(), is("v2.0"));
346 assertThat(auth.protocol(), is(OpenstackAuth.Protocol.HTTP));
347 assertThat(auth.username(), is("admin"));
348 assertThat(auth.password(), is("nova"));
349 assertThat(auth.project(), is("admin"));
350 assertThat(auth.perspective(), is(OpenstackAuth.Perspective.PUBLIC));
351
352 assertThat(endpoint, is("172.16.130.10:35357/v2.0"));
Jian Li27841662018-04-14 01:59:47 +0900353 }
354
355 /**
Jian Li5b402c72018-02-27 14:27:34 +0900356 * Reads in an openstack node from the given resource and decodes it.
357 *
358 * @param resourceName resource to use to read the JSON for the rule
359 * @return decoded openstack node
360 * @throws IOException if processing the resource fails
361 */
362 private OpenstackNode getOpenstackNode(String resourceName) throws IOException {
363 InputStream jsonStream = OpenstackNodeCodecTest.class.getResourceAsStream(resourceName);
364 JsonNode json = context.mapper().readTree(jsonStream);
365 MatcherAssert.assertThat(json, notNullValue());
366 OpenstackNode node = openstackNodeCodec.decode((ObjectNode) json, context);
367 assertThat(node, notNullValue());
368 return node;
369 }
370
371 /**
372 * Mock codec context for use in codec unit tests.
373 */
374 private class MockCodecContext implements CodecContext {
375 private final ObjectMapper mapper = new ObjectMapper();
376 private final CodecManager manager = new CodecManager();
377 private final Map<Class<?>, Object> services = new HashMap<>();
378
379 /**
380 * Constructs a new mock codec context.
381 */
382 public MockCodecContext() {
383 manager.activate();
384 }
385
386 @Override
387 public ObjectMapper mapper() {
388 return mapper;
389 }
390
391 @Override
392 @SuppressWarnings("unchecked")
393 public <T> JsonCodec<T> codec(Class<T> entityClass) {
Jian Lie6312162018-03-21 21:41:00 +0900394 if (entityClass == OpenstackPhyInterface.class) {
395 return (JsonCodec<T>) openstackPhyIntfJsonCodec;
396 }
Jian Li789fadb2018-07-10 13:59:47 +0900397 if (entityClass == ControllerInfo.class) {
398 return (JsonCodec<T>) openstackControllerJsonCodec;
399 }
Jian Li27841662018-04-14 01:59:47 +0900400 if (entityClass == OpenstackAuth.class) {
401 return (JsonCodec<T>) openstackAuthJsonCodec;
402 }
Daniel Parkdeefa702018-07-17 17:55:51 +0900403 if (entityClass == OpenstackSshAuth.class) {
404 return (JsonCodec<T>) openstackSshAuthJsonCodec;
405 }
Daniel Parkd02d7bd2018-08-23 23:04:31 +0900406 if (entityClass == DpdkConfig.class) {
407 return (JsonCodec<T>) dpdkConfigJsonCodec;
408 }
409 if (entityClass == DpdkInterface.class) {
410 return (JsonCodec<T>) dpdkInterfaceJsonCodec;
411 }
Jian Lic704b672018-09-04 18:52:53 +0900412 if (entityClass == KeystoneConfig.class) {
413 return (JsonCodec<T>) keystoneConfigJsonCodec;
414 }
415 if (entityClass == NeutronConfig.class) {
416 return (JsonCodec<T>) neutronConfigJsonCodec;
417 }
Jian Li5b402c72018-02-27 14:27:34 +0900418 return manager.getCodec(entityClass);
419 }
420
421 @SuppressWarnings("unchecked")
422 @Override
423 public <T> T getService(Class<T> serviceClass) {
424 return (T) services.get(serviceClass);
425 }
426
427 // for registering mock services
428 public <T> void registerService(Class<T> serviceClass, T impl) {
429 services.put(serviceClass, impl);
430 }
431 }
432}