|
@@ -33,6 +33,9 @@ import java.security.PrivilegedExceptionAction;
|
|
|
import javax.net.ssl.HostnameVerifier;
|
|
|
import javax.net.ssl.HttpsURLConnection;
|
|
|
import javax.net.ssl.SSLSocketFactory;
|
|
|
+import javax.ws.rs.core.MediaType;
|
|
|
+import javax.ws.rs.core.MultivaluedMap;
|
|
|
+
|
|
|
import org.apache.commons.cli.CommandLine;
|
|
|
import org.apache.commons.cli.GnuParser;
|
|
|
import org.apache.commons.cli.HelpFormatter;
|
|
@@ -42,8 +45,8 @@ import org.apache.commons.logging.LogFactory;
|
|
|
import org.apache.hadoop.classification.InterfaceAudience.Private;
|
|
|
import org.apache.hadoop.classification.InterfaceStability.Evolving;
|
|
|
import org.apache.hadoop.conf.Configuration;
|
|
|
-import org.apache.hadoop.security.UserGroupInformation;
|
|
|
import org.apache.hadoop.security.SecurityUtil;
|
|
|
+import org.apache.hadoop.security.UserGroupInformation;
|
|
|
import org.apache.hadoop.security.authentication.client.AuthenticationException;
|
|
|
import org.apache.hadoop.security.authentication.client.ConnectionConfigurator;
|
|
|
import org.apache.hadoop.security.ssl.SSLFactory;
|
|
@@ -53,6 +56,7 @@ import org.apache.hadoop.security.token.delegation.web.DelegationTokenAuthentica
|
|
|
import org.apache.hadoop.security.token.delegation.web.KerberosDelegationTokenAuthenticator;
|
|
|
import org.apache.hadoop.security.token.delegation.web.PseudoDelegationTokenAuthenticator;
|
|
|
import org.apache.hadoop.yarn.api.records.ApplicationAttemptId;
|
|
|
+import org.apache.hadoop.yarn.api.records.ApplicationId;
|
|
|
import org.apache.hadoop.yarn.api.records.timeline.TimelineDomain;
|
|
|
import org.apache.hadoop.yarn.api.records.timeline.TimelineDomains;
|
|
|
import org.apache.hadoop.yarn.api.records.timeline.TimelineEntities;
|
|
@@ -77,13 +81,15 @@ import com.sun.jersey.api.client.config.DefaultClientConfig;
|
|
|
import com.sun.jersey.api.client.filter.ClientFilter;
|
|
|
import com.sun.jersey.client.urlconnection.HttpURLConnectionFactory;
|
|
|
import com.sun.jersey.client.urlconnection.URLConnectionClientHandler;
|
|
|
+import com.sun.jersey.core.util.MultivaluedMapImpl;
|
|
|
|
|
|
@Private
|
|
|
@Evolving
|
|
|
public class TimelineClientImpl extends TimelineClient {
|
|
|
|
|
|
private static final Log LOG = LogFactory.getLog(TimelineClientImpl.class);
|
|
|
- private static final String RESOURCE_URI_STR = "/ws/v1/timeline/";
|
|
|
+ private static final String RESOURCE_URI_STR_V1 = "/ws/v1/timeline/";
|
|
|
+ private static final String RESOURCE_URI_STR_V2 = "/ws/v2/timeline/";
|
|
|
private static final Joiner JOINER = Joiner.on("");
|
|
|
public final static int DEFAULT_SOCKET_TIMEOUT = 1 * 60 * 1000; // 1 minute
|
|
|
|
|
@@ -250,7 +256,11 @@ public class TimelineClientImpl extends TimelineClient {
|
|
|
}
|
|
|
|
|
|
public TimelineClientImpl() {
|
|
|
- super(TimelineClientImpl.class.getName());
|
|
|
+ super(TimelineClientImpl.class.getName(), null);
|
|
|
+ }
|
|
|
+
|
|
|
+ public TimelineClientImpl(ApplicationId applicationId) {
|
|
|
+ super(TimelineClientImpl.class.getName(), applicationId);
|
|
|
}
|
|
|
|
|
|
protected void serviceInit(Configuration conf) throws Exception {
|
|
@@ -282,21 +292,19 @@ public class TimelineClientImpl extends TimelineClient {
|
|
|
client.addFilter(retryFilter);
|
|
|
|
|
|
if (YarnConfiguration.useHttps(conf)) {
|
|
|
- resURI = URI
|
|
|
- .create(JOINER.join("https://", conf.get(
|
|
|
- YarnConfiguration.TIMELINE_SERVICE_WEBAPP_HTTPS_ADDRESS,
|
|
|
- YarnConfiguration.DEFAULT_TIMELINE_SERVICE_WEBAPP_HTTPS_ADDRESS),
|
|
|
- RESOURCE_URI_STR));
|
|
|
+ timelineServiceAddress = conf.get(
|
|
|
+ YarnConfiguration.TIMELINE_SERVICE_WEBAPP_HTTPS_ADDRESS,
|
|
|
+ YarnConfiguration.DEFAULT_TIMELINE_SERVICE_WEBAPP_HTTPS_ADDRESS);
|
|
|
} else {
|
|
|
- resURI = URI.create(JOINER.join("http://", conf.get(
|
|
|
+ timelineServiceAddress = conf.get(
|
|
|
YarnConfiguration.TIMELINE_SERVICE_WEBAPP_ADDRESS,
|
|
|
- YarnConfiguration.DEFAULT_TIMELINE_SERVICE_WEBAPP_ADDRESS),
|
|
|
- RESOURCE_URI_STR));
|
|
|
+ YarnConfiguration.DEFAULT_TIMELINE_SERVICE_WEBAPP_ADDRESS);
|
|
|
}
|
|
|
LOG.info("Timeline service address: " + resURI);
|
|
|
timelineServiceVersion =
|
|
|
conf.getFloat(YarnConfiguration.TIMELINE_SERVICE_VERSION,
|
|
|
YarnConfiguration.DEFAULT_TIMELINE_SERVICE_VERSION);
|
|
|
+ LOG.info("Timeline service address: " + timelineServiceAddress);
|
|
|
super.serviceInit(conf);
|
|
|
}
|
|
|
|
|
@@ -331,6 +339,39 @@ public class TimelineClientImpl extends TimelineClient {
|
|
|
return timelineWriter.putEntities(entities);
|
|
|
}
|
|
|
|
|
|
+ @Override
|
|
|
+ public void putEntities(
|
|
|
+ org.apache.hadoop.yarn.api.records.timelineservice.TimelineEntity... entities)
|
|
|
+ throws IOException, YarnException {
|
|
|
+ putEntities(false, entities);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void putEntitiesAsync(
|
|
|
+ org.apache.hadoop.yarn.api.records.timelineservice.TimelineEntity... entities)
|
|
|
+ throws IOException, YarnException {
|
|
|
+ putEntities(true, entities);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void putEntities(boolean async,
|
|
|
+ org.apache.hadoop.yarn.api.records.timelineservice.TimelineEntity... entities)
|
|
|
+ throws IOException, YarnException {
|
|
|
+ org.apache.hadoop.yarn.api.records.timelineservice.TimelineEntities
|
|
|
+ entitiesContainer =
|
|
|
+ new org.apache.hadoop.yarn.api.records.timelineservice.TimelineEntities();
|
|
|
+ for (org.apache.hadoop.yarn.api.records.timelineservice.TimelineEntity entity : entities) {
|
|
|
+ entitiesContainer.addEntity(entity);
|
|
|
+ }
|
|
|
+ MultivaluedMap<String, String> params = new MultivaluedMapImpl();
|
|
|
+ if (contextAppId != null) {
|
|
|
+ params.add("appid", contextAppId.toString());
|
|
|
+ }
|
|
|
+ if (async) {
|
|
|
+ params.add("async", Boolean.TRUE.toString());
|
|
|
+ }
|
|
|
+ putObjects(constructResURI(getConfig(), timelineServiceAddress, true),
|
|
|
+ "entities", params, entitiesContainer);
|
|
|
+ }
|
|
|
|
|
|
@Override
|
|
|
public void putDomain(TimelineDomain domain) throws IOException,
|
|
@@ -338,6 +379,36 @@ public class TimelineClientImpl extends TimelineClient {
|
|
|
timelineWriter.putDomain(domain);
|
|
|
}
|
|
|
|
|
|
+ private void putObjects(
|
|
|
+ URI base, String path, MultivaluedMap<String, String> params, Object obj)
|
|
|
+ throws IOException, YarnException {
|
|
|
+ ClientResponse resp;
|
|
|
+ try {
|
|
|
+ resp = client.resource(base).path(path).queryParams(params)
|
|
|
+ .accept(MediaType.APPLICATION_JSON)
|
|
|
+ .type(MediaType.APPLICATION_JSON)
|
|
|
+ .put(ClientResponse.class, obj);
|
|
|
+ } catch (RuntimeException re) {
|
|
|
+ // runtime exception is expected if the client cannot connect the server
|
|
|
+ String msg =
|
|
|
+ "Failed to get the response from the timeline server.";
|
|
|
+ LOG.error(msg, re);
|
|
|
+ throw new IOException(re);
|
|
|
+ }
|
|
|
+ if (resp == null ||
|
|
|
+ resp.getClientResponseStatus() != ClientResponse.Status.OK) {
|
|
|
+ String msg =
|
|
|
+ "Failed to get the response from the timeline server.";
|
|
|
+ LOG.error(msg);
|
|
|
+ if (LOG.isDebugEnabled() && resp != null) {
|
|
|
+ String output = resp.getEntity(String.class);
|
|
|
+ LOG.debug("HTTP error code: " + resp.getStatus()
|
|
|
+ + " Server response:\n" + output);
|
|
|
+ }
|
|
|
+ throw new YarnException(msg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
@SuppressWarnings("unchecked")
|
|
|
@Override
|
|
|
public Token<TimelineDelegationTokenIdentifier> getDelegationToken(
|
|
@@ -352,7 +423,8 @@ public class TimelineClientImpl extends TimelineClient {
|
|
|
new DelegationTokenAuthenticatedURL(authenticator,
|
|
|
connConfigurator);
|
|
|
return (Token) authUrl.getDelegationToken(
|
|
|
- resURI.toURL(), token, renewer, doAsUser);
|
|
|
+ constructResURI(getConfig(), timelineServiceAddress, false).toURL(),
|
|
|
+ token, renewer, doAsUser);
|
|
|
}
|
|
|
};
|
|
|
return (Token<TimelineDelegationTokenIdentifier>) operateDelegationToken(getDTAction);
|
|
@@ -387,7 +459,7 @@ public class TimelineClientImpl extends TimelineClient {
|
|
|
// the configured service address.
|
|
|
final URI serviceURI = isTokenServiceAddrEmpty ? resURI
|
|
|
: new URI(scheme, null, address.getHostName(),
|
|
|
- address.getPort(), RESOURCE_URI_STR, null, null);
|
|
|
+ address.getPort(), RESOURCE_URI_STR_V1, null, null);
|
|
|
return authUrl
|
|
|
.renewDelegationToken(serviceURI.toURL(), token, doAsUser);
|
|
|
}
|
|
@@ -424,7 +496,7 @@ public class TimelineClientImpl extends TimelineClient {
|
|
|
// the configured service address.
|
|
|
final URI serviceURI = isTokenServiceAddrEmpty ? resURI
|
|
|
: new URI(scheme, null, address.getHostName(),
|
|
|
- address.getPort(), RESOURCE_URI_STR, null, null);
|
|
|
+ address.getPort(), RESOURCE_URI_STR_V1, null, null);
|
|
|
authUrl.cancelDelegationToken(serviceURI.toURL(), token, doAsUser);
|
|
|
return null;
|
|
|
}
|
|
@@ -531,6 +603,13 @@ public class TimelineClientImpl extends TimelineClient {
|
|
|
connection.setReadTimeout(socketTimeout);
|
|
|
}
|
|
|
|
|
|
+ private static URI constructResURI(
|
|
|
+ Configuration conf, String address, boolean v2) {
|
|
|
+ return URI.create(
|
|
|
+ JOINER.join(YarnConfiguration.useHttps(conf) ? "https://" : "http://",
|
|
|
+ address, v2 ? RESOURCE_URI_STR_V2 : RESOURCE_URI_STR_V1));
|
|
|
+ }
|
|
|
+
|
|
|
public static void main(String[] argv) throws Exception {
|
|
|
CommandLine cliParser = new GnuParser().parse(opts, argv);
|
|
|
if (cliParser.hasOption("put")) {
|