blob: 94470eb1a2341784f0aca8f65bed23ee7b2813b0 [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 Li5c777c62018-11-11 00:31:20 +090057import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.addRouterIface;
58import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.checkActivationFlag;
59import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.checkArpMode;
60import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValue;
61import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Jian Li0b564282018-06-20 00:50:53 +090062import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.CONTROLLER;
Jian Li5c777c62018-11-11 00:31:20 +090063import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Jian Li0b564282018-06-20 00:50:53 +090064
65/**
66 * REST interface for synchronizing openstack network states and rules.
67 */
68@Path("management")
69public class OpenstackManagementWebResource extends AbstractWebResource {
70 private final Logger log = LoggerFactory.getLogger(getClass());
71
Jian Li803a1d52018-06-21 21:47:48 +090072 private static final String FLOATINGIPS = "floatingips";
Jian Li7f024de2018-07-07 03:51:02 +090073 private static final String ARP_MODE_NAME = "arpMode";
Jian Licad36c72018-09-13 17:44:54 +090074 private static final String USE_SECURITY_GROUP_NAME = "useSecurityGroup";
Jian Li803a1d52018-06-21 21:47:48 +090075
Jian Lif7934d52018-07-10 16:27:02 +090076 private static final long SLEEP_MS = 3000; // we wait 3s for init each node
Jian Li88ae51e2018-07-10 02:23:35 +090077
Jian Li0b564282018-06-20 00:50:53 +090078 private static final String DEVICE_OWNER_IFACE = "network:router_interface";
Jian Li7f024de2018-07-07 03:51:02 +090079
80 private static final String ARP_MODE_REQUIRED = "ARP mode is not specified";
81
Jian Licad36c72018-09-13 17:44:54 +090082 private static final String SECURITY_GROUP_FLAG_REQUIRED = "Security Group flag is not specified";
83
Jian Li803a1d52018-06-21 21:47:48 +090084 private final ObjectNode root = mapper().createObjectNode();
85 private final ArrayNode floatingipsNode = root.putArray(FLOATINGIPS);
Jian Li0b564282018-06-20 00:50:53 +090086
87 private final OpenstackSecurityGroupAdminService osSgAdminService =
88 get(OpenstackSecurityGroupAdminService.class);
89 private final OpenstackNetworkAdminService osNetAdminService =
90 get(OpenstackNetworkAdminService.class);
91 private final OpenstackRouterAdminService osRouterAdminService =
92 get(OpenstackRouterAdminService.class);
Jian Li0b564282018-06-20 00:50:53 +090093 private final OpenstackNodeAdminService osNodeAdminService =
94 get(OpenstackNodeAdminService.class);
95 private final FlowRuleService flowRuleService = get(FlowRuleService.class);
96 private final CoreService coreService = get(CoreService.class);
97
98 /**
99 * Synchronizes the network states with openstack.
100 *
101 * @return 200 OK with sync result, 404 not found
102 */
103 @GET
104 @Produces(MediaType.APPLICATION_JSON)
105 @Path("sync/states")
106 public Response syncStates() {
107
Jian Li78ac0652018-07-17 18:10:16 +0900108 Optional<OpenstackNode> node = osNodeAdminService.nodes(CONTROLLER).stream().findFirst();
Jian Li0b564282018-06-20 00:50:53 +0900109 if (!node.isPresent()) {
110 throw new ItemNotFoundException("Auth info is not found");
111 }
112
113 OSClient osClient = OpenstackNetworkingUtil.getConnectedClient(node.get());
114
115 if (osClient == null) {
116 throw new ItemNotFoundException("Auth info is not correct");
117 }
118
119 osClient.networking().securitygroup().list().forEach(osSg -> {
120 if (osSgAdminService.securityGroup(osSg.getId()) != null) {
121 osSgAdminService.updateSecurityGroup(osSg);
122 } else {
123 osSgAdminService.createSecurityGroup(osSg);
124 }
125 });
126
127 osClient.networking().network().list().forEach(osNet -> {
128 if (osNetAdminService.network(osNet.getId()) != null) {
129 osNetAdminService.updateNetwork(osNet);
130 } else {
131 osNetAdminService.createNetwork(osNet);
132 }
133 });
134
135 osClient.networking().subnet().list().forEach(osSubnet -> {
136 if (osNetAdminService.subnet(osSubnet.getId()) != null) {
137 osNetAdminService.updateSubnet(osSubnet);
138 } else {
139 osNetAdminService.createSubnet(osSubnet);
140 }
141 });
142
143 osClient.networking().port().list().forEach(osPort -> {
144 if (osNetAdminService.port(osPort.getId()) != null) {
145 osNetAdminService.updatePort(osPort);
146 } else {
147 osNetAdminService.createPort(osPort);
148 }
149 });
150
151 osClient.networking().router().list().forEach(osRouter -> {
152 if (osRouterAdminService.router(osRouter.getId()) != null) {
153 osRouterAdminService.updateRouter(osRouter);
154 } else {
155 osRouterAdminService.createRouter(osRouter);
156 }
157
158 osNetAdminService.ports().stream()
159 .filter(osPort -> Objects.equals(osPort.getDeviceId(), osRouter.getId()) &&
160 Objects.equals(osPort.getDeviceOwner(), DEVICE_OWNER_IFACE))
161 .forEach(osPort -> addRouterIface(osPort, osRouterAdminService));
162 });
163
164 osClient.networking().floatingip().list().forEach(osFloating -> {
165 if (osRouterAdminService.floatingIp(osFloating.getId()) != null) {
166 osRouterAdminService.updateFloatingIp(osFloating);
167 } else {
168 osRouterAdminService.createFloatingIp(osFloating);
169 }
170 });
171
172 return ok(mapper().createObjectNode()).build();
173 }
174
175 /**
176 * Synchronizes the flow rules.
177 *
178 * @return 200 OK with sync result, 404 not found
179 */
180 @GET
181 @Produces(MediaType.APPLICATION_JSON)
182 @Path("sync/rules")
183 public Response syncRules() {
184
Jian Li7f024de2018-07-07 03:51:02 +0900185 syncRulesBase();
Jian Li0b564282018-06-20 00:50:53 +0900186 return ok(mapper().createObjectNode()).build();
187 }
188
189 /**
190 * Purges the network states.
191 *
192 * @return 200 OK with purge result, 404 not found
193 */
194 @GET
195 @Produces(MediaType.APPLICATION_JSON)
196 @Path("purge/states")
197 public Response purgeStates() {
198
199 osRouterAdminService.clear();
200 osNetAdminService.clear();
201 osSgAdminService.clear();
202
203 return ok(mapper().createObjectNode()).build();
204 }
205
206 /**
207 * Purges the flow rules installed by openstacknetworking.
208 *
209 * @return 200 OK with purge result, 404 not found
210 */
211 @GET
212 @Produces(MediaType.APPLICATION_JSON)
213 @Path("purge/rules")
214 public Response purgeRules() {
215
Jian Li7f024de2018-07-07 03:51:02 +0900216 purgeRulesBase();
217 return ok(mapper().createObjectNode()).build();
218 }
219
220 /**
221 * Configures the ARP mode (proxy | broadcast).
222 *
223 * @param arpmode ARP mode
224 * @return 200 OK with config result, 404 not found
225 */
226 @GET
227 @Produces(MediaType.APPLICATION_JSON)
228 @Path("config/arpmode/{arpmode}")
229 public Response configArpMode(@PathParam("arpmode") String arpmode) {
230
231 String arpModeStr = nullIsIllegal(arpmode, ARP_MODE_REQUIRED);
232 if (checkArpMode(arpModeStr)) {
233 configArpModeBase(arpModeStr);
234
235 ComponentConfigService service = get(ComponentConfigService.class);
236 String switchingComponent = OpenstackSwitchingArpHandler.class.getName();
237 String routingComponent = OpenstackRoutingArpHandler.class.getName();
238
239 // we check the arpMode configured in each component, and purge and
240 // reinstall all rules only if the arpMode is changed to the configured one
241 while (true) {
242 String switchingValue =
243 getPropertyValue(service.getProperties(switchingComponent), ARP_MODE_NAME);
244 String routingValue =
245 getPropertyValue(service.getProperties(routingComponent), ARP_MODE_NAME);
246
247 if (arpModeStr.equals(switchingValue) && arpModeStr.equals(routingValue)) {
248 break;
249 }
250 }
251
252 purgeRulesBase();
253 syncRulesBase();
254 } else {
255 throw new IllegalArgumentException("The ARP mode is not valid");
Jian Li0b564282018-06-20 00:50:53 +0900256 }
Jian Li0b564282018-06-20 00:50:53 +0900257
258 return ok(mapper().createObjectNode()).build();
259 }
Jian Li803a1d52018-06-21 21:47:48 +0900260
261 /**
Jian Licad36c72018-09-13 17:44:54 +0900262 * Configures the security group (enable | disable).
263 *
264 * @param securityGroup security group activation flag
265 * @return 200 OK with config result, 404 not found
266 */
267 @GET
268 @Produces(MediaType.APPLICATION_JSON)
269 @Path("config/securityGroup/{securityGroup}")
270 public Response configSecurityGroup(@PathParam("securityGroup") String securityGroup) {
271 String securityGroupStr = nullIsIllegal(securityGroup, SECURITY_GROUP_FLAG_REQUIRED);
272
273 boolean flag = checkActivationFlag(securityGroupStr);
274
275 ComponentConfigService service = get(ComponentConfigService.class);
276 String securityGroupComponent = OpenstackSecurityGroupHandler.class.getName();
277
278 service.setProperty(securityGroupComponent, USE_SECURITY_GROUP_NAME, String.valueOf(flag));
279
280 return ok(mapper().createObjectNode()).build();
281 }
282
283 /**
Jian Li803a1d52018-06-21 21:47:48 +0900284 * Obtains a collection of all floating IPs.
285 *
286 * @return 200 OK with a collection of floating IPs, 404 not found
287 */
288 @GET
289 @Produces(MediaType.APPLICATION_JSON)
290 @Path("floatingips/all")
291 public Response allFloatingIps() {
292
293 List<NetFloatingIP> floatingIps =
294 Lists.newArrayList(osRouterAdminService.floatingIps());
295 floatingIps.stream()
296 .sorted(Comparator.comparing(NetFloatingIP::getFloatingIpAddress))
297 .forEach(fip -> floatingipsNode.add(fip.getFloatingIpAddress()));
298
299 return ok(root).build();
300 }
301
302 /**
303 * Obtains a collection of all floating IPs mapped with fixed IPs.
304 *
305 * @return 200 OK with a collection of floating IPs mapped with fixed IPs,
306 * 404 not found
307 */
308 @GET
309 @Produces(MediaType.APPLICATION_JSON)
310 @Path("floatingips/mapped")
311 public Response mappedFloatingIps() {
312
313 List<NetFloatingIP> floatingIps =
314 Lists.newArrayList(osRouterAdminService.floatingIps());
315
316 floatingIps.stream()
317 .filter(fip -> !Strings.isNullOrEmpty(fip.getFixedIpAddress()))
318 .sorted(Comparator.comparing(NetFloatingIP::getFloatingIpAddress))
319 .forEach(fip -> floatingipsNode.add(fip.getFloatingIpAddress()));
320
321 return ok(root).build();
322 }
Jian Li7f024de2018-07-07 03:51:02 +0900323
324 private void syncRulesBase() {
Jian Li5c777c62018-11-11 00:31:20 +0900325 // we first initialize the COMPUTE node, in order to feed all instance ports
326 // by referring to ports' information obtained from neutron server
327 osNodeAdminService.completeNodes(COMPUTE).forEach(this::syncRulesBaseForNode);
328 osNodeAdminService.completeNodes(GATEWAY).forEach(this::syncRulesBaseForNode);
329 }
Jian Li88ae51e2018-07-10 02:23:35 +0900330
Jian Li5c777c62018-11-11 00:31:20 +0900331 private void syncRulesBaseForNode(OpenstackNode osNode) {
332 OpenstackNode updated = osNode.updateState(NodeState.INIT);
333 osNodeAdminService.updateNode(updated);
Jian Li88ae51e2018-07-10 02:23:35 +0900334
Jian Li5c777c62018-11-11 00:31:20 +0900335 try {
336 sleep(SLEEP_MS);
337 } catch (InterruptedException e) {
338 log.error("Exception caused during node synchronization...");
339 }
340
341 if (osNodeAdminService.node(osNode.hostname()).state() == NodeState.COMPLETE) {
342 log.info("Finished sync rules for node {}", osNode.hostname());
343 } else {
344 log.info("Failed to sync rules for node {}", osNode.hostname());
345 }
Jian Li7f024de2018-07-07 03:51:02 +0900346 }
347
348 private void purgeRulesBase() {
349 ApplicationId appId = coreService.getAppId(Constants.OPENSTACK_NETWORKING_APP_ID);
350 if (appId == null) {
351 throw new ItemNotFoundException("application not found");
352 }
353 flowRuleService.removeFlowRulesById(appId);
354 }
355
356 private void configArpModeBase(String arpMode) {
357 ComponentConfigService service = get(ComponentConfigService.class);
358 String switchingComponent = OpenstackSwitchingArpHandler.class.getName();
359 String routingComponent = OpenstackRoutingArpHandler.class.getName();
360
361 service.setProperty(switchingComponent, ARP_MODE_NAME, arpMode);
362 service.setProperty(routingComponent, ARP_MODE_NAME, arpMode);
363 }
Jian Li0b564282018-06-20 00:50:53 +0900364}