mirror of
https://github.com/apache/cloudstack.git
synced 2025-11-02 20:02:29 +01:00
Merge remote-tracking branch 'origin/4.15'
Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
This commit is contained in:
commit
6634382f69
@ -21,11 +21,11 @@ import java.util.Date;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.cloud.hypervisor.Hypervisor;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.BaseResponseWithTagInformation;
|
||||
import org.apache.cloudstack.api.EntityReference;
|
||||
|
||||
import com.cloud.hypervisor.Hypervisor;
|
||||
import com.cloud.serializer.Param;
|
||||
import com.cloud.vm.snapshot.VMSnapshot;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
@ -57,9 +57,17 @@ public class VMSnapshotResponse extends BaseResponseWithTagInformation implement
|
||||
@Param(description = "the Zone ID of the vm snapshot")
|
||||
private String zoneId;
|
||||
|
||||
@SerializedName(ApiConstants.ZONE_NAME)
|
||||
@Param(description = "the Zone name of the vm snapshot", since = "4.15.1")
|
||||
private String zoneName;
|
||||
|
||||
@SerializedName(ApiConstants.VIRTUAL_MACHINE_ID)
|
||||
@Param(description = "the vm ID of the vm snapshot")
|
||||
private String virtualMachineid;
|
||||
private String virtualMachineId;
|
||||
|
||||
@SerializedName(ApiConstants.VIRTUAL_MACHINE_NAME)
|
||||
@Param(description = "the vm name of the vm snapshot", since = "4.15.1")
|
||||
private String virtualMachineName;
|
||||
|
||||
@SerializedName("parent")
|
||||
@Param(description = "the parent ID of the vm snapshot")
|
||||
@ -154,12 +162,28 @@ public class VMSnapshotResponse extends BaseResponseWithTagInformation implement
|
||||
this.zoneId = zoneId;
|
||||
}
|
||||
|
||||
public String getVirtualMachineid() {
|
||||
return virtualMachineid;
|
||||
public String getZoneName() {
|
||||
return zoneName;
|
||||
}
|
||||
|
||||
public void setVirtualMachineid(String virtualMachineid) {
|
||||
this.virtualMachineid = virtualMachineid;
|
||||
public void setZoneName(String zoneName) {
|
||||
this.zoneName = zoneName;
|
||||
}
|
||||
|
||||
public String getVirtualMachineId() {
|
||||
return virtualMachineId;
|
||||
}
|
||||
|
||||
public void setVirtualMachineId(String virtualMachineId) {
|
||||
this.virtualMachineId = virtualMachineId;
|
||||
}
|
||||
|
||||
public String getVirtualMachineName() {
|
||||
return virtualMachineName;
|
||||
}
|
||||
|
||||
public void setVirtualMachineName(String virtualMachineName) {
|
||||
this.virtualMachineName = virtualMachineName;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
|
||||
@ -56,6 +56,9 @@ import org.apache.cloudstack.utils.hypervisor.HypervisorUtils;
|
||||
import org.apache.cloudstack.utils.linux.CPUStat;
|
||||
import org.apache.cloudstack.utils.linux.KVMHostInfo;
|
||||
import org.apache.cloudstack.utils.linux.MemStat;
|
||||
import org.apache.cloudstack.utils.qemu.QemuImg;
|
||||
import org.apache.cloudstack.utils.qemu.QemuImgException;
|
||||
import org.apache.cloudstack.utils.qemu.QemuImgFile;
|
||||
import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
|
||||
import org.apache.cloudstack.utils.security.KeyStoreUtils;
|
||||
import org.apache.commons.collections.MapUtils;
|
||||
@ -2528,6 +2531,15 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
||||
volPath = physicalDisk.getPath();
|
||||
}
|
||||
|
||||
if (volume.getType() != Volume.Type.ISO
|
||||
&& physicalDisk != null && physicalDisk.getFormat() == PhysicalDiskFormat.QCOW2
|
||||
&& (pool.getType() == StoragePoolType.NetworkFilesystem
|
||||
|| pool.getType() == StoragePoolType.SharedMountPoint
|
||||
|| pool.getType() == StoragePoolType.Filesystem
|
||||
|| pool.getType() == StoragePoolType.Gluster)) {
|
||||
setBackingFileFormat(physicalDisk.getPath());
|
||||
}
|
||||
|
||||
// check for disk activity, if detected we should exit because vm is running elsewhere
|
||||
if (_diskActivityCheckEnabled && physicalDisk != null && physicalDisk.getFormat() == PhysicalDiskFormat.QCOW2) {
|
||||
s_logger.debug("Checking physical disk file at path " + volPath + " for disk activity to ensure vm is not running elsewhere");
|
||||
@ -4265,4 +4277,25 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
||||
cmd.setTopology(numCoresPerSocket, vcpus / numCoresPerSocket);
|
||||
}
|
||||
}
|
||||
|
||||
public void setBackingFileFormat(String volPath) {
|
||||
final int timeout = 0;
|
||||
QemuImgFile file = new QemuImgFile(volPath);
|
||||
QemuImg qemu = new QemuImg(timeout);
|
||||
try{
|
||||
Map<String, String> info = qemu.info(file);
|
||||
String backingFilePath = info.get(new String("backing_file"));
|
||||
String backingFileFormat = info.get(new String("backing_file_format"));
|
||||
if (org.apache.commons.lang.StringUtils.isEmpty(backingFileFormat)) {
|
||||
s_logger.info("Setting backing file format of " + volPath);
|
||||
QemuImgFile backingFile = new QemuImgFile(backingFilePath);
|
||||
Map<String, String> backingFileinfo = qemu.info(backingFile);
|
||||
String backingFileFmt = backingFileinfo.get(new String("file_format"));
|
||||
qemu.rebase(file, backingFile, backingFileFmt, false);
|
||||
}
|
||||
} catch (QemuImgException e) {
|
||||
s_logger.error("Failed to set backing file format of " + volPath + " due to : " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -155,6 +155,14 @@ public final class LibvirtMigrateCommandWrapper extends CommandWrapper<MigrateCo
|
||||
// delete the metadata of vm snapshots before migration
|
||||
vmsnapshots = libvirtComputingResource.cleanVMSnapshotMetadata(dm);
|
||||
|
||||
// Verify Format of backing file
|
||||
for (DiskDef disk : disks) {
|
||||
if (disk.getDeviceType() == DiskDef.DeviceType.DISK
|
||||
&& disk.getDiskFormatType() == DiskDef.DiskFmtType.QCOW2) {
|
||||
libvirtComputingResource.setBackingFileFormat(disk.getDiskPath());
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, MigrateCommand.MigrateDiskInfo> mapMigrateStorage = command.getMigrateStorage();
|
||||
// migrateStorage is declared as final because the replaceStorage method may mutate mapMigrateStorage, but
|
||||
// migrateStorage's value should always only be associated with the initial state of mapMigrateStorage.
|
||||
|
||||
@ -379,8 +379,29 @@ public class QemuImg {
|
||||
}
|
||||
|
||||
/* Changes the backing file of an image */
|
||||
public void rebase() throws QemuImgException {
|
||||
public void rebase(final QemuImgFile file, final QemuImgFile backingFile, final String backingFileFormat, final boolean secure) throws QemuImgException {
|
||||
if (backingFile == null) {
|
||||
throw new QemuImgException("No backing file was passed");
|
||||
}
|
||||
final Script s = new Script(_qemuImgPath, timeout);
|
||||
s.add("rebase");
|
||||
if (! secure) {
|
||||
s.add("-u");
|
||||
}
|
||||
s.add("-F");
|
||||
if (backingFileFormat != null) {
|
||||
s.add(backingFileFormat);
|
||||
} else {
|
||||
s.add(backingFile.getFormat().toString());
|
||||
}
|
||||
s.add("-b");
|
||||
s.add(backingFile.getFileName());
|
||||
|
||||
s.add(file.getFileName());
|
||||
final String result = s.execute();
|
||||
if (result != null) {
|
||||
throw new QemuImgException(result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -351,6 +351,7 @@ import com.cloud.vm.dao.NicSecondaryIpVO;
|
||||
import com.cloud.vm.snapshot.VMSnapshot;
|
||||
import com.cloud.vm.snapshot.VMSnapshotVO;
|
||||
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
public class ApiResponseHelper implements ResponseGenerator {
|
||||
|
||||
@ -622,11 +623,13 @@ public class ApiResponseHelper implements ResponseGenerator {
|
||||
vmSnapshotResponse.setDisplayName(vmSnapshot.getDisplayName());
|
||||
UserVm vm = ApiDBUtils.findUserVmById(vmSnapshot.getVmId());
|
||||
if (vm != null) {
|
||||
vmSnapshotResponse.setVirtualMachineid(vm.getUuid());
|
||||
vmSnapshotResponse.setVirtualMachineId(vm.getUuid());
|
||||
vmSnapshotResponse.setVirtualMachineName(Strings.isNullOrEmpty(vm.getDisplayName()) ? vm.getHostName() : vm.getDisplayName());
|
||||
vmSnapshotResponse.setHypervisor(vm.getHypervisorType());
|
||||
DataCenterVO datacenter = ApiDBUtils.findZoneById(vm.getDataCenterId());
|
||||
if (datacenter != null) {
|
||||
vmSnapshotResponse.setZoneId(datacenter.getUuid());
|
||||
vmSnapshotResponse.setZoneName(datacenter.getName());
|
||||
}
|
||||
}
|
||||
if (vmSnapshot.getParent() != null) {
|
||||
|
||||
@ -2232,6 +2232,12 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
||||
if (capabilities != null) {
|
||||
liveMigrateVolume = capabilities.isStorageMotionSupported();
|
||||
}
|
||||
|
||||
if (liveMigrateVolume && HypervisorType.KVM.equals(host.getHypervisorType())) {
|
||||
throw new InvalidParameterValueException("KVM does not support volume live migration due to the limited possibility to refresh VM XML domain. " +
|
||||
"Therefore, to live migrate a volume between storage pools, one must migrate the VM to a different host as well to force the VM XML domain update. " +
|
||||
"Use 'migrateVirtualMachineWithVolumes' instead.");
|
||||
}
|
||||
}
|
||||
|
||||
// If vm is running, and hypervisor doesn't support live migration, then return error
|
||||
|
||||
@ -3968,7 +3968,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
// * verify that there are no duplicates
|
||||
if (hostNames.contains(hostName)) {
|
||||
throw new InvalidParameterValueException("The vm with hostName " + hostName + " already exists in the network domain: " + ntwkDomain.getKey() + "; network="
|
||||
+ _networkModel.getNetwork(ntwkId));
|
||||
+ ((_networkModel.getNetwork(ntwkId) != null) ? _networkModel.getNetwork(ntwkId).getName() : "<unknown>"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,30 +0,0 @@
|
||||
# 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.
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
}
|
||||
location /client/ {
|
||||
# http://127.0.0.1:8080 should be replaced your CloudStack management
|
||||
# Server's actual URI
|
||||
proxy_pass http://127.0.0.1:8080;
|
||||
}
|
||||
}
|
||||
41
ui/package-lock.json
generated
41
ui/package-lock.json
generated
@ -4766,9 +4766,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"ant-design-vue": {
|
||||
"version": "1.7.2",
|
||||
"resolved": "https://registry.npmjs.org/ant-design-vue/-/ant-design-vue-1.7.2.tgz",
|
||||
"integrity": "sha512-iVskTSG62OSiptyGQkvyhoeLlLMiqKtAOTcWZ7MmsMrj38h0TCpGtqSYS4/fwq4yYgyzloYSteBo8U8TrV99RA==",
|
||||
"version": "1.7.3",
|
||||
"resolved": "https://registry.npmjs.org/ant-design-vue/-/ant-design-vue-1.7.3.tgz",
|
||||
"integrity": "sha512-OuJBZmpcy32OvdvP7iW1EqdqU6l/dta1zcQ/U0fep7EGksPviVK7ssifI5QMZFQDDsti0dYQhCEOZWUG0Y/xxQ==",
|
||||
"requires": {
|
||||
"@ant-design/icons": "^2.1.1",
|
||||
"@ant-design/icons-vue": "^2.0.0",
|
||||
@ -5402,11 +5402,23 @@
|
||||
}
|
||||
},
|
||||
"antd-theme-webpack-plugin": {
|
||||
"version": "1.3.7",
|
||||
"resolved": "https://registry.npmjs.org/antd-theme-webpack-plugin/-/antd-theme-webpack-plugin-1.3.7.tgz",
|
||||
"integrity": "sha512-FB101smtUHtEW/SdLm88BiR0MKIKhoIGqiQdmrIwQ46zuwJ7MHxAKEUVXg+IWV3F8b71jKaQlFCPnLCe9RqL2A==",
|
||||
"version": "1.3.9",
|
||||
"resolved": "https://registry.npmjs.org/antd-theme-webpack-plugin/-/antd-theme-webpack-plugin-1.3.9.tgz",
|
||||
"integrity": "sha512-J/xYPqW8oZrk/UZslRODdKSLmhFlpLKuqL6GMHPoKib9u0RoIeVCUAD+IT4yRwIkFBYVIX0vlahnLvGHNEeMxA==",
|
||||
"requires": {
|
||||
"antd-theme-generator": "^1.2.7"
|
||||
"antd-theme-generator": "^1.2.8",
|
||||
"webpack-sources": "^2.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"webpack-sources": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.2.0.tgz",
|
||||
"integrity": "sha512-bQsA24JLwcnWGArOKUxYKhX3Mz/nK1Xf6hxullKERyktjNMC4x8koOeaDNTA2fEJ09BdWLbM/iTW0ithREUP0w==",
|
||||
"requires": {
|
||||
"source-list-map": "^2.0.1",
|
||||
"source-map": "^0.6.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"any-observable": {
|
||||
@ -22641,8 +22653,7 @@
|
||||
"source-list-map": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz",
|
||||
"integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw=="
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
@ -25239,9 +25250,9 @@
|
||||
"integrity": "sha512-uKNKpFOVeWNqS2mrBZqnpLyXJo5Q+vnkex6JvpENvhXHFNBW/SJTP8vJywLuVT3DpxwXcF9N0dyIiZ4/NpTexQ=="
|
||||
},
|
||||
"vue-router": {
|
||||
"version": "3.4.9",
|
||||
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.4.9.tgz",
|
||||
"integrity": "sha512-CGAKWN44RqXW06oC+u4mPgHLQQi2t6vLD/JbGRDAXm0YpMv0bgpKuU5bBd7AvMgfTz9kXVRIWKHqRwGEb8xFkA=="
|
||||
"version": "3.5.1",
|
||||
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.5.1.tgz",
|
||||
"integrity": "sha512-RRQNLT8Mzr8z7eL4p7BtKvRaTSGdCbTy2+Mm5HTJvLGYSSeG9gDzNasJPP/yOYKLy+/cLG/ftrqq5fvkFwBJEw=="
|
||||
},
|
||||
"vue-sfc-descriptor-to-string": {
|
||||
"version": "1.0.0",
|
||||
@ -25363,9 +25374,9 @@
|
||||
}
|
||||
},
|
||||
"vuex": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/vuex/-/vuex-3.6.0.tgz",
|
||||
"integrity": "sha512-W74OO2vCJPs9/YjNjW8lLbj+jzT24waTo2KShI8jLvJW8OaIkgb3wuAMA7D+ZiUxDOx3ubwSZTaJBip9G8a3aQ=="
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/vuex/-/vuex-3.6.2.tgz",
|
||||
"integrity": "sha512-ETW44IqCgBpVomy520DT5jf8n0zoCac+sxWnn+hMe/CzaSejb/eVw2YToiXYX+Ex/AuHHia28vWTq4goAexFbw=="
|
||||
},
|
||||
"w3c-hr-time": {
|
||||
"version": "1.0.2",
|
||||
|
||||
@ -36,8 +36,8 @@
|
||||
"@fortawesome/free-brands-svg-icons": "^5.15.2",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.15.2",
|
||||
"@fortawesome/vue-fontawesome": "^2.0.2",
|
||||
"ant-design-vue": "~1.7.2",
|
||||
"antd-theme-webpack-plugin": "^1.3.7",
|
||||
"ant-design-vue": "~1.7.3",
|
||||
"antd-theme-webpack-plugin": "^1.3.9",
|
||||
"axios": "^0.21.1",
|
||||
"babel-plugin-require-context-hook": "^1.0.0",
|
||||
"core-js": "^3.6.5",
|
||||
@ -54,10 +54,10 @@
|
||||
"vue-cropper": "0.5.6",
|
||||
"vue-i18n": "^8.22.4",
|
||||
"vue-ls": "^3.2.2",
|
||||
"vue-router": "^3.4.9",
|
||||
"vue-router": "^3.5.1",
|
||||
"vue-svg-component-runtime": "^1.0.1",
|
||||
"vuedraggable": "^2.24.3",
|
||||
"vuex": "^3.6.0"
|
||||
"vuex": "^3.6.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli": "^4.4.1",
|
||||
|
||||
@ -35,7 +35,7 @@
|
||||
:pagination="false"
|
||||
>
|
||||
<template slot="account" slot-scope="record">
|
||||
<a-button @click="() => handleOpenAccountModal(record)">{{ `[${record.domain}] ${record.account}` }}</a-button>
|
||||
<a-button @click="() => handleOpenAccountModal(record)">{{ `[${record.domain}] ${record.account === undefined ? '' : record.account}` }}</a-button>
|
||||
</template>
|
||||
<template slot="actions" slot-scope="record">
|
||||
<div class="actions">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user