blob: 3af0ecad010ee499cad50bee25361bf11dbde452 [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;
37import org.onosproject.openstacknode.api.OpenstackNodeService;
38import 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 Li0b564282018-06-20 00:50:53 +090057import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.addRouterIface;
Jian Li7f024de2018-07-07 03:51:02 +090058import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.checkArpMode;
59import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValue;
Jian Li0b564282018-06-20 00:50:53 +090060import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.CONTROLLER;
61
62/**
63 * REST interface for synchronizing openstack network states and rules.
64 */
65@Path("management")
66public class OpenstackManagementWebResource extends AbstractWebResource {
67 private final Logger log = LoggerFactory.getLogger(getClass());
68
Jian Li803a1d52018-06-21 21:47:48 +090069 private static final String FLOATINGIPS = "floatingips";
Jian Li7f024de2018-07-07 03:51:02 +090070 private static final String ARP_MODE_NAME = "arpMode";
Jian Li803a1d52018-06-21 21:47:48 +090071
Jian Lif7934d52018-07-10 16:27:02 +090072 private static final long SLEEP_MS = 3000; // we wait 3s for init each node
Jian Li88ae51e2018-07-10 02:23:35 +090073
Jian Li0b564282018-06-20 00:50:53 +090074 private static final String DEVICE_OWNER_IFACE = "network:router_interface";
Jian Li7f024de2018-07-07 03:51:02 +090075
76 private static final String ARP_MODE_REQUIRED = "ARP mode is not specified";
77
Jian Li803a1d52018-06-21 21:47:48 +090078 private final ObjectNode root = mapper().createObjectNode();
79 private final ArrayNode floatingipsNode = root.putArray(FLOATINGIPS);
Jian Li0b564282018-06-20 00:50:53 +090080
81 private final OpenstackSecurityGroupAdminService osSgAdminService =
82 get(OpenstackSecurityGroupAdminService.class);
83 private final OpenstackNetworkAdminService osNetAdminService =
84 get(OpenstackNetworkAdminService.class);
85 private final OpenstackRouterAdminService osRouterAdminService =
86 get(OpenstackRouterAdminService.class);
87 private final OpenstackNodeService osNodeService =
88 get(OpenstackNodeService.class);
89 private final OpenstackNodeAdminService osNodeAdminService =
90 get(OpenstackNodeAdminService.class);
91 private final FlowRuleService flowRuleService = get(FlowRuleService.class);
92 private final CoreService coreService = get(CoreService.class);
93
94 /**
95 * Synchronizes the network states with openstack.
96 *
97 * @return 200 OK with sync result, 404 not found
98 */
99 @GET
100 @Produces(MediaType.APPLICATION_JSON)
101 @Path("sync/states")
102 public Response syncStates() {
103
104 Optional<OpenstackNode> node = osNodeService.nodes(CONTROLLER).stream().findFirst();
105 if (!node.isPresent()) {
106 throw new ItemNotFoundException("Auth info is not found");
107 }
108
109 OSClient osClient = OpenstackNetworkingUtil.getConnectedClient(node.get());
110
111 if (osClient == null) {
112 throw new ItemNotFoundException("Auth info is not correct");
113 }
114
115 osClient.networking().securitygroup().list().forEach(osSg -> {
116 if (osSgAdminService.securityGroup(osSg.getId()) != null) {
117 osSgAdminService.updateSecurityGroup(osSg);
118 } else {
119 osSgAdminService.createSecurityGroup(osSg);
120 }
121 });
122
123 osClient.networking().network().list().forEach(osNet -> {
124 if (osNetAdminService.network(osNet.getId()) != null) {
125 osNetAdminService.updateNetwork(osNet);
126 } else {
127 osNetAdminService.createNetwork(osNet);
128 }
129 });
130
131 osClient.networking().subnet().list().forEach(osSubnet -> {
132 if (osNetAdminService.subnet(osSubnet.getId()) != null) {
133 osNetAdminService.updateSubnet(osSubnet);
134 } else {
135 osNetAdminService.createSubnet(osSubnet);
136 }
137 });
138
139 osClient.networking().port().list().forEach(osPort -> {
140 if (osNetAdminService.port(osPort.getId()) != null) {
141 osNetAdminService.updatePort(osPort);
142 } else {
143 osNetAdminService.createPort(osPort);
144 }
145 });
146
147 osClient.networking().router().list().forEach(osRouter -> {
148 if (osRouterAdminService.router(osRouter.getId()) != null) {
149 osRouterAdminService.updateRouter(osRouter);
150 } else {
151 osRouterAdminService.createRouter(osRouter);
152 }
153
154 osNetAdminService.ports().stream()
155 .filter(osPort -> Objects.equals(osPort.getDeviceId(), osRouter.getId()) &&
156 Objects.equals(osPort.getDeviceOwner(), DEVICE_OWNER_IFACE))
157 .forEach(osPort -> addRouterIface(osPort, osRouterAdminService));
158 });
159
160 osClient.networking().floatingip().list().forEach(osFloating -> {
161 if (osRouterAdminService.floatingIp(osFloating.getId()) != null) {
162 osRouterAdminService.updateFloatingIp(osFloating);
163 } else {
164 osRouterAdminService.createFloatingIp(osFloating);
165 }
166 });
167
168 return ok(mapper().createObjectNode()).build();
169 }
170
171 /**
172 * Synchronizes the flow rules.
173 *
174 * @return 200 OK with sync result, 404 not found
175 */
176 @GET
177 @Produces(MediaType.APPLICATION_JSON)
178 @Path("sync/rules")
179 public Response syncRules() {
180
Jian Li7f024de2018-07-07 03:51:02 +0900181 syncRulesBase();
Jian Li0b564282018-06-20 00:50:53 +0900182 return ok(mapper().createObjectNode()).build();
183 }
184
185 /**
186 * Purges the network states.
187 *
188 * @return 200 OK with purge result, 404 not found
189 */
190 @GET
191 @Produces(MediaType.APPLICATION_JSON)
192 @Path("purge/states")
193 public Response purgeStates() {
194
195 osRouterAdminService.clear();
196 osNetAdminService.clear();
197 osSgAdminService.clear();
198
199 return ok(mapper().createObjectNode()).build();
200 }
201
202 /**
203 * Purges the flow rules installed by openstacknetworking.
204 *
205 * @return 200 OK with purge result, 404 not found
206 */
207 @GET
208 @Produces(MediaType.APPLICATION_JSON)
209 @Path("purge/rules")
210 public Response purgeRules() {
211
Jian Li7f024de2018-07-07 03:51:02 +0900212 purgeRulesBase();
213 return ok(mapper().createObjectNode()).build();
214 }
215
216 /**
217 * Configures the ARP mode (proxy | broadcast).
218 *
219 * @param arpmode ARP mode
220 * @return 200 OK with config result, 404 not found
221 */
222 @GET
223 @Produces(MediaType.APPLICATION_JSON)
224 @Path("config/arpmode/{arpmode}")
225 public Response configArpMode(@PathParam("arpmode") String arpmode) {
226
227 String arpModeStr = nullIsIllegal(arpmode, ARP_MODE_REQUIRED);
228 if (checkArpMode(arpModeStr)) {
229 configArpModeBase(arpModeStr);
230
231 ComponentConfigService service = get(ComponentConfigService.class);
232 String switchingComponent = OpenstackSwitchingArpHandler.class.getName();
233 String routingComponent = OpenstackRoutingArpHandler.class.getName();
234
235 // we check the arpMode configured in each component, and purge and
236 // reinstall all rules only if the arpMode is changed to the configured one
237 while (true) {
238 String switchingValue =
239 getPropertyValue(service.getProperties(switchingComponent), ARP_MODE_NAME);
240 String routingValue =
241 getPropertyValue(service.getProperties(routingComponent), ARP_MODE_NAME);
242
243 if (arpModeStr.equals(switchingValue) && arpModeStr.equals(routingValue)) {
244 break;
245 }
246 }
247
248 purgeRulesBase();
249 syncRulesBase();
250 } else {
251 throw new IllegalArgumentException("The ARP mode is not valid");
Jian Li0b564282018-06-20 00:50:53 +0900252 }
Jian Li0b564282018-06-20 00:50:53 +0900253
254 return ok(mapper().createObjectNode()).build();
255 }
Jian Li803a1d52018-06-21 21:47:48 +0900256
257 /**
258 * Obtains a collection of all floating IPs.
259 *
260 * @return 200 OK with a collection of floating IPs, 404 not found
261 */
262 @GET
263 @Produces(MediaType.APPLICATION_JSON)
264 @Path("floatingips/all")
265 public Response allFloatingIps() {
266
267 List<NetFloatingIP> floatingIps =
268 Lists.newArrayList(osRouterAdminService.floatingIps());
269 floatingIps.stream()
270 .sorted(Comparator.comparing(NetFloatingIP::getFloatingIpAddress))
271 .forEach(fip -> floatingipsNode.add(fip.getFloatingIpAddress()));
272
273 return ok(root).build();
274 }
275
276 /**
277 * Obtains a collection of all floating IPs mapped with fixed IPs.
278 *
279 * @return 200 OK with a collection of floating IPs mapped with fixed IPs,
280 * 404 not found
281 */
282 @GET
283 @Produces(MediaType.APPLICATION_JSON)
284 @Path("floatingips/mapped")
285 public Response mappedFloatingIps() {
286
287 List<NetFloatingIP> floatingIps =
288 Lists.newArrayList(osRouterAdminService.floatingIps());
289
290 floatingIps.stream()
291 .filter(fip -> !Strings.isNullOrEmpty(fip.getFixedIpAddress()))
292 .sorted(Comparator.comparing(NetFloatingIP::getFloatingIpAddress))
293 .forEach(fip -> floatingipsNode.add(fip.getFloatingIpAddress()));
294
295 return ok(root).build();
296 }
Jian Li7f024de2018-07-07 03:51:02 +0900297
298 private void syncRulesBase() {
299 osNodeService.completeNodes().forEach(osNode -> {
300 OpenstackNode updated = osNode.updateState(NodeState.INIT);
301 osNodeAdminService.updateNode(updated);
Jian Li88ae51e2018-07-10 02:23:35 +0900302
Jian Lif7934d52018-07-10 16:27:02 +0900303 try {
304 sleep(SLEEP_MS);
305 } catch (InterruptedException e) {
306 log.error("Exception caused during node synchronization...");
307 }
Jian Li88ae51e2018-07-10 02:23:35 +0900308
Jian Lif7934d52018-07-10 16:27:02 +0900309 if (osNodeService.node(osNode.hostname()).state() == NodeState.COMPLETE) {
310 log.info("Finished sync rules for node {}", osNode.hostname());
311 } else {
312 log.info("Failed to sync rules for node {}", osNode.hostname());
Jian Li88ae51e2018-07-10 02:23:35 +0900313 }
Jian Li7f024de2018-07-07 03:51:02 +0900314 });
315 }
316
317 private void purgeRulesBase() {
318 ApplicationId appId = coreService.getAppId(Constants.OPENSTACK_NETWORKING_APP_ID);
319 if (appId == null) {
320 throw new ItemNotFoundException("application not found");
321 }
322 flowRuleService.removeFlowRulesById(appId);
323 }
324
325 private void configArpModeBase(String arpMode) {
326 ComponentConfigService service = get(ComponentConfigService.class);
327 String switchingComponent = OpenstackSwitchingArpHandler.class.getName();
328 String routingComponent = OpenstackRoutingArpHandler.class.getName();
329
330 service.setProperty(switchingComponent, ARP_MODE_NAME, arpMode);
331 service.setProperty(routingComponent, ARP_MODE_NAME, arpMode);
332 }
Jian Li0b564282018-06-20 00:50:53 +0900333}