X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fweb%2Ftopology%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Ftopology%2Fweb%2FTopology.java;h=b4695defdb4468d5e3a1324e723e6bab169513ae;hp=af25abded0ca51c8d6812345a4f6b7f3549da289;hb=52caf6e2c43f3ea4d579dddd17ee6953d12a4ac9;hpb=2429b6be7f76de1a8f4f9f7008bcff405adc4059 diff --git a/opendaylight/web/topology/src/main/java/org/opendaylight/controller/topology/web/Topology.java b/opendaylight/web/topology/src/main/java/org/opendaylight/controller/topology/web/Topology.java index af25abded0..b4695defdb 100644 --- a/opendaylight/web/topology/src/main/java/org/opendaylight/controller/topology/web/Topology.java +++ b/opendaylight/web/topology/src/main/java/org/opendaylight/controller/topology/web/Topology.java @@ -10,6 +10,9 @@ package org.opendaylight.controller.topology.web; import java.awt.Dimension; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.ObjectInputStream; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collection; @@ -21,21 +24,32 @@ import java.util.Set; import javax.servlet.http.HttpServletRequest; +import org.opendaylight.controller.configuration.IConfigurationAware; +import org.opendaylight.controller.containermanager.IContainerAuthorization; +import org.opendaylight.controller.sal.authorization.Resource; import org.opendaylight.controller.sal.authorization.UserLevel; import org.opendaylight.controller.sal.core.Bandwidth; import org.opendaylight.controller.sal.core.Edge; import org.opendaylight.controller.sal.core.Host; import org.opendaylight.controller.sal.core.Node; +import org.opendaylight.controller.sal.core.Node.NodeIDType; import org.opendaylight.controller.sal.core.NodeConnector; import org.opendaylight.controller.sal.core.Property; -import org.opendaylight.controller.sal.core.Node.NodeIDType; import org.opendaylight.controller.sal.packet.address.EthernetAddress; +import org.opendaylight.controller.sal.utils.GlobalConstants; +import org.opendaylight.controller.sal.utils.IObjectReader; +import org.opendaylight.controller.sal.utils.ObjectReader; +import org.opendaylight.controller.sal.utils.ObjectWriter; import org.opendaylight.controller.sal.utils.ServiceHelper; +import org.opendaylight.controller.sal.utils.Status; +import org.opendaylight.controller.sal.utils.StatusCode; import org.opendaylight.controller.switchmanager.ISwitchManager; import org.opendaylight.controller.switchmanager.Switch; import org.opendaylight.controller.switchmanager.SwitchConfig; import org.opendaylight.controller.topologymanager.ITopologyManager; import org.opendaylight.controller.usermanager.IUserManager; +import org.opendaylight.controller.web.DaylightWebUtil; +import org.opendaylight.controller.web.IDaylightWeb; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; @@ -49,15 +63,24 @@ import edu.uci.ics.jung.graph.SparseMultigraph; @Controller @RequestMapping("/") -public class Topology { +public class Topology implements IObjectReader, IConfigurationAware { + private static String ROOT = GlobalConstants.STARTUPHOME.toString(); + private String topologyWebFileName = null; - protected Map> cache = new HashMap>(); + protected Map>> metaCache = new HashMap>>(); protected Map> stagedNodes; protected Map> newNodes; - protected Integer nodeHash = null; - protected Integer hostHash = null; - protected Integer nodeSingleHash = null; - protected Integer nodeConfigurationHash = null; + + protected Map metaNodeHash = new HashMap(); + protected Map metaHostHash = new HashMap(); + protected Map metaNodeSingleHash = new HashMap(); + protected Map metaNodeConfigurationHash = new HashMap(); + + public Topology() { + ServiceHelper.registerGlobalService(IConfigurationAware.class, this, null); + topologyWebFileName = ROOT + "topologyCache.sav"; + loadConfiguration(); + } /** * Topology of nodes and hosts in the network in JSON format. @@ -68,13 +91,19 @@ public class Topology { */ @RequestMapping(value = "/visual.json", method = RequestMethod.GET) @ResponseBody - public Collection> getLinkData() { + public Collection> getLinkData(@RequestParam(required = false) String container, HttpServletRequest request) { + String containerName = DaylightWebUtil.getAuthorizedContainer(request, container, this); + ITopologyManager topologyManager = (ITopologyManager) ServiceHelper - .getInstance(ITopologyManager.class, "default", this); - if (topologyManager == null) return null; + .getInstance(ITopologyManager.class, containerName, this); + if (topologyManager == null) { + return null; + } ISwitchManager switchManager = (ISwitchManager) ServiceHelper - .getInstance(ISwitchManager.class, "default", this); - if (switchManager == null) return null; + .getInstance(ISwitchManager.class, containerName, this); + if (switchManager == null) { + return null; + } Map> nodeEdges = topologyManager.getNodeEdges(); Map> hostEdges = topologyManager @@ -88,35 +117,45 @@ public class Topology { switchConfigurations.add(config); } + // initialize cache if needed + if (!metaCache.containsKey(containerName)) { + metaCache.put(containerName, new HashMap>()); + // initialize hashes + metaNodeHash.put(containerName, null); + metaHostHash.put(containerName, null); + metaNodeSingleHash.put(containerName, null); + metaNodeConfigurationHash.put(containerName, null); + } + // return cache if topology hasn't changed if ( - (nodeHash != null && hostHash != null && nodeSingleHash != null && nodeConfigurationHash != null) && - nodeHash == nodeEdges.hashCode() && hostHash == hostEdges.hashCode() && nodeSingleHash == nodes.hashCode() && nodeConfigurationHash == switchConfigurations.hashCode() + (metaNodeHash.get(containerName) != null && metaHostHash.get(containerName) != null && metaNodeSingleHash.get(containerName) != null && metaNodeConfigurationHash.get(containerName) != null) && + metaNodeHash.get(containerName).equals(nodeEdges.hashCode()) && metaHostHash.get(containerName).equals(hostEdges.hashCode()) && metaNodeSingleHash.get(containerName).equals(nodes.hashCode()) && metaNodeConfigurationHash.get(containerName).equals(switchConfigurations.hashCode()) ) { - return cache.values(); + return metaCache.get(containerName).values(); } // cache has changed, we must assign the new values - nodeHash = nodeEdges.hashCode(); - hostHash = hostEdges.hashCode(); - nodeSingleHash = nodes.hashCode(); - nodeConfigurationHash = switchConfigurations.hashCode(); + metaNodeHash.put(containerName, nodeEdges.hashCode()); + metaHostHash.put(containerName, hostEdges.hashCode()); + metaNodeSingleHash.put(containerName, nodes.hashCode()); + metaNodeConfigurationHash.put(containerName, switchConfigurations.hashCode()); stagedNodes = new HashMap>(); newNodes = new HashMap>(); // nodeEdges addition - addNodes(nodeEdges, topologyManager, switchManager); + addNodes(nodeEdges, topologyManager, switchManager, containerName); // single nodes addition - addSingleNodes(nodes, switchManager); + addSingleNodes(nodes, switchManager, containerName); // hostNodes addition - addHostNodes(hostEdges, topologyManager); + addHostNodes(hostEdges, topologyManager, containerName); - repositionTopology(); + repositionTopology(containerName); - return cache.values(); + return metaCache.get(containerName).values(); } /** @@ -126,21 +165,20 @@ public class Topology { * @param topology - the topology instance */ private void addNodes(Map> nodeEdges, - ITopologyManager topology, ISwitchManager switchManager) { + ITopologyManager topology, ISwitchManager switchManager, String containerName) { Bandwidth bandwidth = new Bandwidth(0); Map> properties = topology.getEdges(); for (Map.Entry> e : nodeEdges.entrySet()) { Node n = e.getKey(); + String description = switchManager.getNodeDescription(n); + NodeBean node = createNodeBean(description, n); // skip production node if (nodeIgnore(n)) { continue; } - String description = switchManager.getNodeDescription(n); - NodeBean node = createNodeBean(description, n); - List> adjacencies = new LinkedList>(); Set links = e.getValue(); for (Edge link : links) { @@ -158,9 +196,9 @@ public class Topology { } node.setLinks(adjacencies); - if (cache.containsKey(node.id())) { + if (metaCache.get(containerName).containsKey(node.id())) { // retrieve node from cache - Map nodeEntry = cache.get(node.id()); + Map nodeEntry = metaCache.get(containerName).get(node.id()); Map data = (Map) nodeEntry.get("data"); data.put("$desc", description); @@ -224,29 +262,33 @@ public class Topology { } @SuppressWarnings("unchecked") - private void addSingleNodes(List nodes, ISwitchManager switchManager) { - if (nodes == null) return; + private void addSingleNodes(List nodes, ISwitchManager switchManager, String containerName) { + if (nodes == null) { + return; + } for (Switch sw : nodes) { Node n = sw.getNode(); // skip production node - if (nodeIgnore(n)) { - continue; - } + if (nodeIgnore(n)) { + continue; + } String description = switchManager.getNodeDescription(n); - if ((stagedNodes.containsKey(n.toString()) && cache.containsKey(n.toString())) || newNodes.containsKey(n.toString())) { + if ((stagedNodes.containsKey(n.toString()) && metaCache.get(containerName).containsKey(n.toString())) || newNodes.containsKey(n.toString())) { continue; } NodeBean node = createNodeBean(description, n); // FIXME still doesn't display standalone node when last remaining link is removed - if (cache.containsKey(node.id()) && !stagedNodes.containsKey(node.id())) { - Map nodeEntry = cache.get(node.id()); + if (metaCache.get(containerName).containsKey(node.id()) && !stagedNodes.containsKey(node.id())) { + Map nodeEntry = metaCache.get(containerName).get(node.id()); Map data = (Map) nodeEntry.get("data"); data.put("$desc", description); nodeEntry.put("data", data); + // clear adjacencies since this is now a single node + nodeEntry.put("adjacencies", new LinkedList>()); stagedNodes.put(node.id(), nodeEntry); } else { newNodes.put(node.id(), node.out()); @@ -261,7 +303,7 @@ public class Topology { * @param topology - topology instance */ private void addHostNodes(Map> hostEdges, - ITopologyManager topology) { + ITopologyManager topology, String containerName) { for (Map.Entry> e : hostEdges.entrySet()) { for (NodeConnector connector : e.getValue()) { Host host = topology.getHostAttachedToNodeConnector(connector); @@ -281,8 +323,8 @@ public class Topology { adjacencies.add(edge.out()); hostBean.setLinks(adjacencies); - if (cache.containsKey(hostId)) { - Map hostEntry = cache.get(hostId); + if (metaCache.get(containerName).containsKey(hostId)) { + Map hostEntry = metaCache.get(containerName).get(hostId); hostEntry.put("adjacencies", adjacencies); stagedNodes.put(hostId, hostEntry); } else { @@ -295,12 +337,14 @@ public class Topology { /** * Re-position nodes in circular layout */ - private void repositionTopology() { + private void repositionTopology(String containerName) { Graph graph = new SparseMultigraph(); - cache.clear(); - cache.putAll(stagedNodes); - cache.putAll(newNodes); - for (Map on : cache.values()) { + + metaCache.get(containerName).clear(); + metaCache.get(containerName).putAll(stagedNodes); + metaCache.get(containerName).putAll(newNodes); + + for (Map on : metaCache.get(containerName).values()) { graph.addVertex(on.toString()); List> adjacencies = (List>) on.get("adjacencies"); @@ -313,7 +357,7 @@ public class Topology { } } - CircleLayout layout = new CircleLayout(graph); + CircleLayout layout = new CircleLayout(graph); layout.setSize(new Dimension(1200, 365)); for (Map.Entry> v : newNodes.entrySet()) { Double x = layout.transform(v.getKey()).getX(); @@ -338,17 +382,21 @@ public class Topology { @RequestMapping(value = "/node/{nodeId}", method = RequestMethod.POST) @ResponseBody public Map post(@PathVariable String nodeId, @RequestParam(required = true) String x, - @RequestParam(required = true) String y, HttpServletRequest request) { + @RequestParam(required = true) String y, @RequestParam(required = false) String container, + HttpServletRequest request) { if (!authorize(UserLevel.NETWORKADMIN, request)) { return new HashMap(); // silently disregard new node position } + String containerName = getAuthorizedContainer(request, container); + String id = new String(nodeId); - if (!cache.containsKey(id)) + if (!metaCache.get(containerName).containsKey(id)) { return null; + } - Map node = cache.get(id); + Map node = metaCache.get(containerName).get(id); Map data = (Map) node.get("data"); data.put("$x", x); @@ -505,4 +553,50 @@ public class Topology { } return false; } -} + + private String getAuthorizedContainer(HttpServletRequest request, String container) { + String username = request.getUserPrincipal().getName(); + IContainerAuthorization containerAuthorization = (IContainerAuthorization) ServiceHelper. + getGlobalInstance(IContainerAuthorization.class, this); + if (containerAuthorization != null) { + Set resources = containerAuthorization.getAllResourcesforUser(username); + if (authorizeContainer(container, resources)) { + return container; + } + } + + return GlobalConstants.DEFAULT.toString(); + } + + private boolean authorizeContainer(String container, Set resources) { + for(Resource resource : resources) { + String containerName = (String) resource.getResource(); + if (containerName.equals(container)) { + return true; + } + } + + return false; + } + + @SuppressWarnings("unchecked") + private void loadConfiguration() { + ObjectReader objReader = new ObjectReader(); + metaCache = (Map>>) objReader.read(this, topologyWebFileName); + if (metaCache == null) metaCache = new HashMap>>(); + } + + @Override + public Status saveConfiguration() { + ObjectWriter objWriter = new ObjectWriter(); + objWriter.write(metaCache, topologyWebFileName); + return new Status(StatusCode.SUCCESS, null); + } + + @Override + public Object readObject(ObjectInputStream ois) + throws FileNotFoundException, IOException, ClassNotFoundException { + // Perform the class deserialization locally, from inside the package where the class is defined + return ois.readObject(); + } +} \ No newline at end of file