azkaban-developers
Details
build.gradle 51(+47 -4)
diff --git a/build.gradle b/build.gradle
index a013b46..9681ba7 100644
--- a/build.gradle
+++ b/build.gradle
@@ -40,13 +40,15 @@ configurations {
compile {
description = 'compile classpath'
}
+ generateRestli {
+ transitive = true
+ }
test {
extendsFrom compile
}
}
-configurations.compile {
- description = 'compile classpath'
-}
+
+pegasusVersion = '1.13.4'
dependencies {
compile (
@@ -77,7 +79,21 @@ dependencies {
[group: 'mysql', name:'mysql-connector-java', version: '5.1.28'],
[group: 'javax.servlet', name:'servlet-api', version: '2.5'],
[group: 'org.slf4j', name:'slf4j-api', version: '1.6.1'],
- [group: 'org.apache.velocity', name:'velocity', version: '1.7']
+ [group: 'org.apache.velocity', name:'velocity', version: '1.7'],
+ [group: 'com.linkedin.pegasus', name: 'gradle-plugins', version: pegasusVersion],
+ [group: 'com.linkedin.pegasus', name: 'pegasus-common', version: pegasusVersion],
+ [group: 'com.linkedin.pegasus', name: 'restli-common', version: pegasusVersion],
+ [group: 'com.linkedin.pegasus', name: 'restli-server', version: pegasusVersion],
+ [group: 'com.linkedin.pegasus', name: 'data', version: pegasusVersion],
+ [group: 'com.linkedin.pegasus', name: 'r2', version: pegasusVersion],
+ [group: 'com.linkedin.pegasus', name: 'li-jersey-uri', version: pegasusVersion],
+ [group: 'com.linkedin.parseq', name: 'parseq', version: '1.3.7'],
+ [group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.3.2']
+ )
+
+ generateRestli (
+ [group: 'com.linkedin.pegasus', name:'generator', version: pegasusVersion],
+ [group: 'com.linkedin.pegasus', name:'restli-tools', version: pegasusVersion]
)
testCompile (
@@ -85,6 +101,14 @@ dependencies {
)
}
+sourceSets {
+ main {
+ java {
+ srcDirs 'src/main/java', 'src/restli/generatedJava', 'src/restli/java'
+ }
+ }
+}
+
jar {
baseName = 'azkaban'
manifest {
@@ -95,6 +119,25 @@ jar {
}
}
+task restliTemplateGenerator(type: JavaExec) {
+ mkdir 'src/restli/generatedJava'
+
+ main = 'com.linkedin.pegasus.generator.PegasusDataTemplateGenerator'
+ args = ['src/restli/generatedJava','src/restli/schemas']
+ classpath = configurations.generateRestli
+}
+
+task restliRestSpecGenerator(dependsOn: [build,restliTemplateGenerator], type: JavaExec) {
+ mkdir 'src/restli/generatedRestSpec'
+
+ main = 'com.linkedin.restli.tools.idlgen.RestLiResourceModelExporterCmdLineApp'
+ args = ['-outdir', 'src/restli/generatedRestSpec', '-sourcepath', 'src/restli/java']
+ classpath = configurations.generateRestli
+}
+
+task restli(dependsOn: restliTemplateGenerator) {
+}
+
eclipse.classpath.file {
// Erase the whole classpath
beforeMerged {
diff --git a/src/main/java/azkaban/webapp/AzkabanWebServer.java b/src/main/java/azkaban/webapp/AzkabanWebServer.java
index ebb0aa0..65b656b 100644
--- a/src/main/java/azkaban/webapp/AzkabanWebServer.java
+++ b/src/main/java/azkaban/webapp/AzkabanWebServer.java
@@ -50,6 +50,8 @@ import org.mortbay.jetty.servlet.DefaultServlet;
import org.mortbay.jetty.servlet.ServletHolder;
import org.mortbay.thread.QueuedThreadPool;
+import com.linkedin.restli.server.RestliServlet;
+
import azkaban.alert.Alerter;
import azkaban.database.AzkabanDatabaseSetup;
import azkaban.executor.ExecutorManager;
@@ -158,6 +160,10 @@ public class AzkabanWebServer extends AzkabanServer {
private MBeanServer mbeanServer;
private ArrayList<ObjectName> registeredMBeans = new ArrayList<ObjectName>();
+ public static AzkabanWebServer getInstance() {
+ return app;
+ }
+
/**
* Constructor usually called by tomcat AzkabanServletContext to create the
* initial server
@@ -762,6 +768,10 @@ public class AzkabanWebServer extends AzkabanServer {
root.addServlet(new ServletHolder(new ScheduleServlet()),"/schedule");
root.addServlet(new ServletHolder(new JMXHttpServlet()),"/jmx");
root.addServlet(new ServletHolder(new TriggerManagerServlet()),"/triggers");
+
+ ServletHolder restliHolder = new ServletHolder(new RestliServlet());
+ restliHolder.setInitParameter("resourcePackages", "azkaban.restli");
+ root.addServlet(restliHolder, "/restli/*");
String viewerPluginDir = azkabanSettings.getString("viewer.plugin.dir", "plugins/viewer");
loadViewerPlugins(root, viewerPluginDir, app.getVelocityEngine());
src/restli/.gitignore 2(+2 -0)
diff --git a/src/restli/.gitignore b/src/restli/.gitignore
new file mode 100644
index 0000000..a6ad54c
--- /dev/null
+++ b/src/restli/.gitignore
@@ -0,0 +1,2 @@
+generatedJava
+generatedRestSpec
diff --git a/src/restli/java/azkaban/restli/LoginResource.java b/src/restli/java/azkaban/restli/LoginResource.java
new file mode 100644
index 0000000..c7aedcd
--- /dev/null
+++ b/src/restli/java/azkaban/restli/LoginResource.java
@@ -0,0 +1,83 @@
+package azkaban.restli;
+
+import java.util.UUID;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+
+import azkaban.restli.user.User;
+import azkaban.user.UserManager;
+import azkaban.user.UserManagerException;
+import azkaban.webapp.AzkabanServer;
+import azkaban.webapp.AzkabanWebServer;
+import azkaban.webapp.session.Session;
+
+import com.linkedin.restli.server.annotations.Action;
+import com.linkedin.restli.server.annotations.ActionParam;
+import com.linkedin.restli.server.annotations.Context;
+import com.linkedin.restli.server.annotations.RestLiActions;
+import com.linkedin.restli.server.resources.ResourceContextHolder;
+
+@RestLiActions(name = "login", namespace = "azkaban.restli")
+public class LoginResource extends ResourceContextHolder {
+ private AzkabanServer azkaban;
+
+ public AzkabanWebServer getAzkaban() {
+ return AzkabanWebServer.getInstance();
+ }
+
+ public void setAzkaban(AzkabanServer azkaban) {
+ this.azkaban = azkaban;
+ }
+
+ @Action(name = "login")
+ public String login(
+ @ActionParam("username") String username,
+ @ActionParam("password") String password)
+ throws UserManagerException, ServletException {
+// String ip = requestContext.getRemoteAddr();
+//
+// Session session = createSession(username, password, ip);
+// return session.getSessionId();
+ return "123";
+ }
+
+ @Action(name = "getUserFromSessionId")
+ public User getUserFromSessionId(@ActionParam("sessionId") String sessionId) {
+ // String ip = req.getRemoteAddr();
+ String ip = this.getContext().getParameter("ip");
+ Session session = getSessionFromSessionId(sessionId, ip);
+ azkaban.user.User azUser = session.getUser();
+
+ // Fill out the restli object with properties from the Azkaban user
+ User user = new User();
+ user.setUserId(azUser.getUserId());
+ user.setEmail(azUser.getEmail());
+ return user;
+ }
+
+ private Session createSession(String username, String password, String ip)
+ throws UserManagerException, ServletException {
+ UserManager manager = getAzkaban().getUserManager();
+ azkaban.user.User user = manager.getUser(username, password);
+
+ String randomUID = UUID.randomUUID().toString();
+ Session session = new Session(randomUID, user, ip);
+
+ return session;
+ }
+
+ private Session getSessionFromSessionId(String sessionId, String remoteIp) {
+ if (sessionId == null) {
+ return null;
+ }
+
+ Session session = getAzkaban().getSessionCache().getSession(sessionId);
+ // Check if the IP's are equal. If not, we invalidate the sesson.
+ if (session == null || !remoteIp.equals(session.getIp())) {
+ return null;
+ }
+
+ return session;
+ }
+}
\ No newline at end of file
diff --git a/src/restli/schemas/azkaban/restli/user/User.pdsc b/src/restli/schemas/azkaban/restli/user/User.pdsc
new file mode 100644
index 0000000..156b380
--- /dev/null
+++ b/src/restli/schemas/azkaban/restli/user/User.pdsc
@@ -0,0 +1,10 @@
+{
+ "type": "record",
+ "name": "User",
+ "namespace": "azkaban.restli.user",
+ "doc": "Azkaban User restli info",
+ "fields": [
+ {"name": "userId", "type": "string","doc": "The username this session"},
+ {"name": "email", "type": "string","doc": "User email"}
+ ]
+}
\ No newline at end of file