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(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> hypervisorArchInUse) {
+ String systemVmTemplateLog = String.format("%s system VM Template for %s", getSystemVmTemplateVersion(),
+ templateDetails.getHypervisorArchLog());
+ LOGGER.debug("Registering or updating {}", systemVmTemplateLog,
+ templateDetails.getHypervisorArchLog());
+ VMTemplateVO registeredTemplate = getRegisteredTemplate(templateDetails.getName(),
+ templateDetails.getHypervisorType(), templateDetails.getArch(), templateDetails.getUrl());
if (registeredTemplate != null) {
- updateRegisteredTemplateDetails(registeredTemplate.getId(), templateDetails);
- } else {
- boolean isHypervisorArchMatchMetadata = hypervisorsInUse.stream()
- .anyMatch(p -> p.first().equals(templateDetails.getHypervisorType())
- && Objects.equals(p.second(), templateDetails.getArch()));
- if (isHypervisorArchMatchMetadata) {
- try {
- registerTemplates(hypervisorsInUse);
- return true;
- } catch (final Exception e) {
- throw new CloudRuntimeException(String.format("Failed to register %s templates for hypervisors: [%s]. " +
- "Cannot upgrade system VMs",
- getSystemVmTemplateVersion(),
- StringUtils.join(hypervisorsInUse.stream()
- .map(x -> getHypervisorArchKey(x.first(), x.second()))
- .collect(Collectors.toList()), ",")), e);
- }
- } else {
- LOGGER.warn("Cannot upgrade {} system VM template for {} as it is not used, not failing upgrade",
- getSystemVmTemplateVersion(), templateDetails.getHypervisorArchLog());
- VMTemplateVO templateVO = vmTemplateDao.findLatestTemplateByTypeAndHypervisorAndArch(
- templateDetails.getHypervisorType(), templateDetails.getArch(), Storage.TemplateType.SYSTEM);
- if (templateVO != null) {
- updateTemplateUrlChecksumAndGuestOsId(templateVO, templateDetails);
- }
+ LOGGER.info("{} is already registered, updating details for: {}",
+ systemVmTemplateLog, templateDetails.getHypervisorArchLog(), registeredTemplate);
+ updateRegisteredTemplateDetails(registeredTemplate.getId(), templateDetails, null);
+ return false;
+ }
+ boolean isHypervisorArchMatchMetadata = hypervisorArchInUse.stream()
+ .anyMatch(p -> p.first().equals(templateDetails.getHypervisorType())
+ && Objects.equals(p.second(), templateDetails.getArch()));
+ if (!isHypervisorArchMatchMetadata) {
+ LOGGER.warn("Skipping upgrading {} as it is not used, not failing upgrade",
+ getSystemVmTemplateVersion(), templateDetails.getHypervisorArchLog());
+ VMTemplateVO templateVO = vmTemplateDao.findLatestTemplateByTypeAndHypervisorAndArch(
+ templateDetails.getHypervisorType(), templateDetails.getArch(), Storage.TemplateType.SYSTEM);
+ if (templateVO != null) {
+ updateTemplateUrlChecksumAndGuestOsId(templateVO, templateDetails);
}
+ return false;
+ }
+ try {
+ registerTemplates(hypervisorArchInUse);
+ return true;
+ } catch (final Exception e) {
+ throw new CloudRuntimeException(String.format("Failed to register %s templates for hypervisors: [%s]. " +
+ "Cannot upgrade system VMs",
+ getSystemVmTemplateVersion(),
+ StringUtils.join(hypervisorArchInUse.stream()
+ .map(x -> String.format("%s-%s", x.first().name(), x.second().name()))
+ .collect(Collectors.toList()), ",")), e);
}
- return false;
}
+ /**
+ * Return NFS version for the store: store-specific config if present
+ * or global config if absent. Returns null if not set.
+ */
+ protected String getNfsVersion(long storeId) {
+ final String configKey = "secstorage.nfs.version";
+ final Map storeDetails = imageStoreDetailsDao.getDetails(storeId);
+ if (storeDetails != null && storeDetails.containsKey(configKey)) {
+ return storeDetails.get(configKey);
+ }
+ ConfigurationVO globalNfsVersion = configurationDao.findByName(configKey);
+ if (globalNfsVersion != null) {
+ return globalNfsVersion.getValue();
+ }
+ return null;
+ }
+
+ /**
+ * Validate metadata for the given template's hypervisor/arch and add the existing template
+ * to the specified secondary store. On success, database entries are created/updated.
+ *
+ * @param templateVO template to add
+ * @param templateDataStoreVO 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
+ */
+ public void validateAndAddTemplateToStore(VMTemplateVO templateVO, TemplateDataStoreVO templateDataStoreVO,
+ long zoneId, long storeId, String filePath) {
+ MetadataTemplateDetails templateDetails = getValidatedTemplateDetailsForHypervisorAndArch(
+ templateVO.getHypervisorType(), templateVO.getArch());
+ addExistingTemplateToStore(templateVO, templateDetails, templateDataStoreVO, zoneId, storeId, filePath);
+ }
+
+ /**
+ * Validate metadata for the given hypervisor/arch and register a new system VM Template
+ * on the specified store and zone. Creates DB entries and seeds the template on the store.
+ *
+ * @param hypervisor hypervisor type
+ * @param arch cpu architecture
+ * @param name template name to register
+ * @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
+ */
+ public void validateAndRegisterNewTemplate(Hypervisor.HypervisorType hypervisor, CPU.CPUArch arch, String name,
+ long zoneId, long storeId, String filePath) {
+ MetadataTemplateDetails templateDetails = getValidatedTemplateDetailsForHypervisorAndArch(hypervisor, arch);
+ registerNewTemplate(name, templateDetails, zoneId, storeId, filePath);
+ }
+
+ /**
+ * Check whether the template at the given `path` on NFS `url` is already seeded.
+ * If found, updates DB with sizes and returns true; otherwise returns false.
+ *
+ * @throws CloudRuntimeException on any error
+ */
+ public boolean validateIfSeeded(TemplateDataStoreVO templDataStoreVO, String url, String path, String nfsVersion) {
+ 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, nfsVersion);
+ 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()) {
+ Pair templateSizes = readTemplatePropertiesSizes(templatePath + "/template.properties");
+ updateSeededTemplateDetails(templDataStoreVO.getTemplateId(), templDataStoreVO.getDataStoreId(),
+ templateSizes.first(), templateSizes.second());
+ LOGGER.info("System VM template already seeded, skipping registration");
+ return true;
+ }
+ LOGGER.info("System VM 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("Failed to delete temporary directory: {}", filePath);
+ }
+ }
+ }
+
+ /**
+ * Finds a registered system VM Template matching the provided criteria.
+ *
+ * The method first attempts to locate the latest template by {@code templateName},
+ * {@code hypervisorType} and {@code arch}. If none is found and a non-blank {@code url}
+ * is provided, it falls back to searching for an active system template by the
+ * URL path segment (the substring after the last '/' in the URL).
+ *
+ * @param templateName the template name to search for
+ * @param hypervisorType the hypervisor type
+ * @param arch the CPU architecture
+ * @param url optional download URL used as a fallback; may be {@code null} or blank
+ * @return the matching {@code VMTemplateVO} if found; {@code null} otherwise
+ */
+ public VMTemplateVO getRegisteredTemplate(String templateName, Hypervisor.HypervisorType hypervisorType,
+ CPU.CPUArch arch, String url) {
+ VMTemplateVO registeredTemplate = vmTemplateDao.findLatestTemplateByName(templateName, hypervisorType, arch);
+ if (registeredTemplate == null && StringUtils.isNotBlank(url)) {
+ String urlPath = url.substring(url.lastIndexOf("/") + 1);
+ LOGGER.debug("No template found by name, falling back to search existing SYSTEM template by " +
+ "urlPath: {}, hypervisor: {}, arch:{}", urlPath, hypervisorType, arch);
+ registeredTemplate = vmTemplateDao.findActiveSystemTemplateByHypervisorArchAndUrlPath(hypervisorType, arch,
+ urlPath);
+ }
+ LOGGER.debug("Found existing registered template for hypervisor: {}, arch: {}: {}", hypervisorType,
+ arch, registeredTemplate);
+ return registeredTemplate;
+ }
+
+ /**
+ * Update or register system VM Templates based on metadata.
+ *
+ * Runs the registration logic inside a database transaction: obtains the
+ * set of hypervisors/architectures in use, iterates over metadata entries
+ * and attempts to register or update each template.
+ *
+ * @param conn retained for compatibility with callers (not used directly)
+ */
public void updateSystemVmTemplates(final Connection conn) {
- LOGGER.debug("Updating System Vm template IDs");
- updateSystemVmTemplateGuestOsId();
+ LOGGER.debug("Updating System VM templates");
+ updateHypervisorGuestOsMap();
Transaction.execute(new TransactionCallbackNoReturn() {
@Override
public void doInTransactionWithoutResult(final TransactionStatus status) {
@@ -1069,10 +1282,9 @@ public void doInTransactionWithoutResult(final TransactionStatus status) {
} catch (final Exception e) {
throw new CloudRuntimeException("Exception while getting hypervisor types from clusters", e);
}
- Collection templateEntries = NewTemplateMap.values();
- for (MetadataTemplateDetails templateDetails : templateEntries) {
+ for (MetadataTemplateDetails templateDetails : METADATA_TEMPLATE_LIST) {
try {
- if (registerOrUpdateSystemVmTemplate(templateDetails, hypervisorsInUse)) {
+ if (updateOrRegisterSystemVmTemplate(templateDetails, hypervisorsInUse)) {
break;
}
} catch (final Exception e) {
@@ -1081,24 +1293,11 @@ public void doInTransactionWithoutResult(final TransactionStatus status) {
throw new CloudRuntimeException(errMsg, e);
}
}
- LOGGER.debug("Updating System Vm Template IDs Complete");
+ LOGGER.debug("Updating System VM Templates Complete");
}
});
}
- public String getNfsVersion(long storeId) {
- final String configKey = "secstorage.nfs.version";
- final Map storeDetails = imageStoreDetailsDao.getDetails(storeId);
- if (storeDetails != null && storeDetails.containsKey(configKey)) {
- return storeDetails.get(configKey);
- }
- ConfigurationVO globalNfsVersion = configurationDao.findByName(configKey);
- if (globalNfsVersion != null) {
- return globalNfsVersion.getValue();
- }
- return null;
- }
-
protected static class MetadataTemplateDetails {
private final Hypervisor.HypervisorType hypervisorType;
private final String name;
@@ -1160,6 +1359,16 @@ public String getDefaultFilePath() {
return TEMPLATES_PATH + filename;
}
+ public boolean isFileChecksumDifferent(File file) {
+ String fileChecksum = DigestHelper.calculateChecksum(file);
+ if (!fileChecksum.equals(getChecksum())) {
+ LOGGER.error("Checksum {} for file {} does not match checksum {} from metadata",
+ fileChecksum, file, getChecksum());
+ return true;
+ }
+ return false;
+ }
+
public String getHypervisorArchLog() {
return SystemVmTemplateRegistration.getHypervisorArchLog(hypervisorType, arch);
}
diff --git a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade2214to30.java b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade2214to30.java
index 524b6a34893b..d4cdbcb9707d 100644
--- a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade2214to30.java
+++ b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade2214to30.java
@@ -77,8 +77,6 @@ public void performDataMigration(Connection conn) {
encryptData(conn);
// drop keys
dropKeysIfExist(conn);
- //update template ID for system Vms
- //updateSystemVms(conn); This is not required as system template update is handled during 4.2 upgrade
// update domain network ref
updateDomainNetworkRef(conn);
// update networks that use redundant routers to the new network offering
diff --git a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade302to40.java b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade302to40.java
index aa427252585f..bd8ddaa7c498 100644
--- a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade302to40.java
+++ b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade302to40.java
@@ -62,7 +62,6 @@ public InputStream[] getPrepareScripts() {
@Override
public void performDataMigration(Connection conn) {
- //updateVmWareSystemVms(conn); This is not required as system template update is handled during 4.2 upgrade
correctVRProviders(conn);
correctMultiplePhysicaNetworkSetups(conn);
addHostDetailsUniqueKey(conn);
diff --git a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade304to305.java b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade304to305.java
index 3167dd8115b4..38dc90b460dd 100644
--- a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade304to305.java
+++ b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade304to305.java
@@ -65,7 +65,6 @@ public void performDataMigration(Connection conn) {
addVpcProvider(conn);
updateRouterNetworkRef(conn);
fixZoneUsingExternalDevices(conn);
-// updateSystemVms(conn);
fixForeignKeys(conn);
encryptClusterDetails(conn);
}
@@ -81,54 +80,6 @@ public InputStream[] getCleanupScripts() {
return new InputStream[] {script};
}
- private void updateSystemVms(Connection conn) {
- PreparedStatement pstmt = null;
- ResultSet rs = null;
- boolean VMware = false;
- try {
- pstmt = conn.prepareStatement("select distinct(hypervisor_type) from `cloud`.`cluster` where removed is null");
- rs = pstmt.executeQuery();
- while (rs.next()) {
- if ("VMware".equals(rs.getString(1))) {
- VMware = true;
- }
- }
- } catch (SQLException e) {
- throw new CloudRuntimeException("Error while iterating through list of hypervisors in use", e);
- }
- // Just update the VMware system template. Other hypervisor templates are unchanged from previous 3.0.x versions.
- logger.debug("Updating VMware System Vms");
- try {
- //Get 3.0.5 VMware system Vm template Id
- pstmt = conn.prepareStatement("select id from `cloud`.`vm_template` where name = 'systemvm-vmware-3.0.5' and removed is null");
- rs = pstmt.executeQuery();
- if (rs.next()) {
- long templateId = rs.getLong(1);
- rs.close();
- pstmt.close();
- // change template type to SYSTEM
- pstmt = conn.prepareStatement("update `cloud`.`vm_template` set type='SYSTEM' where id = ?");
- pstmt.setLong(1, templateId);
- pstmt.executeUpdate();
- pstmt.close();
- // update template ID of system Vms
- pstmt = conn.prepareStatement("update `cloud`.`vm_instance` set vm_template_id = ? where type <> 'User' and hypervisor_type = 'VMware'");
- pstmt.setLong(1, templateId);
- pstmt.executeUpdate();
- pstmt.close();
- } else {
- if (VMware) {
- throw new CloudRuntimeException("3.0.5 VMware SystemVm Template not found. Cannot upgrade system Vms");
- } else {
- logger.warn("3.0.5 VMware SystemVm Template not found. VMware hypervisor is not used, so not failing upgrade");
- }
- }
- } catch (SQLException e) {
- throw new CloudRuntimeException("Error while updating VMware systemVM Template", e);
- }
- logger.debug("Updating System VM Template IDs Complete");
- }
-
private void addVpcProvider(Connection conn) {
//Encrypt config params and change category to Hidden
logger.debug("Adding VPC provider to all physical Networks in the system");
diff --git a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade410to420.java b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade410to420.java
index 94e6149e73b2..a78f93fbdd4f 100644
--- a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade410to420.java
+++ b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade410to420.java
@@ -1195,9 +1195,9 @@ private void updateGlobalDeploymentPlanner(Connection conn) {
plannerName = "FirstFitPlanner";
} else if (globalValue.equals(DeploymentPlanner.AllocationAlgorithm.firstfit.toString())) {
plannerName = "FirstFitPlanner";
- } else if (globalValue.equals(DeploymentPlanner.AllocationAlgorithm.userconcentratedpod_firstfit.toString())) {
+ } else if (globalValue.equals("userconcentratedpod_firstfit")) {
plannerName = "UserConcentratedPodPlanner";
- } else if (globalValue.equals(DeploymentPlanner.AllocationAlgorithm.userconcentratedpod_random.toString())) {
+ } else if (globalValue.equals("userconcentratedpod_random")) {
plannerName = "UserConcentratedPodPlanner";
} else if (globalValue.equals(DeploymentPlanner.AllocationAlgorithm.userdispersing.toString())) {
plannerName = "UserDispersingPlanner";
diff --git a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade41810to41900.java b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade41810to41900.java
index a38382623bf5..35e706595ec1 100644
--- a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade41810to41900.java
+++ b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade41810to41900.java
@@ -159,7 +159,7 @@ private void modifyDateColumnNameAndCreateNewOne(Connection conn) {
try (PreparedStatement pstmt = conn.prepareStatement(createNewColumn)) {
pstmt.execute();
} catch (SQLException e) {
- String message = String.format("Unable to crate new backups' column date due to [%s].", e.getMessage());
+ String message = String.format("Unable to create new backups' column date due to [%s].", e.getMessage());
logger.error(message, e);
throw new CloudRuntimeException(message, e);
}
diff --git a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade42210to42300.java b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade42210to42300.java
new file mode 100644
index 000000000000..df4743894c9d
--- /dev/null
+++ b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade42210to42300.java
@@ -0,0 +1,45 @@
+// 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.dao;
+
+import java.io.InputStream;
+
+import com.cloud.utils.exception.CloudRuntimeException;
+
+public class Upgrade42210to42300 extends DbUpgradeAbstractImpl implements DbUpgrade, DbUpgradeSystemVmTemplate {
+
+ @Override
+ public String[] getUpgradableVersionRange() {
+ return new String[]{"4.22.1.0", "4.23.0.0"};
+ }
+
+ @Override
+ public String getUpgradedVersion() {
+ return "4.23.0.0";
+ }
+
+ @Override
+ public InputStream[] getPrepareScripts() {
+ final String scriptFile = "META-INF/db/schema-42210to42300.sql";
+ final InputStream script = Thread.currentThread().getContextClassLoader().getResourceAsStream(scriptFile);
+ if (script == null) {
+ throw new CloudRuntimeException("Unable to find " + scriptFile);
+ }
+
+ return new InputStream[] {script};
+ }
+}
diff --git a/engine/schema/src/main/java/com/cloud/user/UserAccountVO.java b/engine/schema/src/main/java/com/cloud/user/UserAccountVO.java
index e4fcbad6b02f..c5ca410fc530 100644
--- a/engine/schema/src/main/java/com/cloud/user/UserAccountVO.java
+++ b/engine/schema/src/main/java/com/cloud/user/UserAccountVO.java
@@ -226,10 +226,6 @@ public Date getCreated() {
return created;
}
-// public void setCreated(Date created) {
-// this.created = created;
-// }
-
@Override
public Date getRemoved() {
return removed;
diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/UserVmDaoImpl.java b/engine/schema/src/main/java/com/cloud/vm/dao/UserVmDaoImpl.java
index 79d0b0e149ea..761053a89f0c 100644
--- a/engine/schema/src/main/java/com/cloud/vm/dao/UserVmDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/vm/dao/UserVmDaoImpl.java
@@ -782,7 +782,7 @@ public List> countVmsBySize(long dcId, int li
result.add(new Ternary(rs.getInt(1), rs.getInt(2), rs.getInt(3)));
}
} catch (Exception e) {
- logger.warn("Error counting Instances by size for dcId= " + dcId, e);
+ logger.warn("Error counting Instances by size for Data Center ID = " + dcId, e);
}
return result;
}
diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java b/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java
index 703fabd2cab1..b4ad7d2f42d1 100755
--- a/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java
@@ -900,7 +900,7 @@ public Long countByZoneAndStateAndHostTag(long dcId, State state, String hostTag
return rs.getLong(1);
}
} catch (Exception e) {
- logger.warn(String.format("Error counting Instances by host tag for dcId= %s, hostTag= %s", dcId, hostTag), e);
+ logger.warn("Error counting Instances by host tag for dcId = {}, hostTag = {}", dcId, hostTag, e);
}
return 0L;
}
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/backup/BackupOfferingDetailsVO.java b/engine/schema/src/main/java/org/apache/cloudstack/backup/BackupOfferingDetailsVO.java
new file mode 100644
index 000000000000..6bdf7602a9d4
--- /dev/null
+++ b/engine/schema/src/main/java/org/apache/cloudstack/backup/BackupOfferingDetailsVO.java
@@ -0,0 +1,86 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.backup;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+import org.apache.cloudstack.api.ResourceDetail;
+
+@Entity
+@Table(name = "backup_offering_details")
+public class BackupOfferingDetailsVO implements ResourceDetail {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "id")
+ private long id;
+
+ @Column(name = "backup_offering_id")
+ private long resourceId;
+
+ @Column(name = "name")
+ private String name;
+
+ @Column(name = "value")
+ private String value;
+
+ @Column(name = "display")
+ private boolean display = true;
+
+ protected BackupOfferingDetailsVO() {
+ }
+
+ public BackupOfferingDetailsVO(long backupOfferingId, String name, String value, boolean display) {
+ this.resourceId = backupOfferingId;
+ this.name = name;
+ this.value = value;
+ this.display = display;
+ }
+
+ @Override
+ public long getResourceId() {
+ return resourceId;
+ }
+
+ public void setResourceId(long backupOfferingId) {
+ this.resourceId = backupOfferingId;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getValue() {
+ return value;
+ }
+
+ @Override
+ public long getId() {
+ return id;
+ }
+
+ @Override
+ public boolean isDisplay() {
+ return display;
+ }
+}
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/backup/BackupOfferingVO.java b/engine/schema/src/main/java/org/apache/cloudstack/backup/BackupOfferingVO.java
index d30385af575d..ebeb7d4a2d59 100644
--- a/engine/schema/src/main/java/org/apache/cloudstack/backup/BackupOfferingVO.java
+++ b/engine/schema/src/main/java/org/apache/cloudstack/backup/BackupOfferingVO.java
@@ -17,6 +17,8 @@
package org.apache.cloudstack.backup;
+import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
+
import java.util.Date;
import java.util.UUID;
@@ -131,4 +133,9 @@ public void setDescription(String description) {
public Date getCreated() {
return created;
}
+
+ @Override
+ public String toString() {
+ return String.format("Backup offering %s.", ReflectionToStringBuilderUtils.reflectOnlySelectedFields(this, "id", "name", "uuid"));
+ }
}
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupOfferingDaoImpl.java b/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupOfferingDaoImpl.java
index a41e4e70d339..708faeef4643 100644
--- a/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupOfferingDaoImpl.java
+++ b/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupOfferingDaoImpl.java
@@ -20,6 +20,8 @@
import javax.annotation.PostConstruct;
import javax.inject.Inject;
+import com.cloud.domain.DomainVO;
+import com.cloud.domain.dao.DomainDao;
import org.apache.cloudstack.api.response.BackupOfferingResponse;
import org.apache.cloudstack.backup.BackupOffering;
import org.apache.cloudstack.backup.BackupOfferingVO;
@@ -30,10 +32,16 @@
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
+import java.util.List;
+
public class BackupOfferingDaoImpl extends GenericDaoBase implements BackupOfferingDao {
@Inject
DataCenterDao dataCenterDao;
+ @Inject
+ BackupOfferingDetailsDao backupOfferingDetailsDao;
+ @Inject
+ DomainDao domainDao;
private SearchBuilder backupPoliciesSearch;
@@ -51,8 +59,9 @@ protected void init() {
@Override
public BackupOfferingResponse newBackupOfferingResponse(BackupOffering offering, Boolean crossZoneInstanceCreation) {
- DataCenterVO zone = dataCenterDao.findById(offering.getZoneId());
+ DataCenterVO zone = dataCenterDao.findById(offering.getZoneId());
+ List domainIds = backupOfferingDetailsDao.findDomainIds(offering.getId());
BackupOfferingResponse response = new BackupOfferingResponse();
response.setId(offering.getUuid());
response.setName(offering.getName());
@@ -64,6 +73,18 @@ public BackupOfferingResponse newBackupOfferingResponse(BackupOffering offering,
response.setZoneId(zone.getUuid());
response.setZoneName(zone.getName());
}
+ if (domainIds != null && !domainIds.isEmpty()) {
+ String domainUUIDs = domainIds.stream().map(Long::valueOf).map(domainId -> {
+ DomainVO domain = domainDao.findById(domainId);
+ return domain != null ? domain.getUuid() : "";
+ }).filter(name -> !name.isEmpty()).reduce((a, b) -> a + "," + b).orElse("");
+ String domainNames = domainIds.stream().map(Long::valueOf).map(domainId -> {
+ DomainVO domain = domainDao.findById(domainId);
+ return domain != null ? domain.getName() : "";
+ }).filter(name -> !name.isEmpty()).reduce((a, b) -> a + "," + b).orElse("");
+ response.setDomain(domainNames);
+ response.setDomainId(domainUUIDs);
+ }
if (crossZoneInstanceCreation) {
response.setCrossZoneInstanceCreation(true);
}
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupOfferingDetailsDao.java b/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupOfferingDetailsDao.java
new file mode 100644
index 000000000000..390fcba1e0e7
--- /dev/null
+++ b/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupOfferingDetailsDao.java
@@ -0,0 +1,32 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.backup.dao;
+
+import java.util.List;
+
+import org.apache.cloudstack.backup.BackupOfferingDetailsVO;
+import org.apache.cloudstack.resourcedetail.ResourceDetailsDao;
+
+import com.cloud.utils.db.GenericDao;
+
+public interface BackupOfferingDetailsDao extends GenericDao, ResourceDetailsDao {
+ List findDomainIds(final long resourceId);
+ List findZoneIds(final long resourceId);
+ String getDetail(Long backupOfferingId, String key);
+ List findOfferingIdsByDomainIds(List domainIds);
+ void updateBackupOfferingDomainIdsDetail(long backupOfferingId, List filteredDomainIds);
+}
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupOfferingDetailsDaoImpl.java b/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupOfferingDetailsDaoImpl.java
new file mode 100644
index 000000000000..f052c93f9817
--- /dev/null
+++ b/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupOfferingDetailsDaoImpl.java
@@ -0,0 +1,101 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.backup.dao;
+
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import com.cloud.utils.db.DB;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.backup.BackupOfferingDetailsVO;
+import org.apache.cloudstack.resourcedetail.ResourceDetailsDaoBase;
+import org.springframework.stereotype.Component;
+
+@Component
+public class BackupOfferingDetailsDaoImpl extends ResourceDetailsDaoBase implements BackupOfferingDetailsDao {
+
+ @Override
+ public void addDetail(long resourceId, String key, String value, boolean display) {
+ super.addDetail(new BackupOfferingDetailsVO(resourceId, key, value, display));
+ }
+
+ @Override
+ public List findDomainIds(long resourceId) {
+ final List domainIds = new ArrayList<>();
+ for (final BackupOfferingDetailsVO detail: findDetails(resourceId, ApiConstants.DOMAIN_ID)) {
+ final Long domainId = Long.valueOf(detail.getValue());
+ if (domainId > 0) {
+ domainIds.add(domainId);
+ }
+ }
+ return domainIds;
+ }
+
+ @Override
+ public List findZoneIds(long resourceId) {
+ final List zoneIds = new ArrayList<>();
+ for (final BackupOfferingDetailsVO detail: findDetails(resourceId, ApiConstants.ZONE_ID)) {
+ final Long zoneId = Long.valueOf(detail.getValue());
+ if (zoneId > 0) {
+ zoneIds.add(zoneId);
+ }
+ }
+ return zoneIds;
+ }
+
+ @Override
+ public String getDetail(Long backupOfferingId, String key) {
+ String detailValue = null;
+ BackupOfferingDetailsVO backupOfferingDetail = findDetail(backupOfferingId, key);
+ if (backupOfferingDetail != null) {
+ detailValue = backupOfferingDetail.getValue();
+ }
+ return detailValue;
+ }
+
+ @Override
+ public List findOfferingIdsByDomainIds(List domainIds) {
+ Object[] dIds = domainIds.stream().map(s -> String.valueOf(s)).collect(Collectors.toList()).toArray();
+ return findResourceIdsByNameAndValueIn("domainid", dIds);
+ }
+
+ @DB
+ @Override
+ public void updateBackupOfferingDomainIdsDetail(long backupOfferingId, List filteredDomainIds) {
+ SearchBuilder sb = createSearchBuilder();
+ List detailsVO = new ArrayList<>();
+ sb.and("offeringId", sb.entity().getResourceId(), SearchCriteria.Op.EQ);
+ sb.and("detailName", sb.entity().getName(), SearchCriteria.Op.EQ);
+ sb.done();
+ SearchCriteria sc = sb.create();
+ sc.setParameters("offeringId", String.valueOf(backupOfferingId));
+ sc.setParameters("detailName", ApiConstants.DOMAIN_ID);
+ remove(sc);
+ for (Long domainId : filteredDomainIds) {
+ detailsVO.add(new BackupOfferingDetailsVO(backupOfferingId, ApiConstants.DOMAIN_ID, String.valueOf(domainId), false));
+ }
+ if (!detailsVO.isEmpty()) {
+ for (BackupOfferingDetailsVO detailVO : detailsVO) {
+ persist(detailVO);
+ }
+ }
+ }
+}
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/VolumeDataStoreVO.java b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/VolumeDataStoreVO.java
index d57dec8fbfd5..c475a4203a73 100644
--- a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/VolumeDataStoreVO.java
+++ b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/VolumeDataStoreVO.java
@@ -209,10 +209,8 @@ public VolumeDataStoreVO(long hostId, long volumeId) {
public VolumeDataStoreVO(long hostId, long volumeId, Date lastUpdated, int downloadPercent, Status downloadState, String localDownloadPath, String errorString,
String jobId, String installPath, String downloadUrl, String checksum) {
- // super();
dataStoreId = hostId;
this.volumeId = volumeId;
- // this.zoneId = zoneId;
this.lastUpdated = lastUpdated;
this.downloadPercent = downloadPercent;
this.downloadState = downloadState;
diff --git a/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-common-daos-between-management-and-usage-context.xml b/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-common-daos-between-management-and-usage-context.xml
index d308a9e5aaf9..1846c3c62a0e 100644
--- a/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-common-daos-between-management-and-usage-context.xml
+++ b/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-common-daos-between-management-and-usage-context.xml
@@ -71,6 +71,7 @@
-
+
+
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-307to410.sql b/engine/schema/src/main/resources/META-INF/db/schema-307to410.sql
index 55d78b594377..3b0cfa8e6ce3 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-307to410.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-307to410.sql
@@ -3,7 +3,7 @@
-- 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 compliances
+-- "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
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-42210to42300-cleanup.sql b/engine/schema/src/main/resources/META-INF/db/schema-42210to42300-cleanup.sql
new file mode 100644
index 000000000000..e2b066af7800
--- /dev/null
+++ b/engine/schema/src/main/resources/META-INF/db/schema-42210to42300-cleanup.sql
@@ -0,0 +1,20 @@
+-- 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.
+
+--;
+-- Schema upgrade cleanup from 4.22.1.0 to 4.23.0.0
+--;
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql b/engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql
new file mode 100644
index 000000000000..d330ecd0c0d5
--- /dev/null
+++ b/engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql
@@ -0,0 +1,51 @@
+-- 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.
+
+--;
+-- Schema upgrade from 4.22.1.0 to 4.23.0.0
+--;
+
+CREATE TABLE `cloud`.`backup_offering_details` (
+ `id` bigint unsigned NOT NULL auto_increment,
+ `backup_offering_id` bigint unsigned NOT NULL COMMENT 'Backup offering id',
+ `name` varchar(255) NOT NULL,
+ `value` varchar(1024) NOT NULL,
+ `display` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'Should detail be displayed to the end user',
+ PRIMARY KEY (`id`),
+ CONSTRAINT `fk_offering_details__backup_offering_id` FOREIGN KEY `fk_offering_details__backup_offering_id`(`backup_offering_id`) REFERENCES `backup_offering`(`id`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- Update value to random for the config 'vm.allocation.algorithm' or 'volume.allocation.algorithm' if configured as userconcentratedpod_random
+-- Update value to firstfit for the config 'vm.allocation.algorithm' or 'volume.allocation.algorithm' if configured as userconcentratedpod_firstfit
+UPDATE `cloud`.`configuration` SET value='random' WHERE name IN ('vm.allocation.algorithm', 'volume.allocation.algorithm') AND value='userconcentratedpod_random';
+UPDATE `cloud`.`configuration` SET value='firstfit' WHERE name IN ('vm.allocation.algorithm', 'volume.allocation.algorithm') AND value='userconcentratedpod_firstfit';
+
+-- Create webhook_filter table
+DROP TABLE IF EXISTS `cloud`.`webhook_filter`;
+CREATE TABLE IF NOT EXISTS `cloud`.`webhook_filter` (
+ `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id of the webhook filter',
+ `uuid` varchar(255) COMMENT 'uuid of the webhook filter',
+ `webhook_id` bigint unsigned NOT NULL COMMENT 'id of the webhook',
+ `type` varchar(20) COMMENT 'type of the filter',
+ `mode` varchar(20) COMMENT 'mode of the filter',
+ `match_type` varchar(20) COMMENT 'match type of the filter',
+ `value` varchar(256) NOT NULL COMMENT 'value of the filter used for matching',
+ `created` datetime NOT NULL COMMENT 'date created',
+ PRIMARY KEY (`id`),
+ INDEX `i_webhook_filter__webhook_id`(`webhook_id`),
+ CONSTRAINT `fk_webhook_filter__webhook_id` FOREIGN KEY(`webhook_id`) REFERENCES `webhook`(`id`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
diff --git a/engine/schema/src/test/java/com/cloud/storage/dao/VMTemplateDaoImplTest.java b/engine/schema/src/test/java/com/cloud/storage/dao/VMTemplateDaoImplTest.java
index 3c8e4c046ae7..5cff77869be8 100644
--- a/engine/schema/src/test/java/com/cloud/storage/dao/VMTemplateDaoImplTest.java
+++ b/engine/schema/src/test/java/com/cloud/storage/dao/VMTemplateDaoImplTest.java
@@ -76,7 +76,8 @@ public void testFindLatestTemplateByName_ReturnsTemplate() {
VMTemplateVO expectedTemplate = new VMTemplateVO();
List returnedList = Collections.singletonList(expectedTemplate);
doReturn(returnedList).when(templateDao).listBy(any(SearchCriteria.class), any(Filter.class));
- VMTemplateVO result = templateDao.findLatestTemplateByName("test", CPU.CPUArch.getDefault());
+ VMTemplateVO result = templateDao.findLatestTemplateByName("test", Hypervisor.HypervisorType.KVM,
+ CPU.CPUArch.getDefault());
assertNotNull("Expected a non-null template", result);
assertEquals("Expected the returned template to be the first element", expectedTemplate, result);
}
@@ -85,7 +86,8 @@ public void testFindLatestTemplateByName_ReturnsTemplate() {
public void testFindLatestTemplateByName_ReturnsNullWhenNoTemplateFound() {
List emptyList = Collections.emptyList();
doReturn(emptyList).when(templateDao).listBy(any(SearchCriteria.class), any(Filter.class));
- VMTemplateVO result = templateDao.findLatestTemplateByName("test", CPU.CPUArch.getDefault());
+ VMTemplateVO result = templateDao.findLatestTemplateByName("test", Hypervisor.HypervisorType.VMware,
+ CPU.CPUArch.getDefault());
assertNull("Expected null when no templates are found", result);
}
@@ -94,7 +96,8 @@ public void testFindLatestTemplateByName_NullArch() {
VMTemplateVO expectedTemplate = new VMTemplateVO();
List returnedList = Collections.singletonList(expectedTemplate);
doReturn(returnedList).when(templateDao).listBy(any(SearchCriteria.class), any(Filter.class));
- VMTemplateVO result = templateDao.findLatestTemplateByName("test", null);
+ VMTemplateVO result = templateDao.findLatestTemplateByName("test", Hypervisor.HypervisorType.XenServer,
+ null);
assertNotNull("Expected a non-null template even if arch is null", result);
assertEquals("Expected the returned template to be the first element", expectedTemplate, result);
}
@@ -337,4 +340,82 @@ public void testFindSystemVMReadyTemplate() {
VMTemplateVO readyTemplate = templateDao.findSystemVMReadyTemplate(zoneId, Hypervisor.HypervisorType.KVM, CPU.CPUArch.arm64.getType());
Assert.assertEquals(CPU.CPUArch.arm64, readyTemplate.getArch());
}
+
+ @Test
+ public void findActiveSystemTemplateByHypervisorArchAndUrlPath_ReturnsTemplate() {
+ VMTemplateVO expectedTemplate = mock(VMTemplateVO.class);
+ SearchBuilder sb = mock(SearchBuilder.class);
+ when(sb.entity()).thenReturn(expectedTemplate);
+ SearchCriteriasc = mock(SearchCriteria.class);
+ when(sb.create()).thenReturn(sc);
+ when(templateDao.createSearchBuilder()).thenReturn(sb);
+ List templates = Collections.singletonList(expectedTemplate);
+ doReturn(templates).when(templateDao).listBy(any(SearchCriteria.class), any(Filter.class));
+
+ VMTemplateVO result = templateDao.findActiveSystemTemplateByHypervisorArchAndUrlPath(
+ Hypervisor.HypervisorType.KVM, CPU.CPUArch.amd64, "testPath");
+
+ assertNotNull(result);
+ assertEquals(expectedTemplate, result);
+ }
+
+ @Test
+ public void findActiveSystemTemplateByHypervisorArchAndUrlPath_ReturnsNullWhenNoTemplatesFound() {
+ VMTemplateVO template = mock(VMTemplateVO.class);
+ SearchBuilder sb = mock(SearchBuilder.class);
+ when(sb.entity()).thenReturn(template);
+ SearchCriteriasc = mock(SearchCriteria.class);
+ when(sb.create()).thenReturn(sc);
+ when(templateDao.createSearchBuilder()).thenReturn(sb);
+ doReturn(Collections.emptyList()).when(templateDao).listBy(any(SearchCriteria.class), any(Filter.class));
+
+ VMTemplateVO result = templateDao.findActiveSystemTemplateByHypervisorArchAndUrlPath(
+ Hypervisor.HypervisorType.KVM, CPU.CPUArch.amd64, "testPath");
+
+ assertNull(result);
+ }
+
+ @Test
+ public void findActiveSystemTemplateByHypervisorArchAndUrlPath_NullHypervisor() {
+ VMTemplateVO expectedTemplate = mock(VMTemplateVO.class);
+ SearchBuilder sb = mock(SearchBuilder.class);
+ when(sb.entity()).thenReturn(expectedTemplate);
+ SearchCriteriasc = mock(SearchCriteria.class);
+ when(sb.create()).thenReturn(sc);
+ when(templateDao.createSearchBuilder()).thenReturn(sb);
+ List templates = Collections.singletonList(expectedTemplate);
+ doReturn(templates).when(templateDao).listBy(any(SearchCriteria.class), any(Filter.class));
+
+ VMTemplateVO result = templateDao.findActiveSystemTemplateByHypervisorArchAndUrlPath(
+ null, CPU.CPUArch.amd64, "testPath");
+
+ assertNotNull(result);
+ assertEquals(expectedTemplate, result);
+ }
+
+ @Test
+ public void findActiveSystemTemplateByHypervisorArchAndUrlPath_NullArch() {
+ VMTemplateVO expectedTemplate = mock(VMTemplateVO.class);
+ SearchBuilder sb = mock(SearchBuilder.class);
+ when(sb.entity()).thenReturn(expectedTemplate);
+ SearchCriteriasc = mock(SearchCriteria.class);
+ when(sb.create()).thenReturn(sc);
+ when(templateDao.createSearchBuilder()).thenReturn(sb);
+ List templates = Collections.singletonList(expectedTemplate);
+ doReturn(templates).when(templateDao).listBy(any(SearchCriteria.class), any(Filter.class));
+
+ VMTemplateVO result = templateDao.findActiveSystemTemplateByHypervisorArchAndUrlPath(
+ Hypervisor.HypervisorType.KVM, null, "testPath");
+
+ assertNotNull(result);
+ assertEquals(expectedTemplate, result);
+ }
+
+ @Test
+ public void findActiveSystemTemplateByHypervisorArchAndUrlPath_EmptyUrlPathSuffix() {
+ VMTemplateVO result = templateDao.findActiveSystemTemplateByHypervisorArchAndUrlPath(
+ Hypervisor.HypervisorType.KVM, CPU.CPUArch.amd64, "");
+
+ assertNull(result);
+ }
}
diff --git a/engine/schema/src/test/java/com/cloud/upgrade/SystemVmTemplateRegistrationTest.java b/engine/schema/src/test/java/com/cloud/upgrade/SystemVmTemplateRegistrationTest.java
index b943f48ad36e..8028e78c9073 100644
--- a/engine/schema/src/test/java/com/cloud/upgrade/SystemVmTemplateRegistrationTest.java
+++ b/engine/schema/src/test/java/com/cloud/upgrade/SystemVmTemplateRegistrationTest.java
@@ -17,6 +17,7 @@
package com.cloud.upgrade;
+import static com.cloud.upgrade.SystemVmTemplateRegistration.DEFAULT_SYSTEM_VM_GUEST_OS_NAME;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -25,24 +26,41 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.File;
+import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
+import java.util.Date;
import java.util.List;
+import java.util.Map;
+import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
+import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
+import org.apache.cloudstack.framework.config.impl.ConfigurationVO;
+import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
+import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao;
+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.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
@@ -53,15 +71,27 @@
import org.mockito.junit.MockitoJUnitRunner;
import com.cloud.cpu.CPU;
+import com.cloud.dc.DataCenterVO;
import com.cloud.dc.dao.ClusterDao;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.dc.dao.DataCenterDetailsDao;
import com.cloud.hypervisor.Hypervisor;
+import com.cloud.storage.DataStoreRole;
+import com.cloud.storage.GuestOSVO;
+import com.cloud.storage.Storage;
+import com.cloud.storage.VMTemplateStorageResourceAssoc;
import com.cloud.storage.VMTemplateVO;
+import com.cloud.storage.VMTemplateZoneVO;
+import com.cloud.storage.dao.GuestOSDao;
import com.cloud.storage.dao.VMTemplateDao;
+import com.cloud.storage.dao.VMTemplateZoneDao;
+import com.cloud.template.VirtualMachineTemplate;
import com.cloud.utils.HttpUtils;
import com.cloud.utils.Pair;
import com.cloud.utils.UriUtils;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.script.Script;
+import com.cloud.vm.dao.VMInstanceDao;
@RunWith(MockitoJUnitRunner.class)
public class SystemVmTemplateRegistrationTest {
@@ -72,10 +102,42 @@ public class SystemVmTemplateRegistrationTest {
@Mock
VMTemplateDao vmTemplateDao;
+ @Mock
+ GuestOSDao guestOSDao;
+
+ @Mock
+ TemplateDataStoreDao templateDataStoreDao;
+
+ @Mock
+ ConfigurationDao configurationDao;
+
+ @Mock
+ DataCenterDao dataCenterDao;
+
+ @Mock
+ DataCenterDetailsDao dataCenterDetailsDao;
+
+ @Mock
+ VMTemplateZoneDao vmTemplateZoneDao;
+
+ @Mock
+ ImageStoreDao imageStoreDao;
+
+ @Mock
+ ImageStoreDetailsDao imageStoreDetailsDao;
+
+ @Mock
+ VMInstanceDao vmInstanceDao;
+
@Spy
@InjectMocks
SystemVmTemplateRegistration systemVmTemplateRegistration = new SystemVmTemplateRegistration();
+ @Before
+ public void setup() {
+ SystemVmTemplateRegistration.METADATA_TEMPLATE_LIST.clear();
+ }
+
private void setupMetadataFile(MockedStatic mockedStatic, String content) {
try {
String location = "metadata.ini";
@@ -98,7 +160,7 @@ public void test_parseMetadataFile_noFile() {
setupMetadataFile(mockedStatic, null);
CloudRuntimeException exception = assertThrows(CloudRuntimeException.class,
SystemVmTemplateRegistration::parseMetadataFile);
- assertTrue(exception.getMessage().contains("Failed to parse systemVM Template metadata file"));
+ assertTrue(exception.getMessage().contains("Failed to parse system VM Template metadata file"));
}
}
@@ -109,7 +171,7 @@ public void test_parseMetadataFile_invalidContent() {
setupMetadataFile(mockedStatic, "abc");
CloudRuntimeException exception = assertThrows(CloudRuntimeException.class,
SystemVmTemplateRegistration::parseMetadataFile);
- assertTrue(exception.getMessage().contains("Failed to parse systemVM Template metadata file"));
+ assertTrue(exception.getMessage().contains("Failed to parse system VM Template metadata file"));
}
}
@@ -141,21 +203,25 @@ public void test_parseMetadataFile_success() {
String version = SystemVmTemplateRegistration.parseMetadataFile();
assertEquals("x.y.z.0", version);
}
- assertNull(SystemVmTemplateRegistration.NewTemplateMap.get("xenserver"));
+ assertNull(SystemVmTemplateRegistration.getMetadataTemplateDetails(Hypervisor.HypervisorType.XenServer,
+ CPU.CPUArch.getDefault()));
SystemVmTemplateRegistration.MetadataTemplateDetails templateDetails =
- SystemVmTemplateRegistration.NewTemplateMap.get("kvm-x86_64");
+ SystemVmTemplateRegistration.getMetadataTemplateDetails(Hypervisor.HypervisorType.KVM,
+ CPU.CPUArch.amd64);
assertNotNull(templateDetails);
assertEquals(CPU.CPUArch.amd64, templateDetails.getArch());
assertEquals(Hypervisor.HypervisorType.KVM, templateDetails.getHypervisorType());
templateDetails =
- SystemVmTemplateRegistration.NewTemplateMap.get("kvm-aarch64");
+ SystemVmTemplateRegistration.getMetadataTemplateDetails(Hypervisor.HypervisorType.KVM,
+ CPU.CPUArch.arm64);
assertNotNull(templateDetails);
assertEquals(CPU.CPUArch.arm64, templateDetails.getArch());
assertEquals(Hypervisor.HypervisorType.KVM, templateDetails.getHypervisorType());
templateDetails =
- SystemVmTemplateRegistration.NewTemplateMap.get("vmware");
+ SystemVmTemplateRegistration.getMetadataTemplateDetails(Hypervisor.HypervisorType.VMware,
+ CPU.CPUArch.getDefault());
assertNotNull(templateDetails);
- assertNull(templateDetails.getArch());
+ assertEquals(CPU.CPUArch.getDefault(), templateDetails.getArch());
assertEquals(Hypervisor.HypervisorType.VMware, templateDetails.getHypervisorType());
}
@@ -193,11 +259,10 @@ public void testValidateTemplateFile_fileNotFound() {
SystemVmTemplateRegistration.MetadataTemplateDetails details =
new SystemVmTemplateRegistration.MetadataTemplateDetails(Hypervisor.HypervisorType.KVM,
"name", "file", "url", "checksum", CPU.CPUArch.amd64, "guestos");
- SystemVmTemplateRegistration.NewTemplateMap.put(SystemVmTemplateRegistration.getHypervisorArchKey(
- details.getHypervisorType(), details.getArch()), details);
+ SystemVmTemplateRegistration.METADATA_TEMPLATE_LIST.add(details);
doReturn(null).when(systemVmTemplateRegistration).getTemplateFile(details);
try {
- systemVmTemplateRegistration.validateTemplateFileForHypervisorAndArch(details.getHypervisorType(),
+ systemVmTemplateRegistration.getValidatedTemplateDetailsForHypervisorAndArch(details.getHypervisorType(),
details.getArch());
fail("Expected CloudRuntimeException due to missing template file");
} catch (CloudRuntimeException e) {
@@ -211,12 +276,11 @@ public void testValidateTemplateFile_checksumMismatch() {
new SystemVmTemplateRegistration.MetadataTemplateDetails(Hypervisor.HypervisorType.KVM,
"name", "file", "url", "checksum", CPU.CPUArch.amd64, "guestos");
File dummyFile = new File("dummy.txt");
- SystemVmTemplateRegistration.NewTemplateMap.put(SystemVmTemplateRegistration.getHypervisorArchKey(
- details.getHypervisorType(), details.getArch()), details);
+ SystemVmTemplateRegistration.METADATA_TEMPLATE_LIST.add(details);
doReturn(dummyFile).when(systemVmTemplateRegistration).getTemplateFile(details);
- doReturn(true).when(systemVmTemplateRegistration).isTemplateFileChecksumDifferent(details, dummyFile);
- try {
- systemVmTemplateRegistration.validateTemplateFileForHypervisorAndArch(details.getHypervisorType(),
+ try (MockedStatic digestMock = Mockito.mockStatic(DigestHelper.class)) {
+ digestMock.when(() -> DigestHelper.calculateChecksum(dummyFile)).thenReturn("differentChecksum");
+ systemVmTemplateRegistration.getValidatedTemplateDetailsForHypervisorAndArch(details.getHypervisorType(),
details.getArch());
fail("Expected CloudRuntimeException due to checksum failure");
} catch (CloudRuntimeException e) {
@@ -230,42 +294,55 @@ public void testValidateTemplateFile_success() {
new SystemVmTemplateRegistration.MetadataTemplateDetails(Hypervisor.HypervisorType.KVM,
"name", "file", "url", "checksum", CPU.CPUArch.amd64, "guestos");
File dummyFile = new File("dummy.txt");
- SystemVmTemplateRegistration.NewTemplateMap.put(SystemVmTemplateRegistration.getHypervisorArchKey(
- details.getHypervisorType(), details.getArch()), details);
+ SystemVmTemplateRegistration.METADATA_TEMPLATE_LIST.add(details);
doReturn(dummyFile).when(systemVmTemplateRegistration).getTemplateFile(details);
- doReturn(false).when(systemVmTemplateRegistration).isTemplateFileChecksumDifferent(details, dummyFile);
- systemVmTemplateRegistration.validateTemplateFileForHypervisorAndArch(details.getHypervisorType(),
- details.getArch());
+ try (MockedStatic digestMock = Mockito.mockStatic(DigestHelper.class)) {
+ digestMock.when(() -> DigestHelper.calculateChecksum(dummyFile)).thenReturn("checksum");
+ systemVmTemplateRegistration.getValidatedTemplateDetailsForHypervisorAndArch(details.getHypervisorType(),
+ details.getArch());
+ }
}
@Test
- public void testValidateAndRegisterTemplate() {
+ public void testValidateAndAddExistingTemplateToStore() {
+ long zoneId = 1L;
Hypervisor.HypervisorType hypervisor = Hypervisor.HypervisorType.KVM;
- String name = "TestTemplate";
- Long storeId = 123L;
VMTemplateVO templateVO = new VMTemplateVO();
- templateVO.setArch(CPU.CPUArch.x86);
+ templateVO.setHypervisorType(hypervisor);
+ templateVO.setArch(CPU.CPUArch.getDefault());
TemplateDataStoreVO templateDataStoreVO = new TemplateDataStoreVO();
+ Long storeId = 123L;
String filePath = "/dummy/path";
- doNothing().when(systemVmTemplateRegistration).validateTemplateFileForHypervisorAndArch(hypervisor, templateVO.getArch());
- doNothing().when(systemVmTemplateRegistration).registerTemplate(hypervisor, name, storeId, templateVO, templateDataStoreVO, filePath);
- systemVmTemplateRegistration.validateAndRegisterTemplate(hypervisor, name, storeId, templateVO, templateDataStoreVO, filePath);
- verify(systemVmTemplateRegistration).validateTemplateFileForHypervisorAndArch(eq(hypervisor), eq(templateVO.getArch()));
- verify(systemVmTemplateRegistration).registerTemplate(eq(hypervisor), eq(name), eq(storeId), eq(templateVO), eq(templateDataStoreVO), eq(filePath));
+ SystemVmTemplateRegistration.MetadataTemplateDetails details =
+ mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
+ doReturn(details).when(systemVmTemplateRegistration)
+ .getValidatedTemplateDetailsForHypervisorAndArch(hypervisor, templateVO.getArch());
+ doNothing().when(systemVmTemplateRegistration).addExistingTemplateToStore(templateVO, details,
+ templateDataStoreVO, zoneId, storeId, filePath);
+ systemVmTemplateRegistration.validateAndAddTemplateToStore(templateVO, templateDataStoreVO, zoneId, storeId,
+ filePath);
+ verify(systemVmTemplateRegistration)
+ .getValidatedTemplateDetailsForHypervisorAndArch(hypervisor, templateVO.getArch());
+ verify(systemVmTemplateRegistration).addExistingTemplateToStore(templateVO, details, templateDataStoreVO,
+ zoneId, storeId, filePath);
}
@Test
- public void testValidateAndRegisterTemplateForNonExistingEntries() {
+ public void testValidateAndAddExistingTemplateToStoreForNonExistingEntries() {
+ long zoneId = 1L;
Hypervisor.HypervisorType hypervisor = Hypervisor.HypervisorType.KVM;
CPU.CPUArch arch = CPU.CPUArch.amd64;
String name = "TestTemplateNonExisting";
- Pair storeUrlAndId = new Pair<>("nfs://dummy", 456L);
+ long storeId = 123L;
String filePath = "/dummy/path/nonexisting";
- doNothing().when(systemVmTemplateRegistration).validateTemplateFileForHypervisorAndArch(hypervisor, arch);
- doNothing().when(systemVmTemplateRegistration).registerTemplateForNonExistingEntries(hypervisor, arch, name, storeUrlAndId, filePath);
- systemVmTemplateRegistration.validateAndRegisterTemplateForNonExistingEntries(hypervisor, arch, name, storeUrlAndId, filePath);
- verify(systemVmTemplateRegistration).validateTemplateFileForHypervisorAndArch(eq(hypervisor), eq(arch));
- verify(systemVmTemplateRegistration).registerTemplateForNonExistingEntries(eq(hypervisor), eq(arch), eq(name), eq(storeUrlAndId), eq(filePath));
+ SystemVmTemplateRegistration.MetadataTemplateDetails details =
+ mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
+ doReturn(details).when(systemVmTemplateRegistration)
+ .getValidatedTemplateDetailsForHypervisorAndArch(hypervisor, arch);
+ doNothing().when(systemVmTemplateRegistration).registerNewTemplate(name, details, zoneId, storeId, filePath);
+ systemVmTemplateRegistration.validateAndRegisterNewTemplate(hypervisor, arch, name, zoneId, storeId, filePath);
+ verify(systemVmTemplateRegistration).getValidatedTemplateDetailsForHypervisorAndArch(hypervisor, arch);
+ verify(systemVmTemplateRegistration).registerNewTemplate(name, details, zoneId, storeId, filePath);
}
@Test
@@ -316,86 +393,73 @@ public void testGetTemplateFile_fileDoesNotExist_downloadSucceeds() {
}
@Test
- public void testIsTemplateFileChecksumDifferent_noMismatch() {
- SystemVmTemplateRegistration.MetadataTemplateDetails details =
- Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
- when(details.getChecksum()).thenReturn("dummyChecksum");
- File file = new File("dummy.txt");
- try (MockedStatic digestMock = Mockito.mockStatic(DigestHelper.class)) {
- digestMock.when(() -> DigestHelper.calculateChecksum(file)).thenReturn("dummyChecksum");
- boolean result = systemVmTemplateRegistration.isTemplateFileChecksumDifferent(details, file);
- assertFalse(result);
- }
- }
-
- @Test
- public void testIsTemplateFileChecksumDifferent_mismatch() {
- SystemVmTemplateRegistration.MetadataTemplateDetails details =
- Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
- when(details.getChecksum()).thenReturn("expectedChecksum");
- File file = new File("dummy.txt");
- try (MockedStatic digestMock = Mockito.mockStatic(DigestHelper.class)) {
- digestMock.when(() -> DigestHelper.calculateChecksum(file)).thenReturn("actualChecksum");
- boolean result = systemVmTemplateRegistration.isTemplateFileChecksumDifferent(details, file);
- assertTrue(result);
- }
- }
-
- @Test(expected = CloudRuntimeException.class)
- public void testValidateTemplates_metadataTemplateFailure() {
+ public void testValidateTemplates_metadataTemplateSkip() {
+ Hypervisor.HypervisorType hypervisorType = Hypervisor.HypervisorType.VMware;
+ CPU.CPUArch arch = CPU.CPUArch.arm64;
List> list = new ArrayList<>();
- list.add(new Pair<>(Hypervisor.HypervisorType.KVM, CPU.CPUArch.amd64));
+ list.add(new Pair<>(hypervisorType, arch));
systemVmTemplateRegistration.validateTemplates(list);
+ verify(systemVmTemplateRegistration, never()).getValidatedTemplateDetailsForHypervisorAndArch(hypervisorType,
+ arch);
}
@Test(expected = CloudRuntimeException.class)
public void testValidateTemplates_fileFailure() {
+ Hypervisor.HypervisorType hypervisorType = Hypervisor.HypervisorType.KVM;
+ CPU.CPUArch arch = CPU.CPUArch.amd64;
List> list = new ArrayList<>();
- list.add(new Pair<>(Hypervisor.HypervisorType.KVM, CPU.CPUArch.amd64));
-
+ list.add(new Pair<>(hypervisorType, arch));
SystemVmTemplateRegistration.MetadataTemplateDetails details =
Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
- SystemVmTemplateRegistration.NewTemplateMap.put(SystemVmTemplateRegistration.getHypervisorArchKey(
- Hypervisor.HypervisorType.KVM, CPU.CPUArch.amd64), details);
+ when(details.getHypervisorType()).thenReturn(hypervisorType);
+ when(details.getArch()).thenReturn(arch);
File mockFile = Mockito.mock(File.class);
+ when(details.isFileChecksumDifferent(mockFile)).thenReturn(true);
+ SystemVmTemplateRegistration.METADATA_TEMPLATE_LIST.add(details);
doReturn(mockFile).when(systemVmTemplateRegistration).getTemplateFile(details);
- doReturn(true).when(systemVmTemplateRegistration).isTemplateFileChecksumDifferent(details, mockFile);
systemVmTemplateRegistration.validateTemplates(list);
}
+ @Test(expected = CloudRuntimeException.class)
public void testValidateTemplates_downloadableFileNotFound() {
CPU.CPUArch arch = SystemVmTemplateRegistration.DOWNLOADABLE_TEMPLATE_ARCH_TYPES.get(0);
List> list = new ArrayList<>();
- list.add(new Pair<>(Hypervisor.HypervisorType.KVM, arch));
+ Hypervisor.HypervisorType hypervisorType = Hypervisor.HypervisorType.KVM;
+ list.add(new Pair<>(hypervisorType, arch));
SystemVmTemplateRegistration.MetadataTemplateDetails details =
Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
- SystemVmTemplateRegistration.NewTemplateMap.put(SystemVmTemplateRegistration.getHypervisorArchKey(
- Hypervisor.HypervisorType.KVM, arch), details);
+ when(details.getHypervisorType()).thenReturn(hypervisorType);
+ when(details.getArch()).thenReturn(arch);
+ SystemVmTemplateRegistration.METADATA_TEMPLATE_LIST.add(details);
doReturn(null).when(systemVmTemplateRegistration).getTemplateFile(details);
systemVmTemplateRegistration.validateTemplates(list);
}
@Test
public void testValidateTemplates_success() {
+ Hypervisor.HypervisorType hypervisorType = Hypervisor.HypervisorType.KVM;
+ CPU.CPUArch arch = CPU.CPUArch.amd64;
List> list = new ArrayList<>();
- list.add(new Pair<>(Hypervisor.HypervisorType.KVM, CPU.CPUArch.amd64));
-
+ list.add(new Pair<>(hypervisorType, arch));
SystemVmTemplateRegistration.MetadataTemplateDetails details =
Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
- SystemVmTemplateRegistration.NewTemplateMap.put(SystemVmTemplateRegistration.getHypervisorArchKey(
- Hypervisor.HypervisorType.KVM, CPU.CPUArch.amd64), details);
+ when(details.getHypervisorType()).thenReturn(hypervisorType);
+ when(details.getArch()).thenReturn(arch);
File mockFile = Mockito.mock(File.class);
+ when(details.isFileChecksumDifferent(mockFile)).thenReturn(false);
+ SystemVmTemplateRegistration.METADATA_TEMPLATE_LIST.add(details);
doReturn(mockFile).when(systemVmTemplateRegistration).getTemplateFile(details);
- doReturn(false).when(systemVmTemplateRegistration).isTemplateFileChecksumDifferent(details, mockFile);
systemVmTemplateRegistration.validateTemplates(list);
}
@Test
- public void testRegisterTemplatesForZone() {
+ public void testAddExistingTemplatesForZoneToStore() {
long zoneId = 1L;
String filePath = "dummyFilePath";
String nfsVersion = "nfs3";
Pair storeUrlAndId = new Pair<>("nfs://dummy", 100L);
+ String name = "existing";
+ String url = "url";
doReturn(storeUrlAndId).when(systemVmTemplateRegistration).getNfsStoreInZone(zoneId);
doReturn(nfsVersion).when(systemVmTemplateRegistration).getNfsVersion(storeUrlAndId.second());
try (MockedStatic mockedStatic = Mockito.mockStatic(
@@ -407,21 +471,1169 @@ public void testRegisterTemplatesForZone() {
doReturn(hypervisorArchList).when(clusterDao).listDistinctHypervisorsAndArchExcludingExternalType(zoneId);
SystemVmTemplateRegistration.MetadataTemplateDetails details =
Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
- String name = "existing";
- Mockito.when(details.getArch()).thenReturn(CPU.CPUArch.getDefault());
- Mockito.when(details.getName()).thenReturn(name);
+ when(details.getArch()).thenReturn(CPU.CPUArch.getDefault());
+ when(details.getName()).thenReturn(name);
+ when(details.getUrl()).thenReturn(url);
mockedStatic.when(() -> SystemVmTemplateRegistration.getMetadataTemplateDetails(Mockito.any(),
Mockito.any())).thenReturn(details);
- when(systemVmTemplateRegistration.getRegisteredTemplate(name, arch))
- .thenReturn(null);
- doNothing().when(systemVmTemplateRegistration).registerTemplateForNonExistingEntries(
- hypervisorType, arch,
- name, storeUrlAndId, filePath);
+ doNothing().when(systemVmTemplateRegistration).registerNewTemplate(name, details, zoneId,
+ storeUrlAndId.second(), filePath);
systemVmTemplateRegistration.registerTemplatesForZone(zoneId, filePath);
mockedStatic.verify(() -> SystemVmTemplateRegistration.mountStore(storeUrlAndId.first(), filePath,
nfsVersion));
- verify(systemVmTemplateRegistration).registerTemplateForNonExistingEntries(hypervisorType,
- arch, name, storeUrlAndId, filePath);
+ verify(systemVmTemplateRegistration).registerNewTemplate(name, details, zoneId,
+ storeUrlAndId.second(), filePath);
+ }
+ }
+
+ @Test
+ public void updateOrRegisterSystemVmTemplate_UpdatesRegisteredTemplate() {
+ SystemVmTemplateRegistration.MetadataTemplateDetails templateDetails = Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
+ when(templateDetails.getName()).thenReturn("templateName");
+ when(templateDetails.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM);
+ when(templateDetails.getArch()).thenReturn(CPU.CPUArch.amd64);
+ when(templateDetails.getUrl()).thenReturn("http://example.com/template");
+ VMTemplateVO registeredTemplate = Mockito.mock(VMTemplateVO.class);
+ when(registeredTemplate.getId()).thenReturn(1L);
+ doReturn(registeredTemplate).when(systemVmTemplateRegistration).getRegisteredTemplate(
+ "templateName", Hypervisor.HypervisorType.KVM, CPU.CPUArch.amd64, "http://example.com/template");
+ doNothing().when(systemVmTemplateRegistration).updateRegisteredTemplateDetails(1L, templateDetails,
+ null);
+
+ boolean result = systemVmTemplateRegistration.updateOrRegisterSystemVmTemplate(templateDetails,
+ new ArrayList<>());
+
+ assertFalse(result);
+ verify(systemVmTemplateRegistration).updateRegisteredTemplateDetails(1L, templateDetails, null);
+ }
+
+ @Test
+ public void updateOrRegisterSystemVmTemplate_SkipsUnusedHypervisorArch() {
+ SystemVmTemplateRegistration.MetadataTemplateDetails templateDetails = Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
+ when(templateDetails.getName()).thenReturn("templateName");
+ when(templateDetails.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM);
+ when(templateDetails.getArch()).thenReturn(CPU.CPUArch.amd64);
+ when(templateDetails.getUrl()).thenReturn("http://example.com/template");
+ doReturn(null).when(systemVmTemplateRegistration).getRegisteredTemplate(
+ "templateName", Hypervisor.HypervisorType.KVM, CPU.CPUArch.amd64, "http://example.com/template");
+ doReturn(null).when(vmTemplateDao).findLatestTemplateByTypeAndHypervisorAndArch(
+ Hypervisor.HypervisorType.KVM, CPU.CPUArch.amd64, Storage.TemplateType.SYSTEM);
+
+ boolean result = systemVmTemplateRegistration.updateOrRegisterSystemVmTemplate(templateDetails, new ArrayList<>());
+
+ assertFalse(result);
+ verify(systemVmTemplateRegistration, never()).registerTemplates(anyList());
+ }
+
+ @Test
+ public void updateOrRegisterSystemVmTemplate_RegistersNewTemplate() {
+ SystemVmTemplateRegistration.MetadataTemplateDetails templateDetails = Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
+ when(templateDetails.getName()).thenReturn("templateName");
+ when(templateDetails.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM);
+ when(templateDetails.getArch()).thenReturn(CPU.CPUArch.amd64);
+ when(templateDetails.getUrl()).thenReturn("http://example.com/template");
+ doReturn(null).when(systemVmTemplateRegistration).getRegisteredTemplate(
+ "templateName", Hypervisor.HypervisorType.KVM, CPU.CPUArch.amd64, "http://example.com/template");
+ List> hypervisorsInUse = new ArrayList<>();
+ hypervisorsInUse.add(new Pair<>(Hypervisor.HypervisorType.KVM, CPU.CPUArch.amd64));
+ doNothing().when(systemVmTemplateRegistration).registerTemplates(hypervisorsInUse);
+
+ boolean result = systemVmTemplateRegistration.updateOrRegisterSystemVmTemplate(templateDetails, hypervisorsInUse);
+
+ assertTrue(result);
+ verify(systemVmTemplateRegistration).registerTemplates(eq(hypervisorsInUse));
+ }
+
+ @Test
+ public void updateOrRegisterSystemVmTemplate_ThrowsExceptionOnRegistrationFailure() {
+ SystemVmTemplateRegistration.MetadataTemplateDetails templateDetails = Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
+ when(templateDetails.getName()).thenReturn("templateName");
+ when(templateDetails.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM);
+ when(templateDetails.getArch()).thenReturn(CPU.CPUArch.amd64);
+ when(templateDetails.getUrl()).thenReturn("http://example.com/template");
+ doReturn(null).when(systemVmTemplateRegistration).getRegisteredTemplate(
+ "templateName", Hypervisor.HypervisorType.KVM, CPU.CPUArch.amd64, "http://example.com/template");
+ List> hypervisorsInUse = new ArrayList<>();
+ hypervisorsInUse.add(new Pair<>(Hypervisor.HypervisorType.KVM, CPU.CPUArch.amd64));
+ doThrow(new CloudRuntimeException("Registration failed")).when(systemVmTemplateRegistration).registerTemplates(hypervisorsInUse);
+
+ CloudRuntimeException exception = assertThrows(CloudRuntimeException.class,
+ () -> systemVmTemplateRegistration.updateOrRegisterSystemVmTemplate(templateDetails, hypervisorsInUse));
+
+ assertTrue(exception.getMessage().contains("Failed to register"));
+ }
+
+ @Test
+ public void updateRegisteredTemplateDetails_UpdatesTemplateSuccessfully() {
+ Long templateId = 1L;
+ Long zoneId = 2L;
+ SystemVmTemplateRegistration.MetadataTemplateDetails templateDetails =
+ Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
+ VMTemplateVO templateVO = Mockito.mock(VMTemplateVO.class);
+ GuestOSVO guestOS = Mockito.mock(GuestOSVO.class);
+
+ when(templateDetails.getGuestOs()).thenReturn("Debian");
+ when(templateDetails.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM);
+ when(templateDetails.getName()).thenReturn("templateName");
+ when(vmTemplateDao.findById(templateId)).thenReturn(templateVO);
+ when(guestOSDao.findOneByDisplayName("Debian")).thenReturn(guestOS);
+ when(guestOS.getId()).thenReturn(10L);
+ when(vmTemplateDao.update(templateVO.getId(), templateVO)).thenReturn(true);
+ doNothing().when(systemVmTemplateRegistration).updateSystemVMEntries(templateId, Hypervisor.HypervisorType.KVM);
+ doNothing().when(systemVmTemplateRegistration).updateConfigurationParams(Hypervisor.HypervisorType.KVM,
+ "templateName", zoneId);
+
+ systemVmTemplateRegistration.updateRegisteredTemplateDetails(templateId, templateDetails, zoneId);
+
+ verify(templateVO).setTemplateType(Storage.TemplateType.SYSTEM);
+ verify(templateVO).setGuestOSId(10);
+ verify(vmTemplateDao).update(templateVO.getId(), templateVO);
+ verify(systemVmTemplateRegistration).updateSystemVMEntries(templateId, Hypervisor.HypervisorType.KVM);
+ verify(systemVmTemplateRegistration).updateConfigurationParams(Hypervisor.HypervisorType.KVM,
+ "templateName", zoneId);
+ }
+
+ @Test
+ public void updateRegisteredTemplateDetails_ThrowsExceptionWhenUpdateFails() {
+ Long templateId = 1L;
+ Long zoneId = 2L;
+ SystemVmTemplateRegistration.MetadataTemplateDetails templateDetails =
+ Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
+ VMTemplateVO templateVO = Mockito.mock(VMTemplateVO.class);
+
+ when(templateDetails.getGuestOs()).thenReturn("Debian");
+ when(vmTemplateDao.findById(templateId)).thenReturn(templateVO);
+ when(vmTemplateDao.update(templateVO.getId(), templateVO)).thenReturn(false);
+
+ CloudRuntimeException exception = assertThrows(CloudRuntimeException.class,
+ () -> systemVmTemplateRegistration.updateRegisteredTemplateDetails(templateId, templateDetails, zoneId));
+
+ assertTrue(exception.getMessage().contains("Exception while updating template with id"));
+ verify(systemVmTemplateRegistration, never()).updateSystemVMEntries(anyLong(), any());
+ verify(systemVmTemplateRegistration, never()).updateConfigurationParams(any(), any(), any());
+ }
+
+ @Test
+ public void updateRegisteredTemplateDetails_SkipsGuestOSUpdateWhenNotFound() {
+ Long templateId = 1L;
+ Long zoneId = 2L;
+ SystemVmTemplateRegistration.MetadataTemplateDetails templateDetails =
+ Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
+ VMTemplateVO templateVO = Mockito.mock(VMTemplateVO.class);
+
+ when(templateDetails.getGuestOs()).thenReturn("NonExistentOS");
+ when(templateDetails.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM);
+ when(templateDetails.getName()).thenReturn("templateName");
+ when(vmTemplateDao.findById(templateId)).thenReturn(templateVO);
+ when(guestOSDao.findOneByDisplayName("NonExistentOS")).thenReturn(null);
+ when(vmTemplateDao.update(templateVO.getId(), templateVO)).thenReturn(true);
+ doNothing().when(systemVmTemplateRegistration).updateSystemVMEntries(templateId, Hypervisor.HypervisorType.KVM);
+ doNothing().when(systemVmTemplateRegistration).updateConfigurationParams(Hypervisor.HypervisorType.KVM,
+ "templateName", zoneId);
+
+ systemVmTemplateRegistration.updateRegisteredTemplateDetails(templateId, templateDetails, zoneId);
+
+ verify(templateVO, never()).setGuestOSId(anyInt());
+ verify(vmTemplateDao).update(templateVO.getId(), templateVO);
+ verify(systemVmTemplateRegistration).updateSystemVMEntries(templateId, Hypervisor.HypervisorType.KVM);
+ verify(systemVmTemplateRegistration).updateConfigurationParams(Hypervisor.HypervisorType.KVM,
+ "templateName", zoneId);
+ }
+
+ @Test
+ public void registerTemplatesForZone_SuccessfullyRegistersNewTemplate() {
+ long zoneId = 1L;
+ String storeMountPath = "/mnt/nfs";
+ Pair storeUrlAndId = new Pair<>("nfs://dummy", 100L);
+ String nfsVersion = "nfs3";
+ List> hypervisorArchList = new ArrayList<>();
+ Hypervisor.HypervisorType hypervisorType = Hypervisor.HypervisorType.KVM;
+ CPU.CPUArch arch = CPU.CPUArch.amd64;
+ hypervisorArchList.add(new Pair<>(hypervisorType, arch));
+ SystemVmTemplateRegistration.MetadataTemplateDetails templateDetails =
+ Mockito.mock(SystemVmTemplateRegistration.MetadataTemplateDetails.class);
+ when(templateDetails.getHypervisorType()).thenReturn(hypervisorType);
+ when(templateDetails.getArch()).thenReturn(arch);
+ String name = "TestTemplate";
+ String url = "http://example.com/template";
+ when(templateDetails.getName()).thenReturn(name);
+ when(templateDetails.getUrl()).thenReturn(url);
+ doReturn(storeUrlAndId).when(systemVmTemplateRegistration).getNfsStoreInZone(zoneId);
+ doReturn(nfsVersion).when(systemVmTemplateRegistration).getNfsVersion(storeUrlAndId.second());
+ doReturn(null).when(systemVmTemplateRegistration).getRegisteredTemplate(
+ name, hypervisorType, arch, url);
+ doNothing().when(systemVmTemplateRegistration).registerNewTemplate(
+ name, templateDetails, zoneId, storeUrlAndId.second(), storeMountPath);
+ doReturn(hypervisorArchList).when(clusterDao).listDistinctHypervisorsAndArchExcludingExternalType(zoneId);
+ try (MockedStatic mockedStatic =
+ Mockito.mockStatic(SystemVmTemplateRegistration.class)) {
+ mockedStatic.when(() -> SystemVmTemplateRegistration.getMetadataTemplateDetails(
+ hypervisorType, arch)).thenReturn(templateDetails);
+
+ systemVmTemplateRegistration.registerTemplatesForZone(zoneId, storeMountPath);
+
+ mockedStatic.verify(() -> SystemVmTemplateRegistration.mountStore(
+ eq(storeUrlAndId.first()), eq(storeMountPath), eq(nfsVersion)), times(1));
+ verify(systemVmTemplateRegistration).registerNewTemplate(
+ templateDetails.getName(), templateDetails, zoneId, storeUrlAndId.second(), storeMountPath);
+ }
+ }
+
+ @Test
+ public void registerTemplatesForZone_SkipsWhenTemplateDetailsNotFound() {
+ long zoneId = 1L;
+ String storeMountPath = "/mnt/nfs";
+ Pair storeUrlAndId = new Pair<>("nfs://dummy", 100L);
+ String nfsVersion = "nfs3";
+ List