blob: 7c8a41d2535099adff003321990b02ccc43af5a8 [file] [log] [blame]
/*
* Copyright 2016-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.ui.impl.topo.model;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.cluster.ClusterService;
import org.onosproject.cluster.ClusterServiceAdapter;
import org.onosproject.cluster.ControllerNode;
import org.onosproject.cluster.DefaultControllerNode;
import org.onosproject.cluster.NodeId;
import org.onosproject.cluster.RoleInfo;
import org.onosproject.mastership.MastershipService;
import org.onosproject.mastership.MastershipServiceAdapter;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DefaultAnnotations;
import org.onosproject.net.DefaultDevice;
import org.onosproject.net.DefaultHost;
import org.onosproject.net.DefaultLink;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Host;
import org.onosproject.net.HostId;
import org.onosproject.net.HostLocation;
import org.onosproject.net.Link;
import org.onosproject.net.PortNumber;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.device.DeviceServiceAdapter;
import org.onosproject.net.flow.FlowRuleService;
import org.onosproject.net.host.HostService;
import org.onosproject.net.host.HostServiceAdapter;
import org.onosproject.net.intent.IntentService;
import org.onosproject.net.link.LinkService;
import org.onosproject.net.link.LinkServiceAdapter;
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.RegionService;
import org.onosproject.ui.UiTopoLayoutService;
import org.onosproject.ui.impl.AbstractUiImplTest;
import org.onosproject.ui.model.ServiceBundle;
import org.onosproject.ui.model.topo.UiTopoLayout;
import org.onosproject.ui.model.topo.UiTopoLayoutId;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.onosproject.cluster.NodeId.nodeId;
import static org.onosproject.net.DeviceId.deviceId;
import static org.onosproject.net.HostId.hostId;
import static org.onosproject.net.PortNumber.portNumber;
import static org.onosproject.ui.model.topo.UiTopoLayoutId.layoutId;
/**
* Base class for model test classes.
*/
abstract class AbstractTopoModelTest extends AbstractUiImplTest {
/*
Our mock environment:
Three controllers: C1, C2, C3
Nine devices: D1 .. D9
D4 ---+ +--- D7
| |
D5 --- D1 --- D2 --- D3 --- D8
| |
D6 ---+ +--- D9
Twelve hosts (two per D4 ... D9) H4a, H4b, H5a, H5b, ...
Layouts:
LROOT : (default)
+-- L1 : R1
+-- L2 : R2
+-- L3 : R3
Regions:
R1 : D1, D2, D3
R2 : D4, D5, D6
R3 : D7, D8, D9
Mastership:
C1 : D1, D2, D3
C2 : D4, D5, D6
C3 : D7, D8, D9
Roles: (backups)
C1 -> C2, C3
C2 -> C1, C3
C3 -> C1, C2
*/
protected static final String C1 = "C1";
protected static final String C2 = "C2";
protected static final String C3 = "C3";
protected static final NodeId CNID_1 = nodeId(C1);
protected static final NodeId CNID_2 = nodeId(C2);
protected static final NodeId CNID_3 = nodeId(C3);
protected static final ControllerNode CNODE_1 = cnode(CNID_1, "10.0.0.1");
protected static final ControllerNode CNODE_2 = cnode(CNID_2, "10.0.0.2");
protected static final ControllerNode CNODE_3 = cnode(CNID_3, "10.0.0.3");
protected static final String R1 = "R1";
protected static final String R2 = "R2";
protected static final String R3 = "R3";
protected static final Set<NodeId> SET_C1 = ImmutableSet.of(CNID_1);
protected static final Set<NodeId> SET_C2 = ImmutableSet.of(CNID_2);
protected static final Set<NodeId> SET_C3 = ImmutableSet.of(CNID_3);
protected static final Region REGION_1 =
region(R1, Region.Type.METRO, ImmutableList.of(SET_C1, SET_C2));
protected static final Region REGION_2 =
region(R2, Region.Type.CAMPUS, ImmutableList.of(SET_C2, SET_C1));
protected static final Region REGION_3 =
region(R3, Region.Type.CAMPUS, ImmutableList.of(SET_C3, SET_C1));
protected static final Set<Region> REGION_SET =
ImmutableSet.of(REGION_1, REGION_2, REGION_3);
protected static final String LROOT = "LROOT";
protected static final String L1 = "L1";
protected static final String L2 = "L2";
protected static final String L3 = "L3";
protected static final UiTopoLayout LAYOUT_ROOT = layout(LROOT, null, null);
protected static final UiTopoLayout LAYOUT_1 = layout(L1, REGION_1, LROOT);
protected static final UiTopoLayout LAYOUT_2 = layout(L2, REGION_2, LROOT);
protected static final UiTopoLayout LAYOUT_3 = layout(L3, REGION_3, LROOT);
protected static final Set<UiTopoLayout> LAYOUT_SET =
ImmutableSet.of(LAYOUT_ROOT, LAYOUT_1, LAYOUT_2, LAYOUT_3);
protected static final Set<UiTopoLayout> ROOT_KIDS =
ImmutableSet.of(LAYOUT_1, LAYOUT_2, LAYOUT_3);
protected static final Set<UiTopoLayout> PEERS_OF_1 =
ImmutableSet.of(LAYOUT_2, LAYOUT_3);
protected static final Set<UiTopoLayout> PEERS_OF_2 =
ImmutableSet.of(LAYOUT_1, LAYOUT_3);
protected static final Set<UiTopoLayout> PEERS_OF_3 =
ImmutableSet.of(LAYOUT_1, LAYOUT_2);
protected static final String D1 = "d1";
protected static final String D2 = "d2";
protected static final String D3 = "d3";
protected static final String D4 = "d4";
protected static final String D5 = "d5";
protected static final String D6 = "d6";
protected static final String D7 = "d7";
protected static final String D8 = "d8";
protected static final String D9 = "d9";
protected static final String MFR = "Mfr";
protected static final String HW = "h/w";
protected static final String SW = "s/w";
protected static final String SERIAL = "ser123";
protected static final DeviceId DEVID_1 = deviceId(D1);
protected static final DeviceId DEVID_2 = deviceId(D2);
protected static final DeviceId DEVID_3 = deviceId(D3);
protected static final DeviceId DEVID_4 = deviceId(D4);
protected static final DeviceId DEVID_5 = deviceId(D5);
protected static final DeviceId DEVID_6 = deviceId(D6);
protected static final DeviceId DEVID_7 = deviceId(D7);
protected static final DeviceId DEVID_8 = deviceId(D8);
protected static final DeviceId DEVID_9 = deviceId(D9);
protected static final Device DEV_1 = device(D1);
protected static final Device DEV_2 = device(D2);
protected static final Device DEV_3 = device(D3);
protected static final Device DEV_4 = device(D4);
protected static final Device DEV_5 = device(D5);
protected static final Device DEV_6 = device(D6);
protected static final Device DEV_7 = device(D7);
protected static final Device DEV_8 = device(D8);
protected static final Device DEV_9 = device(D9);
protected static final List<Device> ALL_DEVS =
ImmutableList.of(
DEV_1, DEV_2, DEV_3,
DEV_4, DEV_5, DEV_6,
DEV_7, DEV_8, DEV_9
);
private static final Set<DeviceId> DEVS_TRUNK =
ImmutableSet.of(DEVID_1, DEVID_2, DEVID_3);
private static final Set<DeviceId> DEVS_LEFT =
ImmutableSet.of(DEVID_4, DEVID_5, DEVID_6);
private static final Set<DeviceId> DEVS_RIGHT =
ImmutableSet.of(DEVID_7, DEVID_8, DEVID_9);
private static final String[][] LINK_CONNECT_DATA = {
{D1, "12", D2, "21"},
{D2, "23", D3, "32"},
{D4, "41", D1, "14"},
{D5, "51", D1, "15"},
{D6, "61", D1, "16"},
{D7, "73", D3, "37"},
{D8, "83", D3, "38"},
{D9, "93", D3, "39"},
};
private static final String HOST_MAC_PREFIX = "aa:00:00:00:00:";
/**
* Returns IP address instance for given string.
*
* @param s string
* @return IP address
*/
protected static IpAddress ip(String s) {
return IpAddress.valueOf(s);
}
/**
* Returns controller node instance for given ID and IP.
*
* @param id identifier
* @param ip IP address
* @return controller node instance
*/
protected static ControllerNode cnode(NodeId id, String ip) {
return new DefaultControllerNode(id, ip(ip));
}
/**
* Returns UI topology layout instance with the specified parameters.
*
* @param layoutId the layout ID
* @param region the backing region
* @param parentId the parent layout ID
* @return layout instance
*/
protected static UiTopoLayout layout(String layoutId, Region region,
String parentId) {
UiTopoLayoutId pid = parentId == null
? UiTopoLayoutId.DEFAULT_ID : layoutId(parentId);
return new UiTopoLayout(layoutId(layoutId)).region(region).parent(pid);
}
/**
* Returns a region instance with specified parameters.
*
* @param id region id
* @param type region type
* @param masters ordered list of master sets
* @return region instance
*/
protected static Region region(String id, Region.Type type,
List<Set<NodeId>> masters) {
return new DefaultRegion(RegionId.regionId(id), "Region-" + id,
type, DefaultAnnotations.EMPTY, masters);
}
/**
* Returns device with given ID.
*
* @param id device ID
* @return device instance
*/
protected static Device device(String id) {
return new DefaultDevice(ProviderId.NONE, deviceId(id),
Device.Type.SWITCH, MFR, HW, SW, SERIAL, null);
}
/**
* Returns canned results.
* <p>
* At some future point, we may make this "programmable", so that
* its state can be changed over the course of a unit test.
*/
protected static final ServiceBundle MOCK_SERVICES =
new ServiceBundle() {
@Override
public UiTopoLayoutService layout() {
return MOCK_LAYOUT;
}
@Override
public ClusterService cluster() {
return MOCK_CLUSTER;
}
@Override
public MastershipService mastership() {
return MOCK_MASTER;
}
@Override
public RegionService region() {
return MOCK_REGION;
}
@Override
public DeviceService device() {
return MOCK_DEVICE;
}
@Override
public LinkService link() {
return MOCK_LINK;
}
@Override
public HostService host() {
return MOCK_HOST;
}
@Override
public IntentService intent() {
return null;
}
@Override
public FlowRuleService flow() {
return null;
}
};
private static final ClusterService MOCK_CLUSTER = new MockClusterService();
private static final MastershipService MOCK_MASTER = new MockMasterService();
private static final UiTopoLayoutService MOCK_LAYOUT = new MockLayoutService();
private static final RegionService MOCK_REGION = new MockRegionService();
private static final DeviceService MOCK_DEVICE = new MockDeviceService();
private static final LinkService MOCK_LINK = new MockLinkService();
private static final HostService MOCK_HOST = new MockHostService();
private static class MockClusterService extends ClusterServiceAdapter {
private final Map<NodeId, ControllerNode> nodes = new HashMap<>();
private final Map<NodeId, ControllerNode.State> states = new HashMap<>();
MockClusterService() {
nodes.put(CNODE_1.id(), CNODE_1);
nodes.put(CNODE_2.id(), CNODE_2);
nodes.put(CNODE_3.id(), CNODE_3);
states.put(CNODE_1.id(), ControllerNode.State.READY);
states.put(CNODE_2.id(), ControllerNode.State.ACTIVE);
states.put(CNODE_3.id(), ControllerNode.State.ACTIVE);
}
@Override
public Set<ControllerNode> getNodes() {
return ImmutableSet.copyOf(nodes.values());
}
@Override
public ControllerNode getNode(NodeId nodeId) {
return nodes.get(nodeId);
}
@Override
public ControllerNode.State getState(NodeId nodeId) {
return states.get(nodeId);
}
}
private static class MockMasterService extends MastershipServiceAdapter {
private final Map<NodeId, Set<DeviceId>> masterOf = new HashMap<>();
MockMasterService() {
masterOf.put(CNODE_1.id(), DEVS_TRUNK);
masterOf.put(CNODE_2.id(), DEVS_LEFT);
masterOf.put(CNODE_3.id(), DEVS_RIGHT);
}
@Override
public NodeId getMasterFor(DeviceId deviceId) {
if (DEVS_TRUNK.contains(deviceId)) {
return CNID_1;
}
if (DEVS_LEFT.contains(deviceId)) {
return CNID_2;
}
if (DEVS_RIGHT.contains(deviceId)) {
return CNID_3;
}
return null;
}
@Override
public Set<DeviceId> getDevicesOf(NodeId nodeId) {
return masterOf.get(nodeId);
}
@Override
public RoleInfo getNodesFor(DeviceId deviceId) {
NodeId master = null;
List<NodeId> backups = new ArrayList<>();
if (DEVS_TRUNK.contains(deviceId)) {
master = CNID_1;
backups.add(CNID_2);
backups.add(CNID_3);
} else if (DEVS_LEFT.contains(deviceId)) {
master = CNID_2;
backups.add(CNID_1);
backups.add(CNID_3);
} else if (DEVS_RIGHT.contains(deviceId)) {
master = CNID_3;
backups.add(CNID_1);
backups.add(CNID_2);
}
return new RoleInfo(master, backups);
}
}
// TODO: consider implementing UiTopoLayoutServiceAdapter and extending that here
private static class MockLayoutService implements UiTopoLayoutService {
private final Map<UiTopoLayoutId, UiTopoLayout> map = new HashMap<>();
private final Map<UiTopoLayoutId, Set<UiTopoLayout>> peers = new HashMap<>();
private final Map<RegionId, UiTopoLayout> byRegion = new HashMap<>();
MockLayoutService() {
map.put(LAYOUT_ROOT.id(), LAYOUT_ROOT);
map.put(LAYOUT_1.id(), LAYOUT_1);
map.put(LAYOUT_2.id(), LAYOUT_2);
map.put(LAYOUT_3.id(), LAYOUT_3);
peers.put(LAYOUT_ROOT.id(), ImmutableSet.of());
peers.put(LAYOUT_1.id(), ImmutableSet.of(LAYOUT_2, LAYOUT_3));
peers.put(LAYOUT_2.id(), ImmutableSet.of(LAYOUT_1, LAYOUT_3));
peers.put(LAYOUT_3.id(), ImmutableSet.of(LAYOUT_1, LAYOUT_2));
byRegion.put(REGION_1.id(), LAYOUT_1);
byRegion.put(REGION_2.id(), LAYOUT_2);
byRegion.put(REGION_3.id(), LAYOUT_3);
}
@Override
public UiTopoLayout getRootLayout() {
return LAYOUT_ROOT;
}
@Override
public Set<UiTopoLayout> getLayouts() {
return LAYOUT_SET;
}
@Override
public boolean addLayout(UiTopoLayout layout) {
return false;
}
@Override
public UiTopoLayout getLayout(UiTopoLayoutId layoutId) {
return map.get(layoutId);
}
@Override
public UiTopoLayout getLayout(RegionId regionId) {
return byRegion.get(regionId);
}
@Override
public Set<UiTopoLayout> getPeerLayouts(UiTopoLayoutId layoutId) {
return peers.get(layoutId);
}
@Override
public Set<UiTopoLayout> getChildren(UiTopoLayoutId layoutId) {
return LAYOUT_ROOT.id().equals(layoutId)
? ROOT_KIDS
: Collections.emptySet();
}
@Override
public boolean removeLayout(UiTopoLayout layout) {
return false;
}
}
private static class MockRegionService extends RegionServiceAdapter {
private final Map<RegionId, Region> lookup = new HashMap<>();
MockRegionService() {
lookup.put(REGION_1.id(), REGION_1);
lookup.put(REGION_2.id(), REGION_2);
lookup.put(REGION_3.id(), REGION_3);
}
@Override
public Set<Region> getRegions() {
return REGION_SET;
}
@Override
public Region getRegion(RegionId regionId) {
return lookup.get(regionId);
}
@Override
public Region getRegionForDevice(DeviceId deviceId) {
if (DEVS_TRUNK.contains(deviceId)) {
return REGION_1;
}
if (DEVS_LEFT.contains(deviceId)) {
return REGION_2;
}
if (DEVS_RIGHT.contains(deviceId)) {
return REGION_3;
}
return null;
}
@Override
public Set<DeviceId> getRegionDevices(RegionId regionId) {
if (REGION_1.id().equals(regionId)) {
return DEVS_TRUNK;
}
if (REGION_2.id().equals(regionId)) {
return DEVS_LEFT;
}
if (REGION_3.id().equals(regionId)) {
return DEVS_RIGHT;
}
return Collections.emptySet();
}
}
private static class MockDeviceService extends DeviceServiceAdapter {
private final Map<DeviceId, Device> devices = new HashMap<>();
MockDeviceService() {
for (Device dev : ALL_DEVS) {
devices.put(dev.id(), dev);
}
}
@Override
public int getDeviceCount() {
return devices.size();
}
@Override
public Iterable<Device> getDevices() {
return ImmutableList.copyOf(devices.values());
}
@Override
public Device getDevice(DeviceId deviceId) {
return devices.get(deviceId);
}
}
/**
* Synthesizes a pair of unidirectional links between two devices. The
* string array should be of the form:
* <pre>
* { "device-A-id", "device-A-port", "device-B-id", "device-B-port" }
* </pre>
*
* @param linkPairData device ids and ports
* @return pair of synthesized links
*/
protected static List<Link> makeLinkPair(String[] linkPairData) {
DeviceId devA = deviceId(linkPairData[0]);
PortNumber portA = portNumber(Long.valueOf(linkPairData[1]));
DeviceId devB = deviceId(linkPairData[2]);
PortNumber portB = portNumber(Long.valueOf(linkPairData[3]));
Link linkA = DefaultLink.builder()
.providerId(ProviderId.NONE)
.type(Link.Type.DIRECT)
.src(new ConnectPoint(devA, portA))
.dst(new ConnectPoint(devB, portB))
.build();
Link linkB = DefaultLink.builder()
.providerId(ProviderId.NONE)
.type(Link.Type.DIRECT)
.src(new ConnectPoint(devB, portB))
.dst(new ConnectPoint(devA, portA))
.build();
return ImmutableList.of(linkA, linkB);
}
private static class MockLinkService extends LinkServiceAdapter {
private final Set<Link> links = new HashSet<>();
MockLinkService() {
for (String[] linkPair : LINK_CONNECT_DATA) {
links.addAll(makeLinkPair(linkPair));
}
}
@Override
public int getLinkCount() {
return links.size();
}
@Override
public Iterable<Link> getLinks() {
return ImmutableSet.copyOf(links);
}
// TODO: possibly fill out other methods if we find the model uses them
}
/**
* Creates a default host connected at the given edge device and port. Note
* that an identifying hex character ("a" - "f") should be supplied. This
* will be included in the MAC address of the host (and equivalent value
* as last byte in IP address).
*
* @param device edge device
* @param port port number
* @param hexChar identifying hex character
* @return host connected at that location
*/
protected static Host createHost(Device device, int port, String hexChar) {
DeviceId deviceId = device.id();
String devNum = deviceId.toString().substring(1);
MacAddress mac = MacAddress.valueOf(HOST_MAC_PREFIX + devNum + hexChar);
HostId hostId = hostId(String.format("%s/-1", mac));
int ipByte = Integer.valueOf(hexChar, 16);
if (ipByte < 10 || ipByte > 15) {
throw new IllegalArgumentException("hexChar must be a-f");
}
HostLocation loc = new HostLocation(deviceId, portNumber(port), 0);
IpAddress ip = ip("10." + devNum + ".0." + ipByte);
return new DefaultHost(ProviderId.NONE, hostId, mac, VlanId.NONE,
loc, ImmutableSet.of(ip));
}
/**
* Creates a pair of hosts connected to the specified device.
*
* @param d edge device
* @return pair of hosts
*/
protected static List<Host> createHostPair(Device d) {
List<Host> hosts = new ArrayList<>();
hosts.add(createHost(d, 101, "a"));
hosts.add(createHost(d, 102, "b"));
return hosts;
}
private static class MockHostService extends HostServiceAdapter {
private final Map<HostId, Host> hosts = new HashMap<>();
MockHostService() {
for (Device d : ALL_DEVS) {
for (Host h : createHostPair(d)) {
hosts.put(h.id(), h);
}
}
}
@Override
public int getHostCount() {
return hosts.size();
}
@Override
public Iterable<Host> getHosts() {
return ImmutableSet.copyOf(hosts.values());
}
@Override
public Host getHost(HostId hostId) {
return hosts.get(hostId);
}
// TODO: possibly fill out other methods, should the model require them
}
}