Skip to content

Commit 4eda409

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

File tree

17 files changed

+522
-17
lines changed

17 files changed

+522
-17
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>com.github.akostadinov</groupId>
162+
<artifactId>script-security-plugin</artifactId>
163+
<version>master-SNAPSHOT</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: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,27 @@
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+
41+
import java.io.IOException;
42+
import java.io.OutputStream;
43+
import java.util.ArrayList;
44+
import java.util.List;
45+
46+
import javax.annotation.CheckForNull;
47+
48+
import groovy.lang.Binding;
49+
50+
import org.kohsuke.stapler.DataBoundConstructor;
51+
import org.kohsuke.stapler.DataBoundSetter;
52+
53+
import com.michelin.cio.hudson.plugins.maskpasswords.MaskPasswordsBuildWrapper;
54+
import com.michelin.cio.hudson.plugins.maskpasswords.MaskPasswordsBuildWrapper.VarPasswordPair;
55+
import com.michelin.cio.hudson.plugins.maskpasswords.MaskPasswordsConfig;
3856

3957
/**
58+
* Logstash note on each output line.
4059
*
4160
* This BuildWrapper is only a marker and has no other functionality.
4261
* The {@link LogstashConsoleLogFilter} uses this BuildWrapper to decide if it should send the log to an indexer.
@@ -48,13 +67,21 @@
4867
public class LogstashBuildWrapper extends BuildWrapper
4968
{
5069

70+
@CheckForNull
71+
private SecureGroovyScript secureGroovyScript;
72+
5173
/**
5274
* Create a new {@link LogstashBuildWrapper}.
5375
*/
5476
@DataBoundConstructor
5577
public LogstashBuildWrapper()
5678
{}
5779

80+
@DataBoundSetter
81+
public void setSecureGroovyScript(@CheckForNull SecureGroovyScript script) {
82+
this.secureGroovyScript = script != null ? script.configuringWithNonKeyItem() : null;
83+
}
84+
5885
/**
5986
* {@inheritDoc}
6087
*/
@@ -72,6 +99,27 @@ public DescriptorImpl getDescriptor()
7299
{
73100
return (DescriptorImpl)super.getDescriptor();
74101
}
102+
103+
@Override
104+
public DescriptorImpl getDescriptor() {
105+
return (DescriptorImpl) super.getDescriptor();
106+
}
107+
108+
@CheckForNull
109+
public SecureGroovyScript getSecureGroovyScript() {
110+
// FIXME probbably needs to be moved
111+
return secureGroovyScript;
112+
}
113+
114+
// Method to encapsulate calls for unit-testing
115+
LogstashWriter getLogStashWriter(AbstractBuild<?, ?> build, OutputStream errorStream) {
116+
LogstashScriptProcessor processor = null;
117+
if (secureGroovyScript != null) {
118+
processor = new LogstashScriptProcessor(secureGroovyScript, errorStream);
119+
}
120+
121+
return new LogstashWriter(build, errorStream, null, build.getCharset(), processor);
122+
}
75123

76124
/**
77125
* Registers {@link LogstashBuildWrapper} as a {@link BuildWrapper}.

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

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

77+
<<<<<<< HEAD
78+
=======
79+
@Override
80+
public boolean configure(StaplerRequest req, JSONObject formData) throws FormException {
81+
req.bindJSON(this, formData.getJSONObject("logstash"));
82+
save();
83+
return super.configure(req, formData);
84+
}
85+
86+
@Override
87+
@SuppressFBWarnings(
88+
value="NP_PARAMETER_MUST_BE_NONNULL_BUT_MARKED_AS_NULLABLE",
89+
justification="TODO: investigate")
90+
public ToolInstallation newInstance(StaplerRequest req, JSONObject formData) throws FormException {
91+
req.bindJSON(this, formData.getJSONObject("logstash"));
92+
save();
93+
return super.newInstance(req, formData);
94+
}
95+
>>>>>>> akostadinov-master
7796

7897
@Override
7998
public String getDisplayName() {

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)