azkaban-developers

Details

diff --git a/azkaban-common/src/main/java/azkaban/executor/ExecutorManager.java b/azkaban-common/src/main/java/azkaban/executor/ExecutorManager.java
index 1a46230..3eb335b 100644
--- a/azkaban-common/src/main/java/azkaban/executor/ExecutorManager.java
+++ b/azkaban-common/src/main/java/azkaban/executor/ExecutorManager.java
@@ -101,7 +101,7 @@ public class ExecutorManager extends EventHandler implements
   private ExecutingManagerUpdaterThread executingManager;
   // 12 weeks
   private static final long DEFAULT_EXECUTION_LOGS_RETENTION_MS = 3 * 4 * 7
-      * 24 * 60 * 60 * 1000L;
+      * 24 * 60 * 60 * 1000l;
   private long lastCleanerThreadCheckTime = -1;
 
   private long lastThreadCheckTime = -1;
@@ -1982,4 +1982,4 @@ public class ExecutorManager extends EventHandler implements
       queuedFlows.enqueue(exflow, reference);
     }
   }
-}
+}
\ No newline at end of file
diff --git a/azkaban-common/src/main/java/azkaban/executor/JdbcExecutorLoader.java b/azkaban-common/src/main/java/azkaban/executor/JdbcExecutorLoader.java
index a588cca..d6ffb4b 100644
--- a/azkaban-common/src/main/java/azkaban/executor/JdbcExecutorLoader.java
+++ b/azkaban-common/src/main/java/azkaban/executor/JdbcExecutorLoader.java
@@ -104,7 +104,7 @@ public class JdbcExecutorLoader extends AbstractJdbcLoader implements
           runner.query(connection, LastInsertID.LAST_INSERT_ID,
               new LastInsertID());
 
-      if (id == -1L) {
+      if (id == -1l) {
         throw new ExecutorManagerException(
             "Execution id is not properly created.");
       }
@@ -1061,7 +1061,7 @@ public class JdbcExecutorLoader extends AbstractJdbcLoader implements
     @Override
     public Long handle(ResultSet rs) throws SQLException {
       if (!rs.next()) {
-        return -1L;
+        return -1l;
       }
       long id = rs.getLong(1);
       return id;
diff --git a/azkaban-common/src/main/java/azkaban/jobExecutor/ProcessJob.java b/azkaban-common/src/main/java/azkaban/jobExecutor/ProcessJob.java
index 6881c98..f71e483 100644
--- a/azkaban-common/src/main/java/azkaban/jobExecutor/ProcessJob.java
+++ b/azkaban-common/src/main/java/azkaban/jobExecutor/ProcessJob.java
@@ -48,9 +48,11 @@ public class ProcessJob extends AbstractProcessJob {
       "memCheck.freeMemDecrAmt";
 
   public static final String AZKABAN_MEMORY_CHECK = "azkaban.memory.check";
-  
+
   public static final String NATIVE_LIB_FOLDER = "azkaban.native.lib";
   public static final String EXECUTE_AS_USER = "execute.as.user";
+  public static final String EXECUTE_AS_USER_OVERRIDE =
+      "execute.as.user.override";
   public static final String USER_TO_PROXY = "user.to.proxy";
   public static final String KRB5CCNAME = "KRB5CCNAME";
 
@@ -86,7 +88,7 @@ public class ProcessJob extends AbstractProcessJob {
                     memPair.getFirst(), memPair.getSecond(), getId()));
       }
     }
