Merge branch '4.22'

This commit is contained in:
Suresh Kumar Anaparti 2026-04-02 10:30:18 +05:30
commit e2d18c0748
No known key found for this signature in database
GPG Key ID: D7CEAE3A9E71D0AA
19 changed files with 262 additions and 29 deletions

View File

@ -52,6 +52,7 @@ import com.cloud.storage.StorageLayer;
import com.cloud.utils.Pair;
import com.cloud.utils.UriUtils;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.net.HttpClientCloudStackUserAgent;
import com.cloud.utils.net.Proxy;
/**
@ -125,6 +126,7 @@ public class HttpTemplateDownloader extends ManagedContextRunnable implements Te
GetMethod request = new GetMethod(downloadUrl);
request.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, myretryhandler);
request.setFollowRedirects(followRedirects);
request.getParams().setParameter(HttpMethodParams.USER_AGENT, HttpClientCloudStackUserAgent.CLOUDSTACK_USER_AGENT);
return request;
}

View File

@ -18,8 +18,11 @@
//
package com.cloud.storage.template;
import com.cloud.storage.StorageLayer;
import com.cloud.utils.UriUtils;
import com.cloud.utils.net.HttpClientCloudStackUserAgent;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpMethodRetryHandler;
@ -59,6 +62,7 @@ public class MetalinkTemplateDownloader extends TemplateDownloaderBase implement
GetMethod request = new GetMethod(downloadUrl);
request.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, myretryhandler);
request.setFollowRedirects(followRedirects);
request.getParams().setParameter(HttpMethodParams.USER_AGENT, HttpClientCloudStackUserAgent.CLOUDSTACK_USER_AGENT);
if (!toFileSet) {
String[] parts = downloadUrl.split("/");
String filename = parts[parts.length - 1];

View File

@ -44,6 +44,7 @@ import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.lang3.StringUtils;
import com.cloud.storage.StorageLayer;
import com.cloud.utils.net.HttpClientCloudStackUserAgent;
public class SimpleHttpMultiFileDownloader extends ManagedContextRunnable implements TemplateDownloader {
private static final MultiThreadedHttpConnectionManager s_httpClientManager = new MultiThreadedHttpConnectionManager();
@ -95,6 +96,7 @@ public class SimpleHttpMultiFileDownloader extends ManagedContextRunnable implem
GetMethod request = new GetMethod(downloadUrl);
request.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, retryHandler);
request.setFollowRedirects(followRedirects);
request.getParams().setParameter(HttpMethodParams.USER_AGENT, HttpClientCloudStackUserAgent.CLOUDSTACK_USER_AGENT);
return request;
}
@ -141,6 +143,7 @@ public class SimpleHttpMultiFileDownloader extends ManagedContextRunnable implem
continue;
}
HeadMethod headMethod = new HeadMethod(downloadUrl);
headMethod.getParams().setParameter(HttpMethodParams.USER_AGENT, HttpClientCloudStackUserAgent.CLOUDSTACK_USER_AGENT);
try {
if (client.executeMethod(headMethod) != HttpStatus.SC_OK) {
continue;

View File

@ -19,6 +19,7 @@
package org.apache.cloudstack.direct.download;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@ -32,6 +33,7 @@ import java.util.Map;
import com.cloud.utils.Pair;
import com.cloud.utils.UriUtils;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.net.HttpClientCloudStackUserAgent;
import com.cloud.utils.storage.QCOW2Utils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.httpclient.HttpClient;
@ -39,6 +41,7 @@ import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.HeadMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.io.IOUtils;
public class HttpDirectTemplateDownloader extends DirectTemplateDownloaderImpl {
@ -68,6 +71,7 @@ public class HttpDirectTemplateDownloader extends DirectTemplateDownloaderImpl {
protected GetMethod createRequest(String downloadUrl, Map<String, String> headers) {
GetMethod request = new GetMethod(downloadUrl);
request.setFollowRedirects(this.isFollowRedirects());
request.getParams().setParameter(HttpMethodParams.USER_AGENT, HttpClientCloudStackUserAgent.CLOUDSTACK_USER_AGENT);
if (MapUtils.isNotEmpty(headers)) {
for (String key : headers.keySet()) {
request.setRequestHeader(key, headers.get(key));
@ -111,6 +115,7 @@ public class HttpDirectTemplateDownloader extends DirectTemplateDownloaderImpl {
public boolean checkUrl(String url) {
HeadMethod httpHead = new HeadMethod(url);
httpHead.setFollowRedirects(this.isFollowRedirects());
httpHead.getParams().setParameter(HttpMethodParams.USER_AGENT, HttpClientCloudStackUserAgent.CLOUDSTACK_USER_AGENT);
try {
int responseCode = client.executeMethod(httpHead);
if (responseCode != HttpStatus.SC_OK) {

View File

@ -17,6 +17,7 @@
package com.cloud.vm;
import static com.cloud.configuration.ConfigurationManagerImpl.EXPOSE_ERRORS_TO_USER;
import static com.cloud.configuration.ConfigurationManagerImpl.MIGRATE_VM_ACROSS_CLUSTERS;
import java.lang.reflect.Field;
@ -933,10 +934,22 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
public void start(final String vmUuid, final Map<VirtualMachineProfile.Param, Object> params, final DeploymentPlan planToDeploy, final DeploymentPlanner planner) {
try {
advanceStart(vmUuid, params, planToDeploy, planner);
} catch (ConcurrentOperationException | InsufficientCapacityException e) {
throw new CloudRuntimeException(String.format("Unable to start a VM [%s] due to [%s].", vmUuid, e.getMessage()), e).add(VirtualMachine.class, vmUuid);
} catch (ConcurrentOperationException e) {
final CallContext cctxt = CallContext.current();
final Account account = cctxt.getCallingAccount();
if (canExposeError(account)) {
throw new CloudRuntimeException(String.format("Unable to start a VM [%s] due to [%s].", vmUuid, e.getMessage()), e).add(VirtualMachine.class, vmUuid);
}
throw new CloudRuntimeException(String.format("Unable to start a VM [%s] due to concurrent operation.", vmUuid), e).add(VirtualMachine.class, vmUuid);
} catch (final InsufficientCapacityException e) {
final CallContext cctxt = CallContext.current();
final Account account = cctxt.getCallingAccount();
if (canExposeError(account)) {
throw new CloudRuntimeException(String.format("Unable to start a VM [%s] due to [%s].", vmUuid, e.getMessage()), e).add(VirtualMachine.class, vmUuid);
}
throw new CloudRuntimeException(String.format("Unable to start a VM [%s] due to insufficient capacity.", vmUuid), e).add(VirtualMachine.class, vmUuid);
} catch (final ResourceUnavailableException e) {
if (e.getScope() != null && e.getScope().equals(VirtualRouter.class)){
if (e.getScope() != null && e.getScope().equals(VirtualRouter.class)) {
Account callingAccount = CallContext.current().getCallingAccount();
String errorSuffix = (callingAccount != null && callingAccount.getType() == Account.Type.ADMIN) ?
String.format("Failure: %s", e.getMessage()) :
@ -1367,6 +1380,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
final HypervisorGuru hvGuru = _hvGuruMgr.getGuru(vm.getHypervisorType());
Throwable lastKnownError = null;
boolean canRetry = true;
ExcludeList avoids = null;
try {
@ -1390,7 +1404,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
int retry = StartRetry.value();
while (retry-- != 0) {
logger.debug("Instance start attempt #{}", (StartRetry.value() - retry));
int attemptNumber = StartRetry.value() - retry;
logger.debug("Instance start attempt #{}", attemptNumber);
if (reuseVolume) {
final List<VolumeVO> vols = _volsDao.findReadyRootVolumesByInstance(vm.getId());
@ -1456,8 +1471,13 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
reuseVolume = false;
continue;
}
throw new InsufficientServerCapacityException("Unable to create a deployment for " + vmProfile, DataCenter.class, plan.getDataCenterId(),
areAffinityGroupsAssociated(vmProfile));
String message = String.format("Unable to create a deployment for %s after %s attempts", vmProfile, attemptNumber);
if (canExposeError(account) && lastKnownError != null) {
message += String.format(" Last known error: %s", lastKnownError.getMessage());
throw new CloudRuntimeException(message, lastKnownError);
} else {
throw new InsufficientServerCapacityException(message, DataCenter.class, plan.getDataCenterId(), areAffinityGroupsAssociated(vmProfile));
}
}
avoids.addHost(dest.getHost().getId());
@ -1625,11 +1645,15 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
throw new ExecutionException("Unable to start VM:" + vm.getUuid() + " due to error in finalizeStart, not retrying");
}
}
logger.info("Unable to start VM on {} due to {}", dest.getHost(), (startAnswer == null ? " no start answer" : startAnswer.getDetails()));
String msg = String.format("Unable to start VM on %s due to %s", dest.getHost(), startAnswer == null ? "no start command answer" : startAnswer.getDetails());
lastKnownError = new ExecutionException(msg);
if (startAnswer != null && startAnswer.getContextParam("stopRetry") != null) {
logger.error(msg, lastKnownError);
break;
}
logger.debug(msg, lastKnownError);
} catch (OperationTimedoutException e) {
logger.debug("Unable to send the start command to host {} failed to start VM: {}", dest.getHost(), vm);
if (e.isActive()) {
@ -1639,6 +1663,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
throw new AgentUnavailableException("Unable to start " + vm.getHostName(), destHostId, e);
} catch (final ResourceUnavailableException e) {
logger.warn("Unable to contact resource.", e);
lastKnownError = e;
if (!avoids.add(e)) {
if (e.getScope() == Volume.class || e.getScope() == Nic.class) {
throw e;
@ -1695,10 +1720,22 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
}
if (startedVm == null) {
throw new CloudRuntimeException("Unable to start Instance '" + vm.getHostName() + "' (" + vm.getUuid() + "), see management server log for details");
String messageTmpl = "Unable to start Instance '%s' (%s)%s";
String details;
if (canExposeError(account) && lastKnownError != null) {
details = ": " + lastKnownError.getMessage();
} else {
details = ", see management server log for details";
}
String message = String.format(messageTmpl, vm.getHostName(), vm.getUuid(), details);
throw new CloudRuntimeException(message, lastKnownError);
}
}
private boolean canExposeError(Account account) {
return (account != null && account.getType() == Account.Type.ADMIN) || Boolean.TRUE.equals(EXPOSE_ERRORS_TO_USER.value());
}
protected void updateStartCommandWithExternalDetails(Host host, VirtualMachineTO vmTO, StartCommand command) {
if (!HypervisorType.External.equals(host.getHypervisorType())) {
return;

View File

@ -193,6 +193,7 @@ public class NetworkDaoImpl extends GenericDaoBase<NetworkVO, Long>implements Ne
PersistentNetworkSearch.and("id", PersistentNetworkSearch.entity().getId(), Op.NEQ);
PersistentNetworkSearch.and("guestType", PersistentNetworkSearch.entity().getGuestType(), Op.IN);
PersistentNetworkSearch.and("broadcastUri", PersistentNetworkSearch.entity().getBroadcastUri(), Op.EQ);
PersistentNetworkSearch.and("dc", PersistentNetworkSearch.entity().getDataCenterId(), Op.EQ);
PersistentNetworkSearch.and("removed", PersistentNetworkSearch.entity().getRemoved(), Op.NULL);
final SearchBuilder<NetworkOfferingVO> persistentNtwkOffJoin = _ntwkOffDao.createSearchBuilder();
persistentNtwkOffJoin.and("persistent", persistentNtwkOffJoin.entity().isPersistent(), Op.EQ);

View File

@ -35,3 +35,6 @@ UPDATE `cloud`.`alert` SET type = 34 WHERE name = 'ALERT.VR.PRIVATE.IFACE.MTU';
UPDATE `cloud`.`configuration` SET description = 'True if the management server will restart the agent service via SSH into the KVM hosts after or during maintenance operations', is_dynamic = 1 WHERE name = 'kvm.ssh.to.agent';
UPDATE `cloud`.`vm_template` SET guest_os_id = 99 WHERE name = 'kvm-default-vm-import-dummy-template';
-- Update existing vm_template records with NULL type to "USER"
UPDATE `cloud`.`vm_template` SET `type` = 'USER' WHERE `type` IS NULL;

View File

@ -40,6 +40,7 @@ import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.storage.datastore.util.ScaleIOUtil;
import org.apache.cloudstack.storage.to.VolumeObjectTO;
import org.apache.commons.collections.CollectionUtils;
import org.apache.cloudstack.storage.datastore.api.Volume;
import com.cloud.agent.api.VMSnapshotTO;
import com.cloud.alert.AlertManager;
@ -200,11 +201,35 @@ public class ScaleIOVMSnapshotStrategy extends ManagerBase implements VMSnapshot
if (volumeIds != null && !volumeIds.isEmpty()) {
List<VMSnapshotDetailsVO> vmSnapshotDetails = new ArrayList<VMSnapshotDetailsVO>();
vmSnapshotDetails.add(new VMSnapshotDetailsVO(vmSnapshot.getId(), "SnapshotGroupId", snapshotGroupId, false));
Map<String, String> snapshotNameToSrcPathMap = new HashMap<>();
for (Map.Entry<String, String> entry : srcVolumeDestSnapshotMap.entrySet()) {
snapshotNameToSrcPathMap.put(entry.getValue(), entry.getKey());
}
for (int index = 0; index < volumeIds.size(); index++) {
String volumeSnapshotName = srcVolumeDestSnapshotMap.get(ScaleIOUtil.getVolumePath(volumeTOs.get(index).getPath()));
String pathWithScaleIOVolumeName = ScaleIOUtil.updatedPathWithVolumeName(volumeIds.get(index), volumeSnapshotName);
vmSnapshotDetails.add(new VMSnapshotDetailsVO(vmSnapshot.getId(), "Vol_" + volumeTOs.get(index).getId() + "_Snapshot", pathWithScaleIOVolumeName, false));
for (String snapshotVolumeId : volumeIds) {
// Use getVolume() to fetch snapshot volume details and get its name
Volume snapshotVolume = client.getVolume(snapshotVolumeId);
if (snapshotVolume == null) {
throw new CloudRuntimeException("Cannot find snapshot volume with id: " + snapshotVolumeId);
}
String snapshotName = snapshotVolume.getName();
// Match back to source volume path
String srcVolumePath = snapshotNameToSrcPathMap.get(snapshotName);
if (srcVolumePath == null) {
throw new CloudRuntimeException("Cannot match snapshot " + snapshotName + " to a source volume");
}
// Find the matching VolumeObjectTO by path
VolumeObjectTO matchedVolume = volumeTOs.stream()
.filter(v -> ScaleIOUtil.getVolumePath(v.getPath()).equals(srcVolumePath))
.findFirst()
.orElseThrow(() -> new CloudRuntimeException("Cannot find source volume for path: " + srcVolumePath));
String pathWithScaleIOVolumeName = ScaleIOUtil.updatedPathWithVolumeName(snapshotVolumeId, snapshotName);
vmSnapshotDetails.add(new VMSnapshotDetailsVO(vmSnapshot.getId(),
"Vol_" + matchedVolume.getId() + "_Snapshot",
pathWithScaleIOVolumeName, false));
}
vmSnapshotDetailsDao.saveDetails(vmSnapshotDetails);

View File

@ -478,6 +478,9 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co
} else {
host = resourceManager.findOneRandomRunningHostByHypervisor(Hypervisor.HypervisorType.KVM, backup.getZoneId());
}
if (host == null) {
throw new CloudRuntimeException(String.format("Unable to find a running KVM host in zone %d to delete backup %s", backup.getZoneId(), backup.getUuid()));
}
DeleteBackupCommand command = new DeleteBackupCommand(backup.getExternalId(), backupRepository.getType(),
backupRepository.getAddress(), backupRepository.getMountOptions());
@ -564,7 +567,14 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co
@Override
public void syncBackupStorageStats(Long zoneId) {
final List<BackupRepository> repositories = backupRepositoryDao.listByZoneAndProvider(zoneId, getName());
if (CollectionUtils.isEmpty(repositories)) {
return;
}
final Host host = resourceManager.findOneRandomRunningHostByHypervisor(Hypervisor.HypervisorType.KVM, zoneId);
if (host == null) {
logger.warn("Unable to find a running KVM host in zone {} to sync backup storage stats", zoneId);
return;
}
for (final BackupRepository repository : repositories) {
GetBackupStorageStatsCommand command = new GetBackupStorageStatsCommand(repository.getType(), repository.getAddress(), repository.getMountOptions());
BackupStorageStatsAnswer answer;

View File

@ -27,6 +27,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.Predicate;
import com.cloud.agent.api.PrepareStorageClientCommand;
import org.apache.cloudstack.storage.datastore.client.ScaleIOGatewayClient;
@ -644,18 +645,30 @@ public class ScaleIOStorageAdaptor implements StorageAdaptor {
// Assuming SDC service is started, add mdms
String mdms = details.get(ScaleIOGatewayClient.STORAGE_POOL_MDMS);
String[] mdmAddresses = mdms.split(",");
if (mdmAddresses.length > 0) {
if (ScaleIOUtil.isMdmPresent(mdmAddresses[0])) {
return new Ternary<>(true, getSDCDetails(details), "MDM added, no need to prepare the SDC client");
}
ScaleIOUtil.addMdms(mdmAddresses);
if (!ScaleIOUtil.isMdmPresent(mdmAddresses[0])) {
return new Ternary<>(false, null, "Failed to add MDMs");
// remove MDMs already present in the config and added to the SDC
String[] mdmAddressesToAdd = Arrays.stream(mdmAddresses)
.filter(Predicate.not(ScaleIOUtil::isMdmPresent))
.toArray(String[]::new);
// if all MDMs are already in the config and added to the SDC
if (mdmAddressesToAdd.length < 1 && mdmAddresses.length > 0) {
String msg = String.format("MDMs %s of the storage pool %s are already added", mdms, uuid);
logger.debug(msg);
return new Ternary<>(true, getSDCDetails(details), msg);
} else if (mdmAddressesToAdd.length > 0) {
ScaleIOUtil.addMdms(mdmAddressesToAdd);
String[] missingMdmAddresses = Arrays.stream(mdmAddressesToAdd)
.filter(Predicate.not(ScaleIOUtil::isMdmPresent))
.toArray(String[]::new);
if (missingMdmAddresses.length > 0) {
String msg = String.format("Failed to add MDMs %s of the storage pool %s", String.join(", ", missingMdmAddresses), uuid);
logger.debug(msg);
return new Ternary<>(false, null, msg);
} else {
logger.debug(String.format("MDMs %s added to storage pool %s", mdms, uuid));
logger.debug("MDMs {} of the storage pool {} are added", mdmAddressesToAdd, uuid);
applyMdmsChangeWaitTime(details);
}
} else {
return new Ternary<>(false, getSDCDetails(details), "No MDM addresses provided");
}
}

View File

@ -94,6 +94,9 @@ public class ScaleIOGatewayClientImpl implements ScaleIOGatewayClient {
private String password;
private String sessionKey;
private String gatewayVersion = null;
private int[] parsedVersion = null;
// The session token is valid for 8 hours from the time it was created, unless there has been no activity for 10 minutes
// Reference: https://cpsdocs.dellemc.com/bundle/PF_REST_API_RG/page/GUID-92430F19-9F44-42B6-B898-87D5307AE59B.html
private static final long MAX_VALID_SESSION_TIME_IN_HRS = 8;
@ -621,15 +624,26 @@ public class ScaleIOGatewayClientImpl implements ScaleIOGatewayClient {
throw new CloudRuntimeException("Unable to revert, source snapshot volume and destination volume doesn't belong to same volume tree");
}
String requestBody = buildOverwriteVolumeContentRequest(sourceSnapshotVolumeId);
Boolean overwriteVolumeContentStatus = post(
"/instances/Volume::" + destVolumeId + "/action/overwriteVolumeContent",
String.format("{\"srcVolumeId\":\"%s\",\"allowOnExtManagedVol\":\"TRUE\"}", sourceSnapshotVolumeId), Boolean.class);
requestBody, Boolean.class);
if (overwriteVolumeContentStatus != null) {
return overwriteVolumeContentStatus;
}
return false;
}
private String buildOverwriteVolumeContentRequest(final String srcVolumeId) {
if (isVersionAtLeast(4, 0)) {
logger.debug("Using PowerFlex 4.0+ overwriteVolumeContent request body");
return String.format("{\"srcVolumeId\":\"%s\"}", srcVolumeId);
} else {
logger.debug("Using pre-4.0 overwriteVolumeContent request body");
return String.format("{\"srcVolumeId\":\"%s\",\"allowOnExtManagedVol\":\"TRUE\"}", srcVolumeId); }
}
@Override
public boolean mapVolumeToSdc(final String volumeId, final String sdcId) {
Preconditions.checkArgument(StringUtils.isNotEmpty(volumeId), "Volume id cannot be null");
@ -1168,4 +1182,49 @@ public class ScaleIOGatewayClientImpl implements ScaleIOGatewayClient {
sb.append("\n");
return sb.toString();
}
private String fetchGatewayVersion() {
try {
JsonNode node = get("/version", JsonNode.class);
if (node != null && node.isTextual()) {
return node.asText();
}
if (node != null && node.has("version")) {
return node.get("version").asText();
}
} catch (Exception e) {
logger.warn("Could not fetch PowerFlex gateway version: " + e.getMessage());
}
return null;
}
private int[] parseVersion(String version) {
if (StringUtils.isEmpty(version)) return new int[]{0, 0, 0};
String[] parts = version.replaceAll("\"", "").split("\\.");
int[] parsed = new int[3];
for (int i = 0; i < Math.min(parts.length, 3); i++) {
try {
parsed[i] = Integer.parseInt(parts[i].trim());
} catch (NumberFormatException e) {
parsed[i] = 0;
}
}
return parsed;
}
private synchronized int[] getGatewayVersion() {
if (parsedVersion == null) {
gatewayVersion = fetchGatewayVersion();
parsedVersion = parseVersion(gatewayVersion);
logger.info("PowerFlex Gateway version detected: " + gatewayVersion
+ " => parsed: " + Arrays.toString(parsedVersion));
}
return parsedVersion;
}
private boolean isVersionAtLeast(int major, int minor) {
int[] v = getGatewayVersion();
if (v[0] != major) return v[0] > major;
return v[1] >= minor;
}
}

View File

@ -543,6 +543,9 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
public static final ConfigKey<Boolean> ALLOW_DOMAIN_ADMINS_TO_CREATE_TAGGED_OFFERINGS = new ConfigKey<>(Boolean.class, "allow.domain.admins.to.create.tagged.offerings", "Advanced",
"false", "Allow domain admins to create offerings with tags.", true, ConfigKey.Scope.Account, null);
public static final ConfigKey<Boolean> EXPOSE_ERRORS_TO_USER = new ConfigKey<>(Boolean.class, "expose.errors.to.user", ConfigKey.CATEGORY_ADVANCED,
"false", "If set to true, detailed error messages will be returned to all user roles. If false, detailed errors are only shown to admin users", true, ConfigKey.Scope.Global, null);
public static final ConfigKey<Long> DELETE_QUERY_BATCH_SIZE = new ConfigKey<>("Advanced", Long.class, "delete.query.batch.size", "0",
"Indicates the limit applied while deleting entries in bulk. With this, the delete query will apply the limit as many times as necessary," +
" to delete all the entries. This is advised when retaining several days of records, which can lead to slowness. <= 0 means that no limit will " +
@ -9366,11 +9369,10 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
BYTES_MAX_READ_LENGTH, BYTES_MAX_WRITE_LENGTH, ADD_HOST_ON_SERVICE_RESTART_KVM, SET_HOST_DOWN_TO_MAINTENANCE,
VM_SERVICE_OFFERING_MAX_CPU_CORES, VM_SERVICE_OFFERING_MAX_RAM_SIZE, MIGRATE_VM_ACROSS_CLUSTERS,
ENABLE_ACCOUNT_SETTINGS_FOR_DOMAIN, ENABLE_DOMAIN_SETTINGS_FOR_CHILD_DOMAIN,
ALLOW_DOMAIN_ADMINS_TO_CREATE_TAGGED_OFFERINGS, DELETE_QUERY_BATCH_SIZE, AllowNonRFC1918CompliantIPs, HostCapacityTypeCpuMemoryWeight
ALLOW_DOMAIN_ADMINS_TO_CREATE_TAGGED_OFFERINGS, EXPOSE_ERRORS_TO_USER, DELETE_QUERY_BATCH_SIZE, AllowNonRFC1918CompliantIPs, HostCapacityTypeCpuMemoryWeight
};
}
/**
* Returns a string representing the specified configuration's type.
* @param configName name of the configuration.

View File

@ -2416,7 +2416,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
} else if ((cmd instanceof RegisterVnfTemplateCmd || cmd instanceof UpdateVnfTemplateCmd) && !TemplateType.VNF.equals(templateType)) {
throw new InvalidParameterValueException("The template type must be VNF for VNF templates, but the actual type is " + templateType);
}
} else if (cmd instanceof RegisterTemplateCmd) {
} else if (cmd instanceof RegisterTemplateCmd || cmd instanceof GetUploadParamsForTemplateCmd) {
boolean isRouting = Boolean.TRUE.equals(isRoutingType);
templateType = (cmd instanceof RegisterVnfTemplateCmd) ? TemplateType.VNF : (isRouting ? TemplateType.ROUTING : TemplateType.USER);
}
@ -2426,6 +2426,8 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
throw new InvalidParameterValueException(String.format("Users can not register Template with template type %s.", templateType));
} else if (cmd instanceof UpdateTemplateCmd) {
throw new InvalidParameterValueException(String.format("Users can not update Template to template type %s.", templateType));
} else if (cmd instanceof GetUploadParamsForTemplateCmd) {
throw new InvalidParameterValueException(String.format("Users can not request upload parameters for Template with template type %s.", templateType));
}
}
return templateType;

View File

@ -5472,7 +5472,19 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
@Override
public boolean setupVmForPvlan(boolean add, Long hostId, NicProfile nic) {
if (!nic.getBroadCastUri().getScheme().equals("pvlan")) {
if (nic == null) {
logger.warn("Skipping PVLAN setup on host {} because NIC profile is null", hostId);
return false;
}
if (nic.getBroadCastUri() == null) {
logger.debug("Skipping PVLAN setup on host {} for NIC {} because broadcast URI is null", hostId, nic);
return false;
}
String scheme = nic.getBroadCastUri().getScheme();
if (!"pvlan".equalsIgnoreCase(scheme)) {
logger.debug("Skipping PVLAN setup on host {} for NIC {} because broadcast URI scheme is {}", hostId, nic, scheme);
return false;
}
String op = "add";
@ -5480,11 +5492,17 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
// "delete" would remove all the rules(if using ovs) related to this vm
op = "delete";
}
Network network = _networkDao.findById(nic.getNetworkId());
Host host = _hostDao.findById(hostId);
if (host == null) {
logger.warn("Host with id {} does not exist", hostId);
return false;
}
Network network = _networkDao.findById(nic.getNetworkId());
String networkTag = _networkModel.getNetworkTag(host.getHypervisorType(), network);
PvlanSetupCommand cmd = PvlanSetupCommand.createVmSetup(op, nic.getBroadCastUri(), networkTag, nic.getMacAddress());
Answer answer = null;
Answer answer;
try {
answer = _agentMgr.send(hostId, cmd);
} catch (OperationTimedoutException e) {

View File

@ -125,7 +125,7 @@ export default {
postAPI('createBackup', data).then(response => {
this.$pollJob({
jobId: response.createbackupresponse.jobid,
title: this.$t('label.create.bucket'),
title: this.$t('label.create.backup'),
description: values.name,
errorMessage: this.$t('message.create.backup.failed'),
loadingMessage: `${this.$t('label.create.backup')}: ${this.resource.name || this.resource.id}`,

View File

@ -19,6 +19,8 @@
package com.cloud.utils;
import static com.cloud.utils.UriUtils.USER_AGENT;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
@ -33,6 +35,8 @@ import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
import com.cloud.utils.net.HttpClientCloudStackUserAgent;
public class HttpUtils {
protected static Logger LOGGER = LogManager.getLogger(HttpUtils.class);
@ -161,6 +165,7 @@ public class HttpUtils {
try {
URL url = new URL(fileURL);
httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestProperty(USER_AGENT, HttpClientCloudStackUserAgent.CLOUDSTACK_USER_AGENT);
int responseCode = httpConn.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
int contentLength = httpConn.getContentLength();

View File

@ -67,12 +67,14 @@ import org.w3c.dom.NodeList;
import com.cloud.utils.crypt.DBEncryptionUtil;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.net.HttpClientCloudStackUserAgent;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
public class UriUtils {
protected static Logger LOGGER = LogManager.getLogger(UriUtils.class);
public static final String USER_AGENT = "User-Agent";
public static String formNfsUri(String host, String path) {
try {
@ -227,6 +229,7 @@ public class UriUtils {
URI uri = new URI(url);
httpConn = (HttpURLConnection)uri.toURL().openConnection();
httpConn.setRequestMethod(method);
httpConn.setRequestProperty(USER_AGENT, HttpClientCloudStackUserAgent.CLOUDSTACK_USER_AGENT);
httpConn.setConnectTimeout(2000);
httpConn.setReadTimeout(5000);
httpConn.setInstanceFollowRedirects(Boolean.TRUE.equals(followRedirect));

View File

@ -0,0 +1,39 @@
//
// 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.utils.net;
import org.apache.logging.log4j.util.Strings;
public class HttpClientCloudStackUserAgent {
public static final String CLOUDSTACK_USER_AGENT = buildUserAgent();
private static String buildUserAgent() {
String version = HttpClientCloudStackUserAgent.class
.getPackage()
.getImplementationVersion();
if (Strings.isBlank(version)) {
version = "unknown";
}
return "CloudStack-Agent/" + version + " (Apache CloudStack)";
}
private HttpClientCloudStackUserAgent() {}
}

View File

@ -35,6 +35,7 @@ import org.apache.logging.log4j.LogManager;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.UriUtils;
import com.cloud.utils.net.HttpClientCloudStackUserAgent;
public final class QCOW2Utils {
protected static Logger LOGGER = LogManager.getLogger(QCOW2Utils.class);
@ -119,6 +120,7 @@ public final class QCOW2Utils {
try {
URI url = new URI(urlStr);
httpConn = (HttpURLConnection)url.toURL().openConnection();
httpConn.setRequestProperty(UriUtils.USER_AGENT, HttpClientCloudStackUserAgent.CLOUDSTACK_USER_AGENT);
httpConn.setInstanceFollowRedirects(followRedirects);
return getVirtualSize(httpConn.getInputStream(), UriUtils.isUrlForCompressedFile(urlStr));
} catch (URISyntaxException e) {