azkaban-uncached
Changes
src/java/azkaban/execapp/FlowRunner.java 21(+9 -12)
src/java/azkaban/execapp/JobRunner.java 13(+5 -8)
src/java/azkaban/project/Project.java 45(+44 -1)
src/java/azkaban/user/XmlUserManager.java 35(+33 -2)
src/sql/create_project_table.sql 2(+2 -0)
src/sql/update_2.0_to_2.01.sql 3(+3 -0)
src/web/js/azkaban.permission.view.js 79(+69 -10)
Details
src/java/azkaban/execapp/FlowRunner.java 21(+9 -12)
diff --git a/src/java/azkaban/execapp/FlowRunner.java b/src/java/azkaban/execapp/FlowRunner.java
index eebb427..fbbedc0 100644
--- a/src/java/azkaban/execapp/FlowRunner.java
+++ b/src/java/azkaban/execapp/FlowRunner.java
@@ -5,6 +5,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
@@ -33,6 +34,7 @@ import azkaban.executor.ExecutorLoader;
import azkaban.executor.ExecutorManagerException;
import azkaban.flow.FlowProps;
import azkaban.jobtype.JobTypeManager;
+import azkaban.project.Project;
import azkaban.project.ProjectLoader;
import azkaban.project.ProjectManagerException;
import azkaban.user.Permission;
@@ -82,7 +84,7 @@ public class FlowRunner extends EventHandler implements Runnable {
private boolean flowFinished = false;
private boolean flowCancelled = false;
- private List<String> proxyUsers = null;
+ private HashSet<String> proxyUsers = null;
private boolean proxyUserLockDown = false;
@@ -102,23 +104,18 @@ public class FlowRunner extends EventHandler implements Runnable {
this.proxyUserLockDown = doLockDown;
}
- private List<String> getProxyUsers() {
- List<String> allUsers = new ArrayList<String>();
- allUsers.add(flow.getSubmitUser());
- List<Triple<String, Boolean, Permission>> permissions;
+ private HashSet<String> getProxyUsers() {
+ HashSet<String> proxyUsers = null;
+
try {
- permissions = projectLoader.getProjectPermissions(flow.getProjectId());
- for(Triple<String, Boolean, Permission> triple : permissions) {
- if(triple.getSecond() == false && (triple.getThird().isPermissionSet(Permission.Type.EXECUTE) || triple.getThird().isPermissionSet(Permission.Type.ADMIN) )) {
- allUsers.add(triple.getFirst());
- }
- }
+ Project project = projectLoader.fetchProjectById(flow.getProjectId());
+ proxyUsers = project.getProxyUsers();
} catch (ProjectManagerException e) {
// This gets funny when no user specified and submitted by the scheduler
logger.error("Failed to get project permission from project. Using default permission.", e);
}
- return allUsers;
+ return proxyUsers;
}
public FlowRunner setGlobalProps(Props globalProps) {
src/java/azkaban/execapp/JobRunner.java 13(+5 -8)
diff --git a/src/java/azkaban/execapp/JobRunner.java b/src/java/azkaban/execapp/JobRunner.java
index ad03089..9448dd1 100644
--- a/src/java/azkaban/execapp/JobRunner.java
+++ b/src/java/azkaban/execapp/JobRunner.java
@@ -17,6 +17,7 @@ package azkaban.execapp;
import java.io.File;
import java.io.IOException;
+import java.util.HashSet;
import java.util.List;
import org.apache.log4j.Appender;
@@ -63,11 +64,11 @@ public class JobRunner extends EventHandler implements Runnable {
private Object syncObject = new Object();
private final JobTypeManager jobtypeManager;
- private List<String> proxyUsers = null;
+ private HashSet<String> proxyUsers = null;
private boolean userLockDown;
- public JobRunner(ExecutableNode node, Props props, File workingDir, List<String> proxyUsers, ExecutorLoader loader, JobTypeManager jobtypeManager, Logger flowLogger) {
+ public JobRunner(ExecutableNode node, Props props, File workingDir, HashSet<String> proxyUsers, ExecutorLoader loader, JobTypeManager jobtypeManager, Logger flowLogger) {
this.props = props;
this.node = node;
this.workingDir = workingDir;
@@ -226,11 +227,8 @@ public class JobRunner extends EventHandler implements Runnable {
props.put(AbstractProcessJob.WORKING_DIR, workingDir.getAbsolutePath());
}
- String jobProxyUser = props.getString("user.to.proxy", null);
- if(jobProxyUser == null) {
- jobProxyUser = proxyUsers.get(0);
- }
- else {
+ if(props.containsKey("user.to.proxy")) {
+ String jobProxyUser = props.getString("user.to.proxy");
if(! proxyUsers.contains(jobProxyUser)) {
logger.error("User " + jobProxyUser + " has no permission to execute this job " + node.getJobId() + "!");
if(userLockDown) {
@@ -238,7 +236,6 @@ public class JobRunner extends EventHandler implements Runnable {
}
}
}
- props.put("user.to.proxy", jobProxyUser);
//job = JobWrappingFactory.getJobWrappingFactory().buildJobExecutor(node.getJobId(), props, logger);
try {
diff --git a/src/java/azkaban/project/JdbcProjectLoader.java b/src/java/azkaban/project/JdbcProjectLoader.java
index 6f0c3f5..631b4e1 100644
--- a/src/java/azkaban/project/JdbcProjectLoader.java
+++ b/src/java/azkaban/project/JdbcProjectLoader.java
@@ -14,6 +14,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -27,6 +28,7 @@ import org.apache.log4j.Logger;
import azkaban.flow.Flow;
import azkaban.project.ProjectLogEvent.EventType;
+import azkaban.scheduler.JdbcScheduleLoader.EncodingType;
import azkaban.user.Permission;
import azkaban.user.User;
import azkaban.utils.DataSourceUtils;
@@ -236,11 +238,11 @@ public class JdbcProjectLoader implements ProjectLoader {
throw new ProjectManagerException("Checking for existing project failed. " + name, e);
}
- final String INSERT_PROJECT = "INSERT INTO projects ( name, active, modified_time, create_time, version, last_modified_by, description) values (?,?,?,?,?,?,?)";
+ final String INSERT_PROJECT = "INSERT INTO projects ( name, active, modified_time, create_time, version, last_modified_by, description, enc_type, settings_blob) values (?,?,?,?,?,?,?,?,?)";
// Insert project
try {
long time = System.currentTimeMillis();
- int i = runner.update(connection, INSERT_PROJECT, name, true, time, time, null, creator.getUserId(), description);
+ int i = runner.update(connection, INSERT_PROJECT, name, true, time, time, null, creator.getUserId(), description, defaultEncodingType.numVal, null);
if (i == 0) {
throw new ProjectManagerException("No projects have been inserted.");
}
@@ -504,6 +506,49 @@ public class JdbcProjectLoader implements ProjectLoader {
}
}
+
+
+ @Override
+ public void updateProjectSettings(Project project) throws ProjectManagerException {
+ Connection connection = getConnection();
+ try {
+ updateProjectSettings(connection, project, defaultEncodingType);
+ connection.commit();
+ }
+ catch (SQLException e) {
+ throw new ProjectManagerException("Error updating project settings", e);
+ }
+ finally {
+ DbUtils.closeQuietly(connection);
+ }
+ }
+
+ private void updateProjectSettings(Connection connection, Project project, EncodingType encType) throws ProjectManagerException {
+ QueryRunner runner = new QueryRunner();
+ final String UPDATE_PROJECT_SETTINGS = "UPDATE projects SET enc_type=?, settings_blob=? WHERE id=?";
+
+ String json = JSONUtils.toJSON(project.toObject());
+ byte[] data = null;
+ try {
+ byte[] stringData = json.getBytes("UTF-8");
+ data = stringData;
+
+ if (encType == EncodingType.GZIP) {
+ data = GZIPUtils.gzipBytes(stringData);
+ }
+ logger.debug("NumChars: " + json.length() + " UTF-8:" + stringData.length + " Gzip:"+ data.length);
+ } catch(IOException e) {
+ throw new ProjectManagerException("Failed to encode. ", e);
+ }
+
+ try {
+ runner.update(connection, UPDATE_PROJECT_SETTINGS, encType.numVal, data, project.getId());
+ connection.commit();
+ } catch (SQLException e) {
+ throw new ProjectManagerException("Error updating project " + project.getName() + " version " + project.getVersion(), e);
+ }
+ }
+
@Override
public void removePermission(Project project, String name, boolean isGroup) throws ProjectManagerException {
QueryRunner runner = new QueryRunner(dataSource);
@@ -942,13 +987,13 @@ public class JdbcProjectLoader implements ProjectLoader {
private static class ProjectResultHandler implements ResultSetHandler<List<Project>> {
private static String SELECT_PROJECT_BY_ID =
- "SELECT id, name, active, modified_time, create_time, version, last_modified_by, description FROM projects WHERE id=?";
+ "SELECT id, name, active, modified_time, create_time, version, last_modified_by, description, enc_type, settings_blob FROM projects WHERE id=?";
private static String SELECT_ALL_ACTIVE_PROJECTS =
- "SELECT id, name, active, modified_time, create_time, version, last_modified_by, description FROM projects WHERE active=true";
+ "SELECT id, name, active, modified_time, create_time, version, last_modified_by, description, enc_type, settings_blob FROM projects WHERE active=true";
private static String SELECT_ACTIVE_PROJECT_BY_NAME =
- "SELECT id, name, active, modified_time, create_time, version, last_modified_by, description FROM projects WHERE name=? AND active=true";
+ "SELECT id, name, active, modified_time, create_time, version, last_modified_by, description, enc_type, settings_blob FROM projects WHERE name=? AND active=true";
@Override
public List<Project> handle(ResultSet rs) throws SQLException {
@@ -966,8 +1011,35 @@ public class JdbcProjectLoader implements ProjectLoader {
int version = rs.getInt(6);
String lastModifiedBy = rs.getString(7);
String description = rs.getString(8);
+ int encodingType = rs.getInt(9);
+ byte[] data = rs.getBytes(10);
+
+ Project project;
+ if (data != null) {
+ EncodingType encType = EncodingType.fromInteger(encodingType);
+ Object blobObj;
+ try {
+ // Convoluted way to inflate strings. Should find common package or helper function.
+ if (encType == EncodingType.GZIP) {
+ // Decompress the sucker.
+ String jsonString = GZIPUtils.unGzipString(data, "UTF-8");
+ blobObj = JSONUtils.parseJSONFromString(jsonString);
+ }
+ else {
+ String jsonString = new String(data, "UTF-8");
+ blobObj = JSONUtils.parseJSONFromString(jsonString);
+ }
+ project = Project.projectFromObject(blobObj);
+ } catch (IOException e) {
+ throw new SQLException("Failed to get project.", e);
+ }
+ }
+ else {
+ project = new Project(id, name);
+ }
+
+ // update the fields as they may have changed
- Project project = new Project(id, name);
project.setActive(active);
project.setLastModifiedTimestamp(modifiedTime);
project.setCreateTimestamp(createTime);
src/java/azkaban/project/Project.java 45(+44 -1)
diff --git a/src/java/azkaban/project/Project.java b/src/java/azkaban/project/Project.java
index 5a611fc..f7b32b6 100644
--- a/src/java/azkaban/project/Project.java
+++ b/src/java/azkaban/project/Project.java
@@ -18,6 +18,7 @@ package azkaban.project;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -27,6 +28,7 @@ import azkaban.user.Permission;
import azkaban.user.Permission.Type;
import azkaban.user.User;
import azkaban.utils.Pair;
+import azkaban.utils.Props;
public class Project {
private final int id;
@@ -41,6 +43,15 @@ public class Project {
private LinkedHashMap<String, Permission> userPermissionMap = new LinkedHashMap<String, Permission>();
private LinkedHashMap<String, Permission> groupPermissionMap = new LinkedHashMap<String, Permission>();
private Map<String, Flow> flows = null;
+ private HashSet<String> proxyUsers = new HashSet<String>();
+
+ public HashSet<String> getProxyUsers() {
+ return proxyUsers;
+ }
+
+ public void setProxyUsers(HashSet<String> proxyUsers) {
+ this.proxyUsers = proxyUsers;
+ }
public Project(int id, String name) {
this.id = id;
@@ -235,8 +246,13 @@ public class Project {
userMap.put("permissions", entry.getValue().toStringArray());
users.add(userMap);
}
-
+
projectObject.put("users", users);
+
+
+ ArrayList<String> proxyUserList = new ArrayList<String>(proxyUsers);
+ projectObject.put("proxyUsers", proxyUserList);
+
return projectObject;
}
@@ -277,6 +293,10 @@ public class Project {
project.setUserPermission(userid, perm);
}
+
+ List<String> proxyUserList = (List<String>) projectObject.get("proxyUsers");
+ HashSet<String> proxyUsers = new HashSet<String>(proxyUserList);
+ project.setProxyUsers(proxyUsers);
return project;
}
@@ -390,4 +410,27 @@ public class Project {
public void setVersion(int version) {
this.version = version;
}
+
+ public List<String> getProxyUserList() {
+ return new ArrayList<String>(proxyUsers);
+ }
+
+// public Object getSettingsObject() {
+// HashMap<String, Object> projectObject = new HashMap<String, Object>();
+// ArrayList<String> proxyUserList = new ArrayList<String>(proxyUsers);
+// projectObject.put("proxyUsers", proxyUserList);
+//
+// return projectObject;
+// }
+//
+// @SuppressWarnings("unchecked")
+// public static HashSet<String> proxyUserFromSettingsObj(Object object) {
+// Map<String, Object> settingsObj = (Map<String, Object>) object;
+//
+// List<String> proxyUserList = (List<String>) settingsObj.get("proxyUsers");
+// HashSet<String> proxyUsers = new HashSet<String>(proxyUserList);
+//
+// return proxyUsers;
+// }
+
}
diff --git a/src/java/azkaban/project/ProjectLoader.java b/src/java/azkaban/project/ProjectLoader.java
index 5d01a71..f1b04ed 100644
--- a/src/java/azkaban/project/ProjectLoader.java
+++ b/src/java/azkaban/project/ProjectLoader.java
@@ -2,6 +2,7 @@ package azkaban.project;
import java.io.File;
import java.util.Collection;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -221,5 +222,7 @@ public interface ProjectLoader {
Props fetchProjectProperty(int projectId, int projectVer, String propsName) throws ProjectManagerException;
List<Triple<String, Boolean, Permission>> getProjectPermissions(int projectId) throws ProjectManagerException;
+
+ void updateProjectSettings(Project project) throws ProjectManagerException;
}
\ No newline at end of file
diff --git a/src/java/azkaban/project/ProjectManager.java b/src/java/azkaban/project/ProjectManager.java
index e526474..d4ac2fb 100644
--- a/src/java/azkaban/project/ProjectManager.java
+++ b/src/java/azkaban/project/ProjectManager.java
@@ -217,6 +217,10 @@ public class ProjectManager {
return;
}
+ public void updateProjectSetting(Project project) throws ProjectManagerException {
+ projectLoader.updateProjectSettings(project);
+ }
+
public void updateProjectPermission(Project project, String name, Permission perm, boolean group, User modifier) throws ProjectManagerException {
logger.info("User " + modifier.getUserId() + " updating permissions for project " + project.getName() + " for " + name + " " + perm.toString());
projectLoader.updatePermission(project, name, perm, group);
@@ -329,4 +333,6 @@ public class ProjectManager {
public void postProjectEvent(Project project, EventType type, String user,String message) {
projectLoader.postEvent(project, type, user, message);
}
+
+
}
diff --git a/src/java/azkaban/user/UserManager.java b/src/java/azkaban/user/UserManager.java
index 114ccbe..e027c25 100644
--- a/src/java/azkaban/user/UserManager.java
+++ b/src/java/azkaban/user/UserManager.java
@@ -58,4 +58,6 @@ public interface UserManager {
* @return
*/
public Role getRole(String roleName);
+
+ public boolean validateProxyUser(String proxyUser, String realUser);
}
src/java/azkaban/user/XmlUserManager.java 35(+33 -2)
diff --git a/src/java/azkaban/user/XmlUserManager.java b/src/java/azkaban/user/XmlUserManager.java
index 09539b5..ab1fbe8 100644
--- a/src/java/azkaban/user/XmlUserManager.java
+++ b/src/java/azkaban/user/XmlUserManager.java
@@ -19,6 +19,7 @@ package azkaban.user;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
+import java.util.HashSet;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
@@ -53,6 +54,7 @@ public class XmlUserManager implements UserManager {
public static final String USERNAME_ATTR = "username";
public static final String PASSWORD_ATTR = "password";
public static final String ROLES_ATTR = "roles";
+ public static final String PROXY_ATTR = "proxy";
public static final String GROUPS_ATTR = "groups";
private String xmlPath;
@@ -60,6 +62,7 @@ public class XmlUserManager implements UserManager {
private HashMap<String, User> users;
private HashMap<String, String> userPassword;
private HashMap<String, Role> roles;
+ private HashMap<String, HashSet<String>> proxyUserMap;
/**
* The constructor.
@@ -81,6 +84,7 @@ public class XmlUserManager implements UserManager {
HashMap<String, User> users = new HashMap<String, User>();
HashMap<String, String> userPassword = new HashMap<String, String>();
HashMap<String, Role> roles = new HashMap<String, Role>();
+ HashMap<String, HashSet<String>> proxyUserMap = new HashMap<String, HashSet<String>>();
// Creating the document builder to parse xml.
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory
@@ -113,7 +117,7 @@ public class XmlUserManager implements UserManager {
Node node = azkabanUsersList.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
if (node.getNodeName().equals(USER_TAG)) {
- parseUserTag(node, users, userPassword);
+ parseUserTag(node, users, userPassword, proxyUserMap);
}
else if (node.getNodeName().equals(ROLE_TAG)) {
parseRoleTag(node, roles);
@@ -126,10 +130,11 @@ public class XmlUserManager implements UserManager {
this.users = users;
this.userPassword = userPassword;
this.roles = roles;
+ this.proxyUserMap = proxyUserMap;
}
}
- private void parseUserTag(Node node, HashMap<String, User> users, HashMap<String, String> userPassword) {
+ private void parseUserTag(Node node, HashMap<String, User> users, HashMap<String, String> userPassword, HashMap<String, HashSet<String>> proxyUserMap) {
NamedNodeMap userAttrMap = node.getAttributes();
Node userNameAttr = userAttrMap.getNamedItem(USERNAME_ATTR);
if (userNameAttr == null) {
@@ -157,6 +162,22 @@ public class XmlUserManager implements UserManager {
user.addRole(role);
}
}
+
+ Node proxy = userAttrMap.getNamedItem(PROXY_ATTR);
+ if (proxy != null) {
+ String value = proxy.getNodeValue();
+ String[] groupSplit = value.split("\\s*,\\s*");
+ for (String group : groupSplit) {
+ if(proxyUserMap.containsKey(username)) {
+ proxyUserMap.get(username).add(group);
+ }
+ else {
+ HashSet<String> proxySet = new HashSet<String>();
+ proxySet.add(group);
+ proxyUserMap.put(username, proxySet);
+ }
+ }
+ }
Node groups = userAttrMap.getNamedItem(GROUPS_ATTR);
if (groups != null) {
@@ -248,4 +269,14 @@ public class XmlUserManager implements UserManager {
// Return true. Validation should be added when groups are added to the xml.
return true;
}
+
+ @Override
+ public boolean validateProxyUser(String proxyUser, String realUser) {
+ if(proxyUserMap.containsKey(realUser) && proxyUserMap.get(realUser).contains(proxyUser)) {
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
}
diff --git a/src/java/azkaban/webapp/servlet/ProjectManagerServlet.java b/src/java/azkaban/webapp/servlet/ProjectManagerServlet.java
index 2f1403b..328b6d6 100644
--- a/src/java/azkaban/webapp/servlet/ProjectManagerServlet.java
+++ b/src/java/azkaban/webapp/servlet/ProjectManagerServlet.java
@@ -28,6 +28,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -36,6 +37,7 @@ import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import javax.swing.text.StyledEditorKit.BoldAction;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.io.FileUtils;
@@ -212,6 +214,11 @@ public class ProjectManagerServlet extends LoginAbstractAzkabanServlet {
ajaxAddPermission(project, ret, req, user);
}
}
+ else if (ajaxName.equals("addProxyUser")) {
+ if (handleAjaxPermission(project, user, Type.ADMIN, ret)) {
+ ajaxAddProxyUser(project, ret, req, user);
+ }
+ }
else if (ajaxName.equals("fetchFlowExecutions")) {
if (handleAjaxPermission(project, user, Type.READ, ret)) {
ajaxFetchFlowExecutions(project, ret, req);
@@ -546,6 +553,55 @@ public class ProjectManagerServlet extends LoginAbstractAzkabanServlet {
ret.put("nodes", nodeList);
}
+ private void ajaxAddProxyUser(Project project, HashMap<String, Object> ret, HttpServletRequest req, User user) throws ServletException {
+ String name = getParam(req, "name");
+
+ logger.info("Adding proxy user " + name + " by " + user.getUserId());
+
+
+
+ boolean doProxy = Boolean.parseBoolean(getParam(req, "doProxy"));
+
+
+ HashSet<String> proxyUsers = project.getProxyUsers();
+ //add
+ if(doProxy) {
+ if(proxyUsers.contains(name)) {
+ return;
+ }
+ else {
+ if(userManager.validateProxyUser(name, user.getUserId())) {
+ proxyUsers.add(name);
+ }
+ else {
+ ret.put("error", "User " + user.getUserId() + " has no permission to add " + name + " as proxy user for project " + project.getName());
+ return;
+ }
+ }
+ }
+ else {
+ if(!proxyUsers.contains(name)) {
+ return;
+ }
+ else {
+ if(userManager.validateProxyUser(name, user.getUserId())) {
+ proxyUsers.remove(name);
+ }
+ else {
+ ret.put("error", "User " + user.getUserId() + " has no permission to remove " + name + " as proxy user for project " + project.getName());
+ return;
+ }
+ }
+ }
+ try {
+ projectManager.updateProjectSetting(project);
+ } catch (ProjectManagerException e) {
+ // TODO Auto-generated catch block
+ ret.put("error", e.getMessage());
+ }
+
+ }
+
private void ajaxAddPermission(Project project, HashMap<String, Object> ret, HttpServletRequest req, User user) throws ServletException {
String name = getParam(req, "name");
boolean group = Boolean.parseBoolean(getParam(req, "group"));
@@ -792,6 +848,7 @@ public class ProjectManagerServlet extends LoginAbstractAzkabanServlet {
page.add("permissions", project.getUserPermissions());
page.add("groupPermissions", project.getGroupPermissions());
+ page.add("proxyUsers", project.getProxyUserList());
if(hasPermission(project, user, Type.ADMIN)) {
page.add("isAdmin", true);
diff --git a/src/java/azkaban/webapp/servlet/velocity/permissionspage.vm b/src/java/azkaban/webapp/servlet/velocity/permissionspage.vm
index 159bd05..9b13af6 100644
--- a/src/java/azkaban/webapp/servlet/velocity/permissionspage.vm
+++ b/src/java/azkaban/webapp/servlet/velocity/permissionspage.vm
@@ -71,6 +71,7 @@
#if($isAdmin)
<button id="addUser" class="btn1">Add User</button>
<button id="addGroup" class="btn1">Add Group</button>
+ <button id="addProxyUser" class="btn2">Add Proxy User</button>
#end
</div>
@@ -93,7 +94,7 @@
<th class="tb-read">Read</th>
<th class="tb-write">Write</th>
<th class="tb-execute">Execute</th>
- <th class="tb-schedule">Schedule</th>
+ <th class="tb-schedule">Schedule</th>
#if($isAdmin)
<th class="tb-action"></th>
#end
@@ -172,6 +173,45 @@
#end
</tbody>
</table>
+
+ <br></br>
+ <table id="proxy-user-table" class="all-jobs permission-table">
+ <thead>
+ <tr>
+ <th class="tb-username">Proxy User</th>
+ <th class="tb-perm">Admin</th>
+ <th class="tb-read">Read</th>
+ <th class="tb-write">Write</th>
+ <th class="tb-execute">Execute</th>
+ <th class="tb-schedule">Schedule</th>
+ <th class="tb-proxy">Proxy</th>
+ #if($isAdmin)
+ <th class="tb-action"></th>
+ #end
+ </tr>
+ </thead>
+ <tbody>
+#if($proxyUsers)
+#foreach($proxyUser in $proxyUsers)
+ <tr id="${proxyUser}-row" >
+ <td class="tb-name">#if($proxyUser == $username) ${proxyUser} <span class="sublabel">(you)</span> #else $proxyUser #end</td>
+ <td><input id="proxy-${proxyUser}-admin-checkbox" type="checkbox" name="admin" disabled="disabled" ></input></td>
+ <td><input id="proxy-${proxyUser}-read-checkbox" type="checkbox" name="read" disabled="disabled" ></input></td>
+ <td><input id="proxy-${proxyUser}-write-checkbox" type="checkbox" name="write" disabled="disabled" ></input></td>
+ <td><input id="proxy-${proxyUser}-execute-checkbox" type="checkbox" name="execute" disabled="disabled" ></input></td>
+ <td><input id="proxy-${proxyUser}-schedule-checkbox" type="checkbox" name="schedule" disabled="disabled" ></input></td>
+ <td><input id="proxy-${proxyUser}-proxy-checkbox" type="checkbox" name="proxy" disabled="disabled" checked="true"></input></td>
+
+ #if($isAdmin)
+ <td><button id="proxy-${proxyUser}" class="change-btn btn2">Change</button></td>
+ #end
+ </tr>
+#end
+#else
+ <tr><td class="last">No Proxy User Found.</td></tr>
+#end
+ </tbody>
+ </table>
#end
</div>
@@ -184,6 +224,7 @@
<dl>
<dt>User</dt>
<dd><input id="user-box" name="userid" type="text" /></dd>
+ <div id="otherCheckBoxes">
<dt class="nextline">Admin</dt>
<dd><input id="admin-change" name="admin" type="checkbox" /></dd>
<dt>Read</dt>
@@ -194,6 +235,11 @@
<dd><input id="execute-change" name="execute" type="checkbox" /></dd>
<dt>Schedule</dt>
<dd><input id="schedule-change" name="schedule" type="checkbox" /></dd>
+ </div>
+ <div id="proxyCheckBox" hidden=true>
+ <dt>Proxy</dt>
+ <dd><input id="proxy-change" name="proxy" type="checkbox" /></dd>
+ </div>
</dl>
</fieldset>
</div>
src/sql/create_project_table.sql 2(+2 -0)
diff --git a/src/sql/create_project_table.sql b/src/sql/create_project_table.sql
index e52fa76..34115a7 100644
--- a/src/sql/create_project_table.sql
+++ b/src/sql/create_project_table.sql
@@ -7,6 +7,8 @@ CREATE TABLE projects (
version INT,
last_modified_by VARCHAR(64) NOT NULL,
description VARCHAR(255),
+ enc_type TINYINT,
+ settings_blob LONGBLOB,
UNIQUE INDEX project_id (id),
INDEX project_name (name)
) ENGINE=InnoDB;
src/sql/update_2.0_to_2.01.sql 3(+3 -0)
diff --git a/src/sql/update_2.0_to_2.01.sql b/src/sql/update_2.0_to_2.01.sql
index cff37d2..493df5a 100644
--- a/src/sql/update_2.0_to_2.01.sql
+++ b/src/sql/update_2.0_to_2.01.sql
@@ -17,4 +17,7 @@ ALTER TABLE schedules ADD COLUMN schedule_options LONGBLOB;
ALTER TABLE project_events MODIFY COLUMN message VARCHAR(512);
+ALTER TABLE projects ADD COLUMN enc_type TINYINT;
+ALTER TABLE projects ADD COLUMN settings_blob LONGBLOB;
+
src/web/js/azkaban.permission.view.js 79(+69 -10)
diff --git a/src/web/js/azkaban.permission.view.js b/src/web/js/azkaban.permission.view.js
index 429b8ed..e04bc55 100644
--- a/src/web/js/azkaban.permission.view.js
+++ b/src/web/js/azkaban.permission.view.js
@@ -2,18 +2,20 @@ $.namespace('azkaban');
var permissionTableView;
var groupPermissionTableView;
+var proxyTableView;
azkaban.PermissionTableView= Backbone.View.extend({
events : {
"click button": "handleChangePermission"
},
initialize : function(settings) {
this.group = settings.group;
+ this.proxy = settings.proxy;
},
render: function() {
},
handleChangePermission: function(evt) {
var currentTarget = evt.currentTarget;
- changePermissionView.display(currentTarget.id, false, this.group);
+ changePermissionView.display(currentTarget.id, false, this.group, this.proxy);
}
});
@@ -27,13 +29,22 @@ azkaban.ChangePermissionView= Backbone.View.extend({
initialize : function(settings) {
$('#errorMsg').hide();
},
- display: function(userid, newPerm, group) {
+ display: function(userid, newPerm, group, proxy) {
// 6 is the length of the prefix "group-"
this.userid = group ? userid.substring(6, userid.length) : userid;
+ if(group == true) {
+ this.userid = userid.substring(6, userid.length)
+ } else if (proxy == true) {
+ this.userid = userid.substring(6, userid.length)
+ } else {
+ this.userid = userid
+ }
+
this.permission = {};
$('#user-box').val(this.userid);
this.newPerm = newPerm;
this.group = group;
+ this.proxy = proxy;
var prefix = userid;
var adminInput = $("#" + prefix + "-admin-checkbox");
@@ -41,12 +52,16 @@ azkaban.ChangePermissionView= Backbone.View.extend({
var writeInput = $("#" + prefix + "-write-checkbox");
var executeInput = $("#" + prefix + "-execute-checkbox");
var scheduleInput = $("#" + prefix + "-schedule-checkbox");
+ var proxyInput = $("#" + prefix + "-proxy-checkbox");
if (newPerm) {
if (group) {
$('#change-title').text("Add New Group Permissions");
}
- else {
+ else if(proxy){
+ $('#change-title').text("Add New Proxy User Permissions");
+ }
+ else{
$('#change-title').text("Add New User Permissions");
}
$('#user-box').attr("disabled", null);
@@ -57,22 +72,39 @@ azkaban.ChangePermissionView= Backbone.View.extend({
this.permission.write = false;
this.permission.execute = false;
this.permission.schedule = false;
+ this.doProxy = false;
+
}
else {
if (group) {
$('#change-title').text("Change Group Permissions");
}
+ else if(proxy){
+ $('#change-title').text("Change Proxy User Permissions");
+ this.doProxy = $(proxyInput).attr("checked");
+ }
else {
$('#change-title').text("Change User Permissions");
}
$('#user-box').attr("disabled", "disabled");
+
+
this.permission.admin = $(adminInput).attr("checked");
this.permission.read = $(readInput).attr("checked");
this.permission.write = $(writeInput).attr("checked");
this.permission.execute = $(executeInput).attr("checked");
this.permission.schedule = $(scheduleInput).attr("checked");
+ this.doProxy = $(proxyInput).attr("checked");
+ }
+
+ if(proxy) {
+ document.getElementById("otherCheckBoxes").hidden=true;
+ document.getElementById("proxyCheckBox").hidden=false;
+ } else {
+ document.getElementById("otherCheckBoxes").hidden=false;
+ document.getElementById("proxyCheckBox").hidden=true;
}
this.changeCheckbox();
@@ -91,17 +123,27 @@ azkaban.ChangePermissionView= Backbone.View.extend({
$("#errorMsg").hide();
}
});
+
+
+
},
render: function() {
},
handleCheckboxClick : function(evt) {
console.log("click");
var targetName = evt.currentTarget.name;
- this.permission[targetName] = evt.currentTarget.checked;
+ if(targetName == "proxy") {
+ this.doProxy = evt.currentTarget.checked;
+ }
+ else {
+ this.permission[targetName] = evt.currentTarget.checked;
+ }
this.changeCheckbox(evt);
},
changeCheckbox : function(evt) {
var perm = this.permission;
+ var proxy = this.proxy;
+ var doProxy = this.doProxy;
if (perm.admin) {
$("#admin-change").attr("checked", true);
@@ -116,9 +158,13 @@ azkaban.ChangePermissionView= Backbone.View.extend({
$("#schedule-change").attr("checked", true);
$("#schedule-change").attr("disabled", "disabled");
+
+ $("#proxy-change").attr("checked", false);
+ $("#proxy-change").attr("disabled", "disabled");
}
else {
$("#admin-change").attr("checked", false);
+
$("#read-change").attr("checked", perm.read);
$("#read-change").attr("disabled", null);
@@ -130,12 +176,16 @@ azkaban.ChangePermissionView= Backbone.View.extend({
$("#schedule-change").attr("checked", perm.schedule);
$("#schedule-change").attr("disabled", null);
+
+ $("#proxy-change").attr("checked", doProxy);
+ $("#proxy-change").attr("disabled", null);
+
}
$("#change-btn").removeClass("btn-disabled");
$("#change-btn").attr("disabled", null);
- if (perm.admin || perm.read || perm.write || perm.execute || perm.schedule) {
+ if (perm.admin || perm.read || perm.write || perm.execute || perm.schedule || doProxy) {
$("#change-btn").text("Commit");
}
else {
@@ -152,11 +202,14 @@ azkaban.ChangePermissionView= Backbone.View.extend({
var requestURL = contextURL + "/manager";
var name = $('#user-box').val();
var command = this.newPerm ? "addPermission" : "changePermission";
+ if(this.proxy) {
+ command = "addProxyUser";
+ }
var group = this.group;
$.get(
requestURL,
- {"project": projectName, "name": name, "ajax":command, "permissions": this.permission, "group": group},
+ {"project": projectName, "name": name, "ajax":command, "permissions": this.permission, "doProxy": this.doProxy, "group": group},
function(data) {
console.log("Output");
if (data.error) {
@@ -174,15 +227,21 @@ azkaban.ChangePermissionView= Backbone.View.extend({
});
$(function() {
- permissionTableView = new azkaban.PermissionTableView({el:$('#permissions-table'), group: false});
- groupPermissionTableView = new azkaban.PermissionTableView({el:$('#group-permissions-table'), group: true});
+ permissionTableView = new azkaban.PermissionTableView({el:$('#permissions-table'), group: false, proxy: false});
+ groupPermissionTableView = new azkaban.PermissionTableView({el:$('#group-permissions-table'), group: true, proxy: false});
+ proxyTableView = new azkaban.PermissionTableView({el:$('#proxy-user-table'), group: false, proxy: true});
changePermissionView = new azkaban.ChangePermissionView({el:$('#change-permission')});
$('#addUser').bind('click', function() {
- changePermissionView.display("", true, false);
+ changePermissionView.display("", true, false, false);
});
$('#addGroup').bind('click', function() {
- changePermissionView.display("", true, true);
+ changePermissionView.display("", true, true, false);
});
+
+ $('#addProxyUser').bind('click', function() {
+ changePermissionView.display("", true, false, true);
+ });
+
});
diff --git a/unit/java/azkaban/test/execapp/JobRunnerTest.java b/unit/java/azkaban/test/execapp/JobRunnerTest.java
index 056cbac..e7f15a8 100644
--- a/unit/java/azkaban/test/execapp/JobRunnerTest.java
+++ b/unit/java/azkaban/test/execapp/JobRunnerTest.java
@@ -3,6 +3,7 @@ package azkaban.test.execapp;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import junit.framework.Assert;
@@ -263,7 +264,7 @@ public class JobRunnerTest {
node.setExecutableFlow(flow);
Props props = createProps(time, fail);
- List<String> proxyUsers = new ArrayList<String>();
+ HashSet<String> proxyUsers = new HashSet<String>();
proxyUsers.add(flow.getSubmitUser());
JobRunner runner = new JobRunner(node, props, workingDir, proxyUsers, loader, jobtypeManager, logger);
diff --git a/unit/java/azkaban/test/execapp/MockProjectLoader.java b/unit/java/azkaban/test/execapp/MockProjectLoader.java
index 165f0c9..b10ea29 100644
--- a/unit/java/azkaban/test/execapp/MockProjectLoader.java
+++ b/unit/java/azkaban/test/execapp/MockProjectLoader.java
@@ -217,4 +217,11 @@ public class MockProjectLoader implements ProjectLoader {
// TODO Auto-generated method stub
return null;
}
+
+ @Override
+ public void updateProjectSettings(Project project)
+ throws ProjectManagerException {
+ // TODO Auto-generated method stub
+
+ }
}
\ No newline at end of file