ONOS-5970 Added CLIs to purge and sync network states from Neutron
Change-Id: Icd1f4c174de20e261229f30ddfd6857c26cb038c
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/api/OpenstackNetworkAdminService.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/api/OpenstackNetworkAdminService.java
index 5ebb559..f0a2442 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/api/OpenstackNetworkAdminService.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/api/OpenstackNetworkAdminService.java
@@ -86,4 +86,9 @@
* @param portId port id
*/
void removePort(String portId);
+
+ /**
+ * Clears the existing network, subnet and port states.
+ */
+ void clear();
}
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/api/OpenstackNetworkStore.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/api/OpenstackNetworkStore.java
index 86f338fe..671b811 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/api/OpenstackNetworkStore.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/api/OpenstackNetworkStore.java
@@ -138,4 +138,9 @@
* @return set of ports
*/
Set<Port> ports();
+
+ /**
+ * Removes the existing network and ports.
+ */
+ void clear();
}
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/api/OpenstackRouterAdminService.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/api/OpenstackRouterAdminService.java
index 5870eb0..7d4df84 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/api/OpenstackRouterAdminService.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/api/OpenstackRouterAdminService.java
@@ -45,6 +45,7 @@
*/
void removeRouter(String osRouterId);
+ // TODO fix the logic adding a router interface to a router
/**
* Adds a new interface to the router.
*
@@ -86,4 +87,9 @@
* @param floatingIpId floating ip id
*/
void removeFloatingIp(String floatingIpId);
+
+ /**
+ * Clears the existing routers and floating IPs.
+ */
+ void clear();
}
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/api/OpenstackRouterStore.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/api/OpenstackRouterStore.java
index b0744a0..fa83509 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/api/OpenstackRouterStore.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/api/OpenstackRouterStore.java
@@ -138,4 +138,9 @@
* @return openstack floating ip; empty set if no floating ip exists
*/
Set<NetFloatingIP> floatingIps();
+
+ /**
+ * Clears the existing routers and floating IPs.
+ */
+ void clear();
}
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackPurgeStateCommand.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackPurgeStateCommand.java
new file mode 100644
index 0000000..6f28590
--- /dev/null
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackPurgeStateCommand.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * 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.cli;
+
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.openstacknetworking.api.OpenstackNetworkAdminService;
+import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
+
+/**
+ * Purges all existing network states.
+ */
+@Command(scope = "onos", name = "openstack-purge-states",
+ description = "Purges all OpenStack network states")
+public class OpenstackPurgeStateCommand extends AbstractShellCommand {
+
+ @Override
+ protected void execute() {
+ get(OpenstackNetworkAdminService.class).clear();
+ get(OpenstackRouterAdminService.class).clear();
+ }
+}
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackSyncStateCommand.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackSyncStateCommand.java
new file mode 100644
index 0000000..d07591e
--- /dev/null
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackSyncStateCommand.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * 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.cli;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.base.Strings;
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.openstacknetworking.api.OpenstackNetworkAdminService;
+import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
+import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
+import org.onosproject.openstacknetworking.api.OpenstackRouterService;
+import org.openstack4j.api.OSClient;
+import org.openstack4j.api.exceptions.AuthenticationException;
+import org.openstack4j.model.identity.Access;
+import org.openstack4j.model.network.IP;
+import org.openstack4j.model.network.NetFloatingIP;
+import org.openstack4j.model.network.Network;
+import org.openstack4j.model.network.Port;
+import org.openstack4j.model.network.Router;
+import org.openstack4j.model.network.RouterInterface;
+import org.openstack4j.model.network.Subnet;
+import org.openstack4j.openstack.OSFactory;
+import org.openstack4j.openstack.networking.domain.NeutronRouterInterface;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import static org.openstack4j.core.transport.ObjectMapperSingleton.getContext;
+
+/**
+ * Synchronizes OpenStack network states.
+ */
+@Command(scope = "onos", name = "openstack-sync-states",
+ description = "Synchronizes all OpenStack network states")
+public class OpenstackSyncStateCommand extends AbstractShellCommand {
+
+ @Argument(index = 0, name = "endpoint", description = "OpenStack service endpoint",
+ required = true, multiValued = false)
+ private String endpoint = null;
+
+ @Argument(index = 1, name = "tenant", description = "OpenStack admin tenant name",
+ required = true, multiValued = false)
+ private String tenant = null;
+
+ @Argument(index = 2, name = "user", description = "OpenStack admin user name",
+ required = true, multiValued = false)
+ private String user = null;
+
+ @Argument(index = 3, name = "password", description = "OpenStack admin user password",
+ required = true, multiValued = false)
+ private String password = null;
+
+ private static final String NETWORK_FORMAT = "%-40s%-20s%-20s%-8s";
+ private static final String SUBNET_FORMAT = "%-40s%-20s%-20s";
+ private static final String PORT_FORMAT = "%-40s%-20s%-20s%-8s";
+ private static final String ROUTER_FORMAT = "%-40s%-20s%-20s%-8s";
+ private static final String FLOATING_IP_FORMAT = "%-40s%-20s%-20s";
+
+ private static final String DEVICE_OWNER_GW = "network:router_gateway";
+ private static final String DEVICE_OWNER_IFACE = "network:router_interface";
+
+ @Override
+ protected void execute() {
+ OpenstackNetworkAdminService osNetAdminService = get(OpenstackNetworkAdminService.class);
+ OpenstackNetworkService osNetService = get(OpenstackNetworkService.class);
+ OpenstackRouterAdminService osRouterAdminService = get(OpenstackRouterAdminService.class);
+ OpenstackRouterService osRouterService = get(OpenstackRouterService.class);
+
+ Access osAccess;
+ try {
+ osAccess = OSFactory.builder()
+ .endpoint(this.endpoint)
+ .tenantName(this.tenant)
+ .credentials(this.user, this.password)
+ .authenticate()
+ .getAccess();
+ } catch (AuthenticationException e) {
+ print("Authentication failed");
+ return;
+ } catch (Exception e) {
+ print("Failed to access OpenStack service");
+ return;
+ }
+
+ OSClient osClient = OSFactory.clientFromAccess(osAccess);
+
+ print("Synchronizing OpenStack networks...");
+ print(NETWORK_FORMAT, "ID", "Name", "VNI", "Subnets");
+ osClient.networking().network().list().forEach(osNet -> {
+ if (osNetService.network(osNet.getId()) != null) {
+ osNetAdminService.updateNetwork(osNet);
+ } else {
+ osNetAdminService.createNetwork(osNet);
+ }
+ printNetwork(osNet);
+ });
+
+ print("\nSynchronizing OpenStack subnets...");
+ print(SUBNET_FORMAT, "ID", "Network", "CIDR");
+ osClient.networking().subnet().list().forEach(osSubnet -> {
+ if (osNetService.subnet(osSubnet.getId()) != null) {
+ osNetAdminService.updateSubnet(osSubnet);
+ } else {
+ osNetAdminService.createSubnet(osSubnet);
+ }
+ printSubnet(osSubnet, osNetService);
+ });
+
+ print("\nSynchronizing OpenStack ports...");
+ print(PORT_FORMAT, "ID", "Network", "MAC", "Fixed IPs");
+ osClient.networking().port().list().forEach(osPort -> {
+ if (osNetService.port(osPort.getId()) != null) {
+ osNetAdminService.updatePort(osPort);
+ } else {
+ osNetAdminService.createPort(osPort);
+ }
+ printPort(osPort, osNetService);
+ });
+
+ print("\nSynchronizing OpenStack routers...");
+ print(ROUTER_FORMAT, "ID", "Name", "External", "Internal");
+ osClient.networking().router().list().forEach(osRouter -> {
+ if (osRouterService.router(osRouter.getId()) != null) {
+ osRouterAdminService.updateRouter(osRouter);
+ } else {
+ osRouterAdminService.createRouter(osRouter);
+ }
+
+ // FIXME do we need to manage router interfaces separately?
+ osNetService.ports().stream()
+ .filter(osPort -> Objects.equals(osPort.getDeviceId(), osRouter.getId()) &&
+ Objects.equals(osPort.getDeviceOwner(), DEVICE_OWNER_IFACE))
+ .forEach(osPort -> addRouterIface(osPort, osRouterService,
+ osRouterAdminService));
+
+ printRouter(osRouter, osNetService);
+ });
+
+ print("\nSynchronizing OpenStack floating IPs...");
+ print(FLOATING_IP_FORMAT, "ID", "Floating IP", "Fixed IP");
+ osClient.networking().floatingip().list().forEach(osFloating -> {
+ if (osRouterService.floatingIp(osFloating.getId()) != null) {
+ osRouterAdminService.updateFloatingIp(osFloating);
+ } else {
+ osRouterAdminService.createFloatingIp(osFloating);
+ }
+ printFloatingIp(osFloating);
+ });
+ }
+
+ // TODO fix the logic to add router interface to router
+ private void addRouterIface(Port osPort, OpenstackRouterService service,
+ OpenstackRouterAdminService adminService) {
+ osPort.getFixedIps().forEach(p -> {
+ JsonNode jsonTree = mapper().createObjectNode()
+ .put("id", osPort.getDeviceId())
+ .put("tenant_id", osPort.getTenantId())
+ .put("subnet_id", p.getSubnetId())
+ .put("port_id", osPort.getId());
+ try {
+ RouterInterface rIface = getContext(NeutronRouterInterface.class)
+ .readerFor(NeutronRouterInterface.class)
+ .readValue(jsonTree);
+ if (service.routerInterface(rIface.getPortId()) != null) {
+ adminService.updateRouterInterface(rIface);
+ } else {
+ adminService.addRouterInterface(rIface);
+ }
+ } catch (IOException ignore) {
+ }
+ });
+ }
+
+ private void printNetwork(Network osNet) {
+ final String strNet = String.format(NETWORK_FORMAT,
+ osNet.getId(),
+ osNet.getName(),
+ osNet.getProviderSegID(),
+ osNet.getSubnets());
+ print(strNet);
+ }
+
+ private void printSubnet(Subnet osSubnet, OpenstackNetworkService osNetService) {
+ final String strSubnet = String.format(SUBNET_FORMAT,
+ osSubnet.getId(),
+ osNetService.network(osSubnet.getNetworkId()).getName(),
+ osSubnet.getCidr());
+ print(strSubnet);
+ }
+
+ private void printPort(Port osPort, OpenstackNetworkService osNetService) {
+ List<String> fixedIps = osPort.getFixedIps().stream()
+ .map(IP::getIpAddress)
+ .collect(Collectors.toList());
+ final String strPort = String.format(PORT_FORMAT,
+ osPort.getId(),
+ osNetService.network(osPort.getNetworkId()).getName(),
+ osPort.getMacAddress(),
+ fixedIps.isEmpty() ? "" : fixedIps);
+ print(strPort);
+ }
+
+ private void printRouter(Router osRouter, OpenstackNetworkService osNetService) {
+ List<String> externals = osNetService.ports().stream()
+ .filter(osPort -> Objects.equals(osPort.getDeviceId(), osRouter.getId()) &&
+ Objects.equals(osPort.getDeviceOwner(), DEVICE_OWNER_GW))
+ .flatMap(osPort -> osPort.getFixedIps().stream())
+ .map(IP::getIpAddress)
+ .collect(Collectors.toList());
+
+ List<String> internals = osNetService.ports().stream()
+ .filter(osPort -> Objects.equals(osPort.getDeviceId(), osRouter.getId()) &&
+ Objects.equals(osPort.getDeviceOwner(), DEVICE_OWNER_IFACE))
+ .flatMap(osPort -> osPort.getFixedIps().stream())
+ .map(IP::getIpAddress)
+ .collect(Collectors.toList());
+
+ final String strRouter = String.format(ROUTER_FORMAT,
+ osRouter.getId(),
+ osRouter.getName(),
+ externals.isEmpty() ? "" : externals,
+ internals.isEmpty() ? "" : internals);
+ print(strRouter);
+ }
+
+ private void printFloatingIp(NetFloatingIP floatingIp) {
+ final String strFloating = String.format(FLOATING_IP_FORMAT,
+ floatingIp.getId(),
+ floatingIp.getFixedIpAddress(),
+ Strings.isNullOrEmpty(floatingIp.getFixedIpAddress()) ?
+ "" : floatingIp.getFixedIpAddress());
+ print(strFloating);
+ }
+}
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/DistributedOpenstackNetworkStore.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/DistributedOpenstackNetworkStore.java
index 3170a88..453dc01 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/DistributedOpenstackNetworkStore.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/DistributedOpenstackNetworkStore.java
@@ -266,6 +266,13 @@
return ImmutableSet.copyOf(osPorts);
}
+ @Override
+ public void clear() {
+ osPortStore.clear();
+ osSubnetStore.clear();
+ osNetworkStore.clear();
+ }
+
private class OpenstackNetworkMapListener implements MapEventListener<String, Network> {
@Override
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/DistributedOpenstackRouterStore.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/DistributedOpenstackRouterStore.java
index 3262969..aab6fa3 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/DistributedOpenstackRouterStore.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/DistributedOpenstackRouterStore.java
@@ -258,6 +258,13 @@
return ImmutableSet.copyOf(osFloatingIps);
}
+ @Override
+ public void clear() {
+ osFloatingIpStore.clear();
+ osRouterInterfaceStore.clear();
+ osRouterStore.clear();
+ }
+
private class OpenstackRouterMapListener implements MapEventListener<String, Router> {
@Override
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackNetworkManager.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackNetworkManager.java
index b486090..3add240 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackNetworkManager.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackNetworkManager.java
@@ -208,6 +208,11 @@
}
@Override
+ public void clear() {
+ osNetworkStore.clear();
+ }
+
+ @Override
public Network network(String netId) {
checkArgument(!Strings.isNullOrEmpty(netId), ERR_NULL_NETWORK_ID);
return osNetworkStore.network(netId);
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRouterManager.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRouterManager.java
index 0d74940..3087f8f 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRouterManager.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRouterManager.java
@@ -200,6 +200,11 @@
}
@Override
+ public void clear() {
+ osRouterStore.clear();
+ }
+
+ @Override
public Router router(String routerId) {
checkArgument(!Strings.isNullOrEmpty(routerId), ERR_NULL_ROUTER_ID);
return osRouterStore.router(routerId);
diff --git a/apps/openstacknetworking/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/apps/openstacknetworking/src/main/resources/OSGI-INF/blueprint/shell-config.xml
index e14985d..16a8408 100644
--- a/apps/openstacknetworking/src/main/resources/OSGI-INF/blueprint/shell-config.xml
+++ b/apps/openstacknetworking/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -27,5 +27,11 @@
<command>
<action class="org.onosproject.openstacknetworking.cli.OpenstackFloatingIpListCommand"/>
</command>
+ <command>
+ <action class="org.onosproject.openstacknetworking.cli.OpenstackPurgeStateCommand"/>
+ </command>
+ <command>
+ <action class="org.onosproject.openstacknetworking.cli.OpenstackSyncStateCommand"/>
+ </command>
</command-bundle>
</blueprint>