Enable system VM volume migration for KVM (#6341)

Release 4.16.0.0 introduced a feature for migrating system VM volumes (#4385). However, it was enabled only for VMWare.

This PR intends to enable the feature for KVM too.

Co-authored-by: GutoVeronezi <daniel@scclouds.com.br>
This commit is contained in:
Daniel Augusto Veronezi Salvador 2022-08-09 01:33:03 -03:00 committed by GitHub
parent 167cd17d7c
commit b0e780a35e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 118 additions and 25 deletions

View File

@ -20,4 +20,109 @@
--;
UPDATE `cloud`.`configuration` SET `value` = 'false' WHERE `name` = 'network.disable.rpfilter' AND `value` != 'true';
UPDATE `cloud`.`configuration` SET `value` = 'false' WHERE `name` = 'consoleproxy.disable.rpfilter' AND `value` != 'true';
UPDATE `cloud`.`configuration` SET `value` = 'false' WHERE `name` = 'consoleproxy.disable.rpfilter' AND `value` != 'true';
-- Retrieve the hypervisor_type from vm_instance
DROP VIEW IF EXISTS `cloud`.`domain_router_view`;
CREATE VIEW `cloud`.`domain_router_view` AS
select
vm_instance.id id,
vm_instance.name name,
account.id account_id,
account.uuid account_uuid,
account.account_name account_name,
account.type account_type,
domain.id domain_id,
domain.uuid domain_uuid,
domain.name domain_name,
domain.path domain_path,
projects.id project_id,
projects.uuid project_uuid,
projects.name project_name,
vm_instance.uuid uuid,
vm_instance.created created,
vm_instance.state state,
vm_instance.removed removed,
vm_instance.pod_id pod_id,
vm_instance.instance_name instance_name,
vm_instance.hypervisor_type,
host_pod_ref.uuid pod_uuid,
data_center.id data_center_id,
data_center.uuid data_center_uuid,
data_center.name data_center_name,
data_center.networktype data_center_type,
data_center.dns1 dns1,
data_center.dns2 dns2,
data_center.ip6_dns1 ip6_dns1,
data_center.ip6_dns2 ip6_dns2,
host.id host_id,
host.uuid host_uuid,
host.name host_name,
host.cluster_id cluster_id,
vm_template.id template_id,
vm_template.uuid template_uuid,
service_offering.id service_offering_id,
service_offering.uuid service_offering_uuid,
service_offering.name service_offering_name,
nics.id nic_id,
nics.uuid nic_uuid,
nics.network_id network_id,
nics.ip4_address ip_address,
nics.ip6_address ip6_address,
nics.ip6_gateway ip6_gateway,
nics.ip6_cidr ip6_cidr,
nics.default_nic is_default_nic,
nics.gateway gateway,
nics.netmask netmask,
nics.mac_address mac_address,
nics.broadcast_uri broadcast_uri,
nics.isolation_uri isolation_uri,
vpc.id vpc_id,
vpc.uuid vpc_uuid,
vpc.name vpc_name,
networks.uuid network_uuid,
networks.name network_name,
networks.network_domain network_domain,
networks.traffic_type traffic_type,
networks.guest_type guest_type,
async_job.id job_id,
async_job.uuid job_uuid,
async_job.job_status job_status,
async_job.account_id job_account_id,
domain_router.template_version template_version,
domain_router.scripts_version scripts_version,
domain_router.is_redundant_router is_redundant_router,
domain_router.redundant_state redundant_state,
domain_router.stop_pending stop_pending,
domain_router.role role,
domain_router.software_version software_version
from
`cloud`.`domain_router`
inner join
`cloud`.`vm_instance` ON vm_instance.id = domain_router.id
inner join
`cloud`.`account` ON vm_instance.account_id = account.id
inner join
`cloud`.`domain` ON vm_instance.domain_id = domain.id
left join
`cloud`.`host_pod_ref` ON vm_instance.pod_id = host_pod_ref.id
left join
`cloud`.`projects` ON projects.project_account_id = account.id
left join
`cloud`.`data_center` ON vm_instance.data_center_id = data_center.id
left join
`cloud`.`host` ON vm_instance.host_id = host.id
left join
`cloud`.`vm_template` ON vm_instance.vm_template_id = vm_template.id
left join
`cloud`.`service_offering` ON vm_instance.service_offering_id = service_offering.id
left join
`cloud`.`nics` ON vm_instance.id = nics.instance_id and nics.removed is null
left join
`cloud`.`networks` ON nics.network_id = networks.id
left join
`cloud`.`vpc` ON domain_router.vpc_id = vpc.id and vpc.removed is null
left join
`cloud`.`async_job` ON async_job.instance_id = vm_instance.id
and async_job.instance_type = 'DomainRouter'
and async_job.job_status = 0;

View File

@ -329,7 +329,6 @@ import org.apache.cloudstack.framework.jobs.dao.AsyncJobDao;
import org.apache.cloudstack.resourcedetail.dao.DiskOfferingDetailsDao;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.commons.lang3.StringUtils;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
@ -1795,17 +1794,7 @@ public class ApiDBUtils {
///////////////////////////////////////////////////////////////////////
public static DomainRouterResponse newDomainRouterResponse(DomainRouterJoinVO vr, Account caller) {
DomainRouterResponse response = s_domainRouterJoinDao.newDomainRouterResponse(vr, caller);
if (StringUtils.isBlank(response.getHypervisor())) {
VMInstanceVO vm = ApiDBUtils.findVMInstanceById(vr.getId());
if (vm.getLastHostId() != null) {
HostVO lastHost = ApiDBUtils.findHostById(vm.getLastHostId());
if (lastHost != null) {
response.setHypervisor(lastHost.getHypervisorType().toString());
}
}
}
return response;
return s_domainRouterJoinDao.newDomainRouterResponse(vr, caller);
}
public static DomainRouterResponse fillRouterDetails(DomainRouterResponse vrData, DomainRouterJoinVO vr) {

View File

@ -1536,18 +1536,13 @@ public class ApiResponseHelper implements ResponseGenerator {
vmResponse.setTemplateName(template.getName());
}
vmResponse.setCreated(vm.getCreated());
vmResponse.setHypervisor(vm.getHypervisorType().toString());
if (vm.getHostId() != null) {
Host host = ApiDBUtils.findHostById(vm.getHostId());
if (host != null) {
vmResponse.setHostId(host.getUuid());
vmResponse.setHostName(host.getName());
vmResponse.setHypervisor(host.getHypervisorType().toString());
}
} else if (vm.getLastHostId() != null) {
Host lastHost = ApiDBUtils.findHostById(vm.getLastHostId());
if (lastHost != null) {
vmResponse.setHypervisor(lastHost.getHypervisorType().toString());
}
}

View File

@ -118,6 +118,7 @@ public class DomainRouterJoinDaoImpl extends GenericDaoBase<DomainRouterJoinVO,
routerResponse.setRequiresUpgrade(true);
}
routerResponse.setHypervisor(router.getHypervisorType().toString());
routerResponse.setHasAnnotation(annotationDao.hasAnnotations(router.getUuid(), AnnotationService.EntityType.VR.name(),
_accountMgr.isRootAdmin(CallContext.current().getCallingAccount().getId())));
@ -126,7 +127,6 @@ public class DomainRouterJoinDaoImpl extends GenericDaoBase<DomainRouterJoinVO,
if (router.getHostId() != null) {
routerResponse.setHostId(router.getHostUuid());
routerResponse.setHostName(router.getHostName());
routerResponse.setHypervisor(router.getHypervisorType().toString());
}
routerResponse.setPodId(router.getPodUuid());
HostPodVO pod = ApiDBUtils.findPodById(router.getPodId());

View File

@ -630,6 +630,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
HypervisorType.Simulator
));
private static final List<HypervisorType> HYPERVISORS_THAT_CAN_DO_STORAGE_MIGRATION_ON_NON_USER_VMS = Arrays.asList(HypervisorType.KVM, HypervisorType.VMware);
@Override
public UserVmVO getVirtualMachine(long vmId) {
return _vmDao.findById(vmId);
@ -6093,8 +6095,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
throw ex;
}
if (vm.getType() != VirtualMachine.Type.User && !HypervisorType.VMware.equals(vm.getHypervisorType())) {
throw new InvalidParameterValueException("cannot do storage migration on non-user vm for hypervisor: " + vm.getHypervisorType().toString() + ", only supported for VMware");
HypervisorType hypervisorType = vm.getHypervisorType();
if (vm.getType() != VirtualMachine.Type.User && !HYPERVISORS_THAT_CAN_DO_STORAGE_MIGRATION_ON_NON_USER_VMS.contains(hypervisorType)) {
throw new InvalidParameterValueException(String.format("Unable to migrate storage of non-user VMs for hypervisor [%s]. Operation only supported for the following"
+ " hypervisors: [%s].", hypervisorType, HYPERVISORS_THAT_CAN_DO_STORAGE_MIGRATION_ON_NON_USER_VMS));
}
List<VolumeVO> vols = _volsDao.findByInstance(vm.getId());
@ -6102,7 +6106,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
// OffLineVmwareMigration: data disks are not permitted, here!
if (vols.size() > 1 &&
// OffLineVmwareMigration: allow multiple disks for vmware
!HypervisorType.VMware.equals(vm.getHypervisorType())) {
!HypervisorType.VMware.equals(hypervisorType)) {
throw new InvalidParameterValueException("Data disks attached to the vm, can not migrate. Need to detach data disks first");
}
}

View File

@ -193,7 +193,7 @@ export default {
icon: 'drag-outlined',
label: 'label.action.migrate.systemvm.to.ps',
dataView: true,
show: (record, store) => { return ['Stopped'].includes(record.state) && ['VMware'].includes(record.hypervisor) },
show: (record, store) => { return ['Stopped'].includes(record.state) && ['VMware', 'KVM'].includes(record.hypervisor) },
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/MigrateVMStorage'))),
popup: true
},

View File

@ -109,7 +109,7 @@ export default {
icon: 'drag-outlined',
label: 'label.action.migrate.systemvm.to.ps',
dataView: true,
show: (record, store) => { return ['Stopped'].includes(record.state) && ['VMware'].includes(record.hypervisor) },
show: (record, store) => { return ['Stopped'].includes(record.state) && ['VMware', 'KVM'].includes(record.hypervisor) },
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/MigrateVMStorage'))),
popup: true
},