From 04ed41c41d224d47ef5168a68505fc88c2f3e5bd Mon Sep 17 00:00:00 2001 From: Qi Chen Date: Wed, 31 Jan 2024 15:41:13 -0600 Subject: [PATCH] ENH: allow disable secret refreshment (#3990) * ENH: allow disable secret refreshment Signed-off-by: George Chen --- .../aws/AwsSecretManagerConfiguration.java | 8 +++++ .../plugins/aws/AwsSecretPlugin.java | 14 ++++---- .../AwsSecretManagerConfigurationTest.java | 14 ++++++++ .../plugins/aws/AwsSecretPluginIT.java | 35 +++++++++++++++++++ ...r-configuration-null-refresh-interval.yaml | 2 ++ 5 files changed, 67 insertions(+), 6 deletions(-) create mode 100644 data-prepper-plugins/aws-plugin/src/test/resources/test-aws-secret-manager-configuration-null-refresh-interval.yaml diff --git a/data-prepper-plugins/aws-plugin/src/main/java/org/opensearch/dataprepper/plugins/aws/AwsSecretManagerConfiguration.java b/data-prepper-plugins/aws-plugin/src/main/java/org/opensearch/dataprepper/plugins/aws/AwsSecretManagerConfiguration.java index 360ff45883..1aebb13a51 100644 --- a/data-prepper-plugins/aws-plugin/src/main/java/org/opensearch/dataprepper/plugins/aws/AwsSecretManagerConfiguration.java +++ b/data-prepper-plugins/aws-plugin/src/main/java/org/opensearch/dataprepper/plugins/aws/AwsSecretManagerConfiguration.java @@ -42,9 +42,13 @@ public class AwsSecretManagerConfiguration { private String awsStsRoleArn; @JsonProperty("refresh_interval") + @NotNull(message = "refresh_interval must not be null") @DurationMin(hours = 1L, message = "Refresh interval must be at least 1 hour.") private Duration refreshInterval = Duration.ofHours(1L); + @JsonProperty("disable_refresh") + private boolean disableRefresh = false; + public String getAwsSecretId() { return awsSecretId; } @@ -57,6 +61,10 @@ public Duration getRefreshInterval() { return refreshInterval; } + public boolean isDisableRefresh() { + return disableRefresh; + } + public SecretsManagerClient createSecretManagerClient() { return SecretsManagerClient.builder() .credentialsProvider(authenticateAwsConfiguration()) diff --git a/data-prepper-plugins/aws-plugin/src/main/java/org/opensearch/dataprepper/plugins/aws/AwsSecretPlugin.java b/data-prepper-plugins/aws-plugin/src/main/java/org/opensearch/dataprepper/plugins/aws/AwsSecretPlugin.java index 5f32182cb3..552106adb9 100644 --- a/data-prepper-plugins/aws-plugin/src/main/java/org/opensearch/dataprepper/plugins/aws/AwsSecretPlugin.java +++ b/data-prepper-plugins/aws-plugin/src/main/java/org/opensearch/dataprepper/plugins/aws/AwsSecretPlugin.java @@ -59,12 +59,14 @@ public void apply(final ExtensionPoints extensionPoints) { private void submitSecretsRefreshJobs(final AwsSecretPluginConfig awsSecretPluginConfig, final SecretsSupplier secretsSupplier) { awsSecretPluginConfig.getAwsSecretManagerConfigurationMap().forEach((key, value) -> { - final SecretsRefreshJob secretsRefreshJob = new SecretsRefreshJob( - key, secretsSupplier, pluginConfigPublisher, pluginMetrics); - final long period = value.getRefreshInterval().toSeconds(); - final long jitterDelay = ThreadLocalRandom.current().nextLong(60L); - scheduledExecutorService.scheduleAtFixedRate(secretsRefreshJob, period + jitterDelay, - period, TimeUnit.SECONDS); + if (!value.isDisableRefresh()) { + final SecretsRefreshJob secretsRefreshJob = new SecretsRefreshJob( + key, secretsSupplier, pluginConfigPublisher, pluginMetrics); + final long period = value.getRefreshInterval().toSeconds(); + final long jitterDelay = ThreadLocalRandom.current().nextLong(60L); + scheduledExecutorService.scheduleAtFixedRate(secretsRefreshJob, period + jitterDelay, + period, TimeUnit.SECONDS); + } }); } diff --git a/data-prepper-plugins/aws-plugin/src/test/java/org/opensearch/dataprepper/plugins/aws/AwsSecretManagerConfigurationTest.java b/data-prepper-plugins/aws-plugin/src/test/java/org/opensearch/dataprepper/plugins/aws/AwsSecretManagerConfigurationTest.java index 59c310c94b..38c9159fc4 100644 --- a/data-prepper-plugins/aws-plugin/src/test/java/org/opensearch/dataprepper/plugins/aws/AwsSecretManagerConfigurationTest.java +++ b/data-prepper-plugins/aws-plugin/src/test/java/org/opensearch/dataprepper/plugins/aws/AwsSecretManagerConfigurationTest.java @@ -85,6 +85,7 @@ void testAwsSecretManagerConfigurationDefault() throws IOException { assertThat(awsSecretManagerConfiguration.getAwsSecretId(), equalTo("test-secret")); assertThat(awsSecretManagerConfiguration.getAwsRegion(), equalTo(Region.US_EAST_1)); assertThat(awsSecretManagerConfiguration.getRefreshInterval(), equalTo(Duration.ofHours(1))); + assertThat(awsSecretManagerConfiguration.isDisableRefresh(), is(false)); } @Test @@ -100,6 +101,19 @@ void testAwsSecretManagerConfigurationInvalidRefreshInterval() throws IOExceptio assertThat(violation.getMessage(), equalTo("Refresh interval must be at least 1 hour.")); } + @Test + void testAwsSecretManagerConfigurationNullRefreshInterval() throws IOException { + final InputStream inputStream = AwsSecretPluginConfigTest.class.getResourceAsStream( + "/test-aws-secret-manager-configuration-null-refresh-interval.yaml"); + final AwsSecretManagerConfiguration awsSecretManagerConfiguration = objectMapper.readValue( + inputStream, AwsSecretManagerConfiguration.class); + final Set> violations = VALIDATOR.validate( + awsSecretManagerConfiguration); + assertThat(violations.size(), equalTo(1)); + final ConstraintViolation violation = violations.stream().findFirst().get(); + assertThat(violation.getMessage(), equalTo("refresh_interval must not be null")); + } + @Test void testCreateGetSecretValueRequest() throws IOException { when(getSecretValueRequestBuilder.secretId(anyString())).thenReturn(getSecretValueRequestBuilder); diff --git a/data-prepper-plugins/aws-plugin/src/test/java/org/opensearch/dataprepper/plugins/aws/AwsSecretPluginIT.java b/data-prepper-plugins/aws-plugin/src/test/java/org/opensearch/dataprepper/plugins/aws/AwsSecretPluginIT.java index 71e2106461..2f624611a9 100644 --- a/data-prepper-plugins/aws-plugin/src/test/java/org/opensearch/dataprepper/plugins/aws/AwsSecretPluginIT.java +++ b/data-prepper-plugins/aws-plugin/src/test/java/org/opensearch/dataprepper/plugins/aws/AwsSecretPluginIT.java @@ -121,6 +121,41 @@ void testInitializationWithNonNullConfig() { verify(runtime).addShutdownHook(any()); } + @Test + void testInitializationWithDisableRefresh() { + when(awsSecretPluginConfig.getAwsSecretManagerConfigurationMap()).thenReturn( + Map.of(TEST_SECRET_CONFIG_ID, awsSecretManagerConfiguration)); + when(awsSecretManagerConfiguration.isDisableRefresh()).thenReturn(true); + when(awsSecretManagerConfiguration.createSecretManagerClient()).thenReturn(secretsManagerClient); + when(awsSecretManagerConfiguration.createGetSecretValueRequest()).thenReturn(getSecretValueRequest); + when(secretsManagerClient.getSecretValue(eq(getSecretValueRequest))).thenReturn(getSecretValueResponse); + when(getSecretValueResponse.secretString()).thenReturn(UUID.randomUUID().toString()); + try (final MockedStatic executorsMockedStatic = mockStatic(Executors.class); + final MockedStatic runtimeMockedStatic = mockStatic(Runtime.class) + ) { + executorsMockedStatic.when(Executors::newSingleThreadScheduledExecutor) + .thenReturn(scheduledExecutorService); + runtimeMockedStatic.when(Runtime::getRuntime).thenReturn(runtime); + objectUnderTest = new AwsSecretPlugin(awsSecretPluginConfig); + objectUnderTest.apply(extensionPoints); + } + final ArgumentCaptor extensionProviderArgumentCaptor = + ArgumentCaptor.forClass(ExtensionProvider.class); + verify(extensionPoints, times(2)).addExtensionProvider(extensionProviderArgumentCaptor.capture()); + final List actualExtensionProviders = extensionProviderArgumentCaptor.getAllValues(); + assertThat(actualExtensionProviders.get(0), instanceOf(AwsSecretsPluginConfigValueTranslatorExtensionProvider.class)); + final Optional optionalPluginConfigValueTranslator = + actualExtensionProviders.get(0).provideInstance(context); + assertThat(optionalPluginConfigValueTranslator.isPresent(), is(true)); + assertThat(optionalPluginConfigValueTranslator.get(), instanceOf(AwsSecretsPluginConfigValueTranslator.class)); + assertThat(actualExtensionProviders.get(1), instanceOf(AwsSecretsPluginConfigPublisherExtensionProvider.class)); + final Optional optionalPluginConfigPublisher = + actualExtensionProviders.get(1).provideInstance(context); + assertThat(optionalPluginConfigPublisher.isPresent(), is(true)); + verifyNoInteractions(scheduledExecutorService); + verify(runtime).addShutdownHook(any()); + } + @Test void testInitializationWithNullConfig() { objectUnderTest = new AwsSecretPlugin(null); diff --git a/data-prepper-plugins/aws-plugin/src/test/resources/test-aws-secret-manager-configuration-null-refresh-interval.yaml b/data-prepper-plugins/aws-plugin/src/test/resources/test-aws-secret-manager-configuration-null-refresh-interval.yaml new file mode 100644 index 0000000000..9eb1e80920 --- /dev/null +++ b/data-prepper-plugins/aws-plugin/src/test/resources/test-aws-secret-manager-configuration-null-refresh-interval.yaml @@ -0,0 +1,2 @@ +secret_id: test-secret +refresh_interval: null \ No newline at end of file