| // 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 com.cloud.dc.DataCenterVO; |
| import com.cloud.dc.dao.ClusterDao; |
| import com.cloud.dc.dao.ClusterDaoImpl; |
| import com.cloud.dc.dao.DataCenterDao; |
| import com.cloud.dc.dao.DataCenterDaoImpl; |
| import com.cloud.hypervisor.Hypervisor; |
| import com.cloud.storage.DataStoreRole; |
| import com.cloud.storage.Storage; |
| import com.cloud.storage.Storage.ImageFormat; |
| import com.cloud.storage.VMTemplateStorageResourceAssoc; |
| import com.cloud.storage.VMTemplateVO; |
| import com.cloud.storage.VMTemplateZoneVO; |
| import com.cloud.storage.dao.VMTemplateDao; |
| import com.cloud.storage.dao.VMTemplateDaoImpl; |
| import com.cloud.storage.dao.VMTemplateZoneDao; |
| import com.cloud.storage.dao.VMTemplateZoneDaoImpl; |
| import com.cloud.template.VirtualMachineTemplate; |
| import com.cloud.upgrade.dao.BasicTemplateDataStoreDaoImpl; |
| import com.cloud.user.Account; |
| import com.cloud.utils.DateUtil; |
| import com.cloud.utils.Pair; |
| import com.cloud.utils.UriUtils; |
| import com.cloud.utils.db.GlobalLock; |
| import com.cloud.utils.db.Transaction; |
| import com.cloud.utils.db.TransactionCallbackNoReturn; |
| import com.cloud.utils.db.TransactionStatus; |
| import com.cloud.utils.exception.CloudRuntimeException; |
| import com.cloud.utils.script.Script; |
| import com.cloud.vm.dao.VMInstanceDao; |
| import com.cloud.vm.dao.VMInstanceDaoImpl; |
| import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; |
| import org.apache.cloudstack.framework.config.dao.ConfigurationDao; |
| import org.apache.cloudstack.framework.config.dao.ConfigurationDaoImpl; |
| import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; |
| import org.apache.cloudstack.storage.datastore.db.ImageStoreDaoImpl; |
| import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; |
| import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao; |
| import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO; |
| import org.apache.cloudstack.utils.security.DigestHelper; |
| import org.apache.commons.lang3.StringUtils; |
| import org.apache.log4j.Logger; |
| import org.ini4j.Ini; |
| |
| import javax.inject.Inject; |
| import java.io.BufferedReader; |
| import java.io.File; |
| import java.io.FileReader; |
| import java.io.IOException; |
| import java.net.URI; |
| import java.nio.file.Files; |
| import java.nio.file.Path; |
| import java.nio.file.Paths; |
| import java.sql.Connection; |
| import java.sql.Date; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.UUID; |
| import java.util.stream.Collectors; |
| |
| public class SystemVmTemplateRegistration { |
| private static final Logger LOGGER = Logger.getLogger(SystemVmTemplateRegistration.class); |
| private static final String MOUNT_COMMAND = "sudo mount -t nfs %s %s"; |
| private static final String UMOUNT_COMMAND = "sudo umount %s"; |
| private static final String RELATIVE_TEMPLATE_PATH = "./engine/schema/dist/systemvm-templates/"; |
| private static final String ABSOLUTE_TEMPLATE_PATH = "/usr/share/cloudstack-management/templates/systemvm/"; |
| private static final String TEMPLATES_PATH = fetchTemplatesPath(); |
| private static final String METADATA_FILE_NAME = "metadata.ini"; |
| private static final String METADATA_FILE = TEMPLATES_PATH + METADATA_FILE_NAME; |
| public static final String TEMPORARY_SECONDARY_STORE = "tmp"; |
| private static final String PARTIAL_TEMPLATE_FOLDER = String.format("/template/tmpl/%d/", Account.ACCOUNT_ID_SYSTEM); |
| private static final String storageScriptsDir = "scripts/storage/secondary"; |
| private static final Integer OTHER_LINUX_ID = 99; |
| private static final Integer LINUX_5_ID = 15; |
| private static final Integer LINUX_7_ID = 183; |
| private static final Integer SCRIPT_TIMEOUT = 1800000; |
| private static final Integer LOCK_WAIT_TIMEOUT = 1200; |
| |
| |
| public static String CS_MAJOR_VERSION = null; |
| public static String CS_TINY_VERSION = null; |
| |
| @Inject |
| DataCenterDao dataCenterDao; |
| @Inject |
| VMTemplateDao vmTemplateDao; |
| @Inject |
| VMTemplateZoneDao vmTemplateZoneDao; |
| @Inject |
| TemplateDataStoreDao templateDataStoreDao; |
| @Inject |
| VMInstanceDao vmInstanceDao; |
| @Inject |
| ImageStoreDao imageStoreDao; |
| @Inject |
| ClusterDao clusterDao; |
| @Inject |
| ConfigurationDao configurationDao; |
| |
| private String systemVmTemplateVersion; |
| |
| public SystemVmTemplateRegistration() { |
| dataCenterDao = new DataCenterDaoImpl(); |
| vmTemplateDao = new VMTemplateDaoImpl(); |
| vmTemplateZoneDao = new VMTemplateZoneDaoImpl(); |
| templateDataStoreDao = new BasicTemplateDataStoreDaoImpl(); |
| vmInstanceDao = new VMInstanceDaoImpl(); |
| imageStoreDao = new ImageStoreDaoImpl(); |
| clusterDao = new ClusterDaoImpl(); |
| configurationDao = new ConfigurationDaoImpl(); |
| } |
| |
| /** |
| * Convenience constructor method to use when there is no system VM template change for a new version. |
| */ |
| public SystemVmTemplateRegistration(String systemVmTemplateVersion) { |
| this(); |
| this.systemVmTemplateVersion = systemVmTemplateVersion; |
| } |
| |
| public String getSystemVmTemplateVersion() { |
| if (StringUtils.isEmpty(systemVmTemplateVersion)) { |
| return String.format("%s.%s", CS_MAJOR_VERSION, CS_TINY_VERSION); |
| } |
| return systemVmTemplateVersion; |
| } |
| |
| private static class SystemVMTemplateDetails { |
| Long id; |
| String uuid; |
| String name; |
| String uniqueName; |
| Date created; |
| String url; |
| String checksum; |
| ImageFormat format; |
| Integer guestOsId; |
| Hypervisor.HypervisorType hypervisorType; |
| Long storeId; |
| Long size; |
| Long physicalSize; |
| String installPath; |
| boolean deployAsIs; |
| Date updated; |
| |
| SystemVMTemplateDetails(String uuid, String name, Date created, String url, String checksum, |
| ImageFormat format, Integer guestOsId, Hypervisor.HypervisorType hypervisorType, |
| Long storeId) { |
| this.uuid = uuid; |
| this.name = name; |
| this.created = created; |
| this.url = url; |
| this.checksum = checksum; |
| this.format = format; |
| this.guestOsId = guestOsId; |
| this.hypervisorType = hypervisorType; |
| this.storeId = storeId; |
| } |
| |
| public void setId(Long id) { |
| this.id = id; |
| } |
| |
| public Long getId() { |
| return id; |
| } |
| |
| public String getUuid() { |
| return uuid; |
| } |
| |
| public String getName() { |
| return name; |
| } |
| |
| public Date getCreated() { |
| return created; |
| } |
| |
| public String getUrl() { |
| return url; |
| } |
| |
| public String getChecksum() { |
| return checksum; |
| } |
| |
| public ImageFormat getFormat() { |
| return format; |
| } |
| |
| public Integer getGuestOsId() { |
| return guestOsId; |
| } |
| |
| public Hypervisor.HypervisorType getHypervisorType() { |
| return hypervisorType; |
| } |
| |
| public Long getStoreId() { |
| return storeId; |
| } |
| |
| public Long getSize() { |
| return size; |
| } |
| |
| public void setSize(Long size) { |
| this.size = size; |
| } |
| |
| public Long getPhysicalSize() { |
| return physicalSize; |
| } |
| |
| public void setPhysicalSize(Long physicalSize) { |
| this.physicalSize = physicalSize; |
| } |
| |
| public String getInstallPath() { |
| return installPath; |
| } |
| |
| public void setInstallPath(String installPath) { |
| this.installPath = installPath; |
| } |
| |
| public String getUniqueName() { |
| return uniqueName; |
| } |
| |
| public void setUniqueName(String uniqueName) { |
| this.uniqueName = uniqueName; |
| } |
| |
| public boolean isDeployAsIs() { |
| return deployAsIs; |
| } |
| |
| public void setDeployAsIs(boolean deployAsIs) { |
| this.deployAsIs = deployAsIs; |
| } |
| |
| public Date getUpdated() { |
| return updated; |
| } |
| |
| public void setUpdated(Date updated) { |
| this.updated = updated; |
| } |
| } |
| |
| public static final List<Hypervisor.HypervisorType> hypervisorList = Arrays.asList(Hypervisor.HypervisorType.KVM, |
| Hypervisor.HypervisorType.VMware, |
| Hypervisor.HypervisorType.XenServer, |
| Hypervisor.HypervisorType.Hyperv, |
| Hypervisor.HypervisorType.LXC, |
| Hypervisor.HypervisorType.Ovm3 |
| ); |
| |
| public static final Map<Hypervisor.HypervisorType, String> NewTemplateNameList = new HashMap<Hypervisor.HypervisorType, String>(); |
| public static final Map<Hypervisor.HypervisorType, String> FileNames = new HashMap<Hypervisor.HypervisorType, String>(); |
| public static final Map<Hypervisor.HypervisorType, String> NewTemplateUrl = new HashMap<Hypervisor.HypervisorType, String>(); |
| public static final Map<Hypervisor.HypervisorType, String> NewTemplateChecksum = new HashMap<Hypervisor.HypervisorType, String>(); |
| |
| public static final Map<Hypervisor.HypervisorType, String> RouterTemplateConfigurationNames = new HashMap<Hypervisor.HypervisorType, String>() { |
| { |
| put(Hypervisor.HypervisorType.KVM, "router.template.kvm"); |
| put(Hypervisor.HypervisorType.VMware, "router.template.vmware"); |
| put(Hypervisor.HypervisorType.XenServer, "router.template.xenserver"); |
| put(Hypervisor.HypervisorType.Hyperv, "router.template.hyperv"); |
| put(Hypervisor.HypervisorType.LXC, "router.template.lxc"); |
| put(Hypervisor.HypervisorType.Ovm3, "router.template.ovm3"); |
| } |
| }; |
| |
| public static final Map<Hypervisor.HypervisorType, Integer> hypervisorGuestOsMap = new HashMap<Hypervisor.HypervisorType, Integer>() { |
| { |
| put(Hypervisor.HypervisorType.KVM, LINUX_5_ID); |
| put(Hypervisor.HypervisorType.XenServer, OTHER_LINUX_ID); |
| put(Hypervisor.HypervisorType.VMware, OTHER_LINUX_ID); |
| put(Hypervisor.HypervisorType.Hyperv, LINUX_5_ID); |
| put(Hypervisor.HypervisorType.LXC, LINUX_5_ID); |
| put(Hypervisor.HypervisorType.Ovm3, LINUX_7_ID); |
| } |
| }; |
| |
| public static final Map<Hypervisor.HypervisorType, ImageFormat> hypervisorImageFormat = new HashMap<Hypervisor.HypervisorType, ImageFormat>() { |
| { |
| put(Hypervisor.HypervisorType.KVM, ImageFormat.QCOW2); |
| put(Hypervisor.HypervisorType.XenServer, ImageFormat.VHD); |
| put(Hypervisor.HypervisorType.VMware, ImageFormat.OVA); |
| put(Hypervisor.HypervisorType.Hyperv, ImageFormat.VHD); |
| put(Hypervisor.HypervisorType.LXC, ImageFormat.QCOW2); |
| put(Hypervisor.HypervisorType.Ovm3, ImageFormat.RAW); |
| } |
| }; |
| |
| public static boolean validateIfSeeded(String url, String path) { |
| String filePath = null; |
| try { |
| filePath = Files.createTempDirectory(TEMPORARY_SECONDARY_STORE).toString(); |
| if (filePath == null) { |
| throw new CloudRuntimeException("Failed to create temporary directory to mount secondary store"); |
| } |
| mountStore(url, filePath); |
| int lastIdx = path.lastIndexOf(File.separator); |
| String partialDirPath = path.substring(0, lastIdx); |
| String templatePath = filePath + File.separator + partialDirPath; |
| File templateProps = new File(templatePath + "/template.properties"); |
| if (templateProps.exists()) { |
| LOGGER.info("SystemVM template already seeded, skipping registration"); |
| return true; |
| } |
| LOGGER.info("SystemVM template not seeded"); |
| return false; |
| } catch (Exception e) { |
| LOGGER.error("Failed to verify if the template is seeded", e); |
| throw new CloudRuntimeException("Failed to verify if the template is seeded", e); |
| } finally { |
| unmountStore(filePath); |
| try { |
| Files.delete(Path.of(filePath)); |
| } catch (IOException e) { |
| LOGGER.error(String.format("Failed to delete temporary directory: %s", filePath)); |
| } |
| } |
| } |
| |
| public Long getRegisteredTemplateId(Pair<Hypervisor.HypervisorType, String> hypervisorAndTemplateName) { |
| VMTemplateVO vmTemplate = vmTemplateDao.findLatestTemplateByName(hypervisorAndTemplateName.second()); |
| Long templateId = null; |
| if (vmTemplate != null) { |
| templateId = vmTemplate.getId(); |
| } |
| return templateId; |
| } |
| |
| private static String fetchTemplatesPath() { |
| String filePath = RELATIVE_TEMPLATE_PATH + METADATA_FILE_NAME; |
| LOGGER.debug(String.format("Looking for file [ %s ] in the classpath.", filePath)); |
| File metaFile = new File(filePath); |
| String templatePath = null; |
| if (metaFile.exists()) { |
| templatePath = RELATIVE_TEMPLATE_PATH; |
| } |
| if (templatePath == null) { |
| filePath = ABSOLUTE_TEMPLATE_PATH + METADATA_FILE_NAME; |
| metaFile = new File(filePath); |
| templatePath = ABSOLUTE_TEMPLATE_PATH; |
| LOGGER.debug(String.format("Looking for file [ %s ] in the classpath.", filePath)); |
| if (!metaFile.exists()) { |
| String errMsg = String.format("Unable to locate metadata file in your setup at %s", filePath.toString()); |
| LOGGER.error(errMsg); |
| throw new CloudRuntimeException(errMsg); |
| } |
| } |
| return templatePath; |
| } |
| |
| private String getHypervisorName(String name) { |
| if (name.equals("xenserver")) { |
| return "xen"; |
| } |
| if (name.equals("ovm3")) { |
| return "ovm"; |
| } |
| return name; |
| |
| } |
| |
| private Hypervisor.HypervisorType getHypervisorType(String hypervisor) { |
| if (hypervisor.equalsIgnoreCase("xen")) { |
| hypervisor = "xenserver"; |
| } else if (hypervisor.equalsIgnoreCase("ovm")) { |
| hypervisor = "ovm3"; |
| } |
| return Hypervisor.HypervisorType.getType(hypervisor); |
| } |
| |
| private List<Long> getEligibleZoneIds() { |
| List<Long> zoneIds = new ArrayList<>(); |
| List<ImageStoreVO> stores = imageStoreDao.findByProtocol("nfs"); |
| for (ImageStoreVO store : stores) { |
| if (!zoneIds.contains(store.getDataCenterId())) { |
| zoneIds.add(store.getDataCenterId()); |
| } |
| } |
| return zoneIds; |
| } |
| |
| private Pair<String, Long> getNfsStoreInZone(Long zoneId) { |
| String url = null; |
| Long storeId = null; |
| ImageStoreVO storeVO = imageStoreDao.findOneByZoneAndProtocol(zoneId, "nfs"); |
| if (storeVO == null) { |
| String errMsg = String.format("Failed to fetch NFS store in zone = %s for SystemVM template registration", zoneId); |
| LOGGER.error(errMsg); |
| throw new CloudRuntimeException(errMsg); |
| } |
| url = storeVO.getUrl(); |
| storeId = storeVO.getId(); |
| return new Pair<>(url, storeId); |
| } |
| |
| public static void mountStore(String storeUrl, String path) { |
| try { |
| if (storeUrl != null) { |
| URI uri = new URI(UriUtils.encodeURIComponent(storeUrl)); |
| String host = uri.getHost(); |
| String mountPath = uri.getPath(); |
| String mount = String.format(MOUNT_COMMAND, host + ":" + mountPath, path); |
| Script.runSimpleBashScript(mount); |
| } |
| } catch (Exception e) { |
| String msg = "NFS Store URL is not in the correct format"; |
| LOGGER.error(msg, e); |
| throw new CloudRuntimeException(msg, e); |
| } |
| } |
| |
| private List<String> fetchAllHypervisors(Long zoneId) { |
| List<String> hypervisorList = new ArrayList<>(); |
| List<Hypervisor.HypervisorType> hypervisorTypes = clusterDao.getAvailableHypervisorInZone(zoneId); |
| hypervisorList = hypervisorTypes.stream().distinct().map(Enum::name).collect(Collectors.toList()); |
| return hypervisorList; |
| } |
| |
| private VMTemplateVO createTemplateObjectInDB(SystemVMTemplateDetails details) { |
| Long templateId = vmTemplateDao.getNextInSequence(Long.class, "id"); |
| VMTemplateVO template = new VMTemplateVO(); |
| template.setUuid(details.getUuid()); |
| template.setUniqueName(String.format("routing-%s" , String.valueOf(templateId))); |
| template.setName(details.getName()); |
| template.setPublicTemplate(false); |
| template.setFeatured(false); |
| template.setTemplateType(Storage.TemplateType.SYSTEM); |
| template.setRequiresHvm(true); |
| template.setBits(64); |
| template.setAccountId(Account.ACCOUNT_ID_SYSTEM); |
| template.setUrl(details.getUrl()); |
| template.setChecksum(details.getChecksum()); |
| template.setEnablePassword(false); |
| template.setDisplayText(details.getName()); |
| template.setFormat(details.getFormat()); |
| template.setGuestOSId(details.getGuestOsId()); |
| template.setCrossZones(true); |
| template.setHypervisorType(details.getHypervisorType()); |
| template.setState(VirtualMachineTemplate.State.Inactive); |
| template.setDeployAsIs(false); |
| template = vmTemplateDao.persist(template); |
| return template; |
| } |
| |
| private VMTemplateZoneVO createOrUpdateTemplateZoneEntry(long zoneId, long templateId) { |
| VMTemplateZoneVO templateZoneVO = vmTemplateZoneDao.findByZoneTemplate(zoneId, templateId); |
| if (templateZoneVO == null) { |
| templateZoneVO = new VMTemplateZoneVO(zoneId, templateId, new java.util.Date()); |
| templateZoneVO = vmTemplateZoneDao.persist(templateZoneVO); |
| } else { |
| templateZoneVO.setLastUpdated(new java.util.Date()); |
| if (vmTemplateZoneDao.update(templateZoneVO.getId(), templateZoneVO)) { |
| templateZoneVO = null; |
| } |
| } |
| return templateZoneVO; |
| } |
| |
| private void createCrossZonesTemplateZoneRefEntries(VMTemplateVO template) { |
| List<DataCenterVO> dcs = dataCenterDao.listAll(); |
| for (DataCenterVO dc : dcs) { |
| VMTemplateZoneVO templateZoneVO = createOrUpdateTemplateZoneEntry(dc.getId(), template.getId()); |
| if (templateZoneVO == null) { |
| throw new CloudRuntimeException(String.format("Failed to create template_zone_ref record for the systemVM template for hypervisor: %s and zone: %s", template.getHypervisorType().name(), dc)); |
| } |
| } |
| } |
| |
| private void createTemplateStoreRefEntry(SystemVMTemplateDetails details) { |
| TemplateDataStoreVO templateDataStoreVO = new TemplateDataStoreVO(details.storeId, details.getId(), details.getCreated(), 0, |
| VMTemplateStorageResourceAssoc.Status.NOT_DOWNLOADED, null, null, null, details.getInstallPath(), details.getUrl()); |
| templateDataStoreVO.setDataStoreRole(DataStoreRole.Image); |
| templateDataStoreVO = templateDataStoreDao.persist(templateDataStoreVO); |
| if (templateDataStoreVO == null) { |
| throw new CloudRuntimeException(String.format("Failed to create template_store_ref record for the systemVM template for hypervisor: %s", details.getHypervisorType().name())); |
| } |
| } |
| |
| public void updateTemplateDetails(SystemVMTemplateDetails details) { |
| VMTemplateVO template = vmTemplateDao.findById(details.getId()); |
| template.setSize(details.getSize()); |
| template.setState(VirtualMachineTemplate.State.Active); |
| vmTemplateDao.update(template.getId(), template); |
| |
| TemplateDataStoreVO templateDataStoreVO = templateDataStoreDao.findByStoreTemplate(details.getStoreId(), template.getId()); |
| templateDataStoreVO.setSize(details.getSize()); |
| templateDataStoreVO.setPhysicalSize(details.getPhysicalSize()); |
| templateDataStoreVO.setDownloadPercent(100); |
| templateDataStoreVO.setDownloadState(VMTemplateStorageResourceAssoc.Status.DOWNLOADED); |
| templateDataStoreVO.setLastUpdated(details.getUpdated()); |
| templateDataStoreVO.setState(ObjectInDataStoreStateMachine.State.Ready); |
| boolean updated = templateDataStoreDao.update(templateDataStoreVO.getId(), templateDataStoreVO); |
| if (!updated) { |
| throw new CloudRuntimeException("Failed to update template_store_ref entry for registered systemVM template"); |
| } |
| } |
| |
| public void updateSystemVMEntries(Long templateId, Hypervisor.HypervisorType hypervisorType) { |
| vmInstanceDao.updateSystemVmTemplateId(templateId, hypervisorType); |
| } |
| |
| public void updateConfigurationParams(Map<String, String> configParams) { |
| for (Map.Entry<String, String> config : configParams.entrySet()) { |
| boolean updated = configurationDao.update(config.getKey(), config.getValue()); |
| if (!updated) { |
| throw new CloudRuntimeException(String.format("Failed to update configuration parameter %s", config.getKey())); |
| } |
| } |
| } |
| |
| private static void readTemplateProperties(String path, SystemVMTemplateDetails details) { |
| File tmpFile = new File(path); |
| Long size = null; |
| Long physicalSize = 0L; |
| try (FileReader fr = new FileReader(tmpFile); BufferedReader brf = new BufferedReader(fr);) { |
| String line = null; |
| while ((line = brf.readLine()) != null) { |
| if (line.startsWith("size=")) { |
| physicalSize = Long.parseLong(line.split("=")[1]); |
| } else if (line.startsWith("virtualsize=")) { |
| size = Long.parseLong(line.split("=")[1]); |
| } |
| if (size == null) { |
| size = physicalSize; |
| } |
| } |
| } catch (IOException ex) { |
| LOGGER.warn("Failed to read from template.properties", ex); |
| } |
| details.setSize(size); |
| details.setPhysicalSize(physicalSize); |
| } |
| |
| private void updateTemplateTablesOnFailure(long templateId) { |
| VMTemplateVO template = vmTemplateDao.createForUpdate(templateId); |
| template.setState(VirtualMachineTemplate.State.Inactive); |
| vmTemplateDao.update(template.getId(), template); |
| vmTemplateDao.remove(templateId); |
| TemplateDataStoreVO templateDataStoreVO = templateDataStoreDao.findByTemplate(template.getId(), DataStoreRole.Image); |
| templateDataStoreDao.remove(templateDataStoreVO.getId()); |
| } |
| |
| public static void unmountStore(String filePath) { |
| try { |
| LOGGER.info("Unmounting store"); |
| String umountCmd = String.format(UMOUNT_COMMAND, filePath); |
| Script.runSimpleBashScript(umountCmd); |
| try { |
| Files.deleteIfExists(Paths.get(filePath)); |
| } catch (IOException e) { |
| LOGGER.error(String.format("Failed to cleanup mounted store at: %s", filePath), e); |
| } |
| } catch (Exception e) { |
| String msg = String.format("Failed to unmount store mounted at %s", filePath); |
| LOGGER.error(msg, e); |
| throw new CloudRuntimeException(msg, e); |
| } |
| } |
| |
| private void setupTemplate(String templateName, Pair<Hypervisor.HypervisorType, String> hypervisorAndTemplateName, |
| String destTempFolder) throws CloudRuntimeException { |
| String setupTmpltScript = Script.findScript(storageScriptsDir, "setup-sysvm-tmplt"); |
| if (setupTmpltScript == null) { |
| throw new CloudRuntimeException("Unable to find the createtmplt.sh"); |
| } |
| Script scr = new Script(setupTmpltScript, SCRIPT_TIMEOUT, LOGGER); |
| scr.add("-u", templateName); |
| scr.add("-f", TEMPLATES_PATH + FileNames.get(hypervisorAndTemplateName.first())); |
| scr.add("-h", hypervisorAndTemplateName.first().name().toLowerCase(Locale.ROOT)); |
| scr.add("-d", destTempFolder); |
| String result = scr.execute(); |
| if (result != null) { |
| String errMsg = String.format("failed to create template: %s ", result); |
| LOGGER.error(errMsg); |
| throw new CloudRuntimeException(errMsg); |
| } |
| |
| } |
| |
| private Long performTemplateRegistrationOperations(Pair<Hypervisor.HypervisorType, String> hypervisorAndTemplateName, |
| String url, String checksum, ImageFormat format, long guestOsId, |
| Long storeId, Long templateId, String filePath, TemplateDataStoreVO templateDataStoreVO) { |
| Hypervisor.HypervisorType hypervisor = hypervisorAndTemplateName.first(); |
| String templateName = UUID.randomUUID().toString(); |
| Date created = new Date(DateUtil.currentGMTTime().getTime()); |
| SystemVMTemplateDetails details = new SystemVMTemplateDetails(templateName, hypervisorAndTemplateName.second(), created, |
| url, checksum, format, (int) guestOsId, hypervisor, storeId); |
| if (templateId == null) { |
| VMTemplateVO template = createTemplateObjectInDB(details); |
| if (template == null) { |
| throw new CloudRuntimeException(String.format("Failed to register template for hypervisor: %s", hypervisor.name())); |
| } |
| templateId = template.getId(); |
| createCrossZonesTemplateZoneRefEntries(template); |
| } |
| details.setId(templateId); |
| String destTempFolderName = String.valueOf(templateId); |
| String destTempFolder = filePath + PARTIAL_TEMPLATE_FOLDER + destTempFolderName; |
| details.setInstallPath(PARTIAL_TEMPLATE_FOLDER + destTempFolderName + File.separator + templateName + "." + hypervisorImageFormat.get(hypervisor).getFileExtension()); |
| if (templateDataStoreVO == null) { |
| createTemplateStoreRefEntry(details); |
| } |
| setupTemplate(templateName, hypervisorAndTemplateName, destTempFolder); |
| readTemplateProperties(destTempFolder + "/template.properties", details); |
| details.setUpdated(new Date(DateUtil.currentGMTTime().getTime())); |
| updateTemplateDetails(details); |
| return templateId; |
| } |
| |
| public void registerTemplate(Pair<Hypervisor.HypervisorType, String> hypervisorAndTemplateName, |
| Pair<String, Long> storeUrlAndId, VMTemplateVO templateVO, |
| TemplateDataStoreVO templateDataStoreVO, String filePath) { |
| Long templateId = null; |
| try { |
| templateId = templateVO.getId(); |
| performTemplateRegistrationOperations(hypervisorAndTemplateName, templateVO.getUrl(), templateVO.getChecksum(), |
| templateVO.getFormat(), templateVO.getGuestOSId(), storeUrlAndId.second(), templateId, filePath, templateDataStoreVO); |
| } catch (Exception e) { |
| String errMsg = String.format("Failed to register template for hypervisor: %s", hypervisorAndTemplateName.first()); |
| LOGGER.error(errMsg, e); |
| if (templateId != null) { |
| updateTemplateTablesOnFailure(templateId); |
| cleanupStore(templateId, filePath); |
| } |
| throw new CloudRuntimeException(errMsg, e); |
| } |
| } |
| |
| public void registerTemplate(Pair<Hypervisor.HypervisorType, String> hypervisorAndTemplateName, Pair<String, Long> storeUrlAndId, String filePath) { |
| Long templateId = null; |
| try { |
| Hypervisor.HypervisorType hypervisor = hypervisorAndTemplateName.first(); |
| templateId = performTemplateRegistrationOperations(hypervisorAndTemplateName, NewTemplateUrl.get(hypervisor), NewTemplateChecksum.get(hypervisor), |
| hypervisorImageFormat.get(hypervisor), hypervisorGuestOsMap.get(hypervisor), storeUrlAndId.second(), null, filePath, null); |
| Map<String, String> configParams = new HashMap<>(); |
| configParams.put(RouterTemplateConfigurationNames.get(hypervisorAndTemplateName.first()), hypervisorAndTemplateName.second()); |
| configParams.put("minreq.sysvmtemplate.version", getSystemVmTemplateVersion()); |
| updateConfigurationParams(configParams); |
| updateSystemVMEntries(templateId, hypervisorAndTemplateName.first()); |
| } catch (Exception e) { |
| String errMsg = String.format("Failed to register template for hypervisor: %s", hypervisorAndTemplateName.first()); |
| LOGGER.error(errMsg, e); |
| if (templateId != null) { |
| updateTemplateTablesOnFailure(templateId); |
| cleanupStore(templateId, filePath); |
| } |
| throw new CloudRuntimeException(errMsg, e); |
| } |
| } |
| |
| /** |
| * This method parses the metadata file consisting of the systemVM templates information |
| * @return the version of the systemvm template that is to be used. This is done in order |
| * to fallback on the latest available version of the systemVM template when there doesn't |
| * exist a template corresponding to the current code version. |
| */ |
| public static String parseMetadataFile() { |
| try { |
| Ini ini = new Ini(); |
| ini.load(new FileReader(METADATA_FILE)); |
| for (Hypervisor.HypervisorType hypervisorType : hypervisorList) { |
| String hypervisor = hypervisorType.name().toLowerCase(Locale.ROOT); |
| Ini.Section section = ini.get(hypervisor); |
| NewTemplateNameList.put(hypervisorType, section.get("templatename")); |
| FileNames.put(hypervisorType, section.get("filename")); |
| NewTemplateChecksum.put(hypervisorType, section.get("checksum")); |
| NewTemplateUrl.put(hypervisorType, section.get("downloadurl")); |
| } |
| Ini.Section section = ini.get("default"); |
| return section.get("version"); |
| } catch (Exception e) { |
| String errMsg = String.format("Failed to parse systemVM template metadata file: %s", METADATA_FILE); |
| LOGGER.error(errMsg, e); |
| throw new CloudRuntimeException(errMsg, e); |
| } |
| } |
| |
| private static void cleanupStore(Long templateId, String filePath) { |
| String destTempFolder = filePath + PARTIAL_TEMPLATE_FOLDER + String.valueOf(templateId); |
| try { |
| Files.deleteIfExists(Paths.get(destTempFolder)); |
| } catch (IOException e) { |
| LOGGER.error(String.format("Failed to cleanup mounted store at: %s", filePath), e); |
| } |
| } |
| |
| private void validateTemplates(Set<Hypervisor.HypervisorType> hypervisorsInUse) { |
| Set<String> hypervisors = hypervisorsInUse.stream().map(Enum::name). |
| map(name -> name.toLowerCase(Locale.ROOT)).map(this::getHypervisorName).collect(Collectors.toSet()); |
| List<String> templates = new ArrayList<>(); |
| for (Hypervisor.HypervisorType hypervisorType : hypervisorsInUse) { |
| templates.add(FileNames.get(hypervisorType)); |
| } |
| |
| boolean templatesFound = true; |
| for (String hypervisor : hypervisors) { |
| String matchedTemplate = templates.stream().filter(x -> x.contains(hypervisor)).findAny().orElse(null); |
| if (matchedTemplate == null) { |
| templatesFound = false; |
| break; |
| } |
| |
| File tempFile = new File(TEMPLATES_PATH + matchedTemplate); |
| String templateChecksum = DigestHelper.calculateChecksum(tempFile); |
| if (!templateChecksum.equals(NewTemplateChecksum.get(getHypervisorType(hypervisor)))) { |
| LOGGER.error(String.format("Checksum mismatch: %s != %s ", templateChecksum, NewTemplateChecksum.get(getHypervisorType(hypervisor)))); |
| templatesFound = false; |
| break; |
| } |
| } |
| |
| if (!templatesFound) { |
| String errMsg = "SystemVm template not found. Cannot upgrade system Vms"; |
| LOGGER.error(errMsg); |
| throw new CloudRuntimeException(errMsg); |
| } |
| } |
| |
| public void registerTemplates(Set<Hypervisor.HypervisorType> hypervisorsInUse) { |
| GlobalLock lock = GlobalLock.getInternLock("UpgradeDatabase-Lock"); |
| try { |
| LOGGER.info("Grabbing lock to register templates."); |
| if (!lock.lock(LOCK_WAIT_TIMEOUT)) { |
| throw new CloudRuntimeException("Unable to acquire lock to register SystemVM template."); |
| } |
| try { |
| validateTemplates(hypervisorsInUse); |
| // Perform Registration if templates not already registered |
| Transaction.execute(new TransactionCallbackNoReturn() { |
| @Override |
| public void doInTransactionWithoutResult(final TransactionStatus status) { |
| List<Long> zoneIds = getEligibleZoneIds(); |
| for (Long zoneId : zoneIds) { |
| String filePath = null; |
| try { |
| filePath = Files.createTempDirectory(TEMPORARY_SECONDARY_STORE).toString(); |
| if (filePath == null) { |
| throw new CloudRuntimeException("Failed to create temporary file path to mount the store"); |
| } |
| Pair<String, Long> storeUrlAndId = getNfsStoreInZone(zoneId); |
| mountStore(storeUrlAndId.first(), filePath); |
| List<String> hypervisorList = fetchAllHypervisors(zoneId); |
| for (String hypervisor : hypervisorList) { |
| Hypervisor.HypervisorType name = Hypervisor.HypervisorType.getType(hypervisor); |
| String templateName = NewTemplateNameList.get(name); |
| Pair<Hypervisor.HypervisorType, String> hypervisorAndTemplateName = new Pair<Hypervisor.HypervisorType, String>(name, templateName); |
| Long templateId = getRegisteredTemplateId(hypervisorAndTemplateName); |
| if (templateId != null) { |
| VMTemplateVO templateVO = vmTemplateDao.findById(templateId); |
| TemplateDataStoreVO templateDataStoreVO = templateDataStoreDao.findByTemplate(templateId, DataStoreRole.Image); |
| String installPath = templateDataStoreVO.getInstallPath(); |
| if (validateIfSeeded(storeUrlAndId.first(), installPath)) { |
| continue; |
| } else if (templateVO != null) { |
| registerTemplate(hypervisorAndTemplateName, storeUrlAndId, templateVO, templateDataStoreVO, filePath); |
| continue; |
| } |
| } |
| registerTemplate(hypervisorAndTemplateName, storeUrlAndId, filePath); |
| } |
| unmountStore(filePath); |
| } catch (Exception e) { |
| unmountStore(filePath); |
| throw new CloudRuntimeException("Failed to register systemVM template. Upgrade Failed"); |
| } |
| } |
| } |
| }); |
| } catch (Exception e) { |
| throw new CloudRuntimeException("Failed to register systemVM template. Upgrade Failed"); |
| } |
| } finally { |
| lock.unlock(); |
| lock.releaseRef(); |
| } |
| } |
| |
| private void updateRegisteredTemplateDetails(Long templateId, Map.Entry<Hypervisor.HypervisorType, String> hypervisorAndTemplateName) { |
| VMTemplateVO templateVO = vmTemplateDao.findById(templateId); |
| templateVO.setTemplateType(Storage.TemplateType.SYSTEM); |
| boolean updated = vmTemplateDao.update(templateVO.getId(), templateVO); |
| if (!updated) { |
| String errMsg = String.format("updateSystemVmTemplates:Exception while updating template with id %s to be marked as 'system'", templateId); |
| LOGGER.error(errMsg); |
| throw new CloudRuntimeException(errMsg); |
| } |
| |
| updateSystemVMEntries(templateId, hypervisorAndTemplateName.getKey()); |
| |
| // Change value of global configuration parameter router.template.* for the corresponding hypervisor and minreq.sysvmtemplate.version for the ACS version |
| Map<String, String> configParams = new HashMap<>(); |
| configParams.put(RouterTemplateConfigurationNames.get(hypervisorAndTemplateName.getKey()), hypervisorAndTemplateName.getValue()); |
| configParams.put("minreq.sysvmtemplate.version", getSystemVmTemplateVersion()); |
| updateConfigurationParams(configParams); |
| } |
| |
| private void updateTemplateUrlAndChecksum(VMTemplateVO templateVO, Map.Entry<Hypervisor.HypervisorType, String> hypervisorAndTemplateName) { |
| templateVO.setUrl(NewTemplateUrl.get(hypervisorAndTemplateName.getKey())); |
| templateVO.setChecksum(NewTemplateChecksum.get(hypervisorAndTemplateName.getKey())); |
| boolean updated = vmTemplateDao.update(templateVO.getId(), templateVO); |
| if (!updated) { |
| String errMsg = String.format("updateSystemVmTemplates:Exception while updating 'url' and 'checksum' for hypervisor type %s", hypervisorAndTemplateName.getKey().name()); |
| LOGGER.error(errMsg); |
| throw new CloudRuntimeException(errMsg); |
| } |
| } |
| |
| public void updateSystemVmTemplates(final Connection conn) { |
| LOGGER.debug("Updating System Vm template IDs"); |
| Transaction.execute(new TransactionCallbackNoReturn() { |
| @Override |
| public void doInTransactionWithoutResult(final TransactionStatus status) { |
| Set<Hypervisor.HypervisorType> hypervisorsListInUse = new HashSet<Hypervisor.HypervisorType>(); |
| try { |
| hypervisorsListInUse = clusterDao.getDistictAvailableHypervisorsAcrossClusters(); |
| |
| } catch (final Exception e) { |
| LOGGER.error("updateSystemVmTemplates: Exception caught while getting hypervisor types from clusters: " + e.getMessage()); |
| throw new CloudRuntimeException("updateSystemVmTemplates:Exception while getting hypervisor types from clusters", e); |
| } |
| |
| for (final Map.Entry<Hypervisor.HypervisorType, String> hypervisorAndTemplateName : NewTemplateNameList.entrySet()) { |
| LOGGER.debug("Updating " + hypervisorAndTemplateName.getKey() + " System Vms"); |
| Long templateId = getRegisteredTemplateId(new Pair<>(hypervisorAndTemplateName.getKey(), hypervisorAndTemplateName.getValue())); |
| try { |
| // change template type to SYSTEM |
| if (templateId != null) { |
| updateRegisteredTemplateDetails(templateId, hypervisorAndTemplateName); |
| } else { |
| if (hypervisorsListInUse.contains(hypervisorAndTemplateName.getKey())) { |
| try { |
| registerTemplates(hypervisorsListInUse); |
| break; |
| } catch (final Exception e) { |
| throw new CloudRuntimeException(String.format("%s %s SystemVm template not found. Cannot upgrade system Vms", getSystemVmTemplateVersion(), hypervisorAndTemplateName.getKey())); |
| } |
| } else { |
| LOGGER.warn(String.format("%s %s SystemVm template not found. Cannot upgrade system Vms hypervisor is not used, so not failing upgrade", |
| getSystemVmTemplateVersion(), hypervisorAndTemplateName.getKey())); |
| // Update the latest template URLs for corresponding hypervisor |
| VMTemplateVO templateVO = vmTemplateDao.findLatestTemplateByTypeAndHypervisor(hypervisorAndTemplateName.getKey(), Storage.TemplateType.SYSTEM); |
| if (templateVO != null) { |
| updateTemplateUrlAndChecksum(templateVO, hypervisorAndTemplateName); |
| } |
| } |
| } |
| } catch (final Exception e) { |
| String errMsg = "updateSystemVmTemplates:Exception while getting ids of templates"; |
| LOGGER.error(errMsg, e); |
| throw new CloudRuntimeException(errMsg, e); |
| } |
| } |
| LOGGER.debug("Updating System Vm Template IDs Complete"); |
| } |
| }); |
| } |
| } |