You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by jo...@apache.org on 2014/09/20 16:54:26 UTC
[08/14] git commit: AMBARI-7348. Single Sign-On with Views API to
impersonate account (alejandro)
AMBARI-7348. Single Sign-On with Views API to impersonate account (alejandro)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/40050513
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/40050513
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/40050513
Branch: refs/heads/branch-alerts-dev
Commit: 40050513e2cecaabf4139e40e09f8b198e6a7bd5
Parents: 1f7dbd5
Author: Alejandro Fernandez <af...@hortonworks.com>
Authored: Wed Sep 17 19:52:41 2014 -0700
Committer: Alejandro Fernandez <af...@hortonworks.com>
Committed: Fri Sep 19 11:47:20 2014 -0700
----------------------------------------------------------------------
.../controller/internal/URLStreamProvider.java | 4 +
.../ambari/server/proxy/ProxyService.java | 17 +-
.../server/view/HttpImpersonatorImpl.java | 167 +++++++++++++++++++
.../server/view/ImpersonatorSettingImpl.java | 63 +++++++
.../ambari/server/view/ViewContextImpl.java | 18 +-
.../ambari/server/proxy/ProxyServiceTest.java | 14 ++
.../server/view/HttpImpersonatorImplTest.java | 128 ++++++++++++++
.../apache/ambari/view/HttpImpersonator.java | 53 ++++++
.../apache/ambari/view/ImpersonatorSetting.java | 46 +++++
.../org/apache/ambari/view/ViewContext.java | 15 ++
ambari-web/app/utils/ajax/ajax.js | 22 ---
contrib/views/jobs/pom.xml | 15 ++
.../apache/ambari/view/jobs/ProxyServlet.java | 68 ++++++++
.../jobs/src/main/resources/WEB-INF/web.xml | 37 ++++
.../app/scripts/controllers/jobs_controller.js | 10 +-
.../resources/ui/app/scripts/helpers/ajax.js | 25 ++-
.../resources/ui/app/scripts/helpers/jobs.js | 15 +-
.../ui/app/scripts/routes/application_route.js | 8 +
18 files changed, 687 insertions(+), 38 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/40050513/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/URLStreamProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/URLStreamProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/URLStreamProvider.java
index 2b32d11..1b57c84 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/URLStreamProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/URLStreamProvider.java
@@ -218,4 +218,8 @@ public class URLStreamProvider implements StreamProvider {
return connection;
}
+
+ public AppCookieManager getAppCookieManager() {
+ return appCookieManager;
+ }
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/40050513/ambari-server/src/main/java/org/apache/ambari/server/proxy/ProxyService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/proxy/ProxyService.java b/ambari-server/src/main/java/org/apache/ambari/server/proxy/ProxyService.java
index 30e998b..2cdffef 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/proxy/ProxyService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/proxy/ProxyService.java
@@ -20,6 +20,7 @@ package org.apache.ambari.server.proxy;
import com.google.gson.Gson;
import org.apache.ambari.server.controller.internal.URLStreamProvider;
+import org.apache.ambari.server.view.ImpersonatorSettingImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -36,6 +37,7 @@ import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
import java.io.IOException;
import java.io.InputStream;
@@ -48,9 +50,9 @@ import java.util.HashMap;
@Path("/")
public class ProxyService {
- private static final int URL_CONNECT_TIMEOUT = 20000;
- private static final int URL_READ_TIMEOUT = 15000;
- private static final int HTTP_ERROR_RANGE_START = Response.Status.BAD_REQUEST.getStatusCode();
+ public static final int URL_CONNECT_TIMEOUT = 20000;
+ public static final int URL_READ_TIMEOUT = 15000;
+ public static final int HTTP_ERROR_RANGE_START = Response.Status.BAD_REQUEST.getStatusCode();
private static final String REQUEST_TYPE_GET = "GET";
private static final String REQUEST_TYPE_POST = "POST";
@@ -59,6 +61,7 @@ public class ProxyService {
private static final String QUERY_PARAMETER_URL = "url=";
private static final String AMBARI_PROXY_PREFIX = "AmbariProxy-";
private static final String ERROR_PROCESSING_URL = "Error occurred during processing URL ";
+ private static final String INVALID_PARAM_IN_URL = "Invalid query params found in URL ";
private final static Logger LOG = LoggerFactory.getLogger(ProxyService.class);
@@ -90,6 +93,14 @@ public class ProxyService {
String query = ui.getRequestUri().getQuery();
if (query != null && query.indexOf(QUERY_PARAMETER_URL) != -1) {
String url = query.replaceFirst(QUERY_PARAMETER_URL, "");
+
+ MultivaluedMap<String, String> m = ui.getQueryParameters();
+ if (m.containsKey(ImpersonatorSettingImpl.DEFAULT_DO_AS_PARAM)) { // Case doesn't matter
+ LOG.error(INVALID_PARAM_IN_URL + url);
+ return Response.status(Response.Status.BAD_REQUEST.getStatusCode()).type(MediaType.TEXT_PLAIN).
+ entity(INVALID_PARAM_IN_URL).build();
+ }
+
try {
HttpURLConnection connection = urlStreamProvider.processURL(url, requestType, body, getHeaderParamsToForward(headers));
int responseCode = connection.getResponseCode();
http://git-wip-us.apache.org/repos/asf/ambari/blob/40050513/ambari-server/src/main/java/org/apache/ambari/server/view/HttpImpersonatorImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/HttpImpersonatorImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/view/HttpImpersonatorImpl.java
new file mode 100644
index 0000000..ed5ef3c
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/HttpImpersonatorImpl.java
@@ -0,0 +1,167 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.view;
+
+
+import org.apache.ambari.server.controller.internal.URLStreamProvider;
+import org.apache.ambari.server.proxy.ProxyService;
+import org.apache.ambari.view.ImpersonatorSetting;
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.HttpImpersonator;
+import org.apache.ambari.server.controller.internal.AppCookieManager;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.List;
+import java.util.ArrayList;
+
+
+/**
+ * Class for Ambari to impersonate users over HTTP request.
+ * This is handy for Views like Jobs that needs to query ATS via HTTP Get requests and
+ * impersonate the currently logged on user.
+ * Or a file browser view that needs to use WebHDFS with the credentials of the current user.
+ */
+public class HttpImpersonatorImpl implements HttpImpersonator {
+ private ViewContext context;
+ private AppCookieManager appCookieManager;
+ private FactoryHelper helper;
+
+ /**
+ * Helper class that is mocked during unit testing.
+ */
+ static class FactoryHelper{
+ BufferedReader makeBR(InputStreamReader in){
+ return new BufferedReader(in);
+ }
+ }
+
+ public HttpImpersonatorImpl(ViewContext c, AppCookieManager appCookieManager) {
+ this.context = c;
+ this.appCookieManager = appCookieManager;
+ this.helper = new FactoryHelper();
+ }
+
+ public HttpImpersonatorImpl(ViewContext c, AppCookieManager appCookieManager, FactoryHelper h) {
+ this.context = c;
+ this.appCookieManager = appCookieManager;
+ this.helper = h;
+ }
+
+ public ViewContext getContext() {
+ return this.context;
+ }
+
+ public String getUsername() {
+ return getContext().getUsername();
+ }
+
+ /**
+ * @param conn HTTP connection that will be modified and returned
+ * @param type HTTP Request type: GET, PUT, POST, DELETE, etc.
+ * @return HTTP Connection object with the "doAs" query param set to the currently logged on user.
+ */
+ @Override
+ public HttpURLConnection doAs(HttpURLConnection conn, String type) {
+ String username = getUsername();
+ return doAs(conn, type, username, ImpersonatorSettingImpl.DEFAULT_DO_AS_PARAM);
+ }
+
+ /**
+ * @param conn HTTP connection that will be modified and returned
+ * @param type HTTP Request type: GET, PUT, POST, DELETE, etc.
+ * @param username Username to impersonate
+ * @param doAsParamName Query param, typically "doAs"
+ * @return HTTP Connection object with the doAs query param set to the provider username.
+ */
+ @Override
+ public HttpURLConnection doAs(HttpURLConnection conn, String type, String username, String doAsParamName) {
+ String url = conn.getURL().toString();
+ if (url.toLowerCase().contains(doAsParamName.toLowerCase())) {
+ throw new IllegalArgumentException("URL cannot contain \"" + doAsParamName + "\" parameter");
+ }
+
+ try {
+ conn.setRequestMethod(type);
+ } catch (IOException e) {
+ return null;
+ }
+
+ conn.setRequestProperty(doAsParamName, username);
+ return conn;
+ }
+
+ /**
+ * Returns the result of the HTTP request by setting the "doAs" impersonation for the query param and username
+ * in @param impersonatorSetting.
+ * @param urlToRead URL to request
+ * @param requestType HTTP Request type: GET, PUT, POST, DELETE, etc.
+ * @param impersonatorSetting Setting class with default values for username and doAs param name.
+ * To use different values, call the setters of the object.
+ * @return Return a response as a String
+ */
+ @Override
+ public String requestURL(String urlToRead, String requestType, final ImpersonatorSetting impersonatorSetting) {
+ String result = "";
+ BufferedReader rd;
+ String line = null;
+ String url = urlToRead;
+
+ if (url.toLowerCase().contains(impersonatorSetting.getDoAsParamName().toLowerCase())) {
+ throw new IllegalArgumentException("URL cannot contain \"" + impersonatorSetting.getDoAsParamName() + "\" parameter");
+ }
+
+ try {
+ URLStreamProvider urlStreamProvider = new URLStreamProvider(ProxyService.URL_CONNECT_TIMEOUT, ProxyService.URL_READ_TIMEOUT, null, null, null);
+
+ Map<String, List<String>> headers = new HashMap<String, List<String>>();
+ headers.put(impersonatorSetting.getDoAsParamName(), new ArrayList<String>() {{add(impersonatorSetting.getUsername()); }} );
+
+ HttpURLConnection connection = urlStreamProvider.processURL(url, requestType, null, headers);
+
+ int responseCode = connection.getResponseCode();
+ InputStream resultInputStream = null;
+ if (responseCode >= ProxyService.HTTP_ERROR_RANGE_START) {
+ resultInputStream = connection.getErrorStream();
+ } else {
+ resultInputStream = connection.getInputStream();
+ }
+
+ rd = this.helper.makeBR(new InputStreamReader(resultInputStream));
+
+ if (rd != null) {
+ line = rd.readLine();
+ while (line != null) {
+ result += line;
+ line = rd.readLine();
+ }
+ rd.close();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return result;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/40050513/ambari-server/src/main/java/org/apache/ambari/server/view/ImpersonatorSettingImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/ImpersonatorSettingImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/view/ImpersonatorSettingImpl.java
new file mode 100644
index 0000000..1f9c2b2
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/ImpersonatorSettingImpl.java
@@ -0,0 +1,63 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.view;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.ImpersonatorSetting;
+
+/**
+ * Class that provides default values for impersonating, such as the username and doAs parameter name.
+ */
+public class ImpersonatorSettingImpl implements ImpersonatorSetting {
+ private String doAsParamName;
+ private String username;
+
+ public static final String DEFAULT_DO_AS_PARAM = "doAs";
+
+ public ImpersonatorSettingImpl(ViewContext context) {
+ // Default values
+ this.doAsParamName = DEFAULT_DO_AS_PARAM;
+ this.username = context.getUsername();
+ }
+
+ /**
+ * @return The parameter name used for "doAs" impersonation.
+ */
+ @Override
+ public String getDoAsParamName() { return this.doAsParamName; }
+
+ /**
+ * @return The username value that will be used for "doAs" impersonation.
+ */
+ @Override
+ public String getUsername() { return this.username; }
+
+ /**
+ * Set the parameter name used for "doAs" impersonation.
+ * @param doAsParamName Query parameter name
+ */
+ @Override
+ public void setDoAsParamName(String doAsParamName) { this.doAsParamName = doAsParamName; }
+
+ /**
+ * Set the username value that will be used for "doAs" impersonation.
+ * @param username Username to impersonate as
+ */
+ @Override
+ public void setUsername(String username) { this.username = username; }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/40050513/ambari-server/src/main/java/org/apache/ambari/server/view/ViewContextImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewContextImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewContextImpl.java
index 8915134..0254113 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewContextImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewContextImpl.java
@@ -35,6 +35,8 @@ import org.apache.ambari.view.Masker;
import org.apache.ambari.view.ResourceProvider;
import org.apache.ambari.view.SecurityException;
import org.apache.ambari.view.URLStreamProvider;
+import org.apache.ambari.server.controller.internal.AppCookieManager;
+import org.apache.ambari.view.ImpersonatorSetting;
import org.apache.ambari.view.ViewContext;
import org.apache.ambari.view.ViewController;
import org.apache.ambari.view.ViewDefinition;
@@ -88,7 +90,7 @@ public class ViewContextImpl implements ViewContext, ViewController {
/**
* The available stream provider.
*/
- private final URLStreamProvider streamProvider;
+ private final ViewURLStreamProvider streamProvider;
/**
* The data store.
@@ -300,6 +302,15 @@ public class ViewContextImpl implements ViewContext, ViewController {
return this;
}
+ @Override
+ public HttpImpersonatorImpl getHttpImpersonator() {
+ return new HttpImpersonatorImpl(this, this.streamProvider.getAppCookieManager());
+ }
+
+ @Override
+ public ImpersonatorSetting getImpersonatorSetting() {
+ return new ImpersonatorSettingImpl(this);
+ }
// ----- ViewController ----------------------------------------------------
@@ -409,7 +420,6 @@ public class ViewContextImpl implements ViewContext, ViewController {
*/
private final org.apache.ambari.server.controller.internal.URLStreamProvider streamProvider;
-
// ----- Constructor -----------------------------------------------------
protected ViewURLStreamProvider(org.apache.ambari.server.controller.internal.URLStreamProvider streamProvider) {
@@ -448,6 +458,10 @@ public class ViewContextImpl implements ViewContext, ViewController {
configuration.getTruststoreType());
return new ViewURLStreamProvider(streamProvider);
}
+
+ protected AppCookieManager getAppCookieManager() {
+ return streamProvider.getAppCookieManager();
+ }
}
// ----- Inner class : ParameterResolver -------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/40050513/ambari-server/src/test/java/org/apache/ambari/server/proxy/ProxyServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/proxy/ProxyServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/proxy/ProxyServiceTest.java
index 2c1f1bc..8ad8889 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/proxy/ProxyServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/proxy/ProxyServiceTest.java
@@ -65,6 +65,7 @@ class ProxyServiceTest extends BaseServiceTest {
URLStreamProvider streamProviderMock = PowerMock.createNiceMock(URLStreamProvider.class);
HttpURLConnection urlConnectionMock = createMock(HttpURLConnection.class);
URI uriMock = PowerMock.createMock(URI.class);
+ MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl();
MultivaluedMap<String, String> headerParams = new MultivaluedMapImpl();
Map<String, List<String>> headerParamsToForward = new HashMap<String, List<String>>();
Response.ResponseBuilder responseBuilderMock = PowerMock.createMock(ResponseBuilderImpl.class);
@@ -79,6 +80,7 @@ class ProxyServiceTest extends BaseServiceTest {
expect(getHttpHeaders().getRequestHeaders()).andReturn(headerParams);
expect(getHttpHeaders().getRequestHeader("AmbariProxy-User-Remote")).andReturn(userRemoteParams);
expect(getUriInfo().getRequestUri()).andReturn(uriMock);
+ expect(getUriInfo().getQueryParameters()).andReturn(queryParams);
expect(uriMock.getQuery()).andReturn("url=testurl");
expect(streamProviderMock.processURL("testurl", "GET", null, headerParamsToForward)).andReturn(urlConnectionMock);
expect(urlConnectionMock.getResponseCode()).andReturn(200);
@@ -101,6 +103,7 @@ class ProxyServiceTest extends BaseServiceTest {
URLStreamProvider streamProviderMock = PowerMock.createNiceMock(URLStreamProvider.class);
HttpURLConnection urlConnectionMock = createMock(HttpURLConnection.class);
URI uriMock = PowerMock.createMock(URI.class);
+ MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl();
MultivaluedMap<String, String> headerParams = new MultivaluedMapImpl();
Map<String, List<String>> headerParamsToForward = new HashMap<String, List<String>>();
Response.ResponseBuilder responseBuilderMock = PowerMock.createMock(ResponseBuilderImpl.class);
@@ -115,6 +118,7 @@ class ProxyServiceTest extends BaseServiceTest {
expect(getHttpHeaders().getRequestHeaders()).andReturn(headerParams);
expect(getHttpHeaders().getRequestHeader("AmbariProxy-User-Remote")).andReturn(userRemoteParams);
expect(getUriInfo().getRequestUri()).andReturn(uriMock);
+ expect(getUriInfo().getQueryParameters()).andReturn(queryParams);
expect(uriMock.getQuery()).andReturn("url=testurl");
expect(getHttpHeaders().getMediaType()).andReturn(APPLICATION_FORM_URLENCODED_TYPE);
expect(streamProviderMock.processURL("testurl", "POST", is, headerParamsToForward)).andReturn(urlConnectionMock);
@@ -138,6 +142,7 @@ class ProxyServiceTest extends BaseServiceTest {
URLStreamProvider streamProviderMock = PowerMock.createNiceMock(URLStreamProvider.class);
HttpURLConnection urlConnectionMock = createMock(HttpURLConnection.class);
URI uriMock = PowerMock.createMock(URI.class);
+ MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl();
MultivaluedMap<String, String> headerParams = new MultivaluedMapImpl();
Map<String, List<String>> headerParamsToForward = new HashMap<String, List<String>>();
Response.ResponseBuilder responseBuilderMock = PowerMock.createMock(ResponseBuilderImpl.class);
@@ -152,6 +157,7 @@ class ProxyServiceTest extends BaseServiceTest {
expect(getHttpHeaders().getRequestHeaders()).andReturn(headerParams);
expect(getHttpHeaders().getRequestHeader("AmbariProxy-User-Remote")).andReturn(userRemoteParams);
expect(getUriInfo().getRequestUri()).andReturn(uriMock);
+ expect(getUriInfo().getQueryParameters()).andReturn(queryParams);
expect(uriMock.getQuery()).andReturn("url=testurl");
expect(getHttpHeaders().getMediaType()).andReturn(APPLICATION_FORM_URLENCODED_TYPE);
expect(streamProviderMock.processURL("testurl", "PUT", is, headerParamsToForward)).andReturn(urlConnectionMock);
@@ -175,6 +181,7 @@ class ProxyServiceTest extends BaseServiceTest {
URLStreamProvider streamProviderMock = PowerMock.createNiceMock(URLStreamProvider.class);
HttpURLConnection urlConnectionMock = createMock(HttpURLConnection.class);
URI uriMock = PowerMock.createMock(URI.class);
+ MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl();
MultivaluedMap<String, String> headerParams = new MultivaluedMapImpl();
Map<String, List<String>> headerParamsToForward = new HashMap<String, List<String>>();
Response.ResponseBuilder responseBuilderMock = PowerMock.createMock(ResponseBuilderImpl.class);
@@ -189,6 +196,7 @@ class ProxyServiceTest extends BaseServiceTest {
expect(getHttpHeaders().getRequestHeaders()).andReturn(headerParams);
expect(getHttpHeaders().getRequestHeader("AmbariProxy-User-Remote")).andReturn(userRemoteParams);
expect(getUriInfo().getRequestUri()).andReturn(uriMock);
+ expect(getUriInfo().getQueryParameters()).andReturn(queryParams);
expect(uriMock.getQuery()).andReturn("url=testurl");
expect(streamProviderMock.processURL("testurl", "DELETE", null, headerParamsToForward)).andReturn(urlConnectionMock);
expect(urlConnectionMock.getResponseCode()).andReturn(200);
@@ -214,6 +222,7 @@ class ProxyServiceTest extends BaseServiceTest {
URI uriMock = PowerMock.createMock(URI.class);
Response responseMock = createMock(ResponseImpl.class);
InputStream es = new ByteArrayInputStream("error".getBytes());
+ MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl();
MultivaluedMap<String, String> headerParams = new MultivaluedMapImpl();
Map<String, List<String>> headerParamsToForward = new HashMap<String, List<String>>();
headerParams.add("AmbariProxy-User-Remote","testuser");
@@ -225,6 +234,7 @@ class ProxyServiceTest extends BaseServiceTest {
expect(getHttpHeaders().getRequestHeaders()).andReturn(headerParams);
expect(getHttpHeaders().getRequestHeader("AmbariProxy-User-Remote")).andReturn(userRemoteParams);
expect(getUriInfo().getRequestUri()).andReturn(uriMock);
+ expect(getUriInfo().getQueryParameters()).andReturn(queryParams);
expect(uriMock.getQuery()).andReturn("url=testurl");
expect(streamProviderMock.processURL("testurl", "GET", null, headerParamsToForward)).andReturn(urlConnectionMock);
expect(urlConnectionMock.getResponseCode()).andReturn(400).times(2);
@@ -247,6 +257,7 @@ class ProxyServiceTest extends BaseServiceTest {
URLStreamProvider streamProviderMock = PowerMock.createNiceMock(URLStreamProvider.class);
HttpURLConnection urlConnectionMock = createMock(HttpURLConnection.class);
URI uriMock = PowerMock.createMock(URI.class);
+ MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl();
MultivaluedMap<String, String> headerParams = new MultivaluedMapImpl();
Map<String, List<String>> headerParamsToForward = new HashMap<String, List<String>>();
Response.ResponseBuilder responseBuilderMock = PowerMock.createMock(ResponseBuilderImpl.class);
@@ -261,6 +272,7 @@ class ProxyServiceTest extends BaseServiceTest {
expect(getHttpHeaders().getRequestHeaders()).andReturn(headerParams);
expect(getHttpHeaders().getRequestHeader("AmbariProxy-User-Remote")).andReturn(userRemoteParams);
expect(getUriInfo().getRequestUri()).andReturn(uriMock);
+ expect(getUriInfo().getQueryParameters()).andReturn(queryParams);
expect(uriMock.getQuery()).andReturn("url=testurl");
expect(streamProviderMock.processURL("testurl", "GET", null, headerParamsToForward)).andReturn(urlConnectionMock);
expect(urlConnectionMock.getResponseCode()).andReturn(200);
@@ -281,6 +293,7 @@ class ProxyServiceTest extends BaseServiceTest {
public void testEscapedURL() throws Exception {
ProxyService ps = new ProxyService();
URLStreamProvider streamProviderMock = PowerMock.createNiceMock(URLStreamProvider.class);
+ MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl();
MultivaluedMap<String, String> headerParams = new MultivaluedMapImpl();
HttpURLConnection urlConnectionMock = createMock(HttpURLConnection.class);
URI uri = UriBuilder.fromUri("http://dev01.hortonworks.com:8080/proxy?url=http%3a%2f%2fserver%3a8188%2fws%2fv1%2f" +
@@ -295,6 +308,7 @@ class ProxyServiceTest extends BaseServiceTest {
expect(getHttpHeaders().getRequestHeaders()).andReturn(headerParams);
expect(getHttpHeaders().getRequestHeader("AmbariProxy-User-Remote")).andReturn(userRemoteParams);
expect(getUriInfo().getRequestUri()).andReturn(uri);
+ expect(getUriInfo().getQueryParameters()).andReturn(queryParams);
expect(urlConnectionMock.getResponseCode()).andReturn(200);
expect(urlConnectionMock.getContentType()).andReturn("text/plain");
expect(urlConnectionMock.getInputStream()).andReturn(is);
http://git-wip-us.apache.org/repos/asf/ambari/blob/40050513/ambari-server/src/test/java/org/apache/ambari/server/view/HttpImpersonatorImplTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/view/HttpImpersonatorImplTest.java b/ambari-server/src/test/java/org/apache/ambari/server/view/HttpImpersonatorImplTest.java
new file mode 100644
index 0000000..5526592
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/view/HttpImpersonatorImplTest.java
@@ -0,0 +1,128 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.view;
+
+import junit.framework.TestCase;
+import org.apache.ambari.view.ImpersonatorSetting;
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.server.controller.internal.AppCookieManager;
+import org.junit.Assert;
+import org.mockito.Mockito;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.UUID;
+
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.when;
+
+
+public class HttpImpersonatorImplTest extends TestCase {
+
+ String cookie;
+ String username;
+ ViewContext viewContext;
+ HttpImpersonatorImpl impersonator;
+ String expectedResult;
+
+ public void setUp() throws Exception {
+ String uuid = UUID.randomUUID().toString().replace("-", "");
+ this.cookie = uuid;
+ this.username = "admin" + uuid;
+
+ AppCookieManager mockAppCookieManager = Mockito.mock(AppCookieManager.class);
+ when(mockAppCookieManager.getAppCookie(anyString(), anyBoolean())).thenReturn(cookie);
+
+ this.expectedResult = "Dummy text from HTTP response";
+ BufferedReader mockBufferedReader = Mockito.mock(BufferedReader.class);
+ when(mockBufferedReader.readLine()).thenReturn(expectedResult).thenReturn(null);
+
+ HttpImpersonatorImpl.FactoryHelper mockFactory = Mockito.mock(HttpImpersonatorImpl.FactoryHelper.class);
+ when(mockFactory.makeBR(any(InputStreamReader.class))).thenReturn(mockBufferedReader);
+
+ this.viewContext = Mockito.mock(ViewContext.class);
+ when(this.viewContext.getUsername()).thenReturn(username);
+
+ this.impersonator = new HttpImpersonatorImpl(this.viewContext, mockAppCookieManager, mockFactory);
+ when(this.viewContext.getHttpImpersonator()).thenReturn(this.impersonator);
+ }
+
+ @org.junit.Test
+ public void testBasic() throws Exception {
+ String urlToRead = "http://foo.com";
+ String requestMethod = "GET";
+ URL url = new URL(urlToRead);
+
+ // Test default params
+ HttpURLConnection conn1 = (HttpURLConnection) url.openConnection();
+
+ conn1 = this.viewContext.getHttpImpersonator().doAs(conn1, requestMethod);
+ Assert.assertEquals(requestMethod, conn1.getRequestMethod());
+ Assert.assertEquals(username, conn1.getRequestProperty("doAs"));
+
+ // Test specific params
+ HttpURLConnection conn2 = (HttpURLConnection) url.openConnection();
+ conn2 = this.viewContext.getHttpImpersonator().doAs(conn1, requestMethod, "admin", "username");
+ Assert.assertEquals(requestMethod, conn1.getRequestMethod());
+ Assert.assertEquals("admin", conn1.getRequestProperty("username"));
+ }
+
+ @org.junit.Test
+ public void testRequestURL() throws Exception {
+ String urlToRead = "http://foo.com";
+ String requestMethod = "GET";
+
+ // Test default params
+ ImpersonatorSetting impersonatorSetting = new ImpersonatorSettingImpl(this.viewContext);
+ when(this.viewContext.getImpersonatorSetting()).thenReturn(impersonatorSetting);
+ String actualResult = this.viewContext.getHttpImpersonator().requestURL(urlToRead, requestMethod, impersonatorSetting);
+ Assert.assertEquals(this.expectedResult, actualResult);
+ }
+
+ @org.junit.Test
+ public void testRequestURLWithCustom() throws Exception {
+ String urlToRead = "http://foo.com";
+ String requestMethod = "GET";
+
+ // Test custom params
+ ImpersonatorSetting impersonatorSetting = new ImpersonatorSettingImpl(this.viewContext);
+ impersonatorSetting.setDoAsParamName("impersonate");
+ impersonatorSetting.setUsername("hive");
+ when(this.viewContext.getImpersonatorSetting()).thenReturn(impersonatorSetting);
+ String actualResult = this.viewContext.getHttpImpersonator().requestURL(urlToRead, requestMethod, impersonatorSetting);
+ Assert.assertEquals(this.expectedResult, actualResult);
+ }
+
+ @org.junit.Test
+ public void testInvalidURL() throws Exception {
+ String urlToRead = "http://foo.com?" + "doAs" + "=hive";
+ String requestMethod = "GET";
+ URL url = new URL(urlToRead);
+
+ HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+ try {
+ conn = this.viewContext.getHttpImpersonator().doAs(conn, requestMethod);
+ fail("Expected an exception to be thrown." );
+ } catch(Exception e) {
+ ;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/40050513/ambari-views/src/main/java/org/apache/ambari/view/HttpImpersonator.java
----------------------------------------------------------------------
diff --git a/ambari-views/src/main/java/org/apache/ambari/view/HttpImpersonator.java b/ambari-views/src/main/java/org/apache/ambari/view/HttpImpersonator.java
new file mode 100644
index 0000000..00d5d86
--- /dev/null
+++ b/ambari-views/src/main/java/org/apache/ambari/view/HttpImpersonator.java
@@ -0,0 +1,53 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.view;
+
+import java.net.HttpURLConnection;
+
+/**
+ * Interface for views to impersonate users over HTTP request.
+ */
+public interface HttpImpersonator {
+
+ /**
+ * @param conn HTTP connection that will be modified and returned
+ * @param type HTTP Request type: GET, PUT, POST, DELETE, etc.
+ * @return HTTP Connection object with the "doAs" query param set to the currently logged on user.
+ */
+ public HttpURLConnection doAs(HttpURLConnection conn, String type);
+
+ /**
+ * @param conn HTTP connection that will be modified and returned
+ * @param type HTTP Request type: GET, PUT, POST, DELETE, etc.
+ * @param username Username to impersonate
+ * @param doAsParamName Query param, typically "doAs"
+ * @return HTTP Connection object with the doAs query param set to the provider username.
+ */
+ public HttpURLConnection doAs(HttpURLConnection conn, String type, String username, String doAsParamName);
+
+ /**
+ * Returns the result of the HTTP request by setting the "doAs" impersonation for the query param and username
+ * in @param impersonatorSetting.
+ * @param urlToRead URL to request
+ * @param requestType HTTP Request type: GET, PUT, POST, DELETE, etc.
+ * @param impersonatorSetting Setting class with default values for username and doAs param name.
+ * To use different values, call the setters of the object.
+ * @return Return a response as a String
+ */
+ public String requestURL(String urlToRead, String requestType, ImpersonatorSetting impersonatorSetting);
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/40050513/ambari-views/src/main/java/org/apache/ambari/view/ImpersonatorSetting.java
----------------------------------------------------------------------
diff --git a/ambari-views/src/main/java/org/apache/ambari/view/ImpersonatorSetting.java b/ambari-views/src/main/java/org/apache/ambari/view/ImpersonatorSetting.java
new file mode 100644
index 0000000..b52cc90
--- /dev/null
+++ b/ambari-views/src/main/java/org/apache/ambari/view/ImpersonatorSetting.java
@@ -0,0 +1,46 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.view;
+
+/**
+ * Interface that provides default values for impersonating, such as the username and doAs parameter name.
+ */
+public interface ImpersonatorSetting {
+
+ /**
+ * @return The parameter name used for "doAs" impersonation.
+ */
+ public String getDoAsParamName();
+
+ /**
+ * @return The username value that will be used for "doAs" impersonation.
+ */
+ public String getUsername();
+
+ /**
+ * Set the parameter name used for "doAs" impersonation.
+ * @param doAsParamName Query parameter name
+ */
+ public void setDoAsParamName(String doAsParamName);
+
+ /**
+ * Set the username value that will be used for "doAs" impersonation.
+ * @param username Username to impersonate as
+ */
+ public void setUsername(String username);
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/40050513/ambari-views/src/main/java/org/apache/ambari/view/ViewContext.java
----------------------------------------------------------------------
diff --git a/ambari-views/src/main/java/org/apache/ambari/view/ViewContext.java b/ambari-views/src/main/java/org/apache/ambari/view/ViewContext.java
index 37e91a2..97385d3 100644
--- a/ambari-views/src/main/java/org/apache/ambari/view/ViewContext.java
+++ b/ambari-views/src/main/java/org/apache/ambari/view/ViewContext.java
@@ -20,6 +20,7 @@ package org.apache.ambari.view;
import java.util.Collection;
import java.util.Map;
+import org.apache.ambari.view.HttpImpersonator;
/**
* Context object available to the view components to provide access to
@@ -174,4 +175,18 @@ public interface ViewContext {
* @return the view controller
*/
public ViewController getController();
+
+ /**
+ * Get the HTTP Impersonator.
+ *
+ * @return the HTTP Impersonator, which internally uses the App Cookie Manager
+ */
+ public HttpImpersonator getHttpImpersonator();
+
+ /**
+ * Get the default settings for the Impersonator.
+ *
+ * @return the Impersonator settings.
+ */
+ public ImpersonatorSetting getImpersonatorSetting();
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/40050513/ambari-web/app/utils/ajax/ajax.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/ajax/ajax.js b/ambari-web/app/utils/ajax/ajax.js
index c2a971d..f4506ad 100644
--- a/ambari-web/app/utils/ajax/ajax.js
+++ b/ambari-web/app/utils/ajax/ajax.js
@@ -1698,28 +1698,6 @@ var urls = {
}
}
},
-
- 'jobs.lastID': {
- 'real': '/proxy?url=http://{historyServerHostName}:{ahsWebPort}/ws/v1/timeline/HIVE_QUERY_ID?limit=1&secondaryFilter=tez:true',
- 'mock': 'data/jobs/hive-queries.json',
- 'apiPrefix': ''
- },
-
- 'jobs.tezDag.NametoID': {
- 'real': '/proxy?url=http://{historyServerHostName}:{ahsWebPort}/ws/v1/timeline/TEZ_DAG_ID?primaryFilter=dagName:{tezDagName}',
- 'mock': '/data/jobs/tezDag-name-to-id.json',
- 'apiPrefix': ''
- },
- 'jobs.tezDag.tezDagId': {
- 'real': '/proxy?url=http://{historyServerHostName}:{ahsWebPort}/ws/v1/timeline/TEZ_DAG_ID/{tezDagId}?fields=relatedentities,otherinfo',
- 'mock': '/data/jobs/tezDag.json',
- 'apiPrefix': ''
- },
- 'jobs.tezDag.tezDagVertexId': {
- 'real': '/proxy?url=http://{historyServerHostName}:{ahsWebPort}/ws/v1/timeline/TEZ_VERTEX_ID/{tezDagVertexId}?fields=otherinfo',
- 'mock': '/data/jobs/tezDagVertex.json',
- 'apiPrefix': ''
- },
'views.info': {
'real': '/views',
'mock': '/data/views/views.json'
http://git-wip-us.apache.org/repos/asf/ambari/blob/40050513/contrib/views/jobs/pom.xml
----------------------------------------------------------------------
diff --git a/contrib/views/jobs/pom.xml b/contrib/views/jobs/pom.xml
index c4b646e..f2173e3 100644
--- a/contrib/views/jobs/pom.xml
+++ b/contrib/views/jobs/pom.xml
@@ -158,6 +158,7 @@
<directory>src/main/resources</directory>
<filtering>false</filtering>
<includes>
+ <include>WEB-INF/web.xml</include>
<include>META-INF/**/*</include>
<include>view.xml</include>
</includes>
@@ -168,4 +169,18 @@
</resource>
</resources>
</build>
+<dependencies>
+ <dependency>
+ <groupId>org.apache.ambari</groupId>
+ <artifactId>ambari-views</artifactId>
+ <version>${ambari.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <version>2.5</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
</project>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/40050513/contrib/views/jobs/src/main/java/org/apache/ambari/view/jobs/ProxyServlet.java
----------------------------------------------------------------------
diff --git a/contrib/views/jobs/src/main/java/org/apache/ambari/view/jobs/ProxyServlet.java b/contrib/views/jobs/src/main/java/org/apache/ambari/view/jobs/ProxyServlet.java
new file mode 100644
index 0000000..f02844e
--- /dev/null
+++ b/contrib/views/jobs/src/main/java/org/apache/ambari/view/jobs/ProxyServlet.java
@@ -0,0 +1,68 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.jobs;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.HttpImpersonator;
+import org.apache.ambari.view.ImpersonatorSetting;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+
+/**
+ * Simple servlet for proxying requests with doAs impersonation.
+ */
+public class ProxyServlet extends HttpServlet {
+
+ private ViewContext viewContext;
+ private HttpImpersonator impersonator;
+ private ImpersonatorSetting impersonatorSetting;
+
+ @Override
+ public void init(ServletConfig config) throws ServletException {
+ super.init(config);
+
+ ServletContext context = config.getServletContext();
+ viewContext = (ViewContext) context.getAttribute(ViewContext.CONTEXT_ATTRIBUTE);
+
+ this.impersonator = viewContext.getHttpImpersonator();
+ this.impersonatorSetting = viewContext.getImpersonatorSetting();
+ }
+
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ String urlToRead = request.getParameter("url");
+ response.setContentType("text/html");
+ response.setStatus(HttpServletResponse.SC_OK);
+
+ // Getting the result is super simply by using the impersonator and the default values in the factory.
+ String result = this.impersonator.requestURL(urlToRead, "GET", this.impersonatorSetting);
+
+ PrintWriter writer = response.getWriter();
+ writer.print(result);
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/ambari/blob/40050513/contrib/views/jobs/src/main/resources/WEB-INF/web.xml
----------------------------------------------------------------------
diff --git a/contrib/views/jobs/src/main/resources/WEB-INF/web.xml b/contrib/views/jobs/src/main/resources/WEB-INF/web.xml
new file mode 100644
index 0000000..aa3da09
--- /dev/null
+++ b/contrib/views/jobs/src/main/resources/WEB-INF/web.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License. Kerberos, LDAP, Custom. Binary/Htt
+-->
+
+<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
+ version="2.4">
+
+ <display-name>Proxy Application</display-name>
+ <description>
+ This is the proxy application.
+ </description>
+ <servlet>
+ <servlet-name>ProxyServlet</servlet-name>
+ <servlet-class>org.apache.ambari.view.jobs.ProxyServlet</servlet-class>
+ </servlet>
+ <servlet-mapping>
+ <servlet-name>ProxyServlet</servlet-name>
+ <url-pattern>/proxy</url-pattern>
+ </servlet-mapping>
+</web-app>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/40050513/contrib/views/jobs/src/main/resources/ui/app/scripts/controllers/jobs_controller.js
----------------------------------------------------------------------
diff --git a/contrib/views/jobs/src/main/resources/ui/app/scripts/controllers/jobs_controller.js b/contrib/views/jobs/src/main/resources/ui/app/scripts/controllers/jobs_controller.js
index 16acb56..6a04c98 100644
--- a/contrib/views/jobs/src/main/resources/ui/app/scripts/controllers/jobs_controller.js
+++ b/contrib/views/jobs/src/main/resources/ui/app/scripts/controllers/jobs_controller.js
@@ -591,7 +591,10 @@ App.JobsController = Ember.ArrayController.extend(App.RunPeriodically, {
name: 'jobs_lastID',
sender: this,
data: {
- atsURL: atsURL
+ atsURL: atsURL,
+ view: App.get("view"),
+ version: App.get("version"),
+ instanceName: App.get("instanceName")
},
success: 'lastIDSuccessCallback',
error : 'lastIDErrorCallback'
@@ -601,7 +604,10 @@ App.JobsController = Ember.ArrayController.extend(App.RunPeriodically, {
sender: this,
data: {
atsURL: atsURL,
- filtersLink: this.get('filterObject').createJobsFiltersLink()
+ filtersLink: this.get('filterObject').createJobsFiltersLink(),
+ view: App.get("view"),
+ version: App.get("version"),
+ instanceName: App.get("instanceName")
},
success: 'loadJobsSuccessCallback',
error: 'loadJobsErrorCallback'
http://git-wip-us.apache.org/repos/asf/ambari/blob/40050513/contrib/views/jobs/src/main/resources/ui/app/scripts/helpers/ajax.js
----------------------------------------------------------------------
diff --git a/contrib/views/jobs/src/main/resources/ui/app/scripts/helpers/ajax.js b/contrib/views/jobs/src/main/resources/ui/app/scripts/helpers/ajax.js
index e648e61..728b26a 100644
--- a/contrib/views/jobs/src/main/resources/ui/app/scripts/helpers/ajax.js
+++ b/contrib/views/jobs/src/main/resources/ui/app/scripts/helpers/ajax.js
@@ -27,41 +27,54 @@
* testInProduction - can this request be executed on production tests (used only in tests)
*
* @type {Object}
+ *
+ * Any property inside {braces} is substituted dynamically by the formatUrl function provided that the property is passed into the "data" dictionary
+ * by the ajax call.
+ * E.g.,
+ App.ajax.send({
+ name: 'key_foo',
+ data: {
+ property1: value1,
+ property2: value2
+ }
+ });
+
+ Where the "urls" dictionary contains 'key_foo': {real: 'some_value_with_{property1}_and_{property2}' }
*/
var urls = {
'load_jobs': {
- real: '/proxy?url={atsURL}/ws/v1/timeline/HIVE_QUERY_ID{filtersLink}',
+ real: '/views/{view}/{version}/{instanceName}/proxy?url={atsURL}/ws/v1/timeline/HIVE_QUERY_ID{filtersLink}',
mock: '/scripts/assets/hive-queries.json',
apiPrefix: ''
},
'jobs_lastID': {
- real: '/proxy?url={atsURL}/ws/v1/timeline/HIVE_QUERY_ID?limit=1&secondaryFilter=tez:true',
+ real: '/views/{view}/{version}/{instanceName}/proxy?url={atsURL}/ws/v1/timeline/HIVE_QUERY_ID?limit=1&secondaryFilter=tez:true',
mock: '/scripts/assets/hive-queries.json',
apiPrefix: ''
},
'job_details': {
- real: '/proxy?url={atsURL}/ws/v1/timeline/HIVE_QUERY_ID/{job_id}?fields=events,otherinfo',
+ real: '/views/{view}/{version}/{instanceName}/proxy?url={atsURL}/ws/v1/timeline/HIVE_QUERY_ID/{job_id}?fields=events,otherinfo',
mock: '/scripts/assets/hive-query-2.json',
apiPrefix: ''
},
'jobs.tezDag.NametoID': {
- 'real': '/proxy?url={atsURL}/ws/v1/timeline/TEZ_DAG_ID?primaryFilter=dagName:{tezDagName}',
+ 'real': '/views/{view}/{version}/{instanceName}/proxy?url={atsURL}/ws/v1/timeline/TEZ_DAG_ID?primaryFilter=dagName:{tezDagName}',
'mock': '/scripts/assets/tezDag-name-to-id.json',
'apiPrefix': ''
},
'jobs.tezDag.tezDagId': {
- 'real': '/proxy?url={atsURL}/ws/v1/timeline/TEZ_DAG_ID/{tezDagId}?fields=relatedentities,otherinfo',
+ 'real': '/views/{view}/{version}/{instanceName}/proxy?url={atsURL}/ws/v1/timeline/TEZ_DAG_ID/{tezDagId}?fields=relatedentities,otherinfo',
'mock': '/scripts/assets/tezDag.json',
'apiPrefix': ''
},
'jobs.tezDag.tezDagVertexId': {
- 'real': '/proxy?url={atsURL}/ws/v1/timeline/TEZ_VERTEX_ID/{tezDagVertexId}?fields=otherinfo',
+ 'real': '/views/{view}/{version}/{instanceName}/proxy?url={atsURL}/ws/v1/timeline/TEZ_VERTEX_ID/{tezDagVertexId}?fields=otherinfo',
'mock': '/scripts/assets/tezDagVertex.json',
'apiPrefix': ''
},
http://git-wip-us.apache.org/repos/asf/ambari/blob/40050513/contrib/views/jobs/src/main/resources/ui/app/scripts/helpers/jobs.js
----------------------------------------------------------------------
diff --git a/contrib/views/jobs/src/main/resources/ui/app/scripts/helpers/jobs.js b/contrib/views/jobs/src/main/resources/ui/app/scripts/helpers/jobs.js
index f0759da..75511b4 100644
--- a/contrib/views/jobs/src/main/resources/ui/app/scripts/helpers/jobs.js
+++ b/contrib/views/jobs/src/main/resources/ui/app/scripts/helpers/jobs.js
@@ -88,7 +88,10 @@ App.Helpers.jobs = {
sender: sender,
data: {
atsURL: params.atsURL,
- tezDagName: tezDagName
+ tezDagName: tezDagName,
+ view: App.get("view"),
+ version: App.get("version"),
+ instanceName: App.get("instanceName")
},
success: 'dagNameToIdSuccess',
error: 'dagNameToIdError'
@@ -146,7 +149,10 @@ App.Helpers.jobs = {
sender: sender,
data: {
tezDagId: tezDagInstanceId,
- atsURL: atsURL
+ atsURL: atsURL,
+ view: App.get("view"),
+ version: App.get("version"),
+ instanceName: App.get("instanceName")
},
success: 'loadTezDagSuccess',
error: 'loadTezDagError'
@@ -241,7 +247,10 @@ App.Helpers.jobs = {
sender: sender,
data: {
atsURL: atsURL,
- tezDagVertexId: tezVertexInstanceId
+ tezDagVertexId: tezVertexInstanceId,
+ view: App.get("view"),
+ version: App.get("version"),
+ instanceName: App.get("instanceName")
},
success: 'loadTezDagVertexSuccess',
error: 'loadTezDagVertexError'
http://git-wip-us.apache.org/repos/asf/ambari/blob/40050513/contrib/views/jobs/src/main/resources/ui/app/scripts/routes/application_route.js
----------------------------------------------------------------------
diff --git a/contrib/views/jobs/src/main/resources/ui/app/scripts/routes/application_route.js b/contrib/views/jobs/src/main/resources/ui/app/scripts/routes/application_route.js
index ff13b88..b2aeea6 100644
--- a/contrib/views/jobs/src/main/resources/ui/app/scripts/routes/application_route.js
+++ b/contrib/views/jobs/src/main/resources/ui/app/scripts/routes/application_route.js
@@ -36,6 +36,14 @@ App.JobsRoute = Ember.Route.extend({
setupController: function(controller, model) {
this._super(controller, model);
+ var hashArray = location.pathname.split('/');
+ var view = hashArray[2];
+ var version = hashArray[3];
+ var instanceName = hashArray[4];
+ App.set('view', view);
+ App.set('version', version);
+ App.set('instanceName', instanceName);
+
controller.set('interval', 6000);
controller.loop('loadJobs', true);
// This observer should be set with addObserver