| // 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.upgrade; |
| |
| import org.apache.commons.collections.CollectionUtils; |
| import org.apache.commons.lang3.StringUtils; |
| import org.apache.log4j.Logger; |
| |
| import java.sql.Connection; |
| import java.sql.PreparedStatement; |
| import java.sql.SQLException; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| |
| import javax.inject.Inject; |
| |
| import com.cloud.hypervisor.Hypervisor.HypervisorType; |
| import com.cloud.storage.GuestOSHypervisorMapping; |
| import com.cloud.storage.GuestOSHypervisorVO; |
| import com.cloud.storage.GuestOSVO; |
| import com.cloud.storage.dao.GuestOSDao; |
| import com.cloud.storage.dao.GuestOSDaoImpl; |
| import com.cloud.storage.dao.GuestOSHypervisorDao; |
| import com.cloud.storage.dao.GuestOSHypervisorDaoImpl; |
| |
| public class GuestOsMapper { |
| |
| final static Logger LOG = Logger.getLogger(GuestOsMapper.class); |
| |
| @Inject |
| GuestOSHypervisorDao guestOSHypervisorDao; |
| @Inject |
| GuestOSDao guestOSDao; |
| |
| private static final String updateGuestOsHypervisorSql = |
| "UPDATE `cloud`.`guest_os_hypervisor` SET guest_os_id = ? WHERE guest_os_id = ? AND hypervisor_type = ? AND hypervisor_version = ? AND guest_os_name = ? AND is_user_defined = 0 AND removed IS NULL"; |
| |
| public GuestOsMapper() { |
| guestOSHypervisorDao = new GuestOSHypervisorDaoImpl(); |
| guestOSDao = new GuestOSDaoImpl(); |
| } |
| |
| public void mergeDuplicates() { |
| LOG.info("merging duplicate guest osses"); |
| Set<Set<GuestOSVO>> duplicates = findDuplicates(); |
| LOG.debug(String.format("merging %d sets of duplicates", duplicates.size())); |
| for (Set<GuestOSVO> setOfGuestOSes : duplicates) { |
| // decide which to (mark as) remove(d) |
| // # highest/lowest id |
| // # or is user_defined == false |
| GuestOSVO guestOSVO = highestIdFrom(setOfGuestOSes); |
| LOG.info(String.format("merging %d duplicates for %s ", setOfGuestOSes.size(), guestOSVO.getDisplayName())); |
| makeNormative(guestOSVO, setOfGuestOSes); |
| |
| } |
| } |
| |
| public void makeNormative(GuestOSVO guestOSVO, Set<GuestOSVO> setOfGuestOSes) { |
| for (GuestOSVO oldGuestOs : setOfGuestOSes) { |
| if (guestOSVO.getId() != oldGuestOs.getId()) { |
| List<GuestOSHypervisorVO> mappings = guestOSHypervisorDao.listByGuestOsId(oldGuestOs.getId()); |
| copyMappings(guestOSVO, mappings); |
| makeHidden(oldGuestOs); |
| } |
| } |
| } |
| |
| private void makeHidden(GuestOSVO guestOSVO) { |
| guestOSVO.setDisplay(false); |
| guestOSDao.update(guestOSVO.getId(),guestOSVO); |
| } |
| |
| private void copyMappings(GuestOSVO guestOSVO, List<GuestOSHypervisorVO> mappings) { |
| for (GuestOSHypervisorVO mapping : mappings) { |
| if (null == guestOSHypervisorDao.findByOsIdAndHypervisor(guestOSVO.getId(), mapping.getHypervisorType(), mapping.getHypervisorVersion())) { |
| GuestOSHypervisorVO newMap = new GuestOSHypervisorVO(); |
| newMap.setGuestOsId(guestOSVO.getId()); |
| newMap.setGuestOsName(mapping.getGuestOsName()); |
| newMap.setHypervisorType(mapping.getHypervisorType()); |
| newMap.setHypervisorVersion(mapping.getHypervisorVersion()); |
| guestOSHypervisorDao.persist(newMap); |
| } |
| } |
| } |
| |
| private GuestOSVO highestIdFrom(Set<GuestOSVO> setOfGuestOSes) { |
| GuestOSVO rc = null; |
| for (GuestOSVO guestOSVO: setOfGuestOSes) { |
| if (rc == null || (guestOSVO.getId() > rc.getId() && !guestOSVO.getIsUserDefined())) { |
| rc = guestOSVO; |
| break; |
| } |
| } |
| return rc; |
| } |
| |
| /** |
| * |
| ¨¨¨ |
| select * from guest_os go2 |
| where display_name |
| in (select display_name from |
| (select display_name, count(1) as count from guest_os go1 group by display_name having count > 1) tab0); |
| ¨¨¨ |
| * and group them by display_name |
| * |
| * |
| * @return a list of sets of duplicate |
| */ |
| private Set<Set<GuestOSVO>> findDuplicates() { |
| Set<Set<GuestOSVO>> rc = new HashSet<>(); |
| Set<String> names = guestOSDao.findDoubleNames(); |
| for (String name : names) { |
| List<GuestOSVO> guestOsses = guestOSDao.listByDisplayName(name); |
| if (CollectionUtils.isNotEmpty(guestOsses)) { |
| rc.add(new HashSet<>(guestOsses)); |
| } |
| } |
| return rc; |
| } |
| |
| public List<GuestOSVO> listByDisplayName(String displayName) { |
| return guestOSDao.listByDisplayName(displayName); |
| } |
| |
| private long getGuestOsId(long categoryId, String displayName) { |
| GuestOSVO guestOS = guestOSDao.findByCategoryIdAndDisplayNameOrderByCreatedDesc(categoryId, displayName); |
| long id = 0l; |
| if (guestOS != null) { |
| id = guestOS.getId(); |
| } else { |
| LOG.warn(String.format("Unable to find the guest OS details with category id: %d and display name: %s", + categoryId, displayName)); |
| } |
| return id; |
| } |
| |
| private long getGuestOsIdFromHypervisorMapping(GuestOSHypervisorMapping mapping) { |
| GuestOSHypervisorVO guestOSHypervisorVO = guestOSHypervisorDao.findByOsNameAndHypervisorOrderByCreatedDesc(mapping.getGuestOsName(), mapping.getHypervisorType(), mapping.getHypervisorVersion()); |
| long id = 0; |
| if (guestOSHypervisorVO != null) { |
| id = guestOSHypervisorVO.getGuestOsId(); |
| } else { |
| LOG.warn(String.format("Unable to find the guest OS hypervisor mapping details for %s", mapping.toString())); |
| } |
| return id; |
| } |
| |
| public void addGuestOsAndHypervisorMappings(long categoryId, String displayName, List<GuestOSHypervisorMapping> mappings) { |
| long guestOsId = getGuestOsId(categoryId, displayName); |
| if (guestOsId == 0) { |
| LOG.debug("No guest OS found with category id: " + categoryId + " and display name: " + displayName); |
| if (!addGuestOs(categoryId, displayName)) { |
| LOG.warn("Couldn't add the guest OS with category id: " + categoryId + " and display name: " + displayName); |
| return; |
| } |
| guestOsId = getGuestOsId(categoryId, displayName); |
| } else { |
| updateToSystemDefined(guestOsId); |
| } |
| |
| if (CollectionUtils.isEmpty(mappings)) { |
| return; |
| } |
| |
| for (final GuestOSHypervisorMapping mapping : mappings) { |
| addGuestOsHypervisorMapping(mapping, guestOsId); |
| } |
| } |
| |
| private void updateToSystemDefined(long guestOsId) { |
| GuestOSVO guestOsVo = guestOSDao.findById(guestOsId); |
| guestOsVo.setIsUserDefined(false); |
| guestOSDao.update(guestOsId, guestOsVo);// TODO: update is_user_defined to false |
| } |
| |
| public boolean addGuestOs(long categoryId, String displayName) { |
| LOG.debug("Adding guest OS with category id: " + categoryId + " and display name: " + displayName); |
| GuestOSVO guestOS = new GuestOSVO(); |
| guestOS.setCategoryId(categoryId); |
| guestOS.setDisplayName(displayName); |
| guestOS = guestOSDao.persist(guestOS); |
| return (guestOS != null); |
| } |
| public void addGuestOsHypervisorMapping(GuestOSHypervisorMapping mapping, long category, String displayName) { |
| long guestOsId = getGuestOsId(category, displayName); |
| if (guestOsId == 0) { |
| LOG.error(String.format("no guest os found for category %d and name %s, skipping mapping it to %s/%s", guestOsId, displayName, mapping.getHypervisorType(), mapping.getHypervisorVersion())); |
| } else { |
| addGuestOsHypervisorMapping(mapping, guestOsId); |
| } |
| } |
| |
| private void addGuestOsHypervisorMapping(GuestOSHypervisorMapping mapping, long guestOsId) { |
| if(!isValidGuestOSHypervisorMapping(mapping)) { |
| return; |
| } |
| |
| LOG.debug("Adding guest OS hypervisor mapping - " + mapping.toString() + ", for guest OS with id - " + guestOsId); |
| GuestOSHypervisorVO guestOsMapping = new GuestOSHypervisorVO(); |
| guestOsMapping.setHypervisorType(mapping.getHypervisorType()); |
| guestOsMapping.setHypervisorVersion(mapping.getHypervisorVersion()); |
| guestOsMapping.setGuestOsName(mapping.getGuestOsName()); |
| guestOsMapping.setGuestOsId(guestOsId); |
| guestOSHypervisorDao.persist(guestOsMapping); |
| } |
| |
| public void updateGuestOsName(long categoryId, String oldDisplayName, String newDisplayName) { |
| GuestOSVO guestOS = guestOSDao.findByCategoryIdAndDisplayNameOrderByCreatedDesc(categoryId, oldDisplayName); |
| if (guestOS == null) { |
| LOG.debug("Unable to update guest OS name, as there is no guest OS with category id: " + categoryId + " and display name: " + oldDisplayName); |
| return; |
| } |
| |
| guestOS.setDisplayName(newDisplayName); |
| guestOSDao.update(guestOS.getId(), guestOS); |
| } |
| |
| public void updateGuestOsNameFromMapping(String newDisplayName, GuestOSHypervisorMapping mapping) { |
| if(!isValidGuestOSHypervisorMapping(mapping)) { |
| return; |
| } |
| |
| GuestOSHypervisorVO guestOSHypervisorVO = guestOSHypervisorDao.findByOsNameAndHypervisorOrderByCreatedDesc(mapping.getGuestOsName(), mapping.getHypervisorType(), mapping.getHypervisorVersion()); |
| if (guestOSHypervisorVO == null) { |
| LOG.debug("Unable to update guest OS name, as there is no guest os hypervisor mapping"); |
| return; |
| } |
| |
| long guestOsId = guestOSHypervisorVO.getGuestOsId(); |
| GuestOSVO guestOS = guestOSDao.findById(guestOsId); |
| if (guestOS != null) { |
| guestOS.setDisplayName(newDisplayName); |
| guestOSDao.update(guestOS.getId(), guestOS); |
| } |
| } |
| |
| public void updateGuestOsIdInHypervisorMapping(Connection conn, long categoryId, String displayName, GuestOSHypervisorMapping mapping) { |
| if(!isValidGuestOSHypervisorMapping(mapping)) { |
| return; |
| } |
| |
| long oldGuestOsId = getGuestOsIdFromHypervisorMapping(mapping); |
| if (oldGuestOsId == 0) { |
| LOG.debug("Unable to update guest OS in hypervisor mapping, as there is no guest os hypervisor mapping - " + mapping.toString()); |
| return; |
| } |
| |
| long newGuestOsId = getGuestOsId(categoryId, displayName); |
| if (newGuestOsId == 0) { |
| LOG.debug("Unable to update guest OS id in hypervisor mapping, as there is no guest OS with category id: " + categoryId + " and display name: " + displayName); |
| return; |
| } |
| |
| updateGuestOsIdInMapping(conn, oldGuestOsId, newGuestOsId, mapping); |
| } |
| |
| private void updateGuestOsIdInMapping(Connection conn, long oldGuestOsId, long newGuestOsId, GuestOSHypervisorMapping mapping) { |
| LOG.debug("Updating guest os id: " + oldGuestOsId + " to id: " + newGuestOsId + " in hypervisor mapping - " + mapping.toString()); |
| try { |
| PreparedStatement pstmt = conn.prepareStatement(updateGuestOsHypervisorSql); |
| pstmt.setLong(1, newGuestOsId); |
| pstmt.setLong(2, oldGuestOsId); |
| pstmt.setString(3, mapping.getHypervisorType()); |
| pstmt.setString(4, mapping.getHypervisorVersion()); |
| pstmt.setString(5, mapping.getGuestOsName()); |
| pstmt.executeUpdate(); |
| } catch (SQLException e) { |
| LOG.error("Failed to update guest OS id in hypervisor mapping due to: " + e.getMessage(), e); |
| } |
| } |
| |
| private boolean isValidGuestOSHypervisorMapping(GuestOSHypervisorMapping mapping) { |
| if (mapping != null && mapping.isValid()) { |
| return true; |
| } |
| |
| LOG.warn("Invalid Guest OS hypervisor mapping"); |
| return false; |
| } |
| |
| /** |
| * Copies guest OS mappings from src version to dest version for the hypervisor (use this to copy all mappings from older version to newer version during upgrade) |
| * @return true if copied successfully, else false. |
| */ |
| public boolean copyGuestOSHypervisorMappings(HypervisorType hypervisorType, String srcVersion, String destVersion) { |
| if (hypervisorType == HypervisorType.None || hypervisorType == HypervisorType.Any) { |
| LOG.warn("Unable to copy, invalid hypervisor"); |
| return false; |
| } |
| |
| if (StringUtils.isAnyBlank(srcVersion, destVersion)) { |
| LOG.warn("Unable to copy, invalid hypervisor version details"); |
| return false; |
| } |
| |
| List<GuestOSHypervisorVO> guestOSHypervisorMappingsForSrcVersion = guestOSHypervisorDao.listByHypervisorTypeAndVersion(hypervisorType.toString(), srcVersion); |
| if (CollectionUtils.isEmpty(guestOSHypervisorMappingsForSrcVersion)) { |
| LOG.warn(String.format("Unable to copy, couldn't find guest OS mappings for hypervisor: %s and src version: %s", hypervisorType.toString(), srcVersion)); |
| return false; |
| } |
| |
| LOG.debug(String.format("Adding guest OS mappings for hypervisor: %s and version: %s, from version: %s ", hypervisorType.toString(), destVersion, srcVersion)); |
| for (GuestOSHypervisorVO guestOSHypervisorMapping : guestOSHypervisorMappingsForSrcVersion) { |
| GuestOSHypervisorMapping mapping = new GuestOSHypervisorMapping(hypervisorType.toString(), destVersion, guestOSHypervisorMapping.getGuestOsName()); |
| addGuestOsHypervisorMapping(mapping, guestOSHypervisorMapping.getGuestOsId()); |
| } |
| return true; |
| } |
| |
| public void updateGuestOsNameInHypervisorMapping(long categoryId, String displayName, GuestOSHypervisorMapping mapping) { |
| if (!isValidGuestOSHypervisorMapping(mapping)) { |
| return; |
| } |
| |
| long guestOsId = getGuestOsId(categoryId, displayName); |
| if (guestOsId == 0) { |
| LOG.error(String.format("no guest os found for category %d and name %s, skipping mapping it to %s/%s", guestOsId, displayName, mapping.getHypervisorType(), mapping.getHypervisorVersion())); |
| return; |
| } |
| |
| GuestOSHypervisorVO guestOsMapping = guestOSHypervisorDao.findByOsIdAndHypervisor(guestOsId, mapping.getHypervisorType(), mapping.getHypervisorVersion()); |
| guestOsMapping.setGuestOsName(mapping.getGuestOsName()); |
| guestOSHypervisorDao.update(guestOsMapping.getId(), guestOsMapping); |
| } |
| } |