Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWinston Prakash2014-05-30 00:32:46 -0400
committerWinston Prakash2014-05-30 00:32:46 -0400
commit775b0c4e045f809ca528acefdb224c3a56f43b7f (patch)
treeced636b2e51a31ccfb40d6b58666d4258e5c7ac8 /hudson-core
parent7fbe196540356c5bf70b1ee64d50210dae7f963b (diff)
downloadorg.eclipse.hudson.core-775b0c4e045f809ca528acefdb224c3a56f43b7f.tar.gz
org.eclipse.hudson.core-775b0c4e045f809ca528acefdb224c3a56f43b7f.tar.xz
org.eclipse.hudson.core-775b0c4e045f809ca528acefdb224c3a56f43b7f.zip
Phase 4 of View/Node isolation implementation. The team owned nodes are shown when a team member is logged in. Also based on the Team member permission, the create/delete/configure node is allowed.
Diffstat (limited to 'hudson-core')
-rw-r--r--hudson-core/src/main/java/hudson/model/Computer.java10
-rw-r--r--hudson-core/src/main/java/hudson/model/ComputerSet.java55
-rw-r--r--hudson-core/src/main/java/hudson/model/Hudson.java17
-rw-r--r--hudson-core/src/main/java/hudson/model/View.java3
-rw-r--r--hudson-core/src/main/java/org/eclipse/hudson/security/team/TeamBasedACL.java81
-rw-r--r--hudson-core/src/main/java/org/eclipse/hudson/security/team/TeamManager.java20
-rw-r--r--hudson-core/src/main/java/org/eclipse/hudson/security/team/TeamMember.java28
-rw-r--r--hudson-core/src/main/resources/hudson/model/ComputerSet/_new.jelly49
-rw-r--r--hudson-core/src/main/resources/hudson/model/ComputerSet/new.jelly31
-rw-r--r--hudson-core/src/main/resources/hudson/model/ComputerSet/sidepanel.jelly27
-rw-r--r--hudson-core/src/main/resources/hudson/model/View/sidepanel2.jelly10
-rw-r--r--hudson-core/src/main/resources/lib/hudson/executors.jelly13
12 files changed, 250 insertions, 94 deletions
diff --git a/hudson-core/src/main/java/hudson/model/Computer.java b/hudson-core/src/main/java/hudson/model/Computer.java
index 67fc6a0e..16217d34 100644
--- a/hudson-core/src/main/java/hudson/model/Computer.java
+++ b/hudson-core/src/main/java/hudson/model/Computer.java
@@ -76,6 +76,7 @@ import java.net.Inet4Address;
import java.util.Collection;
import org.eclipse.hudson.security.HudsonSecurityEntitiesHolder;
import org.eclipse.hudson.security.HudsonSecurityManager;
+import org.eclipse.hudson.security.team.TeamManager;
/**
* Represents the running state of a remote computer that holds
@@ -1116,6 +1117,7 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces
public HttpResponse doDoDelete() throws IOException {
checkPermission(DELETE);
Hudson.getInstance().removeNode(getNode());
+ removeFromTeam(getName());
return new HttpRedirect("..");
}
@@ -1144,8 +1146,16 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces
}
}
Hudson.getInstance().removeNode(getNode());
+ removeFromTeam(getName());
return new HttpRedirect("..");
}
+
+ private void removeFromTeam(String name) throws IOException {
+ TeamManager teamManager = Hudson.getInstance().getTeamManager();
+ if (teamManager.isTeamManagementEnabled()) {
+ teamManager.removeNode(name);
+ }
+ }
/**
* Handles incremental log.
diff --git a/hudson-core/src/main/java/hudson/model/ComputerSet.java b/hudson-core/src/main/java/hudson/model/ComputerSet.java
index 3a70d683..8cc3e749 100644
--- a/hudson-core/src/main/java/hudson/model/ComputerSet.java
+++ b/hudson-core/src/main/java/hudson/model/ComputerSet.java
@@ -42,6 +42,9 @@ import java.util.Map;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
+import org.eclipse.hudson.security.team.Team;
+import org.eclipse.hudson.security.team.TeamManager;
+import org.eclipse.hudson.security.team.TeamManager.TeamNotFoundException;
/**
* Serves as the top of {@link Computer}s in the URL hierarchy. <p> Getter
@@ -208,7 +211,12 @@ public final class ComputerSet extends AbstractModelObject {
@QueryParameter String name, @QueryParameter String mode,
@QueryParameter String from) throws IOException, ServletException {
final Hudson app = Hudson.getInstance();
- app.checkPermission(Hudson.ADMINISTER); // TODO: new permission?
+
+ if (app.getTeamManager().isTeamManagementEnabled()) {
+ app.checkPermission(Computer.CREATE);
+ } else {
+ app.checkPermission(Hudson.ADMINISTER); // TODO: new permission?
+ }
if (mode != null && mode.equals("copy")) {
name = checkName(name);
@@ -231,6 +239,8 @@ public final class ComputerSet extends AbstractModelObject {
result.holdOffLaunchUntilSave = true;
app.addNode(result);
+
+ addToTeam(result.getNodeName(), null);
// send the browser to the config page
rsp.sendRedirect2(result.getNodeName() + "/configure");
@@ -253,11 +263,16 @@ public final class ComputerSet extends AbstractModelObject {
@QueryParameter String name,
@QueryParameter String type) throws IOException, ServletException, FormException {
final Hudson app = Hudson.getInstance();
- app.checkPermission(Hudson.ADMINISTER); // TODO: new permission?
+ if (app.getTeamManager().isTeamManagementEnabled()) {
+ app.checkPermission(Computer.CREATE);
+ } else {
+ app.checkPermission(Hudson.ADMINISTER); // TODO: new permission?
+ }
checkName(name);
Node result = NodeDescriptor.all().find(type).newInstance(req, req.getSubmittedForm());
app.addNode(result);
+ addToTeam(result.getNodeName(), null);
// take the user back to the slave list top page
rsp.sendRedirect2(".");
@@ -288,7 +303,13 @@ public final class ComputerSet extends AbstractModelObject {
* Makes sure that the given name is good as a slave name.
*/
public FormValidation doCheckName(@QueryParameter String value) throws IOException, ServletException {
- Hudson.getInstance().checkPermission(Hudson.ADMINISTER);
+
+ TeamManager teamManager = Hudson.getInstance().getTeamManager();
+ if (teamManager.isTeamManagementEnabled()) {
+ Hudson.getInstance().checkPermission(Computer.CREATE);
+ } else {
+ Hudson.getInstance().checkPermission(Hudson.ADMINISTER);
+ }
if (Util.fixEmpty(value) == null) {
return FormValidation.ok();
@@ -383,4 +404,32 @@ public final class ComputerSet extends AbstractModelObject {
}
return null;
}
+
+ private void addToTeam(String name, String teamName) throws IOException {
+ TeamManager teamManager = Hudson.getInstance().getTeamManager();
+ if (!teamManager.isTeamManagementEnabled()) {
+ if (teamName != null) {
+ throw new IOException("Team management is not enabled");
+ }
+ }
+ Team team = null;
+ if (teamName == null) {
+ try {
+ team = teamManager.findCurrentUserTeamForNewNode();
+ } catch (TeamNotFoundException ex) {
+ // Shouldn't happen, as user is already confirmed for Computer.CREATE
+ }
+ } else {
+ try {
+ team = teamManager.findTeam(teamName);
+ } catch (TeamNotFoundException e) {
+ throw new IOException("Team " + teamName + " does not exist");
+ }
+ }
+ try {
+ teamManager.addNode(team, name);
+ } catch (TeamNotFoundException ex) {
+ throw new IOException("Team " + teamName + " does not exist");
+ }
+ }
}
diff --git a/hudson-core/src/main/java/hudson/model/Hudson.java b/hudson-core/src/main/java/hudson/model/Hudson.java
index c686614d..e9c0e293 100644
--- a/hudson-core/src/main/java/hudson/model/Hudson.java
+++ b/hudson-core/src/main/java/hudson/model/Hudson.java
@@ -1527,6 +1527,23 @@ public final class Hudson extends Node implements ItemGroup<TopLevelItem>, Stapl
* Gets the read-only list of all {@link Computer}s.
*/
public Computer[] getComputers() {
+ Computer[] allComputers = getAllComputers();
+
+ List<Computer> copy = new ArrayList<Computer>();
+
+ if (this.isTeamManagementEnabled()) {
+ for (Computer computer : allComputers) {
+ if (computer.hasPermission(Computer.READ)) {
+ copy.add(computer);
+ }
+ }
+ return copy.toArray(new Computer[copy.size()]);
+ } else {
+ return allComputers;
+ }
+ }
+
+ public Computer[] getAllComputers() {
Computer[] r = computers.values().toArray(new Computer[computers.size()]);
Arrays.sort(r, new Comparator<Computer>() {
final Collator collator = Collator.getInstance();
diff --git a/hudson-core/src/main/java/hudson/model/View.java b/hudson-core/src/main/java/hudson/model/View.java
index 3149fbf2..14675a4e 100644
--- a/hudson-core/src/main/java/hudson/model/View.java
+++ b/hudson-core/src/main/java/hudson/model/View.java
@@ -739,8 +739,7 @@ public abstract class View extends AbstractModelObject implements AccessControll
try {
team = teamManager.findCurrentUserTeamForNewView();
} catch (TeamNotFoundException ex) {
- // Shouldn't happen, as user is already confirmed for Job.CREATE
-
+ // Shouldn't happen, as user is already confirmed for View.CREATE
}
} else {
try {
diff --git a/hudson-core/src/main/java/org/eclipse/hudson/security/team/TeamBasedACL.java b/hudson-core/src/main/java/org/eclipse/hudson/security/team/TeamBasedACL.java
index 335f96d2..a92e7684 100644
--- a/hudson-core/src/main/java/org/eclipse/hudson/security/team/TeamBasedACL.java
+++ b/hudson-core/src/main/java/org/eclipse/hudson/security/team/TeamBasedACL.java
@@ -11,6 +11,7 @@
package org.eclipse.hudson.security.team;
import hudson.model.Computer;
+import hudson.model.Hudson;
import hudson.model.Item;
import hudson.model.Job;
import hudson.model.View;
@@ -35,6 +36,7 @@ public class TeamBasedACL extends SidACL {
private transient Logger logger = LoggerFactory.getLogger(TeamBasedACL.class);
public enum SCOPE {
+
GLOBAL, TEAM_MANAGEMENT, TEAM, JOB, VIEW, NODE
};
private final SCOPE scope;
@@ -53,12 +55,12 @@ public class TeamBasedACL extends SidACL {
this(teamManager, scope);
this.job = job;
}
-
+
public TeamBasedACL(TeamManager teamManager, SCOPE scope, View view) {
this(teamManager, scope);
this.view = view;
}
-
+
public TeamBasedACL(TeamManager teamManager, SCOPE scope, Computer node) {
this(teamManager, scope);
this.node = node;
@@ -77,14 +79,14 @@ public class TeamBasedACL extends SidACL {
if (teamManager.isSysAdmin(userName)) {
return true;
}
-
+
if (scope == SCOPE.TEAM_MANAGEMENT) {
//Only Sysadmin gets to do Team Management
if (teamManager.isSysAdmin(userName)) {
return true;
}
}
-
+
if (scope == SCOPE.GLOBAL) {
//All non team members gets only READ Permission
if (permission.getImpliedBy() == Permission.READ) {
@@ -111,13 +113,22 @@ public class TeamBasedACL extends SidACL {
}
}
}
+ // Member of any of the team with Node CREATE Permission can create Node
+ if (permission == Computer.CREATE) {
+ for (Team userTeam : teamManager.findUserTeams(userName)) {
+ TeamMember member = userTeam.findMember(userName);
+ if ((member != null) && member.hasPermission(Computer.CREATE)) {
+ return true;
+ }
+ }
+ }
}
if (scope == SCOPE.TEAM) {
// Sysadmin gets to do all team maintenance operations
if (teamManager.isSysAdmin(userName)) {
return true;
}
-
+
for (Team userTeam : teamManager.findUserTeams(userName)) {
if (userTeam == team) {
// Team admin gets to do all team maintenance operations
@@ -148,9 +159,9 @@ public class TeamBasedACL extends SidACL {
}
// Grant Read permission to Public Jobs and jobs based on visibility
if (permission.getImpliedBy() == Permission.READ) {
- if (hasReadPermission(jobTeam, permission, userName)){
- return true;
- }
+ if (hasReadPermission(jobTeam, permission, userName)) {
+ return true;
+ }
}
if (permission == Item.EXTENDED_READ) {
if (hasReadPermission(jobTeam, permission, userName)) {
@@ -163,10 +174,10 @@ public class TeamBasedACL extends SidACL {
}
}
}
-
+
if (scope == SCOPE.VIEW) {
Team viewTeam = teamManager.findViewOwnerTeam(view.getViewName());
-
+
// Member of any of the team with View CREATE Permission can create View
if (permission == View.CREATE) {
for (Team userTeam : teamManager.findUserTeams(userName)) {
@@ -189,20 +200,34 @@ public class TeamBasedACL extends SidACL {
}
// Grant Read permission to Public Jobs and jobs based on visibility
if (permission == View.READ) {
- if (hasViewReadPermission(viewTeam, permission, userName)){
- return true;
- }
+ if (hasViewReadPermission(viewTeam, permission, userName)) {
+ return true;
+ }
}
-
+
}
-
+
if (scope == SCOPE.NODE) {
- Team nodeTeam = teamManager.findNodeOwnerTeam(node.getName());
+ String nodeName = node.getName();
+ if (node instanceof Hudson.MasterComputer) {
+ nodeName = "Master";
+ }
+ Team nodeTeam = teamManager.findNodeOwnerTeam(nodeName);
+
+ // Member of any of the team with Node CREATE Permission can create Node
+ if (permission == Computer.CREATE) {
+ for (Team userTeam : teamManager.findUserTeams(userName)) {
+ TeamMember member = userTeam.findMember(userName);
+ if ((member != null) && member.hasPermission(Computer.CREATE)) {
+ return true;
+ }
+ }
+ }
if (nodeTeam != null) {
if (nodeTeam.isMember(userName)) {
// All members of the team get read permission
- if (permission == View.READ) {
+ if (permission == Computer.READ) {
return true;
}
TeamMember member = nodeTeam.findMember(userName);
@@ -211,15 +236,15 @@ public class TeamBasedACL extends SidACL {
}
// Grant Read permission to Public Jobs and jobs based on visibility
if (permission == Computer.READ) {
- if (hasNodeReadPermission(nodeTeam, permission, userName)){
- return true;
- }
+ if (hasNodeReadPermission(nodeTeam, permission, userName)) {
+ return true;
+ }
}
-
+
}
return null;
}
-
+
private boolean hasReadPermission(Team jobTeam, Permission permission, String userName) {
// Grant Read permission to Public Jobs and jobs based on visibility
try {
@@ -247,7 +272,7 @@ public class TeamBasedACL extends SidACL {
}
return false;
}
-
+
private boolean hasViewReadPermission(Team viewTeam, Permission permission, String userName) {
// Grant Read permission to Public Views and views based on visibility
try {
@@ -275,13 +300,17 @@ public class TeamBasedACL extends SidACL {
}
return false;
}
-
+
private boolean hasNodeReadPermission(Team nodeTeam, Permission permission, String userName) {
+ String nodeName = node.getName();
+ if (node instanceof Hudson.MasterComputer) {
+ nodeName = "Master";
+ }
// Grant Read permission to Public Views and views based on visibility
try {
Team publicTeam = teamManager.findTeam(PublicTeam.PUBLIC_TEAM_NAME);
- if (publicTeam.isNodeOwner(node.getName())) {
+ if (publicTeam.isNodeOwner(nodeName)) {
if (permission == Computer.READ) {
return true;
}
@@ -291,7 +320,7 @@ public class TeamBasedACL extends SidACL {
}
if (nodeTeam != null) {
- TeamNode teamNode = nodeTeam.findNode(node.getName());
+ TeamNode teamNode = nodeTeam.findNode(nodeName);
for (Team userTeam : teamManager.findUserTeams(userName)) {
if (teamNode.isVisible(userTeam.getName())) {
return true;
diff --git a/hudson-core/src/main/java/org/eclipse/hudson/security/team/TeamManager.java b/hudson-core/src/main/java/org/eclipse/hudson/security/team/TeamManager.java
index c9a57571..0e1c350b 100644
--- a/hudson-core/src/main/java/org/eclipse/hudson/security/team/TeamManager.java
+++ b/hudson-core/src/main/java/org/eclipse/hudson/security/team/TeamManager.java
@@ -901,7 +901,7 @@ public final class TeamManager implements Saveable, AccessControlled {
if (!isCurrentUserSysAdmin()) {
throw new RuntimeException(getCurrentUser() + " is not a System Administrator");
}
- for (Computer node : hudson.getComputers()) {
+ for (Computer node : hudson.getAllComputers()) {
String nodeName = node.getName();
if (node instanceof Hudson.MasterComputer) {
//Master node does not have a name!!
@@ -1294,7 +1294,7 @@ public final class TeamManager implements Saveable, AccessControlled {
if (isCurrentUserSysAdmin()) {
return publicTeam;
}
- throw new TeamNotFoundException("User does not have create permission in any team");
+ throw new TeamNotFoundException("User does not have Job create permission in any team");
}
public Team findCurrentUserTeamForNewView() throws TeamNotFoundException {
@@ -1306,7 +1306,19 @@ public final class TeamManager implements Saveable, AccessControlled {
if (isCurrentUserSysAdmin()) {
return publicTeam;
}
- throw new TeamNotFoundException("User does not have create permission in any team");
+ throw new TeamNotFoundException("User does not have View create permission in any team");
+ }
+
+ public Team findCurrentUserTeamForNewNode() throws TeamNotFoundException {
+ // This will only find explicit team members with create permission
+ List<Team> currentUserTeamsWithPermission = getCurrentUserTeamsWithPermission(Computer.CREATE);
+ if (!currentUserTeamsWithPermission.isEmpty()) {
+ return currentUserTeamsWithPermission.get(0);
+ }
+ if (isCurrentUserSysAdmin()) {
+ return publicTeam;
+ }
+ throw new TeamNotFoundException("User does not have Node create permission in any team");
}
/**
@@ -1661,7 +1673,7 @@ public final class TeamManager implements Saveable, AccessControlled {
publicTeam.addView(teamView);
}
}
- for (Computer node : hudson.getComputers()) {
+ for (Computer node : hudson.getAllComputers()) {
TeamNode teamNode = new TeamNode(node.getName());
if (node instanceof Hudson.MasterComputer) {
//Master node does not have a name!!
diff --git a/hudson-core/src/main/java/org/eclipse/hudson/security/team/TeamMember.java b/hudson-core/src/main/java/org/eclipse/hudson/security/team/TeamMember.java
index 51a5f946..4f98afdf 100644
--- a/hudson-core/src/main/java/org/eclipse/hudson/security/team/TeamMember.java
+++ b/hudson-core/src/main/java/org/eclipse/hudson/security/team/TeamMember.java
@@ -253,13 +253,37 @@ public class TeamMember {
strWriter.append(",");
strWriter.append("delete");
}
+ if (teamMember.canConfigure()) {
+ strWriter.append(",");
+ strWriter.append("configure");
+ }
if (teamMember.canBuild()) {
strWriter.append(",");
strWriter.append("build");
}
- if (teamMember.canConfigure()) {
+ if (teamMember.canCreateView()) {
strWriter.append(",");
- strWriter.append("configure");
+ strWriter.append("createView");
+ }
+ if (teamMember.canDeleteView()) {
+ strWriter.append(",");
+ strWriter.append("deleteView");
+ }
+ if (teamMember.canConfigureView()) {
+ strWriter.append(",");
+ strWriter.append("configureView");
+ }
+ if (teamMember.canCreateNode()) {
+ strWriter.append(",");
+ strWriter.append("createNode");
+ }
+ if (teamMember.canDeleteNode()) {
+ strWriter.append(",");
+ strWriter.append("deleteNode");
+ }
+ if (teamMember.canConfigureNode()) {
+ strWriter.append(",");
+ strWriter.append("configureNode");
}
writer.startNode("permissions");
writer.setValue(strWriter.toString());
diff --git a/hudson-core/src/main/resources/hudson/model/ComputerSet/_new.jelly b/hudson-core/src/main/resources/hudson/model/ComputerSet/_new.jelly
index caed786f..21a88086 100644
--- a/hudson-core/src/main/resources/hudson/model/ComputerSet/_new.jelly
+++ b/hudson-core/src/main/resources/hudson/model/ComputerSet/_new.jelly
@@ -21,28 +21,35 @@
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout"
xmlns:t="/lib/hudson" xmlns:f="/lib/form">
- <l:layout norefresh="true" permission="${app.ADMINISTER}">
- <st:include page="sidepanel.jelly"/>
- <l:main-panel>
- <h1>
- <img width="48" height="48" src="${imagesURL}/48x48/setting.png" alt="" style="margin-right:10px"/>
- ${%Node Configurations}
- </h1>
- <f:form method="post" action="doCreateItem">
- <f:entry title="${%Name}" help="/help/system-config/master-slave/name.html">
- <f:textbox name="name" value="${request.getParameter('name')}" clazz="required" checkMessage="${%Name is mandatory}"/>
- </f:entry>
+ <j:if test="${app.isTeamManagementEnabled()}">
+ <j:getStatic var="permission" className="hudson.model.Computer" field="CREATE"/>
+ </j:if>
+ <j:if test="${!app.isTeamManagementEnabled()}">
+ <j:set var="permission" value="${app.ADMINISTER}" />
+ </j:if>
+ <l:layout norefresh="true" permission="${permission}">
+
+ <st:include page="sidepanel.jelly"/>
+ <l:main-panel>
+ <h1>
+ <img width="48" height="48" src="${imagesURL}/48x48/setting.png" alt="" style="margin-right:10px"/>
+ ${%Node Configurations}
+ </h1>
+ <f:form method="post" action="doCreateItem">
+ <f:entry title="${%Name}" help="/help/system-config/master-slave/name.html">
+ <f:textbox name="name" value="${request.getParameter('name')}" clazz="required" checkMessage="${%Name is mandatory}"/>
+ </f:entry>
- <!-- main body of the configuration -->
- <j:set var="it" value="${null}" />
- <st:include class="${requestScope.descriptor.clazz}" page="configure-entries.jelly" />
+ <!-- main body of the configuration -->
+ <j:set var="it" value="${null}" />
+ <st:include class="${requestScope.descriptor.clazz}" page="configure-entries.jelly" />
- <f:block>
- <input type="hidden" name="type" value="${request.getParameter('mode')}"/>
+ <f:block>
+ <input type="hidden" name="type" value="${request.getParameter('mode')}"/>
- <f:submit value="${%Save}"/>
- </f:block>
- </f:form>
- </l:main-panel>
- </l:layout>
+ <f:submit value="${%Save}"/>
+ </f:block>
+ </f:form>
+ </l:main-panel>
+ </l:layout>
</j:jelly>
diff --git a/hudson-core/src/main/resources/hudson/model/ComputerSet/new.jelly b/hudson-core/src/main/resources/hudson/model/ComputerSet/new.jelly
index dfe6b94b..018dc146 100644
--- a/hudson-core/src/main/resources/hudson/model/ComputerSet/new.jelly
+++ b/hudson-core/src/main/resources/hudson/model/ComputerSet/new.jelly
@@ -24,16 +24,23 @@
-->
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:s="/lib/form">
- <l:layout norefresh="true" permission="${app.ADMINISTER}">
- <st:include page="sidepanel.jelly" />
- <l:main-panel>
- <h1>
- <img width="48" height="48" src="${imagesURL}/48x48/computer.png" alt="" style="margin: 2px;"/>
- ${%New Node}
- </h1>
- <j:invokeStatic var="slaves" className="hudson.slaves.NodeDescriptor" method="allInstantiable" />
- <n:form nameTitle="${%Node name}" copyTitle="${%Copy Existing Node}" copyNames="${it._slaveNames}"
- descriptors="${slaves}" checkUrl="computer/checkName" xmlns:n="/lib/hudson/newFromList" />
- </l:main-panel>
- </l:layout>
+
+ <j:if test="${app.isTeamManagementEnabled()}">
+ <j:getStatic var="permission" className="hudson.model.Computer" field="CREATE"/>
+ </j:if>
+ <j:if test="${!app.isTeamManagementEnabled()}">
+ <j:set var="permission" value="${app.ADMINISTER}" />
+ </j:if>
+ <l:layout norefresh="true" permission="${permission}">
+ <st:include page="sidepanel.jelly" />
+ <l:main-panel>
+ <h1>
+ <img width="48" height="48" src="${imagesURL}/48x48/computer.png" alt="" style="margin: 2px;"/>
+ ${%New Node}
+ </h1>
+ <j:invokeStatic var="slaves" className="hudson.slaves.NodeDescriptor" method="allInstantiable" />
+ <n:form nameTitle="${%Node name}" copyTitle="${%Copy Existing Node}" copyNames="${it._slaveNames}"
+ descriptors="${slaves}" checkUrl="computer/checkName" xmlns:n="/lib/hudson/newFromList" />
+ </l:main-panel>
+ </l:layout>
</j:jelly>
diff --git a/hudson-core/src/main/resources/hudson/model/ComputerSet/sidepanel.jelly b/hudson-core/src/main/resources/hudson/model/ComputerSet/sidepanel.jelly
index 24b1b127..431fade6 100644
--- a/hudson-core/src/main/resources/hudson/model/ComputerSet/sidepanel.jelly
+++ b/hudson-core/src/main/resources/hudson/model/ComputerSet/sidepanel.jelly
@@ -14,20 +14,25 @@
#
#************************************************************************** -->
-
<!--
Side panel
-->
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:s="/lib/form">
- <l:header />
- <l:side-panel>
- <l:tasks>
- <l:task icon="images/24x24/up.png" href="${rootURL}/" title="${%Back to Main Dashboard}" />
- <l:task icon="images/24x24/new-computer.png" href="new" title="${%New Node}" permission="${app.ADMINISTER}" />
- <l:task icon="images/24x24/setting.png" href="configure" title="${%Configure}" permission="${app.ADMINISTER}" />
- </l:tasks>
- <t:queue items="${app.queue.items}" />
- <t:executors />
- </l:side-panel>
+ <l:header />
+ <l:side-panel>
+ <l:tasks>
+ <l:task icon="images/24x24/up.png" href="${rootURL}/" title="${%Back to Main Dashboard}" />
+ <j:if test="${app.isTeamManagementEnabled()}">
+ <j:getStatic var="permission" className="hudson.model.Computer" field="CREATE"/>
+ <l:task icon="images/24x24/new-computer.png" href="new" title="${%New Node}" permission="${permission}" />
+ </j:if>
+ <j:if test="${!app.isTeamManagementEnabled()}">
+ <l:task icon="images/24x24/new-computer.png" href="new" title="${%New Node}" permission="${app.ADMINISTER}" />
+ </j:if>
+ <l:task icon="images/24x24/setting.png" href="configure" title="${%Configure}" permission="${app.ADMINISTER}" />
+ </l:tasks>
+ <t:queue items="${app.queue.items}" />
+ <t:executors />
+ </l:side-panel>
</j:jelly>
diff --git a/hudson-core/src/main/resources/hudson/model/View/sidepanel2.jelly b/hudson-core/src/main/resources/hudson/model/View/sidepanel2.jelly
index 1a74a323..6661b981 100644
--- a/hudson-core/src/main/resources/hudson/model/View/sidepanel2.jelly
+++ b/hudson-core/src/main/resources/hudson/model/View/sidepanel2.jelly
@@ -19,7 +19,11 @@
-->
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:s="/lib/form">
- <j:if test="${it.hasPermission(it.CREATE)}">
- <l:task icon="images/32x32/folder.png" href="${rootURL}/newView" title="${%New View}" permission="${it.CONFIGURE}"/>
- </j:if>
+ <j:if test="${it.hasPermission(it.CREATE)}">
+ <l:task icon="images/32x32/folder.png" href="${rootURL}/newView" title="${%New View}" permission="${it.CONFIGURE}"/>
+ </j:if>
+ <j:if test="${app.isTeamManagementEnabled()}">
+ <j:getStatic var="permission" className="hudson.model.Computer" field="CREATE"/>
+ <l:task icon="images/24x24/new-computer.png" href="${rootURL}/computer/new" title="${%New Node}" permission="${permission}" />
+ </j:if>
</j:jelly>
diff --git a/hudson-core/src/main/resources/lib/hudson/executors.jelly b/hudson-core/src/main/resources/lib/hudson/executors.jelly
index 0a039988..b5df7387 100644
--- a/hudson-core/src/main/resources/lib/hudson/executors.jelly
+++ b/hudson-core/src/main/resources/lib/hudson/executors.jelly
@@ -112,18 +112,11 @@
<br/>
<j:forEach var="c" items="${computers}">
<table width="100%">
- <tr>
+ <tr>
<j:choose>
- <j:when test="${c.node==app or computers.size()==1}">
+ <j:when test="${c.node==app}">
<th class="pane" colspan="2">
- <j:choose>
- <j:when test="${empty(app.slaves) or computers.size()==1}">
- <local:computerCaption title="Status"/>
- </j:when>
- <j:otherwise>
- <local:computerCaption title="Master"/>
- </j:otherwise>
- </j:choose>
+ <local:computerCaption title="Master"/>
</th>
</j:when>
<j:otherwise>

Back to the top