Skip to content

Commit ed5445d

Browse files
authored
Merge pull request #202 from mawinter69/JENKINS-63528
[JENKINS-63528] add possibility to check for regex of agent roles
2 parents 8596733 + 263f564 commit ed5445d

File tree

5 files changed

+113
-11
lines changed

5 files changed

+113
-11
lines changed

src/main/java/com/michelin/cio/hudson/plugins/rolestrategy/RoleBasedAuthorizationStrategy.java

+23
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,29 @@ public void doGetMatchingJobs(@QueryParameter(required = true) String pattern,
528528
writer.close();
529529
}
530530

531+
/**
532+
* API method to get a list of agents matching a pattern
533+
* Example: curl -X GET localhost:8080/role-strategy/strategy/getMatchingAgents?pattern=^linux.*
534+
*
535+
* @param pattern Pattern to match against
536+
* @param maxAgents Maximum matching agents to search for
537+
* @throws IOException when unable to write response
538+
*/
539+
@GET
540+
@Restricted(NoExternalUse.class)
541+
public void doGetMatchingAgents(@QueryParameter(required = true) String pattern,
542+
@QueryParameter() int maxAgents) throws IOException {
543+
checkAdminPerm();
544+
List<String> matchingAgents = RoleMap.getMatchingAgentNames(Pattern.compile(pattern), maxAgents);
545+
JSONObject responseJson = new JSONObject();
546+
responseJson.put("matchingAgents", matchingAgents);
547+
StaplerResponse response = Stapler.getCurrentResponse();
548+
response.setContentType("application/json;charset=UTF-8");
549+
Writer writer = response.getCompressedWriter(Stapler.getCurrentRequest());
550+
responseJson.write(writer);
551+
writer.close();
552+
}
553+
531554
@Extension
532555
public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
533556

src/main/java/com/michelin/cio/hudson/plugins/rolestrategy/RoleMap.java

+18
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
3535
import hudson.model.Item;
3636
import hudson.model.ItemGroup;
37+
import hudson.model.Node;
3738
import hudson.model.User;
3839
import hudson.security.AccessControlled;
3940
import hudson.security.Permission;
@@ -439,6 +440,23 @@ public static List<String> getMatchingJobNames(Pattern pattern, int maxJobs) {
439440
return matchingJobNames;
440441
}
441442

443+
/**
444+
* Get all agent names matching the given pattern, viewable to the requesting user
445+
* @param pattern Pattern to match against
446+
* @param maxAgents Max matching agents to look for
447+
* @return List of matching agent names
448+
*/
449+
public static List<String> getMatchingAgentNames(Pattern pattern, int maxAgents) {
450+
List<String> matchingAgentNames = new ArrayList<>();
451+
for (Node node: Jenkins.get().getNodes()) {
452+
if (pattern.matcher(node.getNodeName()).matches()) {
453+
matchingAgentNames.add(node.getNodeName());
454+
if (matchingAgentNames.size() >= maxAgents) break;
455+
}
456+
}
457+
return matchingAgentNames;
458+
}
459+
442460
/**
443461
* The Acl class that will delegate the permission check to the {@link RoleMap} object.
444462
*/

src/main/resources/com/michelin/cio/hudson/plugins/rolestrategy/RoleStrategyConfig/manage-agent-roles.jelly

+63-2
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,8 @@
170170
var child = copy.childNodes[1];
171171
var doubleQuote = '"';
172172
child.innerHTML = escapeHTML(name);
173-
child.next().innerHTML = doubleQuote + escapeHTML(pattern) + doubleQuote;
173+
var patternString = doubleQuote + escapeHTML(pattern) + doubleQuote;
174+
child.next().innerHTML = '<a href="#" class="patternAnchor">' + patternString + '</a>';
174175

175176
var hidden = document.createElement('input');
176177
hidden.setAttribute('name', '[pattern]');
@@ -185,6 +186,10 @@
185186
item.outerHTML = item.outerHTML.replace("{{ROLE}}", doubleEscapeHTML(name)).replace("{{PATTERN}}", doubleEscapeHTML(pattern));
186187
});
187188

189+
child = copy.childNodes[1];
190+
var link = child.next().children[0];
191+
bindAgentListenerToPattern(link);
192+
188193
<j:if test="${nbAgentRoles lt 20}">
189194
table.appendChild(copy);
190195
</j:if>
@@ -196,8 +201,62 @@
196201
});
197202
})();
198203

