diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/timelineservice/HierarchicalTimelineEntity.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/timelineservice/HierarchicalTimelineEntity.java index 1a62a5dcf92..01d85cfb1a9 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/timelineservice/HierarchicalTimelineEntity.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/timelineservice/HierarchicalTimelineEntity.java @@ -33,7 +33,7 @@ import java.util.Set; @InterfaceStability.Unstable public abstract class HierarchicalTimelineEntity extends TimelineEntity { private Identifier parent; - private Map> children = new HashMap<>(); + private HashMap> children = new HashMap<>(); HierarchicalTimelineEntity(String type) { super(type); @@ -56,14 +56,24 @@ public abstract class HierarchicalTimelineEntity extends TimelineEntity { parent.setId(id); } + // required by JAXB + @InterfaceAudience.Private @XmlElement(name = "children") + public HashMap> getChildrenJAXB() { + return children; + } + public Map> getChildren() { return children; } public void setChildren(Map> children) { validateChildren(children); - this.children = children; + if (children != null && !(children instanceof HashMap)) { + this.children = new HashMap>(children); + } else { + this.children = (HashMap) children; + } } public void addChildren(Map> children) { diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/timelineservice/TimelineEntity.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/timelineservice/TimelineEntity.java index d6d54e85e2f..1afb564e446 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/timelineservice/TimelineEntity.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/timelineservice/TimelineEntity.java @@ -65,12 +65,12 @@ public class TimelineEntity { } private Identifier identifier; - private Map info = new HashMap<>(); - private Map configs = new HashMap<>(); + private HashMap info = new HashMap<>(); + private HashMap configs = new HashMap<>(); private Set metrics = new HashSet<>(); private Set events = new HashSet<>(); - private Map> isRelatedToEntities = new HashMap<>(); - private Map> relatesToEntities = new HashMap<>(); + private HashMap> isRelatedToEntities = new HashMap<>(); + private HashMap> relatesToEntities = new HashMap<>(); private long createdTime; private long modifiedTime; @@ -109,13 +109,23 @@ public class TimelineEntity { this.identifier = identifier; } + // required by JAXB + @InterfaceAudience.Private @XmlElement(name = "info") + public HashMap getInfoJAXB() { + return info; + } + public Map getInfo() { return info; } public void setInfo(Map info) { - this.info = info; + if (info != null && !(info instanceof HashMap)) { + this.info = new HashMap(info); + } else { + this.info = (HashMap) info; + } } public void addInfo(Map info) { @@ -126,13 +136,23 @@ public class TimelineEntity { info.put(key, value); } + // required by JAXB + @InterfaceAudience.Private @XmlElement(name = "configs") + public HashMap getConfigsJAXB() { + return configs; + } + public Map getConfigs() { return configs; } public void setConfigs(Map configs) { - this.configs = configs; + if (configs != null && !(configs instanceof HashMap)) { + this.configs = new HashMap(configs); + } else { + this.configs = (HashMap) configs; + } } public void addConfigs(Map configs) { @@ -177,14 +197,24 @@ public class TimelineEntity { events.add(event); } - @XmlElement(name = "isrelatedto") public Map> getIsRelatedToEntities() { return isRelatedToEntities; } + // required by JAXB + @InterfaceAudience.Private + @XmlElement(name = "isrelatedto") + public HashMap> getIsRelatedToEntitiesJAXB() { + return isRelatedToEntities; + } + public void setIsRelatedToEntities( Map> isRelatedToEntities) { - this.isRelatedToEntities = isRelatedToEntities; + if (isRelatedToEntities != null && !(isRelatedToEntities instanceof HashMap)) { + this.isRelatedToEntities = new HashMap>(isRelatedToEntities); + } else { + this.isRelatedToEntities = (HashMap>) isRelatedToEntities; + } } public void addIsRelatedToEntities( @@ -209,7 +239,13 @@ public class TimelineEntity { ids.add(id); } + // required by JAXB + @InterfaceAudience.Private @XmlElement(name = "relatesto") + public HashMap> getRelatesToEntitiesJAXB() { + return relatesToEntities; + } + public Map> getRelatesToEntities() { return relatesToEntities; } @@ -235,7 +271,11 @@ public class TimelineEntity { } public void setRelatesToEntities(Map> relatesToEntities) { - this.relatesToEntities = relatesToEntities; + if (relatesToEntities != null && !(relatesToEntities instanceof HashMap)) { + this.relatesToEntities = new HashMap>(relatesToEntities); + } else { + this.relatesToEntities = (HashMap>) relatesToEntities; + } } @XmlElement(name = "createdtime") diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/timelineservice/TimelineEvent.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/timelineservice/TimelineEvent.java index b4815bb1eec..517c88c1cb2 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/timelineservice/TimelineEvent.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/timelineservice/TimelineEvent.java @@ -33,7 +33,7 @@ import java.util.Map; @InterfaceStability.Unstable public class TimelineEvent { private String id; - private Map info = new HashMap<>(); + private HashMap info = new HashMap<>(); private long timestamp; public TimelineEvent() { @@ -49,13 +49,23 @@ public class TimelineEvent { this.id = id; } + // required by JAXB + @InterfaceAudience.Private @XmlElement(name = "info") + public HashMap getInfoJAXB() { + return info; + } + public Map getInfo() { return info; } public void setInfo(Map info) { - this.info = info; + if (info != null && !(info instanceof HashMap)) { + this.info = new HashMap(info); + } else { + this.info = (HashMap) info; + } } public void addInfo(Map info) { diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/timelineservice/TimelineMetric.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/timelineservice/TimelineMetric.java index 6de895636c4..57babbf633a 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/timelineservice/TimelineMetric.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/timelineservice/TimelineMetric.java @@ -34,9 +34,9 @@ import java.util.Map; @InterfaceStability.Unstable public class TimelineMetric { private String id; - private Map info = new HashMap<>(); + private HashMap info = new HashMap<>(); private Object singleData; - private Map timeSeries = new LinkedHashMap<>(); + private HashMap timeSeries = new LinkedHashMap<>(); private long startTime; private long endTime; @@ -53,13 +53,23 @@ public class TimelineMetric { this.id = id; } + // required by JAXB + @InterfaceAudience.Private @XmlElement(name = "info") + public HashMap getInfoJAXB() { + return info; + } + public Map getInfo() { return info; } public void setInfo(Map info) { - this.info = info; + if (info != null && !(info instanceof HashMap)) { + this.info = new HashMap(info); + } else { + this.info = (HashMap) info; + } } public void addInfo(Map info) { @@ -79,13 +89,23 @@ public class TimelineMetric { this.singleData = singleData; } + // required by JAXB + @InterfaceAudience.Private @XmlElement(name = "timeseries") + public HashMap getTimeSeriesJAXB() { + return timeSeries; + } + public Map getTimeSeries() { return timeSeries; } public void setTimeSeries(Map timeSeries) { - this.timeSeries = timeSeries; + if (timeSeries != null && !(timeSeries instanceof LinkedHashMap)) { + this.timeSeries = new LinkedHashMap(timeSeries); + } else { + this.timeSeries = (LinkedHashMap) timeSeries; + } } public void addTimeSeries(Map timeSeries) { diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/webapp/WebServer.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/webapp/WebServer.java index 4d89dc298fd..ff4013378a4 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/webapp/WebServer.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/webapp/WebServer.java @@ -126,12 +126,6 @@ public class WebServer extends AbstractService { bind(NMWebServices.class); bind(GenericExceptionHandler.class); bind(JAXBContextResolver.class); - // host the timeline service aggregator web service temporarily - // (see YARN-3087) - bind(PerNodeAggregatorWebService.class); - // bind to the global singleton instance - bind(AppLevelServiceManager.class). - toProvider(AppLevelServiceManagerProvider.class); bind(ResourceView.class).toInstance(this.resourceView); bind(ApplicationACLsManager.class).toInstance(this.aclsManager); bind(LocalDirsHandlerService.class).toInstance(dirsHandler); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-timelineservice/src/main/java/org/apache/hadoop/yarn/server/timelineservice/aggregator/PerNodeAggregatorServer.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-timelineservice/src/main/java/org/apache/hadoop/yarn/server/timelineservice/aggregator/PerNodeAggregatorServer.java index ef30b22b652..55c6271103a 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-timelineservice/src/main/java/org/apache/hadoop/yarn/server/timelineservice/aggregator/PerNodeAggregatorServer.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-timelineservice/src/main/java/org/apache/hadoop/yarn/server/timelineservice/aggregator/PerNodeAggregatorServer.java @@ -18,14 +18,16 @@ package org.apache.hadoop.yarn.server.timelineservice.aggregator; +import java.net.URI; import java.nio.ByteBuffer; +import java.util.HashMap; -import com.google.inject.Inject; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.classification.InterfaceAudience.Private; import org.apache.hadoop.classification.InterfaceStability.Unstable; import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.http.lib.StaticUserWebFilter; import org.apache.hadoop.util.ExitUtil; import org.apache.hadoop.util.ShutdownHookManager; import org.apache.hadoop.util.StringUtils; @@ -40,11 +42,16 @@ import org.apache.hadoop.yarn.server.api.AuxiliaryService; import org.apache.hadoop.yarn.server.api.ContainerContext; import org.apache.hadoop.yarn.server.api.ContainerInitializationContext; import org.apache.hadoop.yarn.server.api.ContainerTerminationContext; -import org.apache.hadoop.yarn.webapp.*; +import org.apache.hadoop.yarn.webapp.GenericExceptionHandler; +import org.apache.hadoop.yarn.webapp.YarnJacksonJaxbJsonProvider; import org.apache.hadoop.yarn.webapp.util.WebAppUtils; +import org.apache.hadoop.http.HttpServer2; import com.google.common.annotations.VisibleForTesting; +import static org.apache.hadoop.fs.CommonConfigurationKeys.DEFAULT_HADOOP_HTTP_STATIC_USER; +import static org.apache.hadoop.fs.CommonConfigurationKeys.HADOOP_HTTP_STATIC_USER; + /** * The top-level server for the per-node timeline aggregator service. Currently * it is defined as an auxiliary service to accommodate running within another @@ -56,9 +63,10 @@ public class PerNodeAggregatorServer extends AuxiliaryService { private static final Log LOG = LogFactory.getLog(PerNodeAggregatorServer.class); private static final int SHUTDOWN_HOOK_PRIORITY = 30; + static final String AGGREGATOR_COLLECTION_ATTR_KEY = "aggregator.collection"; private final AppLevelServiceManager serviceManager; - private WebApp webApp; + private HttpServer2 timelineRestServer; public PerNodeAggregatorServer() { // use the same singleton @@ -86,8 +94,8 @@ public class PerNodeAggregatorServer extends AuxiliaryService { @Override protected void serviceStop() throws Exception { - if (webApp != null) { - webApp.stop(); + if (timelineRestServer != null) { + timelineRestServer.stop(); } // stop the service manager serviceManager.stop(); @@ -103,11 +111,31 @@ public class PerNodeAggregatorServer extends AuxiliaryService { WebAppUtils.getAHSWebAppURLWithoutScheme(conf)); LOG.info("Instantiating the per-node aggregator webapp at " + bindAddress); try { - webApp = - WebApps - .$for("timeline", null, null, "ws") - .with(conf).at(bindAddress).start( - new TimelineServiceWebApp()); + Configuration confForInfoServer = new Configuration(conf); + confForInfoServer.setInt(HttpServer2.HTTP_MAX_THREADS, 10); + HttpServer2.Builder builder = new HttpServer2.Builder() + .setName("timeline") + .setConf(conf) + .addEndpoint(URI.create("http://" + bindAddress)); + timelineRestServer = builder.build(); + // TODO: replace this by an authentification filter in future. + HashMap options = new HashMap(); + String username = conf.get(HADOOP_HTTP_STATIC_USER, + DEFAULT_HADOOP_HTTP_STATIC_USER); + options.put(HADOOP_HTTP_STATIC_USER, username); + HttpServer2.defineFilter(timelineRestServer.getWebAppContext(), + "static_user_filter_timeline", + StaticUserWebFilter.StaticUserFilter.class.getName(), + options, new String[] {"/*"}); + + timelineRestServer.addJerseyResourcePackage( + PerNodeAggregatorWebService.class.getPackage().getName() + ";" + + GenericExceptionHandler.class.getPackage().getName() + ";" + + YarnJacksonJaxbJsonProvider.class.getPackage().getName(), + "/*"); + timelineRestServer.setAttribute(AGGREGATOR_COLLECTION_ATTR_KEY, + AppLevelServiceManager.getInstance()); + timelineRestServer.start(); } catch (Exception e) { String msg = "The per-node aggregator webapp failed to start."; LOG.error(msg, e); @@ -115,19 +143,6 @@ public class PerNodeAggregatorServer extends AuxiliaryService { } } - private static class TimelineServiceWebApp - extends WebApp implements YarnWebParams { - @Override - public void setup() { - bind(YarnJacksonJaxbJsonProvider.class); - bind(GenericExceptionHandler.class); - bind(PerNodeAggregatorWebService.class); - // bind to the global singleton - bind(AppLevelServiceManager.class). - toProvider(AppLevelServiceManagerProvider.class); - } - } - // these methods can be used as the basis for future service methods if the // per-node aggregator runs separate from the node manager /** diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-timelineservice/src/main/java/org/apache/hadoop/yarn/server/timelineservice/aggregator/PerNodeAggregatorWebService.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-timelineservice/src/main/java/org/apache/hadoop/yarn/server/timelineservice/aggregator/PerNodeAggregatorWebService.java index 28e6a528550..ffe099e8836 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-timelineservice/src/main/java/org/apache/hadoop/yarn/server/timelineservice/aggregator/PerNodeAggregatorWebService.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-timelineservice/src/main/java/org/apache/hadoop/yarn/server/timelineservice/aggregator/PerNodeAggregatorWebService.java @@ -18,6 +18,7 @@ package org.apache.hadoop.yarn.server.timelineservice.aggregator; +import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.*; @@ -41,11 +42,8 @@ import org.apache.hadoop.yarn.util.ConverterUtils; import org.apache.hadoop.yarn.webapp.ForbiddenException; import org.apache.hadoop.yarn.webapp.NotFoundException; -import com.google.inject.Inject; import com.google.inject.Singleton; -import java.net.URI; - /** * The main per-node REST end point for timeline service writes. It is * essentially a container service that routes requests to the appropriate @@ -59,12 +57,7 @@ public class PerNodeAggregatorWebService { private static final Log LOG = LogFactory.getLog(PerNodeAggregatorWebService.class); - private final AppLevelServiceManager serviceManager; - - @Inject - public PerNodeAggregatorWebService(AppLevelServiceManager serviceManager) { - this.serviceManager = serviceManager; - } + private @Context ServletContext context; @XmlRootElement(name = "about") @XmlAccessorType(XmlAccessType.NONE) @@ -135,7 +128,7 @@ public class PerNodeAggregatorWebService { if (appId == null) { return Response.status(Response.Status.BAD_REQUEST).build(); } - AppLevelAggregatorService service = serviceManager.getService(appId); + AppLevelAggregatorService service = getAggregatorService(req, appId); if (service == null) { LOG.error("Application not found"); throw new NotFoundException(); // different exception? @@ -163,6 +156,15 @@ public class PerNodeAggregatorWebService { } } + private AppLevelAggregatorService + getAggregatorService(HttpServletRequest req, String appIdToParse) { + String appIdString = parseApplicationId(appIdToParse); + final AppLevelServiceManager serviceManager = + (AppLevelServiceManager) context.getAttribute( + PerNodeAggregatorServer.AGGREGATOR_COLLECTION_ATTR_KEY); + return serviceManager.getService(appIdString); + } + private void init(HttpServletResponse response) { response.setContentType(null); }