azkaban-aplcache

First working Restli in Azkaban.

3/26/2014 6:34:24 PM

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());
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