Jenkins/Hudson CLI API to modify the node labels using Groovy - java

Does anyone know how to modify the Jenkins/Hudson node labels in a non-manually way? I mean, thorough an API like the CLI API that this tool offers (without restarting Jenkins/Hudson of course).
My guess is that the best option is using a Groovy script to enter into the Jenkins/Hudson guts. Executing something like:
java -jar -s HUDSON_URL:8080 groovy /path/to/groovy.groovy
Being the content of that script something like:
for (aSlave in hudson.model.Hudson.instance.slaves) {
labels = aSlave.getAssignedLabels()
println labels
**aSlave.setLabel("blabla")** // this method doesn't exist, is there any other way???
}
Thanks in advance!
Victor

Note: the other answers are a bit old, so it could be that the API has appeared since then.
Node labels are accessed in the API as a single string, just like in the Configure screen.
To read and write labels: Node.getLabelString() and Node.setLabelString(String).
Note that you can get the effective labels as well via: Node.getAssignedLabels(), which returns a Collection of LabelAtom that includes dynamically computed labels such as the 'self-label' (representing the node name itself).
Last, these methods on the Node class are directly accessible from the slave objects also, e.g. as a System Groovy Script:
hudson = hudson.model.Hudson.instance
hudson.slaves.findAll { it.nodeName.equals("slave4") }.each { slave ->
print "Slave $slave.nodeName : Labels: $slave.labelString"
slave.labelString = slave.labelString + " " + "offline"
println " --> New labels: $slave.labelString"
}
hudson.save()

I've found a way to do this using the Groovy Postbuild Plugin.
I have a Jenkins job that takes a few parameters (NodeToUpdate, LabelName, DesiredState) and executes this content in the Groovy Postbuild Plugin:
nodeName = manager.envVars['NodeToUpdate']
labelName = manager.envVars['LabelName']
set = manager.envVars['DesiredState']
for (node in jenkins.model.Jenkins.instance.nodes) {
if (node.getNodeName().equals(nodeName)) {
manager.listener.logger.println("Found node to update: " + nodeName)
oldLabelString = node.getLabelString()
if (set.equals('true')) {
if (!oldLabelString.contains(labelName)) {
manager.listener.logger.println("Adding label '" + labelName + "' from node " + nodeName);
newLabelString = oldLabelString + " " + labelName
node.setLabelString(newLabelString)
node.save()
} else {
manager.listener.logger.println("Label '" + labelName + "' already exists on node " + nodeName)
}
}
else {
if (oldLabelString.contains(labelName)) {
manager.listener.logger.println("Removing label '" + labelName + "' from node " + nodeName)
newLabelString = oldLabelString.replaceAll(labelName, "")
node.setLabelString(newLabelString)
node.save()
} else {
manager.listener.logger.println("Label '" + labelName + "' doesn't exist on node " + nodeName)
}
}
}
}

I've not seen a way yet to change the slave label either.
I've taken to editing the main config.xml file and issuing a reload from the CLI.
This has it's own problems though - any jobs currently running are lost until the next jenkins restart - see https://issues.jenkins-ci.org/browse/JENKINS-3265

Related

Bukkit; How to trigger multiple ClickEvent RUN_COMMAND actions with a single click on a single chat message

I've written a rather simple method for my paper/spigot Minecraft server plugin that detects potential lag machines under construction.
The issue I have is that I want to send a single chat message that, when clicked once, will first run a /vanish command on behalf of the clicker.
Then if (and only if) the vanish was successful, I want to run a teleport command to a location included along with the specific instance of the ClickEvent.
Both of those commands need to be completed from the single user click event.
For reference here is the method that calls notifyOps() and includes the TextComponent in question, msg
if (LagMats.contains(blockType) || mat.contains("MINECART") || mat.contains("DOOR")) {
int counter = 0;
for (Material thisMat: LagMats) {
if (thisMat != Material.GRAVEL) {
counter += Utilities.blockCounter(block.getChunk(), thisMat);
}
}
TextComponent warn = new TextComponent("WARN "); warn.setBold(true);
warn.setColor(ChatColor.RED);
TextComponent msg = new TextComponent("Potential lag-machine at " +
block.getX() + ", " + block.getY() + ", " + block.getZ() + " in " + dimension +
" by " + placer_name + " with UUID: " + placer.getUniqueId());
String cmd = "/execute in " + env + " run tp #s " +
block.getX() + " " + block.getY() + " " + block.getZ();
msg.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, cmd));
if (counter > 256) {
Utilities.notifyOps(new TextComponent(warn, msg));
}
}
Oh and the actual little code of notifyOps where the TextComponent is used in a message:
// send a message to all online ops and console
public static boolean notifyOps(TextComponent msg) {
if (msg == null) return false;
for (Player thisPlayer: Bukkit.getOnlinePlayers()) {
try {
if (thisPlayer.isOp()) thisPlayer.spigot().sendMessage(msg);
} catch (Exception e) {return false;}
}
System.out.println(msg.getText());
return true;
}
So I want to have the user click just once, run two commands, the second only if the first succeeds, and would be best if it could be done within the try block the message is sent from.
I could write a custom command for this purpose, and then just run that command, but I rather avoid adding classes for such a small addition if it's actually possible and I just have no idea.
Thanks for any advice or help!
There is no way of doing that without writing a custom command...
This is impossible because the ClickEvent and HoverEvent are entirely client-side. That means that there are no packets sent from the Player to the server. Therefore, it is impossible to callback the click of the Player and call a method to perform what you are trying to do.
You may notice that all the ClickEvent.Actions do not affect the server. OPEN_URL, OPEN_FILE, RUN_COMMAND, SUGGEST_COMMAND, CHANGE_PAGE and COPY_TO_CLIPBOARD are all actions taken on the client-side.
The only way here is to make the client send a command to the server which will trigger a method.

Clone PR using java program or JGIT

I wanted to clone a specific pull request using java JGit API. Does anyone have an idea about it? Or any alternate way to clone Pull request using java program.
Let's consider below is the code to checkout or clone PR from GitHub,
1: git clone https://github.com/deepak-kumbhar/spring-boot-logging-example.git
2. cd PROJECT_NAME
3. git fetch origin pull/1/head:pr-1 (Where 1 is number or PR)
4. git checkout pr-1 (To activate the PR)
The same functionality I want using JGit. Does anyone have an idea about it?
Thanks in advance!
You can do this as described at https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/checking-out-pull-requests-locally
The basic steps for pulling PR #6 from https://github.com/github/testrepo/pull/6/commits are
System.out.println("Cloning from " + REMOTE_URL + " to " + localPath);
try (Git result = Git.cloneRepository()
.setURI(REMOTE_URL)
.setDirectory(localPath)
.setProgressMonitor(new SimpleProgressMonitor())
.call()) {
// Note: the call() returns an opened repository already which needs to be closed to avoid file handle leaks!
System.out.println("Having repository: " + result.getRepository().getDirectory());
FetchResult fetchResult = result.fetch()
.setRemote(REMOTE_URL)
.setRefSpecs("+refs/pull/6/head:pr_6")
.call();
System.out.println("Result when fetching the PR: " + fetchResult.getMessages());
Ref checkoutRef = result.checkout()
.setName("pr_6")
.call();
System.out.println("Checked out PR, now printing log, it should include two commits from the PR on top");
Iterable<RevCommit> logs = result.log()
.call();
for (RevCommit rev : logs) {
System.out.println("Commit: " + rev /* + ", name: " + rev.getName() + ", id: " + rev.getId().getName() */);
}
}
See the ready-to-run snippet at https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/CheckoutGitHubPullRequest.java

java.lang.NullPointerException trying to get specific values from hashmap

