diff --git a/src/main/java/CloudWatchMonitor.java b/src/main/java/CloudWatchMonitor.java index 8b24076..2a13105 100644 --- a/src/main/java/CloudWatchMonitor.java +++ b/src/main/java/CloudWatchMonitor.java @@ -34,24 +34,33 @@ public class CloudWatchMonitor { @Setter @Getter private LogsLocation logsLocation; @Getter private List latestLogs; @Getter private Long lastPollTime; + private boolean cwlStreamingDisabled; private static final int htmlMaxLineLength = 2000; public static final String noLogsMessage = "No CloudWatch logs found for this build."; + public static final String streamingDisabledMessage = "CloudWatch logs streaming is disabled for this build."; public static final String failedConfigurationLogsMessage = "CloudWatch configuration for this build is incorrect."; - public CloudWatchMonitor(AWSLogsClient client) { + public CloudWatchMonitor(AWSLogsClient client, boolean cwlStreamingDisabled) { this.logsClient = client; + this.cwlStreamingDisabled = cwlStreamingDisabled; if(!Validation.checkCloudWatchMonitorConfig(logsClient)) { latestLogs = Arrays.asList(failedConfigurationLogsMessage); return; } + if(cwlStreamingDisabled) { + latestLogs = Arrays.asList(streamingDisabledMessage); + } lastPollTime = 0L; } // Checks if the CloudWatch logs exist. If they do, retrieves/stores them in this.latestLogs. // If the logs don't exist yet, sets this.latestLogs to an error message. + // Does nothing if CloudWatch logs streaming is disabled public void pollForLogs(TaskListener listener) { - if(this.logsLocation != null && this.logsLocation.getGroupName() != null && this.logsLocation.getStreamName() != null) { + if(cwlStreamingDisabled) { + return; + } else if(this.logsLocation != null && this.logsLocation.getGroupName() != null && this.logsLocation.getStreamName() != null) { this.latestLogs = new ArrayList(); GetLogEventsRequest logRequest = new GetLogEventsRequest() .withStartTime(lastPollTime) @@ -69,7 +78,6 @@ public void pollForLogs(TaskListener listener) { latestLogs = Arrays.asList(noLogsMessage); return; } - } private void getAndFormatLogs(List logs, TaskListener listener) { diff --git a/src/main/java/CodeBuildAction.java b/src/main/java/CodeBuildAction.java index d851f0d..7ccab61 100644 --- a/src/main/java/CodeBuildAction.java +++ b/src/main/java/CodeBuildAction.java @@ -168,10 +168,14 @@ public String getBuildStatus() { public void updateLogs(List newLogs) { if(logs != null) { - if(logs.size() == 1 && logs.get(0).equals(CloudWatchMonitor.noLogsMessage)) { //no logs message already displayed - if(newLogs.size() > 0 && !newLogs.get(0).equals(CloudWatchMonitor.noLogsMessage)) { - logs = new ArrayList(); - } else { + if(logs.size() == 1) { + if(logs.get(0).equals(CloudWatchMonitor.noLogsMessage)) { + if (newLogs.size() > 0 && !newLogs.get(0).equals(CloudWatchMonitor.noLogsMessage)) { + logs = new ArrayList(); + } else { + return; + } + } else if(logs.get(0).equals(CloudWatchMonitor.streamingDisabledMessage)) { return; } } diff --git a/src/main/java/CodeBuildStep.java b/src/main/java/CodeBuildStep.java index a46b96f..bb8c130 100644 --- a/src/main/java/CodeBuildStep.java +++ b/src/main/java/CodeBuildStep.java @@ -86,6 +86,7 @@ public class CodeBuildStep extends AbstractStepImpl { @Getter private String envParameters; @Getter private String buildSpecFile; @Getter private String buildTimeoutOverride; + @Getter private String cwlStreamingDisabled; @DataBoundSetter public void setCredentialsType(String credentialsType) { @@ -307,6 +308,11 @@ public void setBuildTimeoutOverride(String buildTimeoutOverride) { this.buildTimeoutOverride = buildTimeoutOverride; } + @DataBoundSetter + public void setCwlStreamingDisabled(String cwlStreamingDisabled) { + this.cwlStreamingDisabled = cwlStreamingDisabled; + } + @Extension public static final class DescriptorImpl extends AbstractStepDescriptorImpl { @@ -528,6 +534,16 @@ public ListBoxModel doFillSseAlgorithmItems() { return selections; } + public ListBoxModel doFillCwlStreamingDisabledItems() { + final ListBoxModel selections = new ListBoxModel(); + + for(BooleanValue t: BooleanValue.values()) { + selections.add(t.toString()); + } + + return selections; + } + } public static final class CodeBuildExecution extends AbstractSynchronousNonBlockingStepExecution { @@ -565,7 +581,7 @@ protected CodeBuildResult run() throws Exception { step.getImageOverride(), step.getComputeTypeOverride(), step.getCacheTypeOverride(), step.getCacheLocationOverride(), step.getCloudWatchLogsStatusOverride(), step.getCloudWatchLogsGroupNameOverride(), step.getCloudWatchLogsStreamNameOverride(), step.getS3LogsStatusOverride(), step.getS3LogsLocationOverride(), step.getCertificateOverride(), step.getServiceRoleOverride(), - step.getInsecureSslOverride(), step.getPrivilegedModeOverride() + step.getInsecureSslOverride(), step.getPrivilegedModeOverride(), step.getCwlStreamingDisabled() ).readResolve(); builder.perform(run, ws, launcher, listener, getContext()); diff --git a/src/main/java/CodeBuilder.java b/src/main/java/CodeBuilder.java index a093ceb..0178e3e 100644 --- a/src/main/java/CodeBuilder.java +++ b/src/main/java/CodeBuilder.java @@ -92,6 +92,7 @@ public class CodeBuilder extends Builder implements SimpleBuildStep { @Getter private String envParameters; @Getter private String buildSpecFile; @Getter private String buildTimeoutOverride; + @Getter private String cwlStreamingDisabled; @Getter private final CodeBuildResult codeBuildResult; private EnvVars envVars; @@ -129,7 +130,7 @@ public CodeBuilder(String credentialsType, String credentialsId, String proxyHos String sourceLocationOverride, String environmentTypeOverride, String imageOverride, String computeTypeOverride, String cacheTypeOverride, String cacheLocationOverride, String cloudWatchLogsStatusOverride, String cloudWatchLogsGroupNameOverride, String cloudWatchLogsStreamNameOverride, String s3LogsStatusOverride, String s3LogsLocationOverride, String certificateOverride, String serviceRoleOverride, - String insecureSslOverride, String privilegedModeOverride) { + String insecureSslOverride, String privilegedModeOverride, String cwlStreamingDisabled) { this.credentialsType = Validation.sanitize(credentialsType); this.credentialsId = Validation.sanitize(credentialsId); @@ -175,6 +176,7 @@ public CodeBuilder(String credentialsType, String credentialsId, String proxyHos this.buildTimeoutOverride = Validation.sanitize(buildTimeoutOverride); this.insecureSslOverride = Validation.sanitize(insecureSslOverride); this.privilegedModeOverride = Validation.sanitize(privilegedModeOverride); + this.cwlStreamingDisabled = Validation.sanitize(cwlStreamingDisabled); this.codeBuildResult = new CodeBuildResult(); this.batchGetBuildsCalls = 0; } @@ -223,6 +225,7 @@ protected Object readResolve() { buildTimeoutOverride = Validation.sanitize(buildTimeoutOverride); insecureSslOverride = Validation.sanitize(insecureSslOverride); privilegedModeOverride = Validation.sanitize(privilegedModeOverride); + cwlStreamingDisabled = Validation.sanitize(cwlStreamingDisabled); return this; } @@ -428,7 +431,7 @@ public void perform(@Nonnull Run build, @Nonnull FilePath ws, @Nonnull Lau currentBuild = buildsForId.get(0); if(!haveInitializedAction) { - logMonitor = new CloudWatchMonitor(awsClientFactory.getCloudWatchLogsClient()); + logMonitor = new CloudWatchMonitor(awsClientFactory.getCloudWatchLogsClient(), Boolean.parseBoolean(getParameterized(cwlStreamingDisabled))); action = new CodeBuildAction(build); //only need to set these once, the others will need to be updated below as the build progresses. @@ -708,6 +711,9 @@ private void logStartBuildMessage(TaskListener listener, String sourceVersion) { if(!serviceRoleOverride.isEmpty()) { message.append("\n\t> service role: " + getParameterized(serviceRoleOverride)); } + if(!cwlStreamingDisabled.isEmpty()) { + message.append("\n\t> CloudWatch logs streaming disabled: " + getParameterized(cwlStreamingDisabled)); + } if(!buildSpecFile.isEmpty()) { message.append("\n\t> build spec: \n" + getParameterized(buildSpecFile)); } @@ -1128,6 +1134,16 @@ public ListBoxModel doFillSseAlgorithmItems() { return selections; } + public ListBoxModel doFillCwlStreamingDisabledItems() { + final ListBoxModel selections = new ListBoxModel(); + + for(BooleanValue t: BooleanValue.values()) { + selections.add(t.toString()); + } + + return selections; + } + public boolean isApplicable(Class aClass) { // Indicates that this builder can be used with all kinds of project types return true; diff --git a/src/main/resources/CodeBuilder/config.jelly b/src/main/resources/CodeBuilder/config.jelly index d184386..0021be0 100644 --- a/src/main/resources/CodeBuilder/config.jelly +++ b/src/main/resources/CodeBuilder/config.jelly @@ -208,5 +208,9 @@ + + + + diff --git a/src/main/webapp/help-cwlStreamingDisabled.html b/src/main/webapp/help-cwlStreamingDisabled.html new file mode 100644 index 0000000..118b37f --- /dev/null +++ b/src/main/webapp/help-cwlStreamingDisabled.html @@ -0,0 +1,17 @@ + + +
+ When set to true, prevents the plugin from downloading your build logs from CloudWatch and displaying them in the CodeBuild + dashboard and console log. +
\ No newline at end of file diff --git a/src/test/java/CloudWatchMonitorTest.java b/src/test/java/CloudWatchMonitorTest.java index 87fca41..6f8dcc4 100644 --- a/src/test/java/CloudWatchMonitorTest.java +++ b/src/test/java/CloudWatchMonitorTest.java @@ -28,6 +28,7 @@ import java.io.PrintStream; import java.util.*; +import static org.junit.Assert.*; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.mockito.Matchers.any; @@ -54,7 +55,7 @@ public void setUp() { @Test public void testInvalidConfig() throws Exception { - CloudWatchMonitor c = new CloudWatchMonitor(null); + CloudWatchMonitor c = new CloudWatchMonitor(null, false); assertLogsContainErrorMessage(c); } @@ -113,8 +114,18 @@ public void testFormatLogsTwoCalls() throws Exception { assert(c.getLastPollTime() == 4L); } + @Test + public void testCwlStreamingDisabled() throws Exception { + CloudWatchMonitor c = new CloudWatchMonitor(mockClient, true); + assertEquals(c.getLatestLogs().size(), 1); + assertEquals(c.getLatestLogs().get(0), CloudWatchMonitor.streamingDisabledMessage); + c.pollForLogs(listener); + assertEquals(c.getLatestLogs().size(), 1); + assertEquals(c.getLatestLogs().get(0), CloudWatchMonitor.streamingDisabledMessage); + } + private CloudWatchMonitor getMockCloudWatchMonitor() { - CloudWatchMonitor c = new CloudWatchMonitor(mockClient); + CloudWatchMonitor c = new CloudWatchMonitor(mockClient, false); c.setLogsLocation(new LogsLocation().withGroupName(mockGroup).withStreamName(mockStream)); return c; } diff --git a/src/test/java/CodeBuilderPerformTest.java b/src/test/java/CodeBuilderPerformTest.java index 463327f..aadf7b8 100644 --- a/src/test/java/CodeBuilderPerformTest.java +++ b/src/test/java/CodeBuilderPerformTest.java @@ -53,7 +53,7 @@ public void testConfigAllNull() throws Exception { null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null); + null, null, null, null, null); ArgumentCaptor savedResult = ArgumentCaptor.forClass(Result.class); test.perform(build, ws, launcher, listener, mockStepContext); @@ -75,7 +75,7 @@ public void testConfigAllBlank() throws Exception { "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", - "", "", "", ""); + "", "", "", "", ""); ArgumentCaptor savedResult = ArgumentCaptor.forClass(Result.class); test.perform(build, ws, launcher, listener, mockStepContext); @@ -97,7 +97,7 @@ public void testNoProjectName() throws Exception { "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", - "", "", "", ""); + "", "", "", "", ""); ArgumentCaptor savedResult = ArgumentCaptor.forClass(Result.class); test.perform(build, ws, launcher, listener, mockStepContext); @@ -122,7 +122,7 @@ public void testNoSourceType() throws Exception { "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", - "", "", "", ""); + "", "", "", "", ""); ArgumentCaptor savedResult = ArgumentCaptor.forClass(Result.class); test.perform(build, ws, launcher, listener, mockStepContext); @@ -199,7 +199,7 @@ public void testComputeTypeOverrideException() throws Exception { "[{k, v}]", "[{k, p}]", "buildspec.yml", "5", SourceType.GITHUB_ENTERPRISE.toString(), "https://1.0.0.0.86/my_repo", EnvironmentType.LINUX_CONTAINER.toString(), "aws/codebuild/openjdk-8", "invalidComputeType", CacheType.NO_CACHE.toString(), "", LogsConfigStatusType.ENABLED.toString(), "group", "stream", LogsConfigStatusType.ENABLED.toString(), "location", - "arn:aws:s3:::my_bucket/certificate.pem", "my_service_role", BooleanValue.False.toString(), BooleanValue.False.toString()); + "arn:aws:s3:::my_bucket/certificate.pem", "my_service_role", BooleanValue.False.toString(), BooleanValue.False.toString(), BooleanValue.False.toString()); ArgumentCaptor savedResult = ArgumentCaptor.forClass(Result.class); test.perform(build, ws, launcher, listener, mockStepContext); @@ -220,7 +220,7 @@ public void testCacheTypeOverrideException() throws Exception { "[{k, v}]", "[{k, p}]", "buildspec.yml", "5", SourceType.GITHUB_ENTERPRISE.toString(), "https://1.0.0.0.86/my_repo", EnvironmentType.LINUX_CONTAINER.toString(), "aws/codebuild/openjdk-8", ComputeType.BUILD_GENERAL1_SMALL.toString(), "invalidCacheType", "", LogsConfigStatusType.ENABLED.toString(), "group", "stream", LogsConfigStatusType.ENABLED.toString(), "location", - "arn:aws:s3:::my_bucket/certificate.pem", "my_service_role", BooleanValue.False.toString(), BooleanValue.False.toString()); + "arn:aws:s3:::my_bucket/certificate.pem", "my_service_role", BooleanValue.False.toString(), BooleanValue.False.toString(), BooleanValue.False.toString()); ArgumentCaptor savedResult = ArgumentCaptor.forClass(Result.class); test.perform(build, ws, launcher, listener, mockStepContext); @@ -241,7 +241,7 @@ public void testCloudWatchLogsStatusOverrideException() throws Exception { "[{k, v}]", "[{k, p}]", "buildspec.yml", "5", SourceType.GITHUB_ENTERPRISE.toString(), "https://1.0.0.0.86/my_repo", EnvironmentType.LINUX_CONTAINER.toString(), "aws/codebuild/openjdk-8", ComputeType.BUILD_GENERAL1_SMALL.toString(), CacheType.NO_CACHE.toString(), "", "invalidCloudWatchLogsStatus", "group", "stream", LogsConfigStatusType.ENABLED.toString(), "location", - "arn:aws:s3:::my_bucket/certificate.pem", "my_service_role", BooleanValue.False.toString(), BooleanValue.False.toString()); + "arn:aws:s3:::my_bucket/certificate.pem", "my_service_role", BooleanValue.False.toString(), BooleanValue.False.toString(), BooleanValue.False.toString()); ArgumentCaptor savedResult = ArgumentCaptor.forClass(Result.class); test.perform(build, ws, launcher, listener, mockStepContext); @@ -262,7 +262,7 @@ public void testS3LogsStatusOverrideException() throws Exception { "[{k, v}]", "[{k, p}]", "buildspec.yml", "5", SourceType.GITHUB_ENTERPRISE.toString(), "https://1.0.0.0.86/my_repo", EnvironmentType.LINUX_CONTAINER.toString(), "aws/codebuild/openjdk-8", ComputeType.BUILD_GENERAL1_SMALL.toString(), CacheType.NO_CACHE.toString(), "", LogsConfigStatusType.ENABLED.toString(), "group", "stream", "invalidS3LogsStatus", "location", - "arn:aws:s3:::my_bucket/certificate.pem", "my_service_role", BooleanValue.False.toString(), BooleanValue.False.toString()); + "arn:aws:s3:::my_bucket/certificate.pem", "my_service_role", BooleanValue.False.toString(), BooleanValue.False.toString(), BooleanValue.False.toString()); ArgumentCaptor savedResult = ArgumentCaptor.forClass(Result.class); test.perform(build, ws, launcher, listener, mockStepContext); @@ -283,7 +283,7 @@ public void testSourceTypeOverrideException() throws Exception { "[{k, v}]", "[{k, p}]", "buildspec.yml", "5", "invalidSourceType", "https://1.0.0.0.86/my_repo", EnvironmentType.LINUX_CONTAINER.toString(), "aws/codebuild/openjdk-8", ComputeType.BUILD_GENERAL1_SMALL.toString(), CacheType.NO_CACHE.toString(), "", LogsConfigStatusType.ENABLED.toString(), "group", "stream", LogsConfigStatusType.ENABLED.toString(), "location", - "arn:aws:s3:::my_bucket/certificate.pem", "my_service_role", BooleanValue.False.toString(), BooleanValue.False.toString()); + "arn:aws:s3:::my_bucket/certificate.pem", "my_service_role", BooleanValue.False.toString(), BooleanValue.False.toString(), BooleanValue.False.toString()); ArgumentCaptor savedResult = ArgumentCaptor.forClass(Result.class); test.perform(build, ws, launcher, listener, mockStepContext); @@ -304,7 +304,7 @@ public void testEnvironmentTypeOverrideException() throws Exception { "[{k, v}]", "[{k, p}]", "buildspec.yml", "5", SourceType.GITHUB_ENTERPRISE.toString(), "https://1.0.0.0.86/my_repo", "invalidEnvironmentType", "aws/codebuild/openjdk-8", ComputeType.BUILD_GENERAL1_SMALL.toString(), CacheType.NO_CACHE.toString(), "", LogsConfigStatusType.ENABLED.toString(), "group", "stream", LogsConfigStatusType.ENABLED.toString(), "location", - "arn:aws:s3:::my_bucket/certificate.pem", "my_service_role", BooleanValue.False.toString(), BooleanValue.False.toString()); + "arn:aws:s3:::my_bucket/certificate.pem", "my_service_role", BooleanValue.False.toString(), BooleanValue.False.toString(), BooleanValue.False.toString()); ArgumentCaptor savedResult = ArgumentCaptor.forClass(Result.class); test.perform(build, ws, launcher, listener, mockStepContext); @@ -329,7 +329,7 @@ public void testBuildParameters() throws Exception { "[{k, v}]", "", "buildspec.yml", "5", SourceType.GITHUB_ENTERPRISE.toString(), "https://1.0.0.0.86/my_repo", EnvironmentType.LINUX_CONTAINER.toString(), "aws/codebuild/openjdk-8", ComputeType.BUILD_GENERAL1_SMALL.toString(), CacheType.NO_CACHE.toString(), "", LogsConfigStatusType.ENABLED.toString(), "group", "stream", LogsConfigStatusType.ENABLED.toString(), "location", - "arn:aws:s3:::my_bucket/certificate.pem", "my_service_role", BooleanValue.False.toString(), BooleanValue.False.toString()); + "arn:aws:s3:::my_bucket/certificate.pem", "my_service_role", BooleanValue.False.toString(), BooleanValue.False.toString(), BooleanValue.False.toString()); cb.perform(build, ws, launcher, listener, mockStepContext); diff --git a/src/test/java/CodeBuilderTest.java b/src/test/java/CodeBuilderTest.java index 94283a3..7008821 100644 --- a/src/test/java/CodeBuilderTest.java +++ b/src/test/java/CodeBuilderTest.java @@ -88,7 +88,7 @@ protected CodeBuilder createDefaultCodeBuilder() { "buildspec.yml", "5", SourceType.GITHUB_ENTERPRISE.toString(), "https://1.0.0.0.86/my_repo", EnvironmentType.LINUX_CONTAINER.toString(), "aws/codebuild/openjdk-8", ComputeType.BUILD_GENERAL1_SMALL.toString(), CacheType.NO_CACHE.toString(), "", LogsConfigStatusType.ENABLED.toString(), "group", "stream", LogsConfigStatusType.ENABLED.toString(), "location", - "arn:aws:s3:::my_bucket/certificate.pem", "my_service_role", BooleanValue.False.toString(), BooleanValue.False.toString()); + "arn:aws:s3:::my_bucket/certificate.pem", "my_service_role", BooleanValue.False.toString(), BooleanValue.False.toString(), BooleanValue.False.toString()); // It will be a mock factory during testing. return cb;