我正在尝试将 Dynatrace App Mon 插件扩展为与 Jenkins 管道兼容。我从Github dynatrace-dashboard-2.0.5获取了源代码(来自这个存储库的主分支和dynatrace github 存储库的源代码有一些问题并且无法正常工作,所以我最终下载了 2.0.5 版本的源代码)
我写了一个类DynatraceAppMonBuildEnvStep
来扩展AbstractStepImpl
和模仿TABuildWrapper
step 的功能。Utils.updateBuildVariables(build, parameters);
在类中调用方法 时遇到问题DynatraceAppMonBuildEnvStep
,最终将设置环境变量。我没有收到任何错误/异常,但它没有设置我需要在mvn build
命令中注入的环境变量。
当我bat 'set'
在我的管道脚本中运行时,它不会显示在环境变量下方。如果我通过非管道调用插件,我可以看到这些环境变量。
dtMarker=testservice
dtPassword=password1
dtProfile=testprofile
dtServerUrl=https://<someurl>:8021
dtTestrunID=<test id>
dtUsername=<username>
dtVersionBuild=36
dtVersionMajor=testservice
代码流程如下:DynatraceAppMonBuildEnvStep -> Utils -> DynatraceVariablesAction -> DynatraceVariablesEnvironmentContributor -> buildEnvironmentFor(方法)。
DynatraceAppMonBuildEnvStep.java
package com.dynatrace.jenkins.steps;
import hudson.Extension;
import hudson.model.ParameterValue;
import hudson.model.PasswordParameterValue;
import hudson.model.Run;
import hudson.model.StringParameterValue;
import hudson.model.TaskListener;
import hudson.util.FormValidation;
import jenkins.model.GlobalConfiguration;
import org.apache.commons.lang.StringUtils;
import org.jenkinsci.plugins.workflow.steps.AbstractStepDescriptorImpl;
import org.jenkinsci.plugins.workflow.steps.AbstractStepImpl;
import org.jenkinsci.plugins.workflow.steps.AbstractSynchronousNonBlockingStepExecution;
import org.jenkinsci.plugins.workflow.steps.StepContextParameter;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;
import com.dynatrace.jenkins.dashboard.Messages;
import com.dynatrace.jenkins.dashboard.TABuildSetupStatusAction;
import com.dynatrace.jenkins.dashboard.TAGlobalConfiguration;
import com.dynatrace.jenkins.dashboard.utils.BuildVarKeys;
import com.dynatrace.jenkins.dashboard.utils.Utils;
import com.dynatrace.sdk.server.exceptions.ServerResponseException;
import com.dynatrace.sdk.server.sessions.Sessions;
import com.dynatrace.sdk.server.sessions.models.StartRecordingRequest;
import com.dynatrace.sdk.server.testautomation.TestAutomation;
import com.dynatrace.sdk.server.testautomation.models.FetchTestRunsRequest;
import com.sun.jersey.api.client.ClientHandlerException;
import static java.net.HttpURLConnection.HTTP_FORBIDDEN;
import static java.net.HttpURLConnection.HTTP_NOT_FOUND;
import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED;
import java.io.PrintStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nonnull;
import javax.inject.Inject;
import javax.net.ssl.SSLHandshakeException;
public final class DynatraceAppMonBuildEnvStep extends AbstractStepImpl {
/**
* The 1st arg is system profile name, the 2nd is build number
*/
private static final String RECORD_SESSION_NAME = "%s_Jenkins_build_%s";
public final String systemProfile;
// Test run attributes - no versionBuild attribute because it's taken from
// the build object
public final String versionMajor;
public final String versionMinor;
public final String versionRevision;
public final String versionMilestone;
public final String marker;
public final Boolean recordSession;
@DataBoundConstructor
public DynatraceAppMonBuildEnvStep(final String systemProfile, final String versionMajor, final String versionMinor,
final String versionRevision, final String versionMilestone, final String marker,
final Boolean recordSession) {
this.systemProfile = systemProfile;
this.versionMajor = versionMajor;
this.versionMinor = versionMinor;
this.versionRevision = versionRevision;
this.versionMilestone = versionMilestone;
this.marker = marker;
this.recordSession = recordSession;
}
private void setupBuildVariables(Run<?, ?> build, String serverUrl) {
final TAGlobalConfiguration globalConfig = GlobalConfiguration.all().get(TAGlobalConfiguration.class);
List<ParameterValue> parameters = new ArrayList<>(10);
parameters.add(new StringParameterValue(BuildVarKeys.BUILD_VAR_KEY_SYSTEM_PROFILE, systemProfile));
if (StringUtils.isNotEmpty(versionMajor)) {
parameters.add(new StringParameterValue(BuildVarKeys.BUILD_VAR_KEY_VERSION_MAJOR, versionMajor));
}
if (StringUtils.isNotEmpty(versionMinor)) {
parameters.add(new StringParameterValue(BuildVarKeys.BUILD_VAR_KEY_VERSION_MINOR, versionMinor));
}
if (StringUtils.isNotEmpty(versionRevision)) {
parameters.add(new StringParameterValue(BuildVarKeys.BUILD_VAR_KEY_VERSION_REVISION, versionRevision));
}
parameters.add(new StringParameterValue(BuildVarKeys.BUILD_VAR_KEY_VERSION_BUILD,
Integer.toString(build.getNumber())));
if (StringUtils.isNotEmpty(versionMilestone)) {
parameters.add(new StringParameterValue(BuildVarKeys.BUILD_VAR_KEY_VERSION_MILESTONE, versionMilestone));
}
if (StringUtils.isNotEmpty(marker)) {
parameters.add(new StringParameterValue(BuildVarKeys.BUILD_VAR_KEY_MARKER, marker));
}
if (StringUtils.isNotEmpty(serverUrl)) {
parameters.add(new StringParameterValue(BuildVarKeys.BUILD_VAR_KEY_GLOBAL_SERVER_URL, serverUrl));
}
if (StringUtils.isNotEmpty(globalConfig.username)) {
parameters.add(new StringParameterValue(BuildVarKeys.BUILD_VAR_KEY_GLOBAL_USERNAME, globalConfig.username));
}
if (StringUtils.isNotEmpty(globalConfig.password)) {
parameters
.add(new PasswordParameterValue(BuildVarKeys.BUILD_VAR_KEY_GLOBAL_PASSWORD, globalConfig.password));
}
System.out.println("first call to utlis.updateBuildVariables from step 1::::");
Utils.updateBuildVariables(build, parameters);
}
@Extension
public static final class DescriptorImpl extends AbstractStepDescriptorImpl {
public DescriptorImpl() {
super(Execution.class);
}
@Override
public String getFunctionName() {
return "dynatraceAppMonBuildEnvStep";
}
private static final boolean DEFAULT_RECORD_SESSION = false;
public static boolean getDefaultRecordSession() {
return DEFAULT_RECORD_SESSION;
}
@Nonnull
@Override
public String getDisplayName() {
return "Use Dynatrace AppMon to monitor tests";
}
public FormValidation doCheckSystemProfile(@QueryParameter final String systemProfile) {
if (StringUtils.isNotBlank(systemProfile)) {
return FormValidation.ok();
} else {
return FormValidation.error(Messages.RECORDER_VALIDATION_BLANK_SYSTEM_PROFILE());
}
}
public FormValidation doTestDynatraceConnection(@QueryParameter final String systemProfile) {
try {
final TestAutomation connection = new TestAutomation(Utils.createClient());
FetchTestRunsRequest request = new FetchTestRunsRequest(systemProfile);
// We set many constraints to ENSURE no or few testruns are
// returned as this is testing the connection only
request.setVersionBuildFilter("1024");
request.setVersionMajorFilter("1024");
request.setMaxBuilds(1);
try {
connection.fetchTestRuns(request);
} catch (ServerResponseException e) {
switch (e.getStatusCode()) {
case HTTP_UNAUTHORIZED:
return FormValidation.warning(Messages.RECORDER_VALIDATION_CONNECTION_UNAUTHORIZED());
case HTTP_FORBIDDEN:
return FormValidation.warning(Messages.RECORDER_VALIDATION_CONNECTION_FORBIDDEN());
case HTTP_NOT_FOUND:
return FormValidation.warning(Messages.RECORDER_VALIDATION_CONNECTION_NOT_FOUND());
default:
return FormValidation
.warning(Messages.RECORDER_VALIDATION_CONNECTION_OTHER_CODE(e.getStatusCode()));
}
}
return FormValidation.ok(Messages.RECORDER_VALIDATION_CONNECTION_OK());
} catch (Exception e) {
e.printStackTrace();
if (e.getCause() instanceof ClientHandlerException
&& e.getCause().getCause() instanceof SSLHandshakeException) {
return FormValidation.warning(Messages.RECORDER_VALIDATION_CONNECTION_CERT_EXCEPTION(e.toString()));
}
return FormValidation.warning(Messages.RECORDER_VALIDATION_CONNECTION_UNKNOWN(e.toString()));
}
}
}
public static final class Execution extends AbstractSynchronousNonBlockingStepExecution<Boolean> {
@Inject
private transient DynatraceAppMonBuildEnvStep step;
// public final Boolean recordSession = step.recordSession;
// public final Boolean recordSession = false;
@StepContextParameter
private transient TaskListener listener;
@StepContextParameter
private transient Run<?, ?> build;
@Override
protected Boolean run() throws Exception {
Boolean result = true;
final TAGlobalConfiguration globalConfig = GlobalConfiguration.all().get(TAGlobalConfiguration.class);
final Sessions sessions = new Sessions(Utils.createClient());
final PrintStream logger = listener.getLogger();
// logger.println("host is:"+globalConfig.host);
try {
String serverUrl = new URI(globalConfig.protocol, null, globalConfig.host, globalConfig.port, null,
null, null).toString();
if (step.recordSession) {
logger.println("Starting session recording via Dynatrace Server REST interface...");
StartRecordingRequest request = new StartRecordingRequest(step.systemProfile);
request.setPresentableName(
String.format(RECORD_SESSION_NAME, step.systemProfile, build.getNumber()));
final String sessionNameOut = sessions.startRecording(request);
logger.println("Dynatrace session " + sessionNameOut + " has been started");
}
step.setupBuildVariables(build, serverUrl);
} catch (Exception e) {
e.printStackTrace();
build.addAction(new TABuildSetupStatusAction(true));
logger.println(
"ERROR: Dynatrace AppMon Plugin - build set up failed (see the stacktrace to get more information):\n"
+ e.toString());
}
// final PrintStream logger = listener.getLogger();
/*
* logger.println("Dynatrace AppMon Plugin - build tear down...");
* try { if (recordSession) { final String storedSessionName =
* storeSession(logger); Utils.updateBuildVariable(build,
* BuildVarKeys.BUILD_VAR_KEY_STORED_SESSION_NAME,
* storedSessionName); } } catch (Exception e) {
* e.printStackTrace(); logger.
* println("ERROR: Dynatrace AppMon Plugin - build tear down failed (see the stacktrace to get more information):\n"
* + e.toString()); }
*/
return result;
}
private static final long serialVersionUID = 1L;
/**
* @return stored session name
*/
/*
* private String storeSession(final PrintStream logger) throws
* ServerResponseException, ServerConnectionException { logger.
* println("Storing session via Dynatrace Server REST interface...");
* String sessionName = sessions.stopRecording(step.systemProfile);
* logger.println("Dynatrace session " + sessionName +
* " has been stored"); return sessionName; }
*/
}
}
**Utils.java**
package com.dynatrace.jenkins.dashboard.utils;
import com.dynatrace.jenkins.dashboard.TABuildSetupStatusAction;
import com.dynatrace.jenkins.dashboard.TAGlobalConfiguration;
import com.dynatrace.jenkins.dashboard.model_2_0_0.*;
import com.dynatrace.sdk.server.BasicServerConfiguration;
import com.dynatrace.sdk.server.DynatraceClient;
import com.dynatrace.sdk.server.testautomation.models.TestRuns;
import hudson.model.AbstractBuild;
import hudson.model.ParameterValue;
import hudson.model.Result;
import hudson.model.Run;
import hudson.model.StringParameterValue;
import jenkins.model.GlobalConfiguration;
import java.io.PrintStream;
import java.text.DecimalFormat;
import java.util.*;
/**
* Created by krzysztof.necel on 2016-01-25.
*/
public final class Utils {
public static final String TEST_MEASURE_UNIT_DEFAULT = "num";
public static final String DYNATRACE_ICON_24_X_24_FILEPATH = "/plugin/dynatrace-dashboard/images/dynatrace_icon_24x24.png";
public static final String DYNATRACE_ICON_48_X_48_FILEPATH = "/plugin/dynatrace-dashboard/images/dynatrace_icon_48x48.png";
private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.##");
private static final String FORMAT_DOUBLE_NULL_VALUE = "N/A";
private Utils() {
}
public static DynatraceClient createClient() {
final TAGlobalConfiguration globalConfig = GlobalConfiguration.all().get(TAGlobalConfiguration.class);
BasicServerConfiguration config = new BasicServerConfiguration(globalConfig.username,
globalConfig.password,
globalConfig.protocol.startsWith("https"),
globalConfig.host,
globalConfig.port,
globalConfig.validateCerts,
//connection timeout, 0 stands for infinite
0);
return new DynatraceClient(config);
}
public static TAReportDetails convertTestRuns(TestRuns sdkTestRuns) {
ArrayList<TestRun> testRuns = new ArrayList<>();
if (sdkTestRuns != null) {
for (com.dynatrace.sdk.server.testautomation.models.TestRun tr : sdkTestRuns.getTestRuns()) {
testRuns.add(convertTestRun(tr));
}
}
return new TAReportDetails(testRuns);
}
public static TestRun convertTestRun(com.dynatrace.sdk.server.testautomation.models.TestRun sdkTestRun) {
List<TestResult> testResults = new ArrayList<>();
for (com.dynatrace.sdk.server.testautomation.models.TestResult sdkResult : sdkTestRun.getTestResults()) {
testResults.add(convertTestResult(sdkResult));
}
Map<TestStatus, Integer> testRunSummary = new EnumMap<>(TestStatus.class);
testRunSummary.put(TestStatus.FAILED, sdkTestRun.getFailedCount());
testRunSummary.put(TestStatus.DEGRADED, sdkTestRun.getDegradedCount());
testRunSummary.put(TestStatus.VOLATILE, sdkTestRun.getVolatileCount());
testRunSummary.put(TestStatus.IMPROVED, sdkTestRun.getImprovedCount());
testRunSummary.put(TestStatus.PASSED, sdkTestRun.getPassedCount());
return new TestRun(testResults, testRunSummary, sdkTestRun.getId(), convertTestCategory(sdkTestRun.getCategory()));
}
public static TestResult convertTestResult(com.dynatrace.sdk.server.testautomation.models.TestResult sdkTestResult) {
Set<TestMeasure> measures = new HashSet<>();
for (com.dynatrace.sdk.server.testautomation.models.TestMeasure sdkMeasure : sdkTestResult.getMeasures()) {
measures.add(convertTestMeasure(sdkMeasure));
}
return new TestResult(new Date(sdkTestResult.getExecutionTime()), sdkTestResult.getName(), sdkTestResult.getPackageName(), sdkTestResult.getPlatform(), convertTestStatus(sdkTestResult.getStatus()), measures);
}
public static TestMeasure convertTestMeasure(com.dynatrace.sdk.server.testautomation.models.TestMeasure sdkTestMeasure) {
String unit = sdkTestMeasure.getUnit() != null ? sdkTestMeasure.getUnit() : TEST_MEASURE_UNIT_DEFAULT;
return new TestMeasure(sdkTestMeasure.getName(),
sdkTestMeasure.getMetricGroup(),
sdkTestMeasure.getExpectedMin(),
sdkTestMeasure.getExpectedMax(),
sdkTestMeasure.getValue(),
unit,
sdkTestMeasure.getViolationPercentage());
}
public static TestCategory convertTestCategory(com.dynatrace.sdk.server.testautomation.models.TestCategory sdkTestCategory) {
switch (sdkTestCategory) {
case UNIT:
return TestCategory.UNIT;
case UI_DRIVEN:
return TestCategory.UI_DRIVEN;
case WEB_API:
return TestCategory.WEB_API;
case PERFORMANCE:
return TestCategory.PERFORMANCE;
}
throw new IllegalArgumentException("Could not convert TestCategory");
}
public static TestStatus convertTestStatus(com.dynatrace.sdk.server.testautomation.models.TestStatus sdkTestStatus) {
return TestStatus.valueOf(sdkTestStatus.name());
}
public static Map<TestStatus, Integer> createReportAggregatedSummary(TAReportDetails reportDetails) {
// just sum all the reports for test runs
final Map<TestStatus, Integer> summary = new EnumMap<>(TestStatus.class);
for (TestRun testRun : reportDetails.getTestRuns()) {
Map<TestStatus, Integer> testRunSummary = testRun.getSummary();
for (Map.Entry<TestStatus, Integer> entry : testRunSummary.entrySet()) {
Integer value = summary.get(entry.getKey());
summary.put(entry.getKey(), value == null ? entry.getValue() : entry.getValue() + value);
}
}
return summary;
}
public static String formatDouble(Double d) {
return d == null ? FORMAT_DOUBLE_NULL_VALUE : DECIMAL_FORMAT.format(d);
}
public static String formatDoublePercentage(Double d) {
return d == null ? FORMAT_DOUBLE_NULL_VALUE : DECIMAL_FORMAT.format(d * 100);
}
public static boolean isValidBuild(AbstractBuild build, PrintStream logger, String message) {
if (build.getResult() == Result.ABORTED) {
logger.println("Build has been aborted - " + message);
return false;
}
TABuildSetupStatusAction setupStatusAction = build.getAction(TABuildSetupStatusAction.class);
if (setupStatusAction != null && setupStatusAction.isSetupFailed()) {
logger.println("Failed to set up environment for Dynatrace AppMon Plugin - " + message);
return false;
}
return true;
}
public static boolean isValidBuild(Run build, PrintStream logger, String message) {
if (build.getResult() == Result.ABORTED) {
logger.println("Build has been aborted - " + message);
return false;
}
TABuildSetupStatusAction setupStatusAction = build.getAction(TABuildSetupStatusAction.class);
if (setupStatusAction != null && setupStatusAction.isSetupFailed()) {
logger.println("Failed to set up environment for Dynatrace AppMon Plugin - " + message);
return false;
}
return true;
}
public static void updateBuildVariables(AbstractBuild<?, ?> build, List<ParameterValue> parameters) {
DynatraceVariablesAction existingAction = build.getAction(DynatraceVariablesAction.class);
if (existingAction == null) {
build.addAction(new DynatraceVariablesAction(parameters));
} else {
build.replaceAction(existingAction.createUpdated(parameters));
}
}
public static void updateBuildVariables(Run<?, ?> build, List<ParameterValue> parameters) {
DynatraceVariablesAction existingAction = build.getAction(DynatraceVariablesAction.class);
if (existingAction == null) {
build.addAction(new DynatraceVariablesAction(parameters));
} else {
build.replaceAction(existingAction.createUpdated(parameters));
}
}
public static void updateBuildVariable(AbstractBuild<?, ?> build, String key, String value) {
updateBuildVariables(build, Collections.<ParameterValue>singletonList(new StringParameterValue(key, value)));
}
public static void updateBuildVariable(Run<?, ?> build, String key, String value) {
updateBuildVariables(build, Collections.<ParameterValue>singletonList(new StringParameterValue(key, value)));
}
}
**DynatraceVariablesAction.java**
package com.dynatrace.jenkins.dashboard.utils;
import hudson.EnvVars;
import hudson.Extension;
import hudson.model.*;
import javax.annotation.Nonnull;
import java.util.*;
public class DynatraceVariablesAction extends ParametersAction {
private List<ParameterValue> parameters = new ArrayList<>();
public DynatraceVariablesAction(Collection<? extends ParameterValue> parameters) {
this.parameters.addAll(parameters);
}
@Override
public List<ParameterValue> getParameters() {
return Collections.unmodifiableList(parameters);
}
@Override
public ParameterValue getParameter(String name) {
for (ParameterValue p : parameters) {
if (p == null) continue;
if (p.getName().equals(name))
return p;
}
return null;
}
@Nonnull
@Override
public DynatraceVariablesAction createUpdated(Collection<? extends ParameterValue> overrides) {
List<ParameterValue> newParams = new ArrayList<>(overrides);
outer:
for (ParameterValue value : this.parameters) {
for (ParameterValue newParam : newParams) {
if (newParam.getName().equals(value.getName())) {
continue outer;
}
}
newParams.add(value);
}
return new DynatraceVariablesAction(newParams);
}
@Extension
public static final class DynatraceBuildVariablesContributor extends BuildVariableContributor {
@Override
public void buildVariablesFor(AbstractBuild r, Map<String, String> variables) {
DynatraceVariablesAction a = r.getAction(DynatraceVariablesAction.class);
if (a == null) {
return;
}
for (ParameterValue spv : a.getParameters()) {
variables.put(spv.getName(), String.valueOf(spv.getValue()));
}
}
}
@Extension
public static final class DynatraceVariablesEnvironmentContributor extends EnvironmentContributor {
@Override
public void buildEnvironmentFor(Run r, EnvVars vars, TaskListener listener) {
DynatraceVariablesAction a = r.getAction(DynatraceVariablesAction.class);
if (a == null) {
return;
}
for (ParameterValue spv : a.getParameters()) {
vars.put(spv.getName(), String.valueOf(spv.getValue()));
}
}
}
}
I also tried to set the environment variables by extending InvisibleAction class instead of ParametersAction, as performance-signature-dynatrace-plugin is doing but that didn't seem to work as well. Dynatrace performance signature plugin is setting the environment variables in a bit different way. See these two links:
[https://github.com/jenkinsci/performance-signature-dynatrace-plugin/blob/master/dynatrace/src/main/java/de/tsystems/mms/apm/performancesignature/dynatrace/PerfSigEnvInvisAction.java][1]
[https://github.com/jenkinsci/performance-signature-dynatrace-plugin/blob/master/dynatrace/src/main/java/de/tsystems/mms/apm/performancesignature/dynatrace/PerfSigEnvContributor.java][2]
[1]: https://github.com/jenkinsci/performance-signature-dynatrace-plugin/blob/master/dynatrace/src/main/java/de/tsystems/mms/apm/performancesignature/dynatrace/PerfSigEnvInvisAction.java
[2]: https://github.com/jenkinsci/performance-signature-dynatrace-plugin/blob/master/dynatrace/src/main/java/de/tsystems/mms/apm/performancesignature/dynatrace/PerfSigEnvContributor.java
Any help would be highly appreciated. I hope I was able to describe the problem. Please feel free to comment if my issue/question is not clear.
Thanks.