I've spent several frustrating days on this now and would appreciate some help. I have a Java agent in Lotus Domino 8.5.3 which is activated by a cgi:POST from my Lotusscript validation agent which is checking that customer has filled in the Billing and delivery address form. This is the code that parses the incoming data into a HashMap where field names are mapped to their respective values.
HashMap hmParam = new HashMap(); //Our Hashmap for request_content data
//Grab transaction parameters from form that called agent (CGI: request_content)
if (contentDecoded != null) {
String[] arrParam = contentDecoded.split("&");
for(int i=0; i < arrParam.length; i++) {
int n = arrParam[i].indexOf("=");
String paramName = arrParam[i].substring(0, n);
String paramValue = arrParam[i].substring(n + 1, arrParam[i].length());
hmParam.put(paramName, paramValue); //Old HashMap
if (paramName.equalsIgnoreCase("transaction_id")) {
transactionID = paramValue;
description = "Order " + transactionID + " from Fareham Wine Cellar";
//System.out.println("OrderID = " + transactionID);
}
if (paramName.equalsIgnoreCase("amount")) {
orderTotal = paramValue;
}
if (paramName.equalsIgnoreCase("deliveryCharge")) {
shipping = paramValue;
}
}
}
The block of code above dates back over a year to my original integration of shopping cart to Barclays EPDQ payment gateway. In that agent I recover the specific values and build a form that is then submitted to EPDQ CPI later on in the agent like this;
out.print("<input type=\"hidden\" name=\"shipping\" value=\"");
out.println(hmParam.get("shipping") + "\">");
I want to do exactly the same thing here, except when I try the agent crashes with a null pointer exception. I can successfully iterate through the hashMap with the snippet below, so I know the data is present, but I can't understand why I can't use myHashMap.Get(key) to get each field value in the order I want them for the html form. The original agent in another application is still in use so what is going on? The data too is essentially unchanged String fieldnames mapped to String values.
Iterator it = cgiData.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pairs = (Map.Entry)it.next();
out.println("<br />" + pairs.getKey() + " = " + pairs.getValue());
//System.out.println(pairs.getKey() + " = " + pairs.getValue());
}
I did two things that may have had an impact, in the process of trying to debug what was going on I needed these further imports;
import java.util.Iterator;
import java.util.Map;
Although I'm not iterating over the hashMap, I've left them in in case which gives me the option of dumping the hashMap out to my system audit trail when application is in production. In variations of the snippet below after it started working I was able to get to any of the data I needed, even if the value was Null, and toString() also seemed to be optional again, as it made no difference to the output.
String cgiValue = "";
cgiValue = hmParam.get("ship_to_lastname").toString();
out.println("<br />Lastname: " + cgiValue);
out.println("<br />Company name: " + hmParam.get("bill_to_company"));
out.println("<br />First name: " + hmParam.get("ship_to_firstname"));
The second thing I did, while trying to get code to work was I enabled the option "Compile Java code with debugging information" for the agent, this may have done something to the way the project was built within the Domino Developer client.
I think I have to put this down to some sort of internal error created when Domino Designer compiled the code. I had a major crash last night while working on this which necessitated a cold boot of my laptop. You also may find that when using Domino Designer 8.5.x that strange things can happen if you don't completely close down all the tasks from time to time with KillNotes

SVN log using SVNKit

I'm sure this question will be silly or annoying on multiple levels....
I am using SVNKit in Java.
I want to get the list of files committed in a particular commit. I have the release ID. Normally I would run something like
svn log url/to/repository -qv -r12345
And I would get the list of commands as normal.
I can't puzzle out how to do a similar thing in SVNKit. Any tips? :)
final SvnOperationFactory svnOperationFactory = new SvnOperationFactory();
final SvnLog log = svnOperationFactory.createLog();
log.setSingleTarget(SvnTarget.fromURL(url));
log.addRange(SvnRevisionRange.create(SVNRevision.create(12345), SVNRevision.create(12345)));
log.setDiscoverChangedPaths(true);
final SVNLogEntry logEntry = log.run();
final Map<String,SVNLogEntryPath> changedPaths = logEntry.getChangedPaths();
for (Map.Entry<String, SVNLogEntryPath> entry : changedPaths.entrySet()) {
final SVNLogEntryPath svnLogEntryPath = entry.getValue();
System.out.println(svnLogEntryPath.getType() + " " + svnLogEntryPath.getPath() +
(svnLogEntryPath.getCopyPath() == null ?
"" : (" from " + svnLogEntryPath.getCopyPath() + ":" + svnLogEntryPath.getCopyRevision())));
}
If you want to run one log request for a revision range, you should use log.setReceiver() call with your receiver implemetation.

