Skip to content

api,ui: multi arch improvements #10289

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 64 commits into from
Apr 25, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
e7ff4ed
wip
shwstppr Jan 28, 2025
67042ce
ui: multi-arch improvements
shwstppr Jan 28, 2025
126dfa9
api,ui: filter resources by arch
shwstppr Jan 29, 2025
8f48da3
ui: show arch tag in infocard
shwstppr Jan 29, 2025
13f3f14
ui: add arch display and filter for kubernetes iso
shwstppr Jan 29, 2025
b017025
simulator: allow adding hosts with arch
shwstppr Jan 29, 2025
ee59e61
api,ui: allow filtering vms by arch
shwstppr Jan 29, 2025
13ced5e
ui: make arch filter a list
shwstppr Jan 29, 2025
16282dd
wip
shwstppr Feb 4, 2025
bed9666
wip
shwstppr Feb 5, 2025
969660a
change for downloading templates if allowed
shwstppr Feb 20, 2025
f74355f
move download method to httputils
shwstppr Feb 20, 2025
9073ec1
remove unnecssary
shwstppr Feb 21, 2025
48c9d29
fix build
shwstppr Feb 21, 2025
bc5f734
fix
shwstppr Feb 22, 2025
60dc9d9
remove unnecessary change
shwstppr Feb 22, 2025
0ac96d6
fixes
shwstppr Mar 6, 2025
33bb563
wip: try system vm deployment with different arch templates
shwstppr Mar 6, 2025
42598f7
fix checkstyle
shwstppr Mar 6, 2025
59f2608
wip: try VR deployment with arch specific template
shwstppr Mar 6, 2025
a2a7f5d
fix systemvm deployment retry
shwstppr Mar 10, 2025
582187a
preferred arch config
shwstppr Mar 11, 2025
6c95e90
ui: changes for arch auto selection in deploy vm
shwstppr Mar 11, 2025
3069929
CPUArch as an enum, make config select
shwstppr Mar 11, 2025
c98ef69
fix persiting ilbvm
shwstppr Mar 11, 2025
ce43205
refactor to use searchbuilder/critera for distinct pair
shwstppr Mar 12, 2025
5d696f0
cpu test
shwstppr Mar 12, 2025
a6bdd52
refactor fetch arch types
shwstppr Mar 12, 2025
499b861
fix
shwstppr Mar 12, 2025
c1750c8
fix
shwstppr Mar 13, 2025
ab07a12
fixes
shwstppr Mar 13, 2025
8d3d9eb
exception fix
shwstppr Mar 13, 2025
cac8a11
refactor and fixes
shwstppr Mar 13, 2025
27f3119
method rename
shwstppr Mar 13, 2025
8475604
refactor
shwstppr Mar 13, 2025
0003b96
add tests
shwstppr Mar 17, 2025
45fc1e1
Revert "add tests"
shwstppr Mar 17, 2025
f8ecb5d
add tests
shwstppr Mar 17, 2025
82ef924
more tests
shwstppr Mar 18, 2025
d86eb34
Merge branch '4.20' into multiarchzones-improvements
shwstppr Mar 18, 2025
6b374a6
fix trailing space
shwstppr Mar 18, 2025
8c8a56a
fix tests
shwstppr Mar 18, 2025
d81d77b
Merge remote-tracking branch 'apache/4.20' into multiarchzones-improv…
shwstppr Mar 19, 2025
38a4fe6
more tests
shwstppr Mar 19, 2025
a04a3a1
add tests
shwstppr Mar 19, 2025
4ff7c4a
change preferred arch config default
shwstppr Mar 19, 2025
11d5ba9
allow same name template for different arch
shwstppr Mar 19, 2025
affd3d8
address config comment, refactor, add arch to sysvm, routers
shwstppr Mar 19, 2025
f0cc075
fix
shwstppr Mar 19, 2025
aface0e
user vm arch
shwstppr Mar 19, 2025
d81283a
set permissions for systemvm template folder
shwstppr Mar 20, 2025
8f3099d
own templates directory itself
shwstppr Mar 24, 2025
ca02558
Update packaging/el8/cloud.spec
shwstppr Mar 27, 2025
68eb611
fix
shwstppr Mar 27, 2025
a096439
change perm on upgrade
shwstppr Mar 27, 2025
f940220
fix for k8s iso arch
shwstppr Apr 10, 2025
b62472d
fix k8s iso response
shwstppr Apr 10, 2025
f58253c
fix tests
shwstppr Apr 10, 2025
daac0d9
fix for cluster arch change
shwstppr Apr 23, 2025
8ce28e7
fix lint
shwstppr Apr 23, 2025
69db12a
allow specifying arch for edge cluster
shwstppr Apr 23, 2025
a15aeb3
fix DISTINCT class field
shwstppr Apr 23, 2025
3807f17
tests
shwstppr Apr 23, 2025
d8da081
Merge remote-tracking branch 'apache/4.20' into multiarchzones-improv…
shwstppr Apr 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
change for downloading templates if allowed
Signed-off-by: Abhishek Kumar <[email protected]>
  • Loading branch information
