Using property/variable value from Jenkins - jenkins

I got stuck to a really annoying issue. Looks pretty simple to solve but I can't see what am I doing wrong.
All started from JMeter: more than nine parameters from Jenkins.
I managed to get the values from Jenkins in Jmeter by spiting an array.
String line = "${__P(jenkinsparams)}";
String[] words = line.split(",");
String looks like:
-Jjenkinsparams="999,999,8443,1433,SQL2012,sa"
So I have:
words[0] = 999;
words[1] = 999;
words[2] = 8443;
[...]
words[5] = sa;
This operation is made inside a BeanShell Sampler with 1 thread. How can I use these values as further on? Even in different Thread Groups.
I've tried:
props.put("SqlIP",words[0]);
props.put("SqlInstance", words[1]);
but ${__P(SqlIP)} doesn't retrieve the value when used in JDBC Connection Configuration as:
jdbc:sqlserver://${__P(SqlIP)}\\${__P(SqlInstance)}
How can I use properties/variables to send data from that array to build an JDBC connection? I need them for: SQL IP, SQL instance, SQL username and SQL password. All sent in that array from Jenkins. Thank you

Because JDBC Connection Configuration is a Configuration element and according to Execution Order it's kicked off before any Beanshell test elements. You will have to come up with another way of setting the value.
I'm not aware of any parameters number limit on JMeter level, if you're running an exotic shell or a form of custom JMeter startup script which introduces this limitation you can work it around by putting your configuration into user.properties file or a custom properties file which can be passed via -q parameter, check out Apache JMeter Properties Customization Guide to learn more about setting and overriding JMeter Properties

Related

JMeter: more than nine parameters from Jenkins

I am trying to pass more than nine parameters from Jenkins to JMeter4.0.
As I was reading, I found out that JMeter does not accept more than 9 parameters. As a workaround, I want to pass all the parameters as a string and split it in JMeter BeanShell.
java -jar -Xms512m -Xmx2048m C:\JMeter4\bin\ApacheJMeter.jar -Jjmeter.save.saveservice.output_format=csv -Jjenkinsparams="%Timetorun%,%Users%" -n -t %JMeterPath%\bin\tests\tests.jmx -l %WORKSPACE%\Results.csv
The tests run on a Windows machine. From this call I have
jenkinsparams = "300,2"
I use a BeanShell PreProcessor like this:
String line = "${__P(jenkinsparams)}";
String[] words = line.split(",");
vars.put("timetorun",words[0]);
vars.put("users",words[1]);
log.info(words[1]);
log.info(users);
I tried few log.info to check the values. For words[1] I have the correct value sent from Jenkins: 2. For the users the value displayed is: void.
I am trying to use it for Number of Threads as: ${__P(users,1)}.
What am I doing wrong? The values clearly arrive from Jenkins but I have a problem passing it to my variable. Thank you
You don't have a script variable named users, so you should either log words[0]:
log.info(words[0]);
Or you can log the value of JMeter variable called users:
log.info(vars.get("users"));
Or you can assign words[0] to variable called users:
String users = words[0];
log.info(users);
Also you are saving it as variable, not property, so you can retrieve it elsewhere in script as
${users}
The syntax __P refers to property, so if you want to use it as property, you need to change how you are saving it:
props.put("users", words[1]);
If you do that, ${__P(users,1)} should work
Now, if you want to use this value as number of threads, then you need to do this:
Have Setup thread group with 1 thread, and your script
In the script you must save users as property, otherwise it won't pass between threads
Next thread group then can use it as number of threads
As long as your command line fits into 8191 characters it should not be a problem to pass as many arguments to JMeter as you want, here is an evidence from Debug Sampler and View Results Tree listener combination
So keep calm and pass as many parameters as needed via -J command line arguments.
Be aware that starting from JMeter version 3.1 users are recommended to use JSR223 Test Elements and Groovy language instead of Beanshell so going forward please consider switching to Groovy.

Dataflow/Beam Templates, Productionization, Initialization, and ValueProviders

