blob: 8b335e677ac81d1e9b8ebe0928e4b359dd7a2b84 [file] [log] [blame]
Jian Li0b564282018-06-20 00:50:53 +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.openstacknetworking.web;
17
Jian Li803a1d52018-06-21 21:47:48 +090018import com.fasterxml.jackson.databind.node.ArrayNode;
19import com.fasterxml.jackson.databind.node.ObjectNode;
20import com.google.common.base.Strings;
21import com.google.common.collect.Lists;
Jian Li0b564282018-06-20 00:50:53 +090022import org.onlab.util.ItemNotFoundException;
Jian Li7f024de2018-07-07 03:51:02 +090023import org.onosproject.cfg.ComponentConfigService;
Jian Li0b564282018-06-20 00:50:53 +090024import org.onosproject.core.ApplicationId;
25import org.onosproject.core.CoreService;
26import org.onosproject.net.flow.FlowRuleService;
27import org.onosproject.openstacknetworking.api.Constants;
28import org.onosproject.openstacknetworking.api.OpenstackNetworkAdminService;
29import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
30import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupAdminService;
Jian Li7f024de2018-07-07 03:51:02 +090031import org.onosproject.openstacknetworking.impl.OpenstackRoutingArpHandler;
Jian Licad36c72018-09-13 17:44:54 +090032import org.onosproject.openstacknetworking.impl.OpenstackSecurityGroupHandler;
Jian Li7f024de2018-07-07 03:51:02 +090033import org.onosproject.openstacknetworking.impl.OpenstackSwitchingArpHandler;
Jian Li0b564282018-06-20 00:50:53 +090034import org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil;
35import org.onosproject.openstacknode.api.NodeState;
36import org.onosproject.openstacknode.api.OpenstackNode;
37import org.onosproject.openstacknode.api.OpenstackNodeAdminService;
Jian Li0b564282018-06-20 00:50:53 +090038import org.onosproject.rest.AbstractWebResource;
39import org.openstack4j.api.OSClient;
Jian Li803a1d52018-06-21 21:47:48 +090040import org.openstack4j.model.network.NetFloatingIP;
Jian Li0b564282018-06-20 00:50:53 +090041import org.slf4j.Logger;
42import org.slf4j.LoggerFactory;
43
44import javax.ws.rs.GET;
45import javax.ws.rs.Path;
Jian Li7f024de2018-07-07 03:51:02 +090046import javax.ws.rs.PathParam;
Jian Li0b564282018-06-20 00:50:53 +090047import javax.ws.rs.Produces;
48import javax.ws.rs.core.MediaType;
49import javax.ws.rs.core.Response;
Jian Li803a1d52018-06-21 21:47:48 +090050import java.util.Comparator;
51import java.util.List;
Jian Li0b564282018-06-20 00:50:53 +090052import java.util.Objects;
53import java.util.Optional;
54
Jian Lif7934d52018-07-10 16:27:02 +090055import static java.lang.Thread.sleep;
Jian Li7f024de2018-07-07 03:51:02 +090056import static org.onlab.util.Tools.nullIsIllegal;
Jian Licad36c72018-09-13 17:44:54 +090057import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.*;
Jian Li0b564282018-06-20 00:50:53 +090058import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.CONTROLLER;
59
60/**
61 * REST interface for synchronizing openstack network states and rules.
62 */
63@Path("management")
64public class OpenstackManagementWebResource extends AbstractWebResource {
65 private final Logger log = LoggerFactory.getLogger(getClass());
66
Jian Li803a1d52018-06-21 21:47:48 +090067 private static final String FLOATINGIPS = "floatingips";
Jian Li7f024de2018-07-07 03:51:02 +090068 private static final String ARP_MODE_NAME = "arpMode";
Jian Licad36c72018-09-13 17:44:54 +090069 private static final String USE_SECURITY_GROUP_NAME = "useSecurityGroup";
Jian Li803a1d52018-06-21 21:47:48 +090070
Jian Lif7934d52018-07-10 16:27:02 +090071 private static final long SLEEP_MS = 3000; // we wait 3s for init each node
Jian Li88ae51e2018-07-10 02:23:35 +090072
Jian Li0b564282018-06-20 00:50:53 +090073 private static final String DEVICE_OWNER_IFACE = "network:router_interface";
Jian Li7f024de2018-07-07 03:51:02 +090074
75 private static final String ARP_MODE_REQUIRED = "ARP mode is not specified";
76
Jian Licad36c72018-09-13 17:44:54 +090077 private static final String SECURITY_GROUP_FLAG_REQUIRED = "Security Group flag is not specified";
78
Jian Li803a1d52018-06-21 21:47:48 +090079 private final ObjectNode root = mapper().createObjectNode();
80 private final ArrayNode floatingipsNode = root.putArray(FLOATINGIPS);
Jian Li0b564282018-06-20 00:50:53 +090081
82 private final OpenstackSecurityGroupAdminService osSgAdminService =
83 get(OpenstackSecurityGroupAdminService.class);
84 private final OpenstackNetworkAdminService osNetAdminService =
85 get(OpenstackNetworkAdminService.class);
86 private final OpenstackRouterAdminService osRouterAdminService =
87 get(OpenstackRouterAdminService.class);
Jian Li0b564282018-06-20 00:50:53 +090088 private final OpenstackNodeAdminService osNodeAdminService =
89 get(OpenstackNodeAdminService.class);
90 private final FlowRuleService flowRuleService = get(FlowRuleService.class);
91 private final CoreService coreService = get(CoreService.class);
92
93 /**
94 * Synchronizes the network states with openstack.
95 *
96 * @return 200 OK with sync result, 404 not found
97 */
98 @GET
99 @Produces(MediaType.APPLICATION_JSON)
100 @Path("sync/states")
101 public Response syncStates() {
102
Jian Li78ac0652018-07-17 18:10:16 +0900103 Optional<OpenstackNode> node = osNodeAdminService.nodes(CONTROLLER).stream().findFirst();
Jian Li0b564282018-06-20 00:50:53 +0900104 if (!node.isPresent()) {
105 throw new ItemNotFoundException("Auth info is not found");
106 }
107
108 OSClient osClient = OpenstackNetworkingUtil.getConnectedClient(node.get());
109
110 if (osClient == null) {
111 throw new ItemNotFoundException("Auth info is not correct");
112 }
113
114 osClient.networking().securitygroup().list().forEach(osSg -> {
115 if (osSgAdminService.securityGroup(osSg.getId()) != null) {
116 osSgAdminService.updateSecurityGroup(osSg);
117 } else {
118 osSgAdminService.createSecurityGroup(osSg);
119 }
120 });
121
122 osClient.networking().network().list().forEach(osNet -> {
123 if (osNetAdminService.network(osNet.getId()) != null) {
124 osNetAdminService.updateNetwork(osNet);
125 } else {
126 osNetAdminService.createNetwork(osNet);
127 }
128 });
129
130 osClient.networking().subnet().list().forEach(osSubnet -> {
131 if (osNetAdminService.subnet(osSubnet.getId()) != null) {
132 osNetAdminService.updateSubnet(osSubnet);
133 } else {
134 osNetAdminService.createSubnet(osSubnet);
135 }
136 });
137
138 osClient.networking().port().list().forEach(osPort -> {
139 if (osNetAdminService.port(osPort.getId()) != null) {
140 osNetAdminService.updatePort(osPort);
141 } else {
142 osNetAdminService.createPort(osPort);
143 }
144 });
145
146 osClient.networking().router().list().forEach(osRouter -> {
147 if (osRouterAdminService.router(osRouter.getId()) != null) {
148 osRouterAdminService.updateRouter(osRouter);
149 } else {
150 osRouterAdminService.createRouter(osRouter);
151 }
152
153 osNetAdminService.ports().stream()
154 .filter(osPort -> Objects.equals(osPort.getDeviceId(), osRouter.getId()) &&
155 Objects.equals(osPort.getDeviceOwner(), DEVICE_OWNER_IFACE))
156 .forEach(osPort -> addRouterIface(osPort, osRouterAdminService));
157 });
158
159 osClient.networking().floatingip().list().forEach(osFloating -> {
160 if (osRouterAdminService.floatingIp(osFloating.getId()) != null) {
161 osRouterAdminService.updateFloatingIp(osFloating);
162 } else {
163 osRouterAdminService.createFloatingIp(osFloating);
164 }
165 });
166
167 return ok(mapper().createObjectNode()).build();
168 }
169
170 /**
171 * Synchronizes the flow rules.
172 *
173 * @return 200 OK with sync result, 404 not found
174 */
175 @GET
176 @Produces(MediaType.APPLICATION_JSON)
177 @Path("sync/rules")
178 public Response syncRules() {
179
Jian Li7f024de2018-07-07 03:51:02 +0900180 syncRulesBase();
Jian Li0b564282018-06-20 00:50:53 +0900181 return ok(mapper().createObjectNode()).build();
182 }
183
184 /**
185 * Purges the network states.
186 *
187 * @return 200 OK with purge result, 404 not found
188 */
189 @GET
190 @Produces(MediaType.APPLICATION_JSON)
191 @Path("purge/states")
192 public Response purgeStates() {
193
194 osRouterAdminService.clear();
195 osNetAdminService.clear();
196 osSgAdminService.clear();
197
198 return ok(mapper().createObjectNode()).build();
199 }
200
201 /**
202 * Purges the flow rules installed by openstacknetworking.
203 *
204 * @return 200 OK with purge result, 404 not found
205 */
206 @GET
207 @Produces(MediaType.APPLICATION_JSON)
208 @Path("purge/rules")
209 public Response purgeRules() {
210
Jian Li7f024de2018-07-07 03:51:02 +0900211 purgeRulesBase();
212 return ok(mapper().createObjectNode()).build();
213 }
214
215 /**
216 * Configures the ARP mode (proxy | broadcast).
217 *
218 * @param arpmode ARP mode
219 * @return 200 OK with config result, 404 not found
220 */
221 @GET
222 @Produces(MediaType.APPLICATION_JSON)
223 @Path("config/arpmode/{arpmode}")
224 public Response configArpMode(@PathParam("arpmode") String arpmode) {
225
226 String arpModeStr = nullIsIllegal(arpmode, ARP_MODE_REQUIRED);
227 if (checkArpMode(arpModeStr)) {
228 configArpModeBase(arpModeStr);
229
230 ComponentConfigService service = get(ComponentConfigService.class);
231 String switchingComponent = OpenstackSwitchingArpHandler.class.getName();
232 String routingComponent = OpenstackRoutingArpHandler.class.getName();
233
234 // we check the arpMode configured in each component, and purge and
235 // reinstall all rules only if the arpMode is changed to the configured one
236 while (true) {
237 String switchingValue =
238 getPropertyValue(service.getProperties(switchingComponent), ARP_MODE_NAME);
239 String routingValue =
240 getPropertyValue(service.getProperties(routingComponent), ARP_MODE_NAME);
241
242 if (arpModeStr.equals(switchingValue) && arpModeStr.equals(routingValue)) {
243 break;
244 }
245 }
246
247 purgeRulesBase();
248 syncRulesBase();
249 } else {
250 throw new IllegalArgumentException("The ARP mode is not valid");
Jian Li0b564282018-06-20 00:50:53 +0900251 }
Jian Li0b564282018-06-20 00:50:53 +0900252
253 return ok(mapper().createObjectNode()).build();
254 }
Jian Li803a1d52018-06-21 21:47:48 +0900255
256 /**
Jian Licad36c72018-09-13 17:44:54 +0900257 * Configures the security group (enable | disable).
258 *
259 * @param securityGroup security group activation flag
260 * @return 200 OK with config result, 404 not found
261 */
262 @GET
263 @Produces(MediaType.APPLICATION_JSON)
264 @Path("config/securityGroup/{securityGroup}")
265 public Response configSecurityGroup(@PathParam("securityGroup") String securityGroup) {
266 String securityGroupStr = nullIsIllegal(securityGroup, SECURITY_GROUP_FLAG_REQUIRED);
267
268 boolean flag = checkActivationFlag(securityGroupStr);
269
270 ComponentConfigService service = get(ComponentConfigService.class);
271 String securityGroupComponent = OpenstackSecurityGroupHandler.class.getName();
272
273 service.setProperty(securityGroupComponent, USE_SECURITY_GROUP_NAME, String.valueOf(flag));
274
275 return ok(mapper().createObjectNode()).build();
276 }
277
278 /**
Jian Li803a1d52018-06-21 21:47:48 +0900279 * Obtains a collection of all floating IPs.
280 *
281 * @return 200 OK with a collection of floating IPs, 404 not found
282 */
283 @GET
284 @Produces(MediaType.APPLICATION_JSON)
285 @Path("floatingips/all")
286 public Response allFloatingIps() {
287
288 List<NetFloatingIP> floatingIps =
289 Lists.newArrayList(osRouterAdminService.floatingIps());
290 floatingIps.stream()
291 .sorted(Comparator.comparing(NetFloatingIP::getFloatingIpAddress))
292 .forEach(fip -> floatingipsNode.add(fip.getFloatingIpAddress()));
293
294 return ok(root).build();
295 }
296
297 /**
298 * Obtains a collection of all floating IPs mapped with fixed IPs.
299 *
300 * @return 200 OK with a collection of floating IPs mapped with fixed IPs,
301 * 404 not found
302 */
303 @GET
304 @Produces(MediaType.APPLICATION_JSON)
305 @Path("floatingips/mapped")
306 public Response mappedFloatingIps() {
307
308 List<NetFloatingIP> floatingIps =
309 Lists.newArrayList(osRouterAdminService.floatingIps());
310
311 floatingIps.stream()
312 .filter(fip -> !Strings.isNullOrEmpty(fip.getFixedIpAddress()))
313 .sorted(Comparator.comparing(NetFloatingIP::getFloatingIpAddress))
314 .forEach(fip -> floatingipsNode.add(fip.getFloatingIpAddress()));
315
316 return ok(root).build();
317 }
Jian Li7f024de2018-07-07 03:51:02 +0900318
319 private void syncRulesBase() {
Jian Li78ac0652018-07-17 18:10:16 +0900320 osNodeAdminService.completeNodes().forEach(osNode -> {
Jian Li7f024de2018-07-07 03:51:02 +0900321 OpenstackNode updated = osNode.updateState(NodeState.INIT);
322 osNodeAdminService.updateNode(updated);
Jian Li88ae51e2018-07-10 02:23:35 +0900323
Jian Lif7934d52018-07-10 16:27:02 +0900324 try {
325 sleep(SLEEP_MS);
326 } catch (InterruptedException e) {
327 log.error("Exception caused during node synchronization...");
328 }
Jian Li88ae51e2018-07-10 02:23:35 +0900329
Jian Li78ac0652018-07-17 18:10:16 +0900330 if (osNodeAdminService.node(osNode.hostname()).state() == NodeState.COMPLETE) {
Jian Lif7934d52018-07-10 16:27:02 +0900331 log.info("Finished sync rules for node {}", osNode.hostname());
332 } else {
333 log.info("Failed to sync rules for node {}", osNode.hostname());
Jian Li88ae51e2018-07-10 02:23:35 +0900334 }
Jian Li7f024de2018-07-07 03:51:02 +0900335 });
336 }
337
338 private void purgeRulesBase() {
339 ApplicationId appId = coreService.getAppId(Constants.OPENSTACK_NETWORKING_APP_ID);
340 if (appId == null) {
341 throw new ItemNotFoundException("application not found");
342 }
343 flowRuleService.removeFlowRulesById(appId);
344 }
345
346 private void configArpModeBase(String arpMode) {
347 ComponentConfigService service = get(ComponentConfigService.class);
348 String switchingComponent = OpenstackSwitchingArpHandler.class.getName();
349 String routingComponent = OpenstackRoutingArpHandler.class.getName();
350
351 service.setProperty(switchingComponent, ARP_MODE_NAME, arpMode);
352 service.setProperty(routingComponent, ARP_MODE_NAME, arpMode);
353 }
Jian Li0b564282018-06-20 00:50:53 +0900354}