mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
Merge branch '4.16' into main
This commit is contained in:
commit
bf70566c2c
@ -22,11 +22,13 @@ public class CopyToSecondaryStorageCommand extends StorageSubSystemCommand {
|
|||||||
private String secondaryStorageUrl;
|
private String secondaryStorageUrl;
|
||||||
private String systemVmIp;
|
private String systemVmIp;
|
||||||
private String fileName;
|
private String fileName;
|
||||||
|
private String nfsVersion;
|
||||||
|
|
||||||
public CopyToSecondaryStorageCommand(String secondaryStorageUrl, String systemVmIp, String fileName) {
|
public CopyToSecondaryStorageCommand(String secondaryStorageUrl, String systemVmIp, String fileName, String nfsVersion) {
|
||||||
this.secondaryStorageUrl = secondaryStorageUrl;
|
this.secondaryStorageUrl = secondaryStorageUrl;
|
||||||
this.systemVmIp = systemVmIp;
|
this.systemVmIp = systemVmIp;
|
||||||
this.fileName = fileName;
|
this.fileName = fileName;
|
||||||
|
this.nfsVersion = nfsVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getSecondaryStorageUrl() {
|
public String getSecondaryStorageUrl() {
|
||||||
@ -41,6 +43,10 @@ public class CopyToSecondaryStorageCommand extends StorageSubSystemCommand {
|
|||||||
return fileName;
|
return fileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getNfsVersion() {
|
||||||
|
return nfsVersion;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean executeInSequence() {
|
public boolean executeInSequence() {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -3847,7 +3847,10 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||||||
/**
|
/**
|
||||||
* duplicated in {@see UserVmManagerImpl} for a {@see UserVmVO}
|
* duplicated in {@see UserVmManagerImpl} for a {@see UserVmVO}
|
||||||
*/
|
*/
|
||||||
private void checkIfNetworkExistsForVM(VirtualMachine virtualMachine, Network network) {
|
private void checkIfNetworkExistsForUserVM(VirtualMachine virtualMachine, Network network) {
|
||||||
|
if (virtualMachine.getType() != VirtualMachine.Type.User) {
|
||||||
|
return; // others may have multiple nics in the same network
|
||||||
|
}
|
||||||
List<NicVO> allNics = _nicsDao.listByVmId(virtualMachine.getId());
|
List<NicVO> allNics = _nicsDao.listByVmId(virtualMachine.getId());
|
||||||
for (NicVO nic : allNics) {
|
for (NicVO nic : allNics) {
|
||||||
if (nic.getNetworkId() == network.getId()) {
|
if (nic.getNetworkId() == network.getId()) {
|
||||||
@ -3860,7 +3863,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||||||
InsufficientCapacityException {
|
InsufficientCapacityException {
|
||||||
final CallContext cctx = CallContext.current();
|
final CallContext cctx = CallContext.current();
|
||||||
|
|
||||||
checkIfNetworkExistsForVM(vm, network);
|
checkIfNetworkExistsForUserVM(vm, network);
|
||||||
s_logger.debug("Adding vm " + vm + " to network " + network + "; requested nic profile " + requested);
|
s_logger.debug("Adding vm " + vm + " to network " + network + "; requested nic profile " + requested);
|
||||||
final VMInstanceVO vmVO = _vmDao.findById(vm.getId());
|
final VMInstanceVO vmVO = _vmDao.findById(vm.getId());
|
||||||
final ReservationContext context = new ReservationContextImpl(null, null, cctx.getCallingUser(), cctx.getCallingAccount());
|
final ReservationContext context = new ReservationContextImpl(null, null, cctx.getCallingUser(), cctx.getCallingAccount());
|
||||||
|
|||||||
@ -30,4 +30,6 @@ public interface DiskOfferingDao extends GenericDao<DiskOfferingVO, Long> {
|
|||||||
|
|
||||||
List<DiskOfferingVO> listAllBySizeAndProvisioningType(long size, Storage.ProvisioningType provisioningType);
|
List<DiskOfferingVO> listAllBySizeAndProvisioningType(long size, Storage.ProvisioningType provisioningType);
|
||||||
|
|
||||||
|
List<DiskOfferingVO> findCustomDiskOfferings();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -140,6 +140,16 @@ public class DiskOfferingDaoImpl extends GenericDaoBase<DiskOfferingVO, Long> im
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<DiskOfferingVO> findCustomDiskOfferings() {
|
||||||
|
SearchBuilder<DiskOfferingVO> sb = createSearchBuilder();
|
||||||
|
sb.and("customized", sb.entity().isCustomized(), SearchCriteria.Op.EQ);
|
||||||
|
sb.done();
|
||||||
|
SearchCriteria<DiskOfferingVO> sc = sb.create();
|
||||||
|
sc.setParameters("customized", true);
|
||||||
|
return listBy(sc);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean remove(Long id) {
|
public boolean remove(Long id) {
|
||||||
DiskOfferingVO diskOffering = createForUpdate();
|
DiskOfferingVO diskOffering = createForUpdate();
|
||||||
|
|||||||
@ -18,31 +18,15 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.cloudstack.storage.image;
|
package org.apache.cloudstack.storage.image;
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao;
|
|
||||||
|
|
||||||
import com.cloud.capacity.CapacityManager;
|
import com.cloud.capacity.CapacityManager;
|
||||||
|
|
||||||
public abstract class NfsImageStoreDriverImpl extends BaseImageStoreDriverImpl {
|
public abstract class NfsImageStoreDriverImpl extends BaseImageStoreDriverImpl {
|
||||||
|
|
||||||
@Inject
|
|
||||||
ImageStoreDetailsDao _imageStoreDetailsDao;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve NFS version to be used for imgStoreId store, if provided in image_store_details table
|
* Retrieve the NFS version to be used for the imgStoreId store
|
||||||
* @param imgStoreId store id
|
|
||||||
* @return "secstorage.nfs.version" associated value for imgStoreId in image_store_details table if exists, null if not
|
|
||||||
*/
|
*/
|
||||||
protected String getNfsVersion(long imgStoreId){
|
protected String getNfsVersion(long imgStoreId) {
|
||||||
Map<String, String> imgStoreDetails = _imageStoreDetailsDao.getDetails(imgStoreId);
|
return CapacityManager.ImageStoreNFSVersion.valueIn(imgStoreId);
|
||||||
String nfsVersionKey = CapacityManager.ImageStoreNFSVersion.key();
|
|
||||||
if (imgStoreDetails != null && imgStoreDetails.containsKey(nfsVersionKey)){
|
|
||||||
return imgStoreDetails.get(nfsVersionKey);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -226,6 +226,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
|
|||||||
protected static final HashMap<VmPowerState, PowerState> s_powerStatesTable;
|
protected static final HashMap<VmPowerState, PowerState> s_powerStatesTable;
|
||||||
|
|
||||||
public static final String XS_TOOLS_ISO_AFTER_70 = "guest-tools.iso";
|
public static final String XS_TOOLS_ISO_AFTER_70 = "guest-tools.iso";
|
||||||
|
protected static final String PLATFORM_CORES_PER_SOCKET_KEY = "cores-per-socket";
|
||||||
|
|
||||||
static {
|
static {
|
||||||
s_powerStatesTable = new HashMap<VmPowerState, PowerState>();
|
s_powerStatesTable = new HashMap<VmPowerState, PowerState>();
|
||||||
@ -1110,8 +1111,8 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
|
|||||||
return cdromVBD;
|
return cdromVBD;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean createSecondaryStorageFolder(final Connection conn, final String remoteMountPath, final String newFolder) {
|
protected boolean createSecondaryStorageFolder(final Connection conn, final String remoteMountPath, final String newFolder, final String nfsVersion) {
|
||||||
final String result = callHostPlugin(conn, "vmopsSnapshot", "create_secondary_storage_folder", "remoteMountPath", remoteMountPath, "newFolder", newFolder);
|
final String result = callHostPlugin(conn, "vmopsSnapshot", "create_secondary_storage_folder", "remoteMountPath", remoteMountPath, "newFolder", newFolder, "nfsVersion", nfsVersion);
|
||||||
return result != null;
|
return result != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1482,8 +1483,8 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
|
|||||||
return vm;
|
return vm;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean deleteSecondaryStorageFolder(final Connection conn, final String remoteMountPath, final String folder) {
|
protected boolean deleteSecondaryStorageFolder(final Connection conn, final String remoteMountPath, final String folder, final String nfsVersion) {
|
||||||
final String details = callHostPlugin(conn, "vmopsSnapshot", "delete_secondary_storage_folder", "remoteMountPath", remoteMountPath, "folder", folder);
|
final String details = callHostPlugin(conn, "vmopsSnapshot", "delete_secondary_storage_folder", "remoteMountPath", remoteMountPath, "folder", folder, "nfsVersion", nfsVersion);
|
||||||
return details != null && details.equals("1");
|
return details != null && details.equals("1");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1899,13 +1900,25 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void syncPlatformAndCoresPerSocketSettings(String coresPerSocket, Map<String, String> platform) {
|
||||||
|
if (org.apache.commons.lang3.StringUtils.isBlank(coresPerSocket) || platform == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (platform.containsKey(PLATFORM_CORES_PER_SOCKET_KEY)) {
|
||||||
|
s_logger.debug("Updating the cores per socket value from: " + platform.get(PLATFORM_CORES_PER_SOCKET_KEY) + " to " + coresPerSocket);
|
||||||
|
}
|
||||||
|
platform.put(PLATFORM_CORES_PER_SOCKET_KEY, coresPerSocket);
|
||||||
|
}
|
||||||
|
|
||||||
protected void finalizeVmMetaData(final VM vm, final VM.Record vmr, final Connection conn, final VirtualMachineTO vmSpec) throws Exception {
|
protected void finalizeVmMetaData(final VM vm, final VM.Record vmr, final Connection conn, final VirtualMachineTO vmSpec) throws Exception {
|
||||||
|
|
||||||
final Map<String, String> details = vmSpec.getDetails();
|
final Map<String, String> details = vmSpec.getDetails();
|
||||||
if (details != null) {
|
if (details != null) {
|
||||||
final String platformstring = details.get(VmDetailConstants.PLATFORM);
|
final String platformstring = details.get(VmDetailConstants.PLATFORM);
|
||||||
|
final String coresPerSocket = details.get(VmDetailConstants.CPU_CORE_PER_SOCKET);
|
||||||
if (platformstring != null && !platformstring.isEmpty()) {
|
if (platformstring != null && !platformstring.isEmpty()) {
|
||||||
final Map<String, String> platform = com.cloud.utils.StringUtils.stringToMap(platformstring);
|
final Map<String, String> platform = com.cloud.utils.StringUtils.stringToMap(platformstring);
|
||||||
|
syncPlatformAndCoresPerSocketSettings(coresPerSocket, platform);
|
||||||
vm.setPlatform(conn, platform);
|
vm.setPlatform(conn, platform);
|
||||||
} else {
|
} else {
|
||||||
final String timeoffset = details.get(VmDetailConstants.TIME_OFFSET);
|
final String timeoffset = details.get(VmDetailConstants.TIME_OFFSET);
|
||||||
@ -1914,10 +1927,9 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
|
|||||||
platform.put(VmDetailConstants.TIME_OFFSET, timeoffset);
|
platform.put(VmDetailConstants.TIME_OFFSET, timeoffset);
|
||||||
vm.setPlatform(conn, platform);
|
vm.setPlatform(conn, platform);
|
||||||
}
|
}
|
||||||
final String coresPerSocket = details.get(VmDetailConstants.CPU_CORE_PER_SOCKET);
|
|
||||||
if (coresPerSocket != null) {
|
if (coresPerSocket != null) {
|
||||||
final Map<String, String> platform = vm.getPlatform(conn);
|
final Map<String, String> platform = vm.getPlatform(conn);
|
||||||
platform.put("cores-per-socket", coresPerSocket);
|
syncPlatformAndCoresPerSocketSettings(coresPerSocket, platform);
|
||||||
vm.setPlatform(conn, platform);
|
vm.setPlatform(conn, platform);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4102,7 +4114,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected boolean postCreatePrivateTemplate(final Connection conn, final String templatePath, final String tmpltFilename, final String templateName, String templateDescription, String checksum,
|
protected boolean postCreatePrivateTemplate(final Connection conn, final String templatePath, final String tmpltFilename, final String templateName, String templateDescription, String checksum,
|
||||||
final long size, final long virtualSize, final long templateId) {
|
final long size, final long virtualSize, final long templateId, final String nfsVersion) {
|
||||||
|
|
||||||
if (templateDescription == null) {
|
if (templateDescription == null) {
|
||||||
templateDescription = "";
|
templateDescription = "";
|
||||||
@ -4113,7 +4125,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
|
|||||||
}
|
}
|
||||||
|
|
||||||
final String result = callHostPlugin(conn, "vmopsSnapshot", "post_create_private_template", "templatePath", templatePath, "templateFilename", tmpltFilename, "templateName", templateName,
|
final String result = callHostPlugin(conn, "vmopsSnapshot", "post_create_private_template", "templatePath", templatePath, "templateFilename", tmpltFilename, "templateName", templateName,
|
||||||
"templateDescription", templateDescription, "checksum", checksum, "size", String.valueOf(size), "virtualSize", String.valueOf(virtualSize), "templateId", String.valueOf(templateId));
|
"templateDescription", templateDescription, "checksum", checksum, "size", String.valueOf(size), "virtualSize", String.valueOf(virtualSize), "templateId", String.valueOf(templateId), "nfsVersion", nfsVersion);
|
||||||
|
|
||||||
boolean success = false;
|
boolean success = false;
|
||||||
if (result != null && !result.isEmpty()) {
|
if (result != null && !result.isEmpty()) {
|
||||||
@ -5661,6 +5673,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
|
|||||||
String secondaryStorageUrl = cmd.getSecondaryStorageUrl();
|
String secondaryStorageUrl = cmd.getSecondaryStorageUrl();
|
||||||
String vmIP = cmd.getSystemVmIp();
|
String vmIP = cmd.getSystemVmIp();
|
||||||
String diagnosticsZipFile = cmd.getFileName();
|
String diagnosticsZipFile = cmd.getFileName();
|
||||||
|
String nfsVersion = cmd.getNfsVersion();
|
||||||
|
|
||||||
String localDir = null;
|
String localDir = null;
|
||||||
boolean success;
|
boolean success;
|
||||||
@ -5671,7 +5684,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
|
|||||||
URI uri = new URI(secondaryStorageUrl);
|
URI uri = new URI(secondaryStorageUrl);
|
||||||
secondaryStorageMountPath = uri.getHost() + ":" + uri.getPath();
|
secondaryStorageMountPath = uri.getHost() + ":" + uri.getPath();
|
||||||
localDir = BASE_MOUNT_POINT_ON_REMOTE + UUID.nameUUIDFromBytes(secondaryStorageMountPath.getBytes());
|
localDir = BASE_MOUNT_POINT_ON_REMOTE + UUID.nameUUIDFromBytes(secondaryStorageMountPath.getBytes());
|
||||||
String mountPoint = mountNfs(conn, secondaryStorageMountPath, localDir);
|
String mountPoint = mountNfs(conn, secondaryStorageMountPath, localDir, nfsVersion);
|
||||||
if (StringUtils.isBlank(mountPoint)) {
|
if (StringUtils.isBlank(mountPoint)) {
|
||||||
return new CopyToSecondaryStorageAnswer(cmd, false, "Could not mount secondary storage " + secondaryStorageMountPath + " on host " + localDir);
|
return new CopyToSecondaryStorageAnswer(cmd, false, "Could not mount secondary storage " + secondaryStorageMountPath + " on host " + localDir);
|
||||||
}
|
}
|
||||||
@ -5698,11 +5711,11 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String mountNfs(Connection conn, String remoteDir, String localDir) {
|
private String mountNfs(Connection conn, String remoteDir, String localDir, String nfsVersion) {
|
||||||
if (localDir == null) {
|
if (localDir == null) {
|
||||||
localDir = BASE_MOUNT_POINT_ON_REMOTE + UUID.nameUUIDFromBytes(remoteDir.getBytes());
|
localDir = BASE_MOUNT_POINT_ON_REMOTE + UUID.nameUUIDFromBytes(remoteDir.getBytes());
|
||||||
}
|
}
|
||||||
return callHostPlugin(conn, "cloud-plugin-storage", "mountNfsSecondaryStorage", "localDir", localDir, "remoteDir", remoteDir);
|
return callHostPlugin(conn, "cloud-plugin-storage", "mountNfsSecondaryStorage", "localDir", localDir, "remoteDir", remoteDir, "nfsVersion", nfsVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unmount secondary storage from host
|
// Unmount secondary storage from host
|
||||||
|
|||||||
@ -916,8 +916,9 @@ public class XenServerStorageProcessor implements StorageProcessor {
|
|||||||
try {
|
try {
|
||||||
final NfsTO nfsStore = (NfsTO) destStore;
|
final NfsTO nfsStore = (NfsTO) destStore;
|
||||||
final URI uri = new URI(nfsStore.getUrl());
|
final URI uri = new URI(nfsStore.getUrl());
|
||||||
|
final String nfsVersion = nfsStore.getNfsVersion();
|
||||||
// Create the volume folder
|
// Create the volume folder
|
||||||
if (!hypervisorResource.createSecondaryStorageFolder(conn, uri.getHost() + ":" + uri.getPath(), destVolume.getPath())) {
|
if (!hypervisorResource.createSecondaryStorageFolder(conn, uri.getHost() + ":" + uri.getPath(), destVolume.getPath(), nfsVersion)) {
|
||||||
throw new InternalErrorException("Failed to create the volume folder.");
|
throw new InternalErrorException("Failed to create the volume folder.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1179,6 +1180,7 @@ public class XenServerStorageProcessor implements StorageProcessor {
|
|||||||
secondaryStorageUrl = cacheStore.getUrl();
|
secondaryStorageUrl = cacheStore.getUrl();
|
||||||
destPath = destData.getPath();
|
destPath = destData.getPath();
|
||||||
}
|
}
|
||||||
|
String nfsVersion = cacheStore.getNfsVersion();
|
||||||
|
|
||||||
final SnapshotObjectTO snapshotTO = (SnapshotObjectTO) srcData;
|
final SnapshotObjectTO snapshotTO = (SnapshotObjectTO) srcData;
|
||||||
final SnapshotObjectTO snapshotOnImage = (SnapshotObjectTO) destData;
|
final SnapshotObjectTO snapshotOnImage = (SnapshotObjectTO) destData;
|
||||||
@ -1235,7 +1237,7 @@ public class XenServerStorageProcessor implements StorageProcessor {
|
|||||||
if (fullbackup) {
|
if (fullbackup) {
|
||||||
// the first snapshot is always a full snapshot
|
// the first snapshot is always a full snapshot
|
||||||
|
|
||||||
if (!hypervisorResource.createSecondaryStorageFolder(conn, secondaryStorageMountPath, folder)) {
|
if (!hypervisorResource.createSecondaryStorageFolder(conn, secondaryStorageMountPath, folder, nfsVersion)) {
|
||||||
details = " Filed to create folder " + folder + " in secondary storage";
|
details = " Filed to create folder " + folder + " in secondary storage";
|
||||||
s_logger.warn(details);
|
s_logger.warn(details);
|
||||||
return new CopyCmdAnswer(details);
|
return new CopyCmdAnswer(details);
|
||||||
@ -1349,6 +1351,7 @@ public class XenServerStorageProcessor implements StorageProcessor {
|
|||||||
final TemplateObjectTO template = (TemplateObjectTO) cmd.getDestTO();
|
final TemplateObjectTO template = (TemplateObjectTO) cmd.getDestTO();
|
||||||
final NfsTO destStore = (NfsTO) cmd.getDestTO().getDataStore();
|
final NfsTO destStore = (NfsTO) cmd.getDestTO().getDataStore();
|
||||||
final int wait = cmd.getWait();
|
final int wait = cmd.getWait();
|
||||||
|
final String nfsVersion = destStore.getNfsVersion();
|
||||||
|
|
||||||
final String secondaryStoragePoolURL = destStore.getUrl();
|
final String secondaryStoragePoolURL = destStore.getUrl();
|
||||||
final String volumeUUID = volume.getPath();
|
final String volumeUUID = volume.getPath();
|
||||||
@ -1364,7 +1367,7 @@ public class XenServerStorageProcessor implements StorageProcessor {
|
|||||||
final URI uri = new URI(secondaryStoragePoolURL);
|
final URI uri = new URI(secondaryStoragePoolURL);
|
||||||
secondaryStorageMountPath = uri.getHost() + ":" + uri.getPath();
|
secondaryStorageMountPath = uri.getHost() + ":" + uri.getPath();
|
||||||
installPath = template.getPath();
|
installPath = template.getPath();
|
||||||
if (!hypervisorResource.createSecondaryStorageFolder(conn, secondaryStorageMountPath, installPath)) {
|
if (!hypervisorResource.createSecondaryStorageFolder(conn, secondaryStorageMountPath, installPath, nfsVersion)) {
|
||||||
details = " Filed to create folder " + installPath + " in secondary storage";
|
details = " Filed to create folder " + installPath + " in secondary storage";
|
||||||
s_logger.warn(details);
|
s_logger.warn(details);
|
||||||
return new CopyCmdAnswer(details);
|
return new CopyCmdAnswer(details);
|
||||||
@ -1391,7 +1394,7 @@ public class XenServerStorageProcessor implements StorageProcessor {
|
|||||||
final String templatePath = secondaryStorageMountPath + "/" + installPath;
|
final String templatePath = secondaryStorageMountPath + "/" + installPath;
|
||||||
result =
|
result =
|
||||||
hypervisorResource.postCreatePrivateTemplate(conn, templatePath, tmpltFilename, tmpltUUID, userSpecifiedName, null, physicalSize, virtualSize,
|
hypervisorResource.postCreatePrivateTemplate(conn, templatePath, tmpltFilename, tmpltUUID, userSpecifiedName, null, physicalSize, virtualSize,
|
||||||
template.getId());
|
template.getId(), nfsVersion);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
throw new CloudRuntimeException("Could not create the template.properties file on secondary storage dir: " + tmpltURI);
|
throw new CloudRuntimeException("Could not create the template.properties file on secondary storage dir: " + tmpltURI);
|
||||||
}
|
}
|
||||||
@ -1411,7 +1414,7 @@ public class XenServerStorageProcessor implements StorageProcessor {
|
|||||||
hypervisorResource.removeSR(conn, tmpltSR);
|
hypervisorResource.removeSR(conn, tmpltSR);
|
||||||
}
|
}
|
||||||
if (secondaryStorageMountPath != null) {
|
if (secondaryStorageMountPath != null) {
|
||||||
hypervisorResource.deleteSecondaryStorageFolder(conn, secondaryStorageMountPath, installPath);
|
hypervisorResource.deleteSecondaryStorageFolder(conn, secondaryStorageMountPath, installPath, nfsVersion);
|
||||||
}
|
}
|
||||||
details = "Creating template from volume " + volumeUUID + " failed due to " + e.toString();
|
details = "Creating template from volume " + volumeUUID + " failed due to " + e.toString();
|
||||||
s_logger.error(details, e);
|
s_logger.error(details, e);
|
||||||
@ -1465,7 +1468,8 @@ public class XenServerStorageProcessor implements StorageProcessor {
|
|||||||
|
|
||||||
final String destNfsPath = destUri.getHost() + ":" + destUri.getPath();
|
final String destNfsPath = destUri.getHost() + ":" + destUri.getPath();
|
||||||
|
|
||||||
if (!hypervisorResource.createSecondaryStorageFolder(conn, destNfsPath, destDir)) {
|
String destNfsVersion = destStore.getNfsVersion();
|
||||||
|
if (!hypervisorResource.createSecondaryStorageFolder(conn, destNfsPath, destDir, destNfsVersion)) {
|
||||||
final String details = " Failed to create folder " + destDir + " in secondary storage";
|
final String details = " Failed to create folder " + destDir + " in secondary storage";
|
||||||
|
|
||||||
s_logger.warn(details);
|
s_logger.warn(details);
|
||||||
@ -1500,7 +1504,7 @@ public class XenServerStorageProcessor implements StorageProcessor {
|
|||||||
templatePath = templatePath.replaceAll("//", "/");
|
templatePath = templatePath.replaceAll("//", "/");
|
||||||
|
|
||||||
result = hypervisorResource.postCreatePrivateTemplate(conn, templatePath, templateFilename, templateUuid, userSpecifiedTemplateName, null,
|
result = hypervisorResource.postCreatePrivateTemplate(conn, templatePath, templateFilename, templateUuid, userSpecifiedTemplateName, null,
|
||||||
physicalSize, virtualSize, templateObjTO.getId());
|
physicalSize, virtualSize, templateObjTO.getId(), destNfsVersion);
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
throw new CloudRuntimeException("Could not create the template.properties file on secondary storage dir: " + templateUri);
|
throw new CloudRuntimeException("Could not create the template.properties file on secondary storage dir: " + templateUri);
|
||||||
|
|||||||
@ -73,11 +73,11 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
|
|||||||
super(resource);
|
super(resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void mountNfs(Connection conn, String remoteDir, String localDir) {
|
private void mountNfs(Connection conn, String remoteDir, String localDir, String nfsVersion) {
|
||||||
if (localDir == null) {
|
if (localDir == null) {
|
||||||
localDir = BASE_MOUNT_POINT_ON_REMOTE + UUID.nameUUIDFromBytes(remoteDir.getBytes());
|
localDir = BASE_MOUNT_POINT_ON_REMOTE + UUID.nameUUIDFromBytes(remoteDir.getBytes());
|
||||||
}
|
}
|
||||||
String result = hypervisorResource.callHostPluginAsync(conn, "cloud-plugin-storage", "mountNfsSecondaryStorage", 100 * 1000, "localDir", localDir, "remoteDir", remoteDir);
|
String result = hypervisorResource.callHostPluginAsync(conn, "cloud-plugin-storage", "mountNfsSecondaryStorage", 100 * 1000, "localDir", localDir, "remoteDir", remoteDir, "nfsVersion", nfsVersion);
|
||||||
if (StringUtils.isBlank(result)) {
|
if (StringUtils.isBlank(result)) {
|
||||||
String errMsg = "Could not mount secondary storage " + remoteDir + " on host " + localDir;
|
String errMsg = "Could not mount secondary storage " + remoteDir + " on host " + localDir;
|
||||||
s_logger.warn(errMsg);
|
s_logger.warn(errMsg);
|
||||||
@ -244,9 +244,9 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SR createFileSr(Connection conn, String remotePath, String dir) {
|
protected SR createFileSr(Connection conn, String remotePath, String dir, String nfsVersion) {
|
||||||
String localDir = BASE_MOUNT_POINT_ON_REMOTE + UUID.nameUUIDFromBytes(remotePath.getBytes());
|
String localDir = BASE_MOUNT_POINT_ON_REMOTE + UUID.nameUUIDFromBytes(remotePath.getBytes());
|
||||||
mountNfs(conn, remotePath, localDir);
|
mountNfs(conn, remotePath, localDir, nfsVersion);
|
||||||
return createFileSR(conn, localDir + "/" + dir);
|
return createFileSR(conn, localDir + "/" + dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,6 +269,7 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
|
|||||||
final String storeUrl = srcImageStore.getUrl();
|
final String storeUrl = srcImageStore.getUrl();
|
||||||
final URI uri = new URI(storeUrl);
|
final URI uri = new URI(storeUrl);
|
||||||
String volumePath = srcData.getPath();
|
String volumePath = srcData.getPath();
|
||||||
|
String nfsVersion = srcImageStore.getNfsVersion();
|
||||||
|
|
||||||
volumePath = StringUtils.stripEnd(volumePath, "/");
|
volumePath = StringUtils.stripEnd(volumePath, "/");
|
||||||
|
|
||||||
@ -282,7 +283,7 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
|
|||||||
volumeDirectory = volumePath.substring(0, index);
|
volumeDirectory = volumePath.substring(0, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
srcSr = createFileSr(conn, uri.getHost() + ":" + uri.getPath(), volumeDirectory);
|
srcSr = createFileSr(conn, uri.getHost() + ":" + uri.getPath(), volumeDirectory, nfsVersion);
|
||||||
|
|
||||||
final Set<VDI> setVdis = srcSr.getVDIs(conn);
|
final Set<VDI> setVdis = srcSr.getVDIs(conn);
|
||||||
|
|
||||||
@ -416,7 +417,7 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected String backupSnapshot(final Connection conn, final String primaryStorageSRUuid, final String localMountPoint, final String path, final String secondaryStorageMountPath,
|
protected String backupSnapshot(final Connection conn, final String primaryStorageSRUuid, final String localMountPoint, final String path, final String secondaryStorageMountPath,
|
||||||
final String snapshotUuid, String prevBackupUuid, final String prevSnapshotUuid, final Boolean isISCSI, int wait) {
|
final String snapshotUuid, String prevBackupUuid, final String prevSnapshotUuid, final Boolean isISCSI, int wait, String nfsVersion) {
|
||||||
boolean filesrcreated = false;
|
boolean filesrcreated = false;
|
||||||
// boolean copied = false;
|
// boolean copied = false;
|
||||||
|
|
||||||
@ -427,7 +428,7 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
|
|||||||
|
|
||||||
final String remoteDir = secondaryStorageMountPath;
|
final String remoteDir = secondaryStorageMountPath;
|
||||||
try {
|
try {
|
||||||
ssSR = createFileSr(conn, remoteDir, path);
|
ssSR = createFileSr(conn, remoteDir, path, nfsVersion);
|
||||||
filesrcreated = true;
|
filesrcreated = true;
|
||||||
|
|
||||||
final VDI snapshotvdi = VDI.getByUuid(conn, snapshotUuid);
|
final VDI snapshotvdi = VDI.getByUuid(conn, snapshotUuid);
|
||||||
@ -509,6 +510,7 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
|
|||||||
secondaryStorageUrl = cacheStore.getUrl();
|
secondaryStorageUrl = cacheStore.getUrl();
|
||||||
destPath = destData.getPath();
|
destPath = destData.getPath();
|
||||||
}
|
}
|
||||||
|
String nfsVersion = cacheStore != null ? cacheStore.getNfsVersion() : null;
|
||||||
|
|
||||||
final SnapshotObjectTO snapshotTO = (SnapshotObjectTO)srcData;
|
final SnapshotObjectTO snapshotTO = (SnapshotObjectTO)srcData;
|
||||||
final SnapshotObjectTO snapshotOnImage = (SnapshotObjectTO)destData;
|
final SnapshotObjectTO snapshotOnImage = (SnapshotObjectTO)destData;
|
||||||
@ -569,7 +571,7 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
|
|||||||
Task task = null;
|
Task task = null;
|
||||||
try {
|
try {
|
||||||
final String localDir = BASE_MOUNT_POINT_ON_REMOTE + UUID.nameUUIDFromBytes(secondaryStorageMountPath.getBytes());
|
final String localDir = BASE_MOUNT_POINT_ON_REMOTE + UUID.nameUUIDFromBytes(secondaryStorageMountPath.getBytes());
|
||||||
mountNfs(conn, secondaryStorageMountPath, localDir);
|
mountNfs(conn, secondaryStorageMountPath, localDir, nfsVersion);
|
||||||
final boolean result = makeDirectory(conn, localDir + "/" + folder);
|
final boolean result = makeDirectory(conn, localDir + "/" + folder);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
details = " Failed to create folder " + folder + " in secondary storage";
|
details = " Failed to create folder " + folder + " in secondary storage";
|
||||||
@ -577,7 +579,7 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
|
|||||||
return new CopyCmdAnswer(details);
|
return new CopyCmdAnswer(details);
|
||||||
}
|
}
|
||||||
|
|
||||||
snapshotSr = createFileSr(conn, secondaryStorageMountPath, folder);
|
snapshotSr = createFileSr(conn, secondaryStorageMountPath, folder, nfsVersion);
|
||||||
|
|
||||||
task = snapshotVdi.copyAsync(conn, snapshotSr, null, null);
|
task = snapshotVdi.copyAsync(conn, snapshotSr, null, null);
|
||||||
// poll every 1 seconds ,
|
// poll every 1 seconds ,
|
||||||
@ -649,7 +651,7 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
|
|||||||
throw new CloudRuntimeException("S3 upload of snapshots " + snapshotPaUuid + " failed");
|
throw new CloudRuntimeException("S3 upload of snapshots " + snapshotPaUuid + " failed");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
final String result = backupSnapshot(conn, primaryStorageSRUuid, localMountPoint, folder, secondaryStorageMountPath, snapshotUuid, prevBackupUuid, prevSnapshotUuid, isISCSI, wait);
|
final String result = backupSnapshot(conn, primaryStorageSRUuid, localMountPoint, folder, secondaryStorageMountPath, snapshotUuid, prevBackupUuid, prevSnapshotUuid, isISCSI, wait, nfsVersion);
|
||||||
final String[] tmp = result.split("#");
|
final String[] tmp = result.split("#");
|
||||||
snapshotBackupUuid = tmp[0];
|
snapshotBackupUuid = tmp[0];
|
||||||
physicalSize = Long.parseLong(tmp[1]);
|
physicalSize = Long.parseLong(tmp[1]);
|
||||||
@ -695,6 +697,7 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
|
|||||||
|
|
||||||
final String secondaryStoragePoolURL = destStore.getUrl();
|
final String secondaryStoragePoolURL = destStore.getUrl();
|
||||||
final String volumeUUID = volume.getPath();
|
final String volumeUUID = volume.getPath();
|
||||||
|
final String nfsVersion = destStore.getNfsVersion();
|
||||||
|
|
||||||
final String userSpecifiedName = template.getName();
|
final String userSpecifiedName = template.getName();
|
||||||
|
|
||||||
@ -708,7 +711,7 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
|
|||||||
final URI uri = new URI(secondaryStoragePoolURL);
|
final URI uri = new URI(secondaryStoragePoolURL);
|
||||||
secondaryStorageMountPath = uri.getHost() + ":" + uri.getPath();
|
secondaryStorageMountPath = uri.getHost() + ":" + uri.getPath();
|
||||||
installPath = template.getPath();
|
installPath = template.getPath();
|
||||||
if (!hypervisorResource.createSecondaryStorageFolder(conn, secondaryStorageMountPath, installPath)) {
|
if (!hypervisorResource.createSecondaryStorageFolder(conn, secondaryStorageMountPath, installPath, nfsVersion)) {
|
||||||
details = " Filed to create folder " + installPath + " in secondary storage";
|
details = " Filed to create folder " + installPath + " in secondary storage";
|
||||||
s_logger.warn(details);
|
s_logger.warn(details);
|
||||||
return new CopyCmdAnswer(details);
|
return new CopyCmdAnswer(details);
|
||||||
@ -716,7 +719,7 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
|
|||||||
|
|
||||||
final VDI vol = getVDIbyUuid(conn, volumeUUID);
|
final VDI vol = getVDIbyUuid(conn, volumeUUID);
|
||||||
// create template SR
|
// create template SR
|
||||||
tmpltSR = createFileSr(conn, uri.getHost() + ":" + uri.getPath(), installPath);
|
tmpltSR = createFileSr(conn, uri.getHost() + ":" + uri.getPath(), installPath, nfsVersion);
|
||||||
|
|
||||||
// copy volume to template SR
|
// copy volume to template SR
|
||||||
task = vol.copyAsync(conn, tmpltSR, null, null);
|
task = vol.copyAsync(conn, tmpltSR, null, null);
|
||||||
@ -736,7 +739,7 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
|
|||||||
final long physicalSize = tmpltVDI.getPhysicalUtilisation(conn);
|
final long physicalSize = tmpltVDI.getPhysicalUtilisation(conn);
|
||||||
// create the template.properties file
|
// create the template.properties file
|
||||||
final String templatePath = secondaryStorageMountPath + "/" + installPath;
|
final String templatePath = secondaryStorageMountPath + "/" + installPath;
|
||||||
result = hypervisorResource.postCreatePrivateTemplate(conn, templatePath, tmpltFilename, tmpltUUID, userSpecifiedName, null, physicalSize, virtualSize, template.getId());
|
result = hypervisorResource.postCreatePrivateTemplate(conn, templatePath, tmpltFilename, tmpltUUID, userSpecifiedName, null, physicalSize, virtualSize, template.getId(), nfsVersion);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
throw new CloudRuntimeException("Could not create the template.properties file on secondary storage dir");
|
throw new CloudRuntimeException("Could not create the template.properties file on secondary storage dir");
|
||||||
}
|
}
|
||||||
@ -756,7 +759,7 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
|
|||||||
hypervisorResource.removeSR(conn, tmpltSR);
|
hypervisorResource.removeSR(conn, tmpltSR);
|
||||||
}
|
}
|
||||||
if (secondaryStorageMountPath != null) {
|
if (secondaryStorageMountPath != null) {
|
||||||
hypervisorResource.deleteSecondaryStorageFolder(conn, secondaryStorageMountPath, installPath);
|
hypervisorResource.deleteSecondaryStorageFolder(conn, secondaryStorageMountPath, installPath, nfsVersion);
|
||||||
}
|
}
|
||||||
details = "Creating template from volume " + volumeUUID + " failed due to " + e.toString();
|
details = "Creating template from volume " + volumeUUID + " failed due to " + e.toString();
|
||||||
s_logger.error(details, e);
|
s_logger.error(details, e);
|
||||||
@ -805,6 +808,7 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final NfsTO nfsImageStore = (NfsTO)imageStore;
|
final NfsTO nfsImageStore = (NfsTO)imageStore;
|
||||||
|
final String nfsVersion = nfsImageStore.getNfsVersion();
|
||||||
final String primaryStorageNameLabel = pool.getUuid();
|
final String primaryStorageNameLabel = pool.getUuid();
|
||||||
final String secondaryStorageUrl = nfsImageStore.getUrl();
|
final String secondaryStorageUrl = nfsImageStore.getUrl();
|
||||||
final int wait = cmd.getWait();
|
final int wait = cmd.getWait();
|
||||||
@ -851,7 +855,7 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
|
|||||||
final String snapshotUuid = getSnapshotUuid(snapshotInstallPath);
|
final String snapshotUuid = getSnapshotUuid(snapshotInstallPath);
|
||||||
|
|
||||||
final URI uri = new URI(secondaryStorageUrl);
|
final URI uri = new URI(secondaryStorageUrl);
|
||||||
srcSr = createFileSr(conn, uri.getHost() + ":" + uri.getPath(), snapshotDirectory);
|
srcSr = createFileSr(conn, uri.getHost() + ":" + uri.getPath(), snapshotDirectory, nfsVersion);
|
||||||
|
|
||||||
final String[] parents = snapshot.getParents();
|
final String[] parents = snapshot.getParents();
|
||||||
final List<VDI> snapshotChains = new ArrayList<VDI>();
|
final List<VDI> snapshotChains = new ArrayList<VDI>();
|
||||||
@ -940,14 +944,15 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
|
|||||||
Task task = null;
|
Task task = null;
|
||||||
try {
|
try {
|
||||||
final NfsTO nfsStore = (NfsTO)destStore;
|
final NfsTO nfsStore = (NfsTO)destStore;
|
||||||
|
final String nfsVersion = nfsStore.getNfsVersion();
|
||||||
final URI uri = new URI(nfsStore.getUrl());
|
final URI uri = new URI(nfsStore.getUrl());
|
||||||
// Create the volume folder
|
// Create the volume folder
|
||||||
if (!hypervisorResource.createSecondaryStorageFolder(conn, uri.getHost() + ":" + uri.getPath(), destVolume.getPath())) {
|
if (!hypervisorResource.createSecondaryStorageFolder(conn, uri.getHost() + ":" + uri.getPath(), destVolume.getPath(), nfsVersion)) {
|
||||||
throw new InternalErrorException("Failed to create the volume folder.");
|
throw new InternalErrorException("Failed to create the volume folder.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a SR for the volume UUID folder
|
// Create a SR for the volume UUID folder
|
||||||
secondaryStorage = createFileSr(conn, uri.getHost() + ":" + uri.getPath(), destVolume.getPath());
|
secondaryStorage = createFileSr(conn, uri.getHost() + ":" + uri.getPath(), destVolume.getPath(), nfsVersion);
|
||||||
// Look up the volume on the source primary storage pool
|
// Look up the volume on the source primary storage pool
|
||||||
final VDI srcVdi = getVDIbyUuid(conn, srcVolume.getPath());
|
final VDI srcVdi = getVDIbyUuid(conn, srcVolume.getPath());
|
||||||
// Copy the volume to secondary storage
|
// Copy the volume to secondary storage
|
||||||
@ -992,6 +997,7 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
|
|||||||
|
|
||||||
if (srcStore instanceof NfsTO) {
|
if (srcStore instanceof NfsTO) {
|
||||||
final NfsTO nfsStore = (NfsTO)srcStore;
|
final NfsTO nfsStore = (NfsTO)srcStore;
|
||||||
|
final String nfsVersion = nfsStore.getNfsVersion();
|
||||||
final String volumePath = srcVolume.getPath();
|
final String volumePath = srcVolume.getPath();
|
||||||
int index = volumePath.lastIndexOf("/");
|
int index = volumePath.lastIndexOf("/");
|
||||||
final String volumeDirectory = volumePath.substring(0, index);
|
final String volumeDirectory = volumePath.substring(0, index);
|
||||||
@ -1006,7 +1012,7 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
|
|||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
return new CopyCmdAnswer(e.toString());
|
return new CopyCmdAnswer(e.toString());
|
||||||
}
|
}
|
||||||
final SR srcSr = createFileSr(conn, uri.getHost() + ":" + uri.getPath(), volumeDirectory);
|
final SR srcSr = createFileSr(conn, uri.getHost() + ":" + uri.getPath(), volumeDirectory, nfsVersion);
|
||||||
Task task = null;
|
Task task = null;
|
||||||
try {
|
try {
|
||||||
final SR primaryStoragePool = hypervisorResource.getStorageRepository(conn,
|
final SR primaryStoragePool = hypervisorResource.getStorageRepository(conn,
|
||||||
@ -1089,12 +1095,14 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
|
|||||||
boolean result = false;
|
boolean result = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
srcSr = createFileSr(conn, srcUri.getHost() + ":" + srcUri.getPath(), srcDir);
|
String srcNfsVersion = srcStore.getNfsVersion();
|
||||||
|
srcSr = createFileSr(conn, srcUri.getHost() + ":" + srcUri.getPath(), srcDir, srcNfsVersion);
|
||||||
|
|
||||||
final String destNfsPath = destUri.getHost() + ":" + destUri.getPath();
|
final String destNfsPath = destUri.getHost() + ":" + destUri.getPath();
|
||||||
final String localDir = BASE_MOUNT_POINT_ON_REMOTE + UUID.nameUUIDFromBytes(destNfsPath.getBytes());
|
final String localDir = BASE_MOUNT_POINT_ON_REMOTE + UUID.nameUUIDFromBytes(destNfsPath.getBytes());
|
||||||
|
|
||||||
mountNfs(conn, destUri.getHost() + ":" + destUri.getPath(), localDir);
|
String destNfsVersion = destStore.getNfsVersion();
|
||||||
|
mountNfs(conn, destUri.getHost() + ":" + destUri.getPath(), localDir, destNfsVersion);
|
||||||
makeDirectory(conn, localDir + "/" + destDir);
|
makeDirectory(conn, localDir + "/" + destDir);
|
||||||
|
|
||||||
destSr = createFileSR(conn, localDir + "/" + destDir);
|
destSr = createFileSR(conn, localDir + "/" + destDir);
|
||||||
@ -1148,7 +1156,7 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
|
|||||||
|
|
||||||
templatePath = templatePath.replaceAll("//", "/");
|
templatePath = templatePath.replaceAll("//", "/");
|
||||||
|
|
||||||
result = hypervisorResource.postCreatePrivateTemplate(conn, templatePath, templateFilename, templateUuid, nameLabel, null, physicalSize, virtualSize, destObj.getId());
|
result = hypervisorResource.postCreatePrivateTemplate(conn, templatePath, templateFilename, templateUuid, nameLabel, null, physicalSize, virtualSize, destObj.getId(), destNfsVersion);
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
throw new CloudRuntimeException("Could not create the template.properties file on secondary storage dir");
|
throw new CloudRuntimeException("Could not create the template.properties file on secondary storage dir");
|
||||||
@ -1236,7 +1244,8 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
|
|||||||
final String destNfsPath = destUri.getHost() + ":" + destUri.getPath();
|
final String destNfsPath = destUri.getHost() + ":" + destUri.getPath();
|
||||||
final String localDir = BASE_MOUNT_POINT_ON_REMOTE + UUID.nameUUIDFromBytes(destNfsPath.getBytes());
|
final String localDir = BASE_MOUNT_POINT_ON_REMOTE + UUID.nameUUIDFromBytes(destNfsPath.getBytes());
|
||||||
|
|
||||||
mountNfs(conn, destNfsPath, localDir);
|
String nfsVersion = destStore.getNfsVersion();
|
||||||
|
mountNfs(conn, destNfsPath, localDir, nfsVersion);
|
||||||
makeDirectory(conn, localDir + "/" + destDir);
|
makeDirectory(conn, localDir + "/" + destDir);
|
||||||
|
|
||||||
destSr = createFileSR(conn, localDir + "/" + destDir);
|
destSr = createFileSR(conn, localDir + "/" + destDir);
|
||||||
@ -1263,7 +1272,7 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
|
|||||||
|
|
||||||
templatePath = templatePath.replaceAll("//", "/");
|
templatePath = templatePath.replaceAll("//", "/");
|
||||||
|
|
||||||
result = hypervisorResource.postCreatePrivateTemplate(conn, templatePath, templateFilename, templateUuid, nameLabel, null, physicalSize, virtualSize, templateObjTO.getId());
|
result = hypervisorResource.postCreatePrivateTemplate(conn, templatePath, templateFilename, templateUuid, nameLabel, null, physicalSize, virtualSize, templateObjTO.getId(), nfsVersion);
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
throw new CloudRuntimeException("Could not create the template.properties file on secondary storage dir");
|
throw new CloudRuntimeException("Could not create the template.properties file on secondary storage dir");
|
||||||
|
|||||||
@ -23,6 +23,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.cloud.utils.StringUtils;
|
||||||
import org.apache.xmlrpc.XmlRpcException;
|
import org.apache.xmlrpc.XmlRpcException;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@ -51,6 +52,8 @@ import com.xensource.xenapi.PBD;
|
|||||||
import com.xensource.xenapi.SR;
|
import com.xensource.xenapi.SR;
|
||||||
import com.xensource.xenapi.Types.XenAPIException;
|
import com.xensource.xenapi.Types.XenAPIException;
|
||||||
|
|
||||||
|
import static com.cloud.hypervisor.xenserver.resource.CitrixResourceBase.PLATFORM_CORES_PER_SOCKET_KEY;
|
||||||
|
|
||||||
@RunWith(PowerMockRunner.class)
|
@RunWith(PowerMockRunner.class)
|
||||||
@PrepareForTest({Host.class, Script.class, SR.class})
|
@PrepareForTest({Host.class, Script.class, SR.class})
|
||||||
public class CitrixResourceBaseTest {
|
public class CitrixResourceBaseTest {
|
||||||
@ -72,6 +75,8 @@ public class CitrixResourceBaseTest {
|
|||||||
|
|
||||||
private String hostUuidMock = "hostUuidMock";
|
private String hostUuidMock = "hostUuidMock";
|
||||||
|
|
||||||
|
private static final String platformString = "device-model:qemu-upstream-compat;vga:std;videoram:8;apic:true;viridian:false;timeoffset:0;pae:true;acpi:1;hpet:true;secureboot:false;nx:true";
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void beforeTest() throws XenAPIException, XmlRpcException {
|
public void beforeTest() throws XenAPIException, XmlRpcException {
|
||||||
citrixResourceBase._host.setUuid(hostUuidMock);
|
citrixResourceBase._host.setUuid(hostUuidMock);
|
||||||
@ -369,4 +374,32 @@ public class CitrixResourceBaseTest {
|
|||||||
|
|
||||||
Assert.assertEquals(1, startUpCommandsForLocalStorage.size());
|
Assert.assertEquals(1, startUpCommandsForLocalStorage.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void syncPlatformAndCoresPerSocketSettingsEmptyCoresPerSocket() {
|
||||||
|
String coresPerSocket = null;
|
||||||
|
Map<String, String> platform = Mockito.mock(Map.class);
|
||||||
|
citrixResourceBase.syncPlatformAndCoresPerSocketSettings(coresPerSocket, platform);
|
||||||
|
Mockito.verify(platform, Mockito.never()).put(Mockito.any(), Mockito.any());
|
||||||
|
Mockito.verify(platform, Mockito.never()).remove(Mockito.any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void syncPlatformAndCoresPerSocketSettingsEmptyCoresPerSocketOnPlatform() {
|
||||||
|
String coresPerSocket = "2";
|
||||||
|
Map<String, String> platform = StringUtils.stringToMap(platformString);
|
||||||
|
citrixResourceBase.syncPlatformAndCoresPerSocketSettings(coresPerSocket, platform);
|
||||||
|
Assert.assertTrue(platform.containsKey(PLATFORM_CORES_PER_SOCKET_KEY));
|
||||||
|
Assert.assertEquals(coresPerSocket, platform.get(PLATFORM_CORES_PER_SOCKET_KEY));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void syncPlatformAndCoresPerSocketSettingsUpdateCoresPerSocketOnPlatform() {
|
||||||
|
String coresPerSocket = "2";
|
||||||
|
String platformStr = platformString + "," + PLATFORM_CORES_PER_SOCKET_KEY + ":3";
|
||||||
|
Map<String, String> platform = StringUtils.stringToMap(platformStr);
|
||||||
|
citrixResourceBase.syncPlatformAndCoresPerSocketSettings(coresPerSocket, platform);
|
||||||
|
Assert.assertTrue(platform.containsKey(PLATFORM_CORES_PER_SOCKET_KEY));
|
||||||
|
Assert.assertEquals(coresPerSocket, platform.get(PLATFORM_CORES_PER_SOCKET_KEY));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -238,6 +238,8 @@ def umount(localDir):
|
|||||||
def mountNfsSecondaryStorage(session, args):
|
def mountNfsSecondaryStorage(session, args):
|
||||||
remoteDir = args['remoteDir']
|
remoteDir = args['remoteDir']
|
||||||
localDir = args['localDir']
|
localDir = args['localDir']
|
||||||
|
nfsVersion = args['nfsVersion']
|
||||||
|
logging.debug("mountNfsSecondaryStorage with params: " + str(args))
|
||||||
mounted = False
|
mounted = False
|
||||||
f = open("/proc/mounts", 'r')
|
f = open("/proc/mounts", 'r')
|
||||||
for line in f:
|
for line in f:
|
||||||
@ -250,6 +252,8 @@ def mountNfsSecondaryStorage(session, args):
|
|||||||
|
|
||||||
makedirs(localDir)
|
makedirs(localDir)
|
||||||
options = "soft,tcp,timeo=133,retrans=1"
|
options = "soft,tcp,timeo=133,retrans=1"
|
||||||
|
if nfsVersion:
|
||||||
|
options += ",vers=" + nfsVersion
|
||||||
try:
|
try:
|
||||||
cmd = ['mount', '-o', options, remoteDir, localDir]
|
cmd = ['mount', '-o', options, remoteDir, localDir]
|
||||||
txt = util.pread2(cmd)
|
txt = util.pread2(cmd)
|
||||||
|
|||||||
@ -68,7 +68,8 @@ def create_secondary_storage_folder(session, args):
|
|||||||
# Mount the remote resource folder locally
|
# Mount the remote resource folder locally
|
||||||
remote_mount_path = args["remoteMountPath"]
|
remote_mount_path = args["remoteMountPath"]
|
||||||
local_mount_path = os.path.join(CLOUD_DIR, util.gen_uuid())
|
local_mount_path = os.path.join(CLOUD_DIR, util.gen_uuid())
|
||||||
mount(remote_mount_path, local_mount_path)
|
nfsVersion = args["nfsVersion"]
|
||||||
|
mount(remote_mount_path, local_mount_path, nfsVersion)
|
||||||
|
|
||||||
# Create the new folder
|
# Create the new folder
|
||||||
new_folder = local_mount_path + "/" + args["newFolder"]
|
new_folder = local_mount_path + "/" + args["newFolder"]
|
||||||
@ -104,7 +105,8 @@ def delete_secondary_storage_folder(session, args):
|
|||||||
# Mount the remote resource folder locally
|
# Mount the remote resource folder locally
|
||||||
remote_mount_path = args["remoteMountPath"]
|
remote_mount_path = args["remoteMountPath"]
|
||||||
local_mount_path = os.path.join(CLOUD_DIR, util.gen_uuid())
|
local_mount_path = os.path.join(CLOUD_DIR, util.gen_uuid())
|
||||||
mount(remote_mount_path, local_mount_path)
|
nfsVersion = args["nfsVersion"]
|
||||||
|
mount(remote_mount_path, local_mount_path, nfsVersion)
|
||||||
|
|
||||||
# Delete the specified folder
|
# Delete the specified folder
|
||||||
folder = local_mount_path + "/" + args["folder"]
|
folder = local_mount_path + "/" + args["folder"]
|
||||||
@ -136,7 +138,8 @@ def post_create_private_template(session, args):
|
|||||||
# get local template folder
|
# get local template folder
|
||||||
templatePath = args["templatePath"]
|
templatePath = args["templatePath"]
|
||||||
local_mount_path = os.path.join(CLOUD_DIR, util.gen_uuid())
|
local_mount_path = os.path.join(CLOUD_DIR, util.gen_uuid())
|
||||||
mount(templatePath, local_mount_path)
|
nfsVersion = args["nfsVersion"]
|
||||||
|
mount(templatePath, local_mount_path, nfsVersion)
|
||||||
# Retrieve args
|
# Retrieve args
|
||||||
filename = args["templateFilename"]
|
filename = args["templateFilename"]
|
||||||
name = args["templateName"]
|
name = args["templateName"]
|
||||||
@ -307,9 +310,11 @@ def makedirs(path):
|
|||||||
raise xs_errors.XenError(errMsg)
|
raise xs_errors.XenError(errMsg)
|
||||||
return
|
return
|
||||||
|
|
||||||
def mount(remoteDir, localDir):
|
def mount(remoteDir, localDir, nfsVersion=None):
|
||||||
makedirs(localDir)
|
makedirs(localDir)
|
||||||
options = "soft,tcp,timeo=133,retrans=1"
|
options = "soft,tcp,timeo=133,retrans=1"
|
||||||
|
if nfsVersion:
|
||||||
|
options += ",vers=" + nfsVersion
|
||||||
try:
|
try:
|
||||||
cmd = ['mount', '-o', options, remoteDir, localDir]
|
cmd = ['mount', '-o', options, remoteDir, localDir]
|
||||||
txt = util.pread2(cmd)
|
txt = util.pread2(cmd)
|
||||||
|
|||||||
@ -19,11 +19,8 @@ package com.cloud.api.query.dao;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.cloud.api.ApiDBUtils;
|
import javax.inject.Inject;
|
||||||
import com.cloud.dc.VsphereStoragePolicyVO;
|
|
||||||
import com.cloud.dc.dao.VsphereStoragePolicyDao;
|
|
||||||
import com.cloud.server.ResourceTag;
|
|
||||||
import com.cloud.user.AccountManager;
|
|
||||||
import org.apache.cloudstack.annotation.AnnotationService;
|
import org.apache.cloudstack.annotation.AnnotationService;
|
||||||
import org.apache.cloudstack.annotation.dao.AnnotationDao;
|
import org.apache.cloudstack.annotation.dao.AnnotationDao;
|
||||||
import org.apache.cloudstack.api.ApiConstants;
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
@ -32,16 +29,19 @@ import org.apache.cloudstack.context.CallContext;
|
|||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import com.cloud.api.ApiDBUtils;
|
||||||
import com.cloud.api.query.vo.DiskOfferingJoinVO;
|
import com.cloud.api.query.vo.DiskOfferingJoinVO;
|
||||||
|
import com.cloud.dc.VsphereStoragePolicyVO;
|
||||||
|
import com.cloud.dc.dao.VsphereStoragePolicyDao;
|
||||||
import com.cloud.offering.DiskOffering;
|
import com.cloud.offering.DiskOffering;
|
||||||
import com.cloud.offering.ServiceOffering;
|
import com.cloud.offering.ServiceOffering;
|
||||||
|
import com.cloud.server.ResourceTag;
|
||||||
|
import com.cloud.user.AccountManager;
|
||||||
import com.cloud.utils.db.Attribute;
|
import com.cloud.utils.db.Attribute;
|
||||||
import com.cloud.utils.db.GenericDaoBase;
|
import com.cloud.utils.db.GenericDaoBase;
|
||||||
import com.cloud.utils.db.SearchBuilder;
|
import com.cloud.utils.db.SearchBuilder;
|
||||||
import com.cloud.utils.db.SearchCriteria;
|
import com.cloud.utils.db.SearchCriteria;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class DiskOfferingJoinDaoImpl extends GenericDaoBase<DiskOfferingJoinVO, Long> implements DiskOfferingJoinDao {
|
public class DiskOfferingJoinDaoImpl extends GenericDaoBase<DiskOfferingJoinVO, Long> implements DiskOfferingJoinDao {
|
||||||
public static final Logger s_logger = Logger.getLogger(DiskOfferingJoinDaoImpl.class);
|
public static final Logger s_logger = Logger.getLogger(DiskOfferingJoinDaoImpl.class);
|
||||||
|
|||||||
@ -1997,12 +1997,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
|
|||||||
Account caller = CallContext.current().getCallingAccount();
|
Account caller = CallContext.current().getCallingAccount();
|
||||||
|
|
||||||
// Verify network id
|
// Verify network id
|
||||||
NetworkVO network = _networksDao.findById(networkId);
|
NetworkVO network = getNetworkVO(networkId, "Unable to find a network with the specified ID.");
|
||||||
if (network == null) {
|
|
||||||
// see NetworkVO.java
|
|
||||||
|
|
||||||
throwInvalidIdException("unable to find network with specified id", String.valueOf(networkId), "networkId");
|
|
||||||
}
|
|
||||||
|
|
||||||
// don't allow to delete system network
|
// don't allow to delete system network
|
||||||
if (isNetworkSystem(network)) {
|
if (isNetworkSystem(network)) {
|
||||||
@ -2032,10 +2027,20 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
|
|||||||
@Override
|
@Override
|
||||||
@ActionEvent(eventType = EventTypes.EVENT_NETWORK_RESTART, eventDescription = "restarting network", async = true)
|
@ActionEvent(eventType = EventTypes.EVENT_NETWORK_RESTART, eventDescription = "restarting network", async = true)
|
||||||
public boolean restartNetwork(Long networkId, boolean cleanup, boolean makeRedundant, User user) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException {
|
public boolean restartNetwork(Long networkId, boolean cleanup, boolean makeRedundant, User user) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException {
|
||||||
|
NetworkVO network = getNetworkVO(networkId, "Network with specified id doesn't exist");
|
||||||
|
return restartNetwork(network, cleanup, makeRedundant, user);
|
||||||
|
}
|
||||||
|
|
||||||
|
private NetworkVO getNetworkVO(Long networkId, String errMsgFormat) {
|
||||||
NetworkVO network = _networksDao.findById(networkId);
|
NetworkVO network = _networksDao.findById(networkId);
|
||||||
if (network == null) {
|
if (network == null) {
|
||||||
throwInvalidIdException("Network with specified id doesn't exist", networkId.toString(), "networkId");
|
throwInvalidIdException(errMsgFormat, networkId.toString(), "networkId");
|
||||||
}
|
}
|
||||||
|
return network;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ActionEvent(eventType = EventTypes.EVENT_NETWORK_RESTART, eventDescription = "restarting network", async = true)
|
||||||
|
public boolean restartNetwork(NetworkVO network, boolean cleanup, boolean makeRedundant, User user) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException {
|
||||||
|
|
||||||
// Don't allow to restart network if it's not in Implemented/Setup state
|
// Don't allow to restart network if it's not in Implemented/Setup state
|
||||||
if (!(network.getState() == Network.State.Implemented || network.getState() == Network.State.Setup)) {
|
if (!(network.getState() == Network.State.Implemented || network.getState() == Network.State.Setup)) {
|
||||||
@ -2061,11 +2066,12 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
|
|||||||
cleanup = true;
|
cleanup = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean success = _networkMgr.restartNetwork(networkId, callerAccount, user, cleanup);
|
long id = network.getId();
|
||||||
|
boolean success = _networkMgr.restartNetwork(id, callerAccount, user, cleanup);
|
||||||
if (success) {
|
if (success) {
|
||||||
s_logger.debug("Network id=" + networkId + " is restarted successfully.");
|
s_logger.debug(String.format("Network id=%d is restarted successfully.",id));
|
||||||
} else {
|
} else {
|
||||||
s_logger.warn("Network id=" + networkId + " failed to restart.");
|
s_logger.warn(String.format("Network id=%d failed to restart.",id));
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
@ -2075,11 +2081,14 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
|
|||||||
@ActionEvent(eventType = EventTypes.EVENT_NETWORK_RESTART, eventDescription = "restarting network", async = true)
|
@ActionEvent(eventType = EventTypes.EVENT_NETWORK_RESTART, eventDescription = "restarting network", async = true)
|
||||||
public boolean restartNetwork(RestartNetworkCmd cmd) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException {
|
public boolean restartNetwork(RestartNetworkCmd cmd) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException {
|
||||||
// This method restarts all network elements belonging to the network and re-applies all the rules
|
// This method restarts all network elements belonging to the network and re-applies all the rules
|
||||||
Long networkId = cmd.getNetworkId();
|
NetworkVO network = getNetworkVO(cmd.getNetworkId(), "Network [%s] to restart was not found.");
|
||||||
boolean cleanup = cmd.getCleanup();
|
boolean cleanup = cmd.getCleanup();
|
||||||
|
if (network.getVpcId() != null && cleanup) {
|
||||||
|
throwInvalidIdException("Cannot restart a VPC tier with cleanup, please restart the whole VPC.", network.getUuid(), "network tier");
|
||||||
|
}
|
||||||
boolean makeRedundant = cmd.getMakeRedundant();
|
boolean makeRedundant = cmd.getMakeRedundant();
|
||||||
User callerUser = _accountMgr.getActiveUser(CallContext.current().getCallingUserId());
|
User callerUser = _accountMgr.getActiveUser(CallContext.current().getCallingUserId());
|
||||||
return restartNetwork(networkId, cleanup, makeRedundant, callerUser);
|
return restartNetwork(network, cleanup, makeRedundant, callerUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -2216,11 +2225,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
|
|||||||
boolean restartNetwork = false;
|
boolean restartNetwork = false;
|
||||||
|
|
||||||
// verify input parameters
|
// verify input parameters
|
||||||
final NetworkVO network = _networksDao.findById(networkId);
|
final NetworkVO network = getNetworkVO(networkId, "Specified network id doesn't exist in the system");
|
||||||
if (network == null) {
|
|
||||||
// see NetworkVO.java
|
|
||||||
throwInvalidIdException("Specified network id doesn't exist in the system", String.valueOf(networkId), "networkId");
|
|
||||||
}
|
|
||||||
|
|
||||||
//perform below validation if the network is vpc network
|
//perform below validation if the network is vpc network
|
||||||
if (network.getVpcId() != null && networkOfferingId != null) {
|
if (network.getVpcId() != null && networkOfferingId != null) {
|
||||||
|
|||||||
@ -133,6 +133,7 @@ import com.cloud.host.dao.HostDao;
|
|||||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||||
import com.cloud.hypervisor.HypervisorCapabilitiesVO;
|
import com.cloud.hypervisor.HypervisorCapabilitiesVO;
|
||||||
import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao;
|
import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao;
|
||||||
|
import com.cloud.offering.DiskOffering;
|
||||||
import com.cloud.org.Grouping;
|
import com.cloud.org.Grouping;
|
||||||
import com.cloud.resource.ResourceState;
|
import com.cloud.resource.ResourceState;
|
||||||
import com.cloud.serializer.GsonHelper;
|
import com.cloud.serializer.GsonHelper;
|
||||||
@ -330,6 +331,8 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||||||
private static final Set<Volume.State> STATES_VOLUME_CANNOT_BE_DESTROYED = new HashSet<>(Arrays.asList(Volume.State.Destroy, Volume.State.Expunging, Volume.State.Expunged, Volume.State.Allocated));
|
private static final Set<Volume.State> STATES_VOLUME_CANNOT_BE_DESTROYED = new HashSet<>(Arrays.asList(Volume.State.Destroy, Volume.State.Expunging, Volume.State.Expunged, Volume.State.Allocated));
|
||||||
private static final long GiB_TO_BYTES = 1024 * 1024 * 1024;
|
private static final long GiB_TO_BYTES = 1024 * 1024 * 1024;
|
||||||
|
|
||||||
|
private static final String CUSTOM_DISK_OFFERING_UNIQUE_NAME = "Cloud.com-Custom";
|
||||||
|
|
||||||
protected VolumeApiServiceImpl() {
|
protected VolumeApiServiceImpl() {
|
||||||
_volStateMachine = Volume.State.getStateMachine();
|
_volStateMachine = Volume.State.getStateMachine();
|
||||||
_gson = GsonHelper.getGsonLogger();
|
_gson = GsonHelper.getGsonLogger();
|
||||||
@ -493,7 +496,6 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||||||
if (!diskOffering.isCustomized()) {
|
if (!diskOffering.isCustomized()) {
|
||||||
throw new InvalidParameterValueException("Please specify a custom sized disk offering.");
|
throw new InvalidParameterValueException("Please specify a custom sized disk offering.");
|
||||||
}
|
}
|
||||||
|
|
||||||
_configMgr.checkDiskOfferingAccess(volumeOwner, diskOffering, zone);
|
_configMgr.checkDiskOfferingAccess(volumeOwner, diskOffering, zone);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -504,12 +506,41 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||||||
return UUID.randomUUID().toString();
|
return UUID.randomUUID().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Long getDefaultCustomOfferingId(Account owner, DataCenter zone) {
|
||||||
|
DiskOfferingVO diskOfferingVO = _diskOfferingDao.findByUniqueName(CUSTOM_DISK_OFFERING_UNIQUE_NAME);
|
||||||
|
if (diskOfferingVO == null || !DiskOffering.State.Active.equals(diskOfferingVO.getState())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
_configMgr.checkDiskOfferingAccess(owner, diskOfferingVO, zone);
|
||||||
|
return diskOfferingVO.getId();
|
||||||
|
} catch (PermissionDeniedException ignored) {
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Long getCustomDiskOfferingIdForVolumeUpload(Account owner, DataCenter zone) {
|
||||||
|
Long offeringId = getDefaultCustomOfferingId(owner, zone);
|
||||||
|
if (offeringId != null) {
|
||||||
|
return offeringId;
|
||||||
|
}
|
||||||
|
List<DiskOfferingVO> offerings = _diskOfferingDao.findCustomDiskOfferings();
|
||||||
|
for (DiskOfferingVO offering : offerings) {
|
||||||
|
try {
|
||||||
|
_configMgr.checkDiskOfferingAccess(owner, offering, zone);
|
||||||
|
return offering.getId();
|
||||||
|
} catch (PermissionDeniedException ignored) {}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@DB
|
@DB
|
||||||
protected VolumeVO persistVolume(final Account owner, final Long zoneId, final String volumeName, final String url, final String format, final Long diskOfferingId, final Volume.State state) {
|
protected VolumeVO persistVolume(final Account owner, final Long zoneId, final String volumeName, final String url, final String format, final Long diskOfferingId, final Volume.State state) {
|
||||||
return Transaction.execute(new TransactionCallback<VolumeVO>() {
|
return Transaction.execute(new TransactionCallbackWithException<VolumeVO, CloudRuntimeException>() {
|
||||||
@Override
|
@Override
|
||||||
public VolumeVO doInTransaction(TransactionStatus status) {
|
public VolumeVO doInTransaction(TransactionStatus status) {
|
||||||
VolumeVO volume = new VolumeVO(volumeName, zoneId, -1, -1, -1, new Long(-1), null, null, Storage.ProvisioningType.THIN, 0, Volume.Type.DATADISK);
|
VolumeVO volume = new VolumeVO(volumeName, zoneId, -1, -1, -1, new Long(-1), null, null, Storage.ProvisioningType.THIN, 0, Volume.Type.DATADISK);
|
||||||
|
DataCenter zone = _dcDao.findById(zoneId);
|
||||||
volume.setPoolId(null);
|
volume.setPoolId(null);
|
||||||
volume.setDataCenterId(zoneId);
|
volume.setDataCenterId(zoneId);
|
||||||
volume.setPodId(null);
|
volume.setPodId(null);
|
||||||
@ -519,23 +550,22 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||||||
volume.setAccountId((owner == null) ? Account.ACCOUNT_ID_SYSTEM : owner.getAccountId());
|
volume.setAccountId((owner == null) ? Account.ACCOUNT_ID_SYSTEM : owner.getAccountId());
|
||||||
volume.setDomainId((owner == null) ? Domain.ROOT_DOMAIN : owner.getDomainId());
|
volume.setDomainId((owner == null) ? Domain.ROOT_DOMAIN : owner.getDomainId());
|
||||||
|
|
||||||
if (diskOfferingId == null) {
|
Long volumeDiskOfferingId = diskOfferingId;
|
||||||
DiskOfferingVO diskOfferingVO = _diskOfferingDao.findByUniqueName("Cloud.com-Custom");
|
if (volumeDiskOfferingId == null) {
|
||||||
if (diskOfferingVO != null) {
|
volumeDiskOfferingId = getCustomDiskOfferingIdForVolumeUpload(owner, zone);
|
||||||
long defaultDiskOfferingId = diskOfferingVO.getId();
|
if (volumeDiskOfferingId == null) {
|
||||||
volume.setDiskOfferingId(defaultDiskOfferingId);
|
throw new CloudRuntimeException(String.format("Unable to find custom disk offering in zone: %s for volume upload", zone.getUuid()));
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
volume.setDiskOfferingId(diskOfferingId);
|
|
||||||
|
|
||||||
DiskOfferingVO diskOfferingVO = _diskOfferingDao.findById(diskOfferingId);
|
volume.setDiskOfferingId(volumeDiskOfferingId);
|
||||||
|
DiskOfferingVO diskOfferingVO = _diskOfferingDao.findById(volumeDiskOfferingId);
|
||||||
|
|
||||||
Boolean isCustomizedIops = diskOfferingVO != null && diskOfferingVO.isCustomizedIops() != null ? diskOfferingVO.isCustomizedIops() : false;
|
Boolean isCustomizedIops = diskOfferingVO != null && diskOfferingVO.isCustomizedIops() != null ? diskOfferingVO.isCustomizedIops() : false;
|
||||||
|
|
||||||
if (isCustomizedIops == null || !isCustomizedIops) {
|
if (isCustomizedIops == null || !isCustomizedIops) {
|
||||||
volume.setMinIops(diskOfferingVO.getMinIops());
|
volume.setMinIops(diskOfferingVO.getMinIops());
|
||||||
volume.setMaxIops(diskOfferingVO.getMaxIops());
|
volume.setMaxIops(diskOfferingVO.getMaxIops());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// volume.setSize(size);
|
// volume.setSize(size);
|
||||||
|
|||||||
@ -30,6 +30,7 @@ import java.util.regex.Pattern;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.naming.ConfigurationException;
|
import javax.naming.ConfigurationException;
|
||||||
|
|
||||||
|
import com.cloud.capacity.CapacityManager;
|
||||||
import org.apache.cloudstack.api.command.admin.diagnostics.GetDiagnosticsDataCmd;
|
import org.apache.cloudstack.api.command.admin.diagnostics.GetDiagnosticsDataCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.diagnostics.RunDiagnosticsCmd;
|
import org.apache.cloudstack.api.command.admin.diagnostics.RunDiagnosticsCmd;
|
||||||
import org.apache.cloudstack.diagnostics.fileprocessor.DiagnosticsFilesList;
|
import org.apache.cloudstack.diagnostics.fileprocessor.DiagnosticsFilesList;
|
||||||
@ -312,7 +313,8 @@ public class DiagnosticsServiceImpl extends ManagerBase implements PluggableServ
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Pair<Boolean, String> copyToSecondaryStorageNonVMware(final DataStore store, final String vmControlIp, String fileToCopy, Long vmHostId) {
|
private Pair<Boolean, String> copyToSecondaryStorageNonVMware(final DataStore store, final String vmControlIp, String fileToCopy, Long vmHostId) {
|
||||||
CopyToSecondaryStorageCommand toSecondaryStorageCommand = new CopyToSecondaryStorageCommand(store.getUri(), vmControlIp, fileToCopy);
|
String nfsVersion = CapacityManager.ImageStoreNFSVersion.valueIn(store.getId());
|
||||||
|
CopyToSecondaryStorageCommand toSecondaryStorageCommand = new CopyToSecondaryStorageCommand(store.getUri(), vmControlIp, fileToCopy, nfsVersion);
|
||||||
Answer copyToSecondaryAnswer = agentManager.easySend(vmHostId, toSecondaryStorageCommand);
|
Answer copyToSecondaryAnswer = agentManager.easySend(vmHostId, toSecondaryStorageCommand);
|
||||||
Pair<Boolean, String> copyAnswer;
|
Pair<Boolean, String> copyAnswer;
|
||||||
if (copyToSecondaryAnswer != null) {
|
if (copyToSecondaryAnswer != null) {
|
||||||
|
|||||||
@ -1036,12 +1036,10 @@ public class SecondaryStorageManagerImpl extends ManagerBase implements Secondar
|
|||||||
if (host != null) {
|
if (host != null) {
|
||||||
s_logger.debug(String.format("Removing host entry for secondary storage VM [%s].", vmId));
|
s_logger.debug(String.format("Removing host entry for secondary storage VM [%s].", vmId));
|
||||||
_hostDao.remove(host.getId());
|
_hostDao.remove(host.getId());
|
||||||
|
|
||||||
_tmplStoreDao.expireDnldUrlsForZone(host.getDataCenterId());
|
_tmplStoreDao.expireDnldUrlsForZone(host.getDataCenterId());
|
||||||
_volumeStoreDao.expireDnldUrlsForZone(host.getDataCenterId());
|
_volumeStoreDao.expireDnldUrlsForZone(host.getDataCenterId());
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
return true;
|
||||||
} catch (ResourceUnavailableException e) {
|
} catch (ResourceUnavailableException e) {
|
||||||
s_logger.error(String.format("Unable to expunge secondary storage [%s] due to [%s].", ssvm.toString(), e.getMessage()), e);
|
s_logger.error(String.format("Unable to expunge secondary storage [%s] due to [%s].", ssvm.toString(), e.getMessage()), e);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -173,13 +173,6 @@ export default {
|
|||||||
this.deployasistemplate = json.listtemplatesresponse.template[0].deployasis
|
this.deployasistemplate = json.listtemplatesresponse.template[0].deployasis
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
filterOrReadOnlyDetails () {
|
|
||||||
for (var i = 0; i < this.details.length; i++) {
|
|
||||||
if (!this.allowEditOfDetail(this.details[i].name)) {
|
|
||||||
this.details.splice(i, 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
allowEditOfDetail (name) {
|
allowEditOfDetail (name) {
|
||||||
if (this.resource.readonlydetails) {
|
if (this.resource.readonlydetails) {
|
||||||
if (this.resource.readonlydetails.split(',').map(item => item.trim()).includes(name)) {
|
if (this.resource.readonlydetails.split(',').map(item => item.trim()).includes(name)) {
|
||||||
@ -211,6 +204,27 @@ export default {
|
|||||||
(this.resource.domainid === this.$store.getters.userInfo.domainid && this.resource.account === this.$store.getters.userInfo.account) ||
|
(this.resource.domainid === this.$store.getters.userInfo.domainid && this.resource.account === this.$store.getters.userInfo.account) ||
|
||||||
this.resource.project && this.resource.projectid === this.$store.getters.project.id
|
this.resource.project && this.resource.projectid === this.$store.getters.project.id
|
||||||
},
|
},
|
||||||
|
getDetailsParam (details) {
|
||||||
|
var params = {}
|
||||||
|
var filteredDetails = details
|
||||||
|
if (this.resource.readonlydetails && filteredDetails) {
|
||||||
|
filteredDetails = []
|
||||||
|
var readOnlyDetailNames = this.resource.readonlydetails.split(',').map(item => item.trim())
|
||||||
|
for (var detail of this.details) {
|
||||||
|
if (!readOnlyDetailNames.includes(detail.name)) {
|
||||||
|
filteredDetails.push(detail)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (filteredDetails.length === 0) {
|
||||||
|
params.cleanupdetails = true
|
||||||
|
} else {
|
||||||
|
filteredDetails.forEach(function (item, index) {
|
||||||
|
params['details[0].' + item.name] = item.value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return params
|
||||||
|
},
|
||||||
runApi () {
|
runApi () {
|
||||||
var apiName = ''
|
var apiName = ''
|
||||||
if (this.resourceType === 'UserVm') {
|
if (this.resourceType === 'UserVm') {
|
||||||
@ -226,14 +240,8 @@ export default {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const params = { id: this.resource.id }
|
var params = { id: this.resource.id }
|
||||||
if (this.details.length === 0) {
|
params = Object.assign(params, this.getDetailsParam(this.details))
|
||||||
params.cleanupdetails = true
|
|
||||||
} else {
|
|
||||||
this.details.forEach(function (item, index) {
|
|
||||||
params['details[0].' + item.name] = item.value
|
|
||||||
})
|
|
||||||
}
|
|
||||||
this.loading = true
|
this.loading = true
|
||||||
api(apiName, params).then(json => {
|
api(apiName, params).then(json => {
|
||||||
var details = {}
|
var details = {}
|
||||||
@ -259,18 +267,19 @@ export default {
|
|||||||
this.error = this.$t('message.error.provide.setting')
|
this.error = this.$t('message.error.provide.setting')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if (!this.allowEditOfDetail(this.newKey)) {
|
||||||
|
this.error = this.$t('error.unable.to.proceed')
|
||||||
|
return
|
||||||
|
}
|
||||||
this.error = false
|
this.error = false
|
||||||
this.details.push({ name: this.newKey, value: this.newValue })
|
this.details.push({ name: this.newKey, value: this.newValue })
|
||||||
this.filterOrReadOnlyDetails()
|
|
||||||
this.runApi()
|
this.runApi()
|
||||||
},
|
},
|
||||||
updateDetail (index) {
|
updateDetail (index) {
|
||||||
this.filterOrReadOnlyDetails()
|
|
||||||
this.runApi()
|
this.runApi()
|
||||||
},
|
},
|
||||||
deleteDetail (index) {
|
deleteDetail (index) {
|
||||||
this.details.splice(index, 1)
|
this.details.splice(index, 1)
|
||||||
this.filterOrReadOnlyDetails()
|
|
||||||
this.runApi()
|
this.runApi()
|
||||||
},
|
},
|
||||||
onShowAddDetail () {
|
onShowAddDetail () {
|
||||||
|
|||||||
@ -99,7 +99,7 @@ export default {
|
|||||||
label: 'label.restart.network',
|
label: 'label.restart.network',
|
||||||
message: 'message.restart.network',
|
message: 'message.restart.network',
|
||||||
dataView: true,
|
dataView: true,
|
||||||
args: ['cleanup'],
|
args: (record) => record.vpcid == null ? ['cleanup'] : [], // if it is a tier in a VPC and so it has a vpc do not allow "cleanup
|
||||||
show: (record) => record.type !== 'L2',
|
show: (record) => record.type !== 'L2',
|
||||||
groupAction: true,
|
groupAction: true,
|
||||||
popup: true,
|
popup: true,
|
||||||
|
|||||||
@ -69,7 +69,8 @@
|
|||||||
optionFilterProp="children"
|
optionFilterProp="children"
|
||||||
:filterOption="(input, option) => {
|
:filterOption="(input, option) => {
|
||||||
return option.componentOptions.propsData.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
return option.componentOptions.propsData.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||||
}" >
|
}"
|
||||||
|
@change="onZoneChange" >
|
||||||
<a-select-option :value="zone.id" v-for="zone in zones" :key="zone.id" :label="zone.name || zone.description">
|
<a-select-option :value="zone.id" v-for="zone in zones" :key="zone.id" :label="zone.name || zone.description">
|
||||||
<span>
|
<span>
|
||||||
<resource-icon v-if="zone.icon" :image="zone.icon.base64image" size="1x" style="margin-right: 5px"/>
|
<resource-icon v-if="zone.icon" :image="zone.icon.base64image" size="1x" style="margin-right: 5px"/>
|
||||||
@ -79,6 +80,22 @@
|
|||||||
</a-select-option>
|
</a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<a-form-item>
|
||||||
|
<tooltip-label slot="label" :title="$t('label.diskofferingid')" :tooltip="apiParams.diskofferingid.description"/>
|
||||||
|
<a-select
|
||||||
|
v-decorator="['diskofferingid', {}]"
|
||||||
|
:loading="offeringLoading"
|
||||||
|
:placeholder="apiParams.diskofferingid.description"
|
||||||
|
showSearch
|
||||||
|
optionFilterProp="children"
|
||||||
|
:filterOption="(input, option) => {
|
||||||
|
return option.componentOptions.propsData.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||||
|
}" >
|
||||||
|
<a-select-option v-for="opt in offerings" :key="opt.id">
|
||||||
|
{{ opt.name || opt.displaytext }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
<a-form-item>
|
<a-form-item>
|
||||||
<tooltip-label slot="label" :title="$t('label.format')" :tooltip="apiParams.format.description"/>
|
<tooltip-label slot="label" :title="$t('label.format')" :tooltip="apiParams.format.description"/>
|
||||||
<a-select
|
<a-select
|
||||||
@ -133,6 +150,8 @@ export default {
|
|||||||
return {
|
return {
|
||||||
fileList: [],
|
fileList: [],
|
||||||
zones: [],
|
zones: [],
|
||||||
|
offerings: [],
|
||||||
|
offeringLoading: false,
|
||||||
formats: ['RAW', 'VHD', 'VHDX', 'OVA', 'QCOW2'],
|
formats: ['RAW', 'VHD', 'VHDX', 'OVA', 'QCOW2'],
|
||||||
zoneSelected: '',
|
zoneSelected: '',
|
||||||
uploadParams: null,
|
uploadParams: null,
|
||||||
@ -153,11 +172,34 @@ export default {
|
|||||||
if (json && json.listzonesresponse && json.listzonesresponse.zone) {
|
if (json && json.listzonesresponse && json.listzonesresponse.zone) {
|
||||||
this.zones = json.listzonesresponse.zone
|
this.zones = json.listzonesresponse.zone
|
||||||
if (this.zones.length > 0) {
|
if (this.zones.length > 0) {
|
||||||
this.zoneSelected = this.zones[0].id
|
this.onZoneChange(this.zones[0].id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
onZoneChange (zoneId) {
|
||||||
|
this.zoneSelected = this.zones[0].id
|
||||||
|
this.fetchDiskOfferings(zoneId)
|
||||||
|
},
|
||||||
|
fetchDiskOfferings (zoneId) {
|
||||||
|
this.offeringLoading = true
|
||||||
|
this.offerings = [{ id: -1, name: '' }]
|
||||||
|
this.form.setFieldsValue({
|
||||||
|
diskofferingid: undefined
|
||||||
|
})
|
||||||
|
api('listDiskOfferings', {
|
||||||
|
zoneid: zoneId,
|
||||||
|
listall: true
|
||||||
|
}).then(json => {
|
||||||
|
for (var offering of json.listdiskofferingsresponse.diskoffering) {
|
||||||
|
if (offering.iscustomized) {
|
||||||
|
this.offerings.push(offering)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).finally(() => {
|
||||||
|
this.offeringLoading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
handleRemove (file) {
|
handleRemove (file) {
|
||||||
const index = this.fileList.indexOf(file)
|
const index = this.fileList.indexOf(file)
|
||||||
const newFileList = this.fileList.slice()
|
const newFileList = this.fileList.slice()
|
||||||
@ -188,7 +230,7 @@ export default {
|
|||||||
}
|
}
|
||||||
this.loading = true
|
this.loading = true
|
||||||
api('getUploadParamsForVolume', params).then(json => {
|
api('getUploadParamsForVolume', params).then(json => {
|
||||||
this.uploadParams = (json.postuploadvolumeresponse && json.postuploadvolumeresponse.getuploadparams) ? json.postuploadvolumeresponse.getuploadparams : ''
|
this.uploadParams = json.postuploadvolumeresponse?.getuploadparams || ''
|
||||||
const { fileList } = this
|
const { fileList } = this
|
||||||
if (this.fileList.length > 1) {
|
if (this.fileList.length > 1) {
|
||||||
this.$notification.error({
|
this.$notification.error({
|
||||||
@ -224,12 +266,20 @@ export default {
|
|||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
this.$notification.error({
|
this.$notification.error({
|
||||||
message: this.$t('message.upload.failed'),
|
message: this.$t('message.upload.failed'),
|
||||||
description: `${this.$t('message.upload.iso.failed.description')} - ${e}`,
|
description: `${this.$t('message.upload.volume.failed')} - ${e}`,
|
||||||
duration: 0
|
duration: 0
|
||||||
})
|
})
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
this.loading = false
|
this.loading = false
|
||||||
})
|
})
|
||||||
|
}).catch(e => {
|
||||||
|
this.$notification.error({
|
||||||
|
message: this.$t('message.upload.failed'),
|
||||||
|
description: `${this.$t('message.upload.volume.failed')} - ${e?.response?.data?.postuploadvolumeresponse?.errortext || e}`,
|
||||||
|
duration: 0
|
||||||
|
})
|
||||||
|
}).finally(() => {
|
||||||
|
this.loading = false
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user