diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/client/api/TimelineReaderClient.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/client/api/TimelineReaderClient.java new file mode 100644 index 00000000000..d76c1cafc0d --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/client/api/TimelineReaderClient.java @@ -0,0 +1,97 @@ +/** + * 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.hadoop.yarn.client.api; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.classification.InterfaceStability; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.service.AbstractService; +import org.apache.hadoop.yarn.api.records.ApplicationAttemptId; +import org.apache.hadoop.yarn.api.records.ApplicationId; +import org.apache.hadoop.yarn.api.records.ContainerId; +import org.apache.hadoop.yarn.api.records.timelineservice.TimelineEntity; +import org.apache.hadoop.yarn.api.records.timelineservice.TimelineEntityType; +import org.apache.hadoop.yarn.client.api.impl.TimelineReaderClientImpl; + +import java.io.IOException; +import java.util.List; + +@InterfaceAudience.Public +@InterfaceStability.Evolving +public abstract class TimelineReaderClient extends AbstractService { + + /** + * Create a new instance of Timeline Reader Client. + */ + @InterfaceAudience.Public + public static TimelineReaderClient createTimelineReaderClient() { + return new TimelineReaderClientImpl(); + } + + @InterfaceAudience.Private + public TimelineReaderClient(String name) { + super(name); + } + + /** + * Get application entity + * @param appId application id + * @return entity of the application + * @throws IOException + */ + public abstract TimelineEntity getApplicationEntity( + ApplicationId appId) throws IOException; + + /** + * Get application attempt entity + * @param appAttemptId application attempt id + * @return entity associated with application attempt + * @throws IOException + */ + public abstract TimelineEntity getApplicationAttemptEntity( + ApplicationAttemptId appAttemptId) throws IOException; + + /** + * Get application attempt entities + * @param appId application id + * @return list of application attempt entities + * @throws IOException + */ + public abstract List getApplicationAttemptEntities( + ApplicationId appId) throws IOException; + + /** + * Get Timeline entity for the container. + * @param containerId container id + * @return timeline entity for contianer + * @throws IOException + */ + public abstract TimelineEntity getContainerEntity( + ContainerId containerId) throws IOException; + + /** + * Get container entities for an application + * @param appAttemptId application attempt id + * @return list of entities + * @throws IOException + */ + public abstract List getContainerEntities( + ApplicationAttemptId appAttemptId) + throws IOException; +} diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/client/api/impl/TimelineReaderClientImpl.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/client/api/impl/TimelineReaderClientImpl.java new file mode 100644 index 00000000000..97032ba56d9 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/client/api/impl/TimelineReaderClientImpl.java @@ -0,0 +1,182 @@ +/** + * 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.hadoop.yarn.client.api.impl; + +import com.sun.jersey.api.client.config.DefaultClientConfig; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.yarn.api.records.ApplicationAttemptId; +import org.apache.hadoop.yarn.api.records.ApplicationId; +import org.apache.hadoop.yarn.api.records.ContainerId; +import org.apache.hadoop.yarn.api.records.timelineservice.TimelineEntity; +import org.apache.hadoop.yarn.client.api.TimelineReaderClient; +import com.sun.jersey.api.client.Client; +import com.sun.jersey.api.client.ClientResponse; +import com.sun.jersey.api.client.config.ClientConfig; +import org.apache.hadoop.yarn.conf.YarnConfiguration; +import org.apache.hadoop.yarn.util.timeline.TimelineUtils; +import org.apache.hadoop.yarn.webapp.YarnJacksonJaxbJsonProvider; + +import java.io.IOException; +import java.net.URI; +import java.util.Arrays; +import java.util.List; + +import static org.apache.hadoop.yarn.api.records.timelineservice.TimelineEntityType.YARN_APPLICATION_ATTEMPT; +import static org.apache.hadoop.yarn.api.records.timelineservice.TimelineEntityType.YARN_CONTAINER; + +public class TimelineReaderClientImpl extends TimelineReaderClient { + private static final Log LOG = + LogFactory.getLog(TimelineReaderClientImpl.class); + + private static final String RESOURCE_URI_STR_V2 = "/ws/v2/timeline/"; + + private Client client; + private volatile String timelineServiceAddress; + private Configuration conf; + + public TimelineReaderClientImpl() { + super(TimelineReaderClientImpl.class.getName()); + } + + @Override + protected void serviceInit(Configuration conf) throws Exception { + this.conf = conf; + ClientConfig cc = new DefaultClientConfig(); + cc.getClasses().add(YarnJacksonJaxbJsonProvider.class); + client = Client.create(cc); + timelineServiceAddress = conf.get( + YarnConfiguration.TIMELINE_SERVICE_READER_WEBAPP_ADDRESS, + YarnConfiguration.DEFAULT_TIMELINE_SERVICE_READER_WEBAPP_ADDRESS); + } + + @Override + public TimelineEntity getApplicationEntity(ApplicationId appId) + throws IOException { + String url = RESOURCE_URI_STR_V2 + + "apps/" + appId.toString(); + url += "?fields=ALL"; + URI uri = TimelineConnector.constructResURI( + conf, timelineServiceAddress, url); + ClientResponse response = client.resource(uri).accept("application/json") + .get(ClientResponse.class); + if (response.getStatus() != 200) { + throw new IOException("Failed to fetch timeline entity : HTTP error code : " + + response.getStatus()); + } + TimelineEntity entity = response.getEntity(TimelineEntity.class); + LOG.info("Entity: " + TimelineUtils.dumpTimelineRecordtoJSON(entity)); + return entity; + } + + @Override + public TimelineEntity getApplicationAttemptEntity( + ApplicationAttemptId appAttemptId) throws IOException { + ApplicationId appId = appAttemptId.getApplicationId(); + String url = RESOURCE_URI_STR_V2 + + "apps/" + appId.toString(); + url += "/entities/" + YARN_APPLICATION_ATTEMPT.toString(); + url += "/" + appAttemptId.toString(); + url += "?fields=ALL"; + URI uri = TimelineConnector.constructResURI( + conf, timelineServiceAddress, url); + ClientResponse response = client.resource(uri).accept("application/json") + .get(ClientResponse.class); + if (response.getStatus() != 200) { + throw new IOException("Failed : HTTP error code : " + + response.getStatus()); + } + TimelineEntity entity = response.getEntity(TimelineEntity.class); + LOG.info("Entity: " + TimelineUtils.dumpTimelineRecordtoJSON(entity)); + return entity; + } + + @Override + public List getApplicationAttemptEntities( + ApplicationId appId) + throws IOException { + String url = RESOURCE_URI_STR_V2 + + "apps/" + appId.toString(); + url += "/entities/" + YARN_APPLICATION_ATTEMPT.toString(); + url += "?fields=ALL"; + URI uri = TimelineConnector.constructResURI( + conf, timelineServiceAddress, url); + ClientResponse response = client.resource(uri).accept("application/json") + .get(ClientResponse.class); + if (response.getStatus() != 200) { + throw new IOException("Failed : HTTP error code : " + + response.getStatus()); + } + TimelineEntity[] entities = response.getEntity(TimelineEntity[].class); + LOG.info("Entity: " + TimelineUtils.dumpTimelineRecordtoJSON(entities)); + return Arrays.asList(entities); + } + + @Override + public TimelineEntity getContainerEntity(ContainerId containerId) + throws IOException { + ApplicationId appId = containerId.getApplicationAttemptId(). + getApplicationId(); + String url = RESOURCE_URI_STR_V2 + + "apps/" + appId.toString(); + url += "/entities/" + YARN_CONTAINER.toString(); + url += "/" + containerId; + url += "?fields=ALL"; + URI uri = TimelineConnector.constructResURI( + conf, timelineServiceAddress, url); + ClientResponse response = doGetUri(uri); + TimelineEntity entity = response.getEntity(TimelineEntity.class); + LOG.info("Entity: " + TimelineUtils.dumpTimelineRecordtoJSON(entity)); + return entity; + } + + @Override + public List getContainerEntities( + ApplicationAttemptId appAttemptId) throws IOException { + ApplicationId appId = appAttemptId.getApplicationId(); + String url = RESOURCE_URI_STR_V2 + + "apps/" + appId.toString(); + url += "/entities/" + YARN_CONTAINER.toString(); + url += "?fields=ALL&infofilters=SYSTEM_INFO_PARENT_ENTITY eq {\"id\":\"" + + appAttemptId.toString() + "\",\"type\":\"YARN_APPLICATION_ATTEMPT\"}"; + URI uri = TimelineConnector.constructResURI( + conf, timelineServiceAddress, url); + ClientResponse response = doGetUri(uri); + TimelineEntity[] entity = response.getEntity(TimelineEntity[].class); + LOG.info("Entity: " + TimelineUtils.dumpTimelineRecordtoJSON(entity)); + return Arrays.asList(entity); + } + + private ClientResponse doGetUri(URI uri) throws IOException { + ClientResponse resp = client.resource(uri).accept("application/json") + .get(ClientResponse.class); + if (resp == null || + resp.getStatusInfo().getStatusCode() != ClientResponse.Status.OK + .getStatusCode()) { + String msg = + "Response from the timeline reader server is " + + ((resp == null) ? "null" : "not successful," + + " HTTP error code: " + resp.getStatus() + + ", Server response:\n" + resp.getEntity(String.class)); + LOG.error(msg); + throw new IOException(msg); + } + return resp; + } +}