Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-18234

environment var not set on job process, and not propagated to forked sub-process

    Details

    • Similar Issues:

      Description

      the EnvInject plugin does not really set the "environment variables" at the OS level, using native POSIX call "putenv()".
      It is only available in some jenkins sub-tasks when calling appropriate jenkins API to exec tasks... but not when calling plain old java code "System.exec()" within a Mojo.... so most Mojo don't work (my problem was when using maven-dotnet-plugin, that forks to execute "Msbuild.exe")

      When doing few search over google to set an environment variable in java, I found a piece of code that might be "portable enough", using JNA native calls to standards dlls (msvcrt on Windows / libc on Linux, which solve 100% of my needs)

      It simply exposes a method "putenv()" to be called as this:

      SetEnvUtil.putenv("testvar", "123", 1);

      So my request is to add such calls within the EnvInject plugin, but I don't know how to patch exactly the EnvInject jenkins plugin

      It depends on the JNA jar, for example using the maven dependency

          <dependency>
      	  <groupId>net.java.dev.jna</groupId>
      	  <artifactId>jna</artifactId>
      	  <version>3.4.0</version>
          </dependency>
      

      Here is the utility class

      SetEnvUtil.java
      import com.sun.jna.Library;
      import com.sun.jna.Native;
      
      public class SetEnvUtil {
      
          // Inside the Environment class...
          public interface WinLibC extends Library {
              public String getenv(String name);
              public int _putenv(String name);
          }
      
          public interface LinuxLibC extends Library {
              public String getenv(String name);
              public int setenv(String name, String value, int overwrite);
              public int unsetenv(String name);
          }
      
          private static Object libc;
          static {
              String osName = System.getProperty("os.name");
              if (osName.equals("Linux")) {
                  libc = Native.loadLibrary("c", LinuxLibC.class);
              } else {
                  libc = Native.loadLibrary("msvcrt", WinLibC.class);
              }
          }
      
          public static String getenv(String name) {
              if (libc instanceof LinuxLibC) {
                  return ((LinuxLibC) libc).getenv(name);
              } else {
                  return ((WinLibC) libc).getenv(name);
              }
          }
          
          public static int setenv(String name, String value, int overwrite) {
              if (libc instanceof LinuxLibC) {
                  return ((LinuxLibC) libc).setenv(name, value, overwrite);
              } else {
                  return ((WinLibC) libc)._putenv(name + "=" + value);
              }
          }
      
          public static int unsetenv(String name) {
              if (libc instanceof LinuxLibC) {
                  return ((LinuxLibC) libc).unsetenv(name);
              } else {
                  return ((WinLibC) libc)._putenv(name + "=");
              }
          }
      
      }
      

      I have done a simple Main for testing purpose, so you can convinced it works simply:

      SetEnvMain.java
      public class SetEnvMain {
      
          public static final String TEST_VAR_NAME  = "TEST_VAR";
      
          public static void main(String[] args) {
              dump("before setenv() ... ");
              
              // *** first setenv()  : add new env var 
              SetEnvUtil.setenv(TEST_VAR_NAME , "123", 1);
              
              dump("after setenv(\"" + TEST_VAR_NAME + ", \"123\") ... ");
      
              // *** second call setenv()  : override existing var 
              SetEnvUtil.setenv(TEST_VAR_NAME , "456", 1);
              
              dump("after setenv(\"" + TEST_VAR_NAME + ", \"456\") ... ");
          }
          
          public static void dump(String messagePrefix) {
              String var_native = SetEnvUtil.getenv(TEST_VAR_NAME);
              String var_cached = System.getenv(TEST_VAR_NAME); // FALSE... cached by java!
              System.out.println(messagePrefix + " " + TEST_VAR_NAME + ": " + var_native + ", (cached): " + var_cached);
          }
          
      }
      

        Attachments

          Activity

          Hide
          ravi116 Ravi Varanasi added a comment -

          Is there a workaround for this ? Can you set the environment variables through Manage Jenkins ?

          Show
          ravi116 Ravi Varanasi added a comment - Is there a workaround for this ? Can you set the environment variables through Manage Jenkins ?
          Hide
          arnaud_nauwynck Arnaud Nauwynck added a comment -

          I did not found a simple solution.
          My workaround was to have several jenkins slave and schedule jobs with different env variables to different slaves! I am still interested by a better solution.

          Show
          arnaud_nauwynck Arnaud Nauwynck added a comment - I did not found a simple solution. My workaround was to have several jenkins slave and schedule jobs with different env variables to different slaves! I am still interested by a better solution.

            People

            • Assignee:
              gbois Gregory Boissinot
              Reporter:
              arnaud_nauwynck Arnaud Nauwynck
            • Votes:
              3 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

              • Created:
                Updated: