Fix NPE triggered after disabling SG on a port
[netvirt.git] / openstack / utils / netvirt-it-utils / src / main / java / org / opendaylight / netvirt / utils / netvirt / it / utils / NeutronNetItUtil.java
1 /*
2  * Copyright (c) 2016 Red Hat, 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
9 package org.opendaylight.netvirt.utils.netvirt.it.utils;
10
11 import java.io.IOException;
12 import java.util.HashMap;
13 import java.util.Map;
14 import java.util.UUID;
15 import org.junit.Assert;
16 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
17 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
18 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityGroup;
19 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSubnet;
20 import org.opendaylight.netvirt.utils.neutron.utils.NeutronUtils;
21 import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils;
22 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
23
24 /**
25  * A utility class used in integration tests that need to create neutron networks with some ports.
26  * Please see NetvirtIT#testNeutronNet for an example of how this class is used
27  */
28 public class NeutronNetItUtil {
29
30     public final String tenantId;
31     public final String id;
32     public final String subnetId;
33     public NeutronNetwork neutronNetwork;
34     public NeutronSubnet neutronSubnet;
35     public String segId = "100";
36     public String macPfx;
37     public String ipPfx;
38     public String cidr;
39
40     public SouthboundUtils southboundUtils;
41     public NeutronUtils neutronUtils;
42
43     /**
44      * Information about a port created using createPort() - fields should be pretty self explanatory
45      */
46     public class PortInfo {
47         public PortInfo(String name, long ofPort) {
48             this.name = name;
49             this.ofPort = ofPort;
50             this.ip = ipFor(ofPort);
51             this.mac = macFor(ofPort);
52         }
53
54         public String name;
55         public NeutronPort neutronPort;
56         public String ip;
57         public String mac;
58         public long ofPort;
59     }
60
61     /**
62      * Maps port names (the ones you pass in to createPort() to their PortInfo objects
63      */
64     public Map<String, PortInfo> portInfoByName = new HashMap<>();
65
66     /**
67      * Construct a new NeutronNetItUtil.
68      * @param southboundUtils used to create termination points
69      * @param tenantId tenant ID
70      */
71     public NeutronNetItUtil(SouthboundUtils southboundUtils, String tenantId) {
72         this(southboundUtils, tenantId, "101", "f4:00:00:0f:00:", "10.0.0.", "10.0.0.0/24");
73     }
74
75     /**
76      * Construct a new NeutronNetItUtil.
77      * @param southboundUtils used to create termination points
78      * @param tenantId tenant ID
79      * @param segId the segmentation id to use for the neutron network
80      * @param macPfx the first characters of the mac addresses generated for ports. Format is "f7:00:00:0f:00:"
81      * @param ipPfx the first characters of the ip addresses generated for ports. Format is "10.0.0."
82      * @param cidr the cidr for this network, e.g., "10.0.0.0/24"
83      */
84     public NeutronNetItUtil(SouthboundUtils southboundUtils, String tenantId,
85                             String segId, String macPfx, String ipPfx, String cidr) {
86         this.tenantId = tenantId;
87         this.segId = segId;
88         this.macPfx = macPfx;
89         this.ipPfx = ipPfx;
90         this.cidr = cidr;
91
92         this.id = UUID.randomUUID().toString();
93         this.subnetId = UUID.randomUUID().toString();
94
95         this.southboundUtils = southboundUtils;
96         neutronUtils = new NeutronUtils();
97         neutronNetwork = null;
98         neutronSubnet = null;
99     }
100
101     /**
102      * Create the network and subnet.
103      */
104     public void create() {
105         neutronNetwork = neutronUtils.createNeutronNetwork(id, tenantId, "vxlan", segId);
106         neutronSubnet = neutronUtils.createNeutronSubnet(subnetId, tenantId, id, "10.0.0.0/24");
107     }
108
109     /**
110      * Clean up all created neutron objects.
111      */
112     public void destroy() {
113         for (PortInfo portInfo : portInfoByName.values()) {
114             neutronUtils.removeNeutronPort(portInfo.neutronPort.getID());
115         }
116         //TODO: probably more polite to clean up everything else as well...
117         //TODO: for now just assume that the docker image will be recreated
118         //TODO: before each test
119         portInfoByName.clear();
120
121         if (neutronSubnet != null) {
122             neutronUtils.removeNeutronSubnet(neutronSubnet.getID());
123             neutronSubnet = null;
124         }
125
126         if (neutronNetwork != null) {
127             neutronUtils.removeNeutronNetwork(neutronNetwork.getID());
128             neutronNetwork = null;
129         }
130     }
131
132     /**
133      * Create a port on the network. The deviceOwner will be set to "compute:None".
134      * @param bridge bridge where the port will be created on OVS
135      * @param portName name for this port
136      * @throws InterruptedException if we're interrupted while waiting for objects to be created
137      */
138     public void createPort(Node bridge, String portName) throws InterruptedException, IOException {
139         createPort(bridge, portName, "compute:None");
140     }
141
142     /**
143      * Create a port on the network. The deviceOwner will be set to "compute:None".
144      * @param bridge bridge where the port will be created on OVS
145      * @param portName name for this port
146      * @param owner deviceOwner, e.g., "network:dhcp"
147      * @param secGroups Optional NeutronSecurityGroup objects see NeutronUtils.createNeutronSecurityGroup()
148      * @throws InterruptedException if we're interrupted while waiting for objects to be created
149      */
150     public void createPort(Node bridge, String portName, String owner, NeutronSecurityGroup... secGroups)
151                                                                             throws InterruptedException, IOException {
152         PortInfo portInfo = buildPortInfo(portName);
153         doCreatePort(bridge, portInfo, owner, "internal", secGroups);
154     }
155
156     protected PortInfo buildPortInfo(String portName) {
157         Assert.assertFalse("Can't have two ports with the same name", portInfoByName.containsKey(portName));
158
159         long idx = portInfoByName.size() + 1;
160         Assert.assertTrue(idx < 256);
161         return new PortInfo(portName, idx);
162     }
163
164     protected void doCreatePort(Node bridge, PortInfo portInfo, String owner,
165                                 String portType, NeutronSecurityGroup ... secGroups) throws InterruptedException {
166
167         String portId = UUID.randomUUID().toString();
168         portInfo.neutronPort = neutronUtils.createNeutronPort(
169                 id, subnetId, portId, owner, portInfo.ip, portInfo.mac, secGroups);
170
171         //TBD: Use NotifyingDataChangeListener
172         Thread.sleep(1000);
173
174         Map<String, String> externalIds = new HashMap<>();
175         externalIds.put("attached-mac", portInfo.mac);
176         externalIds.put("iface-id", portId);
177         southboundUtils.addTerminationPoint(bridge, portInfo.name, portType, null, externalIds, portInfo.ofPort);
178
179         portInfoByName.put(portInfo.name, portInfo);
180     }
181
182     /**
183      * Get the mac address for the n'th port created on this network (starts at 1).
184      * @param portNum index of port created
185      * @return the mac address
186      */
187     public String macFor(long portNum) {
188         return macPfx + String.format("%02x", 5 - portNum);
189     }
190
191     /**
192      * Get the ip address for the n'th port created on this network (starts at 1).
193      * @param portNum index of port created
194      * @return the mac address
195      */
196     public String ipFor(long portNum) {
197         return ipPfx + portNum;
198     }
199 }
200