Skip to content

Commit b726564

Browse files
Merge branch 'akostadinov-master'
2 parents 113d19c + 0b2402c commit b726564

File tree

17 files changed

+493
-21
lines changed

17 files changed

+493
-21
lines changed

pom.xml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@
2121
<id>repo.jenkins-ci.org</id>
2222
<url>https://repo.jenkins-ci.org/public/</url>
2323
</repository>
24+
<repository>
25+
<!-- FIXME remove! -->
26+
<id>jitpack.io</id>
27+
<url>https://jitpack.io</url>
28+
</repository>
2429
</repositories>
2530

2631
<pluginRepositories>
@@ -151,6 +156,19 @@
151156
<version>1.15</version>
152157
<optional>true</optional>
153158
</dependency>
159+
160+
<dependency>
161+
<groupId>org.jenkins-ci.plugins</groupId>
162+
<artifactId>script-security</artifactId>
163+
<version>1.37</version>
164+
</dependency>
165+
166+
<dependency>
167+
<groupId>javax.validation</groupId>
168+
<artifactId>validation-api</artifactId>
169+
<version>1.0.0.GA</version>
170+
<scope>provided</scope>
171+
</dependency>
154172
</dependencies>
155173

156174
<build>

src/main/java/jenkins/plugins/logstash/LogstashBuildWrapper.java

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,16 @@
3535
import hudson.model.BuildListener;
3636
import hudson.tasks.BuildWrapper;
3737
import hudson.tasks.BuildWrapperDescriptor;
38+
import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript;
39+
40+
import java.io.OutputStream;
41+
42+
import javax.annotation.CheckForNull;
43+
44+
import org.kohsuke.stapler.DataBoundSetter;
3845

3946
/**
47+
* Logstash note on each output line.
4048
*
4149
* This BuildWrapper is only a marker and has no other functionality.
4250
* The {@link LogstashConsoleLogFilter} uses this BuildWrapper to decide if it should send the log to an indexer.
@@ -48,13 +56,21 @@
4856
public class LogstashBuildWrapper extends BuildWrapper
4957
{
5058

59+
@CheckForNull
60+
private SecureGroovyScript secureGroovyScript;
61+
5162
/**
5263
* Create a new {@link LogstashBuildWrapper}.
5364
*/
5465
@DataBoundConstructor
5566
public LogstashBuildWrapper()
5667
{}
5768

69+
@DataBoundSetter
70+
public void setSecureGroovyScript(@CheckForNull SecureGroovyScript script) {
71+
this.secureGroovyScript = script != null ? script.configuringWithNonKeyItem() : null;
72+
}
73+
5874
/**
5975
* {@inheritDoc}
6076
*/
@@ -66,11 +82,26 @@ public Environment setUp(AbstractBuild build, Launcher launcher, BuildListener l
6682
{
6783
};
6884
}
69-
85+
7086
@Override
71-
public DescriptorImpl getDescriptor()
72-
{
73-
return (DescriptorImpl)super.getDescriptor();
87+
public DescriptorImpl getDescriptor() {
88+
return (DescriptorImpl) super.getDescriptor();
89+
}
90+
91+
@CheckForNull
92+
public SecureGroovyScript getSecureGroovyScript() {
93+
// FIXME probbably needs to be moved
94+
return secureGroovyScript;
95+
}
96+
97+
// Method to encapsulate calls for unit-testing
98+
LogstashWriter getLogStashWriter(AbstractBuild<?, ?> build, OutputStream errorStream) {
99+
LogstashScriptProcessor processor = null;
100+
if (secureGroovyScript != null) {
101+
processor = new LogstashScriptProcessor(secureGroovyScript, errorStream);
102+
}
103+
104+
return new LogstashWriter(build, errorStream, null, build.getCharset(), processor);
74105
}
75106

76107
/**

src/main/java/jenkins/plugins/logstash/LogstashInstallation.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ public Descriptor() {
7474
load();
7575
}
7676

77-
7877
@Override
7978
public String getDisplayName() {
8079
return Messages.DisplayName();

src/main/java/jenkins/plugins/logstash/LogstashOutputStream.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
import java.io.IOException;
3131
import java.io.OutputStream;
3232

33+
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
34+
3335
/**
3436
* Output stream that writes each line to the provided delegate output stream
3537
* and also sends it to an indexer for logstash to consume.
@@ -54,6 +56,9 @@ LogstashWriter getLogstashWriter()
5456
}
5557

5658
@Override
59+
@SuppressFBWarnings(
60+
value="DM_DEFAULT_ENCODING",
61+
justification="TODO: not sure how to fix this")
5762
protected void eol(byte[] b, int len) throws IOException {
5863
delegate.write(b, 0, len);
5964
this.flush();
@@ -79,6 +84,7 @@ public void flush() throws IOException {
7984
*/
8085
@Override
8186
public void close() throws IOException {
87+
logstash.close();
8288
delegate.close();
8389
super.close();
8490
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* The MIT License
3+
*
4+
* Copyright 2017 Red Hat inc, and individual contributors
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*/
24+
25+
package jenkins.plugins.logstash;
26+
27+
import net.sf.json.JSONObject;
28+
29+
/**
30+
* Interface describing processors of persisted payload.
31+
*
32+
* @author Aleksandar Kostadinov
33+
* @since 1.4.0
34+
*/
35+
public interface LogstashPayloadProcessor {
36+
/**
37+
* Modifies a JSON payload compatible with the Logstash schema.
38+
*
39+
* @param payload the JSON payload that has been constructed so far.
40+
* @return The formatted JSON object, can be null to ignore this payload.
41+
*/
42+
JSONObject process(JSONObject payload) throws Exception;
43+
44+
/**
45+
* Finalizes any operations, for example returns cashed lines at end of build.
46+
*
47+
* @return A formatted JSON object, can be null when it has nothing.
48+
*/
49+
JSONObject finish() throws Exception;
50+
}
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/*
2+
* The MIT License
3+
*
4+
* Copyright 2017 Red Hat inc. and individual contributors
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*/
24+
25+
package jenkins.plugins.logstash;
26+
27+
import java.io.IOException;
28+
import java.io.OutputStream;
29+
import java.io.PrintWriter;
30+
import java.util.LinkedHashMap;
31+
32+
import javax.annotation.Nonnull;
33+
34+
import groovy.lang.Binding;
35+
36+
import net.sf.json.JSONObject;
37+
38+
import jenkins.model.Jenkins;
39+
import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript;
40+
import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.Whitelisted;
41+
42+
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
43+
44+
/**
45+
* This class is handling custom groovy script processing of JSON payload.
46+
* Each call to process executes the script provided in job configuration.
47+
* Script is executed under the same binding each time so that it has ability
48+
* to persist data during build execution if desired by script author.
49+
* When build is finished, script will receive null as the payload and can
50+
* return any cached but non-sent data back for persisting.
51+
* The return value of script is the payload to be persisted unless null.
52+
*
53+
* @author Aleksandar Kostadinov
54+
* @since 1.4.0
55+
*/
56+
public class LogstashScriptProcessor implements LogstashPayloadProcessor{
57+
@Nonnull
58+
private final SecureGroovyScript script;
59+
60+
@Nonnull
61+
private final OutputStream consoleOut;
62+
63+
/** Groovy binding for script execution */
64+
@Nonnull
65+
private final Binding binding;
66+
67+
/** Classloader for script execution */
68+
@Nonnull
69+
private final ClassLoader classLoader;
70+
71+
public LogstashScriptProcessor(SecureGroovyScript script, OutputStream consoleOut) {
72+
this.script = script;
73+
this.consoleOut = consoleOut;
74+
75+
// TODO: should we put variables in the binding like manager, job, etc.?
76+
binding = new Binding();
77+
binding.setVariable("console", new BuildConsoleWrapper());
78+
79+
// not sure what the diff is compared to getClass().getClassLoader();
80+
final Jenkins jenkins = Jenkins.getInstance();
81+
classLoader = jenkins.getPluginManager().uberClassLoader;
82+
}
83+
84+
/**
85+
* Helper method to allow logging to build console.
86+
*/
87+
@SuppressFBWarnings(
88+
value="DM_DEFAULT_ENCODING",
89+
justification="TODO: not sure how to fix this")
90+
private void buildLogPrintln(Object o) throws IOException {
91+
consoleOut.write(o.toString().getBytes());
92+
consoleOut.write("\n".getBytes());
93+
consoleOut.flush();
94+
}
95+
96+
/*
97+
* good examples in:
98+
* https://github.com/jenkinsci/envinject-plugin/blob/master/src/main/java/org/jenkinsci/plugins/envinject/service/EnvInjectEnvVars.java
99+
* https://github.com/jenkinsci/groovy-postbuild-plugin/pull/11/files
100+
*/
101+
@Override
102+
public JSONObject process(JSONObject payload) throws Exception {
103+
binding.setVariable("payload", payload);
104+
script.evaluate(classLoader, binding);
105+
return (JSONObject) binding.getVariable("payload");
106+
}
107+
108+
@Override
109+
public JSONObject finish() throws Exception {
110+
buildLogPrintln("Tearing down Script Log Processor..");
111+
return process(null);
112+
}
113+
114+
/**
115+
* Helper to allow access from sandboxed script to output messages to console.
116+
*/
117+
private class BuildConsoleWrapper {
118+
@Whitelisted
119+
public void println(Object o) throws IOException {
120+
buildLogPrintln(o);
121+
}
122+
}
123+
}

0 commit comments

Comments
 (0)