Repository: ambari
Updated Branches:
  refs/heads/branch-2.2 620daba7c -> 67c9e8131


AMBARI-15064. RU/EU can't start if hosts have name in MixedCASE in configs for 
NameNode, HBASE Master, ResourceManager (alejandro)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/67c9e813
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/67c9e813
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/67c9e813

Branch: refs/heads/branch-2.2
Commit: 67c9e81317547a34a65d6bfe480e665473e47849
Parents: 620daba
Author: Alejandro Fernandez <afernan...@hortonworks.com>
Authored: Tue Feb 16 16:02:12 2016 -0800
Committer: Alejandro Fernandez <afernan...@hortonworks.com>
Committed: Thu Feb 18 11:29:01 2016 -0800

----------------------------------------------------------------------
 .../controller/AmbariActionExecutionHelper.java |  13 ++-
 .../internal/UpgradeResourceProvider.java       |   7 +-
 .../apache/ambari/server/stack/JmxQuery.java    |  87 +++++++++++++++
 .../ambari/server/stack/MasterHostResolver.java |  86 ++++++---------
 .../AmbariManagementControllerTest.java         |   2 +-
 .../ambari/server/state/UpgradeHelperTest.java  | 109 ++++++++++++++++---
 6 files changed, 231 insertions(+), 73 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/67c9e813/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariActionExecutionHelper.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariActionExecutionHelper.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariActionExecutionHelper.java
index fe2cc29..5e1bf9d 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariActionExecutionHelper.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariActionExecutionHelper.java
@@ -262,6 +262,13 @@ public class AmbariActionExecutionHelper {
     final String serviceName = actionContext.getExpectedServiceName();
     final String componentName = actionContext.getExpectedComponentName();
 
+    LOG.debug(String.format("Called addExecutionCommandsToStage() for 
serviceName: %s, componentName: %s.", serviceName, componentName));
+    if (resourceFilter.getHostNames().isEmpty()) {
+      LOG.debug("Resource filter has no hostnames.");
+    } else {
+      LOG.debug(String.format("Resource filter has hosts: %s", 
StringUtils.join(resourceFilter.getHostNames(), ", ")));
+    }
+
     if (null != cluster) {
       StackId stackId = cluster.getCurrentStackVersion();
       if (serviceName != null && !serviceName.isEmpty()) {
@@ -275,6 +282,7 @@ public class AmbariActionExecutionHelper {
                 stackId.getStackVersion(), serviceName, componentName);
           } catch (ObjectNotFoundException e) {
             // do nothing, componentId is checked for null later
+            LOG.error(String.format("Did not find service %s and component %s 
in stack %s.", serviceName, componentName, stackId.getStackName()));
           }
         } else {
           for (String component : 
cluster.getService(serviceName).getServiceComponents().keySet()) {
@@ -288,6 +296,7 @@ public class AmbariActionExecutionHelper {
         // All hosts are valid target host
         
candidateHosts.addAll(clusters.getHostsForCluster(cluster.getClusterName()).keySet());
       }
+      LOG.debug(String.format("Request for service %s and component %s is set 
to run on candidate hosts: %s.", serviceName, componentName, 
StringUtils.join(candidateHosts, ", ")));
 
       // Filter hosts that are in MS
       Set<String> ignoredHosts = 
maintenanceStateHelper.filterHostsInMaintenanceState(
@@ -301,7 +310,9 @@ public class AmbariActionExecutionHelper {
                 }
               }
       );
+
       if (! ignoredHosts.isEmpty()) {
+        LOG.debug(String.format("Hosts to ignore: %s.", 
StringUtils.join(ignoredHosts, ", ")));
         LOG.debug("Ignoring action for hosts due to maintenance state." +
             "Ignored hosts =" + ignoredHosts + ", component="
             + componentName + ", service=" + serviceName
@@ -323,7 +334,7 @@ public class AmbariActionExecutionHelper {
       for (String hostname : resourceFilter.getHostNames()) {
         if (!candidateHosts.contains(hostname)) {
           throw new AmbariException("Request specifies host " + hostname +
-            " but its not a valid host based on the " +
+            " but it is not a valid host based on the " +
             "target service=" + serviceName + " and component=" + 
componentName);
         }
       }

http://git-wip-us.apache.org/repos/asf/ambari/blob/67c9e813/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java
index 371c611..c29fae4 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java
@@ -78,6 +78,7 @@ import org.apache.ambari.server.orm.entities.StackEntity;
 import org.apache.ambari.server.orm.entities.UpgradeEntity;
 import org.apache.ambari.server.orm.entities.UpgradeGroupEntity;
 import org.apache.ambari.server.orm.entities.UpgradeItemEntity;
+import org.apache.ambari.server.stack.JmxQuery;
 import org.apache.ambari.server.stack.MasterHostResolver;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Config;
@@ -679,10 +680,11 @@ public class UpgradeResourceProvider extends 
AbstractControllerResourceProvider
     final String version = (String) requestMap.get(UPGRADE_VERSION);
 
     MasterHostResolver resolver = null;
+    JmxQuery jmx = new JmxQuery();
     if (direction.isUpgrade()) {
-      resolver = new MasterHostResolver(configHelper, cluster);
+      resolver = new MasterHostResolver(configHelper, jmx, cluster);
     } else {
-      resolver = new MasterHostResolver(configHelper, cluster, version);
+      resolver = new MasterHostResolver(configHelper, jmx, cluster, version);
     }
 
     StackId sourceStackId = null;
@@ -1162,6 +1164,7 @@ public class UpgradeResourceProvider extends 
AbstractControllerResourceProvider
     RequestResourceFilter filter = new RequestResourceFilter("", "",
         new ArrayList<String>(wrapper.getHosts()));
 
+    LOG.debug(String.format("Analyzing upgrade item %s with tasks: %s.", 
entity.getText(), entity.getTasks()));
     Map<String, String> params = getNewParameterMap();
     params.put(COMMAND_PARAM_TASKS, entity.getTasks());
     params.put(COMMAND_PARAM_VERSION, context.getVersion());

http://git-wip-us.apache.org/repos/asf/ambari/blob/67c9e813/ambari-server/src/main/java/org/apache/ambari/server/stack/JmxQuery.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/stack/JmxQuery.java 
b/ambari-server/src/main/java/org/apache/ambari/server/stack/JmxQuery.java
new file mode 100644
index 0000000..389d504
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/JmxQuery.java
@@ -0,0 +1,87 @@
+/**
+ * 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.stack;
+
+import com.google.common.reflect.TypeToken;
+import org.apache.ambari.server.utils.HTTPUtils;
+import org.apache.ambari.server.utils.StageUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ * Class with methods to query JMX.
+ * This is its own class with non-static methods because it is mocked during 
unit tests.
+ */
+public class JmxQuery {
+
+  private static Logger LOG = LoggerFactory.getLogger(JmxQuery.class);
+
+  public String queryJmxBeanValue(String hostname, int port, String beanName, 
String attributeName,
+                                   boolean asQuery) {
+    return queryJmxBeanValue(hostname, port, beanName, attributeName, asQuery, 
false);
+  }
+
+  /**
+   * Query the JMX attribute at http(s)://$server:$port/jmx?qry=$query or 
http(s)://$server:$port/jmx?get=$bean::$attribute
+   * @param hostname host name
+   * @param port port number
+   * @param beanName if asQuery is false, then search for this bean name
+   * @param attributeName if asQuery is false, then search for this attribute 
name
+   * @param asQuery whether to search bean or query
+   * @param encrypted true if using https instead of http.
+   * @return The jmx value.
+   */
+  public String queryJmxBeanValue(String hostname, int port, String beanName, 
String attributeName,
+      boolean asQuery, boolean encrypted) {
+
+    String protocol = encrypted ? "https://"; : "http://";;
+    String endPoint = protocol + (asQuery ?
+        String.format("%s:%s/jmx?qry=%s", hostname, port, beanName) :
+        String.format("%s:%s/jmx?get=%s::%s", hostname, port, beanName, 
attributeName));
+
+    String response = HTTPUtils.requestURL(endPoint);
+
+    if (null == response || response.isEmpty()) {
+      return null;
+    }
+
+    Type type = new TypeToken<Map<String, ArrayList<HashMap<String, 
String>>>>() {}.getType();
+
+    try {
+      Map<String, ArrayList<HashMap<String, String>>> jmxBeans =
+          StageUtils.getGson().fromJson(response, type);
+
+      return jmxBeans.get("beans").get(0).get(attributeName);
+    } catch (Exception e) {
+      if (LOG.isDebugEnabled()) {
+        LOG.info("Could not load JMX from {}/{} from {}", beanName, 
attributeName, hostname, e);
+      } else {
+        LOG.info("Could not load JMX from {}/{} from {}", beanName, 
attributeName, hostname);
+      }
+    }
+
+    return null;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/67c9e813/ambari-server/src/main/java/org/apache/ambari/server/stack/MasterHostResolver.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/stack/MasterHostResolver.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/stack/MasterHostResolver.java
index 561350b..6825895 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/stack/MasterHostResolver.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/stack/MasterHostResolver.java
@@ -18,7 +18,6 @@
 
 package org.apache.ambari.server.stack;
 
-import java.lang.reflect.Type;
 import java.net.MalformedURLException;
 import java.text.MessageFormat;
 import java.util.ArrayList;
@@ -38,12 +37,9 @@ import org.apache.ambari.server.state.ServiceComponentHost;
 import org.apache.ambari.server.state.UpgradeState;
 import org.apache.ambari.server.utils.HTTPUtils;
 import org.apache.ambari.server.utils.HostAndPort;
-import org.apache.ambari.server.utils.StageUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.reflect.TypeToken;
-
 
 public class MasterHostResolver {
 
@@ -52,6 +48,7 @@ public class MasterHostResolver {
   private Cluster m_cluster;
   private String m_version;
   private ConfigHelper m_configHelper;
+  private JmxQuery m_jmxQuery;
 
   public enum Service {
     HDFS,
@@ -73,10 +70,11 @@ public class MasterHostResolver {
    * resolving hosts.  Common use case is creating an upgrade that should
    * include an entire cluster.
    * @param configHelper Configuration Helper
+   * @param jmxQuery Jmx Query utils
    * @param cluster the cluster
    */
-  public MasterHostResolver(ConfigHelper configHelper, Cluster cluster) {
-    this(configHelper, cluster, null);
+  public MasterHostResolver(ConfigHelper configHelper, JmxQuery jmxQuery, 
Cluster cluster) {
+    this(configHelper, jmxQuery, cluster, null);
   }
 
   /**
@@ -85,11 +83,13 @@ public class MasterHostResolver {
    * HostComponents need to be downgraded, and HostComponents already at the
    * correct version are skipped.
    * @param configHelper Configuration Helper
+   * @param jmxQuery Jmx Query utils
    * @param cluster the cluster
    * @param version the version, or {@code null} to not compare versions
    */
-  public MasterHostResolver(ConfigHelper configHelper, Cluster cluster, String 
version) {
+  public MasterHostResolver(ConfigHelper configHelper, JmxQuery jmxQuery, 
Cluster cluster, String version) {
     m_configHelper = configHelper;
+    m_jmxQuery = jmxQuery;
     m_cluster = cluster;
     m_version = version;
   }
@@ -247,11 +247,11 @@ public class MasterHostResolver {
     return false;
   }
 
-
   /**
    * Get mapping of the HDFS Namenodes from the state ("active" or "standby") 
to the hostname.
    * @return Returns a map from the state ("active" or "standby" to the 
hostname with that state if exactly
    * one active and one standby host were found, otherwise, return null.
+   * The hostnames are returned in lowercase.
    */
   private Map<Status, String> getNameNodePair() {
     Map<Status, String> stateToHost = new HashMap<Status, String>();
@@ -287,11 +287,13 @@ public class MasterHostResolver {
           throw new MalformedURLException("Could not parse host and port from 
" + value);
         }
 
-        String state = queryJmxBeanValue(hp.host, hp.port, 
"Hadoop:service=NameNode,name=NameNodeStatus", "State", true, encrypted);
+        String state = m_jmxQuery.queryJmxBeanValue(hp.host, hp.port, 
"Hadoop:service=NameNode,name=NameNodeStatus", "State", true, encrypted);
 
         if (null != state && (state.equalsIgnoreCase(Status.ACTIVE.toString()) 
|| state.equalsIgnoreCase(Status.STANDBY.toString()))) {
           Status status = Status.valueOf(state.toUpperCase());
-          stateToHost.put(status, hp.host);
+          stateToHost.put(status, hp.host.toLowerCase());
+        } else {
+          LOG.error(String.format("Could not retrieve state for NameNode %s 
from property %s by querying JMX.", hp.host, key));
         }
       } catch (MalformedURLException e) {
         LOG.error(e.getMessage());
@@ -304,6 +306,12 @@ public class MasterHostResolver {
     return null;
   }
 
+  /**
+   * Resolve the name of the Resource Manager master and convert the hostname 
to lowercase.
+   * @param cluster Cluster
+   * @param hostType RM hosts
+   * @throws MalformedURLException
+   */
   private void resolveResourceManagers(Cluster cluster, HostsType hostType) 
throws MalformedURLException {
     LinkedHashSet<String> orderedHosts = new 
LinkedHashSet<String>(hostType.hosts);
 
@@ -315,23 +323,29 @@ public class MasterHostResolver {
     }
 
     for (String hostname : hostType.hosts) {
-      String value = queryJmxBeanValue(hostname, hp.port,
+      String value = m_jmxQuery.queryJmxBeanValue(hostname, hp.port,
           "Hadoop:service=ResourceManager,name=RMNMInfo", "modelerType", true);
 
       if (null != value) {
         if (null == hostType.master) {
-          hostType.master = hostname;
+          hostType.master = hostname.toLowerCase();
         }
 
         // Quick and dirty to make sure the master is last in the list
-        orderedHosts.remove(hostname);
-        orderedHosts.add(hostname);
+        orderedHosts.remove(hostname.toLowerCase());
+        orderedHosts.add(hostname.toLowerCase());
       }
 
     }
     hostType.hosts = orderedHosts;
   }
 
+  /**
+   * Resolve the HBASE master and convert the hostname to lowercase.
+   * @param cluster Cluster
+   * @param hostsType HBASE master host.
+   * @throws AmbariException
+   */
   private void resolveHBaseMasters(Cluster cluster, HostsType hostsType) 
throws AmbariException {
     String hbaseMasterInfoPortProperty = "hbase.master.info.port";
     String hbaseMasterInfoPortValue = 
m_configHelper.getValueFromDesiredConfigurations(cluster, 
ConfigHelper.HBASE_SITE, hbaseMasterInfoPortProperty);
@@ -342,55 +356,17 @@ public class MasterHostResolver {
 
     final int hbaseMasterInfoPort = Integer.parseInt(hbaseMasterInfoPortValue);
     for (String hostname : hostsType.hosts) {
-      String value = queryJmxBeanValue(hostname, hbaseMasterInfoPort,
+      String value = m_jmxQuery.queryJmxBeanValue(hostname, 
hbaseMasterInfoPort,
           "Hadoop:service=HBase,name=Master,sub=Server", "tag.isActiveMaster", 
false);
 
       if (null != value) {
         Boolean bool = Boolean.valueOf(value);
         if (bool.booleanValue()) {
-          hostsType.master = hostname;
+          hostsType.master = hostname.toLowerCase();
         } else {
-          hostsType.secondary = hostname;
+          hostsType.secondary = hostname.toLowerCase();
         }
       }
-
-    }
-  }
-
-  private String queryJmxBeanValue(String hostname, int port, String beanName, 
String attributeName,
-                                   boolean asQuery) {
-    return queryJmxBeanValue(hostname, port, beanName, attributeName, asQuery, 
false);
-  }
-
-  private String queryJmxBeanValue(String hostname, int port, String beanName, 
String attributeName,
-      boolean asQuery, boolean encrypted) {
-
-    String protocol = encrypted ? "https://"; : "http://";;
-    String endPoint = protocol + (asQuery ?
-        String.format("%s:%s/jmx?qry=%s", hostname, port, beanName) :
-        String.format("%s:%s/jmx?get=%s::%s", hostname, port, beanName, 
attributeName));
-
-    String response = HTTPUtils.requestURL(endPoint);
-
-    if (null == response || response.isEmpty()) {
-      return null;
-    }
-
-    Type type = new TypeToken<Map<String, ArrayList<HashMap<String, 
String>>>>() {}.getType();
-
-    try {
-      Map<String, ArrayList<HashMap<String, String>>> jmxBeans =
-          StageUtils.getGson().fromJson(response, type);
-
-      return jmxBeans.get("beans").get(0).get(attributeName);
-    } catch (Exception e) {
-      if (LOG.isDebugEnabled()) {
-        LOG.info("Could not load JMX from {}/{} from {}", beanName, 
attributeName, hostname, e);
-      } else {
-        LOG.info("Could not load JMX from {}/{} from {}", beanName, 
attributeName, hostname);
-      }
     }
-
-    return null;
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/67c9e813/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
index d2c4d5e..809ee88 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
@@ -4625,7 +4625,7 @@ public class AmbariManagementControllerTest {
 
     actionRequest = new ExecuteActionRequest("c1", null, "a2", 
resourceFilters, null, params, false);
     expectActionCreationErrorWithMessage(actionRequest, requestProperties,
-        "Request specifies host h6 but its not a valid host based on the 
target service=HDFS and component=DATANODE");
+        "Request specifies host h6 but it is not a valid host based on the 
target service=HDFS and component=DATANODE");
 
     hosts.clear();
     hosts.add("h1");

http://git-wip-us.apache.org/repos/asf/ambari/blob/67c9e813/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeHelperTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeHelperTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeHelperTest.java
index 320744f..609dc9b 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeHelperTest.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeHelperTest.java
@@ -45,6 +45,7 @@ import org.apache.ambari.server.orm.GuiceJpaInitializer;
 import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
 import org.apache.ambari.server.orm.OrmTestHelper;
 import org.apache.ambari.server.stack.HostsType;
+import org.apache.ambari.server.stack.JmxQuery;
 import org.apache.ambari.server.stack.MasterHostResolver;
 import org.apache.ambari.server.state.UpgradeHelper.UpgradeGroupHolder;
 import org.apache.ambari.server.state.stack.ConfigUpgradePack;
@@ -91,22 +92,25 @@ public class UpgradeHelperTest {
   private ConfigHelper m_configHelper;
   private AmbariManagementController m_managementController;
   private Gson m_gson = new Gson();
+  private JmxQuery m_jmxQuery;
 
-  @Before
-  public void before() throws Exception {
+  /**
+   * Because test cases need to share config mocks, put common ones in this 
function.
+   * @throws Exception
+   */
+  private void setConfigMocks() throws Exception {
     // configure the mock to return data given a specific placeholder
     m_configHelper = EasyMock.createNiceMock(ConfigHelper.class);
+    expect(m_configHelper.getPlaceholderValueFromDesiredConfigurations(
+        EasyMock.anyObject(Cluster.class), 
EasyMock.eq("{{foo/bar}}"))).andReturn("placeholder-rendered-properly").anyTimes();
+    expect(m_configHelper.getEffectiveDesiredTags(
+        EasyMock.anyObject(Cluster.class), 
EasyMock.anyObject(String.class))).andReturn(new HashMap<String, Map<String, 
String>>()).anyTimes();
+  }
 
-    expect(
-      m_configHelper.getPlaceholderValueFromDesiredConfigurations(
-        EasyMock.anyObject(Cluster.class), 
EasyMock.eq("{{foo/bar}}"))).andReturn(
-        "placeholder-rendered-properly").anyTimes();
-
-    expect(
-        m_configHelper.getEffectiveDesiredTags(
-            EasyMock.anyObject(Cluster.class), 
EasyMock.anyObject(String.class))).
-        andReturn(new HashMap<String, Map<String, String>>()).anyTimes();
-
+  @Before
+  public void before() throws Exception {
+    setConfigMocks();
+    // Most test cases can replay the common config mocks. If any test case 
needs custom ones, it can re-initialize m_configHelper;
     replay(m_configHelper);
 
     final InMemoryDefaultTestModule injectorModule = new 
InMemoryDefaultTestModule() {
@@ -116,6 +120,8 @@ public class UpgradeHelperTest {
       }
     };
 
+    m_jmxQuery = EasyMock.createNiceMock(JmxQuery.class);
+
     MockModule mockModule = new MockModule();
     // create an injector which will inject the mocks
     injector = 
Guice.createInjector(Modules.override(injectorModule).with(mockModule));
@@ -1190,7 +1196,7 @@ public class UpgradeHelperTest {
     Service s = c.getService("ZOOKEEPER");
     ServiceComponent sc = s.addServiceComponent("ZOOKEEPER_SERVER");
 
-    ServiceComponentHost sch1 =sc.addServiceComponentHost("h1");
+    ServiceComponentHost sch1 = sc.addServiceComponentHost("h1");
     sch1.setVersion("2.1.1.0-1234");
 
     ServiceComponentHost sch2 = sc.addServiceComponentHost("h2");
@@ -1199,7 +1205,8 @@ public class UpgradeHelperTest {
     List<ServiceComponentHost> schs = c.getServiceComponentHosts("ZOOKEEPER", 
"ZOOKEEPER_SERVER");
     assertEquals(2, schs.size());
 
-    MasterHostResolver mhr = new MasterHostResolver(null, c, "2.1.1.0-1234");
+    JmxQuery jmx = new JmxQuery();
+    MasterHostResolver mhr = new MasterHostResolver(null, jmx, c, 
"2.1.1.0-1234");
 
     HostsType ht = mhr.getMasterAndHosts("ZOOKEEPER", "ZOOKEEPER_SERVER");
     assertEquals(0, ht.hosts.size());
@@ -1213,6 +1220,80 @@ public class UpgradeHelperTest {
     assertEquals("h2", ht.hosts.iterator().next());
   }
 
+  /**
+   * Test that MasterHostResolver is case-insensitive even if configs have 
hosts in upper case for NameNode.
+   * @throws Exception
+   */
+  @Test
+  public void testResolverCaseInsensitive() throws Exception {
+    Clusters clusters = injector.getInstance(Clusters.class);
+    ServiceFactory serviceFactory = injector.getInstance(ServiceFactory.class);
+
+    String clusterName = "c1";
+    String version = "2.1.1.0-1234";
+
+    StackId stackId = new StackId("HDP-2.1.1");
+    clusters.addCluster(clusterName, stackId);
+    Cluster c = clusters.getCluster(clusterName);
+
+    helper.getOrCreateRepositoryVersion(stackId,
+        c.getDesiredStackVersion().getStackVersion());
+
+    c.createClusterVersion(stackId,
+        c.getDesiredStackVersion().getStackVersion(), "admin",
+        RepositoryVersionState.UPGRADING);
+
+    for (int i = 0; i < 2; i++) {
+      String hostName = "h" + (i+1);
+      clusters.addHost(hostName);
+      Host host = clusters.getHost(hostName);
+
+      Map<String, String> hostAttributes = new HashMap<String, String>();
+      hostAttributes.put("os_family", "redhat");
+      hostAttributes.put("os_release_version", "6");
+
+      host.setHostAttributes(hostAttributes);
+
+      host.persist();
+      clusters.mapHostToCluster(hostName, clusterName);
+    }
+
+    // Add services
+    c.addService(serviceFactory.createNew(c, "HDFS"));
+
+    Service s = c.getService("HDFS");
+    ServiceComponent sc = s.addServiceComponent("NAMENODE");
+    sc.addServiceComponentHost("h1");
+    sc.addServiceComponentHost("h2");
+
+    List<ServiceComponentHost> schs = c.getServiceComponentHosts("HDFS", 
"NAMENODE");
+    assertEquals(2, schs.size());
+
+    setConfigMocks();
+    expect(m_configHelper.getValueFromDesiredConfigurations(c, "hdfs-site", 
"dfs.nameservices")).andReturn("ha").anyTimes();
+    expect(m_configHelper.getValueFromDesiredConfigurations(c, "hdfs-site", 
"dfs.ha.namenodes.ha")).andReturn("nn1,nn2").anyTimes();
+    expect(m_configHelper.getValueFromDesiredConfigurations(c, "hdfs-site", 
"dfs.http.policy")).andReturn("HTTP_ONLY").anyTimes();
+
+    // Notice that these names are all caps.
+    expect(m_configHelper.getValueFromDesiredConfigurations(c, "hdfs-site", 
"dfs.namenode.http-address.ha.nn1")).andReturn("H1:50070").anyTimes();
+    expect(m_configHelper.getValueFromDesiredConfigurations(c, "hdfs-site", 
"dfs.namenode.http-address.ha.nn2")).andReturn("H2:50070").anyTimes();
+    replay(m_configHelper);
+
+    // Mock the calls to JMX
+    expect(m_jmxQuery.queryJmxBeanValue("H1", 50070, 
"Hadoop:service=NameNode,name=NameNodeStatus", "State", true, 
false)).andReturn("ACTIVE").anyTimes();
+    expect(m_jmxQuery.queryJmxBeanValue("H2", 50070, 
"Hadoop:service=NameNode,name=NameNodeStatus", "State", true, 
false)).andReturn("STANDBY").anyTimes();
+    replay(m_jmxQuery);
+
+    MasterHostResolver mhr = new MasterHostResolver(m_configHelper, 
m_jmxQuery, c, version);
+
+    HostsType ht = mhr.getMasterAndHosts("HDFS", "NAMENODE");
+    assertEquals(2, ht.hosts.size());
+
+    // Should be stored in lowercase.
+    assertTrue(ht.hosts.contains("h1"));
+    assertTrue(ht.hosts.contains("h1"));
+  }
+
 
   private class MockModule implements Module {
 

Reply via email to