org.opendaylight.controller.sal.utils,
org.opendaylight.controller.usermanager,
org.opendaylight.controller.containermanager,
+ org.opendaylight.controller.clustering.services,
+ org.opendaylight.controller.connectionmanager,
+ org.opendaylight.controller.switchmanager,
com.google.gson,
javax.annotation,
javax.naming,
</plugins>
</build>
<dependencies>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>clustering.services</artifactId>
+ <version>0.4.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>connectionmanager</artifactId>
+ <version>0.1.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>configuration</artifactId>
<artifactId>containermanager</artifactId>
<version>0.4.0-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>switchmanager</artifactId>
+ <version>0.5.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
--- /dev/null
+package org.opendaylight.controller.web;
+
+import java.net.InetAddress;
+
+/**
+ * Information about a clustered controller to send to the UI frontend
+ * @author andrekim
+ */
+public class ClusterNodeBean {
+ private final byte[] address;
+ private final String name;
+ private final Boolean me;
+ private final Boolean coordinator;
+
+ public static class Builder {
+ // required params
+ private final byte[] address;
+ private final String name;
+
+ // optional params
+ private Boolean me = null;
+ private Boolean coordinator = null;
+
+ public Builder(InetAddress address) {
+ this.address = address.getAddress();
+ this.name = address.getHostAddress();
+ }
+
+ public Builder highlightMe() {
+ this.me = true;
+ return this;
+ }
+
+ public Builder iAmCoordinator() {
+ this.coordinator = true;
+ return this;
+ }
+
+ public ClusterNodeBean build() {
+ return new ClusterNodeBean(this);
+ }
+ }
+
+ private ClusterNodeBean(Builder builder) {
+ this.address = builder.address;
+ this.name = builder.name;
+ this.me = builder.me;
+ this.coordinator = builder.coordinator;
+ }
+}
\ No newline at end of file
package org.opendaylight.controller.web;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
import javax.servlet.http.HttpServletRequest;
+import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
+import org.opendaylight.controller.connectionmanager.IConnectionManager;
import org.opendaylight.controller.sal.authorization.UserLevel;
+import org.opendaylight.controller.sal.core.Description;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.utils.GlobalConstants;
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.usermanager.IUserManager;
import org.opendaylight.controller.usermanager.UserConfig;
import org.springframework.stereotype.Controller;
@Controller
@RequestMapping("/admin")
public class DaylightWebAdmin {
+ Gson gson = new Gson();
+ /**
+ * Returns list of clustered controllers. Highlights "this" controller and
+ * if controller is coordinator
+ * @return List<ClusterBean>
+ */
+ @RequestMapping("/cluster")
+ @ResponseBody
+ public String getClusteredControllers() {
+ IClusterGlobalServices clusterServices = (IClusterGlobalServices) ServiceHelper.getGlobalInstance(
+ IClusterGlobalServices.class, this);
+ if (clusterServices == null) {
+ return null;
+ }
+
+ List<ClusterNodeBean> clusters = new ArrayList<ClusterNodeBean>();
+
+ List<InetAddress> controllers = clusterServices.getClusteredControllers();
+ for (InetAddress controller : controllers) {
+ ClusterNodeBean.Builder clusterBeanBuilder = new ClusterNodeBean.Builder(controller);
+ if (controller.equals(clusterServices.getMyAddress())) {
+ clusterBeanBuilder.highlightMe();
+ }
+ if (clusterServices.amICoordinator()) {
+ clusterBeanBuilder.iAmCoordinator();
+ }
+
+ clusters.add(clusterBeanBuilder.build());
+ }
+
+ return gson.toJson(clusters);
+ }
+
+ /**
+ * Return nodes connected to controller {controller}
+ * @param cluster
+ * - byte[] of the address of the controller
+ * @return List<NodeBean>
+ */
+ @RequestMapping("/cluster/controller/{controller}")
+ @ResponseBody
+ public String getNodesConnectedToController(@PathVariable("controller") String cluster) {
+ IClusterGlobalServices clusterServices = (IClusterGlobalServices) ServiceHelper.getGlobalInstance(
+ IClusterGlobalServices.class, this);
+ if (clusterServices == null) {
+ return null;
+ }
+ IConnectionManager connectionManager = (IConnectionManager) ServiceHelper.getGlobalInstance(
+ IConnectionManager.class, this);
+ if (connectionManager == null) {
+ return null;
+ }
+ ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class,
+ GlobalConstants.DEFAULT.toString(), this);
+ if (switchManager == null) {
+ return null;
+ }
+
+ byte[] address = gson.fromJson(cluster, byte[].class);
+ InetAddress clusterAddress = null;
+ try {
+ clusterAddress = InetAddress.getByAddress(address);
+ } catch (UnknownHostException e) {
+ return null;
+ }
+ InetAddress thisCluster = clusterServices.getMyAddress();
+
+ List<NodeBean> result = new ArrayList<NodeBean>();
+
+ Set<Node> nodes = connectionManager.getNodes(thisCluster);
+ for (Node node : nodes) {
+ Description description = (Description) switchManager.getNodeProp(node, Description.propertyName);
+ NodeBean nodeBean;
+ if (description == null || description.getValue().equals("None")) {
+ nodeBean = new NodeBean(node);
+ } else {
+ nodeBean = new NodeBean(node, description.getValue());
+ }
+ result.add(nodeBean);
+ }
+ return gson.toJson(result);
+ }
@RequestMapping("/users")
@ResponseBody
public List<UserConfig> getUsers() {
- IUserManager userManager = (IUserManager) ServiceHelper
- .getGlobalInstance(IUserManager.class, this);
+ IUserManager userManager = (IUserManager) ServiceHelper.getGlobalInstance(IUserManager.class, this);
if (userManager == null) {
return null;
}
*/
@RequestMapping(value = "/users", method = RequestMethod.POST)
@ResponseBody
- public String saveLocalUserConfig(
- @RequestParam(required = true) String json,
- @RequestParam(required = true) String action,
- HttpServletRequest request) {
+ public String saveLocalUserConfig(@RequestParam(required = true) String json,
+ @RequestParam(required = true) String action, HttpServletRequest request) {
- IUserManager userManager = (IUserManager) ServiceHelper
- .getGlobalInstance(IUserManager.class, this);
+ IUserManager userManager = (IUserManager) ServiceHelper.getGlobalInstance(IUserManager.class, this);
if (userManager == null) {
return "Internal Error";
}
Gson gson = new Gson();
UserConfig config = gson.fromJson(json, UserConfig.class);
- Status result = (action.equals("add")) ? userManager
- .addLocalUser(config) : userManager.removeLocalUser(config);
- if(result.getCode().equals(StatusCode.SUCCESS)) {
- String userAction=(action.equals("add")) ? "added":"removed";
+ Status result = (action.equals("add")) ? userManager.addLocalUser(config) : userManager.removeLocalUser(config);
+ if (result.isSuccess()) {
+ String userAction = (action.equals("add")) ? "added" : "removed";
DaylightWebUtil.auditlog("User", request.getUserPrincipal().getName(), userAction, config.getUser());
return "Success";
}
@RequestMapping(value = "/users/{username}", method = RequestMethod.POST)
@ResponseBody
- public String removeLocalUser(@PathVariable("username") String userName,
- HttpServletRequest request) {
+ public String removeLocalUser(@PathVariable("username") String userName, HttpServletRequest request) {
String username = request.getUserPrincipal().getName();
if (username.equals(userName)) {
return "Invalid Request: User cannot delete itself";
}
- IUserManager userManager = (IUserManager) ServiceHelper
- .getGlobalInstance(IUserManager.class, this);
+ IUserManager userManager = (IUserManager) ServiceHelper.getGlobalInstance(IUserManager.class, this);
if (userManager == null) {
return "Internal Error";
}
}
Status result = userManager.removeLocalUser(userName);
- if(result.getCode().equals(StatusCode.SUCCESS)) {
+ if (result.isSuccess()) {
DaylightWebUtil.auditlog("User", request.getUserPrincipal().getName(), "removed", userName);
return "Success";
}
@ResponseBody
public Status changePassword(@PathVariable("username") String username, HttpServletRequest request,
@RequestParam("currentPassword") String currentPassword, @RequestParam("newPassword") String newPassword) {
- IUserManager userManager = (IUserManager) ServiceHelper
- .getGlobalInstance(IUserManager.class, this);
+ IUserManager userManager = (IUserManager) ServiceHelper.getGlobalInstance(IUserManager.class, this);
if (userManager == null) {
return new Status(StatusCode.GONE, "User Manager not found");
}
}
Status status = userManager.changeLocalUserPassword(username, currentPassword, newPassword);
- if(status.isSuccess()){
+ if (status.isSuccess()) {
DaylightWebUtil.auditlog("User", request.getUserPrincipal().getName(), "changed password for", username);
}
return status;
/**
* Is the operation permitted for the given level
- *
* @param level
*/
- private boolean authorize(IUserManager userManager, UserLevel level,
- HttpServletRequest request) {
+ private boolean authorize(IUserManager userManager, UserLevel level, HttpServletRequest request) {
String username = request.getUserPrincipal().getName();
UserLevel userLevel = userManager.getUserLevel(username);
return userLevel.toNumber() <= level.toNumber();
--- /dev/null
+package org.opendaylight.controller.web;
+
+import org.opendaylight.controller.sal.core.Node;
+
+/**
+ * Information about a node connected to a controller to send to the UI frontend
+ * @author andrekim
+ */
+public class NodeBean {
+ private final String node;
+ private final String description;
+
+ public NodeBean(Node node) {
+ this(node, node.toString());
+ }
+
+ public NodeBean(Node node, String description) {
+ this.node = node.toString();
+ this.description = description;
+ }
+}
<div class="icon-user"></div> ${username} <span class="caret"></span>
</a>
<ul class="dropdown-menu">
- <li><a href="#admin" id="admin" data-role="${role}"><div
- class="icon-users"></div> Users</a></li>
- <li><a href="#save" id="save"><div class="icon-save"></div>
- Save</a></li>
- <li><a href="#logout" id="logout"><div
- class="icon-logout"></div> Logout</a></li>
+ <li><a href="#admin" id="admin" data-role="${role}"><div class="icon-users"></div> Users</a></li>
+ <li><a href="#cluster" id="cluster"><div class="icon-cluster"></div>Cluster</a></li>
+ <li><a href="#save" id="save"><div class="icon-save"></div>Save</a></li>
+ <li><a href="#logout" id="logout"><div class="icon-logout"></div> Logout</a></li>
</ul>
</div>
</div>
.icon;
background-image: url('../img/user_group_0107_16.png');
}
+ .icon-cluster {
+ .icon;
+ background-image: url('../img/topology_view_1033_16.png');
+ }
.icon-save {
.icon;
background-image: url('../img/save_as_0106_16.png');
$h4.text(header);
return $h4;
},
+ label : function(name, type) {
+ var $span = $(document.createElement('span'));
+ $span.addClass('label');
+ if (type !== undefined) {
+ $span.addClass(type);
+ } else if (type !== null) {
+ $span.addClass('label-info');
+ }
+ $span.append(name);
+ return $span;
+ },
list : function(list) {
var $ul = $(document.createElement('ul'));
$(list).each(function(index, value) {
},
footer : function() {
var footer = [];
-
- var closeButton = one.lib.dashlet.button.single("Close",
- one.main.admin.id.modal.close, "", "");
+ var closeButton = one.lib.dashlet.button.single('Close', one.main.admin.id.modal.close, '', '');
var $closeButton = one.lib.dashlet.button.button(closeButton);
footer.push($closeButton);
-
return footer;
}
},
var $body = one.main.admin.remove.body();
var $modal = one.lib.modal.spawn(one.main.admin.id.modal.user,
h3, $body, footer);
-
// close binding
- $('#' + one.main.admin.id.modal.remove.close, $modal).click(
- function() {
- $modal.modal('hide');
- });
-
+ $('#'+one.main.admin.id.modal.remove.close, $modal).click(function() {
+ $modal.modal('hide');
+ });
// remove binding
- $('#' + one.main.admin.id.modal.remove.user, $modal)
- .click(
- function() {
- one.main.admin.remove.modal
- .ajax(
- id,
- function(result) {
- if (result == 'Success') {
- $modal
- .modal('hide');
- // body inject
- var $admin = $('#'
- + one.main.admin.id.modal.main);
- one.main.admin.ajax
- .users(function($body) {
- one.lib.modal.inject
- .body(
- $admin,
- $body);
- });
- } else
- alert("Failed to remove user: "
- + result);
- });
- });
-
+ $('#' + one.main.admin.id.modal.remove.user, $modal).click(function() {
+ one.main.admin.remove.modal.ajax(id, function(result) {
+ if (result == 'Success') {
+ $modal.modal('hide');
+ // body inject
+ var $admin = $('#'+one.main.admin.id.modal.main);
+ one.main.admin.ajax.users(function($body) {
+ one.lib.modal.inject.body($admin, $body);
+ });
+ } else {
+ alert("Failed to remove user: " + result);
+ }
+ });
+ });
// change password binding
$('#' + one.main.admin.id.modal.remove.password, $modal).click(function() {
one.main.admin.password.initialize(id, function() {
$modal.modal('hide');
});
});
-
$modal.modal();
},
ajax : function(id, callback) {
- $.post(one.main.admin.address.root
- + one.main.admin.address.users + '/' + id,
- function(data) {
- callback(data);
- });
+ $.post(one.main.admin.address.root + one.main.admin.address.users + '/' + id, function(data) {
+ callback(data);
+ });
},
},
-
footer : function() {
var footer = [];
-
var removeButton = one.lib.dashlet.button.single("Remove User",
one.main.admin.id.modal.remove.user, "btn-danger", "");
var $removeButton = one.lib.dashlet.button.button(removeButton);
footer.push($removeButton);
-
var change = one.lib.dashlet.button.single('Change Password',
one.main.admin.id.modal.remove.password, 'btn-success', '');
var $change = one.lib.dashlet.button.button(change);
footer.push($change);
-
var closeButton = one.lib.dashlet.button.single("Close",
one.main.admin.id.modal.remove.close, "", "");
var $closeButton = one.lib.dashlet.button.button(closeButton);
footer.push($closeButton);
-
return footer;
},
body : function() {
var $body = one.main.admin.add.body();
var $modal = one.lib.modal.spawn(one.main.admin.id.modal.user,
h3, $body, footer);
-
// close binding
- $('#' + one.main.admin.id.modal.add.close, $modal).click(
- function() {
- $modal.modal('hide');
- });
-
+ $('#' + one.main.admin.id.modal.add.close, $modal).click(function() {
+ $modal.modal('hide');
+ });
// add binding
- $('#' + one.main.admin.id.modal.add.user, $modal)
- .click(
- function() {
- one.main.admin.add.modal
- .add(
- $modal,
- function(result) {
- if (result == 'Success') {
- $modal
- .modal('hide');
- // body inject
- var $admin = $('#'
- + one.main.admin.id.modal.main);
- one.main.admin.ajax
- .users(function($body) {
- one.lib.modal.inject
- .body(
- $admin,
- $body);
- });
- } else
- alert("Failed to add user: "
- + result);
- });
- });
-
+ $('#' + one.main.admin.id.modal.add.user, $modal).click(function() {
+ one.main.admin.add.modal.add($modal, function(result) {
+ if (result == 'Success') {
+ $modal.modal('hide');
+ // body inject
+ var $admin = $('#'+one.main.admin.id.modal.main);
+ one.main.admin.ajax.users(function($body) {
+ one.lib.modal.inject.body($admin, $body);
+ });
+ } else {
+ alert("Failed to add user: "+result);
+ }
+ });
+ });
$modal.modal();
},
add : function($modal, callback) {
}
}
+one.main.cluster = {
+ id : { // one.main.cluster.id
+ modal : 'one-main-cluster-id-modal',
+ close : 'one-main-cluster-id-close',
+ datagrid : 'one-main-cluster-id-datagrid'
+ },
+ registry : { // one.main.cluster.registry
+ cluster : undefined
+ },
+ initialize : function() {
+ var h3 = 'Cluster Management';
+ var footer = one.main.cluster.footer();
+ var $body = '';
+ var $modal = one.lib.modal.spawn(one.main.cluster.id.modal, h3, $body, footer);
+
+ // close
+ $('#'+one.main.cluster.id.close, $modal).click(function() {
+ $modal.modal('hide');
+ });
+
+ // body
+ $.getJSON('/admin/cluster', function(data) {
+ var $gridHTML = one.lib.dashlet.datagrid.init(one.main.cluster.id.datagrid, {
+ searchable: true,
+ filterable: false,
+ pagination: true,
+ flexibleRowsPerPage: true
+ }, 'table-striped table-condensed table-cursor');
+ var source = one.main.cluster.data(data);
+ $gridHTML.datagrid({dataSource : source}).on('loaded', function() {
+ $(this).find('tbody tr').click(function() {
+ var $tr = $(this);
+ if ($tr.find('td:nth-child(1)').attr('colspan') === '1') {
+ return false;
+ }
+ var address = one.main.cluster.registry.cluster[$tr.index()];
+ one.main.cluster.nodes.initialize(address);
+ });
+ });
+ one.lib.modal.inject.body($modal, $gridHTML);
+ });
+
+ $modal.modal();
+ },
+ data : function(data) {
+ var tdata = [];
+ var registry = [];
+ $(data).each(function(idx, val) {
+ var name = val.name;
+ name = one.lib.dashlet.label(name, null)[0].outerHTML;
+ if (val.me === true) {
+ var me = one.lib.dashlet.label('*', 'label-inverse')[0].outerHTML;
+ name += ' '+me;
+ }
+ if (val.coordinator === true) {
+ var coord = one.lib.dashlet.label('C')[0].outerHTML;
+ name += ' '+coord;
+ }
+ tdata.push({
+ 'controller' : name
+ });
+ registry.push(val.address);
+ });
+ one.main.cluster.registry.cluster = registry;
+ var source = new StaticDataSource({
+ columns : [
+ {
+ property : 'controller',
+ label : 'Controller',
+ sortable : true
+ }
+ ],
+ data : tdata,
+ delay : 0
+ });
+ return source;
+ },
+ footer : function() {
+ var footer = [];
+ var close = one.lib.dashlet.button.single('Close', one.main.cluster.id.close, '', '');
+ var $close = one.lib.dashlet.button.button(close);
+ footer.push($close);
+ return footer;
+ }
+}
+
+one.main.cluster.nodes = {
+ id : { // one.main.cluster.nodes.id
+ modal : 'one-main-cluster-nodes-id-modal',
+ close : 'one-main-cluster-nodes-id-close',
+ datagrid : 'one-main-cluser-nodes-id-datagrid'
+ },
+ initialize : function(address) { // one.main.cluster.nodes.initialize
+ var h3 = 'Connected Nodes';
+ var footer = one.main.cluster.nodes.footer();
+ var $body = '';
+ var $modal = one.lib.modal.spawn(one.main.cluster.nodes.id.modal, h3, $body, footer);
+
+ // close
+ $('#'+one.main.cluster.nodes.id.close, $modal).click(function() {
+ $modal.modal('hide');
+ });
+
+ // body
+ $.getJSON('/admin/cluster/controller/'+JSON.stringify(address), function(data) {
+ var $gridHTML = one.lib.dashlet.datagrid.init(one.main.cluster.nodes.id.datagrid, {
+ searchable: true,
+ filterable: false,
+ pagination: true,
+ flexibleRowsPerPage: true
+ }, 'table-striped table-condensed');
+ var source = one.main.cluster.nodes.data(data);
+ $gridHTML.datagrid({dataSource : source});
+ one.lib.modal.inject.body($modal, $gridHTML);
+ });
+
+ $modal.modal();
+ },
+ data : function(data) {
+ var tdata = [];
+ $(data).each(function(idx, val) {
+ tdata.push({
+ 'node' : val.description
+ });
+ });
+ var source = new StaticDataSource({
+ columns : [
+ {
+ property : 'node',
+ label : 'Node',
+ sortable : true
+ }
+ ],
+ data : tdata,
+ delay : 0
+ });
+ return source;
+ },
+ footer : function() { // one.main.cluster.nodes.footer
+ var footer = [];
+ var close = one.lib.dashlet.button.single('Close', one.main.cluster.nodes.id.close, '', '');
+ var $close = one.lib.dashlet.button.button(close);
+ footer.push($close);
+ return footer;
+ }
+}
+
one.main.dashlet = {
left : {
top : $("#left-top .dashlet"),
});
});
+// cluster
+$('#cluster').click(function() {
+ one.main.cluster.initialize();
+});
+
// save
$("#save").click(function() {
$.post(one.main.constants.address.save, function(data) {