shwstppr committed Feb 21, 2025
commit 969660a177ba8a7621e49c31faf4f9f19b72439c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -84,54 +84,14 @@
import com.cloud.utils.db.TransactionCallbackNoReturn;
import com.cloud.utils.db.TransactionStatus;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.net.NetUtils;
import com.cloud.utils.script.Script;
import com.cloud.vm.dao.VMInstanceDao;
import com.cloud.vm.dao.VMInstanceDaoImpl;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.framework.config.dao.ConfigurationDaoImpl;
import org.apache.cloudstack.framework.config.impl.ConfigurationVO;
import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
import org.apache.cloudstack.storage.datastore.db.ImageStoreDaoImpl;
import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao;
import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDaoImpl;
import org.apache.cloudstack.storage.datastore.db.ImageStoreVO;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
import org.apache.cloudstack.utils.security.DigestHelper;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.ini4j.Ini;

import javax.inject.Inject;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.Connection;
import java.sql.Date;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;

public class SystemVmTemplateRegistration {
protected static Logger LOGGER = LogManager.getLogger(SystemVmTemplateRegistration.class);
private static final String MOUNT_COMMAND = "sudo mount -t nfs %s %s";
private static final String MOUNT_COMMAND_BASE = "sudo mount -t nfs";
private static final String UMOUNT_COMMAND = "sudo umount %s";
private static final String RELATIVE_TEMPLATE_PATH = "./engine/schema/dist/systemvm-templates/";
private static final String ABSOLUTE_TEMPLATE_PATH = "/usr/share/cloudstack-management/templates/systemvm/";
Expand All @@ -146,6 +106,9 @@ public class SystemVmTemplateRegistration {
private static final Integer LINUX_7_ID = 183;
private static final Integer SCRIPT_TIMEOUT = 1800000;
private static final Integer LOCK_WAIT_TIMEOUT = 1200;
private static final List<String> DOWNLOADABLE_TEMPLATE_ARCH_TYPES = Arrays.asList(
CPU.archARM64Identifier
);


public static String CS_MAJOR_VERSION = null;
Expand Down Expand Up @@ -193,7 +156,7 @@ public SystemVmTemplateRegistration(String systemVmTemplateVersion) {
}

public static String getMountCommand(String nfsVersion, String device, String dir) {
String cmd = "sudo mount -t nfs";
String cmd = MOUNT_COMMAND_BASE;
if (StringUtils.isNotBlank(nfsVersion)) {
cmd = String.format("%s -o vers=%s", cmd, nfsVersion);
}
Expand Down Expand Up @@ -789,7 +752,7 @@ public static String parseMetadataFile() {
Ini.Section section = ini.get(key);
NewTemplateMap.put(key, new MetadataTemplateDetails(hypervisorType.first(), section.get("templatename"),
section.get("filename"), section.get("downloadurl"), section.get("checksum"),
section.get("arch")));
hypervisorType.second()));
}
Ini.Section section = ini.get("default");
return section.get("version");
Expand All @@ -809,6 +772,21 @@ private static void cleanupStore(Long templateId, String filePath) {
}
}

