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

Update renewed Jira refresh token back to the secrets store #5324

Merged
merged 19 commits into from
Jan 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
aa7ca59
Introduced PluginConfigVariable interaface to provide ability for the…
san81 Jan 13, 2025
0c34119
renewed access token and refresh tokens are now updated back in the s…
san81 Jan 13, 2025
cc82281
better naming
san81 Jan 13, 2025
2f640df
Merge branch 'opensearch-project:main' into secrets-variable-interface
san81 Jan 13, 2025
64bf7bc
fixing the test cases based on the new PluginConfigVariable attribute…
san81 Jan 13, 2025
4df4fba
improving the coverage
san81 Jan 13, 2025
a384d85
Keeping the existing values in the secret. Just updating an existing key
san81 Jan 14, 2025
2f26378
Merge branch 'opensearch-project:main' into secrets-variable-interface
san81 Jan 15, 2025
ca1ec88
Allowing secrets manager update without a key and also some additiona…
san81 Jan 15, 2025
2f98ebc
isUpdatable boolean is introduced and its corresponding tests
san81 Jan 15, 2025
f8802e5
additional coverage
san81 Jan 16, 2025
eb2e431
implementing newly added method
san81 Jan 16, 2025
76a136a
switching PluginConfigVariable from refreshToken to accessToken
san81 Jan 16, 2025
188264e
Only the master node is responsible for Token refresh
san81 Jan 16, 2025
009eafe
Added addition parameter in the API to accept the secrets version to …
san81 Jan 16, 2025
78de3aa
better naming
san81 Jan 16, 2025
7b15c95
removing setting a versionId for idempotency
san81 Jan 16, 2025
1d14234
removed constructor argument to PluginConfigVariable
san81 Jan 16, 2025
8b946af
Merge branch 'opensearch-project:main' into secrets-variable-interface
san81 Jan 17, 2025
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
*/
package org.opensearch.dataprepper.model.plugin;

