You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by vb...@apache.org on 2015/10/27 12:25:43 UTC

ambari git commit: AMBARI-13507. Create a script to change host names for a stopped cluster.(vbrodetskyi)

Repository: ambari
Updated Branches:
  refs/heads/branch-2.1 961b9d103 -> 5491d2aeb


AMBARI-13507. Create a script to change host names for a stopped cluster.(vbrodetskyi)


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

Branch: refs/heads/branch-2.1
Commit: 5491d2aebae14387601a8002f3cb8e28e4952ef7
Parents: 961b9d1
Author: Vitaly Brodetskyi <vb...@hortonworks.com>
Authored: Tue Oct 27 13:22:10 2015 +0200
Committer: Vitaly Brodetskyi <vb...@hortonworks.com>
Committed: Tue Oct 27 13:22:10 2015 +0200

----------------------------------------------------------------------
 ambari-server/sbin/ambari-server                |   6 +-
 .../server/configuration/Configuration.java     |  57 +-
 .../ambari/server/update/HostUpdateHelper.java  | 546 +++++++++++++++++++
 ambari-server/src/main/python/ambari-server.py  |   8 +-
 .../src/main/python/ambari_server/hostUpdate.py | 105 ++++
 .../main/python/ambari_server/setupActions.py   |   1 +
 6 files changed, 705 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/5491d2ae/ambari-server/sbin/ambari-server
----------------------------------------------------------------------
diff --git a/ambari-server/sbin/ambari-server b/ambari-server/sbin/ambari-server
index 1843cd6..490d54d 100755
--- a/ambari-server/sbin/ambari-server
+++ b/ambari-server/sbin/ambari-server
@@ -144,9 +144,13 @@ case "$1" in
         echo -e "Restoring Ambari File System state"
         $PYTHON /usr/sbin/ambari-server.py $@
         ;;
+  update-host-names)
+        echo -e "Updating host names"
+        $PYTHON /usr/sbin/ambari-server.py $@
+        ;;
   *)
         echo "Usage: /usr/sbin/ambari-server
-        {start|stop|restart|setup|setup-jce|upgrade|status|upgradestack|setup-ldap|sync-ldap|set-current|setup-security|refresh-stack-hash|backup|restore} [options]
+        {start|stop|restart|setup|setup-jce|upgrade|status|upgradestack|setup-ldap|sync-ldap|set-current|setup-security|refresh-stack-hash|backup|restore|update-host-names} [options]
         Use usr/sbin/ambari-server <action> --help to get details on options available.
         Or, simply invoke ambari-server.py --help to print the options."
         exit 1

http://git-wip-us.apache.org/repos/asf/ambari/blob/5491d2ae/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
index 04ab1ef..e97a54e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
@@ -17,18 +17,11 @@
  */
 package org.apache.ambari.server.configuration;
 
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Properties;
-
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
 import org.apache.ambari.annotations.Experimental;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.actionmanager.Stage;
@@ -47,8 +40,18 @@ import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
 
 
 /**
@@ -487,6 +490,7 @@ public class Configuration {
       Configuration.class);
 
   private Properties properties;
+  private JsonObject hostChangesJson;
   private Map<String, String> configsMap;
   private Map<String, String> agentConfigsMap;
   private CredentialProvider credentialProvider = null;
@@ -834,6 +838,31 @@ public class Configuration {
     return properties;
   }
 
+  public JsonObject getHostChangesJson(String hostChangesFile) {
+    if (hostChangesJson == null) {
+      hostChangesJson = readFileToJSON(hostChangesFile);
+    }
+    return hostChangesJson;
+  }
+
+  private JsonObject readFileToJSON (String file) {
+
+    // Read from File to String
+    JsonObject jsonObject = new JsonObject();
+
+    try {
+      JsonParser parser = new JsonParser();
+      JsonElement jsonElement = parser.parse(new FileReader(file));
+      jsonObject = jsonElement.getAsJsonObject();
+    } catch (FileNotFoundException e) {
+      throw new IllegalArgumentException("No file " + file, e);
+    } catch (IOException ioe){
+      throw new IllegalArgumentException("Can't read file " + file, ioe);
+    }
+
+    return jsonObject;
+  }
+
   /**
    * Get the views directory.
    *

http://git-wip-us.apache.org/repos/asf/ambari/blob/5491d2ae/ambari-server/src/main/java/org/apache/ambari/server/update/HostUpdateHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/update/HostUpdateHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/update/HostUpdateHelper.java
new file mode 100644
index 0000000..672cd4e
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/update/HostUpdateHelper.java
@@ -0,0 +1,546 @@
+/*
+ * 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.update;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.inject.Guice;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import com.google.inject.persist.PersistService;
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.ControllerModule;
+import org.apache.ambari.server.controller.KerberosHelper;
+import org.apache.ambari.server.orm.dao.AlertDefinitionDAO;
+import org.apache.ambari.server.orm.dao.AlertsDAO;
+import org.apache.ambari.server.orm.dao.ClusterDAO;
+import org.apache.ambari.server.orm.dao.HostDAO;
+import org.apache.ambari.server.orm.dao.TopologyHostGroupDAO;
+import org.apache.ambari.server.orm.dao.TopologyHostRequestDAO;
+import org.apache.ambari.server.orm.dao.TopologyRequestDAO;
+import org.apache.ambari.server.orm.entities.AlertCurrentEntity;
+import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
+import org.apache.ambari.server.orm.entities.AlertHistoryEntity;
+import org.apache.ambari.server.orm.entities.ClusterConfigEntity;
+import org.apache.ambari.server.orm.entities.ClusterEntity;
+import org.apache.ambari.server.orm.entities.HostEntity;
+import org.apache.ambari.server.orm.entities.TopologyHostGroupEntity;
+import org.apache.ambari.server.orm.entities.TopologyHostInfoEntity;
+import org.apache.ambari.server.orm.entities.TopologyHostRequestEntity;
+import org.apache.ambari.server.orm.entities.TopologyLogicalRequestEntity;
+import org.apache.ambari.server.orm.entities.TopologyRequestEntity;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.Config;
+import org.apache.ambari.server.state.ConfigHelper;
+import org.apache.ambari.server.state.ConfigImpl;
+import org.apache.ambari.server.state.Host;
+import org.apache.ambari.server.utils.EventBusSynchronizer;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+/*
+* Class for host names update.
+* Can be used by command "ambari-server update-host-names /hosts_changes.json"
+*
+* Simple example of hosts_changes.json
+* {
+*  "cluster1" : {
+*     "c6400.ambari.apache.org" : "c6411.ambari.apache.org"
+*  }
+* }
+*
+*/
+public class HostUpdateHelper {
+  private static final Logger LOG = LoggerFactory.getLogger
+          (HostUpdateHelper.class);
+
+  private static final String AUTHENTICATED_USER_NAME = "ambari-host-update";
+
+
+  private PersistService persistService;
+  private Configuration configuration;
+  private Injector injector;
+
+  protected String hostChangesFile;
+  protected Map<String, Map<String, String>> hostChangesFileMap;
+
+
+  @Inject
+  public HostUpdateHelper(PersistService persistService,
+                          Configuration configuration,
+                          Injector injector) {
+    this.persistService = persistService;
+    this.configuration = configuration;
+    this.injector = injector;
+  }
+
+  public void startPersistenceService() {
+    persistService.start();
+  }
+
+  public void stopPersistenceService() {
+    persistService.stop();
+  }
+
+  public String getHostChangesFile() {
+    return hostChangesFile;
+  }
+
+  public void setHostChangesFile(String hostChangesFile) {
+    this.hostChangesFile = hostChangesFile;
+  }
+
+  /**
+   * Extension of main controller module
+   */
+  public static class UpdateHelperModule extends ControllerModule {
+
+    public UpdateHelperModule() throws Exception {
+    }
+
+    @Override
+    protected void configure() {
+      super.configure();
+      EventBusSynchronizer.synchronizeAmbariEventPublisher(binder());
+    }
+  }
+
+  /*
+  * Method which validates json with host changes.
+  * Check cluster and hosts existence.
+  * Check on valid structure of json.
+  * */
+  private void validateHostChanges() throws AmbariException {
+    if (hostChangesFileMap == null && hostChangesFileMap.isEmpty()) {
+      throw new AmbariException(String.format("File with host names changes is null or empty"));
+    }
+
+    AmbariManagementController ambariManagementController = injector.getInstance(AmbariManagementController.class);
+    Clusters clusters = ambariManagementController.getClusters();
+
+    if (clusters != null) {
+
+      for (Map.Entry<String, Map<String, String>> clusterHosts : hostChangesFileMap.entrySet()) {
+        String clusterName = clusterHosts.getKey();
+        Cluster cluster = clusters.getCluster(clusterName);
+
+        if (cluster != null) {
+          Collection<Host> hosts = cluster.getHosts();
+          List<String> invalidHostNames = new ArrayList<>();
+          List<String> hostNames = new ArrayList<>();
+
+          for (Host host : hosts) {
+            hostNames.add(host.getHostName());
+          }
+
+          for (Map.Entry<String,String> hostPair : clusterHosts.getValue().entrySet()) {
+            if (!hostNames.contains(hostPair.getKey())) {
+              invalidHostNames.add(hostPair.getKey());
+            }
+          }
+
+          if (!invalidHostNames.isEmpty()) {
+            throw new AmbariException(String.format("Hostname(s): %s was(were) not found.", StringUtils.join(invalidHostNames, ", ")));
+          }
+        } else {
+          throw new AmbariException(String.format("Cluster %s was not found.", clusterName));
+        }
+      }
+    }
+  }
+
+  /*
+  * Method updates all properties in all configs,
+  * which value contains hostname that should be updated
+  * */
+  private void updateHostsInConfigurations() throws AmbariException {
+    ClusterDAO clusterDAO = injector.getInstance(ClusterDAO.class);
+    AmbariManagementController ambariManagementController = injector.getInstance(AmbariManagementController.class);
+    Clusters clusters = ambariManagementController.getClusters();
+    ConfigHelper configHelper = injector.getInstance(ConfigHelper.class);
+
+    if (clusters != null) {
+
+      // going through all clusters with host pairs from file
+      for (Map.Entry<String, Map<String,String>> clusterHosts : hostChangesFileMap.entrySet()) {
+        String clusterName = clusterHosts.getKey();
+        ClusterEntity clusterEntity = clusterDAO.findByName(clusterName);
+        Cluster cluster = clusters.getCluster(clusterName);
+        Map<String, String> hostMapping = clusterHosts.getValue();
+        List<String> currentHostNames = new ArrayList<>();
+        String updatedPropertyValue;
+
+        for (Map.Entry<String, String> hostPair : hostMapping.entrySet()) {
+          currentHostNames.add(hostPair.getKey());
+        }
+
+        //******************************
+
+        if (clusterEntity != null) {
+          Collection<ClusterConfigEntity> clusterConfigEntities = clusterEntity.getClusterConfigEntities();
+          boolean configUpdated;
+
+          // going through all cluster configs and update property values
+          for (ClusterConfigEntity clusterConfigEntity : clusterConfigEntities) {
+            ConfigImpl config = new ConfigImpl(cluster, clusterConfigEntity, injector);
+            configUpdated = false;
+
+            for (Map.Entry<String,String> property : config.getProperties().entrySet()) {
+
+              updatedPropertyValue = replaceHosts(property.getValue(), currentHostNames, hostMapping);
+
+              if (updatedPropertyValue != null) {
+                Map<String,String> propertiesWithUpdates = config.getProperties();
+                propertiesWithUpdates.put(property.getKey(), updatedPropertyValue);
+                config.setProperties(propertiesWithUpdates);
+                configUpdated = true;
+              }
+            }
+            if (configUpdated) {
+              config.persist(false);
+            }
+          }
+        }
+
+        //******************************
+      }
+    }
+  }
+
+  private String replaceHosts(String propertyValue, List<String> currentHostNames, Map<String,String> hostMapping) {
+    List<String> currentHostNamesWhichPropertyValueIncludes = new ArrayList<>();
+    List<String> hostListForReplace = new ArrayList<>();
+    String updatedPropertyValue = null;
+
+    currentHostNamesWhichPropertyValueIncludes = getHostNamesWhichValueIncludes(currentHostNames, propertyValue);
+
+    if (!currentHostNamesWhichPropertyValueIncludes.isEmpty() && hostMapping != null) {
+      // filter current hosts which are included in other hosts
+      hostListForReplace = filterHostNamesIncludedInOtherHostNames(currentHostNamesWhichPropertyValueIncludes);
+
+      updatedPropertyValue = propertyValue;
+      // create map with replace codes, it will help us to replace every hostname only once
+      // replace hosts in value with codes
+      Map<String, String> hostNameCode = new HashMap<>();
+      int counter = 0;
+      for (String hostName : hostListForReplace) {
+        String code = String.format("{replace_code_%d}", counter++);
+        hostNameCode.put(hostName, code);
+        updatedPropertyValue = updatedPropertyValue.replace(hostName, code);
+      }
+
+      // replace codes with new host names according to ald host names
+      for (String hostName : hostListForReplace) {
+        updatedPropertyValue = updatedPropertyValue.replace(hostNameCode.get(hostName), hostMapping.get(hostName));
+      }
+
+    }
+
+    return updatedPropertyValue;
+  }
+
+
+  /*
+  * Method return host names which are included in value
+  * */
+  private List<String> getHostNamesWhichValueIncludes(List<String> hostNames, String value) {
+    List<String> includedHostNames = new ArrayList<>();
+
+    if (value != null && hostNames != null && !value.isEmpty()) {
+      for (String host : hostNames) {
+        if (value.contains(host)) {
+          includedHostNames.add(host);
+        }
+      }
+    }
+
+    return includedHostNames;
+  }
+
+  /*
+  * Method returns filtered list of host names
+  * which are not includes each other
+  * */
+  private List<String> filterHostNamesIncludedInOtherHostNames(List<String> hostNames) {
+    if (hostNames != null && !hostNames.isEmpty()) {
+      int includeCounter;
+      List<String> hostNamesToExclude = new ArrayList<>();
+      for (String hostNameToCheck : hostNames) {
+        includeCounter = 0;
+        for (String hostName : hostNames) {
+          if (StringUtils.contains(hostName, hostNameToCheck)) {
+            includeCounter++;
+          }
+        }
+        if (includeCounter > 1) {
+          hostNamesToExclude.add(hostNameToCheck);
+        }
+      }
+
+      hostNames.removeAll(hostNamesToExclude);
+      return hostNames;
+    } else {
+      return Collections.emptyList();
+    }
+  }
+
+  /*
+  * Method check if security enabled for clusters from file.
+  * If enabled for someone, then we will throw exception
+  * and put message to log.
+  * */
+  private void checkForSecurity() throws AmbariException {
+    AmbariManagementController ambariManagementController = injector.getInstance(AmbariManagementController.class);
+    Clusters clusters = ambariManagementController.getClusters();
+    List<String> clustersInSecure = new ArrayList<>();
+
+    if (clusters != null) {
+      for (String clusterName : hostChangesFileMap.keySet()) {
+        Cluster cluster = clusters.getCluster(clusterName);
+        Config clusterEnv = cluster.getDesiredConfigByType(ConfigHelper.CLUSTER_ENV);
+        if (clusterEnv != null) {
+          String securityEnabled = clusterEnv.getProperties().get(KerberosHelper.SECURITY_ENABLED_PROPERTY_NAME);
+          if (securityEnabled.toLowerCase().equals("true")) {
+            clustersInSecure.add(clusterName);
+          }
+        }
+      }
+
+      if (!clustersInSecure.isEmpty()) {
+        throw new AmbariException(String.format("Cluster(s) %s from file, is(are) in secure mode. Please, turn off security mode.",
+                StringUtils.join(clustersInSecure, ", ")));
+      }
+    }
+
+  }
+
+  /*
+  * Method initialize Map with json data from file
+  * */
+  private void initHostChangesFileMap() throws AmbariException {
+    JsonObject hostChangesJsonObject = configuration.getHostChangesJson(hostChangesFile);
+    hostChangesFileMap = new HashMap<>();
+
+    for (Map.Entry<String, JsonElement> clusterEntry : hostChangesJsonObject.entrySet()) {
+      try {
+        Gson gson = new Gson();
+        hostChangesFileMap.put(clusterEntry.getKey(), gson.fromJson(clusterEntry.getValue(), Map.class));
+      } catch(Exception e) {
+        throw new AmbariException("Error occurred during mapping Json to Map structure. Please check json structure in file.", e);
+      }
+    }
+  }
+
+  /*
+  * Method updates host names in db for hosts table..
+  * */
+  private void updateHostsInDB() {
+    ClusterDAO clusterDAO = injector.getInstance(ClusterDAO.class);
+    HostDAO hostDAO = injector.getInstance(HostDAO.class);
+
+    for (Map.Entry<String, Map<String,String>> clusterHosts : hostChangesFileMap.entrySet()) {
+      String clusterName = clusterHosts.getKey();
+      Map<String, String> hostMapping = clusterHosts.getValue();
+      ClusterEntity clusterEntity = clusterDAO.findByName(clusterName);
+      List<String> currentHostNames = new ArrayList<>();
+
+      for (Map.Entry<String, String> hostPair : hostMapping.entrySet()) {
+        currentHostNames.add(hostPair.getKey());
+      }
+
+      if (clusterEntity != null) {
+        Collection<HostEntity> hostEntities = clusterEntity.getHostEntities();
+        for (HostEntity hostEntity : hostEntities) {
+          if (currentHostNames.contains(hostEntity.getHostName())) {
+            hostEntity.setHostName(hostMapping.get(hostEntity.getHostName()));
+            hostDAO.merge(hostEntity);
+          }
+        }
+      }
+    }
+  }
+
+  /*
+  * Method updates Current Alerts host name and
+  * regenerates hash for alert definitions(for alerts to be recreated)
+  * */
+  private void updateHostsForAlertsInDB() {
+    AmbariManagementController ambariManagementController = injector.getInstance(AmbariManagementController.class);
+    AlertsDAO alertsDAO = injector.getInstance(AlertsDAO.class);
+    AlertDefinitionDAO alertDefinitionDAO = injector.getInstance(AlertDefinitionDAO.class);
+    Clusters clusters = ambariManagementController.getClusters();
+
+    if (clusters != null) {
+      Map<String, Cluster> clusterMap = clusters.getClusters();
+
+      if (clusterMap != null) {
+
+        for (Map.Entry<String, Map<String,String>> clusterHosts : hostChangesFileMap.entrySet()) {
+          List<String> currentHostNames = new ArrayList<>();
+          Map<String, String> hostMapping = clusterHosts.getValue();
+          Long clusterId = clusterMap.get(clusterHosts.getKey()).getClusterId();
+
+          for (Map.Entry<String, String> hostPair : hostMapping.entrySet()) {
+            currentHostNames.add(hostPair.getKey());
+          }
+
+          List<AlertCurrentEntity> currentEntities = alertsDAO.findCurrentByCluster(clusterId);
+          for (AlertCurrentEntity alertCurrentEntity : currentEntities) {
+            AlertHistoryEntity alertHistoryEntity = alertCurrentEntity.getAlertHistory();
+            if (currentHostNames.contains(alertHistoryEntity.getHostName())) {
+              alertHistoryEntity.setHostName(hostMapping.get(alertHistoryEntity.getHostName()));
+              alertsDAO.merge(alertHistoryEntity);
+            }
+          }
+
+          List<AlertDefinitionEntity> alertDefinitionEntities = alertDefinitionDAO.findAll(clusterId);
+          for (AlertDefinitionEntity alertDefinitionEntity : alertDefinitionEntities) {
+            alertDefinitionEntity.setHash(UUID.randomUUID().toString());
+            alertDefinitionDAO.merge(alertDefinitionEntity);
+          }
+        }
+      }
+    }
+  }
+
+  /*
+  * Method updates hosts for Topology Requests (Blue Prints logic)
+  * */
+  private void updateHostsForTopologyRequests() {
+    AmbariManagementController ambariManagementController = injector.getInstance(AmbariManagementController.class);
+    TopologyRequestDAO topologyRequestDAO = injector.getInstance(TopologyRequestDAO.class);
+    TopologyHostRequestDAO topologyHostRequestDAO = injector.getInstance(TopologyHostRequestDAO.class);
+    TopologyHostGroupDAO topologyHostGroupDAO = injector.getInstance(TopologyHostGroupDAO.class);
+    Clusters clusters = ambariManagementController.getClusters();
+
+    if (clusters != null) {
+      Map<String, Cluster> clusterMap = clusters.getClusters();
+
+      if (clusterMap != null) {
+
+        for (Map.Entry<String, Map<String, String>> clusterHosts : hostChangesFileMap.entrySet()) {
+          Long clusterId = clusterMap.get(clusterHosts.getKey()).getClusterId();
+          List<TopologyRequestEntity> topologyRequestEntities = topologyRequestDAO.findByClusterId(clusterId);
+          List<String> currentHostNames = new ArrayList<>();
+          Map<String, String> hostMapping = clusterHosts.getValue();
+
+          for (Map.Entry<String, String> hostPair : hostMapping.entrySet()) {
+            currentHostNames.add(hostPair.getKey());
+          }
+
+          for (TopologyRequestEntity topologyRequestEntity : topologyRequestEntities) {
+            TopologyLogicalRequestEntity topologyLogicalRequestEntity = topologyRequestEntity.getTopologyLogicalRequestEntity();
+            Collection<TopologyHostGroupEntity> topologyHostGroupEntities = topologyRequestEntity.getTopologyHostGroupEntities();
+
+            // update topology host infos
+            if (topologyHostGroupEntities != null) {
+              for (TopologyHostGroupEntity topologyHostGroupEntity : topologyHostGroupEntities) {
+                Collection<TopologyHostInfoEntity> topologyHostInfoEntities = topologyHostGroupEntity.getTopologyHostInfoEntities();
+                boolean updatesAvailable = false;
+
+                if (topologyHostGroupEntities != null) {
+                  for (TopologyHostInfoEntity topologyHostInfoEntity : topologyHostInfoEntities) {
+                    if (currentHostNames.contains(topologyHostInfoEntity.getFqdn())) {
+                      topologyHostInfoEntity.setFqdn(hostMapping.get(topologyHostInfoEntity.getFqdn()));
+                      updatesAvailable = true;
+                    }
+                  }
+                }
+                if (updatesAvailable) {
+                  topologyHostGroupDAO.merge(topologyHostGroupEntity);
+                }
+              }
+            }
+
+            // update topology host requests
+            if (topologyLogicalRequestEntity != null) {
+              Collection<TopologyHostRequestEntity> topologyHostRequestEntities = topologyLogicalRequestEntity.getTopologyHostRequestEntities();
+
+              if (topologyHostRequestEntities != null) {
+                for (TopologyHostRequestEntity topologyHostRequestEntity : topologyHostRequestEntities) {
+                  if (currentHostNames.contains(topologyHostRequestEntity.getHostName())) {
+                    topologyHostRequestEntity.setHostName(hostMapping.get(topologyHostRequestEntity.getHostName()));
+                    topologyHostRequestDAO.merge(topologyHostRequestEntity);
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  public static void main(String[] args) throws Exception {
+    try {
+      LOG.info("Host names update started.");
+
+      String hostChangesFile = args[0];
+
+      if (hostChangesFile == null || hostChangesFile.isEmpty()) {
+        throw new AmbariException("Path to file with host names changes is empty or null.");
+      }
+
+      Injector injector = Guice.createInjector(new UpdateHelperModule());
+      HostUpdateHelper hostUpdateHelper = injector.getInstance(HostUpdateHelper.class);
+
+      hostUpdateHelper.setHostChangesFile(hostChangesFile);
+
+      hostUpdateHelper.initHostChangesFileMap();
+
+      hostUpdateHelper.startPersistenceService();
+
+      hostUpdateHelper.validateHostChanges();
+
+      hostUpdateHelper.checkForSecurity();
+
+      hostUpdateHelper.updateHostsInDB();
+
+      hostUpdateHelper.updateHostsForTopologyRequests();
+
+      hostUpdateHelper.updateHostsForAlertsInDB();
+
+      hostUpdateHelper.updateHostsInConfigurations();
+
+      LOG.info("Host names update completed successfully.");
+
+      hostUpdateHelper.stopPersistenceService();
+    } catch (Throwable e) {
+      if (e instanceof AmbariException) {
+        LOG.error("Exception occurred during host names update, failed", e);
+        throw (AmbariException)e;
+      }else{
+        LOG.error("Unexpected error, host names update failed", e);
+        throw new Exception("Unexpected error, host names update failed", e);
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/5491d2ae/ambari-server/src/main/python/ambari-server.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/python/ambari-server.py b/ambari-server/src/main/python/ambari-server.py
index 88df81a..2963322 100755
--- a/ambari-server/src/main/python/ambari-server.py
+++ b/ambari-server/src/main/python/ambari-server.py
@@ -36,10 +36,11 @@ from ambari_server.serverUtils import is_server_runing, refresh_stack_hash
 from ambari_server.serverSetup import reset, setup, setup_jce_policy
 from ambari_server.serverUpgrade import upgrade, upgrade_stack, set_current
 from ambari_server.setupHttps import setup_https, setup_truststore
+from ambari_server.hostUpdate import update_host_names
 
 from ambari_server.setupActions import BACKUP_ACTION, LDAP_SETUP_ACTION, LDAP_SYNC_ACTION, PSTART_ACTION, \
-  REFRESH_STACK_HASH_ACTION, RESET_ACTION, RESTORE_ACTION, SETUP_ACTION, SETUP_SECURITY_ACTION, START_ACTION, \
-  STATUS_ACTION, STOP_ACTION, UPGRADE_ACTION, UPGRADE_STACK_ACTION, SETUP_JCE_ACTION, SET_CURRENT_ACTION
+  REFRESH_STACK_HASH_ACTION, RESET_ACTION, RESTORE_ACTION, UPDATE_HOST_NAMES_ACTION, SETUP_ACTION, SETUP_SECURITY_ACTION, \
+  START_ACTION, STATUS_ACTION, STOP_ACTION, UPGRADE_ACTION, UPGRADE_STACK_ACTION, SETUP_JCE_ACTION, SET_CURRENT_ACTION
 from ambari_server.setupSecurity import setup_ldap, sync_ldap, setup_master_key, setup_ambari_krb5_jaas
 from ambari_server.userInput import get_validated_string_input
 
@@ -516,7 +517,8 @@ def create_user_action_map(args, options):
         SETUP_SECURITY_ACTION: UserActionRestart(setup_security, options),
         REFRESH_STACK_HASH_ACTION: UserAction(refresh_stack_hash_action),
         BACKUP_ACTION: UserActionPossibleArgs(backup, [1, 2], args),
-        RESTORE_ACTION: UserActionPossibleArgs(restore, [1, 2], args)
+        RESTORE_ACTION: UserActionPossibleArgs(restore, [1, 2], args),
+        UPDATE_HOST_NAMES_ACTION: UserActionPossibleArgs(update_host_names, [2], args, options)
       }
   return action_map
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/5491d2ae/ambari-server/src/main/python/ambari_server/hostUpdate.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/python/ambari_server/hostUpdate.py b/ambari-server/src/main/python/ambari_server/hostUpdate.py
new file mode 100644
index 0000000..bfd6651
--- /dev/null
+++ b/ambari-server/src/main/python/ambari_server/hostUpdate.py
@@ -0,0 +1,105 @@
+#!/usr/bin/env python
+
+'''
+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.
+'''
+
+import os
+import sys
+
+from ambari_commons.exceptions import FatalException
+from ambari_server.serverConfiguration import configDefaults, get_java_exe_path, get_ambari_properties, read_ambari_user, \
+                                              parse_properties_file, JDBC_DATABASE_PROPERTY
+from ambari_commons.logging_utils import print_info_msg, print_warning_msg, print_error_msg
+from ambari_server.dbConfiguration import ensure_jdbc_driver_is_installed, LINUX_DBMS_KEYS_LIST
+from ambari_server.serverClassPath import ServerClassPath
+from ambari_server.setupSecurity import ensure_can_start_under_current_user, generate_env
+from ambari_commons.os_utils import run_os_command
+from ambari_server.serverUtils import is_server_runing
+from ambari_server.userInput import get_YN_input
+
+HOST_UPDATE_HELPER_CMD = "{0} -cp {1} " + \
+                            "org.apache.ambari.server.update.HostUpdateHelper {2}" + \
+                            " > " + configDefaults.SERVER_OUT_FILE + " 2>&1"
+
+def update_host_names(args, options):
+  services_stopped = get_YN_input("Please, confirm Ambari services are stopped [y/n] (n)? ", False)
+  if not services_stopped:
+    print 'Exiting...'
+    sys.exit(1)
+
+  pending_commands = get_YN_input("Please, confirm there are no pending commands on cluster [y/n] (n)? ", False)
+  if not pending_commands:
+    print 'Exiting...'
+    sys.exit(1)
+
+  db_backup_done = get_YN_input("Please, confirm you have made backup of the Ambari db [y/n] (n)? ", False)
+  if not db_backup_done:
+    print 'Exiting...'
+    sys.exit(1)
+
+  status, pid = is_server_runing()
+  if status:
+    raise FatalException(1, "Ambari Server should be stopped")
+
+  try:
+    host_mapping_file_path = args[1]
+  except IndexError:
+    #host_mapping file is mandatory
+    raise FatalException(1, "Invalid number of host update arguments. Probably, you forgot to add json file with "
+                            "host changes.")
+
+  if not os.path.isfile(host_mapping_file_path):
+    raise FatalException(1, "Invalid file path or file doesn't exist")
+
+  if not os.access(host_mapping_file_path, os.R_OK):
+    raise FatalException(1, "File is not readable")
+
+  jdk_path = get_java_exe_path()
+
+  if jdk_path is None:
+    print_error_msg("No JDK found, please run the \"setup\" "
+                    "command to install a JDK automatically or install any "
+                    "JDK manually to " + configDefaults.JDK_INSTALL_DIR)
+    sys.exit(1)
+
+  properties = get_ambari_properties()
+  parse_properties_file(options)
+  options.database_index = LINUX_DBMS_KEYS_LIST.index(properties[JDBC_DATABASE_PROPERTY])
+
+  ensure_jdbc_driver_is_installed(options, get_ambari_properties())
+
+  serverClassPath = ServerClassPath(get_ambari_properties(), options)
+  class_path = serverClassPath.get_full_ambari_classpath_escaped_for_shell()
+
+  command = HOST_UPDATE_HELPER_CMD.format(jdk_path, class_path, host_mapping_file_path)
+
+  ambari_user = read_ambari_user()
+  current_user = ensure_can_start_under_current_user(ambari_user)
+  environ = generate_env(options, ambari_user, current_user)
+
+  (retcode, stdout, stderr) = run_os_command(command, env=environ)
+  print_info_msg("Return code from update host names command, retcode = " + str(retcode))
+
+  if retcode > 0:
+    print_error_msg("Error executing update host names, please check the server logs.")
+    raise FatalException(1, 'Host names update failed.')
+  else:
+    print_info_msg('Host names update completed successfully')
+
+
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/5491d2ae/ambari-server/src/main/python/ambari_server/setupActions.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/python/ambari_server/setupActions.py b/ambari-server/src/main/python/ambari_server/setupActions.py
index 6c6e7ea..686ac9a 100644
--- a/ambari-server/src/main/python/ambari_server/setupActions.py
+++ b/ambari-server/src/main/python/ambari_server/setupActions.py
@@ -35,6 +35,7 @@ SET_CURRENT_ACTION = "set-current"
 SETUP_GANGLIA_HTTPS_ACTION = "setup-ganglia-https"
 ENCRYPT_PASSWORDS_ACTION = "encrypt-passwords"
 SETUP_SECURITY_ACTION = "setup-security"
+UPDATE_HOST_NAMES_ACTION = "update-host-names"
 BACKUP_ACTION = "backup"
 RESTORE_ACTION = "restore"
 SETUP_JCE_ACTION = "setup-jce"