-
Notifications
You must be signed in to change notification settings - Fork 270
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support for JAVA_OPTS_APPEND when creating app deployment
- Loading branch information
1 parent
1f99c3d
commit 8237eac
Showing
4 changed files
with
246 additions
and
0 deletions.
There are no files selected for viewing
1 change: 1 addition & 0 deletions
1
operator/controller/src/main/java/io/apicurio/registry/operator/EnvironmentVariables.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
137 changes: 137 additions & 0 deletions
137
operator/controller/src/main/java/io/apicurio/registry/operator/utils/JavaOptsAppend.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
package io.apicurio.registry.operator.utils; | ||
|
||
import io.apicurio.registry.operator.EnvironmentVariables; | ||
import io.fabric8.kubernetes.api.model.EnvVar; | ||
import io.fabric8.kubernetes.api.model.EnvVarBuilder; | ||
|
||
import java.util.Set; | ||
import java.util.TreeSet; | ||
|
||
/** | ||
* Models the value of the JAVA_OPTS_APPEND environment variable. This is | ||
* a convenient way to merge values and handle conflicts. | ||
*/ | ||
public class JavaOptsAppend { | ||
|
||
private final Set<String> opts = new TreeSet<>(); | ||
|
||
/** | ||
* Called to set the initial value of the ENV var using an existing | ||
* value, typically configured in the "env" section of the CR. This | ||
* will be a value set by the app deployer, with runtime options | ||
* they want to have enabled. | ||
*/ | ||
public void setOptsFromEnvVar(String value) { | ||
opts.clear(); | ||
if (value != null && !value.trim().isEmpty()) { | ||
opts.addAll(Set.of(value.split(" "))); | ||
} | ||
} | ||
|
||
/** | ||
* Converts this object into an {@link EnvVar} instance. | ||
*/ | ||
public EnvVar toEnvVar() { | ||
EnvVarBuilder builder = new EnvVarBuilder(); | ||
return builder | ||
.withName(EnvironmentVariables.JAVA_OPTS_APPEND) | ||
.withValue(String.join(" ", opts)) | ||
.build(); | ||
} | ||
|
||
/** | ||
* Add another option. If the option already exists, do nothing. Whether the | ||
* option already exists may depend on the option. Custom logic may be needed | ||
* to properly support certain options. | ||
*/ | ||
public void addOpt(String optValue) { | ||
if (!containsOpt(optValue)) { | ||
opts.add(optValue); | ||
} | ||
} | ||
|
||
/** | ||
* Returns 'true' if there are no options set. | ||
*/ | ||
public boolean isEmpty() { | ||
return opts.isEmpty(); | ||
} | ||
|
||
/** | ||
* Returns 'true' if the option already exists. The logic for whether an option | ||
* already exists depends on the option. | ||
*/ | ||
public boolean containsOpt(String optValue) { | ||
if (optValue == null || optValue.trim().isEmpty()) { | ||
return false; | ||
} | ||
if (optValue.startsWith("-D") || optValue.startsWith("-XX:")) { | ||
return containsValuedParameter(optValue); | ||
} | ||
if (optValue.startsWith("-Xms")) { | ||
return containsXms(); | ||
} | ||
if (optValue.startsWith("-Xmx")) { | ||
return containsXmx(); | ||
} | ||
if (optValue.startsWith("-javaagent:")) { | ||
return containsJavaAgent(); | ||
} | ||
if (optValue.startsWith("-agentlib:")) { | ||
return containsAgentLib(); | ||
} | ||
return opts.contains(optValue); | ||
} | ||
|
||
/** | ||
* Returns 'true' if an option with the given prefix already exists. | ||
*/ | ||
public boolean containsOptByPrefix(String prefix) { | ||
return this.opts.stream().anyMatch(s -> s.startsWith(prefix)); | ||
} | ||
|
||
/** | ||
* Checks if an option of one of the following form exists already: | ||
* <ul> | ||
* <li>-Dmy.property.name=foo</li> | ||
* <li>-XX:OptionName=bar</li> | ||
* </ul> | ||
* Looks for another option with the same name but potentially different value. | ||
*/ | ||
private boolean containsValuedParameter(String optValue) { | ||
if (optValue.contains("=")) { | ||
String prefix = optValue.substring(0, optValue.indexOf("=")); | ||
return containsOptByPrefix(prefix); | ||
} | ||
return opts.contains(optValue); | ||
} | ||
|
||
/** | ||
* Checks for an option of the form "-Xms512m". | ||
*/ | ||
private boolean containsXms() { | ||
return containsOptByPrefix("-Xms"); | ||
} | ||
|
||
/** | ||
* Checks for an option of the form "-Xmx1024m". | ||
*/ | ||
private boolean containsXmx() { | ||
return containsOptByPrefix("-Xmx"); | ||
} | ||
|
||
/** | ||
* Checks for an option of the form "-javaagent:/path/to/agent.jar" | ||
*/ | ||
private boolean containsJavaAgent() { | ||
return containsOptByPrefix("-javaagent:"); | ||
} | ||
|
||
/** | ||
* Checks for an option of the form "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005" | ||
*/ | ||
private boolean containsAgentLib() { | ||
return containsOptByPrefix("-agentlib:"); | ||
} | ||
|
||
} |
96 changes: 96 additions & 0 deletions
96
operator/controller/src/test/java/io/apicurio/registry/operator/unit/JavaOptsAppendTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
package io.apicurio.registry.operator.unit; | ||
|
||
import io.apicurio.registry.operator.EnvironmentVariables; | ||
import io.apicurio.registry.operator.utils.JavaOptsAppend; | ||
import org.assertj.core.api.Assertions; | ||
import org.junit.jupiter.api.Test; | ||
|
||
public class JavaOptsAppendTest { | ||
|
||
@Test | ||
public void testJavaOpts_Empty() throws Exception { | ||
JavaOptsAppend optsAppend = new JavaOptsAppend(); | ||
Assertions.assertThat(optsAppend.isEmpty()).isTrue(); | ||
Assertions.assertThat(optsAppend.toEnvVar()).isNotNull(); | ||
Assertions.assertThat(optsAppend.toEnvVar().getName()).isEqualTo(EnvironmentVariables.JAVA_OPTS_APPEND); | ||
Assertions.assertThat(optsAppend.toEnvVar().getValue()).isEqualTo(""); | ||
} | ||
|
||
@Test | ||
public void testJavaOpts_EmptyEnvVar() throws Exception { | ||
JavaOptsAppend optsAppend = new JavaOptsAppend(); | ||
optsAppend.setOptsFromEnvVar(""); | ||
Assertions.assertThat(optsAppend.isEmpty()).isTrue(); | ||
Assertions.assertThat(optsAppend.toEnvVar()).isNotNull(); | ||
Assertions.assertThat(optsAppend.toEnvVar().getName()).isEqualTo(EnvironmentVariables.JAVA_OPTS_APPEND); | ||
Assertions.assertThat(optsAppend.toEnvVar().getValue()).isEqualTo(""); | ||
} | ||
|
||
@Test | ||
public void testJavaOpts_EnvVar() throws Exception { | ||
JavaOptsAppend optsAppend = new JavaOptsAppend(); | ||
optsAppend.setOptsFromEnvVar("-Xms512m -Xmx1g -XX:+UseG1GC -Dspring.profiles.active=prod"); | ||
Assertions.assertThat(optsAppend.isEmpty()).isFalse(); | ||
Assertions.assertThat(optsAppend.toEnvVar()).isNotNull(); | ||
Assertions.assertThat(optsAppend.toEnvVar().getName()).isEqualTo(EnvironmentVariables.JAVA_OPTS_APPEND); | ||
Assertions.assertThat(optsAppend.toEnvVar().getValue()).isEqualTo("-Dspring.profiles.active=prod -XX:+UseG1GC -Xms512m -Xmx1g"); | ||
} | ||
|
||
@Test | ||
public void testJavaOpts_EnvVarWithAdds() throws Exception { | ||
JavaOptsAppend optsAppend = new JavaOptsAppend(); | ||
optsAppend.setOptsFromEnvVar("-Xms512m -Xmx1g"); | ||
optsAppend.addOpt("-XX:+UseG1GC"); | ||
optsAppend.addOpt("-Dspring.profiles.active=prod"); | ||
Assertions.assertThat(optsAppend.isEmpty()).isFalse(); | ||
Assertions.assertThat(optsAppend.toEnvVar()).isNotNull(); | ||
Assertions.assertThat(optsAppend.toEnvVar().getName()).isEqualTo(EnvironmentVariables.JAVA_OPTS_APPEND); | ||
Assertions.assertThat(optsAppend.toEnvVar().getValue()).isEqualTo("-Dspring.profiles.active=prod -XX:+UseG1GC -Xms512m -Xmx1g"); | ||
} | ||
|
||
@Test | ||
public void testJavaOpts_ParamConflict() throws Exception { | ||
JavaOptsAppend optsAppend = new JavaOptsAppend(); | ||
optsAppend.addOpt("-Dspring.profiles.active=prod"); | ||
optsAppend.addOpt("-Dspring.profiles.active=dev"); | ||
Assertions.assertThat(optsAppend.toEnvVar().getValue()).isEqualTo("-Dspring.profiles.active=prod"); | ||
|
||
optsAppend = new JavaOptsAppend(); | ||
optsAppend.addOpt("-XX:ReservedCodeCacheSize=128m"); | ||
optsAppend.addOpt("-XX:ReservedCodeCacheSize=256m"); | ||
Assertions.assertThat(optsAppend.toEnvVar().getValue()).isEqualTo("-XX:ReservedCodeCacheSize=128m"); | ||
|
||
optsAppend = new JavaOptsAppend(); | ||
optsAppend.addOpt("-XX:ReservedCodeCacheSize=128m"); | ||
optsAppend.addOpt("-XX:ReservedCodeCacheSize=256m"); | ||
optsAppend.addOpt("-XX:+HeapDumpOnOutOfMemoryError"); | ||
optsAppend.addOpt("-XX:+HeapDumpOnOutOfMemoryError"); | ||
optsAppend.addOpt("-XX:HeapDumpPath=/path/to/dumps/"); | ||
optsAppend.addOpt("-XX:HeapDumpPath=/path/to/other-dumps/"); | ||
Assertions.assertThat(optsAppend.toEnvVar().getValue()).isEqualTo("-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/dumps/ -XX:ReservedCodeCacheSize=128m"); | ||
|
||
optsAppend = new JavaOptsAppend(); | ||
optsAppend.setOptsFromEnvVar("-XX:ReservedCodeCacheSize=128m -XX:+HeapDumpOnOutOfMemoryError"); | ||
optsAppend.addOpt("-XX:ReservedCodeCacheSize=256m"); | ||
optsAppend.addOpt("-XX:+HeapDumpOnOutOfMemoryError"); | ||
optsAppend.addOpt("-XX:HeapDumpPath=/path/to/dumps/"); | ||
optsAppend.addOpt("-XX:HeapDumpPath=/path/to/other-dumps/"); | ||
Assertions.assertThat(optsAppend.toEnvVar().getValue()).isEqualTo("-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/dumps/ -XX:ReservedCodeCacheSize=128m"); | ||
} | ||
|
||
@Test | ||
public void testJavaOpts_Conflicts() throws Exception { | ||
JavaOptsAppend optsAppend = new JavaOptsAppend(); | ||
optsAppend.setOptsFromEnvVar("-Xms512m -Xmx1g -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005"); | ||
optsAppend.addOpt("-Xms256m"); | ||
optsAppend.addOpt("-Xmx2g"); | ||
optsAppend.addOpt("-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:12345"); | ||
optsAppend.addOpt("-javaagent:/path/to/agent.jar"); | ||
optsAppend.addOpt("-javaagent:/path/to/alt_agent.jar"); | ||
Assertions.assertThat(optsAppend.isEmpty()).isFalse(); | ||
Assertions.assertThat(optsAppend.toEnvVar()).isNotNull(); | ||
Assertions.assertThat(optsAppend.toEnvVar().getName()).isEqualTo(EnvironmentVariables.JAVA_OPTS_APPEND); | ||
Assertions.assertThat(optsAppend.toEnvVar().getValue()).isEqualTo("-Xms512m -Xmx1g -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 -javaagent:/path/to/agent.jar"); | ||
} | ||
|
||
} |