protected File getTemplateFile(MetadataTemplateDetails templateDetails) {
final String filePath = TEMPLATES_PATH + templateDetails.getFilename();
File tempFile = new File(filePath);
if (!tempFile.exists() && DOWNLOADABLE_TEMPLATE_ARCH_TYPES.contains(templateDetails.getArch()) &&
StringUtils.isNotBlank(templateDetails.getUrl())) {
LOGGER.debug("Downloading the template file {} for hypervisor {} and arch {} as it is not present",
templateDetails.getUrl(), templateDetails.getHypervisorType().name(), templateDetails.getArch());
if (!NetUtils.downloadFileWithProgress(templateDetails.getUrl(), filePath, LOGGER)) {
return null;
}
return new File(filePath);
}
return tempFile;
}

private void validateTemplates(List<Pair<Hypervisor.HypervisorType, String>> hypervisorsArchInUse) {
boolean templatesFound = true;
for (Pair<Hypervisor.HypervisorType, String> hypervisorArch : hypervisorsArchInUse) {
Expand All @@ -822,11 +800,12 @@ private void validateTemplates(List<Pair<Hypervisor.HypervisorType, String>> hyp
templatesFound = false;
break;
}
if (CPU.archARM64Identifier.equals(matchedTemplate.getArch())) {
LOGGER.debug("Skipping checksum comparison for the template file and metadata as the arch for template is {}",
matchedTemplate.getArch());
File tempFile = getTemplateFile(matchedTemplate);
if (tempFile == null) {
LOGGER.warn("Failed to download template for hypervisor {} and arch {}, moving ahead",
matchedTemplate.getHypervisorType().name(), matchedTemplate.getArch());
continue;
}
File tempFile = new File(TEMPLATES_PATH + matchedTemplate.getFilename());
String templateChecksum = DigestHelper.calculateChecksum(tempFile);
if (!templateChecksum.equals(matchedTemplate.getChecksum())) {
LOGGER.error("Checksum {} for file {} does not match checksum {} from metadata",
Expand All @@ -842,7 +821,7 @@ private void validateTemplates(List<Pair<Hypervisor.HypervisorType, String>> hyp
}
}

protected void registerTemplatesForZone(long zoneId) {
protected void registerTemplatesForZone(long zoneId, String filePath) {
Pair<String, Long> storeUrlAndId = getNfsStoreInZone(zoneId);
String nfsVersion = getNfsVersion(storeUrlAndId.second());
mountStore(storeUrlAndId.first(), filePath, nfsVersion);
Expand All @@ -856,7 +835,7 @@ protected void registerTemplatesForZone(long zoneId) {
TemplateDataStoreVO templateDataStoreVO = templateDataStoreDao.findByStoreTemplate(storeUrlAndId.second(), templateId);
if (templateDataStoreVO != null) {
String installPath = templateDataStoreVO.getInstallPath();
if (validateIfSeeded(storeUrlAndId.first(), installPath, nfsVersion)) {
if (validateIfSeeded(templateDataStoreVO, storeUrlAndId.first(), installPath, nfsVersion)) {
continue;
}
}
Expand Down Expand Up @@ -891,7 +870,7 @@ public void doInTransactionWithoutResult(final TransactionStatus status) {
if (filePath == null) {
throw new CloudRuntimeException("Failed to create temporary file path to mount the store");
}
registerTemplatesForZone(zoneId);
registerTemplatesForZone(zoneId, filePath);
unmountStore(filePath);
} catch (Exception e) {
unmountStore(filePath);
Expand Down
13 changes: 7 additions & 6 deletions engine/schema/templateConfig.sh
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,13 @@ function createMetadataFile() {

declare -a templates
getTemplateVersion $1
templates=( "kvm:https://download.cloudstack.org/systemvm/${CS_VERSION}/systemvmtemplate-$VERSION-x86_64-kvm.qcow2.bz2"
"vmware:https://download.cloudstack.org/systemvm/${CS_VERSION}/systemvmtemplate-$VERSION-x86_64-vmware.ova"
"xenserver:https://download.cloudstack.org/systemvm/$CS_VERSION/systemvmtemplate-$VERSION-x86_64-xen.vhd.bz2"
"hyperv:https://download.cloudstack.org/systemvm/$CS_VERSION/systemvmtemplate-$VERSION-x86_64-hyperv.vhd.zip"
"lxc:https://download.cloudstack.org/systemvm/$CS_VERSION/systemvmtemplate-$VERSION-x86_64-kvm.qcow2.bz2"
"ovm3:https://download.cloudstack.org/systemvm/$CS_VERSION/systemvmtemplate-$VERSION-x86_64-ovm.raw.bz2" )
templates=( "kvm-x86_64:https://download.cloudstack.org/systemvm/${CS_VERSION}/systemvmtemplate-$VERSION-x86_64-kvm.qcow2.bz2"
"kvm-aarch64:https://download.cloudstack.org/systemvm/${CS_VERSION}/systemvmtemplate-$VERSION-aarch64-kvm.qcow2.bz2"
"vmware-x86_64:https://download.cloudstack.org/systemvm/${CS_VERSION}/systemvmtemplate-$VERSION-x86_64-vmware.ova"
"xenserver-x86_64:https://download.cloudstack.org/systemvm/$CS_VERSION/systemvmtemplate-$VERSION-x86_64-xen.vhd.bz2"
"hyperv-x86_64:https://download.cloudstack.org/systemvm/$CS_VERSION/systemvmtemplate-$VERSION-x86_64-hyperv.vhd.zip"
"lxc-x86_64:https://download.cloudstack.org/systemvm/$CS_VERSION/systemvmtemplate-$VERSION-x86_64-kvm.qcow2.bz2"
"ovm3-x86_64:https://download.cloudstack.org/systemvm/$CS_VERSION/systemvmtemplate-$VERSION-x86_64-ovm.raw.bz2" )

PARENTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )/dist/systemvm-templates/"
mkdir -p $PARENTPATH
Expand Down
53 changes: 52 additions & 1 deletion utils/src/main/java/com/cloud/utils/net/NetUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,12 @@
package com.cloud.utils.net;

import java.io.BufferedReader;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.net.HttpURLConnection;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
Expand All @@ -31,6 +34,7 @@
import java.net.SocketException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
Expand All @@ -51,8 +55,8 @@
import org.apache.commons.net.util.SubnetUtils;
import org.apache.commons.validator.routines.InetAddressValidator;
import org.apache.commons.validator.routines.RegexValidator;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.cloud.utils.IteratorUtil;
import com.cloud.utils.Pair;
Expand Down Expand Up @@ -1874,4 +1878,51 @@ public static String transformCidr(final String cidr) {
final long start = (ip & startNetMask);
return String.format("%s/%s", long2Ip(start), size);
}

public static boolean downloadFileWithProgress(final String fileURL, final String savePath, final Logger logger) {
HttpURLConnection httpConn = null;
try {
URL url = new URL(fileURL);
httpConn = (HttpURLConnection) url.openConnection();
int responseCode = httpConn.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
int contentLength = httpConn.getContentLength();
if (contentLength < 0) {
logger.warn("Content length not provided for {}, progress updates may not be accurate",
fileURL);
}
try (InputStream inputStream = httpConn.getInputStream();
FileOutputStream outputStream = new FileOutputStream(savePath)) {
byte[] buffer = new byte[4096];
int bytesRead;
int downloaded = 0;
int lastReportedPercent = 0;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
downloaded += bytesRead;
if (contentLength > 0) {
int percentDownloaded = (int) ((downloaded / (double) contentLength) * 100);
// Update every 5 percent or on completion
if (percentDownloaded - lastReportedPercent >= 5 || percentDownloaded == 100) {
logger.debug("Downloaded {}% from {}", downloaded, fileURL);
lastReportedPercent = percentDownloaded;
}
}
}
}
logger.info("File {} downloaded successfully using {}.", fileURL, savePath);
} else {
logger.error("No file to download {}. Server replied with code: {}", fileURL, responseCode);
return false;
}
} catch (IOException ex) {
logger.error("Failed to download {} due to: {}", fileURL, ex.getMessage(), ex);
return false;
} finally {
if (httpConn != null) {
httpConn.disconnect();
}
}
return true;
}
}