Automatically opening pages on different monitors

I am designing an emergency response page, which needs to display information across 3 different monitors. The first monitor will gather information about the caller, and then contain 2 links. The first link needs to display a different web page on the 2nd monitor, and the 2nd link needs to display a different web page on the 3rd monitor.
Is this possible?
Thanks for any help
The first link needs to display a different web page on the 2nd monitor, and the 2nd link needs to display a different web page on the 3rd monitor.
While, depending on your operating system, it is possible to control where a window appears, there are much fewer options for doing this using javascript / serverside code over HTTP / browsers.
The only sensible way to achieve this is by configuring the displays to be tiles of a larger display rather than independent screens (for *nix/BSD/Linux, check out xinerama).
The code below saves the size of a window - and would only need some simple changes to support x/y offset and multiple windows - I leave it to you as to how you differentiate between the windows.
A simpler approach would be to just have one huge window with frames whose borders align with the monitors.
if (document.getElementById && !document.all) { // NOT for MSIE
stickySizeOverloadOnload(stickySizeSetWindowSize);
stickySizeOverloadOnresize(stickySizeSaveWindowSize);
}
function stickySizeSaveWindowSize(event)
{
var expiry = new Date();
var path = document.location.pathname;
expiry.setDate(expiry.getDate()+500);
stickySizeSetCookie('windowSize', window.outerWidth + ',' + window.outerHeight, expiry, path);
}
function stickySizeSetWindowSize()
{
var saved=stickySizeGetCookie('windowSize');
var parts=new Array();
if (saved.length) {
parts = saved.split(',');
if ((parts[0]>100) && (parts[1]>100)) {
window.outerWidth=parts[0];
window.outerHeight=parts[1];
} else {
alert("invalid size - '" + saved + "'");
stickySizeDeleteCookie('windowSize');
}
}
}
function stickySizeOverloadOnload(func)
{
var oldhandler=window.onload;
if (typeof window.onload != "function") {
window.onload=func;
} else {
window.onload=function(event) {
oldhandler(event);
func(event);
}
}
}
function stickySizeOverloadOnresize(func)
{
var oldhandler=window.onresize;
if (typeof window.onresize != "function") {
window.onresize=func;
} else {
window.onresize=function(event) {
oldhandler(event);
func(event);
}
}
}
function stickySizeSetCookie(name, value, expires, path, domain, secure) {
var curCookie = name + "=" + escape(value) +
((expires) ? "; expires=" + expires.toGMTString() : "") +
((path) ? "; path=" + path : "") +
((domain) ? "; domain=" + domain : "") +
((secure) ? "; secure" : "");
document.cookie = curCookie;
}
function stickySizeGetCookie(name) {
var dc = document.cookie;
var prefix = name + "=";
var begin = dc.indexOf("; " + prefix);
if (begin == -1) {
begin = dc.indexOf(prefix);
if (begin != 0) return null;
} else
begin += 2;
var end = document.cookie.indexOf(";", begin);
if (end == -1)
end = dc.length;
return unescape(dc.substring(begin + prefix.length, end));
}
function stickySizeDeleteCookie(name, path, domain) {
if (stickySizeGetCookie(name)) {
document.cookie = name + "=" +
((path) ? "; path=" + path : "") +
((domain) ? "; domain=" + domain : "") +
"; expires=Thu, 01-Jan-70 00:00:01 GMT";
}
}
You can open the links in a different window with the attribute target="windowName".
You have to set up the three windows manually, so assign them manually to the three screens. When you open a link again in a window it is still on the same screen.
Have a look at Java: Getting resolutions of one/all available monitors (instead of the whole desktop)?
(The answer discuss the GraphicsEnvironment.getLocalGraphicsEnvironment() call)
If you really want the windows to be locked to a specific monitor, you will need to implement this client side. Here is a link describing how to detect which monitor a window is on in Java, so you can move it to the proper monitor and maximize the window if you desire. Obviously you can implement the rest of the system server side and just display pages inside the windows you have created.

Categories

Resources