hypervisorGuestOsMap = new HashMap<>() {
+ {
+ put(Hypervisor.HypervisorType.KVM, LINUX_12_ID);
+ put(Hypervisor.HypervisorType.XenServer, OTHER_LINUX_ID);
+ put(Hypervisor.HypervisorType.VMware, OTHER_LINUX_ID);
+ put(Hypervisor.HypervisorType.Hyperv, LINUX_12_ID);
+ put(Hypervisor.HypervisorType.LXC, LINUX_12_ID);
+ put(Hypervisor.HypervisorType.Ovm3, LINUX_12_ID);
}
+ };
+
+ private static boolean isRunningInTest() {
+ return "true".equalsIgnoreCase(System.getProperty("test.mode"));
}
private static String getHypervisorArchLog(Hypervisor.HypervisorType hypervisorType, CPU.CPUArch arch) {
StringBuilder sb = new StringBuilder("hypervisor: ").append(hypervisorType.name());
- if (Hypervisor.HypervisorType.KVM.equals(hypervisorType)) {
- sb.append(", arch: ").append(arch == null ? CPU.CPUArch.amd64.getType() : arch.getType());
- }
+ sb.append(", arch: ").append(arch == null ? CPU.CPUArch.amd64.getType() : arch.getType());
return sb.toString();
}
- protected static String getHypervisorArchKey(Hypervisor.HypervisorType hypervisorType, CPU.CPUArch arch) {
- if (Hypervisor.HypervisorType.KVM.equals(hypervisorType)) {
- return String.format("%s-%s", hypervisorType.name().toLowerCase(),
- arch == null ? CPU.CPUArch.amd64.getType() : arch.getType());
- }
- return hypervisorType.name().toLowerCase();
- }
-
- protected static MetadataTemplateDetails getMetadataTemplateDetails(Hypervisor.HypervisorType hypervisorType,
- CPU.CPUArch arch) {
- return NewTemplateMap.get(getHypervisorArchKey(hypervisorType, arch));
- }
-
- public VMTemplateVO getRegisteredTemplate(String templateName, CPU.CPUArch arch) {
- return vmTemplateDao.findLatestTemplateByName(templateName, arch);
- }
-
- private static boolean isRunningInTest() {
- return "true".equalsIgnoreCase(System.getProperty("test.mode"));
- }
-
/**
* Attempts to determine the templates directory path by locating the metadata file.
*
@@ -460,7 +399,170 @@ private static String fetchTemplatesPath() {
throw new CloudRuntimeException(errMsg);
}
- private List getEligibleZoneIds() {
+ protected 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("Failed to cleanup mounted store at: {}", filePath, e);
+ }
+ }
+
+ protected static Pair readTemplatePropertiesSizes(String path) {
+ 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);
+ }
+ return new Pair<>(size, physicalSize);
+ }
+
+ protected static MetadataTemplateDetails getMetadataTemplateDetails(Hypervisor.HypervisorType hypervisorType,
+ CPU.CPUArch arch) {
+ return METADATA_TEMPLATE_LIST
+ .stream()
+ .filter(x -> Objects.equals(x.getHypervisorType(), hypervisorType) &&
+ Objects.equals(x.getArch(), arch))
+ .findFirst()
+ .orElse(null);
+ }
+
+ protected static String getMetadataFilePath() {
+ return METADATA_FILE;
+ }
+
+ protected static Ini.Section getMetadataSectionForHypervisorAndArch(Ini ini,
+ Hypervisor.HypervisorType hypervisorType, CPU.CPUArch arch) {
+ String key = String.format("%s-%s", hypervisorType.name().toLowerCase(),
+ arch.getType().toLowerCase());
+ Ini.Section section = ini.get(key);
+ if (section == null && !Hypervisor.HypervisorType.KVM.equals(hypervisorType)) {
+ key = String.format("%s", hypervisorType.name().toLowerCase());
+ section = ini.get(key);
+ }
+ return section;
+ }
+
+ protected static String getMountCommand(String nfsVersion, String device, String dir) {
+ String cmd = MOUNT_COMMAND_BASE;
+ if (StringUtils.isNotBlank(nfsVersion)) {
+ cmd = String.format("%s -o vers=%s", cmd, nfsVersion);
+ }
+ return String.format("%s %s %s", cmd, device, dir);
+ }
+
+ /**
+ * This method parses the metadata file consisting of the system VM Templates information
+ * @return the version of the system VM Template that is to be used. This is done in order
+ * to fallback on the latest available version of the system VM Template when there doesn't
+ * exist a template corresponding to the current code version.
+ */
+ public static String parseMetadataFile() {
+ String metadataFilePath = getMetadataFilePath();
+ String errMsg = String.format("Failed to parse system VM Template metadata file: %s", metadataFilePath);
+ final Ini ini = new Ini();
+ try (FileReader reader = new FileReader(metadataFilePath)) {
+ ini.load(reader);
+ } catch (IOException e) {
+ LOGGER.error(errMsg, e);
+ throw new CloudRuntimeException(errMsg, e);
+ }
+ if (!ini.containsKey("default")) {
+ errMsg = String.format("%s as unable to default section", errMsg);
+ LOGGER.error(errMsg);
+ throw new CloudRuntimeException(errMsg);
+ }
+ Ini.Section defaultSection = ini.get("default");
+ String defaultDownloadRepository = defaultSection.get(TEMPLATES_DOWNLOAD_REPOSITORY_KEY);
+ String customDownloadRepository = ServerPropertiesUtil.getProperty(TEMPLATES_CUSTOM_DOWNLOAD_REPOSITORY_KEY);
+ boolean updateCustomDownloadRepository = StringUtils.isNotBlank(customDownloadRepository) &&
+ StringUtils.isNotBlank(defaultDownloadRepository);
+ for (Pair hypervisorTypeArchPair : AVAILABLE_SYSTEM_TEMPLATES_HYPERVISOR_ARCH_LIST) {
+ String key = String.format("%s-%s", hypervisorTypeArchPair.first().name().toLowerCase(),
+ hypervisorTypeArchPair.second().getType().toLowerCase());
+ Ini.Section section = getMetadataSectionForHypervisorAndArch(ini, hypervisorTypeArchPair.first(),
+ hypervisorTypeArchPair.second());
+ if (section == null) {
+ LOGGER.error("Failed to find details for {} in template metadata file: {}",
+ getHypervisorArchLog(hypervisorTypeArchPair.first(), hypervisorTypeArchPair.second()),
+ metadataFilePath);
+ continue;
+ }
+ String url = section.get(TEMPLATE_DOWNLOAD_URL_KEY);
+ if (StringUtils.isNotBlank(url) && updateCustomDownloadRepository) {
+ url = url.replaceFirst(defaultDownloadRepository.trim(),
+ customDownloadRepository.trim());
+ LOGGER.debug("Updated download URL for {} using custom repository to {}", key, url);
+ }
+ METADATA_TEMPLATE_LIST.add(new MetadataTemplateDetails(
+ hypervisorTypeArchPair.first(),
+ section.get("templatename"),
+ section.get("filename"),
+ url,
+ section.get("checksum"),
+ hypervisorTypeArchPair.second(),
+ section.get("guestos")));
+ }
+ return defaultSection.get("version").trim();
+ }
+
+ public static void mountStore(String storeUrl, String path, String nfsVersion) {
+ try {
+ if (storeUrl == null) {
+ return;
+ }
+ URI uri = new URI(UriUtils.encodeURIComponent(storeUrl));
+ String host = uri.getHost();
+ String mountPath = uri.getPath();
+ Script.runSimpleBashScript(getMountCommand(nfsVersion, host + ":" + mountPath, path));
+ } catch (Exception e) {
+ String msg = "NFS Store URL is not in the correct format";
+ LOGGER.error(msg, e);
+ throw new CloudRuntimeException(msg, e);
+ }
+ }
+
+ 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);
+ }
+ }
+
+ protected File getTempDownloadDir() {
+ return tempDownloadDir;
+ }
+
+ protected void readTemplateProperties(String path, SystemVMTemplateDetails details) {
+ Pair templateSizes = readTemplatePropertiesSizes(path);
+ details.setSize(templateSizes.first());
+ details.setPhysicalSize(templateSizes.second());
+ }
+
+ protected List getEligibleZoneIds() {
List zoneIds = new ArrayList<>();
List stores = imageStoreDao.findByProtocol("nfs");
for (ImageStoreVO store : stores) {
@@ -484,20 +586,11 @@ protected Pair getNfsStoreInZone(Long zoneId) {
return new Pair<>(url, storeId);
}
- public static void mountStore(String storeUrl, String path, String nfsVersion) {
- try {
- if (storeUrl == null) {
- return;
- }
- URI uri = new URI(UriUtils.encodeURIComponent(storeUrl));
- String host = uri.getHost();
- String mountPath = uri.getPath();
- Script.runSimpleBashScript(getMountCommand(nfsVersion, host + ":" + mountPath, path));
- } catch (Exception e) {
- String msg = "NFS Store URL is not in the correct format";
- LOGGER.error(msg, e);
- throw new CloudRuntimeException(msg, e);
+ protected String getSystemVmTemplateVersion() {
+ if (StringUtils.isEmpty(systemVmTemplateVersion)) {
+ return String.format("%s.%s", CS_MAJOR_VERSION, CS_TINY_VERSION);
}
+ return systemVmTemplateVersion;
}
private VMTemplateVO createTemplateObjectInDB(SystemVMTemplateDetails details) {
@@ -527,7 +620,7 @@ private VMTemplateVO createTemplateObjectInDB(SystemVMTemplateDetails details) {
return template;
}
- private VMTemplateZoneVO createOrUpdateTemplateZoneEntry(long zoneId, long templateId) {
+ protected VMTemplateZoneVO createOrUpdateTemplateZoneEntry(long zoneId, long templateId) {
VMTemplateZoneVO templateZoneVO = vmTemplateZoneDao.findByZoneTemplate(zoneId, templateId);
if (templateZoneVO == null) {
templateZoneVO = new VMTemplateZoneVO(zoneId, templateId, new java.util.Date());
@@ -541,33 +634,37 @@ private VMTemplateZoneVO createOrUpdateTemplateZoneEntry(long zoneId, long templ
return templateZoneVO;
}
- private void createCrossZonesTemplateZoneRefEntries(Long templateId) {
+ protected void createCrossZonesTemplateZoneRefEntries(Long templateId) {
List dcs = dataCenterDao.listAll();
for (DataCenterVO dc : dcs) {
VMTemplateZoneVO templateZoneVO = createOrUpdateTemplateZoneEntry(dc.getId(), templateId);
if (templateZoneVO == null) {
- throw new CloudRuntimeException(String.format("Failed to create template_zone_ref record for the systemVM Template (id: %s) and zone: %s", templateId, dc));
+ throw new CloudRuntimeException(String.format("Failed to create template-zone record for the system " +
+ "VM Template (ID : %d) and zone: %s", templateId, 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());
+ protected void createTemplateStoreRefEntry(SystemVMTemplateDetails details) {
+ TemplateDataStoreVO templateDataStoreVO = new TemplateDataStoreVO(details.getStoreId(), 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()));
+ throw new CloudRuntimeException(String.format("Failed to create template-store record for the system VM " +
+ "template (ID : %d) and store (ID: %d)", details.getId(), details.getStoreId()));
}
}
- public void updateTemplateDetails(SystemVMTemplateDetails details) {
+ protected 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 templateDataStoreVO = templateDataStoreDao.findByStoreTemplate(details.getStoreId(),
+ template.getId());
templateDataStoreVO.setSize(details.getSize());
templateDataStoreVO.setPhysicalSize(details.getPhysicalSize());
templateDataStoreVO.setDownloadPercent(100);
@@ -576,11 +673,11 @@ public void updateTemplateDetails(SystemVMTemplateDetails details) {
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");
+ throw new CloudRuntimeException("Failed to update template-store record for registered system VM Template");
}
}
- public void updateSeededTemplateDetails(long templateId, long storeId, long size, long physicalSize) {
+ protected void updateSeededTemplateDetails(long templateId, long storeId, long size, long physicalSize) {
VMTemplateVO template = vmTemplateDao.findById(templateId);
template.setSize(size);
vmTemplateDao.update(template.getId(), template);
@@ -591,108 +688,77 @@ public void updateSeededTemplateDetails(long templateId, long storeId, long size
templateDataStoreVO.setLastUpdated(new Date(DateUtil.currentGMTTime().getTime()));
boolean updated = templateDataStoreDao.update(templateDataStoreVO.getId(), templateDataStoreVO);
if (!updated) {
- throw new CloudRuntimeException("Failed to update template_store_ref entry for seeded systemVM template");
+ throw new CloudRuntimeException("Failed to update template-store record for seeded system VM Template");
}
}
- public void updateSystemVMEntries(Long templateId, Hypervisor.HypervisorType hypervisorType) {
+ protected void updateSystemVMEntries(Long templateId, Hypervisor.HypervisorType hypervisorType) {
vmInstanceDao.updateSystemVmTemplateId(templateId, hypervisorType);
}
- private void updateSystemVmTemplateGuestOsId() {
- String systemVmGuestOsName = "Debian GNU/Linux 12 (64-bit)"; // default
+ protected void updateHypervisorGuestOsMap() {
try {
- GuestOSVO guestOS = guestOSDao.findOneByDisplayName(systemVmGuestOsName);
- if (guestOS != null) {
- LOGGER.debug("Updating SystemVM Template Guest OS [{}] id", systemVmGuestOsName);
- SystemVmTemplateRegistration.LINUX_12_ID = Math.toIntExact(guestOS.getId());
- hypervisorGuestOsMap.put(Hypervisor.HypervisorType.KVM, LINUX_12_ID);
- hypervisorGuestOsMap.put(Hypervisor.HypervisorType.Hyperv, LINUX_12_ID);
- hypervisorGuestOsMap.put(Hypervisor.HypervisorType.LXC, LINUX_12_ID);
- hypervisorGuestOsMap.put(Hypervisor.HypervisorType.Ovm3, LINUX_12_ID);
+ GuestOSVO guestOS = guestOSDao.findOneByDisplayName(DEFAULT_SYSTEM_VM_GUEST_OS_NAME);
+ if (guestOS == null) {
+ LOGGER.warn("Couldn't find Guest OS by name [{}] to update system VM Template guest OS ID",
+ DEFAULT_SYSTEM_VM_GUEST_OS_NAME);
+ return;
}
+ LOGGER.debug("Updating system VM Template guest OS [{}] ID", DEFAULT_SYSTEM_VM_GUEST_OS_NAME);
+ SystemVmTemplateRegistration.LINUX_12_ID = Math.toIntExact(guestOS.getId());
+ hypervisorGuestOsMap.put(Hypervisor.HypervisorType.KVM, LINUX_12_ID);
+ hypervisorGuestOsMap.put(Hypervisor.HypervisorType.Hyperv, LINUX_12_ID);
+ hypervisorGuestOsMap.put(Hypervisor.HypervisorType.LXC, LINUX_12_ID);
+ hypervisorGuestOsMap.put(Hypervisor.HypervisorType.Ovm3, LINUX_12_ID);
} catch (Exception e) {
- LOGGER.warn("Couldn't update SystemVM Template Guest OS id, due to {}", e.getMessage());
+ LOGGER.warn("Couldn't update System VM template guest OS ID, due to {}", e.getMessage());
}
}
- public void updateConfigurationParams(Map configParams) {
- for (Map.Entry 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()));
- }
+ protected void updateConfigurationParams(Hypervisor.HypervisorType hypervisorType, String templateName, Long zoneId) {
+ String configName = ROUTER_TEMPLATE_CONFIGURATION_NAMES.get(hypervisorType);
+ boolean updated = configurationDao.update(configName, templateName);
+ if (!updated) {
+ throw new CloudRuntimeException(String.format("Failed to update configuration parameter %s", configName));
}
- }
-
- private static Pair readTemplatePropertiesSizes(String path) {
- 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);
+ if (zoneId != null) {
+ dataCenterDetailsDao.removeDetail(zoneId, configName);
+ }
+ updated = configurationDao.update(MINIMUM_SYSTEM_VM_VERSION_KEY, getSystemVmTemplateVersion());
+ if (!updated) {
+ throw new CloudRuntimeException(String.format("Failed to update configuration parameter %s", configName));
+ }
+ if (zoneId != null) {
+ dataCenterDetailsDao.removeDetail(zoneId, MINIMUM_SYSTEM_VM_VERSION_KEY);
}
- return new Pair<>(size, physicalSize);
- }
-
- public static void readTemplateProperties(String path, SystemVMTemplateDetails details) {
- Pair templateSizes = readTemplatePropertiesSizes(path);
- details.setSize(templateSizes.first());
- details.setPhysicalSize(templateSizes.second());
}
- private void updateTemplateTablesOnFailure(long templateId) {
+ protected void updateTemplateEntriesOnFailure(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);
+ TemplateDataStoreVO templateDataStoreVO = templateDataStoreDao.findByTemplate(template.getId(),
+ DataStoreRole.Image);
+ if (templateDataStoreVO == null) {
+ return;
}
+ templateDataStoreDao.remove(templateDataStoreVO.getId());
}
- private void setupTemplate(String templateName, Hypervisor.HypervisorType hypervisor, CPU.CPUArch arch,
- String destTempFolder) throws CloudRuntimeException {
- String setupTmpltScript = Script.findScript(storageScriptsDir, "setup-sysvm-tmplt");
+ protected void setupTemplateOnStore(String templateName, MetadataTemplateDetails templateDetails,
+ String destTempFolder) throws CloudRuntimeException {
+ String setupTmpltScript = Script.findScript(STORAGE_SCRIPTS_DIR, "setup-sysvm-tmplt");
if (setupTmpltScript == null) {
- throw new CloudRuntimeException("Unable to find the createtmplt.sh");
+ throw new CloudRuntimeException("Unable to find the setup-sysvm-tmplt script");
}
Script scr = new Script(setupTmpltScript, SCRIPT_TIMEOUT, LOGGER);
scr.add("-u", templateName);
- MetadataTemplateDetails templateDetails = NewTemplateMap.get(getHypervisorArchKey(hypervisor, arch));
String filePath = StringUtils.isNotBlank(templateDetails.getDownloadedFilePath()) ?
templateDetails.getDownloadedFilePath() :
templateDetails.getDefaultFilePath();
scr.add("-f", filePath);
- scr.add("-h", hypervisor.name().toLowerCase(Locale.ROOT));
+ scr.add("-h", templateDetails.getHypervisorType().name().toLowerCase(Locale.ROOT));
scr.add("-d", destTempFolder);
String result = scr.execute();
if (result != null) {
@@ -702,17 +768,33 @@ private void setupTemplate(String templateName, Hypervisor.HypervisorType hyperv
}
}
- private Long performTemplateRegistrationOperations(Hypervisor.HypervisorType hypervisor,
- String name, CPU.CPUArch arch, String url, String checksum, ImageFormat format, long guestOsId,
- Long storeId, Long templateId, String filePath, TemplateDataStoreVO templateDataStoreVO) {
+ /**
+ * Register or update a system VM Template record and seed it on the target store.
+ *
+ * @param name display name of the template
+ * @param templateDetails metadata for the template
+ * @param url download URL of the template
+ * @param checksum expected checksum of the template file
+ * @param format image format of the template
+ * @param guestOsId guest OS id
+ * @param storeId target image store id
+ * @param templateId existing template id if present, otherwise {@code null}
+ * @param filePath temporary mount path for the store
+ * @param templateDataStoreVO existing template-store mapping; may be {@code null}
+ * @return the id of the template that was created or updated
+ */
+ protected Long performTemplateRegistrationOperations(String name, MetadataTemplateDetails templateDetails,
+ String url, String checksum, ImageFormat format, long guestOsId, Long storeId, Long templateId,
+ String filePath, TemplateDataStoreVO templateDataStoreVO) {
String templateName = UUID.randomUUID().toString();
Date created = new Date(DateUtil.currentGMTTime().getTime());
- SystemVMTemplateDetails details = new SystemVMTemplateDetails(templateName, name, created,
- url, checksum, format, (int) guestOsId, hypervisor, arch, storeId);
+ SystemVMTemplateDetails details = new SystemVMTemplateDetails(templateName, name, created, url, checksum,
+ format, (int) guestOsId, templateDetails.getHypervisorType(), templateDetails.getArch(), 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()));
+ throw new CloudRuntimeException(String.format("Failed to register Template for hypervisor: %s",
+ templateDetails.getHypervisorType().name()));
}
templateId = template.getId();
}
@@ -721,153 +803,126 @@ private Long performTemplateRegistrationOperations(Hypervisor.HypervisorType hyp
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());
+ details.setInstallPath(String.format("%s%s%s%s.%s", PARTIAL_TEMPLATE_FOLDER, destTempFolderName,
+ File.separator, templateName,
+ HYPERVISOR_IMAGE_FORMAT_MAP.get(templateDetails.getHypervisorType()).getFileExtension()));
if (templateDataStoreVO == null) {
createTemplateStoreRefEntry(details);
}
- setupTemplate(templateName, hypervisor, arch, destTempFolder);
+ setupTemplateOnStore(templateName, templateDetails, destTempFolder);
readTemplateProperties(destTempFolder + "/template.properties", details);
details.setUpdated(new Date(DateUtil.currentGMTTime().getTime()));
updateTemplateDetails(details);
return templateId;
}
- public void registerTemplate(Hypervisor.HypervisorType hypervisor, String name, Long storeId,
- VMTemplateVO templateVO, TemplateDataStoreVO templateDataStoreVO, String filePath) {
+ /**
+ * Add an existing system VM Template to a secondary image store and update related DB entries.
+ *
+ * @param templateVO the existing VM template (must not be null)
+ * @param templateDetails the metadata details of the template to be added
+ * @param templateDataStoreVO optional existing template-store mapping; may be null
+ * @param zoneId zone id where the operation is performed
+ * @param storeId target image store id
+ * @param filePath temporary mount path for the store
+ * @throws CloudRuntimeException on failure; the method attempts rollback/cleanup
+ */
+ protected void addExistingTemplateToStore(VMTemplateVO templateVO, MetadataTemplateDetails templateDetails,
+ TemplateDataStoreVO templateDataStoreVO, long zoneId, Long storeId, String filePath) {
try {
- performTemplateRegistrationOperations(hypervisor, name, templateVO.getArch(), templateVO.getUrl(),
+ performTemplateRegistrationOperations(templateVO.getName(), templateDetails, templateVO.getUrl(),
templateVO.getChecksum(), templateVO.getFormat(), templateVO.getGuestOSId(), storeId,
templateVO.getId(), filePath, templateDataStoreVO);
} catch (Exception e) {
- String errMsg = String.format("Failed to register Template for hypervisor: %s", hypervisor);
+ String errMsg = String.format("Failed to add %s to store ID: %d, zone ID: %d", templateVO, storeId, zoneId);
LOGGER.error(errMsg, e);
- updateTemplateTablesOnFailure(templateVO.getId());
cleanupStore(templateVO.getId(), filePath);
throw new CloudRuntimeException(errMsg, e);
}
}
- public void registerTemplateForNonExistingEntries(Hypervisor.HypervisorType hypervisor, CPU.CPUArch arch,
- String name, Pair storeUrlAndId, String filePath) {
+ /**
+ * Registers a new system VM Template for the given hypervisor/arch when no existing template is present.
+ *
+ * @param name the name of the new template
+ * @param templateDetails the metadata details of the template to be registered
+ * @param zoneId the zone id for which the new template should be seeded
+ * @param storeId the store id on which the new template will be seeded
+ * @param filePath temporary mount path for the store
+ * @throws CloudRuntimeException on failure; the method attempts rollback/cleanup
+ */
+ protected void registerNewTemplate(String name, MetadataTemplateDetails templateDetails, long zoneId, Long storeId,
+ String filePath) {
Long templateId = null;
+ Hypervisor.HypervisorType hypervisor = templateDetails.getHypervisorType();
try {
- MetadataTemplateDetails templateDetails = getMetadataTemplateDetails(hypervisor, arch);
- templateId = performTemplateRegistrationOperations(hypervisor, name,
- templateDetails.getArch(), templateDetails.getUrl(),
- templateDetails.getChecksum(), hypervisorImageFormat.get(hypervisor),
- hypervisorGuestOsMap.get(hypervisor), storeUrlAndId.second(), null, filePath, null);
- Map configParams = new HashMap<>();
- configParams.put(RouterTemplateConfigurationNames.get(hypervisor), templateDetails.getName());
- configParams.put("minreq.sysvmtemplate.version", getSystemVmTemplateVersion());
- updateConfigurationParams(configParams);
+ templateId = performTemplateRegistrationOperations(name, templateDetails, templateDetails.getUrl(),
+ templateDetails.getChecksum(), HYPERVISOR_IMAGE_FORMAT_MAP.get(hypervisor),
+ hypervisorGuestOsMap.get(hypervisor), storeId, null, filePath, null);
+ updateConfigurationParams(hypervisor, name, zoneId);
updateSystemVMEntries(templateId, hypervisor);
} catch (Exception e) {
String errMsg = String.format("Failed to register Template for hypervisor: %s", hypervisor);
LOGGER.error(errMsg, e);
if (templateId != null) {
- updateTemplateTablesOnFailure(templateId);
+ updateTemplateEntriesOnFailure(templateId);
cleanupStore(templateId, filePath);
}
throw new CloudRuntimeException(errMsg, e);
}
}
- protected void validateTemplateFileForHypervisorAndArch(Hypervisor.HypervisorType hypervisor, CPU.CPUArch arch) {
+ /**
+ * Validate presence and integrity of metadata and local template file for the given hypervisor/arch.
+ *
+ * @param hypervisor target hypervisor type
+ * @param arch target CPU architecture
+ * @return validated MetadataTemplateDetails
+ * @throws CloudRuntimeException if template is not available, missing, or checksum validation fails
+ */
+ protected MetadataTemplateDetails getValidatedTemplateDetailsForHypervisorAndArch(
+ Hypervisor.HypervisorType hypervisor, CPU.CPUArch arch) {
+ if (!AVAILABLE_SYSTEM_TEMPLATES_HYPERVISOR_ARCH_LIST.contains(new Pair<>(hypervisor, arch))) {
+ throw new CloudRuntimeException("No system VM Template available for the given hypervisor and arch");
+ }
MetadataTemplateDetails templateDetails = getMetadataTemplateDetails(hypervisor, arch);
+ if (templateDetails == null) {
+ throw new CloudRuntimeException("No template details found for the given hypervisor and arch");
+ }
File templateFile = getTemplateFile(templateDetails);
if (templateFile == null) {
throw new CloudRuntimeException("Failed to find local template file");
}
- if (isTemplateFileChecksumDifferent(templateDetails, templateFile)) {
+ if (templateDetails.isFileChecksumDifferent(templateFile)) {
throw new CloudRuntimeException("Checksum failed for local template file");
}
- }
-
- public void validateAndRegisterTemplate(Hypervisor.HypervisorType hypervisor, String name, Long storeId,
- VMTemplateVO templateVO, TemplateDataStoreVO templateDataStoreVO, String filePath) {
- validateTemplateFileForHypervisorAndArch(hypervisor, templateVO.getArch());
- registerTemplate(hypervisor, name, storeId, templateVO, templateDataStoreVO, filePath);
- }
-
- public void validateAndRegisterTemplateForNonExistingEntries(Hypervisor.HypervisorType hypervisor,
- CPU.CPUArch arch, String name, Pair storeUrlAndId, String filePath) {
- validateTemplateFileForHypervisorAndArch(hypervisor, arch);
- registerTemplateForNonExistingEntries(hypervisor, arch, name, storeUrlAndId, filePath);
- }
-
- protected static String getMetadataFilePath() {
- return METADATA_FILE;
+ return templateDetails;
}
/**
- * 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.
+ * Return the local template file. Downloads it if not present locally and url is present.
+ *
+ * @param templateDetails template metadata; may set `downloadedFilePath`
+ * @return the template {@code File} on disk, or {@code null} if not found/downloaded
*/
- public static String parseMetadataFile() {
- String metadataFilePath = getMetadataFilePath();
- String errMsg = String.format("Failed to parse systemVM Template metadata file: %s", metadataFilePath);
- final Ini ini = new Ini();
- try (FileReader reader = new FileReader(metadataFilePath)) {
- ini.load(reader);
- } catch (IOException e) {
- LOGGER.error(errMsg, e);
- throw new CloudRuntimeException(errMsg, e);
- }
- if (!ini.containsKey("default")) {
- errMsg = String.format("%s as unable to default section", errMsg);
- LOGGER.error(errMsg);
- throw new CloudRuntimeException(errMsg);
- }
- for (Pair hypervisorType : hypervisorList) {
- String key = getHypervisorArchKey(hypervisorType.first(), hypervisorType.second());
- Ini.Section section = ini.get(key);
- if (section == null) {
- LOGGER.error("Failed to find details for {} in template metadata file: {}",
- key, metadataFilePath);
- continue;
- }
- NewTemplateMap.put(key, new MetadataTemplateDetails(
- hypervisorType.first(),
- section.get("templatename"),
- section.get("filename"),
- section.get("downloadurl"),
- section.get("checksum"),
- hypervisorType.second(),
- section.get("guestos")));
- }
- Ini.Section defaultSection = ini.get("default");
- return defaultSection.get("version").trim();
- }
-
-
- 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);
- }
- }
-
protected File getTemplateFile(MetadataTemplateDetails templateDetails) {
File templateFile = new File(templateDetails.getDefaultFilePath());
if (templateFile.exists()) {
return templateFile;
}
LOGGER.debug("{} is not present", templateFile.getAbsolutePath());
- if (DOWNLOADABLE_TEMPLATE_ARCH_TYPES.contains(templateDetails.getArch()) &&
- StringUtils.isNotBlank(templateDetails.getUrl())) {
+ if (StringUtils.isNotBlank(templateDetails.getUrl())) {
LOGGER.debug("Downloading the template file {} for {}",
templateDetails.getUrl(), templateDetails.getHypervisorArchLog());
Path path = Path.of(TEMPLATES_PATH);
if (!Files.isWritable(path)) {
- templateFile = new File(tempDownloadDir, templateDetails.getFilename());
+ templateFile = new File(getTempDownloadDir(), templateDetails.getFilename());
}
if (!templateFile.exists() &&
!HttpUtils.downloadFileWithProgress(templateDetails.getUrl(), templateFile.getAbsolutePath(),
LOGGER)) {
+ LOGGER.error("Failed to download template for {} using url: {}",
+ templateDetails.getHypervisorArchLog(), templateDetails.getUrl());
return null;
}
templateDetails.setDownloadedFilePath(templateFile.getAbsolutePath());
@@ -875,32 +930,28 @@ protected File getTemplateFile(MetadataTemplateDetails templateDetails) {
return templateFile;
}
- protected boolean isTemplateFileChecksumDifferent(MetadataTemplateDetails templateDetails, File templateFile) {
- String templateChecksum = DigestHelper.calculateChecksum(templateFile);
- if (!templateChecksum.equals(templateDetails.getChecksum())) {
- LOGGER.error("Checksum {} for file {} does not match checksum {} from metadata",
- templateChecksum, templateFile, templateDetails.getChecksum());
- return true;
- }
- return false;
- }
-
- protected void validateTemplates(List> hypervisorsArchInUse) {
+ /**
+ * Validate that templates for the provided hypervisor/architecture pairs which are in use and are valid.
+ *
+ * If a template is missing or validation fails for any required pair, a
+ * {@link CloudRuntimeException} is thrown to abort the upgrade. If system VM Template for a hypervisor/arch is
+ * not considered available then validation is skipped for that pair.
+ *
+ * @param hypervisorArchList list of hypervisor/architecture pairs to validate
+ */
+ protected void validateTemplates(List> hypervisorArchList) {
boolean templatesFound = true;
- for (Pair hypervisorArch : hypervisorsArchInUse) {
- MetadataTemplateDetails matchedTemplate = getMetadataTemplateDetails(hypervisorArch.first(),
- hypervisorArch.second());
- if (matchedTemplate == null) {
- templatesFound = false;
- break;
- }
- File tempFile = getTemplateFile(matchedTemplate);
- if (tempFile == null) {
- LOGGER.warn("Failed to download template for {}, moving ahead",
- matchedTemplate.getHypervisorArchLog());
+ for (Pair hypervisorArch : hypervisorArchList) {
+ if (!AVAILABLE_SYSTEM_TEMPLATES_HYPERVISOR_ARCH_LIST.contains(hypervisorArch)) {
+ LOGGER.info("No system VM Template available for {}. Skipping validation.",
+ getHypervisorArchLog(hypervisorArch.first(), hypervisorArch.second()));
continue;
}
- if (isTemplateFileChecksumDifferent(matchedTemplate, tempFile)) {
+ try {
+ getValidatedTemplateDetailsForHypervisorAndArch(hypervisorArch.first(), hypervisorArch.second());
+ } catch (CloudRuntimeException e) {
+ LOGGER.error("Validation failed for {}: {}",
+ getHypervisorArchLog(hypervisorArch.first(), hypervisorArch.second()), e.getMessage());
templatesFound = false;
break;
}
@@ -912,10 +963,20 @@ protected void validateTemplates(List storeUrlAndId = getNfsStoreInZone(zoneId);
String nfsVersion = getNfsVersion(storeUrlAndId.second());
- mountStore(storeUrlAndId.first(), filePath, nfsVersion);
+ mountStore(storeUrlAndId.first(), storeMountPath, nfsVersion);
List> hypervisorArchList =
clusterDao.listDistinctHypervisorsAndArchExcludingExternalType(zoneId);
for (Pair hypervisorArch : hypervisorArchList) {
@@ -925,7 +986,8 @@ protected void registerTemplatesForZone(long zoneId, String filePath) {
if (templateDetails == null) {
continue;
}
- VMTemplateVO templateVO = getRegisteredTemplate(templateDetails.getName(), templateDetails.getArch());
+ VMTemplateVO templateVO = getRegisteredTemplate(templateDetails.getName(),
+ templateDetails.getHypervisorType(), templateDetails.getArch(), templateDetails.getUrl());
if (templateVO != null) {
TemplateDataStoreVO templateDataStoreVO =
templateDataStoreDao.findByStoreTemplate(storeUrlAndId.second(), templateVO.getId());
@@ -935,22 +997,22 @@ protected void registerTemplatesForZone(long zoneId, String filePath) {
continue;
}
}
- registerTemplate(hypervisorType, templateDetails.getName(), storeUrlAndId.second(), templateVO,
- templateDataStoreVO, filePath);
- updateRegisteredTemplateDetails(templateVO.getId(), templateDetails);
+ addExistingTemplateToStore(templateVO, templateDetails, templateDataStoreVO, zoneId,
+ storeUrlAndId.second(), storeMountPath);
+ updateRegisteredTemplateDetails(templateVO.getId(), templateDetails, zoneId);
continue;
}
- registerTemplateForNonExistingEntries(hypervisorType, templateDetails.getArch(), templateDetails.getName(),
- storeUrlAndId, filePath);
+ registerNewTemplate(templateDetails.getName(), templateDetails, zoneId, storeUrlAndId.second(),
+ storeMountPath);
}
}
- public void registerTemplates(List> hypervisorsArchInUse) {
+ protected void registerTemplates(List> hypervisorsArchInUse) {
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.");
+ throw new CloudRuntimeException("Unable to acquire lock to register system VM Template.");
}
try {
validateTemplates(hypervisorsArchInUse);
@@ -970,13 +1032,13 @@ public void doInTransactionWithoutResult(final TransactionStatus status) {
unmountStore(filePath);
} catch (Exception e) {
unmountStore(filePath);
- throw new CloudRuntimeException("Failed to register SystemVM Template. Upgrade failed");
+ throw new CloudRuntimeException("Failed to register system VM Template. Upgrade Failed");
}
}
}
});
} catch (Exception e) {
- throw new CloudRuntimeException("Failed to register SystemVM Template. Upgrade failed");
+ throw new CloudRuntimeException("Failed to register system VM Template. Upgrade Failed");
}
} finally {
lock.unlock();
@@ -984,7 +1046,18 @@ public void doInTransactionWithoutResult(final TransactionStatus status) {
}
}
- private void updateRegisteredTemplateDetails(Long templateId, MetadataTemplateDetails templateDetails) {
+ /**
+ * Update the DB record for an existing template to mark it as a system template,
+ * set the guest OS (if resolvable), and propagate the change to system VM entries
+ * and related configuration for the template's hypervisor.
+ *
+ * @param templateId id of the template to update
+ * @param templateDetails metadata used to update the template record
+ * @param zoneId zone id whose per-zone details (if any) should be cleared; may be null
+ * @throws CloudRuntimeException if updating the template record fails
+ */
+ protected void updateRegisteredTemplateDetails(Long templateId, MetadataTemplateDetails templateDetails,
+ Long zoneId) {
VMTemplateVO templateVO = vmTemplateDao.findById(templateId);
templateVO.setTemplateType(Storage.TemplateType.SYSTEM);
GuestOSVO guestOS = guestOSDao.findOneByDisplayName(templateDetails.getGuestOs());
@@ -993,20 +1066,18 @@ private void updateRegisteredTemplateDetails(Long templateId, MetadataTemplateDe
}
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);
+ String errMsg = String.format("Exception while updating template with id %s to be marked as 'system'",
+ templateId);
LOGGER.error(errMsg);
throw new CloudRuntimeException(errMsg);
}
Hypervisor.HypervisorType hypervisorType = templateDetails.getHypervisorType();
updateSystemVMEntries(templateId, hypervisorType);
- // Change value of global configuration parameter router.template.* for the corresponding hypervisor and minreq.sysvmtemplate.version for the ACS version
- Map configParams = new HashMap<>();
- configParams.put(RouterTemplateConfigurationNames.get(hypervisorType), templateDetails.getName());
- configParams.put("minreq.sysvmtemplate.version", getSystemVmTemplateVersion());
- updateConfigurationParams(configParams);
+ updateConfigurationParams(hypervisorType, templateDetails.getName(), zoneId);
}
- private void updateTemplateUrlChecksumAndGuestOsId(VMTemplateVO templateVO, MetadataTemplateDetails templateDetails) {
+ protected void updateTemplateUrlChecksumAndGuestOsId(VMTemplateVO templateVO,
+ MetadataTemplateDetails templateDetails) {
templateVO.setUrl(templateDetails.getUrl());
templateVO.setChecksum(DigestHelper.prependAlgorithm(templateDetails.getChecksum()));
GuestOSVO guestOS = guestOSDao.findOneByDisplayName(templateDetails.getGuestOs());
@@ -1015,51 +1086,193 @@ private void updateTemplateUrlChecksumAndGuestOsId(VMTemplateVO templateVO, Meta
}
boolean updated = vmTemplateDao.update(templateVO.getId(), templateVO);
if (!updated) {
- String errMsg = String.format("updateSystemVmTemplates:Exception while updating 'url' and 'checksum' for hypervisor type %s", templateDetails.getHypervisorType());
+ String errMsg = String.format("Exception while updating 'url' and 'checksum' for hypervisor type %s",
+ templateDetails.getHypervisorType());
LOGGER.error(errMsg);
throw new CloudRuntimeException(errMsg);
}
}
- protected boolean registerOrUpdateSystemVmTemplate(MetadataTemplateDetails templateDetails,
- List> hypervisorsInUse) {
- LOGGER.debug("Updating System VM template for {}", templateDetails.getHypervisorArchLog());
- VMTemplateVO registeredTemplate = getRegisteredTemplate(templateDetails.getName(), templateDetails.getArch());
- // change template type to SYSTEM
+ /**
+ * Updates or registers the system VM Template for the given hypervisor/arch if not already present.
+ * Returns true if a new template was registered.
+ * If there is an existing system VM Template for the given hypervisor/arch, its details are updated.
+ * If no existing template is found, new templates are registered for the valid hypervisor/arch which are in use.
+ */
+ protected boolean updateOrRegisterSystemVmTemplate(MetadataTemplateDetails templateDetails,
+ List