0

I have a set of canary tests that regularly produce and consume on a Kubernetes Cluster via a SpringBoot Scheduler. I want to add a second test that will do a similar operation on our 2nd Geo-replicated Kubernetes cluster.

However, I cannot seem to change the environment variable CLUSTER_NAME from our default PRODUCTION_0 value. I tried to implement this solution https://stackoverflow.com/a/7201825/10380766 but it still defaults to the PRODUCTION_0 cluster.

Implementation

HeartBeatJobProd

@Component
public class HeartBeatJobProd1 {

    private static final Logger log = LoggerFactory.getLogger(ScheduledTasks.class);
    private static final String CLUSTER_NAME = "PRODUCTION_1";

    @Scheduled(fixedRate = 5000)
    public void execute() throws EventPlatformClientException, InterruptedException, IOException {
        Map<String, String> env = new HashMap<>(System.getenv());
        env.put("CLUSTER_NAME", CLUSTER_NAME);

        try {
            EnvSetter.setEnv(env);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        log.info(CLUSTER_NAME + ": Producer initializing...");
        HeartBeatProducer.produceAll("Heartbeat 1 producer");
        log.info(CLUSTER_NAME + ": Producer executed...");

        log.info(CLUSTER_NAME + ": Consumer initializing...");
        HeartBeatConsumer.consumeUntilTerminated("Heartbeat 1 consumer");
        log.info(CLUSTER_NAME +": Consumer executed...");
    }
}

EnvSetter

public class EnvSetter {

    /**
     * Sets environment variables programmatically.
     *
     * This method uses reflection to access and modify the current environment variables map. It tries two different
     * approaches depending on the Java version running. If the current version of Java has the fields "theEnvironment" and
     * "theCaseInsensitiveEnvironment" inside the "java.lang.ProcessEnvironment" class, it uses those fields to access and
     * modify the current environment variables map. Otherwise, it gets the current environment variables map using
     * System.getenv() and, if it finds the "UnmodifiableMap" class inside the "Collections" class, it uses reflection to
     * access and modify the current environment variables map.
     *
     * @param newEnv the map of new environment variables to set
     * @throws Exception if there is a problem setting the environment variables
     */
    public static void setEnv(Map<String, String> newEnv) throws Exception {
        try {
            // Try to get the class that contains the environment variables
            Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");

            // Get the field that contains the current environment variables
            Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment");
            theEnvironmentField.setAccessible(true);

            // Get the current environment variables map and add the new environment variables to it
            Map<String, String> env = (Map<String, String>) theEnvironmentField.get(null);
            env.putAll(newEnv);

            // Get the field that contains the case-insensitive environment variables
            Field theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment");
            theCaseInsensitiveEnvironmentField.setAccessible(true);

            // Get the case-insensitive environment variables map and add the new environment variables to it
            Map<String, String> ciEnv = (Map<String, String>) theCaseInsensitiveEnvironmentField.get(null);
            ciEnv.putAll(newEnv);
        } catch (NoSuchFieldException e) {
            // If the fields above don't exist (probably running on an older version of Java),
            // we'll try a different approach

            // Get all the classes inside the Collections class
            Class<?>[] classes = Collections.class.getDeclaredClasses();

            // Get the current environment variables map
            Map<String, String> env = System.getenv();

            // Loop through all the classes
            for (Class<?> cl : classes) {
                // If we find the UnmodifiableMap class, get the field that contains the
                // environment variables and add the new environment variables to it
                if ("java.util.Collections$UnmodifiableMap".equals(cl.getName())) {
                    Field field = cl.getDeclaredField("m");
                    field.setAccessible(true);
                    Object obj = field.get(env);
                    Map<String, String> map = (Map<String, String>) obj;
                    map.clear();
                    map.putAll(newEnv);
                }
            }
        }
    }
}
Hofbr
  • 868
  • 9
  • 31

0 Answers0