CORD-506 Apply existing service dependency when VM is detected
Change-Id: Ib0872c823347bfb6091d6c5f872657f10b7b1083
diff --git a/app.xml b/app.xml
index 5163375..7e8f409 100644
--- a/app.xml
+++ b/app.xml
@@ -18,7 +18,7 @@
category="Traffic Steering" url="http://onosproject.org" title="CORD Virtual Tenant Network"
featuresRepo="mvn:${project.groupId}/${project.artifactId}/${project.version}/xml/features"
features="${project.artifactId}"
- apps="org.onosproject.ovsdb-base,org.onosproject.dhcp">
+ apps="org.onosproject.ovsdb-base,org.onosproject.dhcp,org.onosproject.xosclient">
<description>${project.description}</description>
<artifact>mvn:${project.groupId}/onos-app-cordvtn/${project.version}</artifact>
</app>
diff --git a/pom.xml b/pom.xml
index 64e6e2f..705a9b4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -103,6 +103,11 @@
<version>${project.version}</version>
</dependency>
<dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-app-xos-client</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.53</version>
diff --git a/src/main/java/org/onosproject/cordvtn/api/CordService.java b/src/main/java/org/onosproject/cordvtn/api/CordService.java
index 8a10015..be2b810 100644
--- a/src/main/java/org/onosproject/cordvtn/api/CordService.java
+++ b/src/main/java/org/onosproject/cordvtn/api/CordService.java
@@ -43,6 +43,7 @@
private final IpAddress serviceIp;
private final Map<Host, IpAddress> hosts;
private final Set<CordServiceId> tenantServices;
+ private final Set<CordServiceId> providerServices;
/**
* Default constructor.
@@ -51,9 +52,11 @@
* @param osSubnet OpenStack subnet
* @param hosts host and tunnel ip map
* @param tenantServices list of tenant service ids
+ * @param providerServices list of provider service ids
*/
public CordService(Network osNet, Subnet osSubnet,
- Map<Host, IpAddress> hosts, Set<CordServiceId> tenantServices) {
+ Map<Host, IpAddress> hosts, Set<CordServiceId> tenantServices,
+ Set<CordServiceId> providerServices) {
this.id = CordServiceId.of(osNet.getId());
this.segmentationId = Long.parseLong(osNet.getProviderSegID());
this.serviceType = getServiceType(osNet.getName());
@@ -61,6 +64,7 @@
this.serviceIp = IpAddress.valueOf(osSubnet.getGateway());
this.hosts = hosts;
this.tenantServices = tenantServices;
+ this.providerServices = providerServices;
}
/**
@@ -126,6 +130,15 @@
return tenantServices;
}
+ /**
+ * Returns provider service IDs.
+ *
+ * @return list of provider service id
+ */
+ public Set<CordServiceId> providerServices() {
+ return providerServices;
+ }
+
@Override
public int hashCode() {
return Objects.hash(id);
@@ -152,6 +165,7 @@
.add("serviceIpRange", serviceIpRange)
.add("serviceIp", serviceIp)
.add("tenantServices", tenantServices)
+ .add("providerServices", providerServices)
.toString();
}
@@ -162,7 +176,7 @@
* @param netName network name
* @return network type, or PRIVATE if it doesn't match any type
*/
- private ServiceType getServiceType(String netName) {
+ public static ServiceType getServiceType(String netName) {
checkNotNull(netName);
String name = netName.toUpperCase();
diff --git a/src/main/java/org/onosproject/cordvtn/api/CordVtnConfig.java b/src/main/java/org/onosproject/cordvtn/api/CordVtnConfig.java
index 2c48ba3..9f3a279 100644
--- a/src/main/java/org/onosproject/cordvtn/api/CordVtnConfig.java
+++ b/src/main/java/org/onosproject/cordvtn/api/CordVtnConfig.java
@@ -25,6 +25,7 @@
import org.onosproject.core.ApplicationId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.config.Config;
+import org.onosproject.xosclient.api.XosAccess;
import org.slf4j.Logger;
import java.util.Map;
@@ -59,10 +60,12 @@
public static final String SSH_KEY_FILE = "sshKeyFile";
public static final String OPENSTACK = "openstack";
- public static final String OPENSTACK_ENDPOINT = "endpoint";
- public static final String OPENSTACK_TENANT = "tenant";
- public static final String OPENSTACK_USER = "user";
- public static final String OPENSTACK_PASSWORD = "password";
+ public static final String XOS = "xos";
+
+ public static final String ENDPOINT = "endpoint";
+ public static final String TENANT = "tenant";
+ public static final String USER = "user";
+ public static final String PASSWORD = "password";
/**
* Returns the set of nodes read from network config.
@@ -183,6 +186,28 @@
}
/**
+ * Returns XOS access information.
+ *
+ * @return XOS access, or null
+ */
+ public XosAccess xosAccess() {
+ JsonNode jsonNode = object.get(XOS);
+ if (jsonNode == null) {
+ log.error("Failed to get XOS configurations");
+ return null;
+ }
+
+ try {
+ return new XosAccess(getConfig(jsonNode, ENDPOINT),
+ getConfig(jsonNode, USER),
+ getConfig(jsonNode, PASSWORD));
+ } catch (NullPointerException e) {
+ log.error("Failed to get XOS access");
+ return null;
+ }
+ }
+
+ /**
* Returns OpenStack API access information.
*
* @return openstack config
@@ -196,10 +221,10 @@
try {
return new OpenStackConfig(
- jsonNode.path(OPENSTACK_ENDPOINT).asText(),
- jsonNode.path(OPENSTACK_TENANT).asText(),
- jsonNode.path(OPENSTACK_USER).asText(),
- jsonNode.path(OPENSTACK_PASSWORD).asText());
+ jsonNode.path(ENDPOINT).asText(),
+ jsonNode.path(TENANT).asText(),
+ jsonNode.path(USER).asText(),
+ jsonNode.path(PASSWORD).asText());
} catch (IllegalArgumentException | NullPointerException e) {
log.error("Failed to get OpenStack configurations");
return null;
diff --git a/src/main/java/org/onosproject/cordvtn/impl/CordVtn.java b/src/main/java/org/onosproject/cordvtn/impl/CordVtn.java
index 61f37b5..f7039c3 100644
--- a/src/main/java/org/onosproject/cordvtn/impl/CordVtn.java
+++ b/src/main/java/org/onosproject/cordvtn/impl/CordVtn.java
@@ -30,6 +30,7 @@
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.cordvtn.api.CordService;
+import org.onosproject.cordvtn.api.CordService.ServiceType;
import org.onosproject.cordvtn.api.CordServiceId;
import org.onosproject.cordvtn.api.CordVtnConfig;
import org.onosproject.cordvtn.api.CordVtnNode;
@@ -66,6 +67,8 @@
import org.onosproject.net.packet.PacketService;
import org.onosproject.net.provider.AbstractProvider;
import org.onosproject.net.provider.ProviderId;
+import org.onosproject.xosclient.api.XosAccess;
+import org.onosproject.xosclient.api.XosClientService;
import org.openstack4j.api.OSClient;
import org.openstack4j.api.exceptions.AuthenticationException;
import org.openstack4j.model.identity.Access;
@@ -85,6 +88,7 @@
import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.cordvtn.api.CordService.getServiceType;
import static org.slf4j.LoggerFactory.getLogger;
/**
@@ -130,6 +134,9 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DhcpService dhcpService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected XosClientService xosClient;
+
private final ConfigFactory configFactory =
new ConfigFactory(SubjectFactories.APP_SUBJECT_FACTORY, CordVtnConfig.class, "cordvtn") {
@Override
@@ -412,23 +419,7 @@
return null;
}
- // here it assumes all cord service networks has only one subnet
- Subnet osSubnet = osNet.getNeutronSubnets().stream()
- .findFirst()
- .orElse(null);
- if (osSubnet == null) {
- log.warn("Couldn't find OpenStack subnet for service {}", serviceId.id());
- return null;
- }
-
- Set<CordServiceId> tServices = Sets.newHashSet();
- // TODO get tenant services from XOS
-
- Map<Host, IpAddress> hosts = getHostsWithOpenstackNetwork(osNet)
- .stream()
- .collect(Collectors.toMap(host -> host, this::getTunnelIp));
-
- return new CordService(osNet, osSubnet, hosts, tServices);
+ return getCordService(osNet);
}
/**
@@ -450,14 +441,28 @@
return null;
}
- Set<CordServiceId> tServices = Sets.newHashSet();
- // TODO get tenant services from XOS
-
Map<Host, IpAddress> hosts = getHostsWithOpenstackNetwork(osNet)
.stream()
.collect(Collectors.toMap(host -> host, this::getTunnelIp));
- return new CordService(osNet, osSubnet, hosts, tServices);
+ ServiceType serviceType = getServiceType(osNet.getName());
+ // allows working without XOS for now
+ Set<CordServiceId> tServices = Sets.newHashSet();
+ Set<CordServiceId> pServices = Sets.newHashSet();
+
+ if (xosClient.access() != null && serviceType != ServiceType.MANAGEMENT) {
+ tServices = xosClient.vtnServiceApi().getTenantServices(serviceId.id())
+ .stream()
+ .map(CordServiceId::of)
+ .collect(Collectors.toSet());
+
+ pServices = xosClient.vtnServiceApi().getProviderServices(serviceId.id())
+ .stream()
+ .map(CordServiceId::of)
+ .collect(Collectors.toSet());
+ }
+
+ return new CordService(osNet, osSubnet, hosts, tServices, pServices);
}
/**
@@ -576,6 +581,7 @@
CordService service = getCordService(osNet);
if (service == null) {
+ log.warn("Failed to get CordService for {}", osNet.getName());
return;
}
@@ -587,7 +593,12 @@
arpProxy.addGateway(service.serviceIp(), privateGatewayMac);
case PUBLIC:
default:
- // TODO check if the service needs an update on its group buckets after done CORD-433
+ // TODO get bidirectional information from XOS once XOS supports
+ service.tenantServices().stream().forEach(
+ tServiceId -> createServiceDependency(tServiceId, service.id(), true));
+ service.providerServices().stream().forEach(
+ pServiceId -> createServiceDependency(service.id(), pServiceId, true));
+
ruleInstaller.updateServiceGroup(service);
// sends gratuitous ARP here for the case of adding existing VMs
// when ONOS or cordvtn app is restarted
@@ -648,8 +659,9 @@
}
case PUBLIC:
default:
- // TODO check if the service needs an update on its group buckets after done CORD-433
- ruleInstaller.updateServiceGroup(service);
+ if (!service.tenantServices().isEmpty()) {
+ ruleInstaller.updateServiceGroup(service);
+ }
break;
}
}
@@ -717,6 +729,8 @@
* @param newMac mac address to update
*/
private void setPrivateGatewayMac(MacAddress newMac) {
+ checkNotNull(osAccess, "OpenStack access is not set");
+
if (newMac == null || newMac.equals(privateGatewayMac)) {
// no updates, do nothing
return;
@@ -725,13 +739,11 @@
privateGatewayMac = newMac;
log.debug("Set service gateway MAC address to {}", privateGatewayMac.toString());
- // TODO get existing service list from XOS and replace the loop below
- Set<String> vNets = Sets.newHashSet();
- hostService.getHosts().forEach(host -> vNets.add(host.annotations().value(SERVICE_ID)));
- vNets.remove(null);
+ OSClient osClient = OSFactory.clientFromAccess(osAccess);
+ List<Network> vNets = Lists.newArrayList(osClient.networking().network().list().iterator());
vNets.stream().forEach(vNet -> {
- CordService service = getCordService(CordServiceId.of(vNet));
+ CordService service = getCordService(vNet);
if (service != null) {
arpProxy.addGateway(service.serviceIp(), privateGatewayMac);
arpProxy.sendGratuitousArpForGateway(service.serviceIp(), service.hosts().keySet());
@@ -763,6 +775,8 @@
* @param osConfig openstack config
*/
private void setOpenstackAccess(CordVtnConfig.OpenStackConfig osConfig) {
+ checkNotNull(osConfig, "OpenStack access is not configured");
+
log.debug("Get OpenStack access with Endpoint: {} Tenant: {} User: {} Passwd: {}",
osConfig.endpoint(),
osConfig.tenant(),
@@ -781,6 +795,22 @@
}
/**
+ * Sets XOS access information.
+ *
+ * @param xosAccess xos access
+ */
+ private void setXosAccess(XosAccess xosAccess) {
+ checkNotNull(xosAccess, "XOS access is not configured");
+
+ log.debug("Set XOS access with Endpoint: {} User: {} Passwd: {}",
+ xosAccess.endpoint(),
+ xosAccess.username(),
+ xosAccess.password());
+
+ xosClient.setAccess(xosAccess);
+ }
+
+ /**
* Updates configurations.
*/
private void readConfiguration() {
@@ -790,6 +820,7 @@
return;
}
+ setXosAccess(config.xosAccess());
setOpenstackAccess(config.openstackConfig());
setPrivateGatewayMac(config.privateGatewayMac());
setPublicGatewayMac(config.publicGateways());
diff --git a/src/main/java/org/onosproject/cordvtn/impl/CordVtnRuleInstaller.java b/src/main/java/org/onosproject/cordvtn/impl/CordVtnRuleInstaller.java
index 5914b71..823a5b1 100644
--- a/src/main/java/org/onosproject/cordvtn/impl/CordVtnRuleInstaller.java
+++ b/src/main/java/org/onosproject/cordvtn/impl/CordVtnRuleInstaller.java
@@ -282,12 +282,12 @@
GroupId groupId = createServiceGroup(deviceId, pService);
outGroups.put(deviceId, groupId);
- Set<PortNumber> vms = tService.hosts().keySet()
+ Set<PortNumber> tServiceVms = tService.hosts().keySet()
.stream()
.filter(host -> host.location().deviceId().equals(deviceId))
.map(host -> host.location().port())
.collect(Collectors.toSet());
- inPorts.put(deviceId, vms);
+ inPorts.put(deviceId, tServiceVms);
});
populateIndirectAccessRule(srcRange, serviceIp, outGroups);