You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ro...@apache.org on 2018/11/12 06:02:45 UTC

[cloudstack] branch master updated: vmware: updateVmwareDc API for updating vmware datacenter details (#2919)

This is an automated email from the ASF dual-hosted git repository.

rohit pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/master by this push:
     new d4d91f3  vmware: updateVmwareDc API for updating vmware datacenter details (#2919)
d4d91f3 is described below

commit d4d91f355dbc6b656f28dc0f20c0e687028bb568
Author: Rohit Yadav <ro...@apache.org>
AuthorDate: Mon Nov 12 11:32:36 2018 +0530

    vmware: updateVmwareDc API for updating vmware datacenter details (#2919)
    
    This adds a new API updateVmwareDc that allows admins to update the
    VMware datacenter details of a zone. It also recursively updates
    the cluster_details for any username/password updates
    as well as updates the url detail in cluster_details table and guid
    detail in the host_details table with any newly provided vcenter
    domain/ip. The update API assumes that there is only one vCenter per
    zone. And, since the username/password for each VMware host could be different
    than what gets configured for vcenter at zone level, it does not update the
    username/password in host_details.
    
    Previously, one has to manually update the db with any new vcenter details for the zone.
    
    Signed-off-by: Rohit Yadav <ro...@shapeblue.com>
---
 .../src/main/java/com/cloud/host/dao/HostDao.java  |   2 +
 .../main/java/com/cloud/host/dao/HostDaoImpl.java  |  11 ++
 .../hypervisor/vmware/VmwareDatacenterService.java |   9 +-
 .../vmware/manager/VmwareManagerImpl.java          | 201 +++++++++++++++------
 .../api/command/admin/zone/UpdateVmwareDcCmd.java  | 131 ++++++++++++++
 .../vmware/VmwareDatacenterApiUnitTest.java        |   6 +
 .../vmware/manager/VmwareManagerImplTest.java      | 118 ++++++++++++
 ui/css/cloudstack3.css                             |   8 +
 ui/l10n/en.js                                      |   1 +
 ui/scripts/system.js                               |  61 ++++++-
 10 files changed, 482 insertions(+), 66 deletions(-)

diff --git a/engine/schema/src/main/java/com/cloud/host/dao/HostDao.java b/engine/schema/src/main/java/com/cloud/host/dao/HostDao.java
index 2de3fcd..1fca86c 100644
--- a/engine/schema/src/main/java/com/cloud/host/dao/HostDao.java
+++ b/engine/schema/src/main/java/com/cloud/host/dao/HostDao.java
@@ -85,6 +85,8 @@ public interface HostDao extends GenericDao<HostVO, Long>, StateDao<Status, Stat
 
     List<Long> listAllHosts(long zoneId);
 
+    List<HostVO> listAllHostsByZoneAndHypervisorType(long zoneId, HypervisorType hypervisorType);
+
     List<HostVO> listAllHostsByType(Host.Type type);
 
     HostVO findByPublicIp(String publicIp);
diff --git a/engine/schema/src/main/java/com/cloud/host/dao/HostDaoImpl.java b/engine/schema/src/main/java/com/cloud/host/dao/HostDaoImpl.java
index 6eec7ba..8c8c082 100644
--- a/engine/schema/src/main/java/com/cloud/host/dao/HostDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/host/dao/HostDaoImpl.java
@@ -229,6 +229,7 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
 
         DcSearch = createSearchBuilder();
         DcSearch.and("dc", DcSearch.entity().getDataCenterId(), SearchCriteria.Op.EQ);
+        DcSearch.and("hypervisorType", DcSearch.entity().getHypervisorType(), Op.EQ);
         DcSearch.and("type", DcSearch.entity().getType(), Op.EQ);
         DcSearch.and("status", DcSearch.entity().getStatus(), Op.EQ);
         DcSearch.and("resourceState", DcSearch.entity().getResourceState(), Op.EQ);
@@ -1117,6 +1118,16 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
     }
 
     @Override
+    public List<HostVO> listAllHostsByZoneAndHypervisorType(long zoneId, HypervisorType hypervisorType) {
+        SearchCriteria<HostVO> sc = DcSearch.create();
+        sc.setParameters("dc", zoneId);
+        if (hypervisorType != null) {
+            sc.setParameters("hypervisorType", hypervisorType.toString());
+        }
+        return listBy(sc);
+    }
+
+    @Override
     public List<Long> listClustersByHostTag(String hostTagOnOffering) {
         TransactionLegacy txn = TransactionLegacy.currentTxn();
         PreparedStatement pstmt = null;
diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VmwareDatacenterService.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VmwareDatacenterService.java
index d74c123..5379253 100644
--- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VmwareDatacenterService.java
+++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VmwareDatacenterService.java
@@ -22,6 +22,7 @@ import java.util.List;
 import org.apache.cloudstack.api.command.admin.zone.AddVmwareDcCmd;
 import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcsCmd;
 import org.apache.cloudstack.api.command.admin.zone.RemoveVmwareDcCmd;
+import org.apache.cloudstack.api.command.admin.zone.UpdateVmwareDcCmd;
 
 import com.cloud.exception.DiscoveryException;
 import com.cloud.exception.ResourceInUseException;
@@ -30,9 +31,11 @@ import com.cloud.utils.exception.CloudRuntimeException;
 
 public interface VmwareDatacenterService extends PluggableService {
 
-    public VmwareDatacenterVO addVmwareDatacenter(AddVmwareDcCmd cmd) throws IllegalArgumentException, DiscoveryException, ResourceInUseException;
+    VmwareDatacenterVO addVmwareDatacenter(AddVmwareDcCmd cmd) throws IllegalArgumentException, DiscoveryException, ResourceInUseException;
 
-    public boolean removeVmwareDatacenter(RemoveVmwareDcCmd cmd) throws IllegalArgumentException, ResourceInUseException;
+    VmwareDatacenter updateVmwareDatacenter(UpdateVmwareDcCmd updateVmwareDcCmd);
 
-    public List<? extends VmwareDatacenter> listVmwareDatacenters(ListVmwareDcsCmd cmd) throws IllegalArgumentException, CloudRuntimeException;
+    boolean removeVmwareDatacenter(RemoveVmwareDcCmd cmd) throws IllegalArgumentException, ResourceInUseException;
+
+    List<? extends VmwareDatacenter> listVmwareDatacenters(ListVmwareDcsCmd cmd) throws IllegalArgumentException, CloudRuntimeException;
 }
diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java
index f586f39..643d3ce 100644
--- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java
+++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java
@@ -16,6 +16,42 @@
 // under the License.
 package com.cloud.hypervisor.vmware.manager;
 
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.rmi.RemoteException;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.UUID;
+import java.util.concurrent.Executors;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import javax.inject.Inject;
+import javax.naming.ConfigurationException;
+
+import org.apache.cloudstack.api.command.admin.zone.AddVmwareDcCmd;
+import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcsCmd;
+import org.apache.cloudstack.api.command.admin.zone.RemoveVmwareDcCmd;
+import org.apache.cloudstack.api.command.admin.zone.UpdateVmwareDcCmd;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
+import org.apache.cloudstack.framework.config.ConfigKey;
+import org.apache.cloudstack.framework.config.Configurable;
+import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
+import org.apache.cloudstack.framework.jobs.impl.AsyncJobManagerImpl;
+import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
+import org.apache.cloudstack.utils.identity.ManagementServerNode;
+import org.apache.log4j.Logger;
+
 import com.cloud.agent.AgentManager;
 import com.cloud.agent.Listener;
 import com.cloud.agent.api.AgentControlAnswer;
@@ -36,12 +72,17 @@ import com.cloud.dc.DataCenterVO;
 import com.cloud.dc.dao.ClusterDao;
 import com.cloud.dc.dao.ClusterVSMMapDao;
 import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.event.ActionEvent;
+import com.cloud.event.EventTypes;
 import com.cloud.exception.DiscoveredWithErrorException;
 import com.cloud.exception.DiscoveryException;
 import com.cloud.exception.InvalidParameterValueException;
 import com.cloud.exception.ResourceInUseException;
 import com.cloud.host.Host;
 import com.cloud.host.Status;
+import com.cloud.host.dao.HostDao;
+import com.cloud.host.dao.HostDetailsDao;
+import com.cloud.hypervisor.Hypervisor;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao;
 import com.cloud.hypervisor.vmware.LegacyZoneVO;
@@ -49,6 +90,7 @@ import com.cloud.hypervisor.vmware.VmwareCleanupMaid;
 import com.cloud.hypervisor.vmware.VmwareDatacenter;
 import com.cloud.hypervisor.vmware.VmwareDatacenterService;
 import com.cloud.hypervisor.vmware.VmwareDatacenterVO;
+import com.cloud.hypervisor.vmware.VmwareDatacenterZoneMap;
 import com.cloud.hypervisor.vmware.VmwareDatacenterZoneMapVO;
 import com.cloud.hypervisor.vmware.dao.LegacyZoneDao;
 import com.cloud.hypervisor.vmware.dao.VmwareDatacenterDao;
@@ -71,6 +113,7 @@ import com.cloud.network.Networks.BroadcastDomainType;
 import com.cloud.network.Networks.TrafficType;
 import com.cloud.network.VmwareTrafficLabel;
 import com.cloud.network.dao.CiscoNexusVSMDeviceDao;
+import com.cloud.org.Cluster;
 import com.cloud.org.Cluster.ClusterType;
 import com.cloud.secstorage.CommandExecLogDao;
 import com.cloud.server.ConfigurationServer;
@@ -88,6 +131,7 @@ import com.cloud.utils.concurrency.NamedThreadFactory;
 import com.cloud.utils.db.DB;
 import com.cloud.utils.db.GlobalLock;
 import com.cloud.utils.db.Transaction;
+import com.cloud.utils.db.TransactionCallback;
 import com.cloud.utils.db.TransactionCallbackNoReturn;
 import com.cloud.utils.db.TransactionStatus;
 import com.cloud.utils.exception.CloudRuntimeException;
@@ -96,41 +140,9 @@ import com.cloud.utils.ssh.SshHelper;
 import com.cloud.vm.DomainRouterVO;
 import com.cloud.vm.dao.UserVmCloneSettingDao;
 import com.cloud.vm.dao.VMInstanceDao;
+import com.google.common.base.Strings;
 import com.vmware.vim25.AboutInfo;
 import com.vmware.vim25.ManagedObjectReference;
-import org.apache.cloudstack.api.command.admin.zone.AddVmwareDcCmd;
-import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcsCmd;
-import org.apache.cloudstack.api.command.admin.zone.RemoveVmwareDcCmd;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
-import org.apache.cloudstack.framework.config.ConfigKey;
-import org.apache.cloudstack.framework.config.Configurable;
-import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
-import org.apache.cloudstack.framework.jobs.impl.AsyncJobManagerImpl;
-import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
-import org.apache.cloudstack.utils.identity.ManagementServerNode;
-import org.apache.log4j.Logger;
-
-import javax.inject.Inject;
-import javax.naming.ConfigurationException;
-import java.io.File;
-import java.io.IOException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.rmi.RemoteException;
-import java.time.Duration;
-import java.time.Instant;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Random;
-import java.util.UUID;
-import java.util.concurrent.Executors;
-import java.util.concurrent.RejectedExecutionException;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
 
 public class VmwareManagerImpl extends ManagerBase implements VmwareManager, VmwareStorageMount, Listener, VmwareDatacenterService, Configurable {
     private static final Logger s_logger = Logger.getLogger(VmwareManagerImpl.class);
@@ -148,9 +160,13 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
     @Inject
     private NetworkModel _netMgr;
     @Inject
-    private ClusterDao _clusterDao;
+    private ClusterDao clusterDao;
+    @Inject
+    private ClusterDetailsDao clusterDetailsDao;
+    @Inject
+    private HostDao hostDao;
     @Inject
-    private ClusterDetailsDao _clusterDetailsDao;
+    private HostDetailsDao hostDetailsDao;
     @Inject
     private CommandExecLogDao _cmdExecLogDao;
     @Inject
@@ -166,17 +182,17 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
     @Inject
     private HypervisorCapabilitiesDao _hvCapabilitiesDao;
     @Inject
-    private DataCenterDao _dcDao;
+    private DataCenterDao datacenterDao;
     @Inject
-    private VmwareDatacenterDao _vmwareDcDao;
+    private VmwareDatacenterDao vmwareDcDao;
     @Inject
-    private VmwareDatacenterZoneMapDao _vmwareDcZoneMapDao;
+    private VmwareDatacenterZoneMapDao vmwareDatacenterZoneMapDao;
     @Inject
-    private LegacyZoneDao _legacyZoneDao;
+    private LegacyZoneDao legacyZoneDao;
     @Inject
-    private ManagementServerHostPeerDao _mshostPeerDao;
+    private ManagementServerHostPeerDao msHostPeerDao;
     @Inject
-    private ClusterManager _clusterMgr;
+    private ClusterManager clusterManager;
     @Inject
     private ImageStoreDetailsUtil imageStoreDetailsUtil;
     @Inject
@@ -557,13 +573,13 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
         long msid = Long.parseLong(tokens[1]);
         long runid = Long.parseLong(tokens[2]);
 
-        if (_mshostPeerDao.countStateSeenInPeers(msid, runid, ManagementServerHost.State.Down) > 0) {
+        if (msHostPeerDao.countStateSeenInPeers(msid, runid, ManagementServerHost.State.Down) > 0) {
             if (s_logger.isInfoEnabled())
                 s_logger.info("Worker VM's owner management server node has been detected down from peer nodes, recycle it");
             return true;
         }
 
-        if (runid != _clusterMgr.getManagementRunId(msid)) {
+        if (runid != clusterManager.getManagementRunId(msid)) {
             if (s_logger.isInfoEnabled())
                 s_logger.info("Worker VM's owner management server has changed runid, recycle it");
             return true;
@@ -819,16 +835,16 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
 
     @DB
     private void updateClusterNativeHAState(Host host, StartupCommand cmd) {
-        ClusterVO cluster = _clusterDao.findById(host.getClusterId());
+        ClusterVO cluster = clusterDao.findById(host.getClusterId());
         if (cluster.getClusterType() == ClusterType.ExternalManaged) {
             if (cmd instanceof StartupRoutingCommand) {
                 StartupRoutingCommand hostStartupCmd = (StartupRoutingCommand)cmd;
                 Map<String, String> details = hostStartupCmd.getHostDetails();
 
                 if (details.get("NativeHA") != null && details.get("NativeHA").equalsIgnoreCase("true")) {
-                    _clusterDetailsDao.persist(host.getClusterId(), "NativeHA", "true");
+                    clusterDetailsDao.persist(host.getClusterId(), "NativeHA", "true");
                 } else {
-                    _clusterDetailsDao.persist(host.getClusterId(), "NativeHA", "false");
+                    clusterDetailsDao.persist(host.getClusterId(), "NativeHA", "false");
                 }
             }
         }
@@ -1000,6 +1016,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
     public List<Class<?>> getCommands() {
         List<Class<?>> cmdList = new ArrayList<Class<?>>();
         cmdList.add(AddVmwareDcCmd.class);
+        cmdList.add(UpdateVmwareDcCmd.class);
         cmdList.add(RemoveVmwareDcCmd.class);
         cmdList.add(ListVmwareDcsCmd.class);
         return cmdList;
@@ -1040,14 +1057,14 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
         // Zone validation
         validateZone(zoneId);
 
-        VmwareDatacenterZoneMapVO vmwareDcZoneMap = _vmwareDcZoneMapDao.findByZoneId(zoneId);
+        VmwareDatacenterZoneMapVO vmwareDcZoneMap = vmwareDatacenterZoneMapDao.findByZoneId(zoneId);
         // Check if zone is associated with VMware DC
         if (vmwareDcZoneMap != null) {
             // Check if the associated VMware DC matches the one specified in API params
             // This check would yield success as the association exists between same entities (zone and VMware DC)
             // This scenario would result in if the API addVmwareDc is called more than once with same parameters.
             Long associatedVmwareDcId = vmwareDcZoneMap.getVmwareDcId();
-            VmwareDatacenterVO associatedVmwareDc = _vmwareDcDao.findById(associatedVmwareDcId);
+            VmwareDatacenterVO associatedVmwareDc = vmwareDcDao.findById(associatedVmwareDcId);
             if (associatedVmwareDc.getVcenterHost().equalsIgnoreCase(vCenterHost) && associatedVmwareDc.getVmwareDatacenterName().equalsIgnoreCase(vmwareDcName)) {
                 s_logger.info("Ignoring API call addVmwareDc, because VMware DC " + vCenterHost + "/" + vmwareDcName +
                         " is already associated with specified zone with id " + zoneId);
@@ -1063,7 +1080,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
 
         // Check if DC is already part of zone
         // In that case vmware_data_center table should have the DC
-        vmwareDc = _vmwareDcDao.getVmwareDatacenterByGuid(vmwareDcName + "@" + vCenterHost);
+        vmwareDc = vmwareDcDao.getVmwareDatacenterByGuid(vmwareDcName + "@" + vCenterHost);
         if (vmwareDc != null) {
             throw new ResourceInUseException("This DC is already part of other CloudStack zone(s). Cannot add this DC to more zones.");
         }
@@ -1102,12 +1119,12 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
 
             // Add DC to database into vmware_data_center table
             vmwareDc = new VmwareDatacenterVO(guid, vmwareDcName, vCenterHost, userName, password);
-            vmwareDc = _vmwareDcDao.persist(vmwareDc);
+            vmwareDc = vmwareDcDao.persist(vmwareDc);
 
             // Map zone with vmware datacenter
             vmwareDcZoneMap = new VmwareDatacenterZoneMapVO(zoneId, vmwareDc.getId());
 
-            vmwareDcZoneMap = _vmwareDcZoneMapDao.persist(vmwareDcZoneMap);
+            vmwareDcZoneMap = vmwareDatacenterZoneMapDao.persist(vmwareDcZoneMap);
 
             // Set custom field for this DC
             if (addDcCustomFieldDef) {
@@ -1133,6 +1150,70 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
     }
 
     @Override
+    @ActionEvent(eventType = EventTypes.EVENT_ZONE_EDIT, eventDescription = "updating VMware datacenter")
+    public VmwareDatacenter updateVmwareDatacenter(UpdateVmwareDcCmd cmd) {
+        final Long zoneId = cmd.getZoneId();
+        final String userName = cmd.getUsername();
+        final String password = cmd.getPassword();
+        final String vCenterHost = cmd.getVcenter();
+        final String vmwareDcName = cmd.getName();
+        final Boolean isRecursive = cmd.isRecursive();
+
+        final VmwareDatacenterZoneMap vdcMap = vmwareDatacenterZoneMapDao.findByZoneId(zoneId);
+        final VmwareDatacenterVO vmwareDc = vmwareDcDao.findById(vdcMap.getVmwareDcId());
+        if (vmwareDc == null) {
+            throw new CloudRuntimeException("VMWare datacenter does not exist by provided ID");
+        }
+        final String oldVCenterHost = vmwareDc.getVcenterHost();
+
+        if (!Strings.isNullOrEmpty(userName)) {
+            vmwareDc.setUser(userName);
+        }
+        if (!Strings.isNullOrEmpty(password)) {
+            vmwareDc.setPassword(password);
+        }
+        if (!Strings.isNullOrEmpty(vCenterHost)) {
+            vmwareDc.setVcenterHost(vCenterHost);
+        }
+        if (!Strings.isNullOrEmpty(vmwareDcName)) {
+            vmwareDc.setVmwareDatacenterName(vmwareDcName);
+        }
+        vmwareDc.setGuid(String.format("%s@%s", vmwareDc.getVmwareDatacenterName(), vmwareDc.getVcenterHost()));
+
+        return Transaction.execute(new TransactionCallback<VmwareDatacenter>() {
+            @Override
+            public VmwareDatacenter doInTransaction(TransactionStatus status) {
+                if (vmwareDcDao.update(vmwareDc.getId(), vmwareDc)) {
+                    if (isRecursive) {
+                        for (final Cluster cluster : clusterDao.listByDcHyType(zoneId, Hypervisor.HypervisorType.VMware.toString())) {
+                            final Map<String, String> clusterDetails = clusterDetailsDao.findDetails(cluster.getId());
+                            clusterDetails.put("username", vmwareDc.getUser());
+                            clusterDetails.put("password", vmwareDc.getPassword());
+                            final String clusterUrl = clusterDetails.get("url");
+                            if (!oldVCenterHost.equals(vmwareDc.getVcenterHost()) && !Strings.isNullOrEmpty(clusterUrl)) {
+                                clusterDetails.put("url", clusterUrl.replace(oldVCenterHost, vmwareDc.getVcenterHost()));
+                            }
+                            clusterDetailsDao.persist(cluster.getId(), clusterDetails);
+                        }
+                        for (final Host host : hostDao.listAllHostsByZoneAndHypervisorType(zoneId, HypervisorType.VMware)) {
+                            final Map<String, String> hostDetails = hostDetailsDao.findDetails(host.getId());
+                            hostDetails.put("username", vmwareDc.getUser());
+                            hostDetails.put("password", vmwareDc.getPassword());
+                            final String hostGuid = hostDetails.get("guid");
+                            if (!Strings.isNullOrEmpty(hostGuid)) {
+                                hostDetails.put("guid", hostGuid.replace(oldVCenterHost, vmwareDc.getVcenterHost()));
+                            }
+                            hostDetailsDao.persist(host.getId(), hostDetails);
+                        }
+                    }
+                    return vmwareDc;
+                }
+                return null;
+            }
+        });
+    }
+
+    @Override
     public boolean removeVmwareDatacenter(RemoveVmwareDcCmd cmd) throws ResourceInUseException {
         Long zoneId = cmd.getZoneId();
         // Validate Id of zone
@@ -1148,14 +1229,14 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
         String userName;
         String password;
         DatacenterMO dcMo = null;
-        final VmwareDatacenterZoneMapVO vmwareDcZoneMap = _vmwareDcZoneMapDao.findByZoneId(zoneId);
+        final VmwareDatacenterZoneMapVO vmwareDcZoneMap = vmwareDatacenterZoneMapDao.findByZoneId(zoneId);
         // Check if zone is associated with VMware DC
         if (vmwareDcZoneMap == null) {
             throw new CloudRuntimeException("Zone " + zoneId + " is not associated with any VMware datacenter.");
         }
 
         final long vmwareDcId = vmwareDcZoneMap.getVmwareDcId();
-        vmwareDatacenter = _vmwareDcDao.findById(vmwareDcId);
+        vmwareDatacenter = vmwareDcDao.findById(vmwareDcId);
         vmwareDcName = vmwareDatacenter.getVmwareDatacenterName();
         vCenterHost = vmwareDatacenter.getVcenterHost();
         userName = vmwareDatacenter.getUser();
@@ -1164,9 +1245,9 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
             @Override
             public void doInTransactionWithoutResult(TransactionStatus status) {
                 // Remove the VMware datacenter entry in table vmware_data_center
-                _vmwareDcDao.remove(vmwareDcId);
+                vmwareDcDao.remove(vmwareDcId);
                 // Remove the map entry in table vmware_data_center_zone_map
-                _vmwareDcZoneMapDao.remove(vmwareDcZoneMap.getId());
+                vmwareDatacenterZoneMapDao.remove(vmwareDcZoneMap.getId());
             }
         });
 
@@ -1217,7 +1298,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
 
     private void validateZoneWithResources(Long zoneId, String errStr) throws ResourceInUseException {
         // Check if zone has resources? - For now look for clusters
-        List<ClusterVO> clusters = _clusterDao.listByZoneId(zoneId);
+        List<ClusterVO> clusters = clusterDao.listByZoneId(zoneId);
         if (clusters != null && clusters.size() > 0) {
             // Look for VMware hypervisor.
             for (ClusterVO cluster : clusters) {
@@ -1231,7 +1312,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
     @Override
     public boolean isLegacyZone(long dcId) {
         boolean isLegacyZone = false;
-        LegacyZoneVO legacyZoneVo = _legacyZoneDao.findByZoneId(dcId);
+        LegacyZoneVO legacyZoneVo = legacyZoneDao.findByZoneId(dcId);
         if (legacyZoneVo != null) {
             isLegacyZone = true;
         }
@@ -1250,13 +1331,13 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
         doesZoneExist(zoneId);
 
         // Check if zone is associated with VMware DC
-        vmwareDcZoneMap = _vmwareDcZoneMapDao.findByZoneId(zoneId);
+        vmwareDcZoneMap = vmwareDatacenterZoneMapDao.findByZoneId(zoneId);
         if (vmwareDcZoneMap == null) {
             return null;
         }
         // Retrieve details of VMware DC associated with zone.
         vmwareDcId = vmwareDcZoneMap.getVmwareDcId();
-        vmwareDatacenter = _vmwareDcDao.findById(vmwareDcId);
+        vmwareDatacenter = vmwareDcDao.findById(vmwareDcId);
         vmwareDcList.add(vmwareDatacenter);
 
         // Currently a zone can have only 1 VMware DC associated with.
@@ -1266,7 +1347,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
 
     private void doesZoneExist(Long zoneId) throws InvalidParameterValueException {
         // Check if zone with specified id exists
-        DataCenterVO zone = _dcDao.findById(zoneId);
+        DataCenterVO zone = datacenterDao.findById(zoneId);
         if (zone == null) {
             throw new InvalidParameterValueException("Can't find zone by the id specified.");
         }
diff --git a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/UpdateVmwareDcCmd.java b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/UpdateVmwareDcCmd.java
new file mode 100644
index 0000000..e428947
--- /dev/null
+++ b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/UpdateVmwareDcCmd.java
@@ -0,0 +1,131 @@
+// 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.cloudstack.api.command.admin.zone;
+
+import javax.inject.Inject;
+
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.VmwareDatacenterResponse;
+import org.apache.cloudstack.api.response.ZoneResponse;
+import org.apache.log4j.Logger;
+
+import com.cloud.hypervisor.vmware.VmwareDatacenter;
+import com.cloud.hypervisor.vmware.VmwareDatacenterService;
+import com.cloud.user.Account;
+
+@APICommand(name = UpdateVmwareDcCmd.APINAME, description = "Updates a VMware datacenter details for a zone",
+        responseObject = VmwareDatacenterResponse.class, responseHasSensitiveInfo = false,
+        since = "4.12.0", authorized = {RoleType.Admin})
+public class UpdateVmwareDcCmd extends BaseCmd {
+    public static final Logger LOG = Logger.getLogger(UpdateVmwareDcCmd.class);
+
+    static final String APINAME = "updateVmwareDc";
+
+    @Inject
+    public VmwareDatacenterService vmwareDatacenterService;
+
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+
+    @Parameter(name = ApiConstants.ZONE_ID, type = CommandType.UUID,
+            entityType = ZoneResponse.class, required = true, description = "The zone ID")
+    private Long zoneId;
+
+    @Parameter(name = ApiConstants.NAME, type = CommandType.STRING,
+            description = "VMware datacenter name.")
+    private String name;
+
+    @Parameter(name = ApiConstants.VCENTER, type = CommandType.STRING,
+            description = "The name/IP of vCenter. Make sure it is IP address or full qualified domain name for host running vCenter server.")
+    private String vCenter;
+
+    @Parameter(name = ApiConstants.USERNAME, type = CommandType.STRING,
+            description = "The username required to connect to resource.")
+    private String username;
+
+    @Parameter(name = ApiConstants.PASSWORD, type = CommandType.STRING,
+            description = "The password for specified username.")
+    private String password;
+
+    @Parameter(name = ApiConstants.IS_RECURSIVE, type = CommandType.BOOLEAN,
+            description = "Specify if cluster level username/password/url and host level guid need to be updated as well. By default this is true.")
+    private Boolean recursive = true;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public long getZoneId() {
+        return zoneId;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getVcenter() {
+        return vCenter;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public Boolean isRecursive() {
+        return recursive;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public void execute() {
+        final VmwareDatacenter vmwareDatacenter = vmwareDatacenterService.updateVmwareDatacenter(this);
+        if (vmwareDatacenter == null) {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update VMware datacenter");
+        }
+        final VmwareDatacenterResponse response = new VmwareDatacenterResponse();
+        response.setId(vmwareDatacenter.getUuid());
+        response.setName(vmwareDatacenter.getVmwareDatacenterName());
+        response.setResponseName(getCommandName());
+        response.setObjectName("vmwaredc");
+        setResponseObject(response);
+    }
+
+    @Override
+    public String getCommandName() {
+        return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        return Account.ACCOUNT_ID_SYSTEM;
+    }
+}
\ No newline at end of file
diff --git a/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java b/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java
index e835a0b..eb04139 100644
--- a/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java
+++ b/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java
@@ -36,6 +36,7 @@ import com.cloud.exception.DiscoveryException;
 import com.cloud.exception.InvalidParameterValueException;
 import com.cloud.exception.ResourceInUseException;
 import com.cloud.host.dao.HostDao;
+import com.cloud.host.dao.HostDetailsDao;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao;
 import com.cloud.hypervisor.vmware.dao.LegacyZoneDao;
@@ -357,6 +358,11 @@ public class VmwareDatacenterApiUnitTest {
         }
 
         @Bean
+        public HostDetailsDao hostDetailsDao() {
+            return Mockito.mock(HostDetailsDao.class);
+        }
+
+        @Bean
         public NetworkModel networkModel() {
             return Mockito.mock(NetworkModel.class);
         }
diff --git a/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImplTest.java b/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImplTest.java
new file mode 100644
index 0000000..499ed24
--- /dev/null
+++ b/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImplTest.java
@@ -0,0 +1,118 @@
+// 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 com.cloud.hypervisor.vmware.manager;
+
+import java.util.Collections;
+import java.util.Map;
+
+import org.apache.cloudstack.api.command.admin.zone.UpdateVmwareDcCmd;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.Spy;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import com.cloud.dc.ClusterDetailsDao;
+import com.cloud.dc.ClusterVO;
+import com.cloud.dc.dao.ClusterDao;
+import com.cloud.host.HostVO;
+import com.cloud.host.dao.HostDao;
+import com.cloud.host.dao.HostDetailsDao;
+import com.cloud.hypervisor.Hypervisor;
+import com.cloud.hypervisor.vmware.VmwareDatacenter;
+import com.cloud.hypervisor.vmware.VmwareDatacenterVO;
+import com.cloud.hypervisor.vmware.VmwareDatacenterZoneMapVO;
+import com.cloud.hypervisor.vmware.dao.VmwareDatacenterDao;
+import com.cloud.hypervisor.vmware.dao.VmwareDatacenterZoneMapDao;
+
+@RunWith(MockitoJUnitRunner.class)
+public class VmwareManagerImplTest {
+
+    @Spy
+    @InjectMocks
+    private VmwareManagerImpl vmwareManager;
+
+    @Mock
+    private UpdateVmwareDcCmd updateVmwareDcCmd;
+    @Mock
+    private VmwareDatacenterDao vmwareDcDao;
+    @Mock
+    private VmwareDatacenterZoneMapDao vmwareDatacenterZoneMapDao;
+    @Mock
+    private ClusterDao clusterDao;
+    @Mock
+    private ClusterDetailsDao clusterDetailsDao;
+    @Mock
+    private HostDao hostDao;
+    @Mock
+    private HostDetailsDao hostDetailsDao;
+    @Mock
+    private Map<String, String> clusterDetails;
+    @Mock
+    private Map<String, String> hostDetails;
+
+    @Before
+    public void beforeTest() {
+        VmwareDatacenterZoneMapVO vmwareDatacenterZoneMap = new VmwareDatacenterZoneMapVO();
+        vmwareDatacenterZoneMap.setZoneId(1);
+        vmwareDatacenterZoneMap.setVmwareDcId(1);
+        VmwareDatacenterVO vmwareDatacenterVO = new VmwareDatacenterVO(1, "some-guid", "some-name", "10.1.1.1", "username", "password");
+
+        Mockito.doReturn(vmwareDatacenterZoneMap).when(vmwareDatacenterZoneMapDao).findByZoneId(Mockito.anyLong());
+        Mockito.doReturn(vmwareDatacenterVO).when(vmwareDcDao).findById(Mockito.anyLong());
+        Mockito.doReturn(1L).when(updateVmwareDcCmd).getZoneId();
+    }
+
+    @Test
+    public void updateVmwareDatacenterNoUpdate() {
+        VmwareDatacenter vmwareDatacenter = vmwareManager.updateVmwareDatacenter(updateVmwareDcCmd);
+        Assert.assertNull(vmwareDatacenter);
+    }
+
+    @Test
+    public void updateVmwareDatacenterNormalUpdate() {
+        Mockito.doReturn("some-new-username").when(updateVmwareDcCmd).getUsername();
+        Mockito.doReturn("some-new-password").when(updateVmwareDcCmd).getPassword();
+        Mockito.doReturn("some-new-vcenter-address").when(updateVmwareDcCmd).getVcenter();
+        Mockito.doReturn(true).when(updateVmwareDcCmd).isRecursive();
+        Mockito.doReturn(true).when(vmwareDcDao).update(Mockito.anyLong(), Mockito.any(VmwareDatacenterVO.class));
+        Mockito.doReturn(Collections.singletonList(new ClusterVO(1, 1, "some-cluster"))).when(clusterDao).listByDcHyType(Mockito.anyLong(), Mockito.anyString());
+        Mockito.doReturn(clusterDetails).when(clusterDetailsDao).findDetails(Mockito.anyLong());
+
+        final HostVO host = new HostVO("someGuid");
+        host.setDataCenterId(1);
+        host.setHypervisorType(Hypervisor.HypervisorType.VMware);
+        Mockito.doReturn(Collections.singletonList(host)).when(hostDao).listAllHostsByZoneAndHypervisorType(Mockito.anyLong(), Mockito.any());
+        Mockito.doReturn(hostDetails).when(hostDetailsDao).findDetails(Mockito.anyLong());
+        Mockito.doReturn("some-old-guid").when(hostDetails).get("guid");
+        Mockito.doReturn(hostDetails).when(hostDetailsDao).findDetails(Mockito.anyLong());
+
+        final VmwareDatacenter vmwareDatacenter = vmwareManager.updateVmwareDatacenter(updateVmwareDcCmd);
+
+        Assert.assertEquals(vmwareDatacenter.getUser(), updateVmwareDcCmd.getUsername());
+        Assert.assertEquals(vmwareDatacenter.getPassword(), updateVmwareDcCmd.getPassword());
+        Mockito.verify(clusterDetails, Mockito.times(2)).put(Mockito.anyString(), Mockito.anyString());
+        Mockito.verify(clusterDetailsDao, Mockito.times(1)).persist(Mockito.anyLong(), Mockito.anyMapOf(String.class, String.class));
+        Mockito.verify(hostDetails, Mockito.times(3)).put(Mockito.anyString(), Mockito.anyString());
+        Mockito.verify(hostDetailsDao, Mockito.times(1)).persist(Mockito.anyLong(), Mockito.anyMapOf(String.class, String.class));
+    }
+}
\ No newline at end of file
diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css
index 9eea2e5..59e6235 100644
--- a/ui/css/cloudstack3.css
+++ b/ui/css/cloudstack3.css
@@ -12566,6 +12566,14 @@ div.ui-dialog div.autoscaler div.field-group div.form-container form div.form-it
   background-position: -169px -583px;
 }
 
+.updateVmwareDc .icon {
+  background-position: -265px -148px;
+}
+
+.updateVmwareDc:hover .icon {
+  background-position: -265px -728px;
+}
+
 .stop .icon,
 .removeVmwareDc .icon,
 .release .icon {
diff --git a/ui/l10n/en.js b/ui/l10n/en.js
index 59fa357..e0fb6e7 100644
--- a/ui/l10n/en.js
+++ b/ui/l10n/en.js
@@ -1710,6 +1710,7 @@ var dictionary = {
 "label.update.project.resources":"Update project resources",
 "label.update.ssl":" SSL Certificate",
 "label.update.ssl.cert":" SSL Certificate",
+"label.update.vmware.datacenter":"Update VMware datacenter",
 "label.updating":"Updating",
 "label.upgrade.required":"Upgrade is required",
 "label.upgrade.router.newer.template":"Upgrade Router to Use Newer Template",
diff --git a/ui/scripts/system.js b/ui/scripts/system.js
index e6ba33f..c1c693f 100755
--- a/ui/scripts/system.js
+++ b/ui/scripts/system.js
@@ -8020,6 +8020,58 @@
                                         }
                                     },
 
+                                    updateVmwareDc: {
+                                        label: 'label.update.vmware.datacenter',
+                                        messages: {
+                                            confirm: function (args) {
+                                                return 'label.update.vmware.datacenter';
+                                            },
+                                            notification: function (args) {
+                                                return 'label.update.vmware.datacenter';
+                                            }
+                                        },
+                                        createForm: {
+                                            title: 'label.update.vmware.datacenter',
+                                            fields: {
+                                                name: {
+                                                    label: 'label.vmware.datacenter.name'
+                                                },
+                                                vcenter: {
+                                                    label: 'label.vmware.datacenter.vcenter'
+                                                },
+                                                username: {
+                                                    label: 'label.username'
+                                                },
+                                                password: {
+                                                    label: 'label.password',
+                                                    isPassword: true
+                                                }
+                                            }
+                                        },
+                                        action: function (args) {
+                                            var data = args.data;
+                                            data.zoneid = args.context.physicalResources[0].id;
+                                            $.ajax({
+                                                url: createURL('updateVmwareDc'),
+                                                data: data,
+                                                success: function (json) {
+                                                    args.response.success({
+                                                        data: args.context.physicalResources[0]
+                                                    });
+                                                },
+                                                error: function (XMLHttpResponse) {
+                                                    var errorMsg = parseXMLHttpResponse(XMLHttpResponse);
+                                                    args.response.error(errorMsg);
+                                                }
+                                            });
+                                        },
+                                        notification: {
+                                            poll: function (args) {
+                                                args.complete();
+                                            }
+                                        }
+                                    },
+
                                     removeVmwareDc: {
                                         label: 'label.remove.vmware.datacenter',
                                         messages: {
@@ -22192,9 +22244,12 @@
         var jsonObj = args.context.item;
         var allowedActions =[ 'enableSwift'];
 
-        if (jsonObj.vmwaredcId == null)
-        allowedActions.push('addVmwareDc'); else
-        allowedActions.push('removeVmwareDc');
+        if (jsonObj.vmwaredcId == null) {
+            allowedActions.push('addVmwareDc');
+        } else {
+            allowedActions.push('updateVmwareDc');
+            allowedActions.push('removeVmwareDc');
+        }
 
         if (jsonObj.domainid != null)
         allowedActions.push("releaseDedicatedZone"); else