diff --git a/src/main/java/org/datadog/jenkins/plugins/datadog/apm/DatadogTracerConfigurator.java b/src/main/java/org/datadog/jenkins/plugins/datadog/apm/DatadogTracerConfigurator.java index b3c41e30..446df3ce 100644 --- a/src/main/java/org/datadog/jenkins/plugins/datadog/apm/DatadogTracerConfigurator.java +++ b/src/main/java/org/datadog/jenkins/plugins/datadog/apm/DatadogTracerConfigurator.java @@ -48,11 +48,27 @@ public Map configure(Run run, Computer computer, Node node return Collections.emptyMap(); } + TopLevelItem topLevelItem = getTopLevelItem(run); + FilePath workspacePath = node.getWorkspaceFor(topLevelItem); + if (workspacePath == null) { + listener.error("[datadog] Cannot find workspace path for " + topLevelItem + " on " + node); + return Collections.emptyMap(); + } + String nodeHostname = DatadogUtilities.getNodeHostname(envs, computer); Collection languages = tracerConfig.getLanguages(); for (ConfigureTracerAction action : run.getActions(ConfigureTracerAction.class)) { if (nodeHostname != null && nodeHostname.equals(action.nodeHostname) && action.languages.containsAll(languages)) { - return action.variables; + boolean previousConfigurationValid = true; + for (TracerLanguage language : action.languages) { + TracerConfigurator tracerConfigurator = configurators.get(language); + if (tracerConfigurator != null) { + previousConfigurationValid &= tracerConfigurator.isConfigurationValid(node, workspacePath); + } + } + if (previousConfigurationValid) { + return action.variables; + } } } @@ -62,13 +78,6 @@ public Map configure(Run run, Computer computer, Node node return Collections.emptyMap(); } - TopLevelItem topLevelItem = getTopLevelItem(run); - FilePath workspacePath = node.getWorkspaceFor(topLevelItem); - if (workspacePath == null) { - listener.error("[datadog] Cannot find workspace path for " + topLevelItem + " on " + node); - return Collections.emptyMap(); - } - Map variables = new HashMap<>(getCommonEnvVariables(datadogConfig, tracerConfig)); for (TracerLanguage language : languages) { TracerConfigurator tracerConfigurator = configurators.get(language); diff --git a/src/main/java/org/datadog/jenkins/plugins/datadog/apm/JavaConfigurator.java b/src/main/java/org/datadog/jenkins/plugins/datadog/apm/JavaConfigurator.java index d54c918a..6e7c966b 100644 --- a/src/main/java/org/datadog/jenkins/plugins/datadog/apm/JavaConfigurator.java +++ b/src/main/java/org/datadog/jenkins/plugins/datadog/apm/JavaConfigurator.java @@ -5,6 +5,7 @@ import hudson.model.TaskListener; import hudson.util.Secret; import java.io.ByteArrayInputStream; +import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; @@ -14,14 +15,16 @@ import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.function.Function; +import java.util.logging.Level; import java.util.logging.Logger; import jenkins.model.Jenkins; +import org.datadog.jenkins.plugins.datadog.DatadogUtilities; import org.datadog.jenkins.plugins.datadog.apm.signature.SignatureVerifier; import org.datadog.jenkins.plugins.datadog.clients.HttpClient; final class JavaConfigurator implements TracerConfigurator { - private static final Logger LOGGER = Logger.getLogger(DatadogTracerConfigurator.class.getName()); + private static final Logger LOGGER = Logger.getLogger(JavaConfigurator.class.getName()); private static final String TRACER_DISTRIBUTION_URL_ENV_VAR = "DATADOG_JENKINS_PLUGIN_TRACER_DISTRIBUTION_URL"; private static final String DEFAULT_TRACER_DISTRIBUTION_URL = "https://dtdg.co/latest-java-tracer"; @@ -43,10 +46,7 @@ public Map configure(DatadogTracerJobProperty tracerConfig, N } private FilePath downloadTracer(DatadogTracerJobProperty tracerConfig, FilePath workspacePath, Node node, TaskListener listener) throws Exception { - FilePath datadogFolder = workspacePath.child(".datadog"); - datadogFolder.mkdirs(); - - FilePath datadogTracerFile = datadogFolder.child(TRACER_FILE_NAME); + FilePath datadogTracerFile = getDatadogTracerFile(workspacePath); long minutesSinceModification = TimeUnit.MILLISECONDS.toMinutes(System.currentTimeMillis() - datadogTracerFile.lastModified()); if (minutesSinceModification < getTracerJarCacheTtlMinutes(tracerConfig)) { listener.getLogger().println("[datadog] Configuring DD Java tracer: using existing tracer available at " + datadogTracerFile); @@ -86,6 +86,12 @@ private FilePath downloadTracer(DatadogTracerJobProperty tracerConfig, FilePa return datadogTracerFile.absolutize(); } + private static FilePath getDatadogTracerFile(FilePath workspacePath) throws IOException, InterruptedException { + FilePath datadogFolder = workspacePath.child(".datadog"); + datadogFolder.mkdirs(); + return datadogFolder.child(TRACER_FILE_NAME); + } + private int getTracerJarCacheTtlMinutes(DatadogTracerJobProperty tracerConfig) { return getSetting(tracerConfig, TRACER_JAR_CACHE_TTL_ENV_VAR, DEFAULT_TRACER_JAR_CACHE_TTL_MINUTES, Integer::parseInt); } @@ -212,4 +218,15 @@ private static String getProxyConfiguration(DatadogTracerJobProperty tracerCo } return proxyOptions.length() > 0 ? proxyOptions.toString() : null; } + + @Override + public boolean isConfigurationValid(Node node, FilePath workspacePath) { + try { + FilePath datadogTracerFile = getDatadogTracerFile(workspacePath); + return datadogTracerFile.exists(); + } catch (Exception e) { + DatadogUtilities.logException(LOGGER, Level.FINE, "Could not verify Java tracer file existence", e); + return false; + } + } } diff --git a/src/main/java/org/datadog/jenkins/plugins/datadog/apm/JavascriptConfigurator.java b/src/main/java/org/datadog/jenkins/plugins/datadog/apm/JavascriptConfigurator.java index c8470ff4..7c0f67f5 100644 --- a/src/main/java/org/datadog/jenkins/plugins/datadog/apm/JavascriptConfigurator.java +++ b/src/main/java/org/datadog/jenkins/plugins/datadog/apm/JavascriptConfigurator.java @@ -8,12 +8,19 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.datadog.jenkins.plugins.datadog.DatadogUtilities; final class JavascriptConfigurator implements TracerConfigurator { + private static final Logger LOGGER = Logger.getLogger(JavascriptConfigurator.class.getName()); + private static final int GET_NPM_VERSION_TIMEOUT_MILLIS = 30_000; private static final int INSTALL_TRACER_TIMEOUT_MILLIS = 300_000; + private static final String RELATIVE_TRACER_PATH = "lib/node_modules/dd-trace"; + @Override public Map configure(DatadogTracerJobProperty tracerConfig, Node node, FilePath workspacePath, Map envs, TaskListener listener) throws Exception { String nodeVersion = workspacePath.act(new ShellCommandCallable(Collections.emptyMap(), GET_NPM_VERSION_TIMEOUT_MILLIS, "npm", "-v")); @@ -29,7 +36,7 @@ public Map configure(DatadogTracerJobProperty tracerConfig, N // we install dd-trace as a "global" package // (otherwise, doing SCM checkout might rollback the changes to package.json, and any subsequent `npm install` calls will result in removing the package) String installTracerOutput = workspacePath.act(new ShellCommandCallable(environment, INSTALL_TRACER_TIMEOUT_MILLIS, "npm", "install", "-g", "dd-trace")); - Path tracerPath = absoluteDatadogPath.resolve("lib/node_modules/dd-trace"); + Path tracerPath = absoluteDatadogPath.resolve(RELATIVE_TRACER_PATH); listener.getLogger().println("[datadog] Configuring DD JS tracer: tracer installed in " + tracerPath + " on " + node + "; output: " + installTracerOutput); Map variables = new HashMap<>(); @@ -37,4 +44,16 @@ public Map configure(DatadogTracerJobProperty tracerConfig, N variables.put("NODE_OPTIONS", PropertyUtils.prepend(envs, "NODE_OPTIONS", String.format("-r %s/ci/init", tracerPath))); return variables; } + + @Override + public boolean isConfigurationValid(Node node, FilePath workspacePath) { + try { + FilePath datadogPath = workspacePath.child(".datadog"); + FilePath tracerPath = datadogPath.child(RELATIVE_TRACER_PATH); + return tracerPath.exists(); + } catch (Exception e) { + DatadogUtilities.logException(LOGGER, Level.FINE, "Could not verify JS tracer file existence", e); + return false; + } + } } diff --git a/src/main/java/org/datadog/jenkins/plugins/datadog/apm/PythonConfigurator.java b/src/main/java/org/datadog/jenkins/plugins/datadog/apm/PythonConfigurator.java index 2f31eac6..c05f30cf 100644 --- a/src/main/java/org/datadog/jenkins/plugins/datadog/apm/PythonConfigurator.java +++ b/src/main/java/org/datadog/jenkins/plugins/datadog/apm/PythonConfigurator.java @@ -7,9 +7,14 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.datadog.jenkins.plugins.datadog.DatadogUtilities; final class PythonConfigurator implements TracerConfigurator { + private static final Logger LOGGER = Logger.getLogger(PythonConfigurator.class.getName()); + private static final int GET_PIP_VERSION_TIMEOUT_MILLIS = 30_000; private static final int INSTALL_TRACER_TIMEOUT_MILLIS = 300_000; private static final int SHOW_TRACER_PACKAGE_DETAILS_TIMEOUT_MILLIS = 300_000; @@ -39,4 +44,15 @@ private static String getTracerLocation(FilePath workspacePath) throws IOExcepti } throw new IllegalStateException("Could not determine tracer location in " + workspacePath + "; command output is: " + getTracerLocationOutput); } + + @Override + public boolean isConfigurationValid(Node node, FilePath workspacePath) { + try { + String tracerLocation = getTracerLocation(workspacePath); + return workspacePath.child(tracerLocation).exists(); + } catch (Exception e) { + DatadogUtilities.logException(LOGGER, Level.FINE, "Could not verify Python tracer file existence", e); + return false; + } + } } diff --git a/src/main/java/org/datadog/jenkins/plugins/datadog/apm/TracerConfigurator.java b/src/main/java/org/datadog/jenkins/plugins/datadog/apm/TracerConfigurator.java index ad1510f7..dcc4ac23 100644 --- a/src/main/java/org/datadog/jenkins/plugins/datadog/apm/TracerConfigurator.java +++ b/src/main/java/org/datadog/jenkins/plugins/datadog/apm/TracerConfigurator.java @@ -11,4 +11,11 @@ Map configure(DatadogTracerJobProperty tracerConfig, FilePath workspacePath, Map envs, TaskListener listener) throws Exception; + + /** + * Is used to check whether configuration is valid or needs to be re-applied. + */ + default boolean isConfigurationValid(Node node, FilePath workspacePath) { + return true; + } }