Steven Burrows
Committed by Gerrit Code Review

Implementing region hosts for topology 2

Change-Id: I6d1e45b1152b2387d4ff981dc0666868235eb1c3
......@@ -18,6 +18,7 @@ package org.onosproject.net.region;
import org.onosproject.event.ListenerService;
import org.onosproject.net.DeviceId;
import org.onosproject.net.HostId;
import java.util.Set;
......@@ -59,4 +60,12 @@ public interface RegionService extends ListenerService<RegionEvent, RegionListen
*/
Set<DeviceId> getRegionDevices(RegionId regionId);
/**
* Returns the set of hosts that belong to the specified region.
*
* @param regionId region identifier
* @return set of identifiers for hosts in the given region
*/
Set<HostId> getRegionHosts(RegionId regionId);
}
......
......@@ -17,6 +17,7 @@ package org.onosproject.net.region;
import org.onosproject.cluster.NodeId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.HostId;
import org.onosproject.store.Store;
import java.util.Collection;
......@@ -110,4 +111,12 @@ public interface RegionStore extends Store<RegionEvent, RegionStoreDelegate> {
*/
void removeDevices(RegionId regionId, Collection<DeviceId> deviceIds);
/**
* Returns the set of hosts that belong to the specified region.
*
* @param regionId region identifier
* @return set of identifiers for hosts in the given region
*/
Set<HostId> getRegionHosts(RegionId regionId);
}
......
......@@ -20,6 +20,7 @@ import org.onosproject.net.DeviceId;
import org.onosproject.net.Host;
import org.onosproject.net.HostId;
import org.onosproject.net.PortNumber;
import org.onosproject.net.region.RegionId;
import static com.google.common.base.MoreObjects.toStringHelper;
......@@ -36,6 +37,7 @@ public class UiHost extends UiNode {
private PortNumber locPort;
private UiLinkId edgeLinkId;
private RegionId regionId;
/**
* Creates a new UI host.
......@@ -70,6 +72,15 @@ public class UiHost extends UiNode {
return host.id();
}
/**
* Sets the ID of the region to which this device belongs.
*
* @param regionId region identifier
*/
public void setRegionId(RegionId regionId) {
this.regionId = regionId;
}
@Override
public String idAsString() {
return id().toString();
......
......@@ -241,6 +241,17 @@ public class UiRegion extends UiNode {
return topology.deviceSet(deviceIds);
}
/**
* Make sure we have only these hosts in the region.
*
* @param hosts hosts in the region
*/
public void reconcileHosts(Set<HostId> hosts) {
hostIds.clear();
hostIds.addAll(hosts);
}
/**
* Returns the set of host identifiers for this region.
*
......@@ -260,6 +271,15 @@ public class UiRegion extends UiNode {
}
/**
* Returns the count of devices in this region.
*
* @return the device count
*/
public int hostCount() {
return hostIds.size();
}
/**
* Returns the order in which layers should be rendered. Lower layers
* come earlier in the list. For example, to indicate that nodes in the
* optical layer should be rendered "below" nodes in the packet layer,
......
......@@ -25,6 +25,7 @@ import org.apache.felix.scr.annotations.Service;
import org.onosproject.cluster.NodeId;
import org.onosproject.event.AbstractListenerManager;
import org.onosproject.net.DeviceId;
import org.onosproject.net.HostId;
import org.onosproject.net.region.Region;
import org.onosproject.net.region.RegionAdminService;
import org.onosproject.net.region.RegionEvent;
......@@ -149,4 +150,11 @@ public class RegionManager extends AbstractListenerManager<RegionEvent, RegionLi
return store.getRegionDevices(regionId);
}
@Override
public Set<HostId> getRegionHosts(RegionId regionId) {
checkPermission(REGION_READ);
checkNotNull(regionId, REGION_ID_NULL);
return store.getRegionHosts(regionId);
}
}
......
......@@ -27,6 +27,7 @@ import org.apache.felix.scr.annotations.Service;
import org.onlab.util.Identifier;
import org.onosproject.cluster.NodeId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.HostId;
import org.onosproject.net.region.DefaultRegion;
import org.onosproject.net.region.Region;
import org.onosproject.net.region.RegionEvent;
......@@ -78,6 +79,7 @@ public class DistributedRegionStore
private ConsistentMap<RegionId, Set<DeviceId>> membershipRepo;
private Map<RegionId, Set<DeviceId>> regionDevices;
private Map<RegionId, Set<HostId>> regionHosts;
private Map<DeviceId, Region> regionsByDevice = new HashMap<>();
......@@ -140,6 +142,12 @@ public class DistributedRegionStore
}
@Override
public Set<HostId> getRegionHosts(RegionId regionId) {
Set<HostId> hostIds = regionHosts.get(regionId);
return hostIds != null ? ImmutableSet.copyOf(hostIds) : ImmutableSet.of();
}
@Override
public Region createRegion(RegionId regionId, String name, Region.Type type,
List<Set<NodeId>> masterNodeIds) {
return regionsRepo.compute(regionId, (id, region) -> {
......
......@@ -387,7 +387,8 @@ class Topo2Jsonifier {
.put("id", region.idAsString())
.put("name", region.name())
.put("nodeType", REGION)
.put("nDevs", region.deviceCount());
.put("nDevs", region.deviceCount())
.put("nHosts", region.hostCount());
// TODO: complete closed-region details
addMetaUi(node, region.idAsString());
......
......@@ -193,6 +193,7 @@ class ModelCache {
private void updateRegion(UiRegion region) {
RegionId rid = region.id();
Set<DeviceId> deviceIds = services.region().getRegionDevices(rid);
Set<HostId> hostIds = services.region().getRegionHosts(rid);
// Make sure device objects refer to their region
deviceIds.forEach(d -> {
......@@ -205,8 +206,19 @@ class ModelCache {
}
});
hostIds.forEach(d -> {
UiHost host = uiTopology.findHost(d);
if (host != null) {
host.setRegionId(rid);
} else {
// if we don't have the UiDevice in the topology, what can we do?
log.warn("Region host {}, but we don't have UiHost in topology", d);
}
});
// Make sure the region object refers to the devices
region.reconcileDevices(deviceIds);
region.reconcileHosts(hostIds);
fixupContainmentHierarchy(region);
}
......@@ -526,26 +538,17 @@ class ModelCache {
fixupContainmentHierarchy(uiTopology.nullRegion());
uiTopology.allRegions().forEach(this::fixupContainmentHierarchy);
// make sure devices are in the correct region
// make sure devices and hosts are in the correct region
Set<UiDevice> allDevices = uiTopology.allDevices();
Set<UiHost> allHosts = uiTopology.allHosts();
services.region().getRegions().forEach(r -> {
RegionId rid = r.id();
UiRegion region = uiTopology.findRegion(rid);
if (region != null) {
Set<DeviceId> deviceIds = services.region().getRegionDevices(rid);
region.reconcileDevices(deviceIds);
deviceIds.forEach(devId -> {
UiDevice dev = uiTopology.findDevice(devId);
if (dev != null) {
dev.setRegionId(r.id());
allDevices.remove(dev);
} else {
log.warn("Region device ID {} but no UiDevice in topology",
devId);
}
});
reconcileDevicesWithRegion(allDevices, r, rid, region);
reconcileHostsWithRegion(allHosts, r, rid, region);
} else {
log.warn("No UiRegion in topology for ID {}", rid);
}
......@@ -556,11 +559,49 @@ class ModelCache {
allDevices.forEach(d -> leftOver.add(d.id()));
uiTopology.nullRegion().reconcileDevices(leftOver);
Set<HostId> leftOverHosts = new HashSet<>(allHosts.size());
allHosts.forEach(h -> leftOverHosts.add(h.id()));
uiTopology.nullRegion().reconcileHosts(leftOverHosts);
// now that we have correct region hierarchy, and devices are in their
// respective regions, we can compute synthetic links for each region.
uiTopology.computeSynthLinks();
}
private void reconcileHostsWithRegion(Set<UiHost> allHosts, Region r,
RegionId rid, UiRegion region) {
Set<HostId> hostIds = services.region().getRegionHosts(rid);
region.reconcileHosts(hostIds);
hostIds.forEach(hId -> {
UiHost h = uiTopology.findHost(hId);
if (h != null) {
h.setRegionId(r.id());
allHosts.remove(h);
} else {
log.warn("Region host ID {} but no UiHost in topology",
hId);
}
});
}
private void reconcileDevicesWithRegion(Set<UiDevice> allDevices, Region r,
RegionId rid, UiRegion region) {
Set<DeviceId> deviceIds = services.region().getRegionDevices(rid);
region.reconcileDevices(deviceIds);
deviceIds.forEach(devId -> {
UiDevice dev = uiTopology.findDevice(devId);
if (dev != null) {
dev.setRegionId(r.id());
allDevices.remove(dev);
} else {
log.warn("Region device ID {} but no UiDevice in topology",
devId);
}
});
}
// === CACHE STATISTICS
......
......@@ -52,7 +52,6 @@ import org.onosproject.net.provider.ProviderId;
import org.onosproject.net.region.DefaultRegion;
import org.onosproject.net.region.Region;
import org.onosproject.net.region.RegionId;
import org.onosproject.net.region.RegionListener;
import org.onosproject.net.region.RegionService;
import org.onosproject.ui.UiTopoLayoutService;
import org.onosproject.ui.impl.AbstractUiImplTest;
......@@ -501,8 +500,7 @@ abstract class AbstractTopoModelTest extends AbstractUiImplTest {
}
}
// TODO: consider implementing RegionServiceAdapter and extending that here
private static class MockRegionService implements RegionService {
private static class MockRegionService extends RegionServiceAdapter {
private final Map<RegionId, Region> lookup = new HashMap<>();
......@@ -549,14 +547,6 @@ abstract class AbstractTopoModelTest extends AbstractUiImplTest {
}
return Collections.emptySet();
}
@Override
public void addListener(RegionListener listener) {
}
@Override
public void removeListener(RegionListener listener) {
}
}
......
/*
* Copyright 2016-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.ui.impl.topo.model;
import org.onosproject.net.DeviceId;
import org.onosproject.net.HostId;
import org.onosproject.net.region.Region;
import org.onosproject.net.region.RegionId;
import org.onosproject.net.region.RegionListener;
import org.onosproject.net.region.RegionService;
import java.util.Collections;
import java.util.Set;
/**
* Adapter for {@link RegionService}.
*/
public class RegionServiceAdapter implements RegionService {
@Override
public void addListener(RegionListener listener) {
}
@Override
public void removeListener(RegionListener listener) {
}
@Override
public Set<Region> getRegions() {
return Collections.emptySet();
}
@Override
public Region getRegion(RegionId regionId) {
return null;
}
@Override
public Region getRegionForDevice(DeviceId deviceId) {
return null;
}
@Override
public Set<DeviceId> getRegionDevices(RegionId regionId) {
return Collections.emptySet();
}
@Override
public Set<HostId> getRegionHosts(RegionId regionId) {
return Collections.emptySet();
}
}