You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ha...@apache.org on 2022/12/30 07:46:31 UTC

[cloudstack] 01/07: Guest OS mapping improvements - Checks the OS mapping name in hypervisor (VMware, XenServer) - Displays guest OS mappings in UI

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

harikrishna pushed a commit to branch guest-os-mappings-improvements
in repository https://gitbox.apache.org/repos/asf/cloudstack.git

commit fad7a8fcdf4a0fcef6d526d4a485f656b6936317
Author: Suresh Kumar Anaparti <su...@gmail.com>
AuthorDate: Fri Jul 15 17:39:43 2022 +0530

    Guest OS mapping improvements
    - Checks the OS mapping name in hypervisor (VMware, XenServer)
    - Displays guest OS mappings in UI
---
 .../org/apache/cloudstack/api/ApiConstants.java    |  1 +
 .../command/admin/guest/AddGuestOsMappingCmd.java  | 17 ++++++
 .../admin/guest/UpdateGuestOsMappingCmd.java       | 10 ++++
 .../cloud/agent/api/CheckGuestOsMappingAnswer.java | 38 +++++++++++++
 .../agent/api/CheckGuestOsMappingCommand.java      | 54 +++++++++++++++++++
 .../src/main/java/com/cloud/host/dao/HostDao.java  |  2 +
 .../main/java/com/cloud/host/dao/HostDaoImpl.java  | 18 +++++++
 .../hypervisor/vmware/resource/VmwareResource.java | 28 ++++++++++
 .../CitrixCheckGuestOsMappingCommandWrapper.java   | 63 ++++++++++++++++++++++
 .../com/cloud/server/ManagementServerImpl.java     | 53 +++++++++++++++++-
 ui/public/locales/en.json                          |  9 ++++
 ui/src/components/view/ListView.vue                |  9 ++++
 ui/src/config/section/config.js                    | 19 +++++++
 ui/src/views/AutogenView.vue                       | 10 +++-
 .../com/cloud/hypervisor/vmware/mo/ClusterMO.java  | 12 +++++
 .../com/cloud/hypervisor/vmware/mo/HostMO.java     | 11 ++++
 .../hypervisor/vmware/mo/VmwareHypervisorHost.java |  4 ++
 17 files changed, 355 insertions(+), 3 deletions(-)

diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
index e43572ae489..a52eba6e555 100644
--- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
@@ -301,6 +301,7 @@ public class ApiConstants {
     public static final String OS_TYPE_ID = "ostypeid";
     public static final String OS_DISPLAY_NAME = "osdisplayname";
     public static final String OS_NAME_FOR_HYPERVISOR = "osnameforhypervisor";
+    public static final String OS_MAPPING_CHECK_ENABLED = "osmappingcheckenabled";
     public static final String OUTOFBANDMANAGEMENT_POWERSTATE = "outofbandmanagementpowerstate";
     public static final String OUTOFBANDMANAGEMENT_ENABLED = "outofbandmanagementenabled";
     public static final String OUTPUT = "output";
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/guest/AddGuestOsMappingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/guest/AddGuestOsMappingCmd.java
index 79e82d6f5d4..829668b134f 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/guest/AddGuestOsMappingCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/guest/AddGuestOsMappingCmd.java
@@ -58,6 +58,12 @@ public class AddGuestOsMappingCmd extends BaseAsyncCreateCmd {
     @Parameter(name = ApiConstants.OS_NAME_FOR_HYPERVISOR, type = CommandType.STRING, required = true, description = "OS name specific to the hypervisor")
     private String osNameForHypervisor;
 
+    @Parameter(name = ApiConstants.OS_MAPPING_CHECK_ENABLED, type = CommandType.BOOLEAN, required = false, description = "When set to true, checks the guest os mapping name in the hypervisor (supports VMware and XenServer only)", since = "4.18.0")
+    private Boolean osMappingCheckEnabled;
+
+    @Parameter(name = ApiConstants.FORCED, type = CommandType.BOOLEAN, required = false, description = "Forces add guest os mapping, overrides any existing user defined mapping", since = "4.18.0")
+    private Boolean forced;
+
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -82,6 +88,17 @@ public class AddGuestOsMappingCmd extends BaseAsyncCreateCmd {
         return osNameForHypervisor;
     }
 
+    public Boolean getOsMappingCheckEnabled() {
+        if (osMappingCheckEnabled == null) {
+            return false;
+        }
+        return osMappingCheckEnabled;
+    }
+
+    public boolean isForced() {
+        return (forced != null) ? forced : false;
+    }
+
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////
     /////////////////////////////////////////////////////
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/guest/UpdateGuestOsMappingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/guest/UpdateGuestOsMappingCmd.java
index 2683a21dfcf..5080775500d 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/guest/UpdateGuestOsMappingCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/guest/UpdateGuestOsMappingCmd.java
@@ -48,6 +48,9 @@ public class UpdateGuestOsMappingCmd extends BaseAsyncCmd {
     @Parameter(name = ApiConstants.OS_NAME_FOR_HYPERVISOR, type = CommandType.STRING, required = true, description = "Hypervisor specific name for this Guest OS")
     private String osNameForHypervisor;
 
+    @Parameter(name = ApiConstants.OS_MAPPING_CHECK_ENABLED, type = CommandType.BOOLEAN, required = false, description = "When set to true, checks the guest os mapping name in the hypervisor (supports VMware and XenServer only)", since = "4.18.0")
+    private Boolean osMappingCheckEnabled;
+
 /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -60,6 +63,13 @@ public class UpdateGuestOsMappingCmd extends BaseAsyncCmd {
         return osNameForHypervisor;
     }
 
+    public Boolean getOsMappingCheckEnabled() {
+        if (osMappingCheckEnabled == null) {
+            return false;
+        }
+        return osMappingCheckEnabled;
+    }
+
     @Override
     public void execute() {
         GuestOSHypervisor guestOsMapping = _mgr.updateGuestOsMapping(this);
diff --git a/core/src/main/java/com/cloud/agent/api/CheckGuestOsMappingAnswer.java b/core/src/main/java/com/cloud/agent/api/CheckGuestOsMappingAnswer.java
new file mode 100644
index 00000000000..53cfded2335
--- /dev/null
+++ b/core/src/main/java/com/cloud/agent/api/CheckGuestOsMappingAnswer.java
@@ -0,0 +1,38 @@
+//
+// 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.agent.api;
+
+public class CheckGuestOsMappingAnswer extends Answer {
+
+    protected CheckGuestOsMappingAnswer() {
+    }
+
+    public CheckGuestOsMappingAnswer(CheckGuestOsMappingCommand cmd) {
+        super(cmd, true, null);
+    }
+
+    public CheckGuestOsMappingAnswer(CheckGuestOsMappingCommand cmd, String details) {
+        super(cmd, false, details);
+    }
+
+    public CheckGuestOsMappingAnswer(CheckGuestOsMappingCommand cmd, Throwable th) {
+        super(cmd, false, th.getMessage());
+    }
+}
diff --git a/core/src/main/java/com/cloud/agent/api/CheckGuestOsMappingCommand.java b/core/src/main/java/com/cloud/agent/api/CheckGuestOsMappingCommand.java
new file mode 100644
index 00000000000..f58f3e2cefd
--- /dev/null
+++ b/core/src/main/java/com/cloud/agent/api/CheckGuestOsMappingCommand.java
@@ -0,0 +1,54 @@
+//
+// 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.agent.api;
+
+public class CheckGuestOsMappingCommand extends Command {
+    String guestOsName;
+    String guestOsHypervisorMappingName;
+    String hypervisorVersion;
+
+    public CheckGuestOsMappingCommand() {
+        super();
+    }
+
+    public CheckGuestOsMappingCommand(String guestOsName, String guestOsHypervisorMappingName, String hypervisorVersion) {
+        super();
+        this.guestOsName = guestOsName;
+        this.guestOsHypervisorMappingName = guestOsHypervisorMappingName;
+        this.hypervisorVersion = hypervisorVersion;
+    }
+
+    @Override
+    public boolean executeInSequence() {
+        return false;
+    }
+
+    public String getGuestOsName() {
+        return guestOsName;
+    }
+
+    public String getGuestOsHypervisorMappingName() {
+        return guestOsHypervisorMappingName;
+    }
+
+    public String getHypervisorVersion() {
+        return hypervisorVersion;
+    }
+}
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 54d4a5e9ca3..2055891bcaf 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
@@ -141,6 +141,8 @@ public interface HostDao extends GenericDao<HostVO, Long>, StateDao<Status, Stat
 
     HostVO findByName(String name);
 
+    HostVO findHostByHypervisorTypeAndVersion(HypervisorType hypervisorType, String hypervisorVersion);
+
     List<HostVO> listHostsWithActiveVMs(long offeringId);
 
     /**
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 8e1f8f470dd..49b977e6cd0 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
@@ -113,6 +113,7 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
     protected SearchBuilder<HostVO> ResourceStateSearch;
     protected SearchBuilder<HostVO> NameLikeSearch;
     protected SearchBuilder<HostVO> NameSearch;
+    protected SearchBuilder<HostVO> HostHypervisorTypeAndVersionSearch;
     protected SearchBuilder<HostVO> SequenceSearch;
     protected SearchBuilder<HostVO> DirectlyConnectedSearch;
     protected SearchBuilder<HostVO> UnmanagedDirectConnectSearch;
@@ -308,6 +309,13 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
         NameSearch.and("name", NameSearch.entity().getName(), SearchCriteria.Op.EQ);
         NameSearch.done();
 
+        HostHypervisorTypeAndVersionSearch = createSearchBuilder();
+        HostHypervisorTypeAndVersionSearch.and("hypervisorType", HostHypervisorTypeAndVersionSearch.entity().getHypervisorType(), SearchCriteria.Op.EQ);
+        HostHypervisorTypeAndVersionSearch.and("hypervisorVersion", HostHypervisorTypeAndVersionSearch.entity().getHypervisorVersion(), SearchCriteria.Op.EQ);
+        HostHypervisorTypeAndVersionSearch.and("type", HostHypervisorTypeAndVersionSearch.entity().getType(), SearchCriteria.Op.EQ);
+        HostHypervisorTypeAndVersionSearch.and("status", HostHypervisorTypeAndVersionSearch.entity().getStatus(), SearchCriteria.Op.EQ);
+        HostHypervisorTypeAndVersionSearch.done();
+
         SequenceSearch = createSearchBuilder();
         SequenceSearch.and("id", SequenceSearch.entity().getId(), SearchCriteria.Op.EQ);
         // SequenceSearch.addRetrieve("sequence", SequenceSearch.entity().getSequence());
@@ -1398,6 +1406,16 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
         return findOneBy(sc);
     }
 
+    @Override
+    public HostVO findHostByHypervisorTypeAndVersion(HypervisorType hypervisorType, String hypervisorVersion) {
+        SearchCriteria<HostVO> sc = HostHypervisorTypeAndVersionSearch.create();
+        sc.setParameters("hypervisorType", hypervisorType);
+        sc.setParameters("hypervisorVersion", hypervisorVersion);
+        sc.setParameters("type", Host.Type.Routing);
+        sc.setParameters("status", Status.Up);
+        return findOneBy(sc);
+    }
+
     private ResultSet executeSqlGetResultsetForMethodFindHostInZoneToExecuteCommand(HypervisorType hypervisorType, long zoneId, TransactionLegacy tx, String sql) throws SQLException {
         PreparedStatement pstmt = tx.prepareAutoCloseStatement(sql);
         pstmt.setString(1, Objects.toString(hypervisorType));
diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java
index aabebf56bd1..d1ccba3baff 100644
--- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java
+++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java
@@ -47,6 +47,8 @@ import java.util.stream.Collectors;
 import javax.naming.ConfigurationException;
 import javax.xml.datatype.XMLGregorianCalendar;
 
+import com.cloud.agent.api.CheckGuestOsMappingAnswer;
+import com.cloud.agent.api.CheckGuestOsMappingCommand;
 import com.cloud.agent.api.PatchSystemVmAnswer;
 import com.cloud.agent.api.PatchSystemVmCommand;
 import com.cloud.resource.ServerResourceBase;
@@ -306,6 +308,7 @@ import com.vmware.vim25.DistributedVirtualSwitchPortCriteria;
 import com.vmware.vim25.DynamicProperty;
 import com.vmware.vim25.GuestInfo;
 import com.vmware.vim25.GuestNicInfo;
+import com.vmware.vim25.GuestOsDescriptor;
 import com.vmware.vim25.HostCapability;
 import com.vmware.vim25.HostConfigInfo;
 import com.vmware.vim25.HostFileSystemMountInfo;
@@ -604,6 +607,8 @@ public class VmwareResource extends ServerResourceBase implements StoragePoolRes
                 answer = execute((GetVmVncTicketCommand) cmd);
             } else if (clz == GetAutoScaleMetricsCommand.class) {
                 answer = execute((GetAutoScaleMetricsCommand) cmd);
+            } else if (clz == CheckGuestOsMappingCommand.class) {
+                answer = execute((CheckGuestOsMappingCommand) cmd);
             } else {
                 answer = Answer.createUnsupportedCommandAnswer(cmd);
             }
@@ -7715,6 +7720,29 @@ public class VmwareResource extends ServerResourceBase implements StoragePoolRes
         }
     }
 
+    private CheckGuestOsMappingAnswer execute(CheckGuestOsMappingCommand cmd) {
+        String guestOsName = cmd.getGuestOsName();
+        String guestOsMappingName = cmd.getGuestOsHypervisorMappingName();
+        s_logger.info("Checking guest os mapping name: " + guestOsMappingName + " for the guest os: " + guestOsName + " in the hypervisor");
+        try {
+            VmwareContext context = getServiceContext();
+            VmwareHypervisorHost hyperHost = getHyperHost(context);
+            GuestOsDescriptor guestOsDescriptor = hyperHost.getGuestOsDescriptor(guestOsMappingName);
+            if (guestOsDescriptor == null) {
+                return new CheckGuestOsMappingAnswer(cmd, "Guest os mapping name not found in the hypervisor");
+            }
+            s_logger.debug("Matching hypervisor guest os - id: " + guestOsDescriptor.getId() + ", full name: " + guestOsDescriptor.getFullName() + ", family: " + guestOsDescriptor.getFamily());
+            if (guestOsDescriptor.getFullName().equalsIgnoreCase(guestOsName)) {
+                // Extact matching may fail, try with regex?
+                s_logger.debug("Hypervisor guest os name matches with os name: " + guestOsName + " from user");
+            }
+            return new CheckGuestOsMappingAnswer(cmd);
+        } catch (Exception e) {
+            s_logger.error("Failed to check the hypervisor guest os mapping name: " + guestOsMappingName, e);
+            return new CheckGuestOsMappingAnswer(cmd, e.getLocalizedMessage());
+        }
+    }
+
     private Integer getVmwareWindowTimeInterval() {
         Integer windowInterval = VmwareManager.VMWARE_STATS_TIME_WINDOW.value();
         if (windowInterval == null || windowInterval < 20) {
diff --git a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixCheckGuestOsMappingCommandWrapper.java b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixCheckGuestOsMappingCommandWrapper.java
new file mode 100644
index 00000000000..ed16d5bfed3
--- /dev/null
+++ b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixCheckGuestOsMappingCommandWrapper.java
@@ -0,0 +1,63 @@
+//
+// 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.xenserver.resource.wrapper.xenbase;
+
+import java.util.Set;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.CheckGuestOsMappingAnswer;
+import com.cloud.agent.api.CheckGuestOsMappingCommand;
+import com.cloud.hypervisor.xenserver.resource.CitrixResourceBase;
+import com.cloud.resource.CommandWrapper;
+import com.cloud.resource.ResourceWrapper;
+import com.xensource.xenapi.Connection;
+import com.xensource.xenapi.VM;
+
+@ResourceWrapper(handles =  CheckGuestOsMappingCommand.class)
+public final class CitrixCheckGuestOsMappingCommandWrapper extends CommandWrapper<CheckGuestOsMappingCommand, Answer, CitrixResourceBase> {
+
+    private static final Logger s_logger = Logger.getLogger(CitrixCheckGuestOsMappingCommandWrapper.class);
+
+    @Override
+    public Answer execute(final CheckGuestOsMappingCommand command, final CitrixResourceBase citrixResourceBase) {
+        final Connection conn = citrixResourceBase.getConnection();
+        String guestOsName = command.getGuestOsName();
+        String guestOsMappingName = command.getGuestOsHypervisorMappingName();
+        try {
+            s_logger.info("Checking guest os mapping name: " + guestOsMappingName + " for the guest os: " + guestOsName + " in the hypervisor");
+            final Set<VM> vms = VM.getAll(conn);
+            if (vms.size() == 0) {
+                return new CheckGuestOsMappingAnswer(command, "Guest os mapping name not found in the hypervisor");
+            }
+            for (VM vm : vms) {
+                if (guestOsMappingName.equalsIgnoreCase(vm.getNameLabel(conn))) {
+                    // Extact matching may fail, try with regex?
+                    s_logger.debug("Hypervisor guest os name matches with os name: " + guestOsName + " from user");
+                }
+            }
+            return new CheckGuestOsMappingAnswer(command);
+        } catch (final Exception e) {
+            s_logger.error("Failed to find the hypervisor guest os mapping name: " + guestOsMappingName, e);
+            return new CheckGuestOsMappingAnswer(command, e.getLocalizedMessage());
+        }
+    }
+}
\ No newline at end of file
diff --git a/server/src/main/java/com/cloud/server/ManagementServerImpl.java b/server/src/main/java/com/cloud/server/ManagementServerImpl.java
index aa362b2dc63..29c66bfed6f 100644
--- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java
+++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java
@@ -51,6 +51,8 @@ import com.cloud.user.UserData;
 import com.cloud.user.UserDataVO;
 import com.cloud.user.dao.UserDataDao;
 import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.CheckGuestOsMappingAnswer;
+import com.cloud.agent.api.CheckGuestOsMappingCommand;
 import com.cloud.agent.api.Command;
 import com.cloud.agent.api.PatchSystemVmAnswer;
 import com.cloud.agent.api.PatchSystemVmCommand;
@@ -2599,6 +2601,9 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
     @Override
     public Pair<List<? extends GuestOSHypervisor>, Integer> listGuestOSMappingByCriteria(final ListGuestOsMappingCmd cmd) {
         final Filter searchFilter = new Filter(GuestOSHypervisorVO.class, "hypervisorType", true, cmd.getStartIndex(), cmd.getPageSizeVal());
+        searchFilter.addOrderBy(GuestOSHypervisorVO.class, "hypervisorVersion", false);
+        searchFilter.addOrderBy(GuestOSHypervisorVO.class, "guestOsId", true);
+        searchFilter.addOrderBy(GuestOSHypervisorVO.class, "created", false);
         final Long id = cmd.getId();
         final Long osTypeId = cmd.getOsTypeId();
         final String hypervisor = cmd.getHypervisor();
@@ -2671,9 +2676,28 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
         final GuestOSHypervisorVO duplicate = _guestOSHypervisorDao.findByOsIdAndHypervisorAndUserDefined(guestOs.getId(), hypervisorType.toString(), hypervisorVersion, true);
 
         if (duplicate != null) {
-            throw new InvalidParameterValueException(
-                    "Mapping from hypervisor : " + hypervisorType.toString() + ", version : " + hypervisorVersion + " and guest OS : " + guestOs.getDisplayName() + " already exists!");
+            if (!cmd.isForced()) {
+                throw new InvalidParameterValueException(
+                        "Mapping from hypervisor : " + hypervisorType.toString() + ", version : " + hypervisorVersion + " and guest OS : " + guestOs.getDisplayName() + " already exists!");
+            }
+
+            if (cmd.getOsMappingCheckEnabled()) {
+                checkGuestOSHypervisorMapping(hypervisorType, hypervisorVersion, guestOs.getDisplayName(), osNameForHypervisor);
+            }
+
+            final long guestOsId = duplicate.getId();
+            final GuestOSHypervisorVO guestOsHypervisor = _guestOSHypervisorDao.createForUpdate(guestOsId);
+            guestOsHypervisor.setGuestOsName(osNameForHypervisor);
+            if (_guestOSHypervisorDao.update(guestOsId, guestOsHypervisor)) {
+                return _guestOSHypervisorDao.findById(guestOsId);
+            }
+            return null;
+        }
+
+        if (cmd.getOsMappingCheckEnabled()) {
+            checkGuestOSHypervisorMapping(hypervisorType, hypervisorVersion, guestOs.getDisplayName(), osNameForHypervisor);
         }
+
         final GuestOSHypervisorVO guestOsMapping = new GuestOSHypervisorVO();
         guestOsMapping.setGuestOsId(guestOs.getId());
         guestOsMapping.setGuestOsName(osNameForHypervisor);
@@ -2681,7 +2705,24 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
         guestOsMapping.setHypervisorVersion(hypervisorVersion);
         guestOsMapping.setIsUserDefined(true);
         return _guestOSHypervisorDao.persist(guestOsMapping);
+    }
 
+    private void checkGuestOSHypervisorMapping(HypervisorType hypervisorType, String hypervisorVersion, String guestOsName, String guestOsNameForHypervisor) {
+        if (!isGuestOSMappingCheckSupported(hypervisorType)) {
+            throw new InvalidParameterValueException(String.format("Guest OS mapping check is not supported for hypervisor: %s", hypervisorType.toString()));
+        }
+        final HostVO host = _hostDao.findHostByHypervisorTypeAndVersion(hypervisorType, hypervisorVersion);
+        if (host == null) {
+            throw new CloudRuntimeException(String.format("No host available with hypervisor: %s and version: %s, unable to check the guest os mapping", hypervisorType.toString(), hypervisorVersion));
+        }
+        CheckGuestOsMappingAnswer answer = (CheckGuestOsMappingAnswer) _agentMgr.easySend(host.getId(), new CheckGuestOsMappingCommand(guestOsName, guestOsNameForHypervisor, hypervisorVersion));
+        if (answer == null || !answer.getResult()) {
+            throw new CloudRuntimeException(String.format("Invalid hypervisor os mapping: %s for guest os: %s, hypervisor: %s and version: %s", guestOsNameForHypervisor, guestOsName, hypervisorType.toString(), hypervisorVersion));
+        }
+    }
+
+    private boolean isGuestOSMappingCheckSupported(HypervisorType hypervisorType) {
+        return (hypervisorType == HypervisorType.VMware || hypervisorType == HypervisorType.XenServer);
     }
 
     @Override
@@ -2811,6 +2852,14 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
             throw new InvalidParameterValueException("Unable to modify system defined Guest OS mapping");
         }
 
+        if (cmd.getOsMappingCheckEnabled()) {
+            GuestOS guestOs = ApiDBUtils.findGuestOSById(guestOsHypervisorHandle.getGuestOsId());
+            if (guestOs == null) {
+                throw new InvalidParameterValueException("Unable to find the guest OS for the mapping");
+            }
+            checkGuestOSHypervisorMapping(HypervisorType.getType(guestOsHypervisorHandle.getHypervisorType()), guestOsHypervisorHandle.getHypervisorVersion(), guestOs.getDisplayName(), osNameForHypervisor);
+        }
+
         final GuestOSHypervisorVO guestOsHypervisor = _guestOSHypervisorDao.createForUpdate(id);
         guestOsHypervisor.setGuestOsName(osNameForHypervisor);
         if (_guestOSHypervisorDao.update(id, guestOsHypervisor)) {
diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json
index 571f5f96faa..cf9661ad174 100644
--- a/ui/public/locales/en.json
+++ b/ui/public/locales/en.json
@@ -785,6 +785,7 @@
 "label.guest.ip.range": "Guest IP range",
 "label.guest.netmask": "Guest netmask",
 "label.guest.networks": "Guest networks",
+"label.guest.os.mappings": "Guest OS mappings",
 "label.guest.start.ip": "Guest start IP",
 "label.guest.traffic": "Guest traffic",
 "label.guestcidraddress": "Guest CIDR",
@@ -954,6 +955,7 @@
 "label.issourcenat": "Source NAT",
 "label.isstaticnat": "Static NAT",
 "label.issystem": "Is system",
+"label.isuserdefined": "User defined",
 "label.isvolatile": "Volatile",
 "label.items": "items",
 "label.items.selected": "item(s) selected",
@@ -984,6 +986,7 @@
 "label.kubernetes.version.update": "Manage Kubernetes version",
 "label.kubernetesversionid": "Kubernetes version",
 "label.kubernetesversionname": "Kubernetes version",
+"label.kvm": "KVM",
 "label.kvmnetworklabel": "KVM traffic label",
 "label.l2": "L2",
 "label.l2gatewayserviceuuid": "L2 Gateway Service UUID",
@@ -1046,6 +1049,7 @@
 "label.logout": "Logout",
 "label.lun": "LUN",
 "label.lun.number": "LUN #",
+"label.lxc": "LXC",
 "label.lxcnetworklabel": "LXC traffic label",
 "label.macaddress": "MAC address",
 "label.macaddress.example": "The MAC address. Example: 01:23:45:67:89:ab",
@@ -1242,6 +1246,8 @@
 "label.optional": "Optional",
 "label.order": "Order",
 "label.oscategoryid": "OS preference",
+"label.osdisplayname": "OS name",
+"label.osnameforhypervisor": "Hypervisor mapping name",
 "label.ostypeid": "OS type",
 "label.osdistribution": "OS distribution",
 "label.ostypename": "OS type",
@@ -1260,6 +1266,7 @@
 "label.overridepublictraffic": "Override public-traffic",
 "label.override.root.diskoffering": "Override root disk offering",
 "label.ovf.properties": "vApp properties",
+"label.ovm3": "OVM3",
 "label.ovm3cluster": "Native Clustering",
 "label.ovm3networklabel": "OVM3 traffic label",
 "label.ovm3pool": "Native pooling",
@@ -1905,6 +1912,7 @@
 "label.vms": "VMs",
 "label.vmstate": "VM state",
 "label.vmtotal": "Total of VMs",
+"label.vmware": "VMWare",
 "label.vmware.storage.policy": "VMWare storage policy",
 "label.vmwaredcid": "VMware datacenter ID",
 "label.vmwaredcname": "VMware datacenter name",
@@ -1967,6 +1975,7 @@
 "label.writeio": "Write (IO)",
 "label.writethrough": "Write-through",
 "label.xennetworklabel": "XenServer Traffic Label",
+"label.xenserver": "XenServer",
 "label.xenservertoolsversion61plus": "Original XS Version is 6.1+",
 "label.yes": "Yes",
 "label.yourinstance": "Your instance",
diff --git a/ui/src/components/view/ListView.vue b/ui/src/components/view/ListView.vue
index 6111300881c..e322b1b28f3 100644
--- a/ui/src/components/view/ListView.vue
+++ b/ui/src/components/view/ListView.vue
@@ -178,8 +178,17 @@
       <span v-if="$route.name === 'hypervisorcapability'">
         <router-link :to="{ path: $route.path + '/' + record.id }">{{ text }}</router-link>
       </span>
+      <span v-else-if="$route.name === 'guestoshypervisormapping'">
+        <router-link :to="{ path: $route.path + '/' + record.id }">{{ text }}</router-link>
+      </span>
       <span v-else>{{ text }}</span>
     </template>
+    <!-- <template #guestosmapping="{ text, record }">
+      <span v-if="$route.name === 'guestoshypervisormapping'">
+        <router-link :to="{ path: $route.path + '/' + record.id }">{{ text }}</router-link>
+      </span>
+      <span v-else>{{ text }}</span>
+    </template> -->
     <template #state="{ text, record }">
       <status v-if="$route.path.startsWith('/host')" :text="getHostState(record)" displayText />
       <status v-else :text="text ? text : ''" displayText :styles="{ 'min-width': '80px' }" />
diff --git a/ui/src/config/section/config.js b/ui/src/config/section/config.js
index 5dc3a76e88a..da9a1ea3f10 100644
--- a/ui/src/config/section/config.js
+++ b/ui/src/config/section/config.js
@@ -82,6 +82,25 @@ export default {
           args: ['maxguestslimit']
         }
       ]
+    },
+    {
+      name: 'guestoshypervisormapping',
+      title: 'label.guest.os.mappings',
+      icon: 'database-outlined',
+      permission: ['listGuestOsMapping'],
+      columns: ['hypervisor', 'hypervisorversion', 'osdisplayname', 'osnameforhypervisor'],
+      details: ['hypervisor', 'hypervisorversion', 'osdisplayname', 'osnameforhypervisor', 'isuserdefined'],
+      filters: ['all', 'kvm', 'vmware', 'xenserver', 'lxc', 'ovm3'],
+      searchFilters: ['hypervisor', 'hypervisorversion'],
+      actions: [
+        {
+          api: 'updateGuestOsMapping',
+          icon: 'edit-outlined',
+          label: 'label.edit',
+          dataView: true,
+          args: ['osnameforhypervisor']
+        }
+      ]
     }
   ]
 }
diff --git a/ui/src/views/AutogenView.vue b/ui/src/views/AutogenView.vue
index 8ce9c5d7dbc..c707cabae6b 100644
--- a/ui/src/views/AutogenView.vue
+++ b/ui/src/views/AutogenView.vue
@@ -56,7 +56,7 @@
                     :value="$route.query.filter || (projectView && $route.name === 'vm' ||
                       ['Admin', 'DomainAdmin'].includes($store.getters.userInfo.roletype) && ['vm', 'iso', 'template'].includes($route.name)
                       ? 'all' : ['publicip'].includes($route.name)
-                        ? 'allocated' : ['guestnetwork', 'guestvlans'].includes($route.name) ? 'all' : 'self')"
+                        ? 'allocated' : ['guestnetwork', 'guestvlans', 'guestoshypervisormapping'].includes($route.name) ? 'all' : 'self')"
                     style="min-width: 120px; margin-left: 10px"
                     @change="changeFilter"
                     showSearch
@@ -1560,6 +1560,12 @@ export default {
         } else if (filter === 'allocatedonly') {
           query.allocatedonly = 'true'
         }
+      } else if (this.$route.name === 'guestoshypervisormapping') {
+        if (filter === 'all') {
+          delete query.hypervisor
+        } else {
+          query.hypervisor = filter
+        }
       }
       query.filter = filter
       query.page = '1'
@@ -1587,6 +1593,8 @@ export default {
               query.templatetype = value
             } else if (this.$route.name === 'globalsetting') {
               query.name = value
+            } else if (this.$route.name === 'guestoshypervisormapping') {
+              query.hypervisor = value
             } else {
               query.keyword = value
             }
diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/ClusterMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/ClusterMO.java
index 095b20c5b67..318cdb87e61 100644
--- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/ClusterMO.java
+++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/ClusterMO.java
@@ -740,4 +740,16 @@ public class ClusterMO extends BaseMO implements VmwareHypervisorHost {
             throw new CloudRuntimeException(msg);
         }
     }
+
+    @Override
+    public GuestOsDescriptor getGuestOsDescriptor(String guestOsId) throws Exception {
+        VirtualMachineConfigOption vmConfigOption = _context.getService().queryConfigOption(getEnvironmentBrowser(), null, null);
+        List<GuestOsDescriptor> guestDescriptors = vmConfigOption.getGuestOSDescriptor();
+        for (GuestOsDescriptor descriptor : guestDescriptors) {
+            if (guestOsId != null && guestOsId.equalsIgnoreCase(descriptor.getId())) {
+                return descriptor;
+            }
+        }
+        return null;
+    }
 }
diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java
index 07bead77c1f..7240f0972ba 100644
--- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java
+++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java
@@ -36,6 +36,7 @@ import com.vmware.vim25.ComputeResourceSummary;
 import com.vmware.vim25.CustomFieldStringValue;
 import com.vmware.vim25.DatastoreSummary;
 import com.vmware.vim25.DynamicProperty;
+import com.vmware.vim25.GuestOsDescriptor;
 import com.vmware.vim25.HostConfigManager;
 import com.vmware.vim25.HostConnectInfo;
 import com.vmware.vim25.HostFirewallInfo;
@@ -1163,6 +1164,16 @@ public class HostMO extends BaseMO implements VmwareHypervisorHost {
         return null;
     }
 
+    @Override
+    public GuestOsDescriptor getGuestOsDescriptor(String guestOsId) throws Exception {
+        ManagedObjectReference morParent = getParentMor();
+        if (morParent.getType().equals("ClusterComputeResource")) {
+            ClusterMO clusterMo = new ClusterMO(_context, morParent);
+            return clusterMo.getGuestOsDescriptor(guestOsId);
+        }
+        return null;
+    }
+
     public String getHostManagementIp(String managementPortGroup) throws Exception {
         HostNetworkInfo netInfo = getHostNetworkInfo();
 
diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VmwareHypervisorHost.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VmwareHypervisorHost.java
index ce2f178ef3f..3e6182b5666 100644
--- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VmwareHypervisorHost.java
+++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VmwareHypervisorHost.java
@@ -20,6 +20,7 @@ import java.util.List;
 
 import com.vmware.vim25.ClusterDasConfigInfo;
 import com.vmware.vim25.ComputeResourceSummary;
+import com.vmware.vim25.GuestOsDescriptor;
 import com.vmware.vim25.ManagedObjectReference;
 import com.vmware.vim25.ObjectContent;
 import com.vmware.vim25.VirtualMachineConfigSpec;
@@ -91,5 +92,8 @@ public interface VmwareHypervisorHost {
     ComputeResourceSummary getHyperHostHardwareSummary() throws Exception;
 
     LicenseAssignmentManagerMO getLicenseAssignmentManager() throws Exception;
+
     String getRecommendedDiskController(String guestOsId) throws Exception;
+
+    GuestOsDescriptor getGuestOsDescriptor(String guestOsId) throws Exception;
 }