Skip to content

Commit

Permalink
YARN-3541. Add version info on timeline service / generic history web…
Browse files Browse the repository at this point in the history
… UI and REST API. Contributed by Zhijie Shen
  • Loading branch information
xgong committed May 18, 2015
1 parent cdfae44 commit 76afd28
Show file tree
Hide file tree
Showing 14 changed files with 404 additions and 43 deletions.
3 changes: 3 additions & 0 deletions hadoop-yarn-project/CHANGES.txt
Expand Up @@ -114,6 +114,9 @@ Release 2.8.0 - UNRELEASED
YARN-3505. Node's Log Aggregation Report with SUCCEED should not cached in
RMApps. (Xuan Gong via junping_du)

YARN-3541. Add version info on timeline service / generic history web UI
and REST API. (Zhijie Shen via xgong)

IMPROVEMENTS

YARN-644. Basic null check is not performed on passed in arguments before
Expand Down
@@ -0,0 +1,116 @@
/**
* 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.api.records.timeline;


import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "about")
@XmlAccessorType(XmlAccessType.NONE)
@InterfaceAudience.Public
@InterfaceStability.Evolving
public class TimelineAbout {

private String about;
private String timelineServiceVersion;
private String timelineServiceBuildVersion;
private String timelineServiceVersionBuiltOn;
private String hadoopVersion;
private String hadoopBuildVersion;
private String hadoopVersionBuiltOn;

public TimelineAbout() {
}

public TimelineAbout(String about) {
this.about = about;
}

@XmlElement(name = "About")
public String getAbout() {
return about;
}

public void setAbout(String about) {
this.about = about;
}

@XmlElement(name = "timeline-service-version")
public String getTimelineServiceVersion() {
return timelineServiceVersion;
}

public void setTimelineServiceVersion(String timelineServiceVersion) {
this.timelineServiceVersion = timelineServiceVersion;
}

@XmlElement(name = "timeline-service-build-version")
public String getTimelineServiceBuildVersion() {
return timelineServiceBuildVersion;
}

public void setTimelineServiceBuildVersion(
String timelineServiceBuildVersion) {
this.timelineServiceBuildVersion = timelineServiceBuildVersion;
}

@XmlElement(name = "timeline-service-version-built-on")
public String getTimelineServiceVersionBuiltOn() {
return timelineServiceVersionBuiltOn;
}

public void setTimelineServiceVersionBuiltOn(
String timelineServiceVersionBuiltOn) {
this.timelineServiceVersionBuiltOn = timelineServiceVersionBuiltOn;
}

@XmlElement(name = "hadoop-version")
public String getHadoopVersion() {
return hadoopVersion;
}

public void setHadoopVersion(String hadoopVersion) {
this.hadoopVersion = hadoopVersion;
}

@XmlElement(name = "hadoop-build-version")
public String getHadoopBuildVersion() {
return hadoopBuildVersion;
}

public void setHadoopBuildVersion(String hadoopBuildVersion) {
this.hadoopBuildVersion = hadoopBuildVersion;
}

@XmlElement(name = "hadoop-version-built-on")
public String getHadoopVersionBuiltOn() {
return hadoopVersionBuiltOn;
}

public void setHadoopVersionBuiltOn(String hadoopVersionBuiltOn) {
this.hadoopVersionBuiltOn = hadoopVersionBuiltOn;
}
}

Expand Up @@ -26,7 +26,10 @@
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.security.SecurityUtil;
import org.apache.hadoop.util.VersionInfo;
import org.apache.hadoop.yarn.api.records.timeline.TimelineAbout;
import org.apache.hadoop.yarn.conf.YarnConfiguration;
import org.apache.hadoop.yarn.util.YarnVersionInfo;
import org.apache.hadoop.yarn.webapp.YarnJacksonJaxbJsonProvider;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
Expand Down Expand Up @@ -83,6 +86,17 @@ public static String dumpTimelineRecordtoJSON(Object o, boolean pretty)
}
}

public static TimelineAbout createTimelineAbout(String about) {
TimelineAbout tsInfo = new TimelineAbout(about);
tsInfo.setHadoopBuildVersion(VersionInfo.getBuildVersion());
tsInfo.setHadoopVersion(VersionInfo.getVersion());
tsInfo.setHadoopVersionBuiltOn(VersionInfo.getDate());
tsInfo.setTimelineServiceBuildVersion(YarnVersionInfo.getBuildVersion());
tsInfo.setTimelineServiceVersion(YarnVersionInfo.getVersion());
tsInfo.setTimelineServiceVersionBuiltOn(YarnVersionInfo.getDate());
return tsInfo;
}

public static InetSocketAddress getTimelineTokenServiceAddress(
Configuration conf) {
InetSocketAddress timelineServiceAddr = null;
Expand Down
Expand Up @@ -34,6 +34,10 @@ public void index() {
setTitle("Application History");
}

public void about() {
render(AboutPage.class);
}

public void app() {
render(AppPage.class);
}
Expand Down
Expand Up @@ -56,6 +56,7 @@ public void setup() {
bind(ApplicationBaseProtocol.class).toInstance(historyClientService);
bind(TimelineDataManager.class).toInstance(timelineDataManager);
route("/", AHSController.class);
route("/about", AHSController.class, "about");
route(pajoin("/apps", APP_STATE), AHSController.class);
route(pajoin("/app", APPLICATION_ID), AHSController.class, "app");
route(pajoin("/appattempt", APPLICATION_ATTEMPT_ID), AHSController.class,
Expand Down
Expand Up @@ -34,13 +34,15 @@
import org.apache.hadoop.util.StringUtils;
import org.apache.hadoop.yarn.api.records.YarnApplicationState;
import org.apache.hadoop.yarn.api.ApplicationBaseProtocol;
import org.apache.hadoop.yarn.api.records.timeline.TimelineAbout;
import org.apache.hadoop.yarn.server.webapp.WebServices;
import org.apache.hadoop.yarn.server.webapp.dao.AppAttemptInfo;
import org.apache.hadoop.yarn.server.webapp.dao.AppAttemptsInfo;
import org.apache.hadoop.yarn.server.webapp.dao.AppInfo;
import org.apache.hadoop.yarn.server.webapp.dao.AppsInfo;
import org.apache.hadoop.yarn.server.webapp.dao.ContainerInfo;
import org.apache.hadoop.yarn.server.webapp.dao.ContainersInfo;
import org.apache.hadoop.yarn.util.timeline.TimelineUtils;
import org.apache.hadoop.yarn.webapp.BadRequestException;

import com.google.inject.Inject;
Expand All @@ -55,6 +57,16 @@ public AHSWebServices(ApplicationBaseProtocol appBaseProt) {
super(appBaseProt);
}

@GET
@Path("/about")
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public TimelineAbout about(
@Context HttpServletRequest req,
@Context HttpServletResponse res) {
init(res);
return TimelineUtils.createTimelineAbout("Generic History Service API");
}

@GET
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public AppsInfo get(@Context HttpServletRequest req,
Expand Down
@@ -0,0 +1,47 @@
/**
* 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.server.applicationhistoryservice.webapp;

import com.google.inject.Inject;
import org.apache.hadoop.util.VersionInfo;
import org.apache.hadoop.yarn.api.records.timeline.TimelineAbout;
import org.apache.hadoop.yarn.util.YarnVersionInfo;
import org.apache.hadoop.yarn.util.timeline.TimelineUtils;
import org.apache.hadoop.yarn.webapp.View;
import org.apache.hadoop.yarn.webapp.view.HtmlBlock;
import org.apache.hadoop.yarn.webapp.view.InfoBlock;

public class AboutBlock extends HtmlBlock {
@Inject
AboutBlock(View.ViewContext ctx) {
super(ctx);
}

@Override
protected void render(Block html) {
TimelineAbout tsInfo = TimelineUtils.createTimelineAbout(
"Timeline Server - Generic History Service UI");
info("Timeline Server Overview").
_("Timeline Server Version:", tsInfo.getTimelineServiceBuildVersion() +
" on " + tsInfo.getTimelineServiceVersionBuiltOn()).
_("Hadoop Version:", tsInfo.getHadoopBuildVersion() +
" on " + tsInfo.getHadoopVersionBuiltOn());
html._(InfoBlock.class);
}
}
@@ -0,0 +1,36 @@
/**
* 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.server.applicationhistoryservice.webapp;


import org.apache.hadoop.yarn.webapp.SubView;
import org.apache.hadoop.yarn.webapp.YarnWebParams;

import static org.apache.hadoop.yarn.util.StringHelper.join;

public class AboutPage extends AHSView {
@Override protected void preHead(Page.HTML<_> html) {
commonPreHead(html);
set(TITLE, "Timeline Server - Generic History Service");
}

@Override protected Class<? extends SubView> content() {
return AboutBlock.class;
}
}
Expand Up @@ -43,6 +43,8 @@ public void render(Block html) {
div("#nav").
h3("Application History").
ul().
li().a(url("about"), "About").
_().
li().a(url("apps"), "Applications").
ul().
li().a(url("apps",
Expand Down
Expand Up @@ -42,17 +42,12 @@
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.classification.InterfaceAudience.Public;
import org.apache.hadoop.classification.InterfaceStability.Unstable;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.util.StringUtils;
import org.apache.hadoop.util.VersionInfo;
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;
Expand All @@ -65,6 +60,9 @@
import org.apache.hadoop.yarn.server.timeline.NameValuePair;
import org.apache.hadoop.yarn.server.timeline.TimelineDataManager;
import org.apache.hadoop.yarn.server.timeline.TimelineReader.Field;
import org.apache.hadoop.yarn.api.records.timeline.TimelineAbout;
import org.apache.hadoop.yarn.util.YarnVersionInfo;
import org.apache.hadoop.yarn.util.timeline.TimelineUtils;
import org.apache.hadoop.yarn.webapp.BadRequestException;
import org.apache.hadoop.yarn.webapp.ForbiddenException;
import org.apache.hadoop.yarn.webapp.NotFoundException;
Expand All @@ -86,43 +84,16 @@ public TimelineWebServices(TimelineDataManager timelineDataManager) {
this.timelineDataManager = timelineDataManager;
}

@XmlRootElement(name = "about")
@XmlAccessorType(XmlAccessType.NONE)
@Public
@Unstable
public static class AboutInfo {

private String about;

public AboutInfo() {

}

public AboutInfo(String about) {
this.about = about;
}

@XmlElement(name = "About")
public String getAbout() {
return about;
}

public void setAbout(String about) {
this.about = about;
}

}

/**
* Return the description of the timeline web services.
*/
@GET
@Produces({ MediaType.APPLICATION_JSON /* , MediaType.APPLICATION_XML */})
public AboutInfo about(
public TimelineAbout about(
@Context HttpServletRequest req,
@Context HttpServletResponse res) {
init(res);
return new AboutInfo("Timeline API");
return TimelineUtils.createTimelineAbout("Timeline API");
}

/**
Expand Down
Expand Up @@ -87,6 +87,20 @@ public void testView() throws Exception {
WebAppTests.flushOutput(injector);
}

@Test
public void testAboutPage() throws Exception {
Injector injector =
WebAppTests.createMockInjector(ApplicationBaseProtocol.class,
mockApplicationHistoryClientService(0, 0, 0));
AboutPage aboutPageInstance = injector.getInstance(AboutPage.class);

aboutPageInstance.render();
WebAppTests.flushOutput(injector);

aboutPageInstance.render();
WebAppTests.flushOutput(injector);
}

@Test
public void testAppPage() throws Exception {
Injector injector =
Expand Down

0 comments on commit 76afd28

Please sign in to comment.