blob: 72f23574605146ea00139cc0afa6726245ea403a [file] [log] [blame]
/*
* Copyright 2018-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.openstacknetworking.web;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import org.onlab.util.ItemNotFoundException;
import org.onosproject.cfg.ComponentConfigService;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.net.flow.FlowRuleService;
import org.onosproject.openstacknetworking.api.Constants;
import org.onosproject.openstacknetworking.api.OpenstackNetworkAdminService;
import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupAdminService;
import org.onosproject.openstacknetworking.impl.OpenstackRoutingArpHandler;
import org.onosproject.openstacknetworking.impl.OpenstackSwitchingArpHandler;
import org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil;
import org.onosproject.openstacknode.api.NodeState;
import org.onosproject.openstacknode.api.OpenstackNode;
import org.onosproject.openstacknode.api.OpenstackNodeAdminService;
import org.onosproject.rest.AbstractWebResource;
import org.openstack4j.api.OSClient;
import org.openstack4j.model.network.NetFloatingIP;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import static java.lang.Thread.sleep;
import static org.onlab.util.Tools.nullIsIllegal;
import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.addRouterIface;
import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.checkArpMode;
import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValue;
import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.CONTROLLER;
/**
* REST interface for synchronizing openstack network states and rules.
*/
@Path("management")
public class OpenstackManagementWebResource extends AbstractWebResource {
private final Logger log = LoggerFactory.getLogger(getClass());
private static final String FLOATINGIPS = "floatingips";
private static final String ARP_MODE_NAME = "arpMode";
private static final long SLEEP_MS = 3000; // we wait 3s for init each node
private static final String DEVICE_OWNER_IFACE = "network:router_interface";
private static final String ARP_MODE_REQUIRED = "ARP mode is not specified";
private final ObjectNode root = mapper().createObjectNode();
private final ArrayNode floatingipsNode = root.putArray(FLOATINGIPS);
private final OpenstackSecurityGroupAdminService osSgAdminService =
get(OpenstackSecurityGroupAdminService.class);
private final OpenstackNetworkAdminService osNetAdminService =
get(OpenstackNetworkAdminService.class);
private final OpenstackRouterAdminService osRouterAdminService =
get(OpenstackRouterAdminService.class);
private final OpenstackNodeAdminService osNodeAdminService =
get(OpenstackNodeAdminService.class);
private final FlowRuleService flowRuleService = get(FlowRuleService.class);
private final CoreService coreService = get(CoreService.class);
/**
* Synchronizes the network states with openstack.
*
* @return 200 OK with sync result, 404 not found
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("sync/states")
public Response syncStates() {
Optional<OpenstackNode> node = osNodeAdminService.nodes(CONTROLLER).stream().findFirst();
if (!node.isPresent()) {
throw new ItemNotFoundException("Auth info is not found");
}
OSClient osClient = OpenstackNetworkingUtil.getConnectedClient(node.get());
if (osClient == null) {
throw new ItemNotFoundException("Auth info is not correct");
}
osClient.networking().securitygroup().list().forEach(osSg -> {
if (osSgAdminService.securityGroup(osSg.getId()) != null) {
osSgAdminService.updateSecurityGroup(osSg);
} else {
osSgAdminService.createSecurityGroup(osSg);
}
});
osClient.networking().network().list().forEach(osNet -> {
if (osNetAdminService.network(osNet.getId()) != null) {
osNetAdminService.updateNetwork(osNet);
} else {
osNetAdminService.createNetwork(osNet);
}
});
osClient.networking().subnet().list().forEach(osSubnet -> {
if (osNetAdminService.subnet(osSubnet.getId()) != null) {
osNetAdminService.updateSubnet(osSubnet);
} else {
osNetAdminService.createSubnet(osSubnet);
}
});
osClient.networking().port().list().forEach(osPort -> {
if (osNetAdminService.port(osPort.getId()) != null) {
osNetAdminService.updatePort(osPort);
} else {
osNetAdminService.createPort(osPort);
}
});
osClient.networking().router().list().forEach(osRouter -> {
if (osRouterAdminService.router(osRouter.getId()) != null) {
osRouterAdminService.updateRouter(osRouter);
} else {
osRouterAdminService.createRouter(osRouter);
}
osNetAdminService.ports().stream()
.filter(osPort -> Objects.equals(osPort.getDeviceId(), osRouter.getId()) &&
Objects.equals(osPort.getDeviceOwner(), DEVICE_OWNER_IFACE))
.forEach(osPort -> addRouterIface(osPort, osRouterAdminService));
});
osClient.networking().floatingip().list().forEach(osFloating -> {
if (osRouterAdminService.floatingIp(osFloating.getId()) != null) {
osRouterAdminService.updateFloatingIp(osFloating);
} else {
osRouterAdminService.createFloatingIp(osFloating);
}
});
return ok(mapper().createObjectNode()).build();
}
/**
* Synchronizes the flow rules.
*
* @return 200 OK with sync result, 404 not found
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("sync/rules")
public Response syncRules() {
syncRulesBase();
return ok(mapper().createObjectNode()).build();
}
/**
* Purges the network states.
*
* @return 200 OK with purge result, 404 not found
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("purge/states")
public Response purgeStates() {
osRouterAdminService.clear();
osNetAdminService.clear();
osSgAdminService.clear();
return ok(mapper().createObjectNode()).build();
}
/**
* Purges the flow rules installed by openstacknetworking.
*
* @return 200 OK with purge result, 404 not found
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("purge/rules")
public Response purgeRules() {
purgeRulesBase();
return ok(mapper().createObjectNode()).build();
}
/**
* Configures the ARP mode (proxy | broadcast).
*
* @param arpmode ARP mode
* @return 200 OK with config result, 404 not found
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("config/arpmode/{arpmode}")
public Response configArpMode(@PathParam("arpmode") String arpmode) {
String arpModeStr = nullIsIllegal(arpmode, ARP_MODE_REQUIRED);
if (checkArpMode(arpModeStr)) {
configArpModeBase(arpModeStr);
ComponentConfigService service = get(ComponentConfigService.class);
String switchingComponent = OpenstackSwitchingArpHandler.class.getName();
String routingComponent = OpenstackRoutingArpHandler.class.getName();
// we check the arpMode configured in each component, and purge and
// reinstall all rules only if the arpMode is changed to the configured one
while (true) {
String switchingValue =
getPropertyValue(service.getProperties(switchingComponent), ARP_MODE_NAME);
String routingValue =
getPropertyValue(service.getProperties(routingComponent), ARP_MODE_NAME);
if (arpModeStr.equals(switchingValue) && arpModeStr.equals(routingValue)) {
break;
}
}
purgeRulesBase();
syncRulesBase();
} else {
throw new IllegalArgumentException("The ARP mode is not valid");
}
return ok(mapper().createObjectNode()).build();
}
/**
* Obtains a collection of all floating IPs.
*
* @return 200 OK with a collection of floating IPs, 404 not found
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("floatingips/all")
public Response allFloatingIps() {
List<NetFloatingIP> floatingIps =
Lists.newArrayList(osRouterAdminService.floatingIps());
floatingIps.stream()
.sorted(Comparator.comparing(NetFloatingIP::getFloatingIpAddress))
.forEach(fip -> floatingipsNode.add(fip.getFloatingIpAddress()));
return ok(root).build();
}
/**
* Obtains a collection of all floating IPs mapped with fixed IPs.
*
* @return 200 OK with a collection of floating IPs mapped with fixed IPs,
* 404 not found
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("floatingips/mapped")
public Response mappedFloatingIps() {
List<NetFloatingIP> floatingIps =
Lists.newArrayList(osRouterAdminService.floatingIps());
floatingIps.stream()
.filter(fip -> !Strings.isNullOrEmpty(fip.getFixedIpAddress()))
.sorted(Comparator.comparing(NetFloatingIP::getFloatingIpAddress))
.forEach(fip -> floatingipsNode.add(fip.getFloatingIpAddress()));
return ok(root).build();
}
private void syncRulesBase() {
osNodeAdminService.completeNodes().forEach(osNode -> {
OpenstackNode updated = osNode.updateState(NodeState.INIT);
osNodeAdminService.updateNode(updated);
try {
sleep(SLEEP_MS);
} catch (InterruptedException e) {
log.error("Exception caused during node synchronization...");
}
if (osNodeAdminService.node(osNode.hostname()).state() == NodeState.COMPLETE) {
log.info("Finished sync rules for node {}", osNode.hostname());
} else {
log.info("Failed to sync rules for node {}", osNode.hostname());
}
});
}
private void purgeRulesBase() {
ApplicationId appId = coreService.getAppId(Constants.OPENSTACK_NETWORKING_APP_ID);
if (appId == null) {
throw new ItemNotFoundException("application not found");
}
flowRuleService.removeFlowRulesById(appId);
}
private void configArpModeBase(String arpMode) {
ComponentConfigService service = get(ComponentConfigService.class);
String switchingComponent = OpenstackSwitchingArpHandler.class.getName();
String routingComponent = OpenstackRoutingArpHandler.class.getName();
service.setProperty(switchingComponent, ARP_MODE_NAME, arpMode);
service.setProperty(routingComponent, ARP_MODE_NAME, arpMode);
}
}