You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by rn...@apache.org on 2015/04/21 03:30:33 UTC

ambari git commit: AMBARI-10487. Blueprint processor fails to handle direct host names properly in HA Blueprints. (rnettleton)

Repository: ambari
Updated Branches:
  refs/heads/trunk cf0169c91 -> c79bd1245


AMBARI-10487. Blueprint processor fails to handle direct host names properly in HA Blueprints. (rnettleton)


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

Branch: refs/heads/trunk
Commit: c79bd1245bcbfd8de3d2710e529db843aee90a53
Parents: cf0169c
Author: Bob Nettleton <rn...@hortonworks.com>
Authored: Mon Apr 20 21:29:21 2015 -0400
Committer: Bob Nettleton <rn...@hortonworks.com>
Committed: Mon Apr 20 21:30:17 2015 -0400

----------------------------------------------------------------------
 .../BlueprintConfigurationProcessor.java        |  96 +++++-
 .../BlueprintConfigurationProcessorTest.java    | 331 +++++++++++++++++++
 2 files changed, 419 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/c79bd124/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintConfigurationProcessor.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintConfigurationProcessor.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintConfigurationProcessor.java
index 8247c63..cec93bf 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintConfigurationProcessor.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintConfigurationProcessor.java
@@ -131,7 +131,7 @@ public class BlueprintConfigurationProcessor {
           Map<String, String> typeMap = properties.get(type);
           if (typeMap != null && typeMap.containsKey(propertyName)) {
             typeMap.put(propertyName, updater.updateForClusterCreate(
-                hostGroups, typeMap.get(propertyName), properties, stackDefinition));
+                hostGroups, propertyName, typeMap.get(propertyName), properties, stackDefinition));
           }
         }
       }
@@ -322,6 +322,29 @@ public class BlueprintConfigurationProcessor {
 
 
   /**
+   * Static convenience function to determine if Yarn ResourceManager HA is enabled
+   * @param configProperties configuration properties for this cluster
+   * @return true if Yarn ResourceManager HA is enabled
+   *         false if Yarn ResourceManager HA is not enabled
+   */
+  static boolean isYarnResourceManagerHAEnabled(Map<String, Map<String, String>> configProperties) {
+    return configProperties.containsKey("yarn-site") && configProperties.get("yarn-site").containsKey("yarn.resourcemanager.ha.enabled")
+      && configProperties.get("yarn-site").get("yarn.resourcemanager.ha.enabled").equals("true");
+  }
+
+  /**
+   * Static convenience function to determine if Oozie HA is enabled
+   * @param configProperties configuration properties for this cluster
+   * @return true if Oozie HA is enabled
+   *         false if Oozie HA is not enabled
+   */
+  static boolean isOozieServerHAEnabled(Map<String, Map<String, String>> configProperties) {
+    return configProperties.containsKey("oozie-site") && configProperties.get("oozie-site").containsKey("oozie.services.ext")
+      && configProperties.get("oozie-site").get("oozie.services.ext").contains("org.apache.oozie.service.ZKLocksService");
+  }
+
+
+  /**
    * Convenience method to examine the current configuration, to determine
    * if the hostname of the initial active namenode in an HA deployment has
    * been included.
@@ -595,6 +618,7 @@ public class BlueprintConfigurationProcessor {
      *
      *
      * @param hostGroups      host groups
+     * @param propertyName    name of property
      * @param origValue       original value of property
      * @param properties      all properties
      * @param stackDefinition definition of stack used for this cluster
@@ -603,7 +627,7 @@ public class BlueprintConfigurationProcessor {
      * @return new property value
      */
     public String updateForClusterCreate(Map<String, ? extends HostGroup> hostGroups,
-                                         String origValue, Map<String, Map<String, String>> properties, Stack stackDefinition
+                                         String propertyName, String origValue, Map<String, Map<String, String>> properties, Stack stackDefinition
     );
   }
 
@@ -631,6 +655,7 @@ public class BlueprintConfigurationProcessor {
      *
      *
      * @param hostGroups       host groups
+     * @param propertyName    name of property
      * @param origValue        original value of property
      * @param properties       all properties
      * @param stackDefinition  stack used for cluster creation
@@ -639,6 +664,7 @@ public class BlueprintConfigurationProcessor {
      */
     @Override
     public String updateForClusterCreate(Map<String, ? extends HostGroup> hostGroups,
+                                         String propertyName,
                                          String origValue,
                                          Map<String, Map<String, String>> properties,
                                          Stack stackDefinition)  {
@@ -681,6 +707,12 @@ public class BlueprintConfigurationProcessor {
                 // reference must point to the logical nameservice, rather than an individual namenode
                 return origValue;
               }
+
+              if (!origValue.contains("localhost")) {
+                // if this NameNode HA property is a FDQN, then simply return it
+                return origValue;
+              }
+
             }
 
             if (isNameNodeHAEnabled(properties) && isComponentSecondaryNameNode() && (matchingGroups.isEmpty())) {
@@ -689,7 +721,21 @@ public class BlueprintConfigurationProcessor {
               return origValue;
             }
 
-            throw new IllegalArgumentException("Unable to update configuration property with topology information. " +
+            if (isYarnResourceManagerHAEnabled(properties) && isComponentResourceManager() && (matchingGroups.size() == 2)) {
+              if (!origValue.contains("localhost")) {
+                // if this Yarn property is a FQDN, then simply return it
+                return origValue;
+              }
+            }
+
+            if ((isOozieServerHAEnabled(properties)) && isComponentOozieServer() && (matchingGroups.size() > 1))     {
+              if (!origValue.contains("localhost")) {
+                // if this Oozie property is a FQDN, then simply return i
+                return origValue;
+              }
+            }
+
+            throw new IllegalArgumentException("Unable to update configuration property " + "'" + propertyName + "'"+ " with topology information. " +
               "Component '" + component + "' is not mapped to any host group or is mapped to multiple groups.");
           }
         }
@@ -719,6 +765,28 @@ public class BlueprintConfigurationProcessor {
     }
 
     /**
+     * Utility method to determine if the component associated with this updater
+     * instance is a Yarn ResourceManager
+     *
+     * @return true if the component associated is a Yarn ResourceManager
+     *         false if the component is not a Yarn ResourceManager
+     */
+    private boolean isComponentResourceManager() {
+      return component.equals("RESOURCEMANAGER");
+    }
+
+    /**
+     * Utility method to determine if the component associated with this updater
+     * instance is an Oozie Server
+     *
+     * @return true if the component associated is an Oozie Server
+     *         false if the component is not an Oozie Server
+     */
+    private boolean isComponentOozieServer() {
+      return component.equals("OOZIE_SERVER");
+    }
+
+    /**
      * Provides access to the name of the component associated
      *   with this updater instance.
      *
@@ -747,9 +815,9 @@ public class BlueprintConfigurationProcessor {
     }
 
     @Override
-    public String updateForClusterCreate(Map<String, ? extends HostGroup> hostGroups, String origValue, Map<String, Map<String, String>> properties, Stack stackDefinition) {
+    public String updateForClusterCreate(Map<String, ? extends HostGroup> hostGroups, String propertyName, String origValue, Map<String, Map<String, String>> properties, Stack stackDefinition) {
       try {
-        return super.updateForClusterCreate(hostGroups, origValue, properties, stackDefinition);
+        return super.updateForClusterCreate(hostGroups, propertyName, origValue, properties, stackDefinition);
       } catch (IllegalArgumentException illegalArgumentException) {
         // return the original value, since the optional component is not available in this cluster
         return origValue;
@@ -803,11 +871,12 @@ public class BlueprintConfigurationProcessor {
      */
     @Override
     public String updateForClusterCreate(Map<String, ? extends HostGroup> hostGroups,
+                                         String propertyName,
                                          String origValue, Map<String, Map<String, String>> properties,
                                          Stack stackDefinition) {
 
       if (isDatabaseManaged(properties)) {
-        return super.updateForClusterCreate(hostGroups, origValue, properties, stackDefinition);
+        return super.updateForClusterCreate(hostGroups, propertyName, origValue, properties, stackDefinition);
       } else {
         return origValue;
       }
@@ -871,6 +940,7 @@ public class BlueprintConfigurationProcessor {
      *
      *
      * @param hostGroups       host groups
+     *
      * @param origValue        original value of property
      * @param properties       all properties
      * @param stackDefinition  stack used for cluster creation
@@ -879,9 +949,16 @@ public class BlueprintConfigurationProcessor {
      */
     @Override
     public String updateForClusterCreate(Map<String, ? extends HostGroup> hostGroups,
+                                         String propertyName,
                                          String origValue,
                                          Map<String, Map<String, String>> properties,
                                          Stack stackDefinition) {
+      if (!origValue.contains("%HOSTGROUP") &&
+        (!origValue.contains("localhost"))) {
+        // this property must contain FQDNs specified directly by the user
+        // of the Blueprint, so the processor should not attempt to update them
+        return origValue;
+      }
 
       Collection<String> hostStrings = getHostStrings(hostGroups, origValue);
       if (hostStrings.isEmpty()) {
@@ -964,6 +1041,7 @@ public class BlueprintConfigurationProcessor {
      */
     @Override
     public String updateForClusterCreate(Map<String, ? extends HostGroup> hostGroups,
+                                         String propertyName,
                                          String origValue, Map<String,
                                          Map<String, String>> properties,
                                          Stack stackDefinition) {
@@ -999,11 +1077,12 @@ public class BlueprintConfigurationProcessor {
      */
     @Override
     public String updateForClusterCreate(Map<String, ? extends HostGroup> hostGroupMap,
+                                         String propertyName,
                                          String origValue,
                                          Map<String, Map<String, String>> properties,
                                          Stack stackDefinition) {
 
-      return doFormat(propertyUpdater.updateForClusterCreate(hostGroupMap, origValue, properties, stackDefinition));
+      return doFormat(propertyUpdater.updateForClusterCreate(hostGroupMap, propertyName, origValue, properties, stackDefinition));
     }
 
     /**
@@ -1063,7 +1142,8 @@ public class BlueprintConfigurationProcessor {
    */
   private static class OriginalValuePropertyUpdater implements PropertyUpdater {
     @Override
-    public String updateForClusterCreate(Map<String, ? extends HostGroup> hostGroups, String origValue,
+    public String updateForClusterCreate(Map<String, ? extends HostGroup> hostGroups,
+                                         String propertyName, String origValue,
                                          Map<String, Map<String, String>> properties,
                                          Stack stackDefinition) {
       // always return the original value, since these properties do not require update handling

http://git-wip-us.apache.org/repos/asf/ambari/blob/c79bd124/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/BlueprintConfigurationProcessorTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/BlueprintConfigurationProcessorTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/BlueprintConfigurationProcessorTest.java
index 1839a5f..aa9fa00 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/BlueprintConfigurationProcessorTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/BlueprintConfigurationProcessorTest.java
@@ -1742,6 +1742,125 @@ public class BlueprintConfigurationProcessorTest {
   }
 
   @Test
+  public void testDoUpdateForClusterWithNameNodeHAEnabledSpecifyingHostNamesDirectly() throws Exception {
+    final String expectedNameService = "mynameservice";
+    final String expectedHostName = "c6401.apache.ambari.org";
+    final String expectedHostNameTwo = "serverTwo";
+    final String expectedPortNum = "808080";
+    final String expectedNodeOne = "nn1";
+    final String expectedNodeTwo = "nn2";
+    final String expectedHostGroupName = "host_group_1";
+
+    EasyMockSupport mockSupport = new EasyMockSupport();
+
+    HostGroup mockHostGroupOne = mockSupport.createMock(HostGroup.class);
+    HostGroup mockHostGroupTwo = mockSupport.createMock(HostGroup.class);
+
+    Stack mockStack = mockSupport.createMock(Stack.class);
+
+    expect(mockHostGroupOne.getHostInfo()).andReturn(Arrays.asList(expectedHostName)).atLeastOnce();
+    expect(mockHostGroupTwo.getHostInfo()).andReturn(Arrays.asList(expectedHostNameTwo)).atLeastOnce();
+    expect(mockHostGroupOne.getComponents()).andReturn(Collections.singleton("NAMENODE")).atLeastOnce();
+    expect(mockHostGroupTwo.getComponents()).andReturn(Collections.singleton("NAMENODE")).atLeastOnce();
+    expect(mockStack.getCardinality("NAMENODE")).andReturn(new Cardinality("1-2")).atLeastOnce();
+    expect(mockStack.getCardinality("SECONDARY_NAMENODE")).andReturn(new Cardinality("1")).atLeastOnce();
+
+    mockSupport.replayAll();
+
+    Map<String, Map<String, String>> configProperties =
+      new HashMap<String, Map<String, String>>();
+
+    Map<String, String> hdfsSiteProperties =
+      new HashMap<String, String>();
+    Map<String, String> hbaseSiteProperties =
+      new HashMap<String, String>();
+    Map<String, String> hadoopEnvProperties =
+      new HashMap<String, String>();
+    Map<String, String> coreSiteProperties =
+      new HashMap<String, String>();
+    Map<String, String> accumuloSiteProperties =
+      new HashMap<String, String>();
+
+
+    configProperties.put("hdfs-site", hdfsSiteProperties);
+    configProperties.put("hadoop-env", hadoopEnvProperties);
+    configProperties.put("core-site", coreSiteProperties);
+    configProperties.put("hbase-site", hbaseSiteProperties);
+    configProperties.put("accumulo-site", accumuloSiteProperties);
+
+    // setup hdfs HA config for test
+    hdfsSiteProperties.put("dfs.nameservices", expectedNameService);
+    hdfsSiteProperties.put("dfs.ha.namenodes.mynameservice", expectedNodeOne + ", " + expectedNodeTwo);
+
+
+    // setup properties that include exported host group information
+    hdfsSiteProperties.put("dfs.namenode.https-address." + expectedNameService + "." + expectedNodeOne, createHostAddress(expectedHostName, expectedPortNum));
+    hdfsSiteProperties.put("dfs.namenode.https-address." + expectedNameService + "." + expectedNodeTwo, createHostAddress(expectedHostNameTwo, expectedPortNum));
+    hdfsSiteProperties.put("dfs.namenode.http-address." + expectedNameService + "." + expectedNodeOne, createHostAddress(expectedHostName, expectedPortNum));
+    hdfsSiteProperties.put("dfs.namenode.http-address." + expectedNameService + "." + expectedNodeTwo, createHostAddress(expectedHostNameTwo, expectedPortNum));
+    hdfsSiteProperties.put("dfs.namenode.rpc-address." + expectedNameService + "." + expectedNodeOne, createHostAddress(expectedHostName, expectedPortNum));
+    hdfsSiteProperties.put("dfs.namenode.rpc-address." + expectedNameService + "." + expectedNodeTwo, createHostAddress(expectedHostNameTwo, expectedPortNum));
+
+    // add properties that require the SECONDARY_NAMENODE, which
+    // is not included in this test
+    hdfsSiteProperties.put("dfs.secondary.http.address", "localhost:8080");
+    hdfsSiteProperties.put("dfs.namenode.secondary.http-address", "localhost:8080");
+
+    // configure the defaultFS to use the nameservice URL
+    coreSiteProperties.put("fs.defaultFS", "hdfs://" + expectedNameService);
+
+    // configure the hbase rootdir to use the nameservice URL
+    hbaseSiteProperties.put("hbase.rootdir", "hdfs://" + expectedNameService + "/hbase/test/root/dir");
+
+    // configure the hbase rootdir to use the nameservice URL
+    accumuloSiteProperties.put("instance.volumes", "hdfs://" + expectedNameService + "/accumulo/test/instance/volumes");
+
+    BlueprintConfigurationProcessor configProcessor =
+      new BlueprintConfigurationProcessor(configProperties);
+
+    Map<String, HostGroup> mapOfHostGroups = new LinkedHashMap<String, HostGroup>();
+    mapOfHostGroups.put(expectedHostGroupName, mockHostGroupOne);
+    mapOfHostGroups.put("host-group-2", mockHostGroupTwo);
+
+    configProcessor.doUpdateForClusterCreate(mapOfHostGroups, mockStack);
+
+    // verify that the expected hostname was substituted for the host group name in the config
+    assertEquals("HTTPS address HA property not properly exported",
+      expectedHostName + ":" + expectedPortNum, hdfsSiteProperties.get("dfs.namenode.https-address." + expectedNameService + "." + expectedNodeOne));
+    assertEquals("HTTPS address HA property not properly exported",
+      expectedHostNameTwo + ":" + expectedPortNum, hdfsSiteProperties.get("dfs.namenode.https-address." + expectedNameService + "." + expectedNodeTwo));
+
+    assertEquals("HTTPS address HA property not properly exported",
+      expectedHostName + ":" + expectedPortNum, hdfsSiteProperties.get("dfs.namenode.http-address." + expectedNameService + "." + expectedNodeOne));
+    assertEquals("HTTPS address HA property not properly exported",
+      expectedHostNameTwo + ":" + expectedPortNum, hdfsSiteProperties.get("dfs.namenode.http-address." + expectedNameService + "." + expectedNodeTwo));
+
+    assertEquals("HTTPS address HA property not properly exported",
+      expectedHostName + ":" + expectedPortNum, hdfsSiteProperties.get("dfs.namenode.rpc-address." + expectedNameService + "." + expectedNodeOne));
+    assertEquals("HTTPS address HA property not properly exported",
+      expectedHostNameTwo + ":" + expectedPortNum, hdfsSiteProperties.get("dfs.namenode.rpc-address." + expectedNameService + "." + expectedNodeTwo));
+
+    // verify that the Blueprint config processor has set the internal required properties
+    // that determine the active and standby node hostnames for this HA setup
+    assertEquals("Active Namenode hostname was not set correctly",
+      expectedHostName, hadoopEnvProperties.get("dfs_ha_initial_namenode_active"));
+
+    assertEquals("Standby Namenode hostname was not set correctly",
+      expectedHostNameTwo, hadoopEnvProperties.get("dfs_ha_initial_namenode_standby"));
+
+    assertEquals("fs.defaultFS should not be modified by cluster update when NameNode HA is enabled.",
+      "hdfs://" + expectedNameService, coreSiteProperties.get("fs.defaultFS"));
+
+    assertEquals("hbase.rootdir should not be modified by cluster update when NameNode HA is enabled.",
+      "hdfs://" + expectedNameService + "/hbase/test/root/dir", hbaseSiteProperties.get("hbase.rootdir"));
+
+    assertEquals("instance.volumes should not be modified by cluster update when NameNode HA is enabled.",
+      "hdfs://" + expectedNameService + "/accumulo/test/instance/volumes", accumuloSiteProperties.get("instance.volumes"));
+
+    mockSupport.verifyAll();
+  }
+
+  @Test
   public void testDoUpdateForClusterWithNameNodeHAEnabledAndActiveNodeSet() throws Exception {
     final String expectedNameService = "mynameservice";
     final String expectedHostName = "serverThree";
@@ -2240,6 +2359,90 @@ public class BlueprintConfigurationProcessorTest {
   }
 
   @Test
+  public void testYarnHighAvailabilityConfigClusterUpdateSpecifyingHostNamesDirectly() throws Exception {
+    final String expectedHostName = "c6401.apache.ambari.org";
+    final String expectedPortNum = "808080";
+    final String expectedHostGroupName = "host_group_1";
+    final String expectedHostGroupNameTwo = "host_group_2";
+
+    EasyMockSupport mockSupport = new EasyMockSupport();
+
+    HostGroup mockHostGroupOne = mockSupport.createMock(HostGroup.class);
+    HostGroup mockHostGroupTwo = mockSupport.createMock(HostGroup.class);
+
+    Stack mockStack = mockSupport.createMock(Stack.class);
+
+    Set<String> setOfComponents = new HashSet<String>();
+    setOfComponents.add("RESOURCEMANAGER");
+    setOfComponents.add("APP_TIMELINE_SERVER");
+    setOfComponents.add("HISTORYSERVER");
+    expect(mockHostGroupOne.getComponents()).andReturn(setOfComponents).atLeastOnce();
+    expect(mockHostGroupOne.getHostInfo()).andReturn(Collections.singleton(expectedHostName)).atLeastOnce();
+    expect(mockHostGroupTwo.getComponents()).andReturn(Collections.singleton("RESOURCEMANAGER")).atLeastOnce();
+
+    expect(mockStack.getCardinality("RESOURCEMANAGER")).andReturn(new Cardinality("1-2")).atLeastOnce();
+    //expect(mockStack.getCardinality("APP_TIMELINE_SERVER")).andReturn(new Cardinality("1")).atLeastOnce();
+    //expect(mockStack.getCardinality("HISTORYSERVER")).andReturn(new Cardinality("1")).atLeastOnce();
+
+    mockSupport.replayAll();
+
+    Map<String, Map<String, String>> configProperties =
+      new HashMap<String, Map<String, String>>();
+
+    Map<String, String> yarnSiteProperties =
+      new HashMap<String, String>();
+
+    configProperties.put("yarn-site", yarnSiteProperties);
+
+    // setup properties that include host information
+    yarnSiteProperties.put("yarn.log.server.url", "http://" + expectedHostName +":19888/jobhistory/logs");
+    yarnSiteProperties.put("yarn.resourcemanager.hostname", expectedHostName);
+    yarnSiteProperties.put("yarn.resourcemanager.resource-tracker.address", expectedHostName + ":" + expectedPortNum);
+    yarnSiteProperties.put("yarn.resourcemanager.webapp.address", expectedHostName + ":" + expectedPortNum);
+    yarnSiteProperties.put("yarn.resourcemanager.scheduler.address", expectedHostName + ":" + expectedPortNum);
+    yarnSiteProperties.put("yarn.resourcemanager.address", expectedHostName + ":" + expectedPortNum);
+    yarnSiteProperties.put("yarn.resourcemanager.admin.address", expectedHostName + ":" + expectedPortNum);
+    yarnSiteProperties.put("yarn.timeline-service.address", expectedHostName + ":" + expectedPortNum);
+    yarnSiteProperties.put("yarn.timeline-service.webapp.address", expectedHostName + ":" + expectedPortNum);
+    yarnSiteProperties.put("yarn.timeline-service.webapp.https.address", expectedHostName + ":" + expectedPortNum);
+    yarnSiteProperties.put("yarn.resourcemanager.ha.enabled", "true");
+
+    BlueprintConfigurationProcessor configProcessor =
+      new BlueprintConfigurationProcessor(configProperties);
+
+    Map<String, HostGroup> mapOfHostGroups = new HashMap<String, HostGroup>();
+    mapOfHostGroups.put(expectedHostGroupName, mockHostGroupOne);
+    mapOfHostGroups.put(expectedHostGroupNameTwo, mockHostGroupTwo);
+
+    configProcessor.doUpdateForClusterCreate(mapOfHostGroups, mockStack);
+
+    // verify that the properties with hostname information was correctly preserved
+    assertEquals("Yarn Log Server URL was incorrectly updated",
+      "http://" + expectedHostName +":19888/jobhistory/logs", yarnSiteProperties.get("yarn.log.server.url"));
+    assertEquals("Yarn ResourceManager hostname was incorrectly exported",
+      expectedHostName, yarnSiteProperties.get("yarn.resourcemanager.hostname"));
+    assertEquals("Yarn ResourceManager tracker address was incorrectly updated",
+      createHostAddress(expectedHostName, expectedPortNum), yarnSiteProperties.get("yarn.resourcemanager.resource-tracker.address"));
+    assertEquals("Yarn ResourceManager webapp address was incorrectly updated",
+      createHostAddress(expectedHostName, expectedPortNum), yarnSiteProperties.get("yarn.resourcemanager.webapp.address"));
+    assertEquals("Yarn ResourceManager scheduler address was incorrectly updated",
+      createHostAddress(expectedHostName, expectedPortNum), yarnSiteProperties.get("yarn.resourcemanager.scheduler.address"));
+    assertEquals("Yarn ResourceManager address was incorrectly updated",
+      createHostAddress(expectedHostName, expectedPortNum), yarnSiteProperties.get("yarn.resourcemanager.address"));
+    assertEquals("Yarn ResourceManager admin address was incorrectly updated",
+      createHostAddress(expectedHostName, expectedPortNum), yarnSiteProperties.get("yarn.resourcemanager.admin.address"));
+    assertEquals("Yarn ResourceManager timeline-service address was incorrectly updated",
+      createHostAddress(expectedHostName, expectedPortNum), yarnSiteProperties.get("yarn.timeline-service.address"));
+    assertEquals("Yarn ResourceManager timeline webapp address was incorrectly updated",
+      createHostAddress(expectedHostName, expectedPortNum), yarnSiteProperties.get("yarn.timeline-service.webapp.address"));
+    assertEquals("Yarn ResourceManager timeline webapp HTTPS address was incorrectly updated",
+      createHostAddress(expectedHostName, expectedPortNum), yarnSiteProperties.get("yarn.timeline-service.webapp.https.address"));
+
+    mockSupport.verifyAll();
+
+  }
+
+  @Test
   public void testYarnConfigExportedWithDefaultZeroHostAddress() throws Exception {
     final String expectedHostName = "c6401.apache.ambari.org";
     final String expectedPortNum = "808080";
@@ -2443,6 +2646,56 @@ public class BlueprintConfigurationProcessorTest {
   }
 
   @Test
+  public void testHDFSConfigClusterUpdateQuorumJournalURLSpecifyingHostNamesDirectly() throws Exception {
+    final String expectedHostNameOne = "c6401.apache.ambari.org";
+    final String expectedHostNameTwo = "c6402.apache.ambari.org";
+    final String expectedPortNum = "808080";
+    final String expectedHostGroupName = "host_group_1";
+    final String expectedHostGroupNameTwo = "host_group_2";
+    final String expectedQuorumJournalURL = "qjournal://" + createHostAddress(expectedHostNameOne, expectedPortNum) + ";" +
+                                            createHostAddress(expectedHostNameTwo, expectedPortNum) + "/mycluster";
+
+    EasyMockSupport mockSupport = new EasyMockSupport();
+
+    HostGroup mockHostGroupOne = mockSupport.createMock(HostGroup.class);
+    HostGroup mockHostGroupTwo = mockSupport.createMock(HostGroup.class);
+
+    mockSupport.replayAll();
+
+    Map<String, Map<String, String>> configProperties =
+      new HashMap<String, Map<String, String>>();
+
+    Map<String, String> hdfsSiteProperties =
+      new HashMap<String, String>();
+
+    configProperties.put("hdfs-site", hdfsSiteProperties);
+
+    // setup properties that include host information
+    // setup shared edit property, that includes a qjournal URL scheme
+
+    hdfsSiteProperties.put("dfs.namenode.shared.edits.dir", expectedQuorumJournalURL);
+
+    BlueprintConfigurationProcessor configProcessor =
+      new BlueprintConfigurationProcessor(configProperties);
+
+    Map<String, HostGroup> mapOfHostGroups =
+      new HashMap<String, HostGroup>();
+    mapOfHostGroups.put(expectedHostGroupName, mockHostGroupOne);
+    mapOfHostGroups.put(expectedHostGroupNameTwo, mockHostGroupTwo);
+
+    // call top-level export method
+    configProcessor.doUpdateForClusterCreate(mapOfHostGroups, null);
+
+    // expect that all servers are included in configuration property without changes, and that the qjournal URL format is preserved
+    assertEquals("HDFS HA shared edits directory property should not have been modified, since FQDNs were specified.",
+      expectedQuorumJournalURL,
+      hdfsSiteProperties.get("dfs.namenode.shared.edits.dir"));
+
+    mockSupport.verifyAll();
+
+  }
+
+  @Test
   public void testHDFSConfigClusterUpdateQuorumJournalURL_UsingMinusSymbolInHostName() throws Exception {
     final String expectedHostNameOne = "c6401.apache.ambari.org";
     final String expectedHostNameTwo = "c6402.apache.ambari.org";
@@ -2658,6 +2911,84 @@ public class BlueprintConfigurationProcessorTest {
   }
 
   @Test
+  public void testOozieConfigClusterUpdateHAEnabledSpecifyingHostNamesDirectly() throws Exception {
+    final String expectedHostName = "c6401.apache.ambari.org";
+    final String expectedHostNameTwo = "c6402.ambari.apache.org";
+    final String expectedExternalHost = "c6408.ambari.apache.org";
+    final String expectedHostGroupName = "host_group_1";
+    final String expectedHostGroupNameTwo = "host_group_2";
+
+    EasyMockSupport mockSupport = new EasyMockSupport();
+
+    HostGroup mockHostGroupOne = mockSupport.createMock(HostGroup.class);
+    HostGroup mockHostGroupTwo = mockSupport.createMock(HostGroup.class);
+
+    Stack mockStack = mockSupport.createMock(Stack.class);
+
+    expect(mockHostGroupOne.getComponents()).andReturn(Collections.singleton("OOZIE_SERVER")).atLeastOnce();
+    expect(mockHostGroupTwo.getComponents()).andReturn(Collections.singleton("OOZIE_SERVER")).atLeastOnce();
+
+    expect(mockStack.getCardinality("OOZIE_SERVER")).andReturn(new Cardinality("1+")).atLeastOnce();
+
+    mockSupport.replayAll();
+
+    Map<String, Map<String, String>> configProperties =
+      new HashMap<String, Map<String, String>>();
+
+    Map<String, String> oozieSiteProperties =
+      new HashMap<String, String>();
+    Map<String, String> oozieEnvProperties =
+      new HashMap<String, String>();
+    Map<String, String> coreSiteProperties =
+      new HashMap<String, String>();
+
+    configProperties.put("oozie-site", oozieSiteProperties);
+    configProperties.put("oozie-env", oozieEnvProperties);
+    configProperties.put("hive-env", oozieEnvProperties);
+    configProperties.put("core-site", coreSiteProperties);
+
+    oozieSiteProperties.put("oozie.base.url", expectedHostName);
+    oozieSiteProperties.put("oozie.authentication.kerberos.principal", expectedHostName);
+    oozieSiteProperties.put("oozie.service.HadoopAccessorService.kerberos.principal", expectedHostName);
+    oozieSiteProperties.put("oozie.service.JPAService.jdbc.url", "jdbc:mysql://" + expectedExternalHost + "/ooziedb");
+
+    // simulate the Oozie HA configuration
+    oozieSiteProperties.put("oozie.services.ext",
+      "org.apache.oozie.service.ZKLocksService,org.apache.oozie.service.ZKXLogStreamingService,org.apache.oozie.service.ZKJobsConcurrencyService,org.apache.oozie.service.ZKUUIDService");
+
+
+    oozieEnvProperties.put("oozie_hostname", expectedHostName);
+    oozieEnvProperties.put("oozie_existing_mysql_host", expectedExternalHost);
+
+    coreSiteProperties.put("hadoop.proxyuser.oozie.hosts", expectedHostName + "," + expectedHostNameTwo);
+
+    BlueprintConfigurationProcessor configProcessor =
+      new BlueprintConfigurationProcessor(configProperties);
+
+    Map<String, HostGroup> hostGroups =
+      new HashMap<String, HostGroup>();
+    hostGroups.put(expectedHostGroupName, mockHostGroupOne);
+    hostGroups.put(expectedHostGroupNameTwo, mockHostGroupTwo);
+
+    // call top-level update method
+    configProcessor.doUpdateForClusterCreate(hostGroups, mockStack);
+
+    assertEquals("oozie property not updated correctly",
+      expectedHostName, oozieSiteProperties.get("oozie.base.url"));
+    assertEquals("oozie property not updated correctly",
+      expectedHostName, oozieSiteProperties.get("oozie.authentication.kerberos.principal"));
+    assertEquals("oozie property not updated correctly",
+      expectedHostName, oozieSiteProperties.get("oozie.service.HadoopAccessorService.kerberos.principal"));
+    assertEquals("oozie property not updated correctly",
+      expectedHostName, oozieEnvProperties.get("oozie_hostname"));
+    assertEquals("oozie property not updated correctly",
+      expectedHostName + "," + expectedHostNameTwo, coreSiteProperties.get("hadoop.proxyuser.oozie.hosts"));
+
+    mockSupport.verifyAll();
+
+  }
+
+  @Test
   public void testZookeeperConfigExported() throws Exception {
     final String expectedHostName = "c6401.apache.ambari.org";
     final String expectedHostNameTwo = "c6402.ambari.apache.org";