I have an Apache Beam job running on Google Cloud Dataflow, and as part of its initialization it needs to run some basic sanity/availability checks on services, pub/sub subscriptions, GCS blobs, etc. It's a streaming pipeline intended to run ad infinitum that processes hundreds of thousands of pub/sub messages.
Currently it needs a whole heap of required, variable parameters: which Google Cloud project it needs to run in, which bucket and directory prefix it's going to be storing files in, which pub/sub subscriptions it needs to read from, and so on. It does some work with these parameters before pipeline.run is called - validation, string splitting, and the like. In its current form in order to start a job we've been passing these parameters to to a PipelineOptionsFactory and issuing a new compile every single time, but it seems like there should be a better way. I've set up the parameters to be ValueProvider objects, but because they're being called outside of pipeline.run, Maven complains at compile time that ValueProvider.get() is being called outside of a runtime context (which, yes, it is.)
I've tried using NestedValueProviders as in the Google "Creating Templates" document, but my IDE complains if I try to use NestedValueProvider.of to return a string as shown in the document. The only way I've been able to get NestedValueProviders to compile is as follows:
NestedValueProvider<String, String> pid = NestedValueProvider.of(
pipelineOptions.getDataflowProjectId(),
(SerializableFunction<String, String>) s -> s
);
(String pid = NestedValueProvider.of(...) results in the following error: "incompatible types: no instance(s) of type variable(s) T,X exist so that org.apache.beam.sdk.options.ValueProvider.NestedValueProvider conforms to java.lang.String")
I have the following in my pipelineOptions:
ValueProvider<String> getDataflowProjectId();
void setDataflowProjectId(ValueProvider<String> value);
Because of the volume of messages we're going to be processing, adding these checks at the front of the pipeline for every message that comes through isn't really practical; we'll hit daily account administrative limits on some of these calls pretty quickly.
Are templates the right approach for what I want to do? How do I go about actually productionizing this? Should (can?) I compile with maven into a jar, then just run the jar on a local dev/qa/prod box with my parameters and just not bother with ValueProviders at all? Or is it possible to provide a default to a ValueProvider and override it as part of the options passed to the template?
Any advice on how to proceed would be most appreciated. Thanks!
The way templates are currently implemented there is no point to perform "post-template creation" but "pre-pipeline start" initialization/validation.
All of the existing validation executes during template creation. If the validation detects that there the values aren't available (due to being a ValueProvider) the validation is skipped.
In some cases it is possible to approximate validation by adding runtime checks either as part of initial splitting of a custom source or part of the #Setup method of a DoFn. In the latter case, the #Setup method will run once for each instance of the DoFn that is created. If the pipeline is Batch, after 4 failures for a specific instance it will fail the pipeline.
Another option for productionizing pipelines is to build the JAR that runs the pipeline, and have a production process that runs that JAR to initiate the pipeline.
Regarding the compile error you received -- the NestedValueProvider returns a ValueProvider -- it isn't possible to get a String out of that. You could, however, put the validation code into the SerializableFunction that is run within the NestedValueProvider.
Although I believe this will currently re-run the validation everytime the value is accessed, it wouldn't be unreasonable to have the NestedValueProvider cache the translated value.

Jmeter : Reading variable from csv and pass it into another varaible

I want to read a variable from CSV and use that value into another variable.
Example:
I have a variable as:
${url}: wwww.$(value_from_csv}.com
and secondary url ${url}/xyz
In my Jmeter script, ${value_from_csv} is not passed.
What I am missing?
Observed that CSV Dataset Config values are not passed (not available) to any of the Config Elements irrespective of the order of the components (Config Elements) in JMeter Test Plan (checked with User Defined Config & MongoDB Source Config), though passed to Samplers.
so, suggested the OP to define the value in jmeter.properties instead of a CSV file, so we can access user.host in MongoDB Source Config.
Steps:
Add user.host=address in jmeter.properties
Restart Jmeter
Add ${__P(user.host,)} in Server Address List field in MongoDB Source Config
Note: In case of running JMeter script from Jenkins, property will be picked by the script, from jmeter.properites file.
MongoDB Source Config is initialized before any JMeter Variables so the only way to make it dynamic is using JMeter Properties instead.
You can set a JMeter Property in 2 ways:
Define it in user.properties file like:
server.address.1=some.ip.or.hostname.1
server.address.2=some.ip.or.hostname.2
Pass the properties via -J command-line arguments like:
jmeter -Jserver.address.1=some.ip.or.hostname.1 -Jserver.address.2=some.ip.or.hostname.2 ....
See Apache JMeter Properties Customization Guide for more information on using JMeter Properties

How to retain Cobertura ratcheted configuration in job-dsl-plugin?

