Details
diff --git a/azkaban-common/src/main/java/azkaban/project/JdbcProjectLoader.java b/azkaban-common/src/main/java/azkaban/project/JdbcProjectLoader.java
index bde18ec..2102b43 100644
--- a/azkaban-common/src/main/java/azkaban/project/JdbcProjectLoader.java
+++ b/azkaban-common/src/main/java/azkaban/project/JdbcProjectLoader.java
@@ -169,6 +169,67 @@ public class JdbcProjectLoader extends AbstractJdbcLoader implements
return project;
}
+ /**
+ * Fetch first project with a given name {@inheritDoc}
+ *
+ * @see azkaban.project.ProjectLoader#fetchProjectByName(java.lang.String)
+ */
+ @Override
+ public Project fetchProjectByName(String name)
+ throws ProjectManagerException {
+ Connection connection = getConnection();
+
+ Project project = null;
+ try {
+ project = fetchProjectByName(connection, name);
+ } finally {
+ DbUtils.closeQuietly(connection);
+ }
+
+ return project;
+ }
+
+ private Project fetchProjectByName(Connection connection, String name)
+ throws ProjectManagerException {
+ QueryRunner runner = new QueryRunner();
+ // Fetch the project
+ Project project = null;
+ ProjectResultHandler handler = new ProjectResultHandler();
+ try {
+ List<Project> projects =
+ runner.query(connection,
+ ProjectResultHandler.SELECT_PROJECT_BY_NAME, handler, name);
+ if (projects.isEmpty()) {
+ throw new ProjectManagerException(
+ "No active project with name " + name + " exists in db.");
+ }
+
+ project = projects.get(0);
+ } catch (SQLException e) {
+ logger.error(ProjectResultHandler.SELECT_PROJECT_BY_NAME
+ + " failed.");
+ throw new ProjectManagerException(
+ "Query for existing project failed. Project " + name, e);
+ }
+
+ // Fetch the user permissions
+ List<Triple<String, Boolean, Permission>> permissions =
+ fetchPermissionsForProject(connection, project);
+
+ for (Triple<String, Boolean, Permission> perm : permissions) {
+ if (perm.getThird().toFlags() != 0) {
+ if (perm.getSecond()) {
+ project
+ .setGroupPermission(perm.getFirst(), perm.getThird());
+ } else {
+ project.setUserPermission(perm.getFirst(), perm.getThird());
+ }
+ }
+ }
+
+ return project;
+ }
+
private List<Triple<String, Boolean, Permission>> fetchPermissionsForProject(
Connection connection, Project project) throws ProjectManagerException {
ProjectPermissionsResultHandler permHander =
@@ -1136,6 +1197,9 @@ public class JdbcProjectLoader extends AbstractJdbcLoader implements
private static class ProjectResultHandler implements
ResultSetHandler<List<Project>> {
+ private static String SELECT_PROJECT_BY_NAME =
+ "SELECT id, name, active, modified_time, create_time, version, last_modified_by, description, enc_type, settings_blob FROM projects WHERE name=?";
+
private static String SELECT_PROJECT_BY_ID =
"SELECT id, name, active, modified_time, create_time, version, last_modified_by, description, enc_type, settings_blob FROM projects WHERE id=?";
diff --git a/azkaban-common/src/main/java/azkaban/project/ProjectLoader.java b/azkaban-common/src/main/java/azkaban/project/ProjectLoader.java
index 371599f..aa886d6 100644
--- a/azkaban-common/src/main/java/azkaban/project/ProjectLoader.java
+++ b/azkaban-common/src/main/java/azkaban/project/ProjectLoader.java
@@ -48,6 +48,14 @@ public interface ProjectLoader {
public Project fetchProjectById(int id) throws ProjectManagerException;
/**
+ * Loads whole project, including permissions, by the project name.
+ * @param name
+ * @return
+ * @throws ProjectManagerException
+ */
+ public Project fetchProjectByName(String name) throws ProjectManagerException;
+
+ /**
* Should create an empty project with the given name and user and adds it to
* the data store. It will auto assign a unique id for this project if
* successful.
@@ -269,5 +277,4 @@ public interface ProjectLoader {
throws ProjectManagerException;
void updateProjectSettings(Project project) throws ProjectManagerException;
-
}
diff --git a/azkaban-common/src/main/java/azkaban/project/ProjectLogEvent.java b/azkaban-common/src/main/java/azkaban/project/ProjectLogEvent.java
index a19d013..5512291 100644
--- a/azkaban-common/src/main/java/azkaban/project/ProjectLogEvent.java
+++ b/azkaban-common/src/main/java/azkaban/project/ProjectLogEvent.java
@@ -32,7 +32,8 @@ public class ProjectLogEvent {
UPLOADED(6),
SCHEDULE(7),
SLA(8),
- PROXY_USER(9);
+ PROXY_USER(9),
+ PURGE(10);
private int numVal;
@@ -64,6 +65,8 @@ public class ProjectLogEvent {
return SLA;
case 9:
return PROXY_USER;
+ case 10:
+ return PURGE;
case 128:
return ERROR;
default:
diff --git a/azkaban-common/src/main/java/azkaban/project/ProjectManager.java b/azkaban-common/src/main/java/azkaban/project/ProjectManager.java
index 89c6539..450e76d 100644
--- a/azkaban-common/src/main/java/azkaban/project/ProjectManager.java
+++ b/azkaban-common/src/main/java/azkaban/project/ProjectManager.java
@@ -204,6 +204,34 @@ public class ProjectManager {
return projectsById.get(id);
}
+ /**
+ * fetch inactive project from db by project_id
+ *
+ * @param name
+ * @return
+ */
+ public Project getInactiveProject(String name) {
+ try {
+ return projectLoader.fetchProjectByName(name);
+ } catch (ProjectManagerException e) {
+ throw new RuntimeException("Could not load project from store.", e);
+ }
+ }
+
+ /**
+ * fetch inactive project from db by project_name
+ *
+ * @param name
+ * @return
+ */
+ public Project getInactiveProject(int id) {
+ try {
+ return projectLoader.fetchProjectById(id);
+ } catch (ProjectManagerException e) {
+ throw new RuntimeException("Could not load project from store.", e);
+ }
+ }
+
public Project createProject(String projectName, String description,
User creator) throws ProjectManagerException {
if (projectName == null || projectName.trim().isEmpty()) {
@@ -249,6 +277,25 @@ public class ProjectManager {
return newProject;
}
+ /**
+ * Permanently delete all project files and properties data for all versions
+ * of a project and log event in project_events table
+ *
+ * @param project
+ * @param deleter
+ * @return
+ * @throws ProjectManagerException
+ */
+ public synchronized Project purgeProject(Project project, User deleter)
+ throws ProjectManagerException {
+ projectLoader.cleanOlderProjectVersion(project.getId(),
+ project.getVersion() + 1);
+ projectLoader
+ .postEvent(project, EventType.PURGE, deleter.getUserId(), String
+ .format("Purged versions before %d", project.getVersion() + 1));
+ return project;
+ }
+
public synchronized Project removeProject(Project project, User deleter)
throws ProjectManagerException {
projectLoader.removeProject(project, deleter.getUserId());
diff --git a/azkaban-common/src/test/java/azkaban/project/JdbcProjectLoaderTest.java b/azkaban-common/src/test/java/azkaban/project/JdbcProjectLoaderTest.java
index a7ef5f3..d9b673d 100644
--- a/azkaban-common/src/test/java/azkaban/project/JdbcProjectLoaderTest.java
+++ b/azkaban-common/src/test/java/azkaban/project/JdbcProjectLoaderTest.java
@@ -28,7 +28,6 @@ import javax.sql.DataSource;
import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;
-
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Ignore;
@@ -214,6 +213,96 @@ public class JdbcProjectLoaderTest {
DbUtils.closeQuietly(connection);
}
+ /** Test case to validated permissions for fetchProjectByName **/
+ @Test
+ public void testPermissionRetrivalByFetchProjectByName()
+ throws ProjectManagerException {
+ if (!isTestSetup()) {
+ return;
+ }
+
+ ProjectLoader loader = createLoader();
+ String projectName = "mytestProject";
+ String projectDescription = "This is my new project";
+ User user = new User("testUser");
+
+ Project project =
+ loader.createNewProject(projectName, projectDescription, user);
+
+ Permission perm = new Permission(0x2);
+ loader.updatePermission(project, user.getUserId(), perm, false);
+ loader.updatePermission(project, "group", perm, true);
+
+ Permission permOverride = new Permission(0x6);
+ loader.updatePermission(project, user.getUserId(), permOverride, false);
+
+ Project fetchedProject = loader.fetchProjectByName(project.getName());
+ assertProjectMemberEquals(project, fetchedProject);
+ Assert.assertEquals(permOverride,
+ fetchedProject.getUserPermission(user.getUserId()));
+ }
+
+ /** Default Test case for fetchProjectByName **/
+ @Test
+ public void testProjectRetrivalByFetchProjectByName()
+ throws ProjectManagerException {
+ if (!isTestSetup()) {
+ return;
+ }
+
+ ProjectLoader loader = createLoader();
+ String projectName = "mytestProject";
+ String projectDescription = "This is my new project";
+ User user = new User("testUser");
+
+ Project project =
+ loader.createNewProject(projectName, projectDescription, user);
+
+ Project fetchedProject = loader.fetchProjectByName(project.getName());
+ assertProjectMemberEquals(project, fetchedProject);
+ }
+
+ /** Default Test case for fetchProjectByName **/
+ @Test
+ public void testDuplicateRetrivalByFetchProjectByName()
+ throws ProjectManagerException {
+ if (!isTestSetup()) {
+ return;
+ }
+
+ ProjectLoader loader = createLoader();
+ String projectName = "mytestProject";
+ String projectDescription = "This is my new project";
+ User user = new User("testUser");
+
+ Project project =
+ loader.createNewProject(projectName, projectDescription, user);
+
+ loader.removeProject(project, user.getUserId());
+
+ Project newProject =
+ loader.createNewProject(projectName, projectDescription, user);
+
+ Project fetchedProject = loader.fetchProjectByName(project.getName());
+ Assert.assertEquals(newProject.getId(), fetchedProject.getId());
+
+ }
+
+ /** Test case for NonExistantProject project fetch **/
+ @Test
+ public void testInvalidProjectByFetchProjectByName() {
+ if (!isTestSetup()) {
+ return;
+ }
+ ProjectLoader loader = createLoader();
+ try {
+ loader.fetchProjectByName("NonExistantProject");
+ } catch (ProjectManagerException ex) {
+ System.out.println("Test true");
+ }
+ Assert.fail("No exception");
+ }
+
@Test
public void testCreateProject() throws ProjectManagerException {
if (!isTestSetup()) {
diff --git a/azkaban-common/src/test/java/azkaban/project/MockProjectLoader.java b/azkaban-common/src/test/java/azkaban/project/MockProjectLoader.java
index 909b82e..42d57b7 100644
--- a/azkaban-common/src/test/java/azkaban/project/MockProjectLoader.java
+++ b/azkaban-common/src/test/java/azkaban/project/MockProjectLoader.java
@@ -243,4 +243,10 @@ public class MockProjectLoader implements ProjectLoader {
// TODO Auto-generated method stub
}
+
+@Override
+public Project fetchProjectByName(String name) throws ProjectManagerException {
+ // TODO Auto-generated method stub
+ return null;
+}
}
diff --git a/azkaban-webserver/src/main/java/azkaban/webapp/servlet/ProjectManagerServlet.java b/azkaban-webserver/src/main/java/azkaban/webapp/servlet/ProjectManagerServlet.java
index 435e1f9..33295a8 100644
--- a/azkaban-webserver/src/main/java/azkaban/webapp/servlet/ProjectManagerServlet.java
+++ b/azkaban-webserver/src/main/java/azkaban/webapp/servlet/ProjectManagerServlet.java
@@ -148,6 +148,8 @@ public class ProjectManagerServlet extends LoginAbstractAzkabanServlet {
handleFlowPage(req, resp, session);
} else if (hasParam(req, "delete")) {
handleRemoveProject(req, resp, session);
+ } else if (hasParam(req, "purge")) {
+ handlePurgeProject(req, resp, session);
} else if (hasParam(req, "download")) {
handleDownloadProject(req, resp, session);
} else {
@@ -518,6 +520,50 @@ public class ProjectManagerServlet extends LoginAbstractAzkabanServlet {
}
+ /**
+ * validate readiness of a project and user permission and use
+ * projectManager to purge the project if things looks good
+ **/
+ private void handlePurgeProject(HttpServletRequest req,
+ HttpServletResponse resp, Session session) throws ServletException,
+ IOException {
+ User user = session.getUser();
+ String projectName = getParam(req, "project");
+ HashMap<String, Object> ret = new HashMap<String, Object>();
+ boolean valid = true;
+
+ Project project = projectManager.getProject(projectName);
+ if (project != null) {
+ ret.put("error", "Project " + projectName
+ + " should be deleted before purging");
+ valid = false;
+ }
+
+ // project is already deleted
+ if (valid) {
+ project = projectManager.getInactiveProject(projectName);
+ // only eligible users can purge a project
+ if (!hasPermission(project, user, Type.ADMIN)) {
+ ret.put("error", "Cannot purge. User '" + user.getUserId()
+ + "' is not an ADMIN.");
+ valid = false;
+ ;
+ }
+ }
+
+ if (valid) {
+ try {
+ projectManager.purgeProject(project, user);
+ } catch (ProjectManagerException e) {
+ ret.put("error", e.getMessage());
+ valid = false;
+ }
+ }
+
+ ret.put("success", valid);
+ this.writeJSON(resp, ret);
+ }
+
private void handleRemoveProject(HttpServletRequest req,
HttpServletResponse resp, Session session) throws ServletException,
IOException {