mirror of https://github.com/apache/cloudstack.git
Merge branch '4.22'
This commit is contained in:
commit
e2d18c0748
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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}`,
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
}
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue