Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add validation to include/exlude jobs regular expressions #450

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docker/controller-node/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,4 @@ RUN cat /tmp/jenkins-casc.yaml | envsubst > /var/jenkins_home/casc/jenkins-casc.

RUN mkdir -p /var/jenkins_home/shared
RUN mkdir -p /var/jenkins_home/plugins
ENV JAVA_OPTS="-Djenkins.install.runSetupWizard=false -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5055"
ENV JAVA_OPTS="-Djenkins.install.runSetupWizard=false -XX:+PrintConcurrentLocks -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5055"
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

package org.datadog.jenkins.plugins.datadog;

import static org.datadog.jenkins.plugins.datadog.configuration.DatadogAgentConfiguration.DatadogAgentConfigurationDescriptor.*;
import static org.datadog.jenkins.plugins.datadog.configuration.DatadogAgentConfiguration.DatadogAgentConfigurationDescriptor.getDefaultAgentHost;
import static org.datadog.jenkins.plugins.datadog.configuration.DatadogAgentConfiguration.DatadogAgentConfigurationDescriptor.getDefaultAgentLogCollectionPort;
import static org.datadog.jenkins.plugins.datadog.configuration.DatadogAgentConfiguration.DatadogAgentConfigurationDescriptor.getDefaultAgentPort;
Expand All @@ -44,14 +45,19 @@
import hudson.util.XStream2;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import jenkins.model.GlobalConfiguration;
import jenkins.model.Jenkins;
import net.sf.json.JSONObject;
Expand All @@ -66,6 +72,7 @@
import org.datadog.jenkins.plugins.datadog.configuration.api.key.DatadogCredentialsApiKey;
import org.datadog.jenkins.plugins.datadog.configuration.api.key.DatadogTextApiKey;
import org.datadog.jenkins.plugins.datadog.util.SuppressFBWarnings;
import org.datadog.jenkins.plugins.datadog.util.conversion.PatternListConverter;
import org.datadog.jenkins.plugins.datadog.util.conversion.PolymorphicReflectionConverter;
import org.kohsuke.stapler.*;
import org.kohsuke.stapler.DataBoundConstructor;
Expand Down Expand Up @@ -135,10 +142,15 @@

@XStreamConverter(PolymorphicReflectionConverter.class)
private DatadogClientConfiguration datadogClientConfiguration;

@XStreamConverter(PatternListConverter.class)
private List<Pattern> excluded = null;

@XStreamConverter(PatternListConverter.class)
private List<Pattern> included = null;

private String ciInstanceName = DEFAULT_CI_INSTANCE_NAME;
private String hostname = null;
private String excluded = null;
private String included = null;
private String globalTagFile = null;
private String globalTags = null;
private String globalJobTags = null;
Expand Down Expand Up @@ -221,25 +233,25 @@
}

String excludedEnvVar = System.getenv(EXCLUDED_PROPERTY);
if(StringUtils.isBlank(excludedEnvVar)){
if (StringUtils.isNotBlank(excludedEnvVar)) {
this.excluded = DatadogUtilities.cstrToList(excludedEnvVar, Pattern::compile);
} else {
// backwards compatibility
excludedEnvVar = System.getenv(BLACKLIST_PROPERTY);
if(StringUtils.isNotBlank(excludedEnvVar)){
this.excluded = excludedEnvVar;
this.excluded = DatadogUtilities.cstrToList(excludedEnvVar, Pattern::compile);
}
} else {
this.excluded = excludedEnvVar;
}

String includedEnvVar = System.getenv(INCLUDED_PROPERTY);
if(StringUtils.isBlank(includedEnvVar)){
if (StringUtils.isNotBlank(includedEnvVar)) {
this.included = DatadogUtilities.cstrToList(excludedEnvVar, Pattern::compile);
} else {
// backwards compatibility
includedEnvVar = System.getenv(WHITELIST_PROPERTY);
if(StringUtils.isNotBlank(includedEnvVar)){
this.included = includedEnvVar;
this.included = DatadogUtilities.cstrToList(excludedEnvVar, Pattern::compile);
}
} else {
this.included = includedEnvVar;
}

String globalTagFileEnvVar = System.getenv(GLOBAL_TAG_FILE_PROPERTY);
Expand Down Expand Up @@ -357,6 +369,28 @@
return FormValidation.ok();
}

@RequirePOST
public FormValidation doCheckIncluded(@QueryParameter("included") final String included) {

Check warning

Code scanning / Jenkins Security Scan

Stapler: Missing permission check Warning

Potential missing permission check in DatadogGlobalConfiguration#doCheckIncluded
return doCheckPatterns(included);
}

@RequirePOST
public FormValidation doCheckExcluded(@QueryParameter("excluded") final String excluded) {

Check warning

Code scanning / Jenkins Security Scan

Stapler: Missing permission check Warning

Potential missing permission check in DatadogGlobalConfiguration#doCheckExcluded
return doCheckPatterns(excluded);
}

private static FormValidation doCheckPatterns(String commaSeparatedPatterns) {
List<String> patterns = DatadogUtilities.cstrToList(commaSeparatedPatterns);
for (String pattern : patterns) {
try {
Pattern.compile(pattern);
} catch (PatternSyntaxException e) {
return FormValidation.error(pattern + " is not a valid regular expression");
}
}
return FormValidation.ok();
}

/**
* Indicates if this builder can be used with all kinds of project types.
*
Expand Down Expand Up @@ -426,8 +460,23 @@
}

setHostname(formData.getString("hostname"));
setExcluded(formData.getString("excluded"));
setIncluded(formData.getString("included"));

String excludedFormData = formData.getString("excluded");
FormValidation excludedValidation = doCheckExcluded(excludedFormData);
if (excludedValidation.kind == Kind.ERROR) {
throw new FormException(excludedValidation.getMessage(), "excluded");
} else {
setExcluded(excludedFormData);
}

String includedFormData = formData.getString("included");
FormValidation includedValidation = doCheckIncluded(includedFormData);
if (includedValidation.kind == Kind.ERROR) {
throw new FormException(includedValidation.getMessage(), "included");
} else {
setIncluded(includedFormData);
}

setGlobalTagFile(formData.getString("globalTagFile"));
setGlobalTags(formData.getString("globalTags"));
setGlobalJobTags(formData.getString("globalJobTags"));
Expand All @@ -440,7 +489,6 @@
String includeEvents = formData.getString("includeEvents");
String excludeEvents = formData.getString("excludeEvents");
FormValidation configStatus = validateEventFilteringConfig(emitSecurityEvents, emitSystemEvents, includeEvents, excludeEvents);

if (configStatus.kind == Kind.ERROR) {
String message = configStatus.getMessage();
String formField = !message.contains("included") ? "excludeEvents" : "includeEvents";
Expand Down Expand Up @@ -515,14 +563,27 @@
this.hostname = hostname;
}

public boolean isJobExcluded(@Nonnull final String jobName) {
if (excluded == null || excluded.isEmpty()) {
return false;
}
for (Pattern pattern : excluded) {
Matcher matcher = pattern.matcher(jobName);
if (matcher.matches()) {
return true;
}
}
return false;
}

/**
* Getter function for the excluded global configuration, containing
* a comma-separated list of jobs to exclude from monitoring.
*
* @return a String array containing the excluded global configuration.
*/
public String getExcluded() {
return excluded;
return DatadogUtilities.listToCstr(excluded, Pattern::toString);
}

/**
Expand All @@ -532,7 +593,20 @@
* @param jobs - a comma-separated list of jobs to exclude from monitoring.
*/
public void setExcluded(final String jobs) {
this.excluded = jobs;
this.excluded = DatadogUtilities.cstrToList(jobs, Pattern::compile);
}

public boolean isJobIncluded(@Nonnull final String jobName) {
if (included == null || included.isEmpty()) {
return true;
}
for (Pattern pattern : included) {
Matcher matcher = pattern.matcher(jobName);
if (matcher.matches()) {
return true;
}
}
return false;
}

/**
Expand All @@ -542,7 +616,7 @@
* @return a String array containing the included global configuration.
*/
public String getIncluded() {
return included;
return DatadogUtilities.listToCstr(included, Pattern::toString);
}

/**
Expand All @@ -552,7 +626,7 @@
* @param jobs - a comma-separated list of jobs to include for monitoring.
*/
public void setIncluded(final String jobs) {
this.included = jobs;
this.included = DatadogUtilities.cstrToList(jobs, Pattern::compile);
}

/**
Expand Down Expand Up @@ -1014,13 +1088,13 @@
/** @deprecated use {@link #getExcluded()} */
@Deprecated
public String getBlacklist() {
return excluded;
return DatadogUtilities.listToCstr(excluded, Pattern::toString);
}

/** @deprecated use {@link #getIncluded()} */
@Deprecated
public String getWhitelist() {
return included;
return DatadogUtilities.listToCstr(included, Pattern::toString);
}

/** @deprecated use {@link #getEnableCiVisibility()} */
Expand Down Expand Up @@ -1161,10 +1235,10 @@
this.ciInstanceName = this.traceServiceName;
}
if (StringUtils.isNotBlank(this.blacklist)) {
this.excluded = this.blacklist;
this.excluded = DatadogUtilities.cstrToList(this.blacklist, Pattern::compile);
}
if (StringUtils.isNotBlank(this.whitelist)) {
this.included = this.whitelist;
this.included = DatadogUtilities.cstrToList(this.whitelist, Pattern::compile);
}
if (DATADOG_AGENT_CLIENT_TYPE.equals(reportWith)) {
this.datadogClientConfiguration = new DatadogAgentConfiguration(this.targetHost, this.targetPort, this.targetLogCollectionPort, this.targetTraceCollectionPort);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -364,17 +364,7 @@ private static boolean isJobExcluded(@Nonnull final String jobName) {
if (datadogGlobalConfig == null) {
return false;
}
final String excludedProp = datadogGlobalConfig.getExcluded();
List<String> excluded = cstrToList(excludedProp);
for (String excludedJob : excluded) {
Pattern excludedJobPattern = Pattern.compile(excludedJob);
Matcher jobNameMatcher = excludedJobPattern.matcher(jobName);
if (jobNameMatcher.matches()) {
return true;
}
}
return false;

return datadogGlobalConfig.isJobExcluded(jobName);
}

/**
Expand All @@ -388,16 +378,7 @@ private static boolean isJobIncluded(@Nonnull final String jobName) {
if (datadogGlobalConfig == null) {
return true;
}
final String includedProp = datadogGlobalConfig.getIncluded();
final List<String> included = cstrToList(includedProp);
for (String includedJob : included) {
Pattern includedJobPattern = Pattern.compile(includedJob);
Matcher jobNameMatcher = includedJobPattern.matcher(jobName);
if (jobNameMatcher.matches()) {
return true;
}
}
return included.isEmpty();
return datadogGlobalConfig.isJobIncluded(jobName);
}

/**
Expand All @@ -410,6 +391,23 @@ public static List<String> cstrToList(final String str) {
return convertRegexStringToList(str, ",");
}

/**
* Converts a comma-separated string into a list
*
* @param str - A string containing a comma separated list of items.
* @param converter - Converter function that is applied to every list element
*/
public static <T> List<T> cstrToList(String str, Function<String, T> converter) {
return convertRegexStringToList(str, ",").stream().map(converter).collect(Collectors.toList());
}

/**
* Converts a list to a comma-separated string
*/
public static <T> String listToCstr(List<T> list, Function<T, String> converter) {
return list != null ? list.stream().map(converter).collect(Collectors.joining(",")) : null;
}

/**
* Converts a string List into a List Object
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ public Descriptor<DatadogClientConfiguration> getDescriptor() {
}

@Extension
public static final class DatadogApiConfigurationDescriptor extends DatadogClientConfigurationDescriptor {
public static final class DatadogApiConfigurationDescriptor extends DatadogClientConfiguration.DatadogClientConfigurationDescriptor {
public DatadogApiConfigurationDescriptor() {
load();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public Descriptor<DatadogIntake> getDescriptor() {
}

@Extension
public static final class DatadogIntakeSiteDescriptor extends DatadogIntakeDescriptor {
public static final class DatadogIntakeSiteDescriptor extends DatadogIntake.DatadogIntakeDescriptor {
public DatadogIntakeSiteDescriptor() {
load();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public Descriptor<DatadogApiKey> getDescriptor() {
}

@Extension
public static final class DatadogCredentialsApiKeyDescriptor extends DatadogApiKeyDescriptor {
public static final class DatadogCredentialsApiKeyDescriptor extends DatadogApiKey.DatadogApiKeyDescriptor {
public DatadogCredentialsApiKeyDescriptor() {
load();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public Descriptor<DatadogApiKey> getDescriptor() {
}

@Extension
public static final class DatadogTextApiKeyDescriptor extends DatadogApiKeyDescriptor {
public static final class DatadogTextApiKeyDescriptor extends DatadogApiKey.DatadogApiKeyDescriptor {
public DatadogTextApiKeyDescriptor() {
load();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package org.datadog.jenkins.plugins.datadog.util.conversion;

import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import java.util.List;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.datadog.jenkins.plugins.datadog.DatadogUtilities;

public class PatternListConverter implements Converter {

@Override
public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
String string = DatadogUtilities.listToCstr((List<Pattern>) source, Pattern::toString);
context.convertAnother(string);
}

@Override
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
String string = (String) context.convertAnother(null, String.class);
if (StringUtils.isBlank(string)) {
return null;
}
return DatadogUtilities.cstrToList(string, Pattern::compile);
}

@Override
public boolean canConvert(Class type) {
return List.class.isAssignableFrom(type);
}
}
Loading