204+
var bindAgentListenerToPattern = function(elem) {
205+
elem.addEventListener('click', showMatchingAgents);
206+
}
207+
208+
var showMatchingAgents = function() {
209+
var pattern = this.text.substring(1, this.text.length - 1); // Ignore quotes for the pattern
210+
var maxAgents = 10; // Maximum agents to search for
211+
var url = 'strategy/getMatchingAgents';
212+
reqParams = {
213+
'pattern' : pattern,
214+
'maxAgents' : maxAgents
215+
}
216+
217+
new Ajax.Request(url, {
218+
method: 'get',
219+
parameters: reqParams,
220+
onSuccess: function(req) {
221+
var matchingAgents = req.responseText.evalJSON().matchingAgents;
222+
223+
if(matchingAgents != null) {
224+
showAgentsModal(matchingAgents);
225+
} else {
226+
showAgentErrorMessageModal();
227+
}
228+
},
229+
onFailure: showAgentErrorMessageModal
230+
});
231+
}
232+
233+
var showAgentsModal = function(agents) {
234+
modalText = '';
235+
if(agents.length > 0) {
236+
modalText += 'Matching Agents:\n\n';
237+
for(var i = 0; i != agents.length; i++) {
238+
modalText += ' - ' + agents[i] + '\n';
239+
}
240+
} else {
241+
modalText += 'No matching Agents found.';
242+
}
243+
modalText += '\n\n';
244+
alert(modalText);
245+
}
246+
247+
var showAgentErrorMessageModal = function() {
248+
alert('Unable to fetch matching Agents.');
249+
}
250+
199251
Event.observe(window, 'load', function(event) {
200252
agentTableHighlighter = new TableHighlighter('agentRoles', 3, 2);
253+
// Show agents matching a pattern on click
254+
var agentRolesTable = document.getElementById('agentRoles')
255+
var patterns = agentRolesTable.getElementsByClassName('patternAnchor');
256+
for(var i = 0; i != patterns.length; i++) {
257+
bindAgentListenerToPattern(patterns[i]);
258+
}
259+
201260
});
202261

203262
var deleteAgentRole = function(e) {
@@ -217,7 +276,9 @@
217276
this.innerHTML = '<input type="text" name="[pattern]" value="' + this.childNodes[1].value + '" size="' + (this.childNodes[1].value.length+10) + '"/>';
218277
}
219278
else {
220-
this.innerHTML = this.childNodes[0].value.escapeHTML() + '<input type="hidden" name="[pattern]" value="' + this.childNodes[0].value + '"/>';
279+
this.innerHTML = '<a href="#" class="patternAnchor">&quot;' + this.childNodes[0].value.escapeHTML() + '&quot;</a><input type="hidden" name="[pattern]" value="' + this.childNodes[0].value + '"/>';
280+
child = this.children[0];
281+
bindAgentListenerToPattern(this.children[0]);
221282
}
222283
return false;
223284
}

src/main/resources/com/michelin/cio/hudson/plugins/rolestrategy/RoleStrategyConfig/manage-project-roles.jelly

+8-3
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@
126126
</f:entry>
127127
</l:isAdmin>
128128
<script>
129-
var tableHighlighter;
129+
var projecttableHighlighter;
130130
(function() {
131131
<!-- place master outside the DOM tree so that it won't creep into the submitted form -->
132132
var master = document.getElementById('${id}');
@@ -166,7 +166,6 @@
166166
child.innerHTML = escapeHTML(name);
167167
var patternString = doubleQuote + escapeHTML(pattern) + doubleQuote;
168168
child.next().innerHTML = '<a href="#" class="patternAnchor">' + patternString + '</a>';
169-
bindListenerToPattern(child.next().children[0]);
170169

171170
var hidden = document.createElement('input');
172171
hidden.setAttribute('name', '[pattern]');
@@ -179,6 +178,10 @@
179178
item.outerHTML = item.outerHTML.replace("{{ROLE}}", doubleEscapeHTML(name)).replace("{{PATTERN}}", doubleEscapeHTML(pattern));
180179
});
181180

181+
child = copy.childNodes[1];
182+
var link = child.next().children[0];
183+
bindListenerToPattern(link);
184+
182185
copy.setAttribute("name",'['+name+']');
183186
<j:if test="${nbProjectRoles lt 20}">
184187
table.appendChild(copy);
@@ -242,7 +245,8 @@
242245
projecttableHighlighter = new TableHighlighter('projectRoles', 3, 2);
243246

244247
// Show jobs matching a pattern on click
245-
var patterns = document.getElementsByClassName('patternAnchor');
248+
var projectRolesTable = document.getElementById('projectRoles')
249+
var patterns = projectRolesTable.getElementsByClassName('patternAnchor');
246250
for(var i = 0; i != patterns.length; i++) {
247251
bindListenerToPattern(patterns[i]);
248252
}
@@ -266,6 +270,7 @@
266270
}
267271
else {
268272
this.innerHTML = '<a href="#" class="patternAnchor">&quot;' + this.childNodes[0].value.escapeHTML() + '&quot;</a><input type="hidden" name="[pattern]" value="' + this.childNodes[0].value + '"/>';
273+
bindListenerToPattern(this.children[0]);
269274
}
270275
return false;
271276
}

src/main/resources/com/michelin/cio/hudson/plugins/rolestrategy/RoleStrategyConfig/manage-roles.jelly

+1-6
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,7 @@
6363
<j:set var="pattern" value="&lt;br/&gt; &lt;b&gt;Pattern&lt;/b&gt; : ${h.escape(attrs.role.pattern.toString())}"/>
6464
</j:if>
6565
<td width="*" class="in-place-edit">
66-
<j:if test="${attrs.project}">
67-
<a href="#" class="patternAnchor">&quot;${attrs.role.pattern.toString()}&quot;</a>
68-
</j:if>
69-
<j:if test="${!attrs.project}">
70-
&quot;${h.escape(attrs.role.pattern.toString())}&quot;
71-
</j:if>
66+
<a href="#" class="patternAnchor">&quot;${attrs.role.pattern.toString()}&quot;</a>
7267
<input type="hidden" name="[pattern]" value="${attrs.role.pattern}" />
7368
</td>
7469
</j:if>

0 commit comments

Comments
 (0)