-    
+
     List<String> commands = null;
     try {
       commands = getCommandList();
@@ -102,29 +104,45 @@ public class ProcessJob extends AbstractProcessJob {
 
     info(commands.size() + " commands to execute.");
     File[] propFiles = initPropsFiles();
-    
+
     // change krb5ccname env var so that each job execution gets its own cache
     Map<String, String> envVars = getEnvironmentVariables();
     envVars.put(KRB5CCNAME, getKrb5ccname(jobProps));
-  
-    // determine whether users should be running their jobs as proxyUser/submit user or 
-    // if everybody will run as Azkaban
-    String executeAsUserBinary = null;    
-    boolean isExecuteAsUser = sysProps.getBoolean(EXECUTE_AS_USER, false);    
-    if(isExecuteAsUser){
-    	String nativeLibFolder = sysProps.getString(NATIVE_LIB_FOLDER);
-    	executeAsUserBinary = String.format("%s/%s", nativeLibFolder, "execute-as-user");    	
+
+    // determine whether to run as Azkaban or run as effectiveUser
+    String executeAsUserBinary = null;
+    String effectiveUser = null;
+    boolean isExecuteAsUser = determineExecuteAsUser(sysProps, jobProps);
+
+    if (isExecuteAsUser) {
+      String nativeLibFolder = sysProps.getString(NATIVE_LIB_FOLDER);
+      executeAsUserBinary =
+          String.format("%s/%s", nativeLibFolder, "execute-as-user");
+      effectiveUser = getEffectiveUser(jobProps);
+      if ("root".equals(effectiveUser)) {
+        throw new RuntimeException(
+            "Not permitted to proxy as root through Azkaban");
+      }
     }
-        
+
     for (String command : commands) {
-    	if(isExecuteAsUser){
-    	  command = String.format("%s %s %s", executeAsUserBinary, getEffectiveUser(jobProps), command);
-    	}
-      
-      info("Command: " + command);
-      AzkabanProcessBuilder builder =
-          new AzkabanProcessBuilder(partitionCommandLine(command))
-              .setEnv(envVars).setWorkingDir(getCwd()).setLogger(getLog());
+      AzkabanProcessBuilder builder = null;
+      if (isExecuteAsUser) {
+        command =
+            String.format("%s %s %s", executeAsUserBinary, effectiveUser,
+                command);
+        info("Command: " + command);
+        builder =
+            new AzkabanProcessBuilder(partitionCommandLine(command))
+                .setEnv(envVars).setWorkingDir(getCwd()).setLogger(getLog())
+                .setExecuteAsUser().setExecuteAsUserBinary(executeAsUserBinary)
+                .setEffectiveUser(effectiveUser);
+      } else {
+        info("Command: " + command);
+        builder =
+            new AzkabanProcessBuilder(partitionCommandLine(command))
+                .setEnv(envVars).setWorkingDir(getCwd()).setLogger(getLog());
+      }
 
       if (builder.getEnv().size() > 0) {
         info("Environment variables: " + builder.getEnv());
@@ -157,6 +175,15 @@ public class ProcessJob extends AbstractProcessJob {
     generateProperties(propFiles[1]);
   }
 
+  private boolean determineExecuteAsUser(Props sysProps, Props jobProps) {
+    boolean isExecuteAsUser = sysProps.getBoolean(EXECUTE_AS_USER, false);
+    // putting an override in case user needs to override. A temporary opening
+    if (jobProps.containsKey(EXECUTE_AS_USER_OVERRIDE))
+      isExecuteAsUser = jobProps.getBoolean(EXECUTE_AS_USER_OVERRIDE, false);
+
+    return isExecuteAsUser;
+  }
+
   /**
    * <pre>
    * This method extracts the kerberos ticket cache file name from the jobprops.
diff --git a/azkaban-common/src/main/java/azkaban/jobExecutor/utils/process/AzkabanProcess.java b/azkaban-common/src/main/java/azkaban/jobExecutor/utils/process/AzkabanProcess.java
index 1035be0..cbe6ec3 100644
--- a/azkaban-common/src/main/java/azkaban/jobExecutor/utils/process/AzkabanProcess.java
+++ b/azkaban-common/src/main/java/azkaban/jobExecutor/utils/process/AzkabanProcess.java
@@ -50,6 +50,10 @@ public class AzkabanProcess {
   private volatile int processId;
   private volatile Process process;
 
+  private boolean isExecuteAsUser = false;
+  private String executeAsUserBinary = null;
+  private String effectiveUser = null;
+
   public AzkabanProcess(final List<String> cmd, final Map<String, String> env,
       final String workingDir, final Logger logger) {
     this.cmd = cmd;
@@ -61,6 +65,15 @@ public class AzkabanProcess {
     this.logger = logger;
   }
 
+  public AzkabanProcess(List<String> cmd, Map<String, String> env,
+      String workingDir, Logger logger, String executeAsUserBinary,
+      String effectiveUser) {
+    this(cmd, env, workingDir, logger);
+    this.isExecuteAsUser = true;
+    this.executeAsUserBinary = executeAsUserBinary;
+    this.effectiveUser = effectiveUser;
+  }
+
   /**
    * Execute this process, blocking until it has completed.
    */
@@ -101,16 +114,15 @@ public class AzkabanProcess {
       }
 
       completeLatch.countDown();
-      
+
       // try to wait for everything to get logged out before exiting
       outputGobbler.awaitCompletion(5000);
       errorGobbler.awaitCompletion(5000);
-      
+
       if (exitCode != 0) {
         throw new ProcessFailureException(exitCode, errorGobbler.getRecentLog());
       }
 
-
     } finally {
       IOUtils.closeQuietly(process.getInputStream());
       IOUtils.closeQuietly(process.getOutputStream());
@@ -158,7 +170,14 @@ public class AzkabanProcess {
     checkStarted();
     if (processId != 0 && isStarted()) {
       try {
-        Runtime.getRuntime().exec("kill " + processId);
+        if (isExecuteAsUser) {
+          String cmd =
+              String.format("%s %s kill %d", executeAsUserBinary,
+                  effectiveUser, processId);
+          Runtime.getRuntime().exec(cmd);
+        } else {
+          Runtime.getRuntime().exec("kill " + processId);
+        }
         return completeLatch.await(time, unit);
       } catch (IOException e) {
         logger.error("Kill attempt failed.", e);
@@ -176,7 +195,14 @@ public class AzkabanProcess {
     if (isRunning()) {
       if (processId != 0) {
         try {
-          Runtime.getRuntime().exec("kill -9 " + processId);
+          if (isExecuteAsUser) {
+            String cmd =
+                String.format("%s %s kill -9 %d", executeAsUserBinary,
+                    effectiveUser, processId);
+            Runtime.getRuntime().exec(cmd);
+          } else {
+            Runtime.getRuntime().exec("kill -9 " + processId);
+          }
         } catch (IOException e) {
           logger.error("Kill attempt failed.", e);
         }
@@ -237,4 +263,12 @@ public class AzkabanProcess {
     return "Process(cmd = " + Joiner.on(" ").join(cmd) + ", env = " + env
         + ", cwd = " + workingDir + ")";
   }
+
+  public boolean isExecuteAsUser() {
+    return isExecuteAsUser;
+  }
+
+  public String getEffectiveUser() {
+    return effectiveUser;
+  }
 }
diff --git a/azkaban-common/src/main/java/azkaban/jobExecutor/utils/process/AzkabanProcessBuilder.java b/azkaban-common/src/main/java/azkaban/jobExecutor/utils/process/AzkabanProcessBuilder.java
index 8832195..070c407 100644
--- a/azkaban-common/src/main/java/azkaban/jobExecutor/utils/process/AzkabanProcessBuilder.java
+++ b/azkaban-common/src/main/java/azkaban/jobExecutor/utils/process/AzkabanProcessBuilder.java
@@ -35,6 +35,9 @@ public class AzkabanProcessBuilder {
   private Map<String, String> env = new HashMap<String, String>();
   private String workingDir = System.getProperty("user.dir");
   private Logger logger = Logger.getLogger(AzkabanProcess.class);
+  private boolean isExecuteAsUser = false;
+  private String executeAsUserBinary = null;
+  private String effectiveUser = null;
 
   private int stdErrSnippetSize = 30;
   private int stdOutSnippetSize = 30;
@@ -100,7 +103,11 @@ public class AzkabanProcessBuilder {
   }
 
   public AzkabanProcess build() {
-    return new AzkabanProcess(cmd, env, workingDir, logger);
+    if (isExecuteAsUser)
+      return new AzkabanProcess(cmd, env, workingDir, logger,
+          executeAsUserBinary, effectiveUser);
+    else
+      return new AzkabanProcess(cmd, env, workingDir, logger);
   }
 
   public List<String> getCommand() {
@@ -116,4 +123,19 @@ public class AzkabanProcessBuilder {
     return "ProcessBuilder(cmd = " + Joiner.on(" ").join(cmd) + ", env = "
         + env + ", cwd = " + workingDir + ")";
   }
+
+  public AzkabanProcessBuilder setExecuteAsUser() {
+    this.isExecuteAsUser = true;
+    return this;
+  }
+
+  public AzkabanProcessBuilder setExecuteAsUserBinary(String executeAsUserBinary) {
+    this.executeAsUserBinary = executeAsUserBinary;
+    return this;
+  }
+
+  public AzkabanProcessBuilder setEffectiveUser(String effectiveUser) {
+    this.effectiveUser = effectiveUser;
+    return this;
+  }
 }
diff --git a/azkaban-common/src/main/java/azkaban/project/ProjectManager.java b/azkaban-common/src/main/java/azkaban/project/ProjectManager.java
index 1e5e522..0f09b9c 100644
--- a/azkaban-common/src/main/java/azkaban/project/ProjectManager.java
+++ b/azkaban-common/src/main/java/azkaban/project/ProjectManager.java
@@ -269,7 +269,7 @@ public class ProjectManager {
           "Project names must start with a letter, followed by any number of letters, digits, '-' or '_'.");
     }
 
-    if (projectsByName.containsKey(projectName)) {
+    if (projectsByName.contains(projectName)) {
       throw new ProjectManagerException("Project already exists.");
     }
 
diff --git a/azkaban-common/src/main/java/azkaban/server/session/SessionCache.java b/azkaban-common/src/main/java/azkaban/server/session/SessionCache.java
index 1237678..fc4d64f 100644
--- a/azkaban-common/src/main/java/azkaban/server/session/SessionCache.java
+++ b/azkaban-common/src/main/java/azkaban/server/session/SessionCache.java
@@ -58,7 +58,7 @@ public class SessionCache {
    * @return
    */
   public Session getSession(String sessionId) {
-    Session elem = cache.get(Session.class, sessionId);
+    Session elem = cache.<Session> get(sessionId);
 
     return elem;
   }
diff --git a/azkaban-common/src/main/java/azkaban/trigger/JdbcTriggerLoader.java b/azkaban-common/src/main/java/azkaban/trigger/JdbcTriggerLoader.java
index 007d872..99b32f9 100644
--- a/azkaban-common/src/main/java/azkaban/trigger/JdbcTriggerLoader.java
+++ b/azkaban-common/src/main/java/azkaban/trigger/JdbcTriggerLoader.java
@@ -178,7 +178,7 @@ public class JdbcTriggerLoader extends AbstractJdbcLoader implements
           runner.query(connection, LastInsertID.LAST_INSERT_ID,
               new LastInsertID());
 
-      if (id == -1L) {
+      if (id == -1l) {
         logger.error("trigger id is not properly created.");
         throw new TriggerLoaderException("trigger id is not properly created.");
       }
@@ -257,7 +257,7 @@ public class JdbcTriggerLoader extends AbstractJdbcLoader implements
     @Override
     public Long handle(ResultSet rs) throws SQLException {
       if (!rs.next()) {
-        return -1L;
+        return -1l;
       }
 
       long id = rs.getLong(1);
diff --git a/azkaban-common/src/main/java/azkaban/utils/cache/Cache.java b/azkaban-common/src/main/java/azkaban/utils/cache/Cache.java
index 231d419..a2ddc60 100644
--- a/azkaban-common/src/main/java/azkaban/utils/cache/Cache.java
+++ b/azkaban-common/src/main/java/azkaban/utils/cache/Cache.java
@@ -38,16 +38,17 @@ public class Cache {
     LRU, FIFO
   }
 
-  /* package */ Cache(CacheManager manager) {
+  /* package */Cache(CacheManager manager) {
     this.manager = manager;
   }
 
-  public <T> T get(Class<T> clazz, Object key) {
+  @SuppressWarnings("unchecked")
+  public <T> T get(Object key) {
     Element<?> element = elementMap.get(key);
     if (element == null) {
       return null;
     }
-    return clazz.cast(element.getElement());
+    return (T) element.getElement();
   }
 
   public <T> void put(Object key, T item) {
diff --git a/azkaban-common/src/main/java/azkaban/utils/TypedMapWrapper.java b/azkaban-common/src/main/java/azkaban/utils/TypedMapWrapper.java
index 62208f3..7118e8c 100644
--- a/azkaban-common/src/main/java/azkaban/utils/TypedMapWrapper.java
+++ b/azkaban-common/src/main/java/azkaban/utils/TypedMapWrapper.java
@@ -71,7 +71,7 @@ public class TypedMapWrapper<K, V> {
   }
 
   public Long getLong(K key) {
-    return getLong(key, -1L);
+    return getLong(key, -1l);
   }
 
   public Long getLong(K key, Long defaultVal) {
diff --git a/azkaban-common/src/test/java/azkaban/executor/JavaJobRunnerMain.java b/azkaban-common/src/test/java/azkaban/executor/JavaJobRunnerMain.java
index cf46637..67d0284 100644
--- a/azkaban-common/src/test/java/azkaban/executor/JavaJobRunnerMain.java
+++ b/azkaban-common/src/test/java/azkaban/executor/JavaJobRunnerMain.java
@@ -196,7 +196,7 @@ public class JavaJobRunnerMain {
       }
       writer.write("}".getBytes());
     } catch (Exception e) {
-      throw new RuntimeException("Unable to store output properties to: "
+      new RuntimeException("Unable to store output properties to: "
           + outputFileStr);
     } finally {
       try {
diff --git a/azkaban-common/src/test/java/azkaban/jobExecutor/PythonJobTest.java b/azkaban-common/src/test/java/azkaban/jobExecutor/PythonJobTest.java
index 7320c15..ee767de 100644
--- a/azkaban-common/src/test/java/azkaban/jobExecutor/PythonJobTest.java
+++ b/azkaban-common/src/test/java/azkaban/jobExecutor/PythonJobTest.java
@@ -24,7 +24,6 @@ import org.apache.log4j.Logger;
 import org.junit.AfterClass;
 import org.junit.Assert;
 import org.junit.BeforeClass;
-import org.junit.Ignore;
 import org.junit.Test;
 
 import azkaban.utils.Props;
@@ -83,7 +82,6 @@ public class PythonJobTest {
     Utils.removeFile(scriptFile);
   }
 
-  @Ignore("Test appears to hang.")
   @Test
   public void testPythonJob() {
 
diff --git a/azkaban-common/src/test/java/azkaban/project/ProjectTest.java b/azkaban-common/src/test/java/azkaban/project/ProjectTest.java
index 63c19f0..da36d46 100644
--- a/azkaban-common/src/test/java/azkaban/project/ProjectTest.java
+++ b/azkaban-common/src/test/java/azkaban/project/ProjectTest.java
@@ -28,8 +28,8 @@ public class ProjectTest {
   @Test
   public void testToAndFromObject() throws Exception {
     Project project = new Project(1, "tesTing");
-    project.setCreateTimestamp(1L);
-    project.setLastModifiedTimestamp(2L);
+    project.setCreateTimestamp(1l);
+    project.setLastModifiedTimestamp(2l);
     project.setDescription("I am a test");
     project.setUserPermission("user1", new Permission(new Type[] { Type.ADMIN,
         Type.EXECUTE }));
diff --git a/azkaban-common/src/test/java/azkaban/utils/cache/CacheTest.java b/azkaban-common/src/test/java/azkaban/utils/cache/CacheTest.java
index 55dd5d9..125f1b3 100644
--- a/azkaban-common/src/test/java/azkaban/utils/cache/CacheTest.java
+++ b/azkaban-common/src/test/java/azkaban/utils/cache/CacheTest.java
@@ -34,19 +34,19 @@ public class CacheTest {
     cache.insertElement("key3", "val3");
     cache.insertElement("key4", "val4");
 
-    Assert.assertEquals(cache.get(String.class, "key2"), "val2");
-    Assert.assertEquals(cache.get(String.class, "key3"), "val3");
-    Assert.assertEquals(cache.get(String.class, "key4"), "val4");
-    Assert.assertEquals(cache.get(String.class, "key1"), "val1");
+    Assert.assertEquals(cache.get("key2"), "val2");
+    Assert.assertEquals(cache.get("key3"), "val3");
+    Assert.assertEquals(cache.get("key4"), "val4");
+    Assert.assertEquals(cache.get("key1"), "val1");
     Assert.assertEquals(4, cache.getSize());
 
     cache.insertElement("key5", "val5");
     Assert.assertEquals(4, cache.getSize());
-    Assert.assertEquals(cache.get(String.class, "key3"), "val3");
-    Assert.assertEquals(cache.get(String.class, "key4"), "val4");
-    Assert.assertEquals(cache.get(String.class, "key1"), "val1");
-    Assert.assertEquals(cache.get(String.class, "key5"), "val5");
-    Assert.assertNull(cache.get(String.class, "key2"));
+    Assert.assertEquals(cache.get("key3"), "val3");
+    Assert.assertEquals(cache.get("key4"), "val4");
+    Assert.assertEquals(cache.get("key1"), "val1");
+    Assert.assertEquals(cache.get("key5"), "val5");
+    Assert.assertNull(cache.get("key2"));
   }
 
   @Test
@@ -67,19 +67,19 @@ public class CacheTest {
     cache.insertElement("key3", "val3");
     cache.insertElement("key4", "val4");
 
-    Assert.assertEquals(cache.get(String.class, "key2"), "val2");
-    Assert.assertEquals(cache.get(String.class, "key3"), "val3");
-    Assert.assertEquals(cache.get(String.class, "key4"), "val4");
-    Assert.assertEquals(cache.get(String.class, "key1"), "val1");
+    Assert.assertEquals(cache.get("key2"), "val2");
+    Assert.assertEquals(cache.get("key3"), "val3");
+    Assert.assertEquals(cache.get("key4"), "val4");
+    Assert.assertEquals(cache.get("key1"), "val1");
     Assert.assertEquals(4, cache.getSize());
 
     cache.insertElement("key5", "val5");
     Assert.assertEquals(4, cache.getSize());
-    Assert.assertEquals(cache.get(String.class, "key3"), "val3");
-    Assert.assertEquals(cache.get(String.class, "key4"), "val4");
-    Assert.assertEquals(cache.get(String.class, "key2"), "val2");
-    Assert.assertEquals(cache.get(String.class, "key5"), "val5");
-    Assert.assertNull(cache.get(String.class, "key1"));
+    Assert.assertEquals(cache.get("key3"), "val3");
+    Assert.assertEquals(cache.get("key4"), "val4");
+    Assert.assertEquals(cache.get("key2"), "val2");
+    Assert.assertEquals(cache.get("key5"), "val5");
+    Assert.assertNull(cache.get("key1"));
   }
 
   @Test
@@ -99,7 +99,7 @@ public class CacheTest {
       } catch (InterruptedException e) {
       }
     }
-    Assert.assertEquals(cache.get(String.class, "key1"), "val1");
+    Assert.assertEquals(cache.get("key1"), "val1");
     cache.insertElement("key2", "val2");
     synchronized (this) {
       try {
@@ -107,8 +107,8 @@ public class CacheTest {
       } catch (InterruptedException e) {
       }
     }
-    Assert.assertNull(cache.get(String.class, "key1"));
-    Assert.assertEquals("val2", cache.get(String.class, "key2"));
+    Assert.assertNull(cache.get("key1"));
+    Assert.assertEquals("val2", cache.get("key2"));
 
     synchronized (this) {
       try {
@@ -117,7 +117,7 @@ public class CacheTest {
       }
     }
 
-    Assert.assertNull(cache.get(String.class, "key2"));
+    Assert.assertNull(cache.get("key2"));
   }
 
   @Test
@@ -137,7 +137,7 @@ public class CacheTest {
       } catch (InterruptedException e) {
       }
     }
-    Assert.assertEquals(cache.get(String.class, "key1"), "val1");
+    Assert.assertEquals(cache.get("key1"), "val1");
     cache.insertElement("key2", "val2");
     synchronized (this) {
       try {
@@ -145,8 +145,8 @@ public class CacheTest {
       } catch (InterruptedException e) {
       }
     }
-    Assert.assertEquals("val1", cache.get(String.class, "key1"));
-    Assert.assertNull(cache.get(String.class, "key3"));
+    Assert.assertEquals("val1", cache.get("key1"));
+    Assert.assertNull(cache.get("key3"));
     synchronized (this) {
       try {
         wait(1000);
@@ -154,6 +154,6 @@ public class CacheTest {
       }
     }
 
-    Assert.assertNull(cache.get(String.class, "key2"));
+    Assert.assertNull(cache.get("key2"));
   }
 }
diff --git a/azkaban-execserver/src/main/resources/execute-as-user.c b/azkaban-execserver/src/main/resources/execute-as-user.c
index e87bd85..0a8cbe3 100644
--- a/azkaban-execserver/src/main/resources/execute-as-user.c
+++ b/azkaban-execserver/src/main/resources/execute-as-user.c
@@ -33,7 +33,9 @@
 
 FILE *LOGFILE = NULL;
 FILE *ERRORFILE = NULL;
-int SETUID_OPER_FAILED=10;
+int SETUID_OPER_FAILED = 10;
+int USER_NOT_FOUND = 20;
+int INVALID_INPUT = 30;
 
 /*
  *  Change the real and effective user and group from super user to the specified user
@@ -73,55 +75,41 @@ int change_user(uid_t user, gid_t group) {
 }
 
 int main(int argc, char **argv){
-    if (argc < 3) {
-        fprintf(ERRORFILE, "Requires at least 3 variables: ./execute-as-user uid command [args]");
-    }
 
+// set up the logging stream
     if(!LOGFILE)
         LOGFILE=stdout;
     if(!ERRORFILE)
         ERRORFILE=stderr;
 
-    char *uid = argv[1];
-
-    // for loop to calculate the length to malloc
-    int i;
-    int total_len = 0;
-    for(i=2;i<argc;i++){
-        total_len += strlen(argv[i])+1;
+    if (argc < 3) {
+        fprintf(ERRORFILE, "Requires at least 3 variables: ./execute-as-user uid command [args]");
+        return INVALID_INPUT;
     }
-    fprintf(LOGFILE, "total_len: %d\n", total_len);
 
-    // allocate memory and clear memory
-    char *cmd = malloc(total_len+2);
-    if(cmd == NULL){
-        fprintf(LOGFILE, "unable to malloc memory in execute-as-user.c");
-        return 10;
+    char *uid = argv[1];
+
+    // gather information about user
+    struct passwd *user_info = getpwnam(uid);
+    if ( user_info == NULL ){
+        fprintf(LOGFILE, "user does not exist: %s", uid);
+        return USER_NOT_FOUND;
     }
-    memset(cmd, 0, total_len+2);
 
-    // change user 
-    struct passwd *userInfo = getpwnam(uid);
-    fprintf(LOGFILE, "Changing user: user: %s, uid: %d, gid: %d\n", uid, userInfo->pw_uid, userInfo->pw_gid);
-    int retval = change_user(userInfo->pw_uid, userInfo->pw_gid);
-    fprintf(LOGFILE, "change user function return value: %d\n", retval);
+    // try to change user
+    fprintf(LOGFILE, "Changing user: user: %s, uid: %d, gid: %d\n", uid, user_info->pw_uid, user_info->pw_gid);
+    int retval = change_user(user_info->pw_uid, user_info->pw_gid);
     if( retval != 0){
         fprintf(LOGFILE, "Error changing user to %s\n", uid);
         return SETUID_OPER_FAILED;
     }
 
-    // create the command
-    char *cur = cmd;
-    int len;
-    for(i=2;i<argc;i++){
-        len = strlen(argv[i]);
-        memcpy(cur, argv[i], len);
-        cur+=len+1;
-    }
-
-    fprintf(LOGFILE, "executing as user command: %s\n", cmd);
-    retval = system(cmd);
-    fprintf(LOGFILE, "system call return value: %d", retval);
+    // execute the command
+    char **user_argv = &argv[2];
+    fprintf(LOGFILE, "user command starting from: %s\n", user_argv[0]);
+    fflush(LOGFILE);
+    retval = execvp(*user_argv, user_argv);
+    fprintf(LOGFILE, "system call return value: %d\n", retval);
 
     // sometimes system(cmd) returns 256, which is interpreted to 0, making a failed job a successful job
     // hence this goofy piece of if statement.

build.gradle 32(+6 -26)

diff --git a/build.gradle b/build.gradle
index 7a5db1e..d8afcca 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,14 +1,10 @@
 buildscript {
   repositories {
     mavenCentral()
-    maven {
-      url 'https://plugins.gradle.org/m2/'
-    }
   }
   dependencies {
     classpath 'com.linkedin:gradle-dustjs-plugin:1.0.0'
     classpath 'de.obqo.gradle:gradle-lesscss-plugin:1.0-1.3.3'
-    classpath 'net.ltgt.gradle:gradle-errorprone-plugin:0.0.8'
   }
 }
 
@@ -36,11 +32,6 @@ def cmdCaller = { commandln ->
 subprojects {
   apply plugin: 'java'
   apply plugin: 'eclipse'
-  apply plugin: 'net.ltgt.errorprone'
-
-  configurations.errorprone {
-    resolutionStrategy.force 'com.google.errorprone:error_prone_core:2.0.5'
-  }
 
   /**
    * Gets the version name from the latest Git tag
@@ -87,9 +78,6 @@ project(':azkaban-common') {
     all {
       transitive = false
     }
-    errorprone {
-      transitive = true
-    }
   }
 
   dependencies {
@@ -126,11 +114,11 @@ project(':azkaban-common') {
     testCompile('junit:junit:4.11')
     testCompile('org.hamcrest:hamcrest-all:1.3')
   }
-
+  
   tasks.withType(JavaCompile) {
     options.encoding = "UTF-8"
   }
-
+  
 }
 
 project(':azkaban-migration') {
@@ -138,9 +126,6 @@ project(':azkaban-migration') {
     all {
       transitive = false
     }
-    errorprone {
-      transitive = true
-    }
   }
 
   dependencies {
@@ -189,9 +174,6 @@ project(':azkaban-webserver') {
     generateRestli {
       transitive = true
     }
-    errorprone {
-      transitive = true
-    }
   }
 
   dependencies {
@@ -315,9 +297,6 @@ project(':azkaban-execserver') {
     all {
       transitive = false
     }
-    errorprone {
-      transitive = true
-    }
   }
 
   dependencies {
@@ -333,6 +312,7 @@ project(':azkaban-execserver') {
     compile('org.mortbay.jetty:jetty-util:6.1.26')
     compile('org.codehaus.jackson:jackson-core-asl:1.9.5')
     compile('org.codehaus.jackson:jackson-mapper-asl:1.9.5')
+    
 
     testCompile('junit:junit:4.11')
     testCompile('org.hamcrest:hamcrest-all:1.3')
@@ -498,11 +478,11 @@ project(':azkaban-test') {
     }
   }
 
-  distZip.dependsOn animalDistZip, embeddedDistZip, embedded2DistZip,
+  distZip.dependsOn build, animalDistZip, embeddedDistZip, embedded2DistZip,
       embedded3DistZip, embeddedBadDistZip, execpropstestDistZip,
       exectest1DistZip, exectest2DistZip, logtestDistZip
 
-  distTar.dependsOn animalDistTar, embeddedDistTar, embedded2DistTar,
+  distTar.dependsOn build, animalDistTar, embeddedDistTar, embedded2DistTar,
       embedded3DistTar, embeddedBadDistTar, execpropstestDistTar,
       exectest1DistTar, exectest2DistTar, logtestDistTar
 }
@@ -590,5 +570,5 @@ distZip.dependsOn migrationDistZip, webserverDistZip, execserverDistZip, soloser
  * Gradle wrapper task.
  */
 task wrapper(type: Wrapper) {
-  gradleVersion = '2.7'
+  gradleVersion = '1.12'
 }
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index e8c6bf7..0087cd3 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index bbc82a1..506745b 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Sat Sep 26 15:48:43 PDT 2015
+#Wed Jun 11 01:55:01 PDT 2014
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-1.12-bin.zip

gradlew 6(+5 -1)

diff --git a/gradlew b/gradlew
index 97fac78..91a7e26 100755
--- a/gradlew
+++ b/gradlew
@@ -42,6 +42,11 @@ case "`uname`" in
     ;;
 esac
 
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
 # Attempt to set APP_HOME
 # Resolve links: $0 may be a link
 PRG="$0"
@@ -109,7 +114,6 @@ fi
 if $cygwin ; then
     APP_HOME=`cygpath --path --mixed "$APP_HOME"`
     CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
-    JAVACMD=`cygpath --unix "$JAVACMD"`
 
     # We build the pattern for arguments to be converted via cygpath
     ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`