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; ...@@ -18,6 +18,7 @@ package org.onosproject.net.region;
18 18
19 import org.onosproject.event.ListenerService; 19 import org.onosproject.event.ListenerService;
20 import org.onosproject.net.DeviceId; 20 import org.onosproject.net.DeviceId;
21 +import org.onosproject.net.HostId;
21 22
22 import java.util.Set; 23 import java.util.Set;
23 24
...@@ -59,4 +60,12 @@ public interface RegionService extends ListenerService<RegionEvent, RegionListen ...@@ -59,4 +60,12 @@ public interface RegionService extends ListenerService<RegionEvent, RegionListen
59 */ 60 */
60 Set<DeviceId> getRegionDevices(RegionId regionId); 61 Set<DeviceId> getRegionDevices(RegionId regionId);
61 62
63 + /**
64 + * Returns the set of hosts that belong to the specified region.
65 + *
66 + * @param regionId region identifier
67 + * @return set of identifiers for hosts in the given region
68 + */
69 + Set<HostId> getRegionHosts(RegionId regionId);
70 +
62 } 71 }
......
...@@ -17,6 +17,7 @@ package org.onosproject.net.region; ...@@ -17,6 +17,7 @@ package org.onosproject.net.region;
17 17
18 import org.onosproject.cluster.NodeId; 18 import org.onosproject.cluster.NodeId;
19 import org.onosproject.net.DeviceId; 19 import org.onosproject.net.DeviceId;
20 +import org.onosproject.net.HostId;
20 import org.onosproject.store.Store; 21 import org.onosproject.store.Store;
21 22
22 import java.util.Collection; 23 import java.util.Collection;
...@@ -110,4 +111,12 @@ public interface RegionStore extends Store<RegionEvent, RegionStoreDelegate> { ...@@ -110,4 +111,12 @@ public interface RegionStore extends Store<RegionEvent, RegionStoreDelegate> {
110 */ 111 */
111 void removeDevices(RegionId regionId, Collection<DeviceId> deviceIds); 112 void removeDevices(RegionId regionId, Collection<DeviceId> deviceIds);
112 113
114 + /**
115 + * Returns the set of hosts that belong to the specified region.
116 + *
117 + * @param regionId region identifier
118 + * @return set of identifiers for hosts in the given region
119 + */
120 + Set<HostId> getRegionHosts(RegionId regionId);
121 +
113 } 122 }
......
...@@ -20,6 +20,7 @@ import org.onosproject.net.DeviceId; ...@@ -20,6 +20,7 @@ import org.onosproject.net.DeviceId;
20 import org.onosproject.net.Host; 20 import org.onosproject.net.Host;
21 import org.onosproject.net.HostId; 21 import org.onosproject.net.HostId;
22 import org.onosproject.net.PortNumber; 22 import org.onosproject.net.PortNumber;
23 +import org.onosproject.net.region.RegionId;
23 24
24 import static com.google.common.base.MoreObjects.toStringHelper; 25 import static com.google.common.base.MoreObjects.toStringHelper;
25 26
...@@ -36,6 +37,7 @@ public class UiHost extends UiNode { ...@@ -36,6 +37,7 @@ public class UiHost extends UiNode {
36 private PortNumber locPort; 37 private PortNumber locPort;
37 38
38 private UiLinkId edgeLinkId; 39 private UiLinkId edgeLinkId;
40 + private RegionId regionId;
39 41
40 /** 42 /**
41 * Creates a new UI host. 43 * Creates a new UI host.
...@@ -70,6 +72,15 @@ public class UiHost extends UiNode { ...@@ -70,6 +72,15 @@ public class UiHost extends UiNode {
70 return host.id(); 72 return host.id();
71 } 73 }
72 74
75 + /**
76 + * Sets the ID of the region to which this device belongs.
77 + *
78 + * @param regionId region identifier
79 + */
80 + public void setRegionId(RegionId regionId) {
81 + this.regionId = regionId;
82 + }
83 +
73 @Override 84 @Override
74 public String idAsString() { 85 public String idAsString() {
75 return id().toString(); 86 return id().toString();
......
...@@ -241,6 +241,17 @@ public class UiRegion extends UiNode { ...@@ -241,6 +241,17 @@ public class UiRegion extends UiNode {
241 return topology.deviceSet(deviceIds); 241 return topology.deviceSet(deviceIds);
242 } 242 }
243 243
244 +
245 + /**
246 + * Make sure we have only these hosts in the region.
247 + *
248 + * @param hosts hosts in the region
249 + */
250 + public void reconcileHosts(Set<HostId> hosts) {
251 + hostIds.clear();
252 + hostIds.addAll(hosts);
253 + }
254 +
244 /** 255 /**
245 * Returns the set of host identifiers for this region. 256 * Returns the set of host identifiers for this region.
246 * 257 *
...@@ -260,6 +271,15 @@ public class UiRegion extends UiNode { ...@@ -260,6 +271,15 @@ public class UiRegion extends UiNode {
260 } 271 }
261 272
262 /** 273 /**
274 + * Returns the count of devices in this region.
275 + *
276 + * @return the device count
277 + */
278 + public int hostCount() {
279 + return hostIds.size();
280 + }
281 +
282 + /**
263 * Returns the order in which layers should be rendered. Lower layers 283 * Returns the order in which layers should be rendered. Lower layers
264 * come earlier in the list. For example, to indicate that nodes in the 284 * come earlier in the list. For example, to indicate that nodes in the
265 * optical layer should be rendered "below" nodes in the packet layer, 285 * optical layer should be rendered "below" nodes in the packet layer,
......
...@@ -25,6 +25,7 @@ import org.apache.felix.scr.annotations.Service; ...@@ -25,6 +25,7 @@ import org.apache.felix.scr.annotations.Service;
25 import org.onosproject.cluster.NodeId; 25 import org.onosproject.cluster.NodeId;
26 import org.onosproject.event.AbstractListenerManager; 26 import org.onosproject.event.AbstractListenerManager;
27 import org.onosproject.net.DeviceId; 27 import org.onosproject.net.DeviceId;
28 +import org.onosproject.net.HostId;
28 import org.onosproject.net.region.Region; 29 import org.onosproject.net.region.Region;
29 import org.onosproject.net.region.RegionAdminService; 30 import org.onosproject.net.region.RegionAdminService;
30 import org.onosproject.net.region.RegionEvent; 31 import org.onosproject.net.region.RegionEvent;
...@@ -149,4 +150,11 @@ public class RegionManager extends AbstractListenerManager<RegionEvent, RegionLi ...@@ -149,4 +150,11 @@ public class RegionManager extends AbstractListenerManager<RegionEvent, RegionLi
149 return store.getRegionDevices(regionId); 150 return store.getRegionDevices(regionId);
150 } 151 }
151 152
153 + @Override
154 + public Set<HostId> getRegionHosts(RegionId regionId) {
155 + checkPermission(REGION_READ);
156 + checkNotNull(regionId, REGION_ID_NULL);
157 + return store.getRegionHosts(regionId);
158 + }
159 +
152 } 160 }
......
...@@ -27,6 +27,7 @@ import org.apache.felix.scr.annotations.Service; ...@@ -27,6 +27,7 @@ import org.apache.felix.scr.annotations.Service;
27 import org.onlab.util.Identifier; 27 import org.onlab.util.Identifier;
28 import org.onosproject.cluster.NodeId; 28 import org.onosproject.cluster.NodeId;
29 import org.onosproject.net.DeviceId; 29 import org.onosproject.net.DeviceId;
30 +import org.onosproject.net.HostId;
30 import org.onosproject.net.region.DefaultRegion; 31 import org.onosproject.net.region.DefaultRegion;
31 import org.onosproject.net.region.Region; 32 import org.onosproject.net.region.Region;
32 import org.onosproject.net.region.RegionEvent; 33 import org.onosproject.net.region.RegionEvent;
...@@ -78,6 +79,7 @@ public class DistributedRegionStore ...@@ -78,6 +79,7 @@ public class DistributedRegionStore
78 79
79 private ConsistentMap<RegionId, Set<DeviceId>> membershipRepo; 80 private ConsistentMap<RegionId, Set<DeviceId>> membershipRepo;
80 private Map<RegionId, Set<DeviceId>> regionDevices; 81 private Map<RegionId, Set<DeviceId>> regionDevices;
82 + private Map<RegionId, Set<HostId>> regionHosts;
81 83
82 private Map<DeviceId, Region> regionsByDevice = new HashMap<>(); 84 private Map<DeviceId, Region> regionsByDevice = new HashMap<>();
83 85
...@@ -140,6 +142,12 @@ public class DistributedRegionStore ...@@ -140,6 +142,12 @@ public class DistributedRegionStore
140 } 142 }
141 143
142 @Override 144 @Override
145 + public Set<HostId> getRegionHosts(RegionId regionId) {
146 + Set<HostId> hostIds = regionHosts.get(regionId);
147 + return hostIds != null ? ImmutableSet.copyOf(hostIds) : ImmutableSet.of();
148 + }
149 +
150 + @Override
143 public Region createRegion(RegionId regionId, String name, Region.Type type, 151 public Region createRegion(RegionId regionId, String name, Region.Type type,
144 List<Set<NodeId>> masterNodeIds) { 152 List<Set<NodeId>> masterNodeIds) {
145 return regionsRepo.compute(regionId, (id, region) -> { 153 return regionsRepo.compute(regionId, (id, region) -> {
......
...@@ -387,7 +387,8 @@ class Topo2Jsonifier { ...@@ -387,7 +387,8 @@ class Topo2Jsonifier {
387 .put("id", region.idAsString()) 387 .put("id", region.idAsString())
388 .put("name", region.name()) 388 .put("name", region.name())
389 .put("nodeType", REGION) 389 .put("nodeType", REGION)
390 - .put("nDevs", region.deviceCount()); 390 + .put("nDevs", region.deviceCount())
391 + .put("nHosts", region.hostCount());
391 // TODO: complete closed-region details 392 // TODO: complete closed-region details
392 393
393 addMetaUi(node, region.idAsString()); 394 addMetaUi(node, region.idAsString());
......
...@@ -193,6 +193,7 @@ class ModelCache { ...@@ -193,6 +193,7 @@ class ModelCache {
193 private void updateRegion(UiRegion region) { 193 private void updateRegion(UiRegion region) {
194 RegionId rid = region.id(); 194 RegionId rid = region.id();
195 Set<DeviceId> deviceIds = services.region().getRegionDevices(rid); 195 Set<DeviceId> deviceIds = services.region().getRegionDevices(rid);
196 + Set<HostId> hostIds = services.region().getRegionHosts(rid);
196 197
197 // Make sure device objects refer to their region 198 // Make sure device objects refer to their region
198 deviceIds.forEach(d -> { 199 deviceIds.forEach(d -> {
...@@ -205,8 +206,19 @@ class ModelCache { ...@@ -205,8 +206,19 @@ class ModelCache {
205 } 206 }
206 }); 207 });
207 208
209 + hostIds.forEach(d -> {
210 + UiHost host = uiTopology.findHost(d);
211 + if (host != null) {
212 + host.setRegionId(rid);
213 + } else {
214 + // if we don't have the UiDevice in the topology, what can we do?
215 + log.warn("Region host {}, but we don't have UiHost in topology", d);
216 + }
217 + });
218 +
208 // Make sure the region object refers to the devices 219 // Make sure the region object refers to the devices
209 region.reconcileDevices(deviceIds); 220 region.reconcileDevices(deviceIds);
221 + region.reconcileHosts(hostIds);
210 222
211 fixupContainmentHierarchy(region); 223 fixupContainmentHierarchy(region);
212 } 224 }
...@@ -526,26 +538,17 @@ class ModelCache { ...@@ -526,26 +538,17 @@ class ModelCache {
526 fixupContainmentHierarchy(uiTopology.nullRegion()); 538 fixupContainmentHierarchy(uiTopology.nullRegion());
527 uiTopology.allRegions().forEach(this::fixupContainmentHierarchy); 539 uiTopology.allRegions().forEach(this::fixupContainmentHierarchy);
528 540
529 - // make sure devices are in the correct region 541 + // make sure devices and hosts are in the correct region
530 Set<UiDevice> allDevices = uiTopology.allDevices(); 542 Set<UiDevice> allDevices = uiTopology.allDevices();
543 + Set<UiHost> allHosts = uiTopology.allHosts();
531 544
532 services.region().getRegions().forEach(r -> { 545 services.region().getRegions().forEach(r -> {
533 RegionId rid = r.id(); 546 RegionId rid = r.id();
534 UiRegion region = uiTopology.findRegion(rid); 547 UiRegion region = uiTopology.findRegion(rid);
535 if (region != null) { 548 if (region != null) {
536 - Set<DeviceId> deviceIds = services.region().getRegionDevices(rid); 549 + reconcileDevicesWithRegion(allDevices, r, rid, region);
537 - region.reconcileDevices(deviceIds); 550 + reconcileHostsWithRegion(allHosts, r, rid, region);
538 - 551 +
539 - deviceIds.forEach(devId -> {
540 - UiDevice dev = uiTopology.findDevice(devId);
541 - if (dev != null) {
542 - dev.setRegionId(r.id());
543 - allDevices.remove(dev);
544 - } else {
545 - log.warn("Region device ID {} but no UiDevice in topology",
546 - devId);
547 - }
548 - });
549 } else { 552 } else {
550 log.warn("No UiRegion in topology for ID {}", rid); 553 log.warn("No UiRegion in topology for ID {}", rid);
551 } 554 }
...@@ -556,11 +559,49 @@ class ModelCache { ...@@ -556,11 +559,49 @@ class ModelCache {
556 allDevices.forEach(d -> leftOver.add(d.id())); 559 allDevices.forEach(d -> leftOver.add(d.id()));
557 uiTopology.nullRegion().reconcileDevices(leftOver); 560 uiTopology.nullRegion().reconcileDevices(leftOver);
558 561
562 + Set<HostId> leftOverHosts = new HashSet<>(allHosts.size());
563 + allHosts.forEach(h -> leftOverHosts.add(h.id()));
564 + uiTopology.nullRegion().reconcileHosts(leftOverHosts);
565 +
559 // now that we have correct region hierarchy, and devices are in their 566 // now that we have correct region hierarchy, and devices are in their
560 // respective regions, we can compute synthetic links for each region. 567 // respective regions, we can compute synthetic links for each region.
561 uiTopology.computeSynthLinks(); 568 uiTopology.computeSynthLinks();
562 } 569 }
563 570
571 + private void reconcileHostsWithRegion(Set<UiHost> allHosts, Region r,
572 + RegionId rid, UiRegion region) {
573 + Set<HostId> hostIds = services.region().getRegionHosts(rid);
574 + region.reconcileHosts(hostIds);
575 +
576 + hostIds.forEach(hId -> {
577 + UiHost h = uiTopology.findHost(hId);
578 + if (h != null) {
579 + h.setRegionId(r.id());
580 + allHosts.remove(h);
581 + } else {
582 + log.warn("Region host ID {} but no UiHost in topology",
583 + hId);
584 + }
585 + });
586 + }
587 +
588 + private void reconcileDevicesWithRegion(Set<UiDevice> allDevices, Region r,
589 + RegionId rid, UiRegion region) {
590 + Set<DeviceId> deviceIds = services.region().getRegionDevices(rid);
591 + region.reconcileDevices(deviceIds);
592 +
593 + deviceIds.forEach(devId -> {
594 + UiDevice dev = uiTopology.findDevice(devId);
595 + if (dev != null) {
596 + dev.setRegionId(r.id());
597 + allDevices.remove(dev);
598 + } else {
599 + log.warn("Region device ID {} but no UiDevice in topology",
600 + devId);
601 + }
602 + });
603 + }
604 +
564 605
565 // === CACHE STATISTICS 606 // === CACHE STATISTICS
566 607
......
...@@ -52,7 +52,6 @@ import org.onosproject.net.provider.ProviderId; ...@@ -52,7 +52,6 @@ import org.onosproject.net.provider.ProviderId;
52 import org.onosproject.net.region.DefaultRegion; 52 import org.onosproject.net.region.DefaultRegion;
53 import org.onosproject.net.region.Region; 53 import org.onosproject.net.region.Region;
54 import org.onosproject.net.region.RegionId; 54 import org.onosproject.net.region.RegionId;
55 -import org.onosproject.net.region.RegionListener;
56 import org.onosproject.net.region.RegionService; 55 import org.onosproject.net.region.RegionService;
57 import org.onosproject.ui.UiTopoLayoutService; 56 import org.onosproject.ui.UiTopoLayoutService;
58 import org.onosproject.ui.impl.AbstractUiImplTest; 57 import org.onosproject.ui.impl.AbstractUiImplTest;
...@@ -501,8 +500,7 @@ abstract class AbstractTopoModelTest extends AbstractUiImplTest { ...@@ -501,8 +500,7 @@ abstract class AbstractTopoModelTest extends AbstractUiImplTest {
501 } 500 }
502 } 501 }
503 502
504 - // TODO: consider implementing RegionServiceAdapter and extending that here 503 + private static class MockRegionService extends RegionServiceAdapter {
505 - private static class MockRegionService implements RegionService {
506 504
507 private final Map<RegionId, Region> lookup = new HashMap<>(); 505 private final Map<RegionId, Region> lookup = new HashMap<>();
508 506
...@@ -549,14 +547,6 @@ abstract class AbstractTopoModelTest extends AbstractUiImplTest { ...@@ -549,14 +547,6 @@ abstract class AbstractTopoModelTest extends AbstractUiImplTest {
549 } 547 }
550 return Collections.emptySet(); 548 return Collections.emptySet();
551 } 549 }
552 -
553 - @Override
554 - public void addListener(RegionListener listener) {
555 - }
556 -
557 - @Override
558 - public void removeListener(RegionListener listener) {
559 - }
560 } 550 }
561 551
562 552
......
1 +/*
2 + * Copyright 2016-present Open Networking Laboratory
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 + */
16 +
17 +package org.onosproject.ui.impl.topo.model;
18 +
19 +import org.onosproject.net.DeviceId;
20 +import org.onosproject.net.HostId;
21 +import org.onosproject.net.region.Region;
22 +import org.onosproject.net.region.RegionId;
23 +import org.onosproject.net.region.RegionListener;
24 +import org.onosproject.net.region.RegionService;
25 +
26 +import java.util.Collections;
27 +import java.util.Set;
28 +
29 +/**
30 + * Adapter for {@link RegionService}.
31 + */
32 +public class RegionServiceAdapter implements RegionService {
33 + @Override
34 + public void addListener(RegionListener listener) {
35 + }
36 +
37 + @Override
38 + public void removeListener(RegionListener listener) {
39 + }
40 +
41 + @Override
42 + public Set<Region> getRegions() {
43 + return Collections.emptySet();
44 + }
45 +
46 + @Override
47 + public Region getRegion(RegionId regionId) {
48 + return null;
49 + }
50 +
51 + @Override
52 + public Region getRegionForDevice(DeviceId deviceId) {
53 + return null;
54 + }
55 +
56 + @Override
57 + public Set<DeviceId> getRegionDevices(RegionId regionId) {
58 + return Collections.emptySet();
59 + }
60 +
61 + @Override
62 + public Set<HostId> getRegionHosts(RegionId regionId) {
63 + return Collections.emptySet();
64 + }
65 +}