Adding topology overlay support for the server-side topo layout app.
Also:
- parametrized access network layout in preparation for multiple variants
- removed WS authentication code temporarily until proper forced-logout is implemented
- updated STC warden environment (test only)
Change-Id: I0adbe60737828db79350e7eb2fc72cf313b78a28
diff --git a/apps/layout/BUCK b/apps/layout/BUCK
index 87e21e3..5d249c4 100644
--- a/apps/layout/BUCK
+++ b/apps/layout/BUCK
@@ -1,5 +1,6 @@
COMPILE_DEPS = [
'//lib:CORE_DEPS',
+ '//lib:JACKSON',
'//lib:org.apache.karaf.shell.console',
'//core/common:onos-core-common',
'//cli:onos-cli',
diff --git a/apps/layout/src/main/java/org/onosproject/layout/AccessNetworkLayout.java b/apps/layout/src/main/java/org/onosproject/layout/AccessNetworkLayout.java
index 02917f1..9f4f39d 100644
--- a/apps/layout/src/main/java/org/onosproject/layout/AccessNetworkLayout.java
+++ b/apps/layout/src/main/java/org/onosproject/layout/AccessNetworkLayout.java
@@ -27,6 +27,7 @@
import org.onosproject.utils.Comparators;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@@ -35,31 +36,62 @@
*/
public class AccessNetworkLayout extends LayoutAlgorithm {
- private static final double COMPUTE_Y = -400.0;
- private static final double SERVICE_Y = -200.0;
- private static final double SPINE_Y = 0.0;
- private static final double AGGREGATION_Y = +200.0;
- private static final double ACCESS_Y = +400.0;
- private static final double HOSTS_Y = +700.0;
- private static final double GATEWAY_X = 900.0;
+ private double computeY = -350.0;
+ private double serviceY = -200.0;
+ private double spineY = 0.0;
+ private double aggregationY = +200.0;
+ private double accessY = +400.0;
+ private double hostsY = +550.0;
- private static final double ROW_GAP = 70;
- private static final double COMPUTE_ROW_GAP = -120;
- private static final double COL_GAP = 54;
- private static final double COMPUTE_OFFSET = 800.0;
- private static final double GATEWAY_GAP = 200.0;
- private static final double GATEWAY_OFFSET = -200.0;
-
- private static final double SERVICE_GAP = 800;
- private static final int COMPUTE_PER_ROW = 25;
-
- private static final double SPINES_GAP = 800;
- private static final double AGGREGATION_GAP = 400;
- private static final double ACCESS_GAP = 400;
- private static final int HOSTS_PER_ROW = 6;
+ private double gatewayX = 900.0;
+ private double rowGap = 70;
+ private double computeRowGap = -120;
+ private double colGap = 54;
+ private double computeOffset = 800.0;
+ private double gatewayGap = 200.0;
+ private double gatewayOffset = -200.0;
+ private double serviceGap = 800;
+ private int computePerRow = 25;
+ private double spinesGap = 800;
+ private double aggregationGap = 400;
+ private double accessGap = 400;
+ private int hostsPerRow = 6;
private int spine, aggregation, accessLeaf, serviceLeaf, gateway;
+ /**
+ * Creates the network layout using default layout options.
+ */
+ public AccessNetworkLayout() {
+ }
+
+ /**
+ * Creates the network layout using the specified layout property overrides.
+ *
+ * @param custom overrides of the default layout properties
+ */
+ public AccessNetworkLayout(Map<String, Object> custom) {
+ computeY = (double) custom.getOrDefault("computeY", computeY);
+ serviceY = (double) custom.getOrDefault("serviceY", serviceY);
+ spineY = (double) custom.getOrDefault("spineY", spineY);
+ aggregationY = (double) custom.getOrDefault("aggregationY", aggregationY);
+ accessY = (double) custom.getOrDefault("accessY", accessY);
+ hostsY = (double) custom.getOrDefault("hostsY", hostsY);
+ gatewayX = (double) custom.getOrDefault("gatewayX", gatewayX);
+ rowGap = (double) custom.getOrDefault("rowGap", rowGap);
+ computeRowGap = (double) custom.getOrDefault("computeRowGap", computeRowGap);
+ colGap = (double) custom.getOrDefault("colGap", colGap);
+ computeOffset = (double) custom.getOrDefault("computeOffset", computeOffset);
+ gatewayGap = (double) custom.getOrDefault("gatewayGap", gatewayGap);
+ gatewayOffset = (double) custom.getOrDefault("gatewayOffset", gatewayOffset);
+ serviceGap = (double) custom.getOrDefault("serviceGap", serviceGap);
+ computePerRow = (int) custom.getOrDefault("computePerRow", computePerRow);
+ spinesGap = (double) custom.getOrDefault("spinesGap", spinesGap);
+ aggregationGap = (double) custom.getOrDefault("aggregationGap", aggregationGap);
+ accessGap = (double) custom.getOrDefault("accessGap", accessGap);
+ hostsPerRow = (int) custom.getOrDefault("hostsPerRow", hostsPerRow);
+ }
+
@Override
protected boolean classify(Device device) {
if (!super.classify(device)) {
@@ -112,7 +144,7 @@
spine = 1;
List<DeviceId> spines = deviceCategories.get(SPINE);
spines.stream().sorted(Comparators.ELEMENT_ID_COMPARATOR)
- .forEach(d -> place(d, c(spine++, spines.size(), SPINES_GAP), SPINE_Y));
+ .forEach(d -> place(d, c(spine++, spines.size(), spinesGap), spineY));
}
private void placeServiceLeavesAndHosts() {
@@ -124,7 +156,7 @@
serviceLeaf = 1;
leaves.stream().sorted(Comparators.ELEMENT_ID_COMPARATOR).forEach(id -> {
gateway = 1;
- place(id, c(serviceLeaf++, leaves.size(), SERVICE_GAP), SERVICE_Y);
+ place(id, c(serviceLeaf++, leaves.size(), serviceGap), serviceY);
List<HostId> gwHosts = hostService.getConnectedHosts(id).stream()
.map(Host::id)
@@ -134,8 +166,8 @@
.collect(Collectors.toList());
gwHosts.forEach(hid -> {
- place(hid, serviceLeaf <= 2 ? -GATEWAY_X : GATEWAY_X,
- c(gateway++, gwHosts.size(), GATEWAY_GAP, GATEWAY_OFFSET));
+ place(hid, serviceLeaf <= 2 ? -gatewayX : gatewayX,
+ c(gateway++, gwHosts.size(), gatewayGap, gatewayOffset));
placed.add(hid);
});
@@ -146,9 +178,9 @@
.sorted(Comparators.ELEMENT_ID_COMPARATOR)
.collect(Collectors.toList());
- placeHostBlock(hosts, serviceLeaf <= 2 ? -COMPUTE_OFFSET : COMPUTE_OFFSET,
- COMPUTE_Y, COMPUTE_PER_ROW, COMPUTE_ROW_GAP,
- serviceLeaf <= 2 ? -COL_GAP : COL_GAP);
+ placeHostBlock(hosts, serviceLeaf <= 2 ? -computeOffset : computeOffset,
+ computeY, computePerRow, computeRowGap,
+ serviceLeaf <= 2 ? -colGap : colGap);
placed.addAll(hosts);
});
}
@@ -165,7 +197,7 @@
.forEach(lid -> placeAccessLeafAndHosts(lid, leaves.size(), placed));
} else {
spines.stream().sorted(Comparators.ELEMENT_ID_COMPARATOR).forEach(id -> {
- place(id, c(aggregation++, spines.size(), AGGREGATION_GAP), AGGREGATION_Y);
+ place(id, c(aggregation++, spines.size(), aggregationGap), aggregationY);
linkService.getDeviceEgressLinks(id).stream()
.map(l -> l.dst().deviceId())
.filter(leaves::contains)
@@ -177,14 +209,14 @@
}
private void placeAccessLeafAndHosts(DeviceId leafId, int leafCount, Set<DeviceId> placed) {
- double x = c(accessLeaf++, leafCount, ACCESS_GAP);
- place(leafId, x, ACCESS_Y);
+ double x = c(accessLeaf++, leafCount, accessGap);
+ place(leafId, x, accessY);
placed.add(leafId);
placeHostBlock(hostService.getConnectedHosts(leafId).stream()
.map(Host::id)
.sorted(Comparators.ELEMENT_ID_COMPARATOR)
- .collect(Collectors.toList()), x, HOSTS_Y,
- HOSTS_PER_ROW, ROW_GAP, COL_GAP);
+ .collect(Collectors.toList()), x, hostsY,
+ hostsPerRow, rowGap, colGap);
}
}
diff --git a/apps/layout/src/main/java/org/onosproject/layout/LayoutOverlayMessageHandler.java b/apps/layout/src/main/java/org/onosproject/layout/LayoutOverlayMessageHandler.java
new file mode 100644
index 0000000..f66f1bd
--- /dev/null
+++ b/apps/layout/src/main/java/org/onosproject/layout/LayoutOverlayMessageHandler.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2018-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.layout;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.ImmutableSet;
+import org.onlab.osgi.ServiceDirectory;
+import org.onosproject.ui.RequestHandler;
+import org.onosproject.ui.UiConnection;
+import org.onosproject.ui.UiMessageHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collection;
+
+/**
+ * ONOS UI Layout Topology-Overlay message handler.
+ */
+public class LayoutOverlayMessageHandler extends UiMessageHandler {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ private static final String DO_LAYOUT = "doLayout";
+ private static final String TYPE = "type";
+
+ RoleBasedLayoutManager layoutManager;
+
+ @Override
+ public void init(UiConnection connection, ServiceDirectory directory) {
+ super.init(connection, directory);
+ layoutManager = directory.get(RoleBasedLayoutManager.class);
+ }
+
+ @Override
+ protected Collection<RequestHandler> createRequestHandlers() {
+ return ImmutableSet.of(
+ new LayoutHandler()
+ );
+ }
+
+ private final class LayoutHandler extends RequestHandler {
+
+ public LayoutHandler() {
+ super(DO_LAYOUT);
+ }
+
+ @Override
+ public void process(ObjectNode payload) {
+ String algorithm = string(payload, TYPE);
+ switch (algorithm) {
+ case "access":
+ layoutManager.layout(new AccessNetworkLayout());
+ break;
+ default:
+ layoutManager.layout(new DefaultForceLayout());
+ break;
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/apps/layout/src/main/java/org/onosproject/layout/RoleBasedLayoutManager.java b/apps/layout/src/main/java/org/onosproject/layout/RoleBasedLayoutManager.java
index 0340c7c..932e626 100644
--- a/apps/layout/src/main/java/org/onosproject/layout/RoleBasedLayoutManager.java
+++ b/apps/layout/src/main/java/org/onosproject/layout/RoleBasedLayoutManager.java
@@ -16,6 +16,7 @@
package org.onosproject.layout;
+import com.google.common.collect.ImmutableList;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
@@ -26,9 +27,18 @@
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.host.HostService;
import org.onosproject.net.link.LinkService;
+import org.onosproject.ui.UiExtension;
+import org.onosproject.ui.UiExtensionService;
+import org.onosproject.ui.UiMessageHandlerFactory;
+import org.onosproject.ui.UiTopoOverlay;
+import org.onosproject.ui.UiTopoOverlayFactory;
+import org.onosproject.ui.UiView;
+import org.onosproject.ui.UiViewHidden;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.List;
+
/**
* Manages automatic layout of the current network elements into one of several
* supported layout variants using roles assigned to network elements using
@@ -40,6 +50,30 @@
private Logger log = LoggerFactory.getLogger(getClass());
+ private static final String VIEW_ID = "tlTopov";
+ private static final String OVERLAY_ID = "tl-overlay";
+
+ // List of application views
+ private final List<UiView> uiViews = ImmutableList.of(
+ new UiViewHidden(VIEW_ID)
+ );
+
+ // Factory for UI message handlers
+ private final UiMessageHandlerFactory messageHandlerFactory =
+ () -> ImmutableList.of(new LayoutOverlayMessageHandler());
+
+ // Factory for UI topology overlays
+ private final UiTopoOverlayFactory topoOverlayFactory =
+ () -> ImmutableList.of(new UiTopoOverlay(OVERLAY_ID));
+
+ // Application UI extension
+ protected UiExtension extension =
+ new UiExtension.Builder(getClass().getClassLoader(), uiViews)
+ .resourcePath(VIEW_ID)
+ .messageHandlerFactory(messageHandlerFactory)
+ .topoOverlayFactory(topoOverlayFactory)
+ .build();
+
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected NetworkConfigService networkConfigService;
@@ -52,17 +86,21 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected LinkService linkService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected UiExtensionService uiExtensionService;
+
@Activate
protected void activate() {
+ uiExtensionService.register(extension);
log.info("Started");
}
@Deactivate
protected void deactivate() {
+ uiExtensionService.unregister(extension);
log.info("Stopped");
}
-
/**
* Executes the specified layout algorithm.
*
diff --git a/apps/layout/src/main/resources/app/view/tlTopov/tlTopov.css b/apps/layout/src/main/resources/app/view/tlTopov/tlTopov.css
new file mode 100644
index 0000000..8aa18f6
--- /dev/null
+++ b/apps/layout/src/main/resources/app/view/tlTopov/tlTopov.css
@@ -0,0 +1,2 @@
+/* css for layout topology overlay */
+
diff --git a/apps/layout/src/main/resources/app/view/tlTopov/tlTopov.html b/apps/layout/src/main/resources/app/view/tlTopov/tlTopov.html
new file mode 100644
index 0000000..1f76225
--- /dev/null
+++ b/apps/layout/src/main/resources/app/view/tlTopov/tlTopov.html
@@ -0,0 +1,4 @@
+<!-- partial HTML -->
+<div id="ov-tl-topov">
+ <p>This is a hidden view .. just a placeholder to house the javascript</p>
+</div>
diff --git a/apps/layout/src/main/resources/app/view/tlTopov/tlTopov.js b/apps/layout/src/main/resources/app/view/tlTopov/tlTopov.js
new file mode 100644
index 0000000..729d117
--- /dev/null
+++ b/apps/layout/src/main/resources/app/view/tlTopov/tlTopov.js
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2015-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.
+ */
+
+/*
+ Module containing the "business logic" for the layout topology overlay.
+ */
+
+(function () {
+ 'use strict';
+
+ // injected refs
+ var $log, flash, wss;
+
+ function doLayout(type, description) {
+ flash.flash(description);
+ wss.sendEvent('doLayout', {
+ type: type
+ });
+ }
+
+ angular.module('ovTlTopov', [])
+ .factory('LayoutTopovService',
+ ['$log', 'FlashService', 'WebSocketService',
+
+ function (_$log_, _flash_, _wss_) {
+ $log = _$log_;
+ flash = _flash_;
+ wss = _wss_;
+
+ return {
+ doLayout: doLayout
+ };
+ }]);
+}());
diff --git a/apps/layout/src/main/resources/app/view/tlTopov/tlTopovOverlay.js b/apps/layout/src/main/resources/app/view/tlTopov/tlTopovOverlay.js
new file mode 100644
index 0000000..aba7d14
--- /dev/null
+++ b/apps/layout/src/main/resources/app/view/tlTopov/tlTopovOverlay.js
@@ -0,0 +1,58 @@
+// path painter topology overlay - client side
+//
+// This is the glue that binds our business logic (in ppTopov.js)
+// to the overlay framework.
+
+(function () {
+ 'use strict';
+
+ // injected refs
+ var $log, tov, lts;
+
+ // our overlay definition
+ var overlay = {
+ overlayId: 'tl-overlay',
+ glyphId: 'm_disjointPaths',
+ tooltip: 'Algorithmic Layout Overlay',
+
+ activate: function () {
+ $log.debug("Layout topology overlay ACTIVATED");
+ },
+ deactivate: function () {
+ lts.clear();
+ $log.debug("Layout topology overlay DEACTIVATED");
+ },
+
+ keyBindings: {
+ 0: {
+ cb: function () {
+ lts.doLayout('default', 'Default (force-based) Layout');
+ },
+ tt: 'Default (force-based) layout',
+ gid: 'm_fiberSwitch'
+ },
+ 1: {
+ cb: function () {
+ lts.doLayout('access', 'Access Network Layout - separate service leafs');
+ },
+ tt: 'Access layout - separate service leafs',
+ gid: 'm_disjointPaths'
+ },
+
+ _keyOrder: [
+ '0', '1'
+ ]
+ }
+ };
+
+ // invoke code to register with the overlay service
+ angular.module('ovTlTopov')
+ .run(['$log', 'TopoOverlayService', 'LayoutTopovService',
+
+ function (_$log_, _tov_, _lts_) {
+ $log = _$log_;
+ tov = _tov_;
+ lts = _lts_;
+ tov.register(overlay);
+ }]);
+}());
diff --git a/apps/layout/src/main/resources/tlTopov/css.html b/apps/layout/src/main/resources/tlTopov/css.html
new file mode 100644
index 0000000..12810e7
--- /dev/null
+++ b/apps/layout/src/main/resources/tlTopov/css.html
@@ -0,0 +1 @@
+<link rel="stylesheet" href="app/view/tlTopov/tlTopov.css">
\ No newline at end of file
diff --git a/apps/layout/src/main/resources/tlTopov/js.html b/apps/layout/src/main/resources/tlTopov/js.html
new file mode 100644
index 0000000..85afb32
--- /dev/null
+++ b/apps/layout/src/main/resources/tlTopov/js.html
@@ -0,0 +1,2 @@
+<script src="app/view/tlTopov/tlTopov.js"></script>
+<script src="app/view/tlTopov/tlTopovOverlay.js"></script>
\ No newline at end of file
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/UiWebSocket.java b/web/gui/src/main/java/org/onosproject/ui/impl/UiWebSocket.java
index 4d01f8c..61f8015 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/UiWebSocket.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/UiWebSocket.java
@@ -251,18 +251,18 @@
ObjectNode message = (ObjectNode) mapper.reader().readTree(data);
String type = message.path(EVENT).asText(UNKNOWN);
- if (sessionToken == null) {
- authenticate(type, message);
-
+// if (sessionToken == null) {
+// authenticate(type, message);
+//
+// } else {
+ UiMessageHandler handler = handlers.get(type);
+ if (handler != null) {
+ log.debug("RX message: {}", message);
+ handler.process(message);
} else {
- UiMessageHandler handler = handlers.get(type);
- if (handler != null) {
- log.debug("RX message: {}", message);
- handler.process(message);
- } else {
- log.warn("No GUI message handler for type {}", type);
- }
+ log.warn("No GUI message handler for type {}", type);
}
+// }
} catch (Exception e) {
log.warn("Unable to parse GUI message {} due to {}", data, e);