blob: 72f23574605146ea00139cc0afa6726245ea403a [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;
32import org.onosproject.openstacknetworking.impl.OpenstackSwitchingArpHandler;
Jian Li0b564282018-06-20 00:50:53 +090033import org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil;
34import org.onosproject.openstacknode.api.NodeState;
35import org.onosproject.openstacknode.api.OpenstackNode;
36import org.onosproject.openstacknode.api.OpenstackNodeAdminService;
Jian Li0b564282018-06-20 00:50:53 +090037import org.onosproject.rest.AbstractWebResource;
38import org.openstack4j.api.OSClient;
Jian Li803a1d52018-06-21 21:47:48 +090039import org.openstack4j.model.network.NetFloatingIP;
Jian Li0b564282018-06-20 00:50:53 +090040import org.slf4j.Logger;
41import org.slf4j.LoggerFactory;
42
43import javax.ws.rs.GET;
44import javax.ws.rs.Path;
Jian Li7f024de2018-07-07 03:51:02 +090045import javax.ws.rs.PathParam;
Jian Li0b564282018-06-20 00:50:53 +090046import javax.ws.rs.Produces;
47import javax.ws.rs.core.MediaType;
48import javax.ws.rs.core.Response;
Jian Li803a1d52018-06-21 21:47:48 +090049import java.util.Comparator;
50import java.util.List;
Jian Li0b564282018-06-20 00:50:53 +090051import java.util.Objects;
52import java.util.Optional;
53
Jian Lif7934d52018-07-10 16:27:02 +090054import static java.lang.Thread.sleep;
Jian Li7f024de2018-07-07 03:51:02 +090055import static org.onlab.util.Tools.nullIsIllegal;
Jian Li0b564282018-06-20 00:50:53 +090056import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.addRouterIface;
Jian Li7f024de2018-07-07 03:51:02 +090057import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.checkArpMode;
58import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValue;
Jian Li0b564282018-06-20 00:50:53 +090059import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.CONTROLLER;
60
61/**
62 * REST interface for synchronizing openstack network states and rules.
63 */
64@Path("management")
65public class OpenstackManagementWebResource extends AbstractWebResource {
66 private final Logger log = LoggerFactory.getLogger(getClass());
67
Jian Li803a1d52018-06-21 21:47:48 +090068 private static final String FLOATINGIPS = "floatingips";
Jian Li7f024de2018-07-07 03:51:02 +090069 private static final String ARP_MODE_NAME = "arpMode";
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 Li803a1d52018-06-21 21:47:48 +090077 private final ObjectNode root = mapper().createObjectNode();
78 private final ArrayNode floatingipsNode = root.putArray(FLOATINGIPS);
Jian Li0b564282018-06-20 00:50:53 +090079
80 private final OpenstackSecurityGroupAdminService osSgAdminService =
81 get(OpenstackSecurityGroupAdminService.class);
82 private final OpenstackNetworkAdminService osNetAdminService =
83 get(OpenstackNetworkAdminService.class);
84 private final OpenstackRouterAdminService osRouterAdminService =
85 get(OpenstackRouterAdminService.class);
Jian Li0b564282018-06-20 00:50:53 +090086 private final OpenstackNodeAdminService osNodeAdminService =
87 get(OpenstackNodeAdminService.class);
88 private final FlowRuleService flowRuleService = get(FlowRuleService.class);
89 private final CoreService coreService = get(CoreService.class);
90
91 /**
92 * Synchronizes the network states with openstack.
93 *
94 * @return 200 OK with sync result, 404 not found
95 */
96 @GET
97 @Produces(MediaType.APPLICATION_JSON)
98 @Path("sync/states")
99 public Response syncStates() {
100
Jian Li78ac0652018-07-17 18:10:16 +0900101 Optional<OpenstackNode> node = osNodeAdminService.nodes(CONTROLLER).stream().findFirst();
Jian Li0b564282018-06-20 00:50:53 +0900102 if (!node.isPresent()) {
103 throw new ItemNotFoundException("Auth info is not found");
104 }
105
106 OSClient osClient = OpenstackNetworkingUtil.getConnectedClient(node.get());
107
108 if (osClient == null) {
109 throw new ItemNotFoundException("Auth info is not correct");
110 }
111
112 osClient.networking().securitygroup().list().forEach(osSg -> {
113 if (osSgAdminService.securityGroup(osSg.getId()) != null) {
114 osSgAdminService.updateSecurityGroup(osSg);
115 } else {
116 osSgAdminService.createSecurityGroup(osSg);
117 }
118 });
119
120 osClient.networking().network().list().forEach(osNet -> {
121 if (osNetAdminService.network(osNet.getId()) != null) {
122 osNetAdminService.updateNetwork(osNet);
123 } else {
124 osNetAdminService.createNetwork(osNet);
125 }
126 });
127
128 osClient.networking().subnet().list().forEach(osSubnet -> {
129 if (osNetAdminService.subnet(osSubnet.getId()) != null) {
130 osNetAdminService.updateSubnet(osSubnet);
131 } else {
132 osNetAdminService.createSubnet(osSubnet);
133 }
134 });
135
136 osClient.networking().port().list().forEach(osPort -> {
137 if (osNetAdminService.port(osPort.getId()) != null) {
138 osNetAdminService.updatePort(osPort);
139 } else {
140 osNetAdminService.createPort(osPort);
141 }
142 });
143
144 osClient.networking().router().list().forEach(osRouter -> {
145 if (osRouterAdminService.router(osRouter.getId()) != null) {
146 osRouterAdminService.updateRouter(osRouter);
147 } else {
148 osRouterAdminService.createRouter(osRouter);
149 }
150
151 osNetAdminService.ports().stream()
152 .filter(osPort -> Objects.equals(osPort.getDeviceId(), osRouter.getId()) &&
153 Objects.equals(osPort.getDeviceOwner(), DEVICE_OWNER_IFACE))
154 .forEach(osPort -> addRouterIface(osPort, osRouterAdminService));
155 });
156
157 osClient.networking().floatingip().list().forEach(osFloating -> {
158 if (osRouterAdminService.floatingIp(osFloating.getId()) != null) {
159 osRouterAdminService.updateFloatingIp(osFloating);
160 } else {
161 osRouterAdminService.createFloatingIp(osFloating);
162 }
163 });
164
165 return ok(mapper().createObjectNode()).build();
166 }
167
168 /**
169 * Synchronizes the flow rules.
170 *
171 * @return 200 OK with sync result, 404 not found
172 */
173 @GET
174 @Produces(MediaType.APPLICATION_JSON)
175 @Path("sync/rules")
176 public Response syncRules() {
177
Jian Li7f024de2018-07-07 03:51:02 +0900178 syncRulesBase();
Jian Li0b564282018-06-20 00:50:53 +0900179 return ok(mapper().createObjectNode()).build();
180 }
181
182 /**
183 * Purges the network states.
184 *
185 * @return 200 OK with purge result, 404 not found
186 */
187 @GET
188 @Produces(MediaType.APPLICATION_JSON)
189 @Path("purge/states")
190 public Response purgeStates() {
191
192 osRouterAdminService.clear();
193 osNetAdminService.clear();
194 osSgAdminService.clear();
195
196 return ok(mapper().createObjectNode()).build();
197 }
198
199 /**
200 * Purges the flow rules installed by openstacknetworking.
201 *
202 * @return 200 OK with purge result, 404 not found
203 */
204 @GET
205 @Produces(MediaType.APPLICATION_JSON)
206 @Path("purge/rules")
207 public Response purgeRules() {
208
Jian Li7f024de2018-07-07 03:51:02 +0900209 purgeRulesBase();
210 return ok(mapper().createObjectNode()).build();
211 }
212
213 /**
214 * Configures the ARP mode (proxy | broadcast).
215 *
216 * @param arpmode ARP mode
217 * @return 200 OK with config result, 404 not found
218 */
219 @GET
220 @Produces(MediaType.APPLICATION_JSON)
221 @Path("config/arpmode/{arpmode}")
222 public Response configArpMode(@PathParam("arpmode") String arpmode) {
223
224 String arpModeStr = nullIsIllegal(arpmode, ARP_MODE_REQUIRED);
225 if (checkArpMode(arpModeStr)) {
226 configArpModeBase(arpModeStr);
227
228 ComponentConfigService service = get(ComponentConfigService.class);
229 String switchingComponent = OpenstackSwitchingArpHandler.class.getName();
230 String routingComponent = OpenstackRoutingArpHandler.class.getName();
231
232 // we check the arpMode configured in each component, and purge and
233 // reinstall all rules only if the arpMode is changed to the configured one
234 while (true) {
235 String switchingValue =
236 getPropertyValue(service.getProperties(switchingComponent), ARP_MODE_NAME);
237 String routingValue =
238 getPropertyValue(service.getProperties(routingComponent), ARP_MODE_NAME);
239
240 if (arpModeStr.equals(switchingValue) && arpModeStr.equals(routingValue)) {
241 break;
242 }
243 }
244
245 purgeRulesBase();
246 syncRulesBase();
247 } else {
248 throw new IllegalArgumentException("The ARP mode is not valid");
Jian Li0b564282018-06-20 00:50:53 +0900249 }
Jian Li0b564282018-06-20 00:50:53 +0900250
251 return ok(mapper().createObjectNode()).build();
252 }
Jian Li803a1d52018-06-21 21:47:48 +0900253
254 /**
255 * Obtains a collection of all floating IPs.
256 *
257 * @return 200 OK with a collection of floating IPs, 404 not found
258 */
259 @GET
260 @Produces(MediaType.APPLICATION_JSON)
261 @Path("floatingips/all")
262 public Response allFloatingIps() {
263
264 List<NetFloatingIP> floatingIps =
265 Lists.newArrayList(osRouterAdminService.floatingIps());
266 floatingIps.stream()
267 .sorted(Comparator.comparing(NetFloatingIP::getFloatingIpAddress))
268 .forEach(fip -> floatingipsNode.add(fip.getFloatingIpAddress()));
269
270 return ok(root).build();
271 }
272
273 /**
274 * Obtains a collection of all floating IPs mapped with fixed IPs.
275 *
276 * @return 200 OK with a collection of floating IPs mapped with fixed IPs,
277 * 404 not found
278 */
279 @GET
280 @Produces(MediaType.APPLICATION_JSON)
281 @Path("floatingips/mapped")
282 public Response mappedFloatingIps() {
283
284 List<NetFloatingIP> floatingIps =
285 Lists.newArrayList(osRouterAdminService.floatingIps());
286
287 floatingIps.stream()
288 .filter(fip -> !Strings.isNullOrEmpty(fip.getFixedIpAddress()))
289 .sorted(Comparator.comparing(NetFloatingIP::getFloatingIpAddress))
290 .forEach(fip -> floatingipsNode.add(fip.getFloatingIpAddress()));
291
292 return ok(root).build();
293 }
Jian Li7f024de2018-07-07 03:51:02 +0900294
295 private void syncRulesBase() {
Jian Li78ac0652018-07-17 18:10:16 +0900296 osNodeAdminService.completeNodes().forEach(osNode -> {
Jian Li7f024de2018-07-07 03:51:02 +0900297 OpenstackNode updated = osNode.updateState(NodeState.INIT);
298 osNodeAdminService.updateNode(updated);
Jian Li88ae51e2018-07-10 02:23:35 +0900299
Jian Lif7934d52018-07-10 16:27:02 +0900300 try {
301 sleep(SLEEP_MS);
302 } catch (InterruptedException e) {
303 log.error("Exception caused during node synchronization...");
304 }
Jian Li88ae51e2018-07-10 02:23:35 +0900305
Jian Li78ac0652018-07-17 18:10:16 +0900306 if (osNodeAdminService.node(osNode.hostname()).state() == NodeState.COMPLETE) {
Jian Lif7934d52018-07-10 16:27:02 +0900307 log.info("Finished sync rules for node {}", osNode.hostname());
308 } else {
309 log.info("Failed to sync rules for node {}", osNode.hostname());
Jian Li88ae51e2018-07-10 02:23:35 +0900310 }
Jian Li7f024de2018-07-07 03:51:02 +0900311 });
312 }
313
314 private void purgeRulesBase() {
315 ApplicationId appId = coreService.getAppId(Constants.OPENSTACK_NETWORKING_APP_ID);
316 if (appId == null) {
317 throw new ItemNotFoundException("application not found");
318 }
319 flowRuleService.removeFlowRulesById(appId);
320 }
321
322 private void configArpModeBase(String arpMode) {
323 ComponentConfigService service = get(ComponentConfigService.class);
324 String switchingComponent = OpenstackSwitchingArpHandler.class.getName();
325 String routingComponent = OpenstackRoutingArpHandler.class.getName();
326
327 service.setProperty(switchingComponent, ARP_MODE_NAME, arpMode);
328 service.setProperty(routingComponent, ARP_MODE_NAME, arpMode);
329 }
Jian Li0b564282018-06-20 00:50:53 +0900330}