.../hadoop-common/src/main/conf/log4j.properties | 10 ++
.../ApplicationHistoryAuditLogger.java | 159 +++++++++++++++++++++
.../ApplicationHistoryServer.java | 26 +++-
.../yarn/server/timeline/TimelineDataManager.java | 8 ++
.../timeline/webapp/TimelineWebServices.java | 95 +++++++++++-
5 files changed, 294 insertions(+), 4 deletions(-)
diff --git a/hadoop-common-project/hadoop-common/src/main/conf/log4j.properties b/hadoop-common-project/hadoop-common/src/main/conf/log4j.properties
index 5a2ca4d9228..2b22efe356b 100644
--- a/hadoop-common-project/hadoop-common/src/main/conf/log4j.properties
+++ b/hadoop-common-project/hadoop-common/src/main/conf/log4j.properties
@@ -250,6 +250,16 @@ log4j.appender.NMAUDIT.MaxBackupIndex=${nm.audit.log.maxbackupindex}
#log4j.appender.HSAUDIT.layout.ConversionPattern=%d{ISO8601} %p %c{2}: %m%n
#log4j.appender.HSAUDIT.DatePattern=.yyyy-MM-dd
+# AHS audit log configs
+#yarn.ahs.audit.logger=INFO,AHSAUDIT
+#log4j.logger.org.apache.hadoop.yarn.server.applicationhistoryservice.ApplicationHistoryAuditLogger=${yarn.ahs.audit.logger}
+#log4j.additivity.org.apache.hadoop.yarn.server.applicationhistoryservice.ApplicationHistoryAuditLogger=false
+#log4j.appender.AHSAUDIT=org.apache.log4j.DailyRollingFileAppender
+#log4j.appender.AHSAUDIT.File=${hadoop.log.dir}/ahs-audit.log
+#log4j.appender.AHSAUDIT.layout=org.apache.log4j.PatternLayout
+#log4j.appender.AHSAUDIT.layout.ConversionPattern=%d{ISO8601} %p %c{2}: %m%n
+#log4j.appender.AHSAUDIT.DatePattern=.yyyy-MM-dd
+
# Http Server Request Logs
#log4j.logger.http.requests.namenode=INFO,namenoderequestlog
#log4j.appender.namenoderequestlog=org.apache.hadoop.http.HttpRequestLogAppender
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/ApplicationHistoryAuditLogger.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/ApplicationHistoryAuditLogger.java
new file mode 100644
index 00000000000..27b4f5d3fae
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/ApplicationHistoryAuditLogger.java
@@ -0,0 +1,159 @@
+/**
+ * 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;
+
+import java.net.InetAddress;
+
+import org.apache.hadoop.classification.InterfaceAudience.Private;
+import org.apache.hadoop.ipc.Server;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Private
+public class ApplicationHistoryAuditLogger {
+ private static final Logger LOG = LoggerFactory
+ .getLogger(ApplicationHistoryAuditLogger.class);
+
+ public static final String UNKNOWN_USER = "UNKNOWN";
+
+ enum Keys {
+ USER, OPERATION, TARGET, RESULT, IP, PERMISSIONS, DESCRIPTION
+ }
+
+ private ApplicationHistoryAuditLogger() {
+ throw new IllegalStateException("Utility class");
+ }
+
+ public static class AuditConstants {
+ static final String SUCCESS = "SUCCESS";
+ static final String FAILURE = "FAILURE";
+ static final String KEY_VAL_SEPARATOR = "=";
+ static final char PAIR_SEPARATOR = '\t';
+
+ // Some commonly used descriptions
+ public static final String UNAUTHORIZED_USER = "Unauthorized user";
+ }
+
+ /**
+ * Create a readable and parseable audit log string for a successful event.
+ *
+ * @param user
+ * User who made the service request.
+ * @param operation
+ * Operation requested by the user.
+ * @param target
+ * The target on which the operation is being performed.
+ *
+ *
+ *
+ * Note that the {@link ApplicationHistoryAuditLogger} uses tabs
+ * ('\t') as a key-val delimiter and hence the value fields should
+ * not contains tabs ('\t').
+ */
+ public static void logSuccess(String user, String operation, String target) {
+ if (LOG.isInfoEnabled()) {
+ LOG.info(createSuccessLog(user, operation, target));
+ }
+ }
+
+ /**
+ * A helper api for creating an audit log for a successful event.
+ */
+ static String createSuccessLog(String user, String operation, String target) {
+ StringBuilder b = new StringBuilder();
+ start(Keys.USER, user, b);
+ addRemoteIP(b);
+ add(Keys.OPERATION, operation, b);
+ add(Keys.TARGET, target, b);
+ add(Keys.RESULT, AuditConstants.SUCCESS, b);
+ return b.toString();
+ }
+
+ /**
+ * A helper api to add remote IP address.
+ */
+ static void addRemoteIP(StringBuilder b) {
+ InetAddress ip = Server.getRemoteIp();
+ // ip address can be null for testcases
+ if (ip != null) {
+ add(Keys.IP, ip.getHostAddress(), b);
+ }
+ }
+
+ /**
+ * Appends the key-val pair to the passed builder in the following format.
+ * key=value
+ */
+ static void add(Keys key, String value, StringBuilder b) {
+ b.append(AuditConstants.PAIR_SEPARATOR).append(key.name())
+ .append(AuditConstants.KEY_VAL_SEPARATOR).append(value);
+ }
+
+ /**
+ * Adds the first key-val pair to the passed builder in the following format.
+ * key=value
+ */
+ static void start(Keys key, String value, StringBuilder b) {
+ b.append(key.name()).append(AuditConstants.KEY_VAL_SEPARATOR).append(value);
+ }
+
+ /**
+ * Create a readable and parseable audit log string for a failed event.
+ *
+ * @param user
+ * User who made the service request.
+ * @param operation
+ * Operation requested by the user.
+ * @param perm
+ * Target permissions.
+ * @param target
+ * The target on which the operation is being performed.
+ * @param description
+ * Some additional information as to why the operation failed.
+ *
+ *
+ *
+ * Note that the {@link ApplicationHistoryAuditLogger} uses tabs
+ * ('\t') as a key-val delimiter and hence the value fields should
+ * not contains tabs ('\t').
+ */
+ public static void logFailure(String user, String operation, String perm,
+ String target, String description) {
+ if (LOG.isWarnEnabled()) {
+ LOG.warn(createFailureLog(user, operation, perm, target, description));
+ }
+ }
+
+ /**
+ * A helper api for creating an audit log for a failure event.
+ */
+ static String createFailureLog(String user, String operation, String perm,
+ String target, String description) {
+ StringBuilder b = new StringBuilder();
+ start(Keys.USER, user, b);
+ addRemoteIP(b);
+ add(Keys.OPERATION, operation, b);
+ add(Keys.TARGET, target, b);
+ add(Keys.RESULT, AuditConstants.FAILURE, b);
+ add(Keys.DESCRIPTION, description, b);
+ add(Keys.PERMISSIONS, perm, b);
+
+ return b.toString();
+ }
+}
\ No newline at end of file
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/ApplicationHistoryServer.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/ApplicationHistoryServer.java
index 5f1d7c29de2..4b31da43f89 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/ApplicationHistoryServer.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/ApplicationHistoryServer.java
@@ -30,6 +30,7 @@
import org.apache.hadoop.metrics2.source.JvmMetrics;
import org.apache.hadoop.security.HttpCrossOriginFilterInitializer;
import org.apache.hadoop.security.SecurityUtil;
+import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.service.CompositeService;
import org.apache.hadoop.service.Service;
import org.apache.hadoop.util.ExitUtil;
@@ -128,6 +129,8 @@ protected void serviceStop() throws Exception {
}
DefaultMetricsSystem.shutdown();
super.serviceStop();
+ ApplicationHistoryAuditLogger.logSuccess(getUserName(),
+ "ApplicationHistoryServerShutdown", "ApplicationHistoryServer");
}
@Private
@@ -176,8 +179,13 @@ static ApplicationHistoryServer launchAppHistoryServer(String[] args) {
new GenericOptionsParser(conf, args);
appHistoryServer.init(conf);
appHistoryServer.start();
+ ApplicationHistoryAuditLogger.logSuccess(getUserName(),
+ "ApplicationHistoryServerStartup", "ApplicationHistoryServer");
} catch (Throwable t) {
LOG.error("Error starting ApplicationHistoryServer", t);
+ ApplicationHistoryAuditLogger.logFailure(getUserName(),
+ "ApplicationHistoryServerStartup", "", "ApplicationHistoryServer",
+ "Exception during startup");
ExitUtil.terminate(-1, "Error starting ApplicationHistoryServer");
}
return appHistoryServer;
@@ -330,7 +338,7 @@ private void doSecureLogin(Configuration conf) throws IOException {
}
/**
- * Retrieve the timeline server bind address from configuration
+ * Retrieve the timeline server bind address from configuration.
*
* @param conf
* @return InetSocketAddress
@@ -340,4 +348,20 @@ private static InetSocketAddress getBindAddress(Configuration conf) {
YarnConfiguration.DEFAULT_TIMELINE_SERVICE_ADDRESS,
YarnConfiguration.DEFAULT_TIMELINE_SERVICE_PORT);
}
+
+ /**
+ * Returns user name.
+ *
+ * @return String
+ */
+ public static String getUserName() {
+ String userName = ApplicationHistoryAuditLogger.UNKNOWN_USER;
+ try {
+ UserGroupInformation user = UserGroupInformation.getCurrentUser();
+ userName = user.getShortUserName();
+ } catch (IOException ioe) {
+ LOG.warn("Couldn't get current user", ioe);
+ }
+ return userName;
+ }
}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/timeline/TimelineDataManager.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/timeline/TimelineDataManager.java
index bf40d41c8ff..20f49bdb46d 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/timeline/TimelineDataManager.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/timeline/TimelineDataManager.java
@@ -38,6 +38,7 @@
import org.apache.hadoop.yarn.api.records.timeline.TimelineDomains;
import org.apache.hadoop.yarn.api.records.timeline.TimelinePutResponse;
import org.apache.hadoop.yarn.exceptions.YarnException;
+import org.apache.hadoop.yarn.server.applicationhistoryservice.ApplicationHistoryAuditLogger;
import org.apache.hadoop.yarn.server.timeline.TimelineReader.Field;
import org.apache.hadoop.yarn.server.timeline.security.TimelineACLsManager;
import org.apache.hadoop.yarn.webapp.BadRequestException;
@@ -350,6 +351,10 @@ private TimelinePutResponse doPostEntities(
}
// check if there is existing entity
TimelineEntity existingEntity = null;
+ String user = (null != callerUGI) ? callerUGI.getUserName()
+ : ApplicationHistoryAuditLogger.UNKNOWN_USER;
+ String url = "/postEntities (EntityID=" + entity.getEntityId()
+ + ";EntityType=" + entity.getEntityType() + ")";
try {
existingEntity =
store.getEntity(entity.getEntityId(), entity.getEntityType(),
@@ -371,6 +376,7 @@ private TimelinePutResponse doPostEntities(
+ entity.getEntityType() + " } into the domain "
+ entity.getDomainId() + ".");
}
+ ApplicationHistoryAuditLogger.logSuccess(user, "/postEntities", url);
} catch (Exception e) {
// Skip the entity which already exists and was put by others
LOG.warn("Skip the timeline entity: { id: " + entity.getEntityId()
@@ -382,6 +388,8 @@ private TimelinePutResponse doPostEntities(
error.setErrorCode(
TimelinePutResponse.TimelinePutError.ACCESS_DENIED);
errors.add(error);
+ ApplicationHistoryAuditLogger.logFailure(user, "/postEntities", "", url,
+ "Exception while handling request");
continue;
}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/timeline/webapp/TimelineWebServices.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/timeline/webapp/TimelineWebServices.java
index 9423e7f71b5..48b8f17ee6f 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/timeline/webapp/TimelineWebServices.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/timeline/webapp/TimelineWebServices.java
@@ -53,6 +53,7 @@
import org.apache.hadoop.yarn.api.records.timeline.TimelineEvents;
import org.apache.hadoop.yarn.api.records.timeline.TimelinePutResponse;
import org.apache.hadoop.yarn.exceptions.YarnException;
+import org.apache.hadoop.yarn.server.applicationhistoryservice.ApplicationHistoryAuditLogger;
import org.apache.hadoop.yarn.server.timeline.EntityIdentifier;
import org.apache.hadoop.yarn.server.timeline.GenericObjectMapper;
import org.apache.hadoop.yarn.server.timeline.NameValuePair;
@@ -78,6 +79,14 @@
.getLogger(TimelineWebServices.class);
private TimelineDataManager timelineDataManager;
+ private static final String AHS_REST_ABOUT = "/about";
+ private static final String AHS_REST_GETENTITIES = "/getEntities";
+ private static final String AHS_REST_GETENTITY = "/getEntity";
+ private static final String AHS_REST_GETEVENTS = "/getEvents";
+ private static final String AHS_REST_POSTENTITIES = "/postEntities";
+ private static final String AHS_REST_PUTDOMAIN = "/putDomain";
+ private static final String AHS_REST_GETDOMAIN = "/getDomain";
+ private static final String AHS_REST_GETDOMAINS = "/getDomains";
@Inject
public TimelineWebServices(TimelineDataManager timelineDataManager) {
@@ -94,6 +103,11 @@ public TimelineAbout about(
@Context HttpServletRequest req,
@Context HttpServletResponse res) {
init(res);
+ UserGroupInformation callerUGI = getUser(req);
+ String user = (null != callerUGI) ? callerUGI.getUserName()
+ : ApplicationHistoryAuditLogger.UNKNOWN_USER;
+ ApplicationHistoryAuditLogger.logSuccess(user, AHS_REST_ABOUT,
+ AHS_REST_ABOUT);
return TimelineUtils.createTimelineAbout("Timeline API");
}
@@ -117,8 +131,12 @@ public TimelineEntities getEntities(
@QueryParam("limit") String limit,
@QueryParam("fields") String fields) {
init(res);
+ UserGroupInformation callerUGI = getUser(req);
+ String user = (null != callerUGI) ? callerUGI.getUserName()
+ : ApplicationHistoryAuditLogger.UNKNOWN_USER;
+ String url = "/" + entityType;
try {
- return timelineDataManager.getEntities(
+ TimelineEntities entities = timelineDataManager.getEntities(
parseStr(entityType),
parsePairStr(primaryFilter, ":"),
parsePairsStr(secondaryFilter, ",", ":"),
@@ -129,13 +147,21 @@ public TimelineEntities getEntities(
parseLongStr(limit),
parseFieldsStr(fields, ","),
getUser(req));
+ ApplicationHistoryAuditLogger.logSuccess(user, AHS_REST_GETENTITIES, url);
+ return entities;
} catch (NumberFormatException e) {
+ ApplicationHistoryAuditLogger.logFailure(user, AHS_REST_GETENTITIES, "",
+ url, "NumberFormatException while processing request");
throw new BadRequestException(
"windowStart, windowEnd, fromTs or limit is not a numeric value: " + e);
} catch (IllegalArgumentException e) {
+ ApplicationHistoryAuditLogger.logFailure(user, AHS_REST_GETENTITIES, "",
+ url, "IllegalArgumentException while processing request");
throw new BadRequestException("requested invalid field: " + e);
} catch (Exception e) {
LOG.error("Error getting entities", e);
+ ApplicationHistoryAuditLogger.logFailure(user, AHS_REST_GETENTITIES, "",
+ url, "Exception while handling request");
throw new WebApplicationException(e,
Response.Status.INTERNAL_SERVER_ERROR);
}
@@ -156,24 +182,37 @@ public TimelineEntity getEntity(
@QueryParam("fields") String fields) {
init(res);
TimelineEntity entity = null;
+ UserGroupInformation callerUGI = getUser(req);
+ String user = (null != callerUGI) ? callerUGI.getUserName()
+ : ApplicationHistoryAuditLogger.UNKNOWN_USER;
+ String url = "/" + entityType + "/" + entityId;
try {
entity = timelineDataManager.getEntity(
parseStr(entityType),
parseStr(entityId),
parseFieldsStr(fields, ","),
getUser(req));
+ ApplicationHistoryAuditLogger.logSuccess(user, AHS_REST_GETENTITY, url);
} catch (YarnException e) {
// The user doesn't have the access to override the existing domain.
LOG.info(e.getMessage(), e);
+ ApplicationHistoryAuditLogger.logFailure(user, AHS_REST_GETENTITY, "",
+ url, "YarnException while processing request");
throw new ForbiddenException(e);
} catch (IllegalArgumentException e) {
+ ApplicationHistoryAuditLogger.logFailure(user, AHS_REST_GETENTITY, "",
+ url, "IllegalArgumentException while processing request");
throw new BadRequestException(e);
} catch (Exception e) {
LOG.error("Error getting entity", e);
+ ApplicationHistoryAuditLogger.logFailure(user, AHS_REST_GETENTITY, "",
+ url, "Exception while handling request");
throw new WebApplicationException(e,
Response.Status.INTERNAL_SERVER_ERROR);
}
if (entity == null) {
+ ApplicationHistoryAuditLogger.logFailure(user, AHS_REST_GETENTITY, "",
+ url, url + " not found");
throw new NotFoundException("Timeline entity "
+ new EntityIdentifier(parseStr(entityId), parseStr(entityType))
+ " is not found");
@@ -198,8 +237,12 @@ public TimelineEvents getEvents(
@QueryParam("windowEnd") String windowEnd,
@QueryParam("limit") String limit) {
init(res);
+ UserGroupInformation callerUGI = getUser(req);
+ String user = (null != callerUGI) ? callerUGI.getUserName()
+ : ApplicationHistoryAuditLogger.UNKNOWN_USER;
+ String url = "/" + entityType + "/events";
try {
- return timelineDataManager.getEvents(
+ TimelineEvents events = timelineDataManager.getEvents(
parseStr(entityType),
parseArrayStr(entityId, ","),
parseArrayStr(eventType, ","),
@@ -207,12 +250,18 @@ public TimelineEvents getEvents(
parseLongStr(windowEnd),
parseLongStr(limit),
getUser(req));
+ ApplicationHistoryAuditLogger.logSuccess(user, AHS_REST_GETEVENTS, url);
+ return events;
} catch (NumberFormatException e) {
+ ApplicationHistoryAuditLogger.logFailure(user, AHS_REST_GETEVENTS, "",
+ url, "BadRequestException while processing request");
throw (BadRequestException)new BadRequestException(
"windowStart, windowEnd or limit is not a numeric value.")
.initCause(e);
} catch (Exception e) {
LOG.error("Error getting entity timelines", e);
+ ApplicationHistoryAuditLogger.logFailure(user, AHS_REST_GETEVENTS, "",
+ url, "Exception while handling request");
throw new WebApplicationException(e,
Response.Status.INTERNAL_SERVER_ERROR);
}
@@ -237,12 +286,18 @@ public TimelinePutResponse postEntities(
LOG.error(msg);
throw new ForbiddenException(msg);
}
+ String user = callerUGI.getUserName();
+ String url = "/postEntities";
try {
return timelineDataManager.postEntities(entities, callerUGI);
} catch (BadRequestException bre) {
+ ApplicationHistoryAuditLogger.logFailure(user, AHS_REST_POSTENTITIES, "",
+ url, "BadRequestException while handling request");
throw bre;
} catch (Exception e) {
LOG.error("Error putting entities", e);
+ ApplicationHistoryAuditLogger.logFailure(user, AHS_REST_POSTENTITIES, "",
+ url, "Error putting entities");
throw new WebApplicationException(e,
Response.Status.INTERNAL_SERVER_ERROR);
}
@@ -266,21 +321,33 @@ public TimelinePutResponse putDomain(
if (callerUGI == null) {
String msg = "The owner of the posted timeline domain is not set";
LOG.error(msg);
+ ApplicationHistoryAuditLogger.logFailure(
+ ApplicationHistoryAuditLogger.UNKNOWN_USER, AHS_REST_PUTDOMAIN, "",
+ "/domain", "The owner of the posted timeline domain is not set");
throw new ForbiddenException(msg);
}
domain.setOwner(callerUGI.getShortUserName());
+ String user = callerUGI.getUserName();
+ String url = "/domain";
try {
timelineDataManager.putDomain(domain, callerUGI);
+ ApplicationHistoryAuditLogger.logSuccess(user, AHS_REST_PUTDOMAIN, url);
} catch (YarnException e) {
// The user doesn't have the access to override the existing domain.
LOG.error(e.getMessage(), e);
+ ApplicationHistoryAuditLogger.logFailure(user, AHS_REST_PUTDOMAIN, "",
+ url, "YarnException while processing request");
throw new ForbiddenException(e);
} catch (RuntimeException e) {
LOG.error("Error putting domain", e);
+ ApplicationHistoryAuditLogger.logFailure(user, AHS_REST_PUTDOMAIN, "",
+ url, "RuntimeException while processing request");
throw new WebApplicationException(e,
Response.Status.INTERNAL_SERVER_ERROR);
} catch (IOException e) {
LOG.error("Error putting domain", e);
+ ApplicationHistoryAuditLogger.logFailure(user, AHS_REST_PUTDOMAIN, "",
+ url, "Exception while processing request");
throw new WebApplicationException(e,
Response.Status.INTERNAL_SERVER_ERROR);
}
@@ -301,21 +368,32 @@ public TimelineDomain getDomain(
init(res);
domainId = parseStr(domainId);
if (domainId == null || domainId.length() == 0) {
+ ApplicationHistoryAuditLogger.logFailure("", AHS_REST_GETDOMAIN, "",
+ "/domain", "Domain ID is not specified.");
throw new BadRequestException("Domain ID is not specified.");
}
TimelineDomain domain = null;
+ UserGroupInformation callerUGI = getUser(req);
+ String user = (null != callerUGI) ? callerUGI.getUserName()
+ : ApplicationHistoryAuditLogger.UNKNOWN_USER;
+ String url = "/domain/" + domainId;
try {
domain = timelineDataManager.getDomain(
parseStr(domainId), getUser(req));
} catch (Exception e) {
LOG.error("Error getting domain", e);
+ ApplicationHistoryAuditLogger.logFailure(user, AHS_REST_GETDOMAIN, "",
+ url, "Error getting domain");
throw new WebApplicationException(e,
Response.Status.INTERNAL_SERVER_ERROR);
}
if (domain == null) {
+ ApplicationHistoryAuditLogger.logFailure(user, AHS_REST_GETDOMAIN, "",
+ url, "Timeline domain [" + domainId + "] not found");
throw new NotFoundException("Timeline domain ["
+ domainId + "] is not found");
}
+ ApplicationHistoryAuditLogger.logSuccess(user, AHS_REST_GETDOMAIN, url);
return domain;
}
@@ -335,16 +413,27 @@ public TimelineDomains getDomains(
UserGroupInformation callerUGI = getUser(req);
if (owner == null || owner.length() == 0) {
if (callerUGI == null) {
+ ApplicationHistoryAuditLogger.logFailure(
+ ApplicationHistoryAuditLogger.UNKNOWN_USER, AHS_REST_GETDOMAINS, "",
+ "/domain", "Domain owner is not specified.");
throw new BadRequestException("Domain owner is not specified.");
} else {
// By default it's going to list the caller's domains
owner = callerUGI.getShortUserName();
}
}
+ String user = (null != callerUGI) ? callerUGI.getUserName()
+ : ApplicationHistoryAuditLogger.UNKNOWN_USER;
+ String url = "/domain";
try {
- return timelineDataManager.getDomains(owner, callerUGI);
+ TimelineDomains timelineDomains =
+ timelineDataManager.getDomains(owner, callerUGI);
+ ApplicationHistoryAuditLogger.logSuccess(user, AHS_REST_GETDOMAINS, url);
+ return timelineDomains;
} catch (Exception e) {
LOG.error("Error getting domains", e);
+ ApplicationHistoryAuditLogger.logFailure(user, AHS_REST_GETDOMAINS, "",
+ url, "Error getting domains");
throw new WebApplicationException(e,
Response.Status.INTERNAL_SERVER_ERROR);
}