Cobertura plugin in Jenkins has a support of ratcheting by ticking these boxes:
Health auto update
Stability auto update
When ticking this box, the coverage metric targets (in Jenkins configuration page) will be updated on every successful build:
These values will be overridden by job-dsl-plugin when seed job is triggered. How can I retain these values when my seed job is triggered?
Seems like I can't find a pretty way to do this right now, but here is my solution.
Solution
1. Execute a Groovy script and store all of the current job cobertura configuration in a JSON file.
Cobertura configuration can be retrieved like:
def coberturaPublisher = project.getPublishersList().get(CoberturaPublisher)
coberturaPublisher.**healthyTarget**.getTarget(**CoverageMetric.METHOD**)
2. job-dsl-plugin to configure cobertura by using the JSON file if it's available
job-dsl's CoberturaContext normal method can't be called here because the data represented in the first step is different with the method parameter:
80% is stored as 8000000 in the JSON file
80% must be passed in as 80 instead of 8000000 to CoberturaContext methods.
As of today, I can't simply divide the value by 100000 because the method is accepting Integer instead of double. To retain the precision of the ratcheted configuration, I have to bypass the validation by manipulating the target directly:
coberturaContext.targets = [
'METHOD': new CoberturaContext.CoberturaTarget(
targetType: CoberturaContext.TargetType.METHOD,
healthyTarget: 8000000,
unhealthyTarget: previousConfig ? previousConfig.cobertura.method.unhealthy : 0,
failingTarget: previousConfig ? previousConfig.cobertura.method.failing : 0
),
Why bother creating the JSON file while you can call Jenkins API directly?
My seed job is configured with this example here, hence I have an additional classpath used in the job configuration. When I tried to hit Jenkins API directly, I'm getting class loading issue for Cobertura plugin classes.

Jenkins - retrieve full console output during build step

I have been scouring the internet for days, I have a problem similar to this.
I need to retrieve the console output in raw (plain) text. But if I can get it in HTML that is fine too, I can always parse it. The only thing is that I need to get it during the build step, which is a problem since the location where it should be available is truncated...
I have tried retrieving the console output from the following URL's (relative to the job):
/consoleText
/logText/progressiveText
/logText/progressiveHTML
The two text ones are plain text and would be perfect if not for the truncation, same goes for the HTML one... exactly what I need - only its truncated....
I am sure it is possible to retrieve this information somehow, since when viewing /consoleFull there is a real-time update of the console, without truncating or buffering.
However, upon examining that web page, instead of finding the content I desired, I found this code where it should have been (I did not include the full pages code, since it would be mostly irrelevant, and I believe those answering would be able to find out and know what should be there on their own)
new Ajax.Request(href,{
method: "post",
parameters: {"start":e.fetchedBytes},
requestHeaders: headers,
onComplete: function(rsp,_) {
var stickToBottom = scroller.isSticking();
var text = rsp.responseText;
if(text!="") {
var p = document.createElement("DIV");
e.appendChild(p); // Needs to be first for IE
// Use "outerHTML" for IE; workaround for:
// http://www.quirksmode.org/bugreports/archives/2004/11/innerhtml_and_t.html
if (p.outerHTML) {
p.outerHTML = '<pre>'+text+'</pre>';
p = e.lastChild;
}
else p.innerHTML = text;
Behaviour.applySubtree(p);
if(stickToBottom) scroller.scrollToBottom();
}
e.fetchedBytes = rsp.getResponseHeader("X-Text-Size");
e.consoleAnnotator = rsp.getResponseHeader("X-ConsoleAnnotator");
if(rsp.getResponseHeader("X-More-Data")=="true")
setTimeout(function(){fetchNext(e,href);},1000);
else
$("spinner").style.display = "none";
}
});
Specifically, I am hoping there is a way for me to get the content from text whatever it may be. I am not familiar with this language and so am not sure how I might be able to get the content I want. Plugins won't help since I want to retrieve this content as part of my script during the build step
You did pretty much good investigation already. I can only add the following: all console related plug-ins I know are designed as a post build actions.
The Log Trigger plugin provides a post-build action that allows Hudson
builds to search their console log for a given regular expression and
if found, trigger additional downstream jobs.
So it looks like there is no straightforward solution to your problem. I can see the following options:
1. Use tee or something similar (applicable to shell build steps only)
This solution is far from being universal, but it can provide quick access to the latest console output, produced by a command or set of command.
tee - read from standard input and write to standard output and files
Using synonyms on the system level other Jenkins build steps can modified in order to produce console output. File with console output can be referenced through Jenkins or using any other way.
2. Modify Jenkins code
You can just do a quick fix for internal usage or provide a patch introducing specific system-wide setting.
3. Mimic /console behavior
Code in your example is used to request updates from the Jenkins server. As you may expect the server side can return piece of information starting with some offset. Let me show.
Periodically console page sends requests to the server:
Parameters are straightforward:
Response is a chunk of information to be added:
Another request with updated offset (start) value
You can easily understand there is no data by analyzing Content-Length
So the answer is: use url/job-name/build-number/logText/progressiveHtml, specify start offset, send request and receive console update.
I had a similar issue, the last part of my Jenkinsfile build script needs to parse the ConsoleLog for particular error messages to put in an email build report.
First attempt: http request.
It felt like a hack, it mostly worked, but ran into issues when we locked down access to the Jenkins server & my build nodes could no longer perform annon http gets on the page
Second attempt: use the APIs to enumerate the log lines.
It felt like the right thing to do, but it failed horribly as my nodes would take 30 minutes to get through the 100 meg log files. My presumption is that the Jenkins server was not caching the file, so each request involved a re-reading of the entire file up until the point of the last read.
Third and most successful solution: run grep on the server.
node('master') {
sh 'grep some_criteria $JENKINS_HOME/workspace/path/to/job/console.log'
}
it was fast, reliable, and it didn't matter how big the log files were.
Yes, this required trust of the Jenkins admin and knowledge of the directory paths on the Jenkins server - but since I was the admin, I trusted myself to do the right thing. Your mileage may vary.
To add some insight: when the Jenkins build was in progress, the response for the .../consoleText URL maxed out at 10000 lines, exactly.
I was using 'requests()' package in Python. I have tried the same URL with curl and again received only the first 10K lines.
Only after the build has finished both methods returned the full log (>22K lines in my case).
I will research further and hope to report back.
[2015-08-18] Update: It seems that this is a known issue (see here) and it's fixed in Jenkins 1.618 and later. I am still running 1.615 so I cannot verify.
Amir

Resources