/**
* Exception thrown when a secret could not be updated.
*
* @since 2.11
*/
public class FailedToUpdatePluginConfigValueException extends RuntimeException {

public FailedToUpdatePluginConfigValueException(final String message) {
super(message);
}

public FailedToUpdatePluginConfigValueException(final String message, Throwable e) {
super(message, e);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,48 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
*/
package org.opensearch.dataprepper.model.plugin;

/**
* Interface for a Plugin configuration value translator.
* It translates a string expression that is describing a secret store Id and secret Key in to a secretValue
* extracted from corresponding secret store.
*
* @since 2.0
*/

public interface PluginConfigValueTranslator {
/**
* Translates a string expression that is describing a secret store Id and secret Key in to a secretValue
* extracted from corresponding secret store.
* Example expression: ${{aws_secrets:secretId:secretKey}}
*
* @param value the string value to translate
* @return the translated object
*/
Object translate(final String value);

/**
* Returns the prefix for this translator.
*
* @return the prefix for this translator
*/
String getPrefix();

/**
* Translates a string expression that is describing a secret store Id and secret Key in to an instance
* of PluginConfigVariable with secretValue extracted from corresponding secret store. Additionally,
* this PluginConfigVariable helps with updating the secret value in the secret store, if required.
* Example expression: ${{aws_secrets:secretId:secretKey}}
*
* @param value the string value to translate
* @return the translated object
*/
PluginConfigVariable translateToPluginConfigVariable(final String value);
san81 marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
*/
package org.opensearch.dataprepper.model.plugin;

/**
* Interface for a Extension Plugin configuration variable.
* It gives access to the details of a defined extension variable.
*
* @since 2.11
*/
public interface PluginConfigVariable {
san81 marked this conversation as resolved.
Show resolved Hide resolved

/**
* Returns the value of this variable.
san81 marked this conversation as resolved.
Show resolved Hide resolved
*
* @return the value of this variable
*/
Object getValue();

/**
* If this variable is updatable, this method helps to set a new value for this variable
san81 marked this conversation as resolved.
Show resolved Hide resolved
*
* @param updatedValue the new value to set
*/
void setValue(Object updatedValue);

/**
* Returns if the variable is updatable.
*
* @return true if this variable is updatable, false otherwise
*/
boolean isUpdatable();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
*/
package org.opensearch.dataprepper.model.plugin;


import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.util.UUID;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;

public class FailedToUpdatePluginConfigValueExceptionTest extends RuntimeException {
private String message;

@BeforeEach
void setUp() {
message = UUID.randomUUID().toString();
}

@Test
void testGetMessage_should_return_correct_message() {
FailedToUpdatePluginConfigValueException failedToUpdateSecretException = new FailedToUpdatePluginConfigValueException(message);
assertThat(failedToUpdateSecretException.getMessage(), equalTo(message));
}

@Test
void testGetMessage_should_return_correct_message_with_throwable() {
RuntimeException cause = new RuntimeException("testException");
FailedToUpdatePluginConfigValueException failedToUpdateSecretException = new FailedToUpdatePluginConfigValueException(message, cause);
assertThat(failedToUpdateSecretException.getMessage(), equalTo(message));
assertThat(failedToUpdateSecretException.getCause(), equalTo(cause));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.opensearch.dataprepper.model.event.EventKey;
import org.opensearch.dataprepper.model.event.EventKeyFactory;
import org.opensearch.dataprepper.model.plugin.PluginConfigVariable;
import org.opensearch.dataprepper.model.types.ByteCount;
import org.opensearch.dataprepper.pipeline.parser.ByteCountDeserializer;
import org.opensearch.dataprepper.pipeline.parser.DataPrepperDurationDeserializer;
Expand All @@ -28,7 +29,7 @@
public class ObjectMapperConfiguration {
static final Set<Class> TRANSLATE_VALUE_SUPPORTED_JAVA_TYPES = Set.of(
String.class, Number.class, Long.class, Short.class, Integer.class, Double.class, Float.class,
Boolean.class, Character.class);
Boolean.class, Character.class, PluginConfigVariable.class);

@Bean(name = "extensionPluginConfigObjectMapper")
ObjectMapper extensionPluginConfigObjectMapper() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.opensearch.dataprepper.model.plugin.PluginConfigValueTranslator;
import org.opensearch.dataprepper.model.plugin.PluginConfigVariable;

import javax.inject.Inject;
import javax.inject.Named;
Expand All @@ -29,8 +30,7 @@ public class VariableExpander {

@Inject
public VariableExpander(
@Named("extensionPluginConfigObjectMapper")
final ObjectMapper objectMapper,
@Named("extensionPluginConfigObjectMapper") final ObjectMapper objectMapper,
final Set<PluginConfigValueTranslator> pluginConfigValueTranslators) {
this.objectMapper = objectMapper;
patternPluginConfigValueTranslatorMap = pluginConfigValueTranslators.stream().collect(Collectors.toMap(
Expand All @@ -48,8 +48,13 @@ public <T> T translate(final JsonParser jsonParser, final Class<T> destinationTy
.filter(entry -> entry.getKey().matches())
.map(entry -> {
final String valueReferenceKey = entry.getKey().group(VALUE_REFERENCE_KEY);
return objectMapper.convertValue(
entry.getValue().translate(valueReferenceKey), destinationType);
if (destinationType.equals(PluginConfigVariable.class)) {
san81 marked this conversation as resolved.
Show resolved Hide resolved
return (T) entry.getValue().translateToPluginConfigVariable(valueReferenceKey);
} else {
return objectMapper.convertValue(
entry.getValue().translate(valueReferenceKey), destinationType);
}

})
.findFirst()
.orElseGet(() -> objectMapper.convertValue(rawValue, destinationType));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.opensearch.dataprepper.model.plugin.PluginConfigValueTranslator;
import org.opensearch.dataprepper.model.plugin.PluginConfigVariable;

import java.io.IOException;
import java.math.BigDecimal;
Expand All @@ -30,6 +31,8 @@

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;

Expand All @@ -43,6 +46,32 @@ class VariableExpanderTest {

private VariableExpander objectUnderTest;

private static Stream<Arguments> getNonStringTypeArguments() {
return Stream.of(Arguments.of(Boolean.class, "true", true),
Arguments.of(Short.class, "2", (short) 2),
Arguments.of(Integer.class, "10", 10),
Arguments.of(Long.class, "200", 200L),
Arguments.of(Double.class, "1.23", 1.23d),
Arguments.of(Float.class, "2.15", 2.15f),
Arguments.of(BigDecimal.class, "2.15", BigDecimal.valueOf(2.15)),
Arguments.of(Map.class, "{}", Collections.emptyMap()));
}

private static Stream<Arguments> getStringTypeArguments() {
final String testRandomValue = "non-secret-prefix-" + RandomStringUtils.randomAlphabetic(5);
return Stream.of(Arguments.of(String.class, String.format("\"%s\"", testRandomValue),
testRandomValue),
Arguments.of(Duration.class, "\"PT15M\"", Duration.parse("PT15M")),
Arguments.of(Boolean.class, "\"true\"", true),
Arguments.of(Short.class, "\"2\"", (short) 2),
Arguments.of(Integer.class, "\"10\"", 10),
Arguments.of(Long.class, "\"200\"", 200L),
Arguments.of(Double.class, "\"1.23\"", 1.23d),
Arguments.of(Float.class, "\"2.15\"", 2.15f),
Arguments.of(BigDecimal.class, "\"2.15\"", BigDecimal.valueOf(2.15)),
Arguments.of(Character.class, "\"c\"", 'c'));
}

@BeforeEach
void setUp() {
objectUnderTest = new VariableExpander(OBJECT_MAPPER, Set.of(pluginConfigValueTranslator));
Expand Down Expand Up @@ -107,29 +136,53 @@ void testTranslateJsonParserWithStringValue_translate_success(
assertThat(actualResult, equalTo(expectedResult));
}

private static Stream<Arguments> getNonStringTypeArguments() {
return Stream.of(Arguments.of(Boolean.class, "true", true),
Arguments.of(Short.class, "2", (short) 2),
Arguments.of(Integer.class, "10", 10),
Arguments.of(Long.class, "200", 200L),
Arguments.of(Double.class, "1.23", 1.23d),
Arguments.of(Float.class, "2.15", 2.15f),
Arguments.of(BigDecimal.class, "2.15", BigDecimal.valueOf(2.15)),
Arguments.of(Map.class, "{}", Collections.emptyMap()));
@Test
void testTranslateJsonParserWithSPluginConfigVariableValue_translate_success() throws IOException {
final String testSecretKey = "testSecretKey";
final String testTranslatorKey = "test_prefix";
final String testSecretReference = String.format("${{%s:%s}}", testTranslatorKey, testSecretKey);
final JsonParser jsonParser = JSON_FACTORY.createParser(String.format("\"%s\"", testSecretReference));
jsonParser.nextToken();
PluginConfigVariable mockPluginConfigVariable = new PluginConfigVariable() {

String secretValue = "samplePluginConfigValue";

@Override
public Object getValue() {
return secretValue;
}

@Override
public void setValue(Object updatedValue) {
this.secretValue = updatedValue.toString();
}

@Override
public boolean isUpdatable() {
return true;
}
};
when(pluginConfigValueTranslator.getPrefix()).thenReturn(testTranslatorKey);
when(pluginConfigValueTranslator.translateToPluginConfigVariable(eq(testSecretKey)))
.thenReturn(mockPluginConfigVariable);
objectUnderTest = new VariableExpander(OBJECT_MAPPER, Set.of(pluginConfigValueTranslator));
final Object actualResult = objectUnderTest.translate(jsonParser, PluginConfigVariable.class);
assertNotNull(actualResult);
assertThat(actualResult, equalTo(mockPluginConfigVariable));
}

private static Stream<Arguments> getStringTypeArguments() {
final String testRandomValue = "non-secret-prefix-" + RandomStringUtils.randomAlphabetic(5);
return Stream.of(Arguments.of(String.class, String.format("\"%s\"", testRandomValue),
testRandomValue),
Arguments.of(Duration.class, "\"PT15M\"", Duration.parse("PT15M")),
Arguments.of(Boolean.class, "\"true\"", true),
Arguments.of(Short.class, "\"2\"", (short) 2),
Arguments.of(Integer.class, "\"10\"", 10),
Arguments.of(Long.class, "\"200\"", 200L),
Arguments.of(Double.class, "\"1.23\"", 1.23d),
Arguments.of(Float.class, "\"2.15\"", 2.15f),
Arguments.of(BigDecimal.class, "\"2.15\"", BigDecimal.valueOf(2.15)),
Arguments.of(Character.class, "\"c\"", 'c'));
@Test
void testTranslateJsonParserWithSPluginConfigVariableValue_translate_failure() throws IOException {
final String testSecretKey = "testSecretKey";
final String testTranslatorKey = "test_prefix";
final String testSecretReference = String.format("${{%s:%s}}", testTranslatorKey, testSecretKey);
final JsonParser jsonParser = JSON_FACTORY.createParser(String.format("\"%s\"", testSecretReference));
jsonParser.nextToken();
when(pluginConfigValueTranslator.getPrefix()).thenReturn(testTranslatorKey);
when(pluginConfigValueTranslator.translateToPluginConfigVariable(eq(testSecretKey)))
.thenThrow(IllegalArgumentException.class);
objectUnderTest = new VariableExpander(OBJECT_MAPPER, Set.of(pluginConfigValueTranslator));
assertThrows(IllegalArgumentException.class,
() -> objectUnderTest.translate(jsonParser, PluginConfigVariable.class));
}
}
2 changes: 1 addition & 1 deletion data-prepper-plugins/aws-plugin/build.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

dependencies {
implementation project(':data-prepper-api')
implementation project(':data-prepper-plugins:aws-plugin-api')
Expand All @@ -11,6 +10,7 @@ dependencies {
implementation 'org.hibernate.validator:hibernate-validator:8.0.2.Final'
testImplementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml'
testImplementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310'
testImplementation project(':data-prepper-test-common')
}

test {
Expand Down
Loading
Loading