You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by yu...@apache.org on 2014/10/16 22:11:37 UTC

[13/51] [partial] AMBARI-7718. Rebase branch-windows-dev against trunk. (Jayush Luniya and Florian Barca via yusaku)

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/agent/CancelCommand.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/CancelCommand.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/CancelCommand.java
new file mode 100644
index 0000000..7aa24c8
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/CancelCommand.java
@@ -0,0 +1,52 @@
+/**
+ * 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.ambari.server.agent;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * Command to report the status of a list of services in roles.
+ */
+public class CancelCommand extends AgentCommand {
+
+  public CancelCommand() {
+    super(AgentCommandType.CANCEL_COMMAND);
+  }
+
+  @SerializedName("target_task_id")
+  private long targetTaskId;
+
+  @SerializedName("reason")
+  private String reason;
+
+  public long getTargetTaskId() {
+    return targetTaskId;
+  }
+
+  public void setTargetTaskId(long targetTaskId) {
+    this.targetTaskId = targetTaskId;
+  }
+
+  public String getReason() {
+    return reason;
+  }
+
+  public void setReason(String reason) {
+    this.reason = reason;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java
index 882f1e3..f0614e4 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java
@@ -18,6 +18,7 @@
 package org.apache.ambari.server.agent;
 
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 
@@ -25,7 +26,8 @@ import org.apache.ambari.server.RoleCommand;
 import org.apache.ambari.server.utils.StageUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.codehaus.jackson.annotate.JsonProperty;
+
+import com.google.gson.annotations.SerializedName;
 
 
 /**
@@ -33,63 +35,95 @@ import org.codehaus.jackson.annotate.JsonProperty;
  * persisted in the database for recovery.
  */
 public class ExecutionCommand extends AgentCommand {
-  
+
   private static Log LOG = LogFactory.getLog(ExecutionCommand.class);
-  
+
   public ExecutionCommand() {
     super(AgentCommandType.EXECUTION_COMMAND);
   }
 
+  @SerializedName("clusterName")
   private String clusterName;
+
+  @SerializedName("taskId")
   private long taskId;
+
+  @SerializedName("commandId")
   private String commandId;
+
+  @SerializedName("hostname")
   private String hostname;
+
+  @SerializedName("role")
   private String role;
+
+  @SerializedName("hostLevelParams")
   private Map<String, String> hostLevelParams = new HashMap<String, String>();
+
+  @SerializedName("roleParams")
   private Map<String, String> roleParams = null;
+
+  @SerializedName("roleCommand")
   private RoleCommand roleCommand;
-  private Map<String, Set<String>> clusterHostInfo = 
+
+  @SerializedName("clusterHostInfo")
+  private Map<String, Set<String>> clusterHostInfo =
       new HashMap<String, Set<String>>();
+
+  @SerializedName("configurations")
   private Map<String, Map<String, String>> configurations;
+
+  @SerializedName("configuration_attributes")
+  private Map<String, Map<String, Map<String, String>>> configurationAttributes;
+
+  @SerializedName("configurationTags")
   private Map<String, Map<String, String>> configurationTags;
-  private Map<String, String> commandParams;
+
+  @SerializedName("forceRefreshConfigTags")
+  private Set<String> forceRefreshConfigTags = new HashSet<String>();
+
+  @SerializedName("commandParams")
+  private Map<String, String> commandParams = new HashMap<String, String>();
+
+  @SerializedName("serviceName")
   private String serviceName;
+
+  @SerializedName("componentName")
   private String componentName;
 
   /**
    * Used for ignoring nagios alerts at agent
    */
+  @SerializedName("passiveInfo")
   private Set<Map<String,String>> passiveInfo;
 
-  @JsonProperty("commandId")
   public String getCommandId() {
-    return this.commandId;
+    return commandId;
   }
-  
-  @JsonProperty("commandId")
+
   public void setCommandId(String commandId) {
     this.commandId = commandId;
   }
-  
+
   @Override
   public boolean equals(Object other) {
     if (!(other instanceof ExecutionCommand)) {
       return false;
     }
     ExecutionCommand o = (ExecutionCommand) other;
-    return (this.commandId.equals(o.commandId) &&
-            this.hostname.equals(o.hostname) &&
-            this.role.equals(o.role) &&
-            this.roleCommand.equals(o.roleCommand));
+    return (commandId.equals(o.commandId) &&
+            hostname.equals(o.hostname) &&
+            role.equals(o.role) &&
+            roleCommand.equals(o.roleCommand));
   }
-  
+
   @Override
   public String toString() {
     try {
       return StageUtils.jaxbToString(this);
     } catch (Exception ex) {
       LOG.warn("Exception in json conversion", ex);
-      return "Exception in json conversion"; 
+      return "Exception in json conversion";
     }
   }
 
@@ -98,122 +132,116 @@ public class ExecutionCommand extends AgentCommand {
     return (hostname + commandId + role).hashCode();
   }
 
-  @JsonProperty("taskId")
   public long getTaskId() {
     return taskId;
   }
 
-  @JsonProperty("taskId")
   public void setTaskId(long taskId) {
     this.taskId = taskId;
   }
 
-  @JsonProperty("role")
   public String getRole() {
     return role;
   }
 
-  @JsonProperty("role")
   public void setRole(String role) {
     this.role = role;
   }
 
-  @JsonProperty("roleParams")
   public Map<String, String> getRoleParams() {
     return roleParams;
   }
 
-  @JsonProperty("roleParams")
   public void setRoleParams(Map<String, String> roleParams) {
     this.roleParams = roleParams;
   }
 
-  @JsonProperty("roleCommand")
   public RoleCommand getRoleCommand() {
     return roleCommand;
   }
 
-  @JsonProperty("roleCommand")
   public void setRoleCommand(RoleCommand cmd) {
-    this.roleCommand = cmd;
+    roleCommand = cmd;
   }
-  
-  @JsonProperty("clusterName")
+
   public String getClusterName() {
     return clusterName;
   }
-  
-  @JsonProperty("clusterName")
+
   public void setClusterName(String clusterName) {
     this.clusterName = clusterName;
   }
 
-  @JsonProperty("hostname")
   public String getHostname() {
     return hostname;
   }
 
-  @JsonProperty("hostname")
   public void setHostname(String hostname) {
     this.hostname = hostname;
   }
 
-  @JsonProperty("hostLevelParams")
   public Map<String, String> getHostLevelParams() {
     return hostLevelParams;
   }
 
-  @JsonProperty("hostLevelParams")
   public void setHostLevelParams(Map<String, String> params) {
-    this.hostLevelParams = params;
+    hostLevelParams = params;
   }
 
-  @JsonProperty("clusterHostInfo")
   public Map<String, Set<String>> getClusterHostInfo() {
     return clusterHostInfo;
   }
 
-  @JsonProperty("clusterHostInfo")
   public void setClusterHostInfo(Map<String, Set<String>> clusterHostInfo) {
     this.clusterHostInfo = clusterHostInfo;
   }
-  
-  @JsonProperty("configurations")
+
   public Map<String, Map<String, String>> getConfigurations() {
     return configurations;
   }
 
-  @JsonProperty("configurations")
   public void setConfigurations(Map<String, Map<String, String>> configurations) {
     this.configurations = configurations;
   }
+  /**
+   * @return Returns the set of config-types that have to be propagated to actual-config of component of given custom command, if command is successfully finished.
+   */
+  public Set<String> getForceRefreshConfigTags() {
+    return forceRefreshConfigTags;
+  }
+
+  public void setForceRefreshConfigTags(Set<String> forceRefreshConfigTags) {
+    this.forceRefreshConfigTags = forceRefreshConfigTags;
+  }
+
+  public Map<String, Map<String, Map<String, String>>> getConfigurationAttributes() {
+    return configurationAttributes;
+  }
+
+  public void setConfigurationAttributes(Map<String, Map<String, Map<String, String>>> configurationAttributes) {
+    this.configurationAttributes = configurationAttributes;
+  }
 
-  @JsonProperty("commandParams")
   public Map<String, String> getCommandParams() {
     return commandParams;
   }
 
-  @JsonProperty("commandParams")
   public void setCommandParams(Map<String, String> commandParams) {
     this.commandParams = commandParams;
   }
 
-  @JsonProperty("serviceName")
   public String getServiceName() {
     return serviceName;
   }
 
-  @JsonProperty("serviceName")
   public void setServiceName(String serviceName) {
     this.serviceName = serviceName;
   }
 
-  @JsonProperty("componentName")
   public String getComponentName() {
     return componentName;
   }
 
-  @JsonProperty("componentName")
   public void setComponentName(String componentName) {
     this.componentName = componentName;
   }
@@ -223,22 +251,22 @@ public class ExecutionCommand extends AgentCommand {
    */
   public void setConfigurationTags(Map<String, Map<String, String>> configTags) {
     configurationTags = configTags;
-  }  
+  }
 
   /**
-   * @return the configuration tags 
+   * @return the configuration tags
    */
   public Map<String, Map<String, String>> getConfigurationTags() {
     return configurationTags;
   }
-  
+
   /**
    * @return the passive info for the cluster
    */
   public Set<Map<String, String>> getPassiveInfo() {
     return passiveInfo;
   }
-  
+
   /**
    * @param info the passive info for the cluster
    */
@@ -252,7 +280,6 @@ public class ExecutionCommand extends AgentCommand {
    * incapsulated inside command.
    */
   public static interface KeyNames {
-
     String COMMAND_TIMEOUT = "command_timeout";
     String SCRIPT = "script";
     String SCRIPT_TYPE = "script_type";
@@ -269,6 +296,7 @@ public class ExecutionCommand extends AgentCommand {
     String MYSQL_JDBC_URL = "mysql_jdbc_url";
     String ORACLE_JDBC_URL = "oracle_jdbc_url";
     String DB_DRIVER_FILENAME = "db_driver_filename";
+    String CLIENTS_TO_UPDATE_CONFIGS = "clientsToUpdateConfigs";
     String REPO_INFO = "repo_info";
     String DB_NAME = "db_name";
     String GLOBAL = "global";
@@ -277,10 +305,12 @@ public class ExecutionCommand extends AgentCommand {
     String AMBARI_DB_RCA_USERNAME = "ambari_db_rca_username";
     String AMBARI_DB_RCA_PASSWORD = "ambari_db_rca_password";
     String COMPONENT_CATEGORY = "component_category";
+    String REFRESH_ADITIONAL_COMPONENT_TAGS = "forceRefreshConfigTags";
+    String USER_LIST = "user_list";
+    String GROUP_LIST = "group_list";
 
     String SERVICE_CHECK = "SERVICE_CHECK"; // TODO: is it standart command? maybe add it to RoleCommand enum?
     String CUSTOM_COMMAND = "custom_command";
-
   }
 
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeat.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeat.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeat.java
index 80cad4e..f41027b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeat.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeat.java
@@ -21,6 +21,7 @@ package org.apache.ambari.server.agent;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.ambari.server.state.Alert;
 import org.codehaus.jackson.annotate.JsonProperty;
 
 /**
@@ -39,6 +40,7 @@ public class HeartBeat {
   private List<DiskInfo> mounts = new ArrayList<DiskInfo>();
   HostStatus nodeStatus;
   private AgentEnv agentEnv = null;
+  private List<Alert> alerts = null;
 
   public long getResponseId() {
     return responseId;
@@ -110,6 +112,10 @@ public class HeartBeat {
     this.mounts = mounts;
   }
 
+  public List<Alert> getAlerts() {
+    return alerts;
+  }
+
   @Override
   public String toString() {
     return "HeartBeat{" +

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
index cdaf947..7d1fe6e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
@@ -18,7 +18,9 @@
 package org.apache.ambari.server.agent;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -32,9 +34,14 @@ import org.apache.ambari.server.ServiceComponentHostNotFoundException;
 import org.apache.ambari.server.ServiceComponentNotFoundException;
 import org.apache.ambari.server.ServiceNotFoundException;
 import org.apache.ambari.server.actionmanager.ActionManager;
+import org.apache.ambari.server.actionmanager.HostRoleCommand;
+import org.apache.ambari.server.actionmanager.HostRoleStatus;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.controller.MaintenanceStateHelper;
+import org.apache.ambari.server.events.AlertEvent;
+import org.apache.ambari.server.events.AlertReceivedEvent;
+import org.apache.ambari.server.events.publishers.AlertEventPublisher;
 import org.apache.ambari.server.metadata.ActionMetadata;
 import org.apache.ambari.server.state.AgentVersion;
 import org.apache.ambari.server.state.Alert;
@@ -54,6 +61,8 @@ import org.apache.ambari.server.state.ServiceInfo;
 import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.StackInfo;
 import org.apache.ambari.server.state.State;
+import org.apache.ambari.server.state.alert.AlertDefinition;
+import org.apache.ambari.server.state.alert.AlertDefinitionHash;
 import org.apache.ambari.server.state.fsm.InvalidStateTransitionException;
 import org.apache.ambari.server.state.host.HostHealthyHeartbeatEvent;
 import org.apache.ambari.server.state.host.HostRegistrationRequestEvent;
@@ -86,29 +95,46 @@ public class HeartBeatHandler {
   private final Clusters clusterFsm;
   private final ActionQueue actionQueue;
   private final ActionManager actionManager;
+  private HeartbeatMonitor heartbeatMonitor;
+
   @Inject
-  Injector injector;
+  private Injector injector;
+
   @Inject
-  Configuration config;
+  private Configuration config;
+
   @Inject
-  AmbariMetaInfo ambariMetaInfo;
+  private AmbariMetaInfo ambariMetaInfo;
+
   @Inject
-  ActionMetadata actionMetadata;
-  private HeartbeatMonitor heartbeatMonitor;
+  private ActionMetadata actionMetadata;
+
   @Inject
   private Gson gson;
+
+  @Inject
+  private ConfigHelper configHelper;
+
   @Inject
-  ConfigHelper configHelper;
+  private AlertDefinitionHash alertDefinitionHash;
+
+  /**
+   * Publishes {@link AlertEvent} instances.
+   */
+  @Inject
+  private AlertEventPublisher alertEventPublisher;
+
   private Map<String, Long> hostResponseIds = new ConcurrentHashMap<String, Long>();
+
   private Map<String, HeartBeatResponse> hostResponses = new ConcurrentHashMap<String, HeartBeatResponse>();
 
   @Inject
   public HeartBeatHandler(Clusters fsm, ActionQueue aq, ActionManager am,
                           Injector injector) {
-    this.clusterFsm = fsm;
-    this.actionQueue = aq;
-    this.actionManager = am;
-    this.heartbeatMonitor = new HeartbeatMonitor(fsm, aq, am, 60000, injector);
+    clusterFsm = fsm;
+    actionQueue = aq;
+    actionManager = am;
+    heartbeatMonitor = new HeartbeatMonitor(fsm, aq, am, 60000, injector);
     injector.injectMembers(this);
   }
 
@@ -126,14 +152,17 @@ public class HeartBeatHandler {
     if(heartbeat.getAgentEnv() != null && heartbeat.getAgentEnv().getHostHealth() != null) {
       heartbeat.getAgentEnv().getHostHealth().setServerTimeStampAtReporting(now);
     }
+
     String hostname = heartbeat.getHostname();
     Long currentResponseId = hostResponseIds.get(hostname);
     HeartBeatResponse response;
+
     if (currentResponseId == null) {
       //Server restarted, or unknown host.
       LOG.error("CurrentResponseId unknown for " + hostname + " - send register command");
       return createRegisterCommand();
     }
+
     LOG.debug("Received heartbeat from host"
         + ", hostname=" + hostname
         + ", currentResponseId=" + currentResponseId
@@ -191,19 +220,45 @@ public class HeartBeatHandler {
 
     // Examine heartbeart for component live status reports
     processStatusReports(heartbeat, hostname, clusterFsm);
-    
+
     // Calculate host status
     // NOTE: This step must be after processing command/status reports
     processHostStatus(heartbeat, hostname);
 
+    calculateHostAlerts(heartbeat, hostname);
+
     // Send commands if node is active
     if (hostObject.getState().equals(HostState.HEALTHY)) {
       sendCommands(hostname, response);
       annotateResponse(hostname, response);
-    }    
+    }
+
     return response;
   }
 
+  protected void calculateHostAlerts(HeartBeat heartbeat, String hostname)
+          throws AmbariException {
+    if (null == hostname || null == heartbeat) {
+      return;
+    }
+
+    if (null != heartbeat.getAlerts()) {
+      for (Alert alert : heartbeat.getAlerts()) {
+        if (null == alert.getHost()) {
+          alert.setHost(hostname);
+        }
+
+        Cluster cluster = clusterFsm.getCluster(alert.getCluster());
+        AlertEvent event = new AlertReceivedEvent(cluster.getClusterId(), alert);
+        alertEventPublisher.publish(event);
+      }
+    }
+
+    for (Cluster cluster : clusterFsm.getClustersForHost(hostname)) {
+      cluster.addAlerts(heartbeat.getNodeStatus().getAlerts());
+    }
+  }
+
   protected void processHostStatus(HeartBeat heartbeat, String hostname) throws AmbariException {
 
     Host host = clusterFsm.getHost(hostname);
@@ -253,7 +308,7 @@ public class HeartBeatHandler {
         StackId stackId;
         Cluster cluster = clusterFsm.getCluster(clusterName);
         stackId = cluster.getDesiredStackVersion();
-        
+
         MaintenanceStateHelper psh = injector.getInstance(MaintenanceStateHelper.class);
 
         List<ServiceComponentHost> scHosts = cluster.getServiceComponentHosts(heartbeat.getHostname());
@@ -307,8 +362,23 @@ public class HeartBeatHandler {
       HeartBeat heartbeat, String hostname, Clusters clusterFsm, long now)
       throws AmbariException {
     List<CommandReport> reports = heartbeat.getReports();
+
+    // Cache HostRoleCommand entities because we will need them few times
+    List<Long> taskIds = new ArrayList<Long>();
+    for (CommandReport report : reports) {
+      taskIds.add(report.getTaskId());
+    }
+    Collection<HostRoleCommand> commands = actionManager.getTasks(taskIds);
+
+    Iterator<HostRoleCommand> hostRoleCommandIterator = commands.iterator();
     for (CommandReport report : reports) {
       LOG.debug("Received command report: " + report);
+      // Fetch HostRoleCommand that corresponds to a given task ID
+      HostRoleCommand hostRoleCommand = hostRoleCommandIterator.next();
+      // Skip sending events for command reports for ABORTed commands
+      if (hostRoleCommand.getStatus() == HostRoleStatus.ABORTED) {
+        continue;
+      }
       //pass custom STAR, STOP and RESTART
       if (RoleCommand.ACTIONEXECUTE.toString().equals(report.getRoleCommand()) ||
          (RoleCommand.CUSTOM_COMMAND.toString().equals(report.getRoleCommand()) &&
@@ -317,7 +387,7 @@ public class HeartBeatHandler {
          "STOP".equals(report.getCustomCommand())))) {
         continue;
       }
-      
+
       Cluster cl = clusterFsm.getCluster(report.getClusterName());
       String service = report.getServiceName();
       if (service == null || service.isEmpty()) {
@@ -396,7 +466,7 @@ public class HeartBeatHandler {
       }
     }
     //Update state machines from reports
-    actionManager.processTaskResponse(hostname, reports);
+    actionManager.processTaskResponse(hostname, reports, commands);
   }
 
   protected void processStatusReports(HeartBeat heartbeat,
@@ -409,7 +479,7 @@ public class HeartBeatHandler {
         if (status.getClusterName().equals(cl.getClusterName())) {
           try {
             Service svc = cl.getService(status.getServiceName());
-            
+
             String componentName = status.getComponentName();
             if (svc.getServiceComponents().containsKey(componentName)) {
               ServiceComponent svcComp = svc.getServiceComponent(
@@ -440,7 +510,7 @@ public class HeartBeatHandler {
               if (null != status.getConfigTags()) {
                 scHost.updateActualConfigs(status.getConfigTags());
               }
-              
+
               Map<String, Object> extra = status.getExtra();
               if (null != extra && !extra.isEmpty()) {
                 try {
@@ -449,7 +519,7 @@ public class HeartBeatHandler {
                     List<Map<String, String>> list = (List<Map<String, String>>) extra.get("processes");
                     scHost.setProcesses(list);
                   }
-                  
+
                 } catch (Exception e) {
                   LOG.error("Could not access extra JSON for " +
                       scHost.getServiceComponentName() + " from " +
@@ -457,7 +527,7 @@ public class HeartBeatHandler {
                       " (" + e.getMessage() + ")");
                 }
               }
-              
+
               if (null != status.getAlerts()) {
                 List<Alert> clusterAlerts = new ArrayList<Alert>();
                 for (AgentAlert aa : status.getAlerts()) {
@@ -466,14 +536,15 @@ public class HeartBeatHandler {
                       scHost.getHostName(), aa.getState());
                   alert.setLabel(aa.getLabel());
                   alert.setText(aa.getText());
-                  
+
                   clusterAlerts.add(alert);
                 }
-                
-               if (0 != clusterAlerts.size())
-                 cl.addAlerts(clusterAlerts);
+
+               if (0 != clusterAlerts.size()) {
+                cl.addAlerts(clusterAlerts);
+              }
               }
-              
+
 
             } else {
               // TODO: What should be done otherwise?
@@ -533,6 +604,7 @@ public class HeartBeatHandler {
           throw new AmbariException("Could not get jaxb string for command", e);
         }
         switch (ac.getCommandType()) {
+          case BACKGROUND_EXECUTION_COMMAND:
           case EXECUTION_COMMAND: {
             response.addExecutionCommand((ExecutionCommand) ac);
             break;
@@ -541,9 +613,21 @@ public class HeartBeatHandler {
             response.addStatusCommand((StatusCommand) ac);
             break;
           }
+          case CANCEL_COMMAND: {
+            response.addCancelCommand((CancelCommand) ac);
+            break;
+          }
+          case ALERT_DEFINITION_COMMAND: {
+            response.addAlertDefinitionCommand((AlertDefinitionCommand) ac);
+            break;
+          }
+          case ALERT_EXECUTION_COMMAND: {
+            response.addAlertExecutionCommand((AlertExecutionCommand) ac);
+            break;
+          }
           default:
-            LOG.error("There is no action for agent command =" +
-                ac.getCommandType().name());
+            LOG.error("There is no action for agent command ="
+                + ac.getCommandType().name());
         }
       }
     }
@@ -601,6 +685,7 @@ public class HeartBeatHandler {
 
     String agentOsType = getOsType(register.getHardwareProfile().getOS(),
         register.getHardwareProfile().getOSRelease());
+    LOG.info("agentOsType = "+agentOsType );
     if (!ambariMetaInfo.isOsSupported(agentOsType)) {
       LOG.warn("Received registration request from host with not supported"
           + " os type"
@@ -621,6 +706,7 @@ public class HeartBeatHandler {
       clusterFsm.addHost(hostname);
       hostObject = clusterFsm.getHost(hostname);
     }
+
     // Resetting host state
     hostObject.setState(HostState.INIT);
 
@@ -630,10 +716,14 @@ public class HeartBeatHandler {
     // Get status of service components
     List<StatusCommand> cmds = heartbeatMonitor.generateStatusCommands(hostname);
 
+    // Save the prefix of the log file paths
+    hostObject.setPrefix(register.getPrefix());
+
     hostObject.handleEvent(new HostRegistrationRequestEvent(hostname,
         null != register.getPublicHostname() ? register.getPublicHostname() : hostname,
         new AgentVersion(register.getAgentVersion()), now, register.getHardwareProfile(),
         register.getAgentEnv()));
+
     RegistrationResponse response = new RegistrationResponse();
     if (cmds.isEmpty()) {
       //No status commands needed let the fsm know that status step is done
@@ -647,6 +737,10 @@ public class HeartBeatHandler {
 
     response.setResponseStatus(RegistrationStatus.OK);
 
+    // force the registering agent host to receive its list of alert definitions
+    List<AlertDefinitionCommand> alertDefinitionCommands = getRegistrationAlertDefinitionCommands(hostname);
+    response.setAlertDefinitionCommands(alertDefinitionCommands);
+
     Long requestId = 0L;
     hostResponseIds.put(hostname, requestId);
     response.setResponseId(requestId);
@@ -661,7 +755,7 @@ public class HeartBeatHandler {
    * @throws org.apache.ambari.server.AmbariException
    */
   private void annotateResponse(String hostname, HeartBeatResponse response) throws AmbariException {
-    for (Cluster cl : this.clusterFsm.getClustersForHost(hostname)) {
+    for (Cluster cl : clusterFsm.getClustersForHost(hostname)) {
       List<ServiceComponentHost> scHosts = cl.getServiceComponentHosts(hostname);
       if (scHosts != null && scHosts.size() > 0) {
         response.setHasMappedComponents(true);
@@ -680,19 +774,19 @@ public class HeartBeatHandler {
       throws AmbariException {
     ComponentsResponse response = new ComponentsResponse();
 
-    Cluster cluster = this.clusterFsm.getCluster(clusterName);
+    Cluster cluster = clusterFsm.getCluster(clusterName);
     StackId stackId = cluster.getCurrentStackVersion();
     if (stackId == null) {
       throw new AmbariException("Cannot provide stack components map. " +
         "Stack hasn't been selected yet.");
     }
-    StackInfo stack = this.ambariMetaInfo.getStackInfo(stackId.getStackName(),
+    StackInfo stack = ambariMetaInfo.getStackInfo(stackId.getStackName(),
         stackId.getStackVersion());
 
     response.setClusterName(clusterName);
     response.setStackName(stackId.getStackName());
     response.setStackVersion(stackId.getStackVersion());
-    response.setComponents(this.getComponentsMap(stack));
+    response.setComponents(getComponentsMap(stack));
 
     return response;
   }
@@ -712,4 +806,41 @@ public class HeartBeatHandler {
 
     return result;
   }
+
+  /**
+   * Gets the {@link AlertDefinitionCommand} instances that need to be sent for
+   * each cluster that the registering host is a member of.
+   *
+   * @param hostname
+   * @return
+   * @throws AmbariException
+   */
+  private List<AlertDefinitionCommand> getRegistrationAlertDefinitionCommands(
+      String hostname) throws AmbariException {
+
+    Set<Cluster> hostClusters = clusterFsm.getClustersForHost(hostname);
+    if (null == hostClusters || hostClusters.size() == 0) {
+      return null;
+    }
+
+    List<AlertDefinitionCommand> commands = new ArrayList<AlertDefinitionCommand>();
+
+    // for every cluster this host is a member of, build the command
+    for (Cluster cluster : hostClusters) {
+      String clusterName = cluster.getClusterName();
+      alertDefinitionHash.invalidate(clusterName, hostname);
+
+      List<AlertDefinition> definitions = alertDefinitionHash.getAlertDefinitions(
+          clusterName, hostname);
+
+      String hash = alertDefinitionHash.getHash(clusterName, hostname);
+      AlertDefinitionCommand command = new AlertDefinitionCommand(clusterName,
+          hostname, hash, definitions);
+
+      command.addConfigs(configHelper, cluster);
+      commands.add(command);
+    }
+
+    return commands;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatResponse.java
index 67a4815..56b4f18 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatResponse.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatResponse.java
@@ -21,81 +21,125 @@ package org.apache.ambari.server.agent;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.codehaus.jackson.annotate.JsonProperty;
+import com.google.gson.annotations.SerializedName;
 
 /**
- *
  * Controller to Agent response data model.
- *
  */
 public class HeartBeatResponse {
 
+  @SerializedName("responseId")
   private long responseId;
- 
-  List<ExecutionCommand> executionCommands = new ArrayList<ExecutionCommand>();
-  List<StatusCommand> statusCommands = new ArrayList<StatusCommand>();
 
-  RegistrationCommand registrationCommand;
+  @SerializedName("executionCommands")
+  private List<ExecutionCommand> executionCommands = new ArrayList<ExecutionCommand>();
+
+  @SerializedName("statusCommands")
+  private List<StatusCommand> statusCommands = new ArrayList<StatusCommand>();
+
+  @SerializedName("cancelCommands")
+  private List<CancelCommand> cancelCommands = new ArrayList<CancelCommand>();
+
+  /**
+   * {@link AlertDefinitionCommand}s are used to isntruct the agent as to which
+   * alert definitions it needs to schedule. A {@code null} value here indicates
+   * that no data is to be sent and no change is required on the agent. This is
+   * different from sending an empty list where the empty list would instruct
+   * the agent to abandon all alert definitions that are scheduled.
+   */
+  @SerializedName("alertDefinitionCommands")
+  private List<AlertDefinitionCommand> alertDefinitionCommands = null;
+
+  /**
+   * {@link AlertExecutionCommand}s are used to execute an alert job
+   * immediately.
+   */
+  @SerializedName("alertExecutionCommands")
+  private List<AlertExecutionCommand> alertExecutionCommands = null;
 
-  boolean restartAgent = false;
-  boolean hasMappedComponents = false;
+  @SerializedName("registrationCommand")
+  private RegistrationCommand registrationCommand;
+
+  @SerializedName("restartAgent")
+  private boolean restartAgent = false;
+
+  @SerializedName("hasMappedComponents")
+  private boolean hasMappedComponents = false;
 
-  @JsonProperty("responseId")
   public long getResponseId() {
     return responseId;
   }
 
-  @JsonProperty("responseId")
   public void setResponseId(long responseId) {
     this.responseId=responseId;
   }
 
-  @JsonProperty("executionCommands")
   public List<ExecutionCommand> getExecutionCommands() {
     return executionCommands;
   }
 
-  @JsonProperty("executionCommands")
   public void setExecutionCommands(List<ExecutionCommand> executionCommands) {
     this.executionCommands = executionCommands;
   }
 
-  @JsonProperty("statusCommands")
   public List<StatusCommand> getStatusCommands() {
     return statusCommands;
   }
 
-  @JsonProperty("statusCommands")
   public void setStatusCommands(List<StatusCommand> statusCommands) {
     this.statusCommands = statusCommands;
   }
 
-  @JsonProperty("registrationCommand")
+  public List<CancelCommand> getCancelCommands() {
+    return cancelCommands;
+  }
+
+  public void setCancelCommands(List<CancelCommand> cancelCommands) {
+    this.cancelCommands = cancelCommands;
+  }
+
   public RegistrationCommand getRegistrationCommand() {
     return registrationCommand;
   }
 
-  @JsonProperty("registrationCommand")
   public void setRegistrationCommand(RegistrationCommand registrationCommand) {
     this.registrationCommand = registrationCommand;
   }
 
-  @JsonProperty("restartAgent")
+  /**
+   * Gets the alert definition commands that contain the alert definitions for
+   * each cluster that the host is a member of.
+   *
+   * @param commands
+   *          the commands, or {@code null} for none.
+   */
+  public List<AlertDefinitionCommand> getAlertDefinitionCommands() {
+    return alertDefinitionCommands;
+  }
+
+  /**
+   * Sets the alert definition commands that contain the alert definitions for
+   * each cluster that the host is a member of.
+   *
+   * @param commands
+   *          the commands, or {@code null} for none.
+   */
+  public void setAlertDefinitionCommands(List<AlertDefinitionCommand> commands) {
+    alertDefinitionCommands = commands;
+  }
+
   public boolean isRestartAgent() {
     return restartAgent;
   }
 
-  @JsonProperty("restartAgent")
   public void setRestartAgent(boolean restartAgent) {
     this.restartAgent = restartAgent;
   }
 
-  @JsonProperty("hasMappedComponents")
   public boolean hasMappedComponents() {
     return hasMappedComponents;
   }
 
-  @JsonProperty("hasMappedComponents")
   public void setHasMappedComponents(boolean hasMappedComponents) {
     this.hasMappedComponents = hasMappedComponents;
   }
@@ -108,14 +152,41 @@ public class HeartBeatResponse {
     statusCommands.add(statCmd);
   }
 
+  public void addCancelCommand(CancelCommand cancelCmd) {
+    cancelCommands.add(cancelCmd);
+  }
+
+  public void addAlertDefinitionCommand(AlertDefinitionCommand command) {
+    // commands are added here when they are taken off the queue; there should
+    // be no thread contention and thus no worry about locks for the null check
+    if (null == alertDefinitionCommands) {
+      alertDefinitionCommands = new ArrayList<AlertDefinitionCommand>();
+    }
+
+    alertDefinitionCommands.add(command);
+  }
+
+  public void addAlertExecutionCommand(AlertExecutionCommand command) {
+    // commands are added here when they are taken off the queue; there should
+    // be no thread contention and thus no worry about locks for the null check
+    if (null == alertExecutionCommands) {
+      alertExecutionCommands = new ArrayList<AlertExecutionCommand>();
+    }
+
+    alertExecutionCommands.add(command);
+  }
+
   @Override
   public String toString() {
-    return "HeartBeatResponse{" +
-            "responseId=" + responseId +
-            ", executionCommands=" + executionCommands +
-            ", statusCommands=" + statusCommands +
-            ", registrationCommand=" + registrationCommand +
-            ", restartAgent=" + restartAgent +
-            '}';
+    StringBuilder buffer = new StringBuilder("HeartBeatResponse{");
+    buffer.append("responseId=").append(responseId);
+    buffer.append(", executionCommands=").append(executionCommands);
+    buffer.append(", statusCommands=").append(statusCommands);
+    buffer.append(", cancelCommands=").append(cancelCommands);
+    buffer.append(", alertDefinitionCommands=").append(alertDefinitionCommands);
+    buffer.append(", registrationCommand=").append(registrationCommand);
+    buffer.append(", restartAgent=").append(restartAgent);
+    buffer.append('}');
+    return buffer.toString();
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatMonitor.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatMonitor.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatMonitor.java
index 8b8b252..c39ba29 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatMonitor.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatMonitor.java
@@ -18,7 +18,6 @@
 package org.apache.ambari.server.agent;
 
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.COMMAND_TIMEOUT;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.GLOBAL;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.HOOKS_FOLDER;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.JDK_LOCATION;
 import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SCRIPT;
@@ -30,6 +29,7 @@ import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.STACK_VER
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.TreeMap;
@@ -39,7 +39,6 @@ import org.apache.ambari.server.actionmanager.ActionManager;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.controller.AmbariManagementController;
-import org.apache.ambari.server.controller.MaintenanceStateHelper;
 import org.apache.ambari.server.state.Alert;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
@@ -82,14 +81,14 @@ public class HeartbeatMonitor implements Runnable {
   public HeartbeatMonitor(Clusters clusters, ActionQueue aq, ActionManager am,
                           int threadWakeupInterval, Injector injector) {
     this.clusters = clusters;
-    this.actionQueue = aq;
-    this.actionManager = am;
+    actionQueue = aq;
+    actionManager = am;
     this.threadWakeupInterval = threadWakeupInterval;
-    this.configHelper = injector.getInstance(ConfigHelper.class);
-    this.ambariMetaInfo = injector.getInstance(AmbariMetaInfo.class);
-    this.ambariManagementController = injector.getInstance(
+    configHelper = injector.getInstance(ConfigHelper.class);
+    ambariMetaInfo = injector.getInstance(AmbariMetaInfo.class);
+    ambariManagementController = injector.getInstance(
             AmbariManagementController.class);
-    this.configuration = injector.getInstance(Configuration.class);
+    configuration = injector.getInstance(Configuration.class);
   }
 
   public void shutdown() {
@@ -219,7 +218,6 @@ public class HeartbeatMonitor implements Runnable {
     return cmds;
   }
 
-
   /**
    * Generates status command and fills all apropriate fields.
    * @throws AmbariException
@@ -239,44 +237,55 @@ public class HeartbeatMonitor implements Runnable {
             stackId.getStackVersion());
 
     Map<String, Map<String, String>> configurations = new TreeMap<String, Map<String, String>>();
+    Map<String, Map<String,  Map<String, String>>> configurationAttributes = new TreeMap<String, Map<String, Map<String, String>>>();
 
     // get the cluster config for type '*-env'
     // apply config group overrides
-
     //Config clusterConfig = cluster.getDesiredConfigByType(GLOBAL);
     Collection<Config> clusterConfigs = cluster.getAllConfigs();
-    
+
     for(Config clusterConfig: clusterConfigs) {
-      if(!clusterConfig.getType().endsWith("-env"))
+      if(!clusterConfig.getType().endsWith("-env")) {
         continue;
-    
+      }
+
       if (clusterConfig != null) {
         // cluster config for 'global'
         Map<String, String> props = new HashMap<String, String>(clusterConfig.getProperties());
-  
+
         // Apply global properties for this host from all config groups
         Map<String, Map<String, String>> allConfigTags = configHelper
                 .getEffectiveDesiredTags(cluster, hostname);
-  
+
         Map<String, Map<String, String>> configTags = new HashMap<String,
                 Map<String, String>>();
-  
+
         for (Map.Entry<String, Map<String, String>> entry : allConfigTags.entrySet()) {
           if (entry.getKey().equals(clusterConfig.getType())) {
             configTags.put(clusterConfig.getType(), entry.getValue());
           }
         }
-  
+
         Map<String, Map<String, String>> properties = configHelper
                 .getEffectiveConfigProperties(cluster, configTags);
-  
+
         if (!properties.isEmpty()) {
           for (Map<String, String> propertyMap : properties.values()) {
             props.putAll(propertyMap);
           }
         }
-  
+
         configurations.put(clusterConfig.getType(), props);
+
+        Map<String, Map<String, String>> attrs = new TreeMap<String, Map<String, String>>();
+        configHelper.cloneAttributesMap(clusterConfig.getPropertiesAttributes(), attrs);
+
+        Map<String, Map<String, Map<String, String>>> attributes = configHelper
+            .getEffectiveConfigAttributes(cluster, configTags);
+        for (Map<String, Map<String, String>> attributesMap : attributes.values()) {
+          configHelper.cloneAttributesMap(attributesMap, attrs);
+        }
+        configurationAttributes.put(clusterConfig.getType(), attrs);
       }
     }
 
@@ -284,8 +293,14 @@ public class HeartbeatMonitor implements Runnable {
     if (sch.getServiceComponentName().equals("NAGIOS_SERVER")) {
       // this requires special treatment
 
-      Collection<Alert> alerts = cluster.getAlerts();
-      if (null != alerts && alerts.size() > 0) {
+      Collection<Alert> clusterAlerts = cluster.getAlerts();
+      Collection<Alert> alerts = new HashSet<Alert>();
+      for (Alert alert : clusterAlerts) {
+        if (!alert.getName().equals("host_alert")) {
+          alerts.add(alert);
+        }
+      }
+      if (alerts.size() > 0) {
         statusCmd = new NagiosAlertCommand();
         ((NagiosAlertCommand) statusCmd).setAlerts(alerts);
       }
@@ -295,6 +310,8 @@ public class HeartbeatMonitor implements Runnable {
     statusCmd.setServiceName(serviceName);
     statusCmd.setComponentName(componentName);
     statusCmd.setConfigurations(configurations);
+    statusCmd.setConfigurationAttributes(configurationAttributes);
+    statusCmd.setHostname(hostname);
 
     // Fill command params
     Map<String, String> commandParams = statusCmd.getCommandParams();

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/agent/HostStatus.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/HostStatus.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/HostStatus.java
index d609ecd..e9ff821 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/HostStatus.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/HostStatus.java
@@ -17,6 +17,10 @@
  */
 package org.apache.ambari.server.agent;
 
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.ambari.server.state.Alert;
+import org.codehaus.jackson.annotate.JsonProperty;
 
 /**
  * Status of the host as described by the agent.
@@ -38,24 +42,43 @@ public class HostStatus {
   }
   Status status;
   String cause;
+  List<Alert> alerts = new ArrayList<Alert>();
+
+  @JsonProperty("status")
   public Status getStatus() {
     return status;
   }
+
+  @JsonProperty("status")
   public void setStatus(Status status) {
     this.status = status;
   }
+
+  @JsonProperty("cause")
   public String getCause() {
     return cause;
   }
+
+  @JsonProperty("cause")
   public void setCause(String cause) {
     this.cause = cause;
   }
 
+  @JsonProperty("alerts")
+  public List<Alert> getAlerts() {
+    return alerts;
+  }
+
+  @JsonProperty("alerts")
+  public void setAlerts(List<Alert> alerts) {
+    this.alerts = alerts;
+  }
+
   @Override
   public String toString() {
     return "HostStatus{" +
             "status=" + status +
             ", cause='" + cause + '\'' +
-            '}';
+            ", alerts=" + alerts.size() + '}';
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/agent/NagiosAlertCommand.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/NagiosAlertCommand.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/NagiosAlertCommand.java
index f8e2f26..bdf9039 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/NagiosAlertCommand.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/NagiosAlertCommand.java
@@ -21,24 +21,27 @@ import java.util.Collection;
 
 import org.apache.ambari.server.state.Alert;
 
+import com.google.gson.annotations.SerializedName;
+
 /**
- * Specialized command that updates Nagios with alert data 
+ * Specialized command that updates Nagios with alert data
  */
 public class NagiosAlertCommand extends StatusCommand {
+  @SerializedName("alerts")
   private Collection<Alert> alerts = null;
-  
+
   /**
    * @param alerts
    */
   public void setAlerts(Collection<Alert> alertData) {
     alerts = alertData;
   }
-  
+
   /**
    * @return the alerts
    */
   public Collection<Alert> getAlerts() {
     return alerts;
   }
-  
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/agent/Register.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/Register.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/Register.java
index ec6f4f7..a571afd 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/Register.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/Register.java
@@ -34,6 +34,7 @@ public class Register {
   private String publicHostname;
   private AgentEnv agentEnv;
   private String agentVersion;
+  private String prefix;
 
   @JsonProperty("responseId")
   public int getResponseId() {
@@ -89,6 +90,10 @@ public class Register {
     return agentVersion;
   }
 
+  public String getPrefix() { return prefix; }
+
+  public void setPrefix(String prefix) { this.prefix = prefix; }
+
   public void setAgentVersion(String agentVersion) {
     this.agentVersion = agentVersion;
   }
@@ -106,7 +111,8 @@ public class Register {
     String ret = "responseId=" + responseId + "\n" +
              "timestamp=" + timestamp + "\n" +
              "hostname="  + hostname + "\n" +
-             "currentPingPort=" + currentPingPort + "\n";
+             "currentPingPort=" + currentPingPort + "\n" +
+             "prefix=" + prefix + "\n";
 
     if (hardwareProfile != null)
       ret = ret + "hardwareprofile=" + this.hardwareProfile.toString();

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/agent/RegistrationResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/RegistrationResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/RegistrationResponse.java
index dae80bb..8a24560 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/RegistrationResponse.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/RegistrationResponse.java
@@ -18,6 +18,7 @@
 
 package org.apache.ambari.server.agent;
 
+import java.util.ArrayList;
 import java.util.List;
 
 import org.codehaus.jackson.annotate.JsonProperty;
@@ -32,6 +33,13 @@ public class RegistrationResponse {
   private RegistrationStatus response;
 
   /**
+   * {@link AlertDefinitionCommand}s are used to isntruct the agent as to which
+   * alert definitions it needs to schedule.
+   */
+  @JsonProperty("alertDefinitionCommands")
+  private List<AlertDefinitionCommand> alertDefinitionCommands = new ArrayList<AlertDefinitionCommand>();
+
+  /**
    * exitstatus is a code of error which was rised on server side.
    * exitstatus = 0 (OK - Default)
    * exitstatus = 1 (Registration failed because
@@ -44,12 +52,12 @@ public class RegistrationResponse {
    * log - message, which will be printed to agents  log
    */
   @JsonProperty("log")
-  private String log;  
-  
+  private String log;
+
   //Response id to start with, usually zero.
   @JsonProperty("responseId")
   private long responseId;
-  
+
   @JsonProperty("statusCommands")
   private List<StatusCommand> statusCommands = null;
 
@@ -69,6 +77,28 @@ public class RegistrationResponse {
     this.statusCommands = statusCommands;
   }
 
+  /**
+   * Gets the alert definition commands that contain the alert definitions for
+   * each cluster that the host is a member of.
+   *
+   * @param commands
+   *          the commands, or {@code null} for none.
+   */
+  public List<AlertDefinitionCommand> getAlertDefinitionCommands() {
+    return alertDefinitionCommands;
+  }
+
+  /**
+   * Sets the alert definition commands that contain the alert definitions for
+   * each cluster that the host is a member of.
+   *
+   * @param commands
+   *          the commands, or {@code null} for none.
+   */
+  public void setAlertDefinitionCommands(List<AlertDefinitionCommand> commands) {
+    alertDefinitionCommands = commands;
+  }
+
   public long getResponseId() {
     return responseId;
   }
@@ -84,13 +114,15 @@ public class RegistrationResponse {
   public void setLog(String log) {
     this.log = log;
   }
- 
+
   @Override
   public String toString() {
-    return "RegistrationResponse{" +
-            "response=" + response +
-            ", responseId=" + responseId +
-            ", statusCommands=" + statusCommands +
-            '}';
+    StringBuilder buffer = new StringBuilder("RegistrationResponse{");
+    buffer.append("response=").append(response);
+    buffer.append(", responseId=").append(responseId);
+    buffer.append(", statusCommands=").append(statusCommands);
+    buffer.append(", alertDefinitionCommands=").append(alertDefinitionCommands);
+    buffer.append('}');
+    return buffer.toString();
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/agent/StatusCommand.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/StatusCommand.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/StatusCommand.java
index e7a46ff..6e08ef0 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/StatusCommand.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/StatusCommand.java
@@ -18,10 +18,9 @@
 package org.apache.ambari.server.agent;
 
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
-import org.codehaus.jackson.annotate.JsonProperty;
+import com.google.gson.annotations.SerializedName;
 
 /**
  * Command to report the status of a list of services in roles.
@@ -32,71 +31,91 @@ public class StatusCommand extends AgentCommand {
     super(AgentCommandType.STATUS_COMMAND);
   }
 
+  @SerializedName("clusterName")
   private String clusterName;
+
+  @SerializedName("serviceName")
   private String serviceName;
+
+  @SerializedName("componentName")
   private String componentName;
+
+  @SerializedName("configurations")
   private Map<String, Map<String, String>> configurations;
+
+  @SerializedName("configuration_attributes")
+  private Map<String, Map<String, Map<String, String>>> configurationAttributes;
+
+  @SerializedName("commandParams")
   private Map<String, String> commandParams = new HashMap<String, String>();
+
+  @SerializedName("hostLevelParams")
   private Map<String, String> hostLevelParams = new HashMap<String, String>();
 
-  @JsonProperty("clusterName")
+  @SerializedName("hostname")
+  private String hostname = null;
+
   public String getClusterName() {
     return clusterName;
   }
-  
-  @JsonProperty("clusterName")
+
   public void setClusterName(String clusterName) {
     this.clusterName = clusterName;
   }
 
-  @JsonProperty("serviceName")
   public String getServiceName() {
     return serviceName;
   }
 
-  @JsonProperty("serviceName")
   public void setServiceName(String serviceName) {
     this.serviceName = serviceName;
   }
 
-  @JsonProperty("componentName")
   public String getComponentName() {
     return componentName;
   }
 
-  @JsonProperty("componentName")
   public void setComponentName(String componentName) {
     this.componentName = componentName;
   }
-  
-  @JsonProperty("configurations")
+
   public Map<String, Map<String, String>> getConfigurations() {
     return configurations;
   }
 
-  @JsonProperty("configurations")
   public void setConfigurations(Map<String, Map<String, String>> configurations) {
     this.configurations = configurations;
   }
 
-  @JsonProperty("hostLevelParams")
+  public Map<String, Map<String, Map<String, String>>> getConfigurationAttributes() {
+    return configurationAttributes;
+  }
+
+  public void setConfigurationAttributes(Map<String, Map<String, Map<String, String>>> configurationAttributes) {
+    this.configurationAttributes = configurationAttributes;
+  }
+
   public Map<String, String> getHostLevelParams() {
     return hostLevelParams;
   }
 
-  @JsonProperty("hostLevelParams")
   public void setHostLevelParams(Map<String, String> params) {
-    this.hostLevelParams = params;
+    hostLevelParams = params;
   }
 
-  @JsonProperty("commandParams")
   public Map<String, String> getCommandParams() {
     return commandParams;
   }
 
-  @JsonProperty("commandParams")
   public void setCommandParams(Map<String, String> commandParams) {
     this.commandParams = commandParams;
   }
 
+  public void setHostname(String hostname) {
+    this.hostname = hostname;
+  }
+
+  public String getHostname() {
+    return hostname;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/api/AmbariPersistFilter.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/AmbariPersistFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/api/AmbariPersistFilter.java
index 971b8a0..a5ab041 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/AmbariPersistFilter.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/AmbariPersistFilter.java
@@ -19,7 +19,6 @@ package org.apache.ambari.server.api;
 
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
-import com.google.inject.persist.PersistService;
 import com.google.inject.persist.UnitOfWork;
 
 import javax.servlet.*;

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/api/handlers/CreateHandler.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/handlers/CreateHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/api/handlers/CreateHandler.java
index 91903d1..c1bd91b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/handlers/CreateHandler.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/handlers/CreateHandler.java
@@ -38,7 +38,11 @@ public class CreateHandler extends BaseManagementHandler {
       result = createResult(status);
 
       if (result.isSynchronous()) {
-        result.setResultStatus(new ResultStatus(ResultStatus.STATUS.CREATED));
+        if (resource.getResourceDefinition().isCreatable()) {
+          result.setResultStatus(new ResultStatus(ResultStatus.STATUS.CREATED));
+        } else {
+          result.setResultStatus(new ResultStatus(ResultStatus.STATUS.OK));
+        }
       } else {
         result.setResultStatus(new ResultStatus(ResultStatus.STATUS.ACCEPTED));
       }

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/api/handlers/DeleteHandler.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/handlers/DeleteHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/api/handlers/DeleteHandler.java
index f7d3425..55385a5 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/handlers/DeleteHandler.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/handlers/DeleteHandler.java
@@ -18,8 +18,13 @@
 
 package org.apache.ambari.server.api.handlers;
 
+import org.apache.ambari.server.ConfigGroupNotFoundException;
 import org.apache.ambari.server.api.resources.ResourceInstance;
-import org.apache.ambari.server.api.services.*;
+
+import org.apache.ambari.server.api.services.RequestBody;
+import org.apache.ambari.server.api.services.Result;
+import org.apache.ambari.server.api.services.ResultImpl;
+import org.apache.ambari.server.api.services.ResultStatus;
 import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
 import org.apache.ambari.server.controller.spi.NoSuchResourceException;
 import org.apache.ambari.server.controller.spi.RequestStatus;
@@ -54,6 +59,8 @@ public class DeleteHandler extends BaseManagementHandler implements RequestHandl
           //todo: 200 may be ok but we need to return a collection
           //todo: of resources that were updated.
           result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.OK, e));
+        } else if (e.getCause() instanceof ConfigGroupNotFoundException){
+          result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.ACCEPTED, e));
         } else {
           result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.NOT_FOUND, e));
         }

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/api/handlers/QueryCreateHandler.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/handlers/QueryCreateHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/api/handlers/QueryCreateHandler.java
index 040a1f1..1bc4a0f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/handlers/QueryCreateHandler.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/handlers/QueryCreateHandler.java
@@ -170,7 +170,11 @@ public class QueryCreateHandler extends BaseManagementHandler {
       result = createResult(status);
 
       if (result.isSynchronous()) {
-        result.setResultStatus(new ResultStatus(ResultStatus.STATUS.CREATED));
+        if (resource.getResourceDefinition().isCreatable()) {
+          result.setResultStatus(new ResultStatus(ResultStatus.STATUS.CREATED));
+        } else {
+          result.setResultStatus(new ResultStatus(ResultStatus.STATUS.OK));
+        }
       } else {
         result.setResultStatus(new ResultStatus(ResultStatus.STATUS.ACCEPTED));
       }

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/api/query/JpaPredicateVisitor.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/query/JpaPredicateVisitor.java b/ambari-server/src/main/java/org/apache/ambari/server/api/query/JpaPredicateVisitor.java
new file mode 100644
index 0000000..660bae7
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/query/JpaPredicateVisitor.java
@@ -0,0 +1,258 @@
+/**
+ * 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.ambari.server.api.query;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Path;
+import javax.persistence.criteria.Root;
+import javax.persistence.metamodel.SingularAttribute;
+
+import org.apache.ambari.server.controller.predicate.AlwaysPredicate;
+import org.apache.ambari.server.controller.predicate.ArrayPredicate;
+import org.apache.ambari.server.controller.predicate.CategoryPredicate;
+import org.apache.ambari.server.controller.predicate.ComparisonPredicate;
+import org.apache.ambari.server.controller.predicate.PredicateVisitor;
+import org.apache.ambari.server.controller.predicate.UnaryPredicate;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.utilities.PredicateHelper;
+
+/**
+ * The {@link JpaPredicateVisitor} is used to convert an Ambari
+ * {@link Predicate} into a JPA {@link javax.persistence.criteria.Predicate}.
+ */
+public abstract class JpaPredicateVisitor<T> implements PredicateVisitor {
+  /**
+   * JPA entity manager
+   */
+  private EntityManager m_entityManager;
+
+  /**
+   * Builds the {@link CriteriaQuery} from the {@link Predicate}.
+   */
+  private CriteriaBuilder m_builder;
+
+  /**
+   * The root that the {@code from} clause requests from.
+   */
+  private Root<T> m_root;
+
+  /**
+   * The query to submit to JPA.
+   */
+  private CriteriaQuery<T> m_query;
+
+  /**
+   * The last calculated predicate.
+   */
+  private javax.persistence.criteria.Predicate m_lastPredicate = null;
+
+  /**
+   * A queue of lists of {@link javax.persistence.criteria.Predicate}. Every
+   * time an {@code OR} or {@code AND} is encountered, a new chain (list) is
+   * created and the prior list is enqeued. When the logical statement is
+   * closed, the chain is completed and added to the prior chain's list.
+   */
+  private ArrayDeque<List<javax.persistence.criteria.Predicate>> m_queue =
+      new ArrayDeque<List<javax.persistence.criteria.Predicate>>();
+
+  /**
+   * Constructor.
+   *
+   * @param entityManager
+   *          the EM used to get a {@link CriteriaBuilder}.
+   * @param entityClass
+   *          the entity class being queried from.
+   */
+  public JpaPredicateVisitor(EntityManager entityManager, Class<T> entityClass) {
+    m_entityManager = entityManager;
+    m_builder = m_entityManager.getCriteriaBuilder();
+    m_query = m_builder.createQuery(entityClass);
+    m_root = m_query.from(entityClass);
+  }
+
+  /**
+   * Gets the entity class that is the root type in the JPA {@code from} clause.
+   *
+   * @return the entity class (not {@code null}).
+   */
+  public abstract Class<T> getEntityClass();
+
+  /**
+   * Gets the {@link SingularAttribute}s mapped to the specified Ambari-style
+   * property.
+   *
+   * @param propertyId
+   *          the Ambari-style property (not {@code null}).
+   * @return the {@link SingularAttribute}, or {@code null} if no mapping
+   *         exists.
+   */
+  public abstract List<? extends SingularAttribute<?, ?>> getPredicateMapping(
+      String propertyId);
+
+  /**
+   * Gets the final JPA {@link javax.persistence.criteria.Predicate} after the
+   * visitor is done traversing the Ambari {@link Predicate}.
+   *
+   * @return the predicate, or {@code null} if none.
+   */
+  public javax.persistence.criteria.Predicate getJpaPredicate() {
+    return m_lastPredicate;
+  }
+
+  /**
+   * Gets the query to use along with {@link #getJpaPredicate()}.
+   *
+   * @return the query (not {@code null}).
+   */
+  public CriteriaQuery<T> getCriteriaQuery() {
+    return m_query;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @SuppressWarnings({ "unchecked", "rawtypes" })
+  public void acceptComparisonPredicate(ComparisonPredicate predicate) {
+    String propertyId = predicate.getPropertyId();
+
+    List<? extends SingularAttribute<?, ?>> singularAttributes = getPredicateMapping(propertyId);
+
+    if (null == singularAttributes || singularAttributes.size() == 0) {
+      return;
+    }
+
+    SingularAttribute<?, ?> lastSingularAttribute = null;
+    Path<Comparable> path = null;
+
+    for (SingularAttribute<?, ?> singularAttribute : singularAttributes) {
+      lastSingularAttribute = singularAttribute;
+
+      if (null == path) {
+        path = m_root.get(singularAttribute.getName());
+      } else {
+        path = path.get(singularAttribute.getName());
+      }
+    }
+
+    if (null == path) {
+      return;
+    }
+
+    String operator = predicate.getOperator();
+    Comparable<?> value = predicate.getValue();
+
+    // convert string to enum for proper JPA comparisons
+    Class<?> clazz = lastSingularAttribute.getJavaType();
+    if (clazz.isEnum()) {
+      Class<? extends Enum> enumClass = (Class<? extends Enum>) clazz;
+      value = Enum.valueOf(enumClass, value.toString());
+    }
+
+    javax.persistence.criteria.Predicate jpaPredicate = null;
+    if ("=".equals(operator)) {
+      jpaPredicate = m_builder.equal(path, value);
+    } else if ("<".equals(operator)) {
+      jpaPredicate = m_builder.lessThan(path, value);
+    } else if ("<=".equals(operator)) {
+      jpaPredicate = m_builder.lessThanOrEqualTo(path, value);
+    } else if (">".equals(operator)) {
+      jpaPredicate = m_builder.greaterThan(path, value);
+    } else if (">=".equals(operator)) {
+      jpaPredicate = m_builder.greaterThanOrEqualTo(path, value);
+    }
+
+    if (null == jpaPredicate) {
+      return;
+    }
+
+    if (null == m_queue.peekLast()) {
+      m_lastPredicate = jpaPredicate;
+    } else {
+      m_queue.peekLast().add(jpaPredicate);
+    }
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void acceptArrayPredicate(ArrayPredicate predicate) {
+    // no predicates, no work
+    Predicate[] predicates = predicate.getPredicates();
+    if (predicates.length == 0) {
+      return;
+    }
+
+    // create a new list for all of the predicates in this chain
+    List<javax.persistence.criteria.Predicate> predicateList = new ArrayList<javax.persistence.criteria.Predicate>();
+    m_queue.add(predicateList);
+
+    // visit every child predicate so it can be added to the list
+    String operator = predicate.getOperator();
+    for (int i = 0; i < predicates.length; i++) {
+      PredicateHelper.visit(predicates[i], this);
+    }
+
+    // the list is done; deque and apply logical AND or OR
+    predicateList = m_queue.pollLast();
+
+    javax.persistence.criteria.Predicate jpaPredicate = null;
+    javax.persistence.criteria.Predicate[] array = new javax.persistence.criteria.Predicate[predicateList.size()];
+    array = predicateList.toArray(array);
+
+    if ("AND".equals(operator)) {
+      jpaPredicate = m_builder.and(array);
+    } else {
+      jpaPredicate = m_builder.or(array);
+    }
+
+    if (null == m_queue.peekLast()) {
+      m_lastPredicate = jpaPredicate;
+    } else {
+      m_queue.peekLast().add(jpaPredicate);
+    }
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void acceptUnaryPredicate(UnaryPredicate predicate) {
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void acceptAlwaysPredicate(AlwaysPredicate predicate) {
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void acceptCategoryPredicate(CategoryPredicate predicate) {
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/api/query/ProcessingPredicateVisitor.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/query/ProcessingPredicateVisitor.java b/ambari-server/src/main/java/org/apache/ambari/server/api/query/ProcessingPredicateVisitor.java
index a9cd46c..8924840 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/query/ProcessingPredicateVisitor.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/query/ProcessingPredicateVisitor.java
@@ -129,7 +129,20 @@ public class ProcessingPredicateVisitor implements PredicateVisitor {
 
   @Override
   public void acceptUnaryPredicate(UnaryPredicate predicate) {
-    lastVisited = predicate;
+    String propertyId = predicate.getPropertyIds().iterator().next();
+    int    index      = propertyId.indexOf("/");
+    String category   = index == -1 ? propertyId : propertyId.substring(0, index);
+
+    Map<String, QueryImpl> subResources = query.ensureSubResources();
+
+    if (subResources.containsKey(category)) {
+      subResourceCategories.add(category);
+      subResourceProperties.add(propertyId);
+      lastVisited = AlwaysPredicate.INSTANCE;
+    }
+    else {
+      lastVisited = predicate;
+    }
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/api/query/QueryImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/query/QueryImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/api/query/QueryImpl.java
index 261559a..6dfdb49 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/query/QueryImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/query/QueryImpl.java
@@ -895,7 +895,6 @@ public class QueryImpl implements Query, ResourceInstance {
         mapTemporalInfo.put(propertyId, globalTemporalInfo);
       }
     }
-
     return PropertyHelper.getReadRequest(setProperties, requestInfoProperties, mapTemporalInfo);
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/api/query/SubResourcePredicateVisitor.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/query/SubResourcePredicateVisitor.java b/ambari-server/src/main/java/org/apache/ambari/server/api/query/SubResourcePredicateVisitor.java
index 5ec2f10..070cb40 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/query/SubResourcePredicateVisitor.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/query/SubResourcePredicateVisitor.java
@@ -24,6 +24,7 @@ import org.apache.ambari.server.controller.predicate.CategoryPredicate;
 import org.apache.ambari.server.controller.predicate.ComparisonPredicate;
 import org.apache.ambari.server.controller.predicate.PredicateVisitor;
 import org.apache.ambari.server.controller.predicate.UnaryPredicate;
+import org.apache.ambari.server.controller.predicate.NotPredicate;
 import org.apache.ambari.server.controller.spi.Predicate;
 import org.apache.ambari.server.controller.utilities.PredicateHelper;
 
@@ -100,7 +101,23 @@ public class SubResourcePredicateVisitor implements PredicateVisitor {
 
   @Override
   public void acceptUnaryPredicate(UnaryPredicate predicate) {
-    lastVisited = predicate;
+    //TODO implement subresource parsing not only for ComparisonPredicate
+    if (predicate.getPredicate() instanceof ComparisonPredicate) {
+      ComparisonPredicate innerPredicate = (ComparisonPredicate) predicate.getPredicate();
+      String propertyId = innerPredicate.getPropertyId();
+
+      int    index    = propertyId.indexOf("/");
+      String category = index == -1 ? propertyId : propertyId.substring(0, index);
+
+      if(index > -1 && category.equals(this.category)) {
+        // copy and strip off category
+        lastVisited = new NotPredicate(innerPredicate.copy(propertyId.substring(index + 1)));
+      } else {
+        lastVisited = AlwaysPredicate.INSTANCE;
+      }
+    } else {
+      lastVisited = predicate;
+    }
   }
 
   @Override