mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
Merge branch '4.19'
This commit is contained in:
commit
90fe1d5fdc
@ -1127,6 +1127,12 @@ public class Agent implements HandlerFactory, IAgentControl, AgentStatusUpdater
|
|||||||
logger.error("Error parsing task", e);
|
logger.error("Error parsing task", e);
|
||||||
}
|
}
|
||||||
} else if (task.getType() == Task.Type.DISCONNECT) {
|
} else if (task.getType() == Task.Type.DISCONNECT) {
|
||||||
|
try {
|
||||||
|
// an issue has been found if reconnect immediately after disconnecting. please refer to https://github.com/apache/cloudstack/issues/8517
|
||||||
|
// wait 5 seconds before reconnecting
|
||||||
|
Thread.sleep(5000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
}
|
||||||
reconnect(task.getLink());
|
reconnect(task.getLink());
|
||||||
return;
|
return;
|
||||||
} else if (task.getType() == Task.Type.OTHER) {
|
} else if (task.getType() == Task.Type.OTHER) {
|
||||||
|
|||||||
@ -751,7 +751,7 @@ public class AgentProperties{
|
|||||||
public static final Property<Integer> IOTHREADS = new Property<>("iothreads", 1);
|
public static final Property<Integer> IOTHREADS = new Property<>("iothreads", 1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable verbose mode for virt-v2v Instance Conversion from Vmware to KVM
|
* Enable verbose mode for virt-v2v Instance Conversion from VMware to KVM
|
||||||
* Data type: Boolean.<br>
|
* Data type: Boolean.<br>
|
||||||
* Default value: <code>false</code>
|
* Default value: <code>false</code>
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -18,40 +18,39 @@
|
|||||||
*/
|
*/
|
||||||
package com.cloud.agent.api.to;
|
package com.cloud.agent.api.to;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
import com.cloud.agent.api.LogLevel;
|
import com.cloud.agent.api.LogLevel;
|
||||||
import com.cloud.hypervisor.Hypervisor;
|
import com.cloud.hypervisor.Hypervisor;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
public class RemoteInstanceTO implements Serializable {
|
public class RemoteInstanceTO implements Serializable {
|
||||||
|
|
||||||
private Hypervisor.HypervisorType hypervisorType;
|
private Hypervisor.HypervisorType hypervisorType;
|
||||||
private String hostName;
|
|
||||||
private String instanceName;
|
private String instanceName;
|
||||||
|
|
||||||
// Vmware Remote Instances parameters
|
// VMware Remote Instances parameters (required for exporting OVA through ovftool)
|
||||||
// TODO: cloud.agent.transport.Request#getCommands() cannot handle gsoc decode for polymorphic classes
|
// TODO: cloud.agent.transport.Request#getCommands() cannot handle gsoc decode for polymorphic classes
|
||||||
private String vcenterUsername;
|
private String vcenterUsername;
|
||||||
@LogLevel(LogLevel.Log4jLevel.Off)
|
@LogLevel(LogLevel.Log4jLevel.Off)
|
||||||
private String vcenterPassword;
|
private String vcenterPassword;
|
||||||
private String vcenterHost;
|
private String vcenterHost;
|
||||||
private String datacenterName;
|
private String datacenterName;
|
||||||
private String clusterName;
|
|
||||||
|
|
||||||
public RemoteInstanceTO() {
|
public RemoteInstanceTO() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public RemoteInstanceTO(String hostName, String instanceName, String vcenterHost,
|
public RemoteInstanceTO(String instanceName) {
|
||||||
String datacenterName, String clusterName,
|
this.hypervisorType = Hypervisor.HypervisorType.VMware;
|
||||||
String vcenterUsername, String vcenterPassword) {
|
this.instanceName = instanceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RemoteInstanceTO(String instanceName, String vcenterHost, String vcenterUsername, String vcenterPassword, String datacenterName) {
|
||||||
this.hypervisorType = Hypervisor.HypervisorType.VMware;
|
this.hypervisorType = Hypervisor.HypervisorType.VMware;
|
||||||
this.hostName = hostName;
|
|
||||||
this.instanceName = instanceName;
|
this.instanceName = instanceName;
|
||||||
this.vcenterHost = vcenterHost;
|
this.vcenterHost = vcenterHost;
|
||||||
this.datacenterName = datacenterName;
|
|
||||||
this.clusterName = clusterName;
|
|
||||||
this.vcenterUsername = vcenterUsername;
|
this.vcenterUsername = vcenterUsername;
|
||||||
this.vcenterPassword = vcenterPassword;
|
this.vcenterPassword = vcenterPassword;
|
||||||
|
this.datacenterName = datacenterName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Hypervisor.HypervisorType getHypervisorType() {
|
public Hypervisor.HypervisorType getHypervisorType() {
|
||||||
@ -62,10 +61,6 @@ public class RemoteInstanceTO implements Serializable {
|
|||||||
return this.instanceName;
|
return this.instanceName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getHostName() {
|
|
||||||
return this.hostName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getVcenterUsername() {
|
public String getVcenterUsername() {
|
||||||
return vcenterUsername;
|
return vcenterUsername;
|
||||||
}
|
}
|
||||||
@ -81,8 +76,4 @@ public class RemoteInstanceTO implements Serializable {
|
|||||||
public String getDatacenterName() {
|
public String getDatacenterName() {
|
||||||
return datacenterName;
|
return datacenterName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getClusterName() {
|
|
||||||
return clusterName;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,6 +54,7 @@ public interface Host extends StateObject<Status>, Identity, Partition, HAResour
|
|||||||
}
|
}
|
||||||
public static final String HOST_UEFI_ENABLE = "host.uefi.enable";
|
public static final String HOST_UEFI_ENABLE = "host.uefi.enable";
|
||||||
public static final String HOST_VOLUME_ENCRYPTION = "host.volume.encryption";
|
public static final String HOST_VOLUME_ENCRYPTION = "host.volume.encryption";
|
||||||
|
public static final String HOST_INSTANCE_CONVERSION = "host.instance.conversion";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return name of the machine.
|
* @return name of the machine.
|
||||||
|
|||||||
@ -23,6 +23,7 @@ import org.apache.cloudstack.backup.Backup;
|
|||||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||||
|
|
||||||
import com.cloud.agent.api.Command;
|
import com.cloud.agent.api.Command;
|
||||||
|
import com.cloud.agent.api.to.DataStoreTO;
|
||||||
import com.cloud.agent.api.to.NicTO;
|
import com.cloud.agent.api.to.NicTO;
|
||||||
import com.cloud.agent.api.to.VirtualMachineTO;
|
import com.cloud.agent.api.to.VirtualMachineTO;
|
||||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||||
@ -101,21 +102,20 @@ public interface HypervisorGuru extends Adapter {
|
|||||||
* Will generate commands to migrate a vm to a pool. For now this will only work for stopped VMs on Vmware.
|
* Will generate commands to migrate a vm to a pool. For now this will only work for stopped VMs on Vmware.
|
||||||
*
|
*
|
||||||
* @param vm the stopped vm to migrate
|
* @param vm the stopped vm to migrate
|
||||||
* @param destination the primary storage pool to migrate to
|
* @param volumeToPool the primary storage pools to migrate to
|
||||||
* @return a list of commands to perform for a successful migration
|
* @return a list of commands to perform for a successful migration
|
||||||
*/
|
*/
|
||||||
List<Command> finalizeMigrate(VirtualMachine vm, Map<Volume, StoragePool> volumeToPool);
|
List<Command> finalizeMigrate(VirtualMachine vm, Map<Volume, StoragePool> volumeToPool);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will perform a clone of a VM on an external host (if the guru can handle)
|
* Will return the hypervisor VM (clone VM for PowerOn VMs), performs a clone of a VM if required on an external host (if the guru can handle)
|
||||||
* @param hostIp VM's source host IP
|
* @param hostIp VM's source host IP
|
||||||
* @param vmName name of the source VM to clone from
|
* @param vmName name of the source VM (clone VM name if cloned)
|
||||||
* @param params hypervisor specific additional parameters
|
* @param params hypervisor specific additional parameters
|
||||||
* @return a reference to the cloned VM
|
* @return a reference to the hypervisor or cloned VM, and cloned flag
|
||||||
*/
|
*/
|
||||||
UnmanagedInstanceTO cloneHypervisorVMOutOfBand(String hostIp, String vmName,
|
Pair<UnmanagedInstanceTO, Boolean> getHypervisorVMOutOfBandAndCloneIfRequired(String hostIp, String vmName, Map<String, String> params);
|
||||||
Map<String, String> params);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a VM created as a clone of a VM on an external host
|
* Removes a VM created as a clone of a VM on an external host
|
||||||
@ -124,6 +124,23 @@ public interface HypervisorGuru extends Adapter {
|
|||||||
* @param params hypervisor specific additional parameters
|
* @param params hypervisor specific additional parameters
|
||||||
* @return true if the operation succeeds, false if not
|
* @return true if the operation succeeds, false if not
|
||||||
*/
|
*/
|
||||||
boolean removeClonedHypervisorVMOutOfBand(String hostIp, String vmName,
|
boolean removeClonedHypervisorVMOutOfBand(String hostIp, String vmName, Map<String, String> params);
|
||||||
Map<String, String> params);
|
|
||||||
|
/**
|
||||||
|
* Create an OVA/OVF template of a VM on an external host (if the guru can handle)
|
||||||
|
* @param hostIp VM's source host IP
|
||||||
|
* @param vmName name of the source VM to create template from
|
||||||
|
* @param params hypervisor specific additional parameters
|
||||||
|
* @param templateLocation datastore to create the template file
|
||||||
|
* @return the created template dir/name
|
||||||
|
*/
|
||||||
|
String createVMTemplateOutOfBand(String hostIp, String vmName, Map<String, String> params, DataStoreTO templateLocation, int threadsCountToExportOvf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the template on the location
|
||||||
|
* @param templateLocation datastore to remove the template file
|
||||||
|
* @param templateDir the template dir to remove from datastore
|
||||||
|
* @return true if the operation succeeds, false if not
|
||||||
|
*/
|
||||||
|
boolean removeVMTemplateOutOfBand(DataStoreTO templateLocation, String templateDir);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -317,6 +317,8 @@ public interface NetworkModel {
|
|||||||
|
|
||||||
void checkIp6Parameters(String startIPv6, String endIPv6, String ip6Gateway, String ip6Cidr) throws InvalidParameterValueException;
|
void checkIp6Parameters(String startIPv6, String endIPv6, String ip6Gateway, String ip6Cidr) throws InvalidParameterValueException;
|
||||||
|
|
||||||
|
void checkIp6CidrSizeEqualTo64(String ip6Cidr) throws InvalidParameterValueException;
|
||||||
|
|
||||||
void checkRequestedIpAddresses(long networkId, IpAddresses ips) throws InvalidParameterValueException;
|
void checkRequestedIpAddresses(long networkId, IpAddresses ips) throws InvalidParameterValueException;
|
||||||
|
|
||||||
String getStartIpv6Address(long id);
|
String getStartIpv6Address(long id);
|
||||||
|
|||||||
@ -17,17 +17,22 @@
|
|||||||
package com.cloud.network;
|
package com.cloud.network;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.cloudstack.api.command.admin.router.UpgradeRouterCmd;
|
import org.apache.cloudstack.api.command.admin.router.UpgradeRouterCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.router.UpgradeRouterTemplateCmd;
|
import org.apache.cloudstack.api.command.admin.router.UpgradeRouterTemplateCmd;
|
||||||
|
|
||||||
|
import com.cloud.deploy.DeploymentPlanner;
|
||||||
import com.cloud.exception.ConcurrentOperationException;
|
import com.cloud.exception.ConcurrentOperationException;
|
||||||
import com.cloud.exception.InsufficientCapacityException;
|
import com.cloud.exception.InsufficientCapacityException;
|
||||||
|
import com.cloud.exception.OperationTimedoutException;
|
||||||
import com.cloud.exception.ResourceUnavailableException;
|
import com.cloud.exception.ResourceUnavailableException;
|
||||||
import com.cloud.network.router.VirtualRouter;
|
import com.cloud.network.router.VirtualRouter;
|
||||||
import com.cloud.user.Account;
|
import com.cloud.user.Account;
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
import com.cloud.vm.Nic;
|
import com.cloud.vm.Nic;
|
||||||
|
import com.cloud.vm.VirtualMachine;
|
||||||
|
import com.cloud.vm.VirtualMachineProfile;
|
||||||
|
|
||||||
public interface VirtualNetworkApplianceService {
|
public interface VirtualNetworkApplianceService {
|
||||||
/**
|
/**
|
||||||
@ -62,6 +67,10 @@ public interface VirtualNetworkApplianceService {
|
|||||||
|
|
||||||
VirtualRouter startRouter(long id) throws ResourceUnavailableException, InsufficientCapacityException, ConcurrentOperationException;
|
VirtualRouter startRouter(long id) throws ResourceUnavailableException, InsufficientCapacityException, ConcurrentOperationException;
|
||||||
|
|
||||||
|
void startRouterForHA(VirtualMachine vm, Map<VirtualMachineProfile.Param, Object> params, DeploymentPlanner planner)
|
||||||
|
throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException,
|
||||||
|
OperationTimedoutException;
|
||||||
|
|
||||||
VirtualRouter destroyRouter(long routerId, Account caller, Long callerUserId) throws ResourceUnavailableException, ConcurrentOperationException;
|
VirtualRouter destroyRouter(long routerId, Account caller, Long callerUserId) throws ResourceUnavailableException, ConcurrentOperationException;
|
||||||
|
|
||||||
VirtualRouter findRouter(long routerId);
|
VirtualRouter findRouter(long routerId);
|
||||||
|
|||||||
@ -212,4 +212,7 @@ public interface NetworkGuru extends Adapter {
|
|||||||
|
|
||||||
boolean isMyTrafficType(TrafficType type);
|
boolean isMyTrafficType(TrafficType type);
|
||||||
|
|
||||||
|
default boolean isSlaacV6Only() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -62,6 +62,7 @@ public class NicProfile implements InternalIdentity, Serializable {
|
|||||||
String iPv4Dns1;
|
String iPv4Dns1;
|
||||||
String iPv4Dns2;
|
String iPv4Dns2;
|
||||||
String requestedIPv4;
|
String requestedIPv4;
|
||||||
|
boolean ipv4AllocationRaceCheck;
|
||||||
|
|
||||||
// IPv6
|
// IPv6
|
||||||
String iPv6Address;
|
String iPv6Address;
|
||||||
@ -405,6 +406,13 @@ public class NicProfile implements InternalIdentity, Serializable {
|
|||||||
this.mtu = mtu;
|
this.mtu = mtu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean getIpv4AllocationRaceCheck() {
|
||||||
|
return this.ipv4AllocationRaceCheck;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIpv4AllocationRaceCheck(boolean ipv4AllocationRaceCheck) {
|
||||||
|
this.ipv4AllocationRaceCheck = ipv4AllocationRaceCheck;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// OTHER METHODS
|
// OTHER METHODS
|
||||||
|
|||||||
@ -42,6 +42,7 @@ import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd;
|
|||||||
import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd;
|
import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd;
|
||||||
|
|
||||||
import com.cloud.dc.DataCenter;
|
import com.cloud.dc.DataCenter;
|
||||||
|
import com.cloud.deploy.DeploymentPlanner;
|
||||||
import com.cloud.exception.ConcurrentOperationException;
|
import com.cloud.exception.ConcurrentOperationException;
|
||||||
import com.cloud.exception.InsufficientCapacityException;
|
import com.cloud.exception.InsufficientCapacityException;
|
||||||
import com.cloud.exception.ManagementServerException;
|
import com.cloud.exception.ManagementServerException;
|
||||||
@ -112,6 +113,10 @@ public interface UserVmService {
|
|||||||
|
|
||||||
void startVirtualMachine(UserVm vm) throws OperationTimedoutException, ResourceUnavailableException, InsufficientCapacityException;
|
void startVirtualMachine(UserVm vm) throws OperationTimedoutException, ResourceUnavailableException, InsufficientCapacityException;
|
||||||
|
|
||||||
|
void startVirtualMachineForHA(VirtualMachine vm, Map<VirtualMachineProfile.Param, Object> params,
|
||||||
|
DeploymentPlanner planner) throws InsufficientCapacityException, ResourceUnavailableException,
|
||||||
|
ConcurrentOperationException, OperationTimedoutException;
|
||||||
|
|
||||||
UserVm updateVirtualMachine(UpdateVMCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException;
|
UserVm updateVirtualMachine(UpdateVMCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -192,6 +192,10 @@ public interface VirtualMachineProfile {
|
|||||||
|
|
||||||
Map<Param, Object> getParameters();
|
Map<Param, Object> getParameters();
|
||||||
|
|
||||||
|
void setCpuOvercommitRatio(Float cpuOvercommitRatio);
|
||||||
|
|
||||||
|
void setMemoryOvercommitRatio(Float memoryOvercommitRatio);
|
||||||
|
|
||||||
Float getCpuOvercommitRatio();
|
Float getCpuOvercommitRatio();
|
||||||
|
|
||||||
Float getMemoryOvercommitRatio();
|
Float getMemoryOvercommitRatio();
|
||||||
|
|||||||
@ -191,6 +191,7 @@ public class ApiConstants {
|
|||||||
public static final String FORCED = "forced";
|
public static final String FORCED = "forced";
|
||||||
public static final String FORCED_DESTROY_LOCAL_STORAGE = "forcedestroylocalstorage";
|
public static final String FORCED_DESTROY_LOCAL_STORAGE = "forcedestroylocalstorage";
|
||||||
public static final String FORCE_DELETE_HOST = "forcedeletehost";
|
public static final String FORCE_DELETE_HOST = "forcedeletehost";
|
||||||
|
public static final String FORCE_MS_TO_IMPORT_VM_FILES = "forcemstoimportvmfiles";
|
||||||
public static final String FORMAT = "format";
|
public static final String FORMAT = "format";
|
||||||
public static final String FOR_VIRTUAL_NETWORK = "forvirtualnetwork";
|
public static final String FOR_VIRTUAL_NETWORK = "forvirtualnetwork";
|
||||||
public static final String FOR_SYSTEM_VMS = "forsystemvms";
|
public static final String FOR_SYSTEM_VMS = "forsystemvms";
|
||||||
@ -239,6 +240,7 @@ public class ApiConstants {
|
|||||||
public static final String NEXT_ACL_RULE_ID = "nextaclruleid";
|
public static final String NEXT_ACL_RULE_ID = "nextaclruleid";
|
||||||
public static final String MOVE_ACL_CONSISTENCY_HASH = "aclconsistencyhash";
|
public static final String MOVE_ACL_CONSISTENCY_HASH = "aclconsistencyhash";
|
||||||
public static final String IMAGE_PATH = "imagepath";
|
public static final String IMAGE_PATH = "imagepath";
|
||||||
|
public static final String INSTANCE_CONVERSION_SUPPORTED = "instanceconversionsupported";
|
||||||
public static final String INTERNAL_DNS1 = "internaldns1";
|
public static final String INTERNAL_DNS1 = "internaldns1";
|
||||||
public static final String INTERNAL_DNS2 = "internaldns2";
|
public static final String INTERNAL_DNS2 = "internaldns2";
|
||||||
public static final String INTERNET_PROTOCOL = "internetprotocol";
|
public static final String INTERNET_PROTOCOL = "internetprotocol";
|
||||||
@ -1135,6 +1137,8 @@ public class ApiConstants {
|
|||||||
public static final String WEBHOOK_ID = "webhookid";
|
public static final String WEBHOOK_ID = "webhookid";
|
||||||
public static final String WEBHOOK_NAME = "webhookname";
|
public static final String WEBHOOK_NAME = "webhookname";
|
||||||
|
|
||||||
|
public static final String NFS_MOUNT_OPTIONS = "nfsmountopts";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This enum specifies IO Drivers, each option controls specific policies on I/O.
|
* This enum specifies IO Drivers, each option controls specific policies on I/O.
|
||||||
* Qemu guests support "threads" and "native" options Since 0.8.8 ; "io_uring" is supported Since 6.3.0 (QEMU 5.0).
|
* Qemu guests support "threads" and "native" options Since 0.8.8 ; "io_uring" is supported Since 6.3.0 (QEMU 5.0).
|
||||||
|
|||||||
@ -37,6 +37,7 @@ import org.apache.cloudstack.api.response.UserVmResponse;
|
|||||||
import org.apache.cloudstack.api.response.VmwareDatacenterResponse;
|
import org.apache.cloudstack.api.response.VmwareDatacenterResponse;
|
||||||
import org.apache.cloudstack.api.response.ZoneResponse;
|
import org.apache.cloudstack.api.response.ZoneResponse;
|
||||||
import org.apache.cloudstack.vm.VmImportService;
|
import org.apache.cloudstack.vm.VmImportService;
|
||||||
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
import org.apache.commons.lang3.ObjectUtils;
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
@ -116,40 +117,44 @@ public class ImportVmCmd extends ImportUnmanagedInstanceCmd {
|
|||||||
description = "Temp Path on external host for disk image copy" )
|
description = "Temp Path on external host for disk image copy" )
|
||||||
private String tmpPath;
|
private String tmpPath;
|
||||||
|
|
||||||
// Import from Vmware to KVM migration parameters
|
// Import from VMware to KVM migration parameters
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.EXISTING_VCENTER_ID,
|
@Parameter(name = ApiConstants.EXISTING_VCENTER_ID,
|
||||||
type = CommandType.UUID,
|
type = CommandType.UUID,
|
||||||
entityType = VmwareDatacenterResponse.class,
|
entityType = VmwareDatacenterResponse.class,
|
||||||
description = "(only for importing migrated VMs from Vmware to KVM) UUID of a linked existing vCenter")
|
description = "(only for importing VMs from VMware to KVM) UUID of a linked existing vCenter")
|
||||||
private Long existingVcenterId;
|
private Long existingVcenterId;
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.HOST_IP,
|
@Parameter(name = ApiConstants.HOST_IP,
|
||||||
type = BaseCmd.CommandType.STRING,
|
type = BaseCmd.CommandType.STRING,
|
||||||
description = "(only for importing migrated VMs from Vmware to KVM) VMware ESXi host IP/Name.")
|
description = "(only for importing VMs from VMware to KVM) VMware ESXi host IP/Name.")
|
||||||
private String hostip;
|
private String hostip;
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.VCENTER,
|
@Parameter(name = ApiConstants.VCENTER,
|
||||||
type = CommandType.STRING,
|
type = CommandType.STRING,
|
||||||
description = "(only for importing migrated VMs from Vmware to KVM) The name/ip of vCenter. Make sure it is IP address or full qualified domain name for host running vCenter server.")
|
description = "(only for importing VMs from VMware to KVM) The name/ip of vCenter. Make sure it is IP address or full qualified domain name for host running vCenter server.")
|
||||||
private String vcenter;
|
private String vcenter;
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.DATACENTER_NAME, type = CommandType.STRING,
|
@Parameter(name = ApiConstants.DATACENTER_NAME, type = CommandType.STRING,
|
||||||
description = "(only for importing migrated VMs from Vmware to KVM) Name of VMware datacenter.")
|
description = "(only for importing VMs from VMware to KVM) Name of VMware datacenter.")
|
||||||
private String datacenterName;
|
private String datacenterName;
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.CLUSTER_NAME, type = CommandType.STRING,
|
@Parameter(name = ApiConstants.CLUSTER_NAME, type = CommandType.STRING,
|
||||||
description = "(only for importing migrated VMs from Vmware to KVM) Name of VMware cluster.")
|
description = "(only for importing VMs from VMware to KVM) Name of VMware cluster.")
|
||||||
private String clusterName;
|
private String clusterName;
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.CONVERT_INSTANCE_HOST_ID, type = CommandType.UUID, entityType = HostResponse.class,
|
@Parameter(name = ApiConstants.CONVERT_INSTANCE_HOST_ID, type = CommandType.UUID, entityType = HostResponse.class,
|
||||||
description = "(only for importing migrated VMs from Vmware to KVM) optional - the host to perform the virt-v2v migration from VMware to KVM.")
|
description = "(only for importing VMs from VMware to KVM) optional - the host to perform the virt-v2v migration from VMware to KVM.")
|
||||||
private Long convertInstanceHostId;
|
private Long convertInstanceHostId;
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.CONVERT_INSTANCE_STORAGE_POOL_ID, type = CommandType.UUID, entityType = StoragePoolResponse.class,
|
@Parameter(name = ApiConstants.CONVERT_INSTANCE_STORAGE_POOL_ID, type = CommandType.UUID, entityType = StoragePoolResponse.class,
|
||||||
description = "(only for importing migrated VMs from Vmware to KVM) optional - the temporary storage pool to perform the virt-v2v migration from VMware to KVM.")
|
description = "(only for importing VMs from VMware to KVM) optional - the temporary storage pool to perform the virt-v2v migration from VMware to KVM.")
|
||||||
private Long convertStoragePoolId;
|
private Long convertStoragePoolId;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.FORCE_MS_TO_IMPORT_VM_FILES, type = CommandType.BOOLEAN,
|
||||||
|
description = "(only for importing VMs from VMware to KVM) optional - if true, forces MS to import VM file(s) to temporary storage, else uses KVM Host if ovftool is available, falls back to MS if not.")
|
||||||
|
private Boolean forceMsToImportVmFiles;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////////// Accessors ///////////////////////
|
/////////////////// Accessors ///////////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
@ -198,6 +203,10 @@ public class ImportVmCmd extends ImportUnmanagedInstanceCmd {
|
|||||||
return convertStoragePoolId;
|
return convertStoragePoolId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean getForceMsToImportVmFiles() {
|
||||||
|
return BooleanUtils.toBooleanDefaultIfNull(forceMsToImportVmFiles, false);
|
||||||
|
}
|
||||||
|
|
||||||
public String getHypervisor() {
|
public String getHypervisor() {
|
||||||
return hypervisor;
|
return hypervisor;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -72,7 +72,7 @@ public class AssignToLoadBalancerRuleCmd extends BaseAsyncCmd {
|
|||||||
|
|
||||||
@Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID_IP,
|
@Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID_IP,
|
||||||
type = CommandType.MAP,
|
type = CommandType.MAP,
|
||||||
description = "VM ID and IP map, vmidipmap[0].vmid=1 vmidipmap[0].ip=10.1.1.75",
|
description = "VM ID and IP map, vmidipmap[0].vmid=1 vmidipmap[0].vmip=10.1.1.75",
|
||||||
since = "4.4")
|
since = "4.4")
|
||||||
private Map vmIdIpMap;
|
private Map vmIdIpMap;
|
||||||
|
|
||||||
|
|||||||
@ -29,6 +29,7 @@ import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement;
|
|||||||
|
|
||||||
import com.cloud.host.Host;
|
import com.cloud.host.Host;
|
||||||
import com.cloud.host.Status;
|
import com.cloud.host.Status;
|
||||||
|
import com.cloud.hypervisor.Hypervisor;
|
||||||
import com.cloud.serializer.Param;
|
import com.cloud.serializer.Param;
|
||||||
import com.google.gson.annotations.SerializedName;
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
@ -285,6 +286,10 @@ public class HostResponse extends BaseResponseWithAnnotations {
|
|||||||
@Param(description = "true if the host supports encryption", since = "4.18")
|
@Param(description = "true if the host supports encryption", since = "4.18")
|
||||||
private Boolean encryptionSupported;
|
private Boolean encryptionSupported;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.INSTANCE_CONVERSION_SUPPORTED)
|
||||||
|
@Param(description = "true if the host supports instance conversion (using virt-v2v)", since = "4.19.1")
|
||||||
|
private Boolean instanceConversionSupported;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getObjectId() {
|
public String getObjectId() {
|
||||||
return this.getId();
|
return this.getId();
|
||||||
@ -550,7 +555,7 @@ public class HostResponse extends BaseResponseWithAnnotations {
|
|||||||
this.username = username;
|
this.username = username;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDetails(Map details) {
|
public void setDetails(Map details, Hypervisor.HypervisorType hypervisorType) {
|
||||||
|
|
||||||
if (details == null) {
|
if (details == null) {
|
||||||
return;
|
return;
|
||||||
@ -571,6 +576,15 @@ public class HostResponse extends BaseResponseWithAnnotations {
|
|||||||
this.setEncryptionSupported(new Boolean(false)); // default
|
this.setEncryptionSupported(new Boolean(false)); // default
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Hypervisor.HypervisorType.KVM.equals(hypervisorType)) {
|
||||||
|
if (detailsCopy.containsKey(Host.HOST_INSTANCE_CONVERSION)) {
|
||||||
|
this.setInstanceConversionSupported(Boolean.parseBoolean((String) detailsCopy.get(Host.HOST_INSTANCE_CONVERSION)));
|
||||||
|
detailsCopy.remove(Host.HOST_INSTANCE_CONVERSION);
|
||||||
|
} else {
|
||||||
|
this.setInstanceConversionSupported(new Boolean(false)); // default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.details = detailsCopy;
|
this.details = detailsCopy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -761,6 +775,10 @@ public class HostResponse extends BaseResponseWithAnnotations {
|
|||||||
this.encryptionSupported = encryptionSupported;
|
this.encryptionSupported = encryptionSupported;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setInstanceConversionSupported(Boolean instanceConversionSupported) {
|
||||||
|
this.instanceConversionSupported = instanceConversionSupported;
|
||||||
|
}
|
||||||
|
|
||||||
public Boolean getIsTagARule() {
|
public Boolean getIsTagARule() {
|
||||||
return isTagARule;
|
return isTagARule;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -101,6 +101,10 @@ public class StoragePoolResponse extends BaseResponseWithAnnotations {
|
|||||||
@Param(description = "the tags for the storage pool")
|
@Param(description = "the tags for the storage pool")
|
||||||
private String tags;
|
private String tags;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.NFS_MOUNT_OPTIONS)
|
||||||
|
@Param(description = "the nfs mount options for the storage pool", since = "4.19.1")
|
||||||
|
private String nfsMountOpts;
|
||||||
|
|
||||||
@SerializedName(ApiConstants.IS_TAG_A_RULE)
|
@SerializedName(ApiConstants.IS_TAG_A_RULE)
|
||||||
@Param(description = ApiConstants.PARAMETER_DESCRIPTION_IS_TAG_A_RULE)
|
@Param(description = ApiConstants.PARAMETER_DESCRIPTION_IS_TAG_A_RULE)
|
||||||
private Boolean isTagARule;
|
private Boolean isTagARule;
|
||||||
@ -347,4 +351,12 @@ public class StoragePoolResponse extends BaseResponseWithAnnotations {
|
|||||||
public void setProvider(String provider) {
|
public void setProvider(String provider) {
|
||||||
this.provider = provider;
|
this.provider = provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getNfsMountOpts() {
|
||||||
|
return nfsMountOpts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNfsMountOpts(String nfsMountOpts) {
|
||||||
|
this.nfsMountOpts = nfsMountOpts;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,6 +17,8 @@
|
|||||||
|
|
||||||
package org.apache.cloudstack.vm;
|
package org.apache.cloudstack.vm;
|
||||||
|
|
||||||
|
import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class UnmanagedInstanceTO {
|
public class UnmanagedInstanceTO {
|
||||||
@ -317,6 +319,16 @@ public class UnmanagedInstanceTO {
|
|||||||
public int getDatastorePort() {
|
public int getDatastorePort() {
|
||||||
return datastorePort;
|
return datastorePort;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Disk {" +
|
||||||
|
"diskId='" + diskId + '\'' +
|
||||||
|
", capacity=" + toHumanReadableSize(capacity) +
|
||||||
|
", controller='" + controller + '\'' +
|
||||||
|
", controllerUnit=" + controllerUnit +
|
||||||
|
"}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Nic {
|
public static class Nic {
|
||||||
@ -409,5 +421,14 @@ public class UnmanagedInstanceTO {
|
|||||||
public void setPciSlot(String pciSlot) {
|
public void setPciSlot(String pciSlot) {
|
||||||
this.pciSlot = pciSlot;
|
this.pciSlot = pciSlot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Nic{" +
|
||||||
|
"nicId='" + nicId + '\'' +
|
||||||
|
", adapterType='" + adapterType + '\'' +
|
||||||
|
", macAddress='" + macAddress + '\'' +
|
||||||
|
"}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,6 +39,37 @@ public interface UnmanagedVMsManager extends VmImportService, UnmanageVMService,
|
|||||||
ConfigKey.Scope.Global,
|
ConfigKey.Scope.Global,
|
||||||
null);
|
null);
|
||||||
|
|
||||||
|
ConfigKey<Integer> ConvertVmwareInstanceToKvmTimeout = new ConfigKey<>(Integer.class,
|
||||||
|
"convert.vmware.instance.to.kvm.timeout",
|
||||||
|
"Advanced",
|
||||||
|
"3",
|
||||||
|
"Timeout (in hours) for the instance conversion process from VMware through the virt-v2v binary on a KVM host",
|
||||||
|
true,
|
||||||
|
ConfigKey.Scope.Global,
|
||||||
|
null);
|
||||||
|
|
||||||
|
ConfigKey<Integer> ThreadsOnMSToImportVMwareVMFiles = new ConfigKey<>(Integer.class,
|
||||||
|
"threads.on.ms.to.import.vmware.vm.files",
|
||||||
|
"Advanced",
|
||||||
|
"0",
|
||||||
|
"Threads to use on the management server when importing VM files from VMWare." +
|
||||||
|
" -1 or 1 disables threads, 0 uses a thread per VM disk (disabled for single disk) and >1 for manual thread configuration." +
|
||||||
|
" Max number is 10, Default is 0.",
|
||||||
|
true,
|
||||||
|
ConfigKey.Scope.Global,
|
||||||
|
null);
|
||||||
|
|
||||||
|
ConfigKey<Integer> ThreadsOnKVMHostToImportVMwareVMFiles = new ConfigKey<>(Integer.class,
|
||||||
|
"threads.on.kvm.host.to.import.vmware.vm.files",
|
||||||
|
"Advanced",
|
||||||
|
"0",
|
||||||
|
"Threads to use on the KVM host (by the ovftool, if the version is 4.4.0+) when importing VM files from VMWare." +
|
||||||
|
" -1 or 1 disables threads, 0 uses a thread per VM disk (disabled for single disk) and >1 for manual thread configuration." +
|
||||||
|
" Max number is 10, Default is 0.",
|
||||||
|
true,
|
||||||
|
ConfigKey.Scope.Global,
|
||||||
|
null);
|
||||||
|
|
||||||
static boolean isSupported(Hypervisor.HypervisorType hypervisorType) {
|
static boolean isSupported(Hypervisor.HypervisorType hypervisorType) {
|
||||||
return hypervisorType == VMware || hypervisorType == KVM;
|
return hypervisorType == VMware || hypervisorType == KVM;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,6 +23,8 @@ import org.junit.Test;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.cloud.hypervisor.Hypervisor;
|
||||||
|
|
||||||
public final class HostResponseTest extends TestCase {
|
public final class HostResponseTest extends TestCase {
|
||||||
|
|
||||||
private static final String VALID_KEY = "validkey";
|
private static final String VALID_KEY = "validkey";
|
||||||
@ -32,7 +34,7 @@ public final class HostResponseTest extends TestCase {
|
|||||||
public void testSetDetailsNull() {
|
public void testSetDetailsNull() {
|
||||||
|
|
||||||
final HostResponse hostResponse = new HostResponse();
|
final HostResponse hostResponse = new HostResponse();
|
||||||
hostResponse.setDetails(null);
|
hostResponse.setDetails(null, null);
|
||||||
|
|
||||||
assertEquals(null, hostResponse.getDetails());
|
assertEquals(null, hostResponse.getDetails());
|
||||||
|
|
||||||
@ -51,7 +53,7 @@ public final class HostResponseTest extends TestCase {
|
|||||||
final Map expectedDetails = new HashedMap();
|
final Map expectedDetails = new HashedMap();
|
||||||
expectedDetails.put(VALID_KEY, VALID_VALUE);
|
expectedDetails.put(VALID_KEY, VALID_VALUE);
|
||||||
|
|
||||||
hostResponse.setDetails(details);
|
hostResponse.setDetails(details, Hypervisor.HypervisorType.KVM);
|
||||||
final Map actualDetails = hostResponse.getDetails();
|
final Map actualDetails = hostResponse.getDetails();
|
||||||
|
|
||||||
assertTrue(details != actualDetails);
|
assertTrue(details != actualDetails);
|
||||||
@ -70,7 +72,7 @@ public final class HostResponseTest extends TestCase {
|
|||||||
final Map expectedDetails = new HashedMap();
|
final Map expectedDetails = new HashedMap();
|
||||||
expectedDetails.put(VALID_KEY, VALID_VALUE);
|
expectedDetails.put(VALID_KEY, VALID_VALUE);
|
||||||
|
|
||||||
hostResponse.setDetails(details);
|
hostResponse.setDetails(details, Hypervisor.HypervisorType.KVM);
|
||||||
final Map actualDetails = hostResponse.getDetails();
|
final Map actualDetails = hostResponse.getDetails();
|
||||||
|
|
||||||
assertTrue(details != actualDetails);
|
assertTrue(details != actualDetails);
|
||||||
|
|||||||
@ -0,0 +1,43 @@
|
|||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you under the Apache License, Version 2.0 (the
|
||||||
|
// "License"); you may not use this file except in compliance
|
||||||
|
// with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing,
|
||||||
|
// software distributed under the License is distributed on an
|
||||||
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations
|
||||||
|
// under the License.
|
||||||
|
package com.cloud.agent.api;
|
||||||
|
|
||||||
|
public class CheckConvertInstanceAnswer extends Answer {
|
||||||
|
|
||||||
|
private boolean ovfExportSupported = false;
|
||||||
|
|
||||||
|
public CheckConvertInstanceAnswer() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CheckConvertInstanceAnswer(Command command, boolean success) {
|
||||||
|
super(command, success, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public CheckConvertInstanceAnswer(Command command, boolean success, String details) {
|
||||||
|
super(command, success, details);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CheckConvertInstanceAnswer(Command command, boolean success, boolean ovfExportSupported, String details) {
|
||||||
|
super(command, success, details);
|
||||||
|
this.ovfExportSupported = ovfExportSupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOvfExportSupported() {
|
||||||
|
return ovfExportSupported;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you under the Apache License, Version 2.0 (the
|
||||||
|
// "License"); you may not use this file except in compliance
|
||||||
|
// with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing,
|
||||||
|
// software distributed under the License is distributed on an
|
||||||
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations
|
||||||
|
// under the License.
|
||||||
|
package com.cloud.agent.api;
|
||||||
|
|
||||||
|
public class CheckConvertInstanceCommand extends Command {
|
||||||
|
boolean checkWindowsGuestConversionSupport = false;
|
||||||
|
|
||||||
|
public CheckConvertInstanceCommand() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public CheckConvertInstanceCommand(boolean checkWindowsGuestConversionSupport) {
|
||||||
|
this.checkWindowsGuestConversionSupport = checkWindowsGuestConversionSupport;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean executeInSequence() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getCheckWindowsGuestConversionSupport() {
|
||||||
|
return checkWindowsGuestConversionSupport;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -28,16 +28,24 @@ public class ConvertInstanceCommand extends Command {
|
|||||||
private Hypervisor.HypervisorType destinationHypervisorType;
|
private Hypervisor.HypervisorType destinationHypervisorType;
|
||||||
private List<String> destinationStoragePools;
|
private List<String> destinationStoragePools;
|
||||||
private DataStoreTO conversionTemporaryLocation;
|
private DataStoreTO conversionTemporaryLocation;
|
||||||
|
private String templateDirOnConversionLocation;
|
||||||
|
private boolean checkConversionSupport;
|
||||||
|
private boolean exportOvfToConversionLocation;
|
||||||
|
private int threadsCountToExportOvf = 0;
|
||||||
|
|
||||||
public ConvertInstanceCommand() {
|
public ConvertInstanceCommand() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConvertInstanceCommand(RemoteInstanceTO sourceInstance, Hypervisor.HypervisorType destinationHypervisorType,
|
public ConvertInstanceCommand(RemoteInstanceTO sourceInstance, Hypervisor.HypervisorType destinationHypervisorType,
|
||||||
List<String> destinationStoragePools, DataStoreTO conversionTemporaryLocation) {
|
List<String> destinationStoragePools, DataStoreTO conversionTemporaryLocation,
|
||||||
|
String templateDirOnConversionLocation, boolean checkConversionSupport, boolean exportOvfToConversionLocation) {
|
||||||
this.sourceInstance = sourceInstance;
|
this.sourceInstance = sourceInstance;
|
||||||
this.destinationHypervisorType = destinationHypervisorType;
|
this.destinationHypervisorType = destinationHypervisorType;
|
||||||
this.destinationStoragePools = destinationStoragePools;
|
this.destinationStoragePools = destinationStoragePools;
|
||||||
this.conversionTemporaryLocation = conversionTemporaryLocation;
|
this.conversionTemporaryLocation = conversionTemporaryLocation;
|
||||||
|
this.templateDirOnConversionLocation = templateDirOnConversionLocation;
|
||||||
|
this.checkConversionSupport = checkConversionSupport;
|
||||||
|
this.exportOvfToConversionLocation = exportOvfToConversionLocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RemoteInstanceTO getSourceInstance() {
|
public RemoteInstanceTO getSourceInstance() {
|
||||||
@ -56,6 +64,26 @@ public class ConvertInstanceCommand extends Command {
|
|||||||
return conversionTemporaryLocation;
|
return conversionTemporaryLocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getTemplateDirOnConversionLocation() {
|
||||||
|
return templateDirOnConversionLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getCheckConversionSupport() {
|
||||||
|
return checkConversionSupport;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getExportOvfToConversionLocation() {
|
||||||
|
return exportOvfToConversionLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getThreadsCountToExportOvf() {
|
||||||
|
return threadsCountToExportOvf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setThreadsCountToExportOvf(int threadsCountToExportOvf) {
|
||||||
|
this.threadsCountToExportOvf = threadsCountToExportOvf;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean executeInSequence() {
|
public boolean executeInSequence() {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -46,6 +46,10 @@ public class ModifyStoragePoolCommand extends Command {
|
|||||||
this.details = details;
|
this.details = details;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ModifyStoragePoolCommand(boolean add, StoragePool pool, Map<String, String> details) {
|
||||||
|
this(add, pool, LOCAL_PATH_PREFIX + File.separator + UUID.nameUUIDFromBytes((pool.getHostAddress() + pool.getPath()).getBytes()), details);
|
||||||
|
}
|
||||||
|
|
||||||
public ModifyStoragePoolCommand(boolean add, StoragePool pool) {
|
public ModifyStoragePoolCommand(boolean add, StoragePool pool) {
|
||||||
this(add, pool, LOCAL_PATH_PREFIX + File.separator + UUID.nameUUIDFromBytes((pool.getHostAddress() + pool.getPath()).getBytes()));
|
this(add, pool, LOCAL_PATH_PREFIX + File.separator + UUID.nameUUIDFromBytes((pool.getHostAddress() + pool.getPath()).getBytes()));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -126,6 +126,8 @@ public interface ResourceManager extends ResourceService, Configurable {
|
|||||||
|
|
||||||
public List<HostVO> listAllUpAndEnabledHostsInOneZoneByHypervisor(HypervisorType type, long dcId);
|
public List<HostVO> listAllUpAndEnabledHostsInOneZoneByHypervisor(HypervisorType type, long dcId);
|
||||||
|
|
||||||
|
public List<HostVO> listAllUpHostsInOneZoneByHypervisor(HypervisorType type, long dcId);
|
||||||
|
|
||||||
public List<HostVO> listAllUpAndEnabledHostsInOneZone(long dcId);
|
public List<HostVO> listAllUpAndEnabledHostsInOneZone(long dcId);
|
||||||
|
|
||||||
public List<HostVO> listAllHostsInOneZoneByType(Host.Type type, long dcId);
|
public List<HostVO> listAllHostsInOneZoneByType(Host.Type type, long dcId);
|
||||||
|
|||||||
@ -18,6 +18,7 @@ package com.cloud.storage;
|
|||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener;
|
import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener;
|
||||||
@ -96,14 +97,6 @@ public interface StorageManager extends StorageService {
|
|||||||
true,
|
true,
|
||||||
ConfigKey.Scope.Global,
|
ConfigKey.Scope.Global,
|
||||||
null);
|
null);
|
||||||
ConfigKey<Integer> ConvertVmwareInstanceToKvmTimeout = new ConfigKey<>(Integer.class,
|
|
||||||
"convert.vmware.instance.to.kvm.timeout",
|
|
||||||
"Storage",
|
|
||||||
"8",
|
|
||||||
"Timeout (in hours) for the instance conversion process from VMware through the virt-v2v binary on a KVM host",
|
|
||||||
true,
|
|
||||||
ConfigKey.Scope.Global,
|
|
||||||
null);
|
|
||||||
ConfigKey<Boolean> KvmAutoConvergence = new ConfigKey<>(Boolean.class,
|
ConfigKey<Boolean> KvmAutoConvergence = new ConfigKey<>(Boolean.class,
|
||||||
"kvm.auto.convergence",
|
"kvm.auto.convergence",
|
||||||
"Storage",
|
"Storage",
|
||||||
@ -348,6 +341,10 @@ public interface StorageManager extends StorageService {
|
|||||||
|
|
||||||
boolean registerHostListener(String providerUuid, HypervisorHostListener listener);
|
boolean registerHostListener(String providerUuid, HypervisorHostListener listener);
|
||||||
|
|
||||||
|
Pair<Map<String, String>, Boolean> getStoragePoolNFSMountOpts(StoragePool pool, Map<String, String> details);
|
||||||
|
|
||||||
|
String getStoragePoolMountFailureReason(String error);
|
||||||
|
|
||||||
boolean connectHostToSharedPool(long hostId, long poolId) throws StorageUnavailableException, StorageConflictException;
|
boolean connectHostToSharedPool(long hostId, long poolId) throws StorageUnavailableException, StorageConflictException;
|
||||||
|
|
||||||
void disconnectHostFromSharedPool(long hostId, long poolId) throws StorageUnavailableException, StorageConflictException;
|
void disconnectHostFromSharedPool(long hostId, long poolId) throws StorageUnavailableException, StorageConflictException;
|
||||||
|
|||||||
@ -264,11 +264,13 @@ public class VirtualMachineProfileImpl implements VirtualMachineProfile {
|
|||||||
_offering = offering;
|
_offering = offering;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setCpuOvercommitRatio(Float cpuOvercommitRatio) {
|
public void setCpuOvercommitRatio(Float cpuOvercommitRatio) {
|
||||||
this.cpuOvercommitRatio = cpuOvercommitRatio;
|
this.cpuOvercommitRatio = cpuOvercommitRatio;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setMemoryOvercommitRatio(Float memoryOvercommitRatio) {
|
public void setMemoryOvercommitRatio(Float memoryOvercommitRatio) {
|
||||||
this.memoryOvercommitRatio = memoryOvercommitRatio;
|
this.memoryOvercommitRatio = memoryOvercommitRatio;
|
||||||
|
|
||||||
|
|||||||
@ -45,6 +45,8 @@ import com.cloud.agent.api.CheckOnHostCommand;
|
|||||||
import com.cloud.agent.api.CheckVirtualMachineCommand;
|
import com.cloud.agent.api.CheckVirtualMachineCommand;
|
||||||
import com.cloud.agent.api.CleanupNetworkRulesCmd;
|
import com.cloud.agent.api.CleanupNetworkRulesCmd;
|
||||||
import com.cloud.agent.api.Command;
|
import com.cloud.agent.api.Command;
|
||||||
|
import com.cloud.agent.api.CreateStoragePoolCommand;
|
||||||
|
import com.cloud.agent.api.DeleteStoragePoolCommand;
|
||||||
import com.cloud.agent.api.MaintainCommand;
|
import com.cloud.agent.api.MaintainCommand;
|
||||||
import com.cloud.agent.api.MigrateCommand;
|
import com.cloud.agent.api.MigrateCommand;
|
||||||
import com.cloud.agent.api.ModifySshKeysCommand;
|
import com.cloud.agent.api.ModifySshKeysCommand;
|
||||||
@ -122,8 +124,9 @@ public abstract class AgentAttache {
|
|||||||
StopCommand.class.toString(), CheckVirtualMachineCommand.class.toString(), PingTestCommand.class.toString(), CheckHealthCommand.class.toString(),
|
StopCommand.class.toString(), CheckVirtualMachineCommand.class.toString(), PingTestCommand.class.toString(), CheckHealthCommand.class.toString(),
|
||||||
ReadyCommand.class.toString(), ShutdownCommand.class.toString(), SetupCommand.class.toString(),
|
ReadyCommand.class.toString(), ShutdownCommand.class.toString(), SetupCommand.class.toString(),
|
||||||
CleanupNetworkRulesCmd.class.toString(), CheckNetworkCommand.class.toString(), PvlanSetupCommand.class.toString(), CheckOnHostCommand.class.toString(),
|
CleanupNetworkRulesCmd.class.toString(), CheckNetworkCommand.class.toString(), PvlanSetupCommand.class.toString(), CheckOnHostCommand.class.toString(),
|
||||||
ModifyTargetsCommand.class.toString(), ModifySshKeysCommand.class.toString(), ModifyStoragePoolCommand.class.toString(), SetupMSListCommand.class.toString(), RollingMaintenanceCommand.class.toString(),
|
ModifyTargetsCommand.class.toString(), ModifySshKeysCommand.class.toString(),
|
||||||
CleanupPersistentNetworkResourceCommand.class.toString()};
|
CreateStoragePoolCommand.class.toString(), DeleteStoragePoolCommand.class.toString(), ModifyStoragePoolCommand.class.toString(),
|
||||||
|
SetupMSListCommand.class.toString(), RollingMaintenanceCommand.class.toString(), CleanupPersistentNetworkResourceCommand.class.toString()};
|
||||||
protected final static String[] s_commandsNotAllowedInConnectingMode = new String[] { StartCommand.class.toString(), CreateCommand.class.toString() };
|
protected final static String[] s_commandsNotAllowedInConnectingMode = new String[] { StartCommand.class.toString(), CreateCommand.class.toString() };
|
||||||
static {
|
static {
|
||||||
Arrays.sort(s_commandsAllowedInMaintenanceMode);
|
Arrays.sort(s_commandsAllowedInMaintenanceMode);
|
||||||
|
|||||||
@ -1230,21 +1230,9 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||||||
|
|
||||||
long destHostId = dest.getHost().getId();
|
long destHostId = dest.getHost().getId();
|
||||||
vm.setPodIdToDeployIn(dest.getPod().getId());
|
vm.setPodIdToDeployIn(dest.getPod().getId());
|
||||||
final Long cluster_id = dest.getCluster().getId();
|
final Long clusterId = dest.getCluster().getId();
|
||||||
final ClusterDetailsVO cluster_detail_cpu = _clusterDetailsDao.findDetail(cluster_id, VmDetailConstants.CPU_OVER_COMMIT_RATIO);
|
updateOverCommitRatioForVmProfile(vmProfile, clusterId);
|
||||||
final ClusterDetailsVO cluster_detail_ram = _clusterDetailsDao.findDetail(cluster_id, VmDetailConstants.MEMORY_OVER_COMMIT_RATIO);
|
|
||||||
|
|
||||||
if (userVmDetailsDao.findDetail(vm.getId(), VmDetailConstants.CPU_OVER_COMMIT_RATIO) == null &&
|
|
||||||
(Float.parseFloat(cluster_detail_cpu.getValue()) > 1f || Float.parseFloat(cluster_detail_ram.getValue()) > 1f)) {
|
|
||||||
userVmDetailsDao.addDetail(vm.getId(), VmDetailConstants.CPU_OVER_COMMIT_RATIO, cluster_detail_cpu.getValue(), true);
|
|
||||||
userVmDetailsDao.addDetail(vm.getId(), VmDetailConstants.MEMORY_OVER_COMMIT_RATIO, cluster_detail_ram.getValue(), true);
|
|
||||||
} else if (userVmDetailsDao.findDetail(vm.getId(), VmDetailConstants.CPU_OVER_COMMIT_RATIO) != null) {
|
|
||||||
userVmDetailsDao.addDetail(vm.getId(), VmDetailConstants.CPU_OVER_COMMIT_RATIO, cluster_detail_cpu.getValue(), true);
|
|
||||||
userVmDetailsDao.addDetail(vm.getId(), VmDetailConstants.MEMORY_OVER_COMMIT_RATIO, cluster_detail_ram.getValue(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
vmProfile.setCpuOvercommitRatio(Float.parseFloat(cluster_detail_cpu.getValue()));
|
|
||||||
vmProfile.setMemoryOvercommitRatio(Float.parseFloat(cluster_detail_ram.getValue()));
|
|
||||||
StartAnswer startAnswer = null;
|
StartAnswer startAnswer = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -1259,7 +1247,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||||||
resetVmNicsDeviceId(vm.getId());
|
resetVmNicsDeviceId(vm.getId());
|
||||||
_networkMgr.prepare(vmProfile, dest, ctx);
|
_networkMgr.prepare(vmProfile, dest, ctx);
|
||||||
if (vm.getHypervisorType() != HypervisorType.BareMetal) {
|
if (vm.getHypervisorType() != HypervisorType.BareMetal) {
|
||||||
checkAndAttemptMigrateVmAcrossCluster(vm, cluster_id, dest.getStorageForDisks());
|
checkAndAttemptMigrateVmAcrossCluster(vm, clusterId, dest.getStorageForDisks());
|
||||||
volumeMgr.prepare(vmProfile, dest);
|
volumeMgr.prepare(vmProfile, dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1504,6 +1492,27 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||||||
networkToNetworkNameMap.put(networkVO.getId(), networkName);
|
networkToNetworkNameMap.put(networkVO.getId(), networkName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateOverCommitRatioForVmProfile(VirtualMachineProfile vmProfile, long clusterId) {
|
||||||
|
final ClusterDetailsVO clusterDetailCpu = _clusterDetailsDao.findDetail(clusterId, VmDetailConstants.CPU_OVER_COMMIT_RATIO);
|
||||||
|
final ClusterDetailsVO clusterDetailRam = _clusterDetailsDao.findDetail(clusterId, VmDetailConstants.MEMORY_OVER_COMMIT_RATIO);
|
||||||
|
final float parsedClusterCpuDetailCpu = Float.parseFloat(clusterDetailCpu.getValue());
|
||||||
|
final float parsedClusterDetailRam = Float.parseFloat(clusterDetailRam.getValue());
|
||||||
|
UserVmDetailVO vmDetailCpu = userVmDetailsDao.findDetail(vmProfile.getId(), VmDetailConstants.CPU_OVER_COMMIT_RATIO);
|
||||||
|
UserVmDetailVO vmDetailRam = userVmDetailsDao.findDetail(vmProfile.getId(), VmDetailConstants.MEMORY_OVER_COMMIT_RATIO);
|
||||||
|
|
||||||
|
if ((vmDetailCpu == null && parsedClusterCpuDetailCpu > 1f) ||
|
||||||
|
(vmDetailCpu != null && Float.parseFloat(vmDetailCpu.getValue()) != parsedClusterCpuDetailCpu)) {
|
||||||
|
userVmDetailsDao.addDetail(vmProfile.getId(), VmDetailConstants.CPU_OVER_COMMIT_RATIO, clusterDetailCpu.getValue(), true);
|
||||||
|
}
|
||||||
|
if ((vmDetailRam == null && parsedClusterDetailRam > 1f) ||
|
||||||
|
(vmDetailRam != null && Float.parseFloat(vmDetailRam.getValue()) != parsedClusterDetailRam)) {
|
||||||
|
userVmDetailsDao.addDetail(vmProfile.getId(), VmDetailConstants.MEMORY_OVER_COMMIT_RATIO, clusterDetailRam.getValue(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
vmProfile.setCpuOvercommitRatio(Float.parseFloat(clusterDetailCpu.getValue()));
|
||||||
|
vmProfile.setMemoryOvercommitRatio(Float.parseFloat(clusterDetailRam.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setting pod id to null can result in migration of Volumes across pods. This is not desirable for VMs which
|
* Setting pod id to null can result in migration of Volumes across pods. This is not desirable for VMs which
|
||||||
* have a volume in Ready state (happens when a VM is shutdown and started again).
|
* have a volume in Ready state (happens when a VM is shutdown and started again).
|
||||||
@ -2001,20 +2010,24 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updatePersistenceMap(Map<String, Boolean> vlanToPersistenceMap, NetworkVO networkVO) {
|
private void updatePersistenceMap(Map<String, Boolean> vlanToPersistenceMap, NetworkVO networkVO) {
|
||||||
|
if (networkVO == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
NetworkOfferingVO offeringVO = networkOfferingDao.findById(networkVO.getNetworkOfferingId());
|
NetworkOfferingVO offeringVO = networkOfferingDao.findById(networkVO.getNetworkOfferingId());
|
||||||
if (offeringVO != null) {
|
if (offeringVO == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
Pair<String, Boolean> data = getVMNetworkDetails(networkVO, offeringVO.isPersistent());
|
Pair<String, Boolean> data = getVMNetworkDetails(networkVO, offeringVO.isPersistent());
|
||||||
Boolean shouldDeleteNwResource = (MapUtils.isNotEmpty(vlanToPersistenceMap) && data != null) ? vlanToPersistenceMap.get(data.first()) : null;
|
Boolean shouldDeleteNwResource = (MapUtils.isNotEmpty(vlanToPersistenceMap) && data != null) ? vlanToPersistenceMap.get(data.first()) : null;
|
||||||
if (data != null && (shouldDeleteNwResource == null || shouldDeleteNwResource)) {
|
if (data != null && (shouldDeleteNwResource == null || shouldDeleteNwResource)) {
|
||||||
vlanToPersistenceMap.put(data.first(), data.second());
|
vlanToPersistenceMap.put(data.first(), data.second());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, Boolean> getVlanToPersistenceMapForVM(long vmId) {
|
private Map<String, Boolean> getVlanToPersistenceMapForVM(long vmId) {
|
||||||
List<UserVmJoinVO> userVmJoinVOs = userVmJoinDao.searchByIds(vmId);
|
List<UserVmJoinVO> userVmJoinVOs = userVmJoinDao.searchByIds(vmId);
|
||||||
Map<String, Boolean> vlanToPersistenceMap = new HashMap<>();
|
Map<String, Boolean> vlanToPersistenceMap = new HashMap<>();
|
||||||
if (userVmJoinVOs != null && !userVmJoinVOs.isEmpty()) {
|
if (CollectionUtils.isNotEmpty(userVmJoinVOs)) {
|
||||||
for (UserVmJoinVO userVmJoinVO : userVmJoinVOs) {
|
for (UserVmJoinVO userVmJoinVO : userVmJoinVOs) {
|
||||||
NetworkVO networkVO = _networkDao.findById(userVmJoinVO.getNetworkId());
|
NetworkVO networkVO = _networkDao.findById(userVmJoinVO.getNetworkId());
|
||||||
updatePersistenceMap(vlanToPersistenceMap, networkVO);
|
updatePersistenceMap(vlanToPersistenceMap, networkVO);
|
||||||
@ -2728,6 +2741,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||||||
_networkMgr.prepareNicForMigration(profile, dest);
|
_networkMgr.prepareNicForMigration(profile, dest);
|
||||||
volumeMgr.prepareForMigration(profile, dest);
|
volumeMgr.prepareForMigration(profile, dest);
|
||||||
profile.setConfigDriveLabel(VmConfigDriveLabel.value());
|
profile.setConfigDriveLabel(VmConfigDriveLabel.value());
|
||||||
|
updateOverCommitRatioForVmProfile(profile, dest.getHost().getClusterId());
|
||||||
|
|
||||||
final VirtualMachineTO to = toVmTO(profile);
|
final VirtualMachineTO to = toVmTO(profile);
|
||||||
final PrepareForMigrationCommand pfmc = new PrepareForMigrationCommand(to);
|
final PrepareForMigrationCommand pfmc = new PrepareForMigrationCommand(to);
|
||||||
@ -4777,6 +4791,18 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ApiCommandResourceType getApiCommandResourceTypeForVm(VirtualMachine vm) {
|
||||||
|
switch (vm.getType()) {
|
||||||
|
case DomainRouter:
|
||||||
|
return ApiCommandResourceType.DomainRouter;
|
||||||
|
case ConsoleProxy:
|
||||||
|
return ApiCommandResourceType.ConsoleProxy;
|
||||||
|
case SecondaryStorageVm:
|
||||||
|
return ApiCommandResourceType.SystemVm;
|
||||||
|
}
|
||||||
|
return ApiCommandResourceType.VirtualMachine;
|
||||||
|
}
|
||||||
|
|
||||||
private void handlePowerOnReportWithNoPendingJobsOnVM(final VMInstanceVO vm) {
|
private void handlePowerOnReportWithNoPendingJobsOnVM(final VMInstanceVO vm) {
|
||||||
Host host = _hostDao.findById(vm.getHostId());
|
Host host = _hostDao.findById(vm.getHostId());
|
||||||
Host poweredHost = _hostDao.findById(vm.getPowerHostId());
|
Host poweredHost = _hostDao.findById(vm.getPowerHostId());
|
||||||
@ -4824,7 +4850,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||||||
+ " -> Running) from out-of-context transition. VM network environment may need to be reset");
|
+ " -> Running) from out-of-context transition. VM network environment may need to be reset");
|
||||||
|
|
||||||
ActionEventUtils.onActionEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM, vm.getDomainId(),
|
ActionEventUtils.onActionEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM, vm.getDomainId(),
|
||||||
EventTypes.EVENT_VM_START, "Out of band VM power on", vm.getId(), ApiCommandResourceType.VirtualMachine.toString());
|
EventTypes.EVENT_VM_START, "Out of band VM power on", vm.getId(), getApiCommandResourceTypeForVm(vm).toString());
|
||||||
logger.info("VM {} is sync-ed to at Running state according to power-on report from hypervisor.", vm.getInstanceName());
|
logger.info("VM {} is sync-ed to at Running state according to power-on report from hypervisor.", vm.getInstanceName());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -4857,7 +4883,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||||||
case Running:
|
case Running:
|
||||||
case Stopped:
|
case Stopped:
|
||||||
ActionEventUtils.onActionEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM,vm.getDomainId(),
|
ActionEventUtils.onActionEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM,vm.getDomainId(),
|
||||||
EventTypes.EVENT_VM_STOP, "Out of band VM power off", vm.getId(), ApiCommandResourceType.VirtualMachine.toString());
|
EventTypes.EVENT_VM_STOP, "Out of band VM power off", vm.getId(), getApiCommandResourceTypeForVm(vm).toString());
|
||||||
case Migrating:
|
case Migrating:
|
||||||
logger.info("VM {} is at {} and we received a {} report while there is no pending jobs on it"
|
logger.info("VM {} is at {} and we received a {} report while there is no pending jobs on it"
|
||||||
, vm.getInstanceName(), vm.getState(), vm.getPowerState());
|
, vm.getInstanceName(), vm.getState(), vm.getPowerState());
|
||||||
|
|||||||
@ -765,6 +765,14 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure cidr size is equal to 64 for
|
||||||
|
// - networks other than shared networks
|
||||||
|
// - shared networks with SLAAC V6 only
|
||||||
|
if (predefined != null && StringUtils.isNotBlank(predefined.getIp6Cidr()) &&
|
||||||
|
(!GuestType.Shared.equals(offering.getGuestType()) || guru.isSlaacV6Only())) {
|
||||||
|
_networkModel.checkIp6CidrSizeEqualTo64(predefined.getIp6Cidr());
|
||||||
|
}
|
||||||
|
|
||||||
if (network.getId() != -1) {
|
if (network.getId() != -1) {
|
||||||
if (network instanceof NetworkVO) {
|
if (network instanceof NetworkVO) {
|
||||||
networks.add((NetworkVO) network);
|
networks.add((NetworkVO) network);
|
||||||
@ -1033,29 +1041,37 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@DB
|
private NicVO persistNicAfterRaceCheck(final NicVO nic, final Long networkId, final NicProfile profile, int deviceId) {
|
||||||
|
return Transaction.execute(new TransactionCallback<NicVO>() {
|
||||||
@Override
|
@Override
|
||||||
public Pair<NicProfile, Integer> allocateNic(final NicProfile requested, final Network network, final Boolean isDefaultNic, int deviceId, final VirtualMachineProfile vm)
|
public NicVO doInTransaction(TransactionStatus status) {
|
||||||
throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException, ConcurrentOperationException {
|
NicVO vo = _nicDao.findByIp4AddressAndNetworkId(profile.getIPv4Address(), networkId);
|
||||||
|
if (vo == null) {
|
||||||
|
applyProfileToNic(nic, profile, deviceId);
|
||||||
|
vo = _nicDao.persist(nic);
|
||||||
|
return vo;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private NicVO checkForRaceAndAllocateNic(final NicProfile requested, final Network network, final Boolean isDefaultNic, int deviceId, final VirtualMachineProfile vm)
|
||||||
|
throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException {
|
||||||
final NetworkVO ntwkVO = _networksDao.findById(network.getId());
|
final NetworkVO ntwkVO = _networksDao.findById(network.getId());
|
||||||
logger.debug("Allocating nic for vm {} in network {} with requested profile {}", vm.getVirtualMachine(), network, requested);
|
logger.debug("Allocating nic for vm {} in network {} with requested profile {}", vm.getVirtualMachine(), network, requested);
|
||||||
final NetworkGuru guru = AdapterBase.getAdapterByName(networkGurus, ntwkVO.getGuruName());
|
final NetworkGuru guru = AdapterBase.getAdapterByName(networkGurus, ntwkVO.getGuruName());
|
||||||
|
|
||||||
if (requested != null && requested.getMode() == null) {
|
NicVO vo = null;
|
||||||
requested.setMode(network.getMode());
|
boolean retryIpAllocation;
|
||||||
}
|
do {
|
||||||
|
retryIpAllocation = false;
|
||||||
final NicProfile profile = guru.allocate(network, requested, vm);
|
final NicProfile profile = guru.allocate(network, requested, vm);
|
||||||
if (profile == null) {
|
if (profile == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isNicAllocatedForNsxPublicNetworkOnVR(network, profile, vm)) {
|
|
||||||
String guruName = "NsxPublicNetworkGuru";
|
|
||||||
NetworkGuru nsxGuru = AdapterBase.getAdapterByName(networkGurus, guruName);
|
|
||||||
nsxGuru.allocate(network, profile, vm);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isDefaultNic != null) {
|
if (isDefaultNic != null) {
|
||||||
profile.setDefaultNic(isDefaultNic);
|
profile.setDefaultNic(isDefaultNic);
|
||||||
}
|
}
|
||||||
@ -1066,15 +1082,43 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
|
|||||||
profile.setMode(network.getMode());
|
profile.setMode(network.getMode());
|
||||||
}
|
}
|
||||||
|
|
||||||
NicVO vo = new NicVO(guru.getName(), vm.getId(), network.getId(), vm.getType());
|
vo = new NicVO(guru.getName(), vm.getId(), network.getId(), vm.getType());
|
||||||
|
|
||||||
DataCenterVO dcVo = _dcDao.findById(network.getDataCenterId());
|
DataCenterVO dcVo = _dcDao.findById(network.getDataCenterId());
|
||||||
if (dcVo.getNetworkType() == NetworkType.Basic) {
|
if (dcVo.getNetworkType() == NetworkType.Basic) {
|
||||||
configureNicProfileBasedOnRequestedIp(requested, profile, network);
|
configureNicProfileBasedOnRequestedIp(requested, profile, network);
|
||||||
}
|
}
|
||||||
|
|
||||||
deviceId = applyProfileToNic(vo, profile, deviceId);
|
if (profile.getIpv4AllocationRaceCheck()) {
|
||||||
|
vo = persistNicAfterRaceCheck(vo, network.getId(), profile, deviceId);
|
||||||
|
} else {
|
||||||
|
applyProfileToNic(vo, profile, deviceId);
|
||||||
vo = _nicDao.persist(vo);
|
vo = _nicDao.persist(vo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vo == null) {
|
||||||
|
if (requested.getRequestedIPv4() != null) {
|
||||||
|
throw new InsufficientVirtualNetworkCapacityException("Unable to acquire requested Guest IP address " + requested.getRequestedIPv4() + " for network " + network, DataCenter.class, dcVo.getId());
|
||||||
|
} else {
|
||||||
|
requested.setIPv4Address(null);
|
||||||
|
}
|
||||||
|
retryIpAllocation = true;
|
||||||
|
}
|
||||||
|
} while (retryIpAllocation);
|
||||||
|
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@DB
|
||||||
|
@Override
|
||||||
|
public Pair<NicProfile, Integer> allocateNic(final NicProfile requested, final Network network, final Boolean isDefaultNic, int deviceId, final VirtualMachineProfile vm)
|
||||||
|
throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException, ConcurrentOperationException {
|
||||||
|
|
||||||
|
if (requested != null && requested.getMode() == null) {
|
||||||
|
requested.setMode(network.getMode());
|
||||||
|
}
|
||||||
|
|
||||||
|
NicVO vo = checkForRaceAndAllocateNic(requested, network, isDefaultNic, deviceId, vm);
|
||||||
|
|
||||||
final Integer networkRate = _networkModel.getNetworkRate(network.getId(), vm.getId());
|
final Integer networkRate = _networkModel.getNetworkRate(network.getId(), vm.getId());
|
||||||
final NicProfile vmNic = new NicProfile(vo, network, vo.getBroadcastUri(), vo.getIsolationUri(), networkRate, _networkModel.isSecurityGroupSupportedInNetwork(network),
|
final NicProfile vmNic = new NicProfile(vo, network, vo.getBroadcastUri(), vo.getIsolationUri(), networkRate, _networkModel.isSecurityGroupSupportedInNetwork(network),
|
||||||
@ -2723,8 +2767,8 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ipv6 && NetUtils.getIp6CidrSize(ip6Cidr) != 64) {
|
if (ipv6 && !GuestType.Shared.equals(ntwkOff.getGuestType())) {
|
||||||
throw new InvalidParameterValueException("IPv6 subnet should be exactly 64-bits in size");
|
_networkModel.checkIp6CidrSizeEqualTo64(ip6Cidr);
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO(VXLAN): Support VNI specified
|
//TODO(VXLAN): Support VNI specified
|
||||||
@ -4605,10 +4649,16 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
|
|||||||
final NicVO vo = Transaction.execute(new TransactionCallback<NicVO>() {
|
final NicVO vo = Transaction.execute(new TransactionCallback<NicVO>() {
|
||||||
@Override
|
@Override
|
||||||
public NicVO doInTransaction(TransactionStatus status) {
|
public NicVO doInTransaction(TransactionStatus status) {
|
||||||
NicVO existingNic = _nicDao.findByNetworkIdAndMacAddress(network.getId(), macAddress);
|
if (StringUtils.isBlank(macAddress)) {
|
||||||
String macAddressToPersist = macAddress;
|
throw new CloudRuntimeException("Mac address not specified");
|
||||||
|
}
|
||||||
|
String macAddressToPersist = macAddress.trim();
|
||||||
|
if (!NetUtils.isValidMac(macAddressToPersist)) {
|
||||||
|
throw new CloudRuntimeException("Invalid mac address: " + macAddressToPersist);
|
||||||
|
}
|
||||||
|
NicVO existingNic = _nicDao.findByNetworkIdAndMacAddress(network.getId(), macAddressToPersist);
|
||||||
if (existingNic != null) {
|
if (existingNic != null) {
|
||||||
macAddressToPersist = generateNewMacAddressIfForced(network, macAddress, forced);
|
macAddressToPersist = generateNewMacAddressIfForced(network, macAddressToPersist, forced);
|
||||||
}
|
}
|
||||||
NicVO vo = new NicVO(network.getGuruName(), vm.getId(), network.getId(), vm.getType());
|
NicVO vo = new NicVO(network.getGuruName(), vm.getId(), network.getId(), vm.getType());
|
||||||
vo.setMacAddress(macAddressToPersist);
|
vo.setMacAddress(macAddressToPersist);
|
||||||
@ -4653,7 +4703,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
|
|||||||
final NicProfile vmNic = new NicProfile(vo, network, vo.getBroadcastUri(), vo.getIsolationUri(), networkRate, _networkModel.isSecurityGroupSupportedInNetwork(network),
|
final NicProfile vmNic = new NicProfile(vo, network, vo.getBroadcastUri(), vo.getIsolationUri(), networkRate, _networkModel.isSecurityGroupSupportedInNetwork(network),
|
||||||
_networkModel.getNetworkTag(vm.getHypervisorType(), network));
|
_networkModel.getNetworkTag(vm.getHypervisorType(), network));
|
||||||
|
|
||||||
return new Pair<NicProfile, Integer>(vmNic, Integer.valueOf(deviceId));
|
return new Pair<>(vmNic, Integer.valueOf(deviceId));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getSelectedIpForNicImport(Network network, DataCenter dataCenter, Network.IpAddresses ipAddresses) {
|
protected String getSelectedIpForNicImport(Network network, DataCenter dataCenter, Network.IpAddresses ipAddresses) {
|
||||||
@ -4697,7 +4747,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
|
|||||||
|
|
||||||
private String generateNewMacAddressIfForced(Network network, String macAddress, boolean forced) {
|
private String generateNewMacAddressIfForced(Network network, String macAddress, boolean forced) {
|
||||||
if (!forced) {
|
if (!forced) {
|
||||||
throw new CloudRuntimeException("NIC with MAC address = " + macAddress + " exists on network with ID = " + network.getId() +
|
throw new CloudRuntimeException("NIC with MAC address " + macAddress + " exists on network with ID " + network.getUuid() +
|
||||||
" and forced flag is disabled");
|
" and forced flag is disabled");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -17,6 +17,7 @@
|
|||||||
package org.apache.cloudstack.engine.orchestration;
|
package org.apache.cloudstack.engine.orchestration;
|
||||||
|
|
||||||
import static org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService.NetworkLockTimeout;
|
import static org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService.NetworkLockTimeout;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
@ -31,6 +32,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.cloud.dc.DataCenter;
|
import com.cloud.dc.DataCenter;
|
||||||
|
import com.cloud.exception.InsufficientVirtualNetworkCapacityException;
|
||||||
import com.cloud.network.IpAddressManager;
|
import com.cloud.network.IpAddressManager;
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
@ -39,6 +41,7 @@ import org.junit.Test;
|
|||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.junit.runners.JUnit4;
|
import org.junit.runners.JUnit4;
|
||||||
import org.mockito.ArgumentMatchers;
|
import org.mockito.ArgumentMatchers;
|
||||||
|
import org.mockito.MockedStatic;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
import com.cloud.api.query.dao.DomainRouterJoinDao;
|
import com.cloud.api.query.dao.DomainRouterJoinDao;
|
||||||
@ -71,6 +74,8 @@ import com.cloud.network.vpc.VpcManager;
|
|||||||
import com.cloud.network.vpc.VpcVO;
|
import com.cloud.network.vpc.VpcVO;
|
||||||
import com.cloud.offerings.NetworkOfferingVO;
|
import com.cloud.offerings.NetworkOfferingVO;
|
||||||
import com.cloud.utils.db.EntityManager;
|
import com.cloud.utils.db.EntityManager;
|
||||||
|
import com.cloud.utils.db.Transaction;
|
||||||
|
import com.cloud.utils.db.TransactionCallback;
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
import com.cloud.utils.net.Ip;
|
import com.cloud.utils.net.Ip;
|
||||||
import com.cloud.vm.DomainRouterVO;
|
import com.cloud.vm.DomainRouterVO;
|
||||||
@ -890,4 +895,118 @@ public class NetworkOrchestratorTest extends TestCase {
|
|||||||
verify(testOrchestrator._networksDao, times(1)).acquireInLockTable(networkId, NetworkLockTimeout.value());
|
verify(testOrchestrator._networksDao, times(1)).acquireInLockTable(networkId, NetworkLockTimeout.value());
|
||||||
verify(testOrchestrator._networksDao, times(1)).releaseFromLockTable(networkId);
|
verify(testOrchestrator._networksDao, times(1)).releaseFromLockTable(networkId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = InsufficientVirtualNetworkCapacityException.class)
|
||||||
|
public void testImportNicAcquireGuestIPFailed() throws Exception {
|
||||||
|
DataCenter dataCenter = Mockito.mock(DataCenter.class);
|
||||||
|
VirtualMachine vm = mock(VirtualMachine.class);
|
||||||
|
Network network = Mockito.mock(Network.class);
|
||||||
|
Mockito.when(network.getGuestType()).thenReturn(GuestType.Isolated);
|
||||||
|
Mockito.when(network.getNetworkOfferingId()).thenReturn(networkOfferingId);
|
||||||
|
long dataCenterId = 1L;
|
||||||
|
Mockito.when(network.getDataCenterId()).thenReturn(dataCenterId);
|
||||||
|
Network.IpAddresses ipAddresses = Mockito.mock(Network.IpAddresses.class);
|
||||||
|
String ipAddress = "10.1.10.10";
|
||||||
|
Mockito.when(ipAddresses.getIp4Address()).thenReturn(ipAddress);
|
||||||
|
Mockito.when(testOrchestrator.getSelectedIpForNicImport(network, dataCenter, ipAddresses)).thenReturn(null);
|
||||||
|
Mockito.when(testOrchestrator._networkModel.listNetworkOfferingServices(networkOfferingId)).thenReturn(Arrays.asList(Service.Dns, Service.Dhcp));
|
||||||
|
String macAddress = "02:01:01:82:00:01";
|
||||||
|
int deviceId = 0;
|
||||||
|
testOrchestrator.importNic(macAddress, deviceId, network, true, vm, ipAddresses, dataCenter, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InsufficientVirtualNetworkCapacityException.class)
|
||||||
|
public void testImportNicAutoAcquireGuestIPFailed() throws Exception {
|
||||||
|
DataCenter dataCenter = Mockito.mock(DataCenter.class);
|
||||||
|
VirtualMachine vm = mock(VirtualMachine.class);
|
||||||
|
Network network = Mockito.mock(Network.class);
|
||||||
|
Mockito.when(network.getGuestType()).thenReturn(GuestType.Isolated);
|
||||||
|
Mockito.when(network.getNetworkOfferingId()).thenReturn(networkOfferingId);
|
||||||
|
long dataCenterId = 1L;
|
||||||
|
Mockito.when(network.getDataCenterId()).thenReturn(dataCenterId);
|
||||||
|
Network.IpAddresses ipAddresses = Mockito.mock(Network.IpAddresses.class);
|
||||||
|
String ipAddress = "auto";
|
||||||
|
Mockito.when(ipAddresses.getIp4Address()).thenReturn(ipAddress);
|
||||||
|
Mockito.when(testOrchestrator.getSelectedIpForNicImport(network, dataCenter, ipAddresses)).thenReturn(null);
|
||||||
|
Mockito.when(testOrchestrator._networkModel.listNetworkOfferingServices(networkOfferingId)).thenReturn(Arrays.asList(Service.Dns, Service.Dhcp));
|
||||||
|
String macAddress = "02:01:01:82:00:01";
|
||||||
|
int deviceId = 0;
|
||||||
|
testOrchestrator.importNic(macAddress, deviceId, network, true, vm, ipAddresses, dataCenter, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testImportNicNoIP4Address() throws Exception {
|
||||||
|
DataCenter dataCenter = Mockito.mock(DataCenter.class);
|
||||||
|
Long vmId = 1L;
|
||||||
|
Hypervisor.HypervisorType hypervisorType = Hypervisor.HypervisorType.KVM;
|
||||||
|
VirtualMachine vm = mock(VirtualMachine.class);
|
||||||
|
Mockito.when(vm.getId()).thenReturn(vmId);
|
||||||
|
Mockito.when(vm.getHypervisorType()).thenReturn(hypervisorType);
|
||||||
|
Long networkId = 1L;
|
||||||
|
Network network = Mockito.mock(Network.class);
|
||||||
|
Mockito.when(network.getId()).thenReturn(networkId);
|
||||||
|
Network.IpAddresses ipAddresses = Mockito.mock(Network.IpAddresses.class);
|
||||||
|
Mockito.when(ipAddresses.getIp4Address()).thenReturn(null);
|
||||||
|
URI broadcastUri = URI.create("vlan://123");
|
||||||
|
NicVO nic = mock(NicVO.class);
|
||||||
|
Mockito.when(nic.getBroadcastUri()).thenReturn(broadcastUri);
|
||||||
|
String macAddress = "02:01:01:82:00:01";
|
||||||
|
int deviceId = 1;
|
||||||
|
Integer networkRate = 200;
|
||||||
|
Mockito.when(testOrchestrator._networkModel.getNetworkRate(networkId, vmId)).thenReturn(networkRate);
|
||||||
|
Mockito.when(testOrchestrator._networkModel.isSecurityGroupSupportedInNetwork(network)).thenReturn(false);
|
||||||
|
Mockito.when(testOrchestrator._networkModel.getNetworkTag(hypervisorType, network)).thenReturn("testtag");
|
||||||
|
try (MockedStatic<Transaction> transactionMocked = Mockito.mockStatic(Transaction.class)) {
|
||||||
|
transactionMocked.when(() -> Transaction.execute(any(TransactionCallback.class))).thenReturn(nic);
|
||||||
|
Pair<NicProfile, Integer> nicProfileIntegerPair = testOrchestrator.importNic(macAddress, deviceId, network, true, vm, ipAddresses, dataCenter, false);
|
||||||
|
verify(testOrchestrator._networkModel, times(1)).getNetworkRate(networkId, vmId);
|
||||||
|
verify(testOrchestrator._networkModel, times(1)).isSecurityGroupSupportedInNetwork(network);
|
||||||
|
verify(testOrchestrator._networkModel, times(1)).getNetworkTag(Hypervisor.HypervisorType.KVM, network);
|
||||||
|
assertEquals(deviceId, nicProfileIntegerPair.second().intValue());
|
||||||
|
NicProfile nicProfile = nicProfileIntegerPair.first();
|
||||||
|
assertEquals(broadcastUri, nicProfile.getBroadCastUri());
|
||||||
|
assertEquals(networkRate, nicProfile.getNetworkRate());
|
||||||
|
assertFalse(nicProfile.isSecurityGroupEnabled());
|
||||||
|
assertEquals("testtag", nicProfile.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testImportNicWithIP4Address() throws Exception {
|
||||||
|
DataCenter dataCenter = Mockito.mock(DataCenter.class);
|
||||||
|
Long vmId = 1L;
|
||||||
|
Hypervisor.HypervisorType hypervisorType = Hypervisor.HypervisorType.KVM;
|
||||||
|
VirtualMachine vm = mock(VirtualMachine.class);
|
||||||
|
Mockito.when(vm.getId()).thenReturn(vmId);
|
||||||
|
Mockito.when(vm.getHypervisorType()).thenReturn(hypervisorType);
|
||||||
|
Long networkId = 1L;
|
||||||
|
Network network = Mockito.mock(Network.class);
|
||||||
|
Mockito.when(network.getId()).thenReturn(networkId);
|
||||||
|
String ipAddress = "10.1.10.10";
|
||||||
|
Network.IpAddresses ipAddresses = Mockito.mock(Network.IpAddresses.class);
|
||||||
|
Mockito.when(ipAddresses.getIp4Address()).thenReturn(ipAddress);
|
||||||
|
URI broadcastUri = URI.create("vlan://123");
|
||||||
|
NicVO nic = mock(NicVO.class);
|
||||||
|
Mockito.when(nic.getBroadcastUri()).thenReturn(broadcastUri);
|
||||||
|
String macAddress = "02:01:01:82:00:01";
|
||||||
|
int deviceId = 1;
|
||||||
|
Integer networkRate = 200;
|
||||||
|
Mockito.when(testOrchestrator._networkModel.getNetworkRate(networkId, vmId)).thenReturn(networkRate);
|
||||||
|
Mockito.when(testOrchestrator._networkModel.isSecurityGroupSupportedInNetwork(network)).thenReturn(false);
|
||||||
|
Mockito.when(testOrchestrator._networkModel.getNetworkTag(hypervisorType, network)).thenReturn("testtag");
|
||||||
|
try (MockedStatic<Transaction> transactionMocked = Mockito.mockStatic(Transaction.class)) {
|
||||||
|
transactionMocked.when(() -> Transaction.execute(any(TransactionCallback.class))).thenReturn(nic);
|
||||||
|
Pair<NicProfile, Integer> nicProfileIntegerPair = testOrchestrator.importNic(macAddress, deviceId, network, true, vm, ipAddresses, dataCenter, false);
|
||||||
|
verify(testOrchestrator, times(1)).getSelectedIpForNicImport(network, dataCenter, ipAddresses);
|
||||||
|
verify(testOrchestrator._networkModel, times(1)).getNetworkRate(networkId, vmId);
|
||||||
|
verify(testOrchestrator._networkModel, times(1)).isSecurityGroupSupportedInNetwork(network);
|
||||||
|
verify(testOrchestrator._networkModel, times(1)).getNetworkTag(Hypervisor.HypervisorType.KVM, network);
|
||||||
|
assertEquals(deviceId, nicProfileIntegerPair.second().intValue());
|
||||||
|
NicProfile nicProfile = nicProfileIntegerPair.first();
|
||||||
|
assertEquals(broadcastUri, nicProfile.getBroadCastUri());
|
||||||
|
assertEquals(networkRate, nicProfile.getNetworkRate());
|
||||||
|
assertFalse(nicProfile.isSecurityGroupEnabled());
|
||||||
|
assertEquals("testtag", nicProfile.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -141,6 +141,8 @@ public interface HostDao extends GenericDao<HostVO, Long>, StateDao<Status, Stat
|
|||||||
|
|
||||||
List<HostVO> listByHostCapability(Host.Type type, Long clusterId, Long podId, long dcId, String hostCapabilty);
|
List<HostVO> listByHostCapability(Host.Type type, Long clusterId, Long podId, long dcId, String hostCapabilty);
|
||||||
|
|
||||||
|
List<HostVO> listByClusterHypervisorTypeAndHostCapability(Long clusterId, HypervisorType hypervisorType, String hostCapabilty);
|
||||||
|
|
||||||
List<HostVO> listByClusterAndHypervisorType(long clusterId, HypervisorType hypervisorType);
|
List<HostVO> listByClusterAndHypervisorType(long clusterId, HypervisorType hypervisorType);
|
||||||
|
|
||||||
HostVO findByName(String name);
|
HostVO findByName(String name);
|
||||||
|
|||||||
@ -341,6 +341,7 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
|
|||||||
ClusterHypervisorSearch.and("hypervisor", ClusterHypervisorSearch.entity().getHypervisorType(), SearchCriteria.Op.EQ);
|
ClusterHypervisorSearch.and("hypervisor", ClusterHypervisorSearch.entity().getHypervisorType(), SearchCriteria.Op.EQ);
|
||||||
ClusterHypervisorSearch.and("type", ClusterHypervisorSearch.entity().getType(), SearchCriteria.Op.EQ);
|
ClusterHypervisorSearch.and("type", ClusterHypervisorSearch.entity().getType(), SearchCriteria.Op.EQ);
|
||||||
ClusterHypervisorSearch.and("status", ClusterHypervisorSearch.entity().getStatus(), SearchCriteria.Op.EQ);
|
ClusterHypervisorSearch.and("status", ClusterHypervisorSearch.entity().getStatus(), SearchCriteria.Op.EQ);
|
||||||
|
ClusterHypervisorSearch.and("resourceState", ClusterHypervisorSearch.entity().getResourceState(), SearchCriteria.Op.EQ);
|
||||||
ClusterHypervisorSearch.done();
|
ClusterHypervisorSearch.done();
|
||||||
|
|
||||||
UnmanagedDirectConnectSearch = createSearchBuilder();
|
UnmanagedDirectConnectSearch = createSearchBuilder();
|
||||||
@ -1506,12 +1507,42 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
|
|||||||
return listBy(sc);
|
return listBy(sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<HostVO> listByClusterHypervisorTypeAndHostCapability(Long clusterId, HypervisorType hypervisorType, String hostCapabilty) {
|
||||||
|
SearchBuilder<DetailVO> hostCapabilitySearch = _detailsDao.createSearchBuilder();
|
||||||
|
DetailVO tagEntity = hostCapabilitySearch.entity();
|
||||||
|
hostCapabilitySearch.and("capability", tagEntity.getName(), SearchCriteria.Op.EQ);
|
||||||
|
hostCapabilitySearch.and("value", tagEntity.getValue(), SearchCriteria.Op.EQ);
|
||||||
|
|
||||||
|
SearchBuilder<HostVO> hostSearch = createSearchBuilder();
|
||||||
|
HostVO entity = hostSearch.entity();
|
||||||
|
hostSearch.and("clusterId", entity.getClusterId(), SearchCriteria.Op.EQ);
|
||||||
|
hostSearch.and("hypervisor", entity.getHypervisorType(), SearchCriteria.Op.EQ);
|
||||||
|
hostSearch.and("type", entity.getType(), SearchCriteria.Op.EQ);
|
||||||
|
hostSearch.and("status", entity.getStatus(), SearchCriteria.Op.EQ);
|
||||||
|
hostSearch.and("resourceState", entity.getResourceState(), SearchCriteria.Op.EQ);
|
||||||
|
hostSearch.join("hostCapabilitySearch", hostCapabilitySearch, entity.getId(), tagEntity.getHostId(), JoinBuilder.JoinType.INNER);
|
||||||
|
|
||||||
|
SearchCriteria<HostVO> sc = hostSearch.create();
|
||||||
|
sc.setJoinParameters("hostCapabilitySearch", "value", Boolean.toString(true));
|
||||||
|
sc.setJoinParameters("hostCapabilitySearch", "capability", hostCapabilty);
|
||||||
|
|
||||||
|
sc.setParameters("clusterId", clusterId);
|
||||||
|
sc.setParameters("hypervisor", hypervisorType);
|
||||||
|
sc.setParameters("type", Type.Routing);
|
||||||
|
sc.setParameters("status", Status.Up);
|
||||||
|
sc.setParameters("resourceState", ResourceState.Enabled);
|
||||||
|
return listBy(sc);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public List<HostVO> listByClusterAndHypervisorType(long clusterId, HypervisorType hypervisorType) {
|
public List<HostVO> listByClusterAndHypervisorType(long clusterId, HypervisorType hypervisorType) {
|
||||||
SearchCriteria<HostVO> sc = ClusterHypervisorSearch.create();
|
SearchCriteria<HostVO> sc = ClusterHypervisorSearch.create();
|
||||||
sc.setParameters("clusterId", clusterId);
|
sc.setParameters("clusterId", clusterId);
|
||||||
sc.setParameters("hypervisor", hypervisorType);
|
sc.setParameters("hypervisor", hypervisorType);
|
||||||
sc.setParameters("type", Type.Routing);
|
sc.setParameters("type", Type.Routing);
|
||||||
sc.setParameters("status", Status.Up);
|
sc.setParameters("status", Status.Up);
|
||||||
|
sc.setParameters("resourceState", ResourceState.Enabled);
|
||||||
return listBy(sc);
|
return listBy(sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -18,9 +18,12 @@
|
|||||||
*/
|
*/
|
||||||
package com.cloud.storage.dao;
|
package com.cloud.storage.dao;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.cloudstack.resourcedetail.ResourceDetailsDao;
|
import org.apache.cloudstack.resourcedetail.ResourceDetailsDao;
|
||||||
|
|
||||||
import com.cloud.utils.db.GenericDao;
|
import com.cloud.utils.db.GenericDao;
|
||||||
|
|
||||||
public interface SnapshotDetailsDao extends GenericDao<SnapshotDetailsVO, Long>, ResourceDetailsDao<SnapshotDetailsVO> {
|
public interface SnapshotDetailsDao extends GenericDao<SnapshotDetailsVO, Long>, ResourceDetailsDao<SnapshotDetailsVO> {
|
||||||
|
public List<SnapshotDetailsVO> findDetailsByZoneAndKey(long dcId, String key);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,11 +18,44 @@
|
|||||||
*/
|
*/
|
||||||
package com.cloud.storage.dao;
|
package com.cloud.storage.dao;
|
||||||
|
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.cloudstack.resourcedetail.ResourceDetailsDaoBase;
|
import org.apache.cloudstack.resourcedetail.ResourceDetailsDaoBase;
|
||||||
|
|
||||||
|
import com.cloud.utils.db.TransactionLegacy;
|
||||||
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
|
|
||||||
public class SnapshotDetailsDaoImpl extends ResourceDetailsDaoBase<SnapshotDetailsVO> implements SnapshotDetailsDao {
|
public class SnapshotDetailsDaoImpl extends ResourceDetailsDaoBase<SnapshotDetailsVO> implements SnapshotDetailsDao {
|
||||||
|
private static final String GET_SNAPSHOT_DETAILS_ON_ZONE = "SELECT s.* FROM snapshot_details s LEFT JOIN snapshots ss ON ss.id=s.snapshot_id WHERE ss.data_center_id = ? AND s.name = ?";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addDetail(long resourceId, String key, String value, boolean display) {
|
public void addDetail(long resourceId, String key, String value, boolean display) {
|
||||||
super.addDetail(new SnapshotDetailsVO(resourceId, key, value, display));
|
super.addDetail(new SnapshotDetailsVO(resourceId, key, value, display));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<SnapshotDetailsVO> findDetailsByZoneAndKey(long dcId, String key) {
|
||||||
|
StringBuilder sql = new StringBuilder(GET_SNAPSHOT_DETAILS_ON_ZONE);
|
||||||
|
TransactionLegacy txn = TransactionLegacy.currentTxn();
|
||||||
|
List<SnapshotDetailsVO> snapshotDetailsOnZone = new ArrayList<SnapshotDetailsVO>();
|
||||||
|
try (PreparedStatement pstmt = txn.prepareStatement(sql.toString());) {
|
||||||
|
if (pstmt != null) {
|
||||||
|
pstmt.setLong(1, dcId);
|
||||||
|
pstmt.setString(2, key);
|
||||||
|
try (ResultSet rs = pstmt.executeQuery();) {
|
||||||
|
while (rs.next()) {
|
||||||
|
snapshotDetailsOnZone.add(toEntityBean(rs, false));
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new CloudRuntimeException("Could not find details by given zone and key due to:" + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return snapshotDetailsOnZone;
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new CloudRuntimeException("Could not find details by given zone and key due to:" + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -160,4 +160,6 @@ public interface VolumeDao extends GenericDao<VolumeVO, Long>, StateDao<Volume.S
|
|||||||
List<VolumeVO> listAllocatedVolumesForAccountDiskOfferingIdsAndNotForVms(long accountId, List<Long> diskOfferingIds, List<Long> vmIds);
|
List<VolumeVO> listAllocatedVolumesForAccountDiskOfferingIdsAndNotForVms(long accountId, List<Long> diskOfferingIds, List<Long> vmIds);
|
||||||
|
|
||||||
List<VolumeVO> searchRemovedByVms(List<Long> vmIds, Long batchSize);
|
List<VolumeVO> searchRemovedByVms(List<Long> vmIds, Long batchSize);
|
||||||
|
|
||||||
|
VolumeVO findOneByIScsiName(String iScsiName);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -395,6 +395,7 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
|
|||||||
AllFieldsSearch.and("updatedCount", AllFieldsSearch.entity().getUpdatedCount(), Op.EQ);
|
AllFieldsSearch.and("updatedCount", AllFieldsSearch.entity().getUpdatedCount(), Op.EQ);
|
||||||
AllFieldsSearch.and("name", AllFieldsSearch.entity().getName(), Op.EQ);
|
AllFieldsSearch.and("name", AllFieldsSearch.entity().getName(), Op.EQ);
|
||||||
AllFieldsSearch.and("passphraseId", AllFieldsSearch.entity().getPassphraseId(), Op.EQ);
|
AllFieldsSearch.and("passphraseId", AllFieldsSearch.entity().getPassphraseId(), Op.EQ);
|
||||||
|
AllFieldsSearch.and("iScsiName", AllFieldsSearch.entity().get_iScsiName(), Op.EQ);
|
||||||
AllFieldsSearch.done();
|
AllFieldsSearch.done();
|
||||||
|
|
||||||
RootDiskStateSearch = createSearchBuilder();
|
RootDiskStateSearch = createSearchBuilder();
|
||||||
@ -910,4 +911,10 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
|
|||||||
Filter filter = new Filter(VolumeVO.class, "id", true, 0L, batchSize);
|
Filter filter = new Filter(VolumeVO.class, "id", true, 0L, batchSize);
|
||||||
return searchIncludingRemoved(sc, filter, null, false);
|
return searchIncludingRemoved(sc, filter, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public VolumeVO findOneByIScsiName(String iScsiName) {
|
||||||
|
SearchCriteria<VolumeVO> sc = AllFieldsSearch.create();
|
||||||
|
sc.setParameters("iScsiName", iScsiName);
|
||||||
|
return findOneIncludingRemovedBy(sc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -75,8 +75,10 @@ public interface VolumeStatsDao extends GenericDao<VolumeStatsVO, Long> {
|
|||||||
/**
|
/**
|
||||||
* Removes (expunges) all Volume stats with {@code timestamp} less than
|
* Removes (expunges) all Volume stats with {@code timestamp} less than
|
||||||
* a given Date.
|
* a given Date.
|
||||||
* @param limit the maximum date to keep stored. Records that exceed this limit will be removed.
|
* @param limitDate the maximum date to keep stored. Records that exceed this limit will be removed.
|
||||||
|
* @param limitPerQuery the maximum amount of rows to be removed in a single query. We loop if there are still rows to be removed after a given query.
|
||||||
|
* If 0 or negative, no limit is used.
|
||||||
*/
|
*/
|
||||||
void removeAllByTimestampLessThan(Date limit);
|
void removeAllByTimestampLessThan(Date limitDate, long limitPerQuery);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,6 +21,8 @@ import java.util.List;
|
|||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import com.cloud.utils.db.Filter;
|
import com.cloud.utils.db.Filter;
|
||||||
@ -33,6 +35,8 @@ import com.cloud.storage.VolumeStatsVO;
|
|||||||
@Component
|
@Component
|
||||||
public class VolumeStatsDaoImpl extends GenericDaoBase<VolumeStatsVO, Long> implements VolumeStatsDao {
|
public class VolumeStatsDaoImpl extends GenericDaoBase<VolumeStatsVO, Long> implements VolumeStatsDao {
|
||||||
|
|
||||||
|
protected Logger logger = LogManager.getLogger(getClass());
|
||||||
|
|
||||||
protected SearchBuilder<VolumeStatsVO> volumeIdSearch;
|
protected SearchBuilder<VolumeStatsVO> volumeIdSearch;
|
||||||
protected SearchBuilder<VolumeStatsVO> volumeIdTimestampGreaterThanEqualSearch;
|
protected SearchBuilder<VolumeStatsVO> volumeIdTimestampGreaterThanEqualSearch;
|
||||||
protected SearchBuilder<VolumeStatsVO> volumeIdTimestampLessThanEqualSearch;
|
protected SearchBuilder<VolumeStatsVO> volumeIdTimestampLessThanEqualSearch;
|
||||||
@ -116,9 +120,21 @@ public class VolumeStatsDaoImpl extends GenericDaoBase<VolumeStatsVO, Long> impl
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeAllByTimestampLessThan(Date limit) {
|
public void removeAllByTimestampLessThan(Date limitDate, long limitPerQuery) {
|
||||||
SearchCriteria<VolumeStatsVO> sc = timestampSearch.create();
|
SearchCriteria<VolumeStatsVO> sc = timestampSearch.create();
|
||||||
sc.setParameters(TIMESTAMP, limit);
|
sc.setParameters(TIMESTAMP, limitDate);
|
||||||
expunge(sc);
|
|
||||||
|
logger.debug(String.format("Starting to remove all volume_stats rows older than [%s].", limitDate));
|
||||||
|
|
||||||
|
long totalRemoved = 0;
|
||||||
|
long removed;
|
||||||
|
|
||||||
|
do {
|
||||||
|
removed = expunge(sc, limitPerQuery);
|
||||||
|
totalRemoved += removed;
|
||||||
|
logger.trace(String.format("Removed [%s] volume_stats rows on the last update and a sum of [%s] volume_stats rows older than [%s] until now.", removed, totalRemoved, limitDate));
|
||||||
|
} while (limitPerQuery > 0 && removed >= limitPerQuery);
|
||||||
|
|
||||||
|
logger.info(String.format("Removed a total of [%s] volume_stats rows older than [%s].", totalRemoved, limitDate));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -127,6 +127,10 @@ public interface PrimaryDataStoreDao extends GenericDao<StoragePoolVO, Long> {
|
|||||||
|
|
||||||
List<StoragePoolVO> findZoneWideStoragePoolsByHypervisor(long dataCenterId, HypervisorType hypervisorType, String keyword);
|
List<StoragePoolVO> findZoneWideStoragePoolsByHypervisor(long dataCenterId, HypervisorType hypervisorType, String keyword);
|
||||||
|
|
||||||
|
List<StoragePoolVO> findZoneWideStoragePoolsByHypervisorAndPoolType(long dataCenterId, HypervisorType hypervisorType, Storage.StoragePoolType poolType);
|
||||||
|
|
||||||
|
List<StoragePoolVO> findClusterWideStoragePoolsByHypervisorAndPoolType(long clusterId, HypervisorType hypervisorType, Storage.StoragePoolType poolType);
|
||||||
|
|
||||||
List<StoragePoolVO> findLocalStoragePoolsByHostAndTags(long hostId, String[] tags);
|
List<StoragePoolVO> findLocalStoragePoolsByHostAndTags(long hostId, String[] tags);
|
||||||
|
|
||||||
List<StoragePoolVO> listLocalStoragePoolByPath(long datacenterId, String path);
|
List<StoragePoolVO> listLocalStoragePoolByPath(long datacenterId, String path);
|
||||||
@ -141,6 +145,8 @@ public interface PrimaryDataStoreDao extends GenericDao<StoragePoolVO, Long> {
|
|||||||
|
|
||||||
List<StoragePoolVO> findPoolsByStorageType(Storage.StoragePoolType storageType);
|
List<StoragePoolVO> findPoolsByStorageType(Storage.StoragePoolType storageType);
|
||||||
|
|
||||||
|
StoragePoolVO findPoolByZoneAndPath(long zoneId, String datastorePath);
|
||||||
|
|
||||||
List<StoragePoolVO> listStoragePoolsWithActiveVolumesByOfferingId(long offeringid);
|
List<StoragePoolVO> listStoragePoolsWithActiveVolumesByOfferingId(long offeringid);
|
||||||
|
|
||||||
Pair<List<Long>, Integer> searchForIdsAndCount(Long storagePoolId, String storagePoolName, Long zoneId,
|
Pair<List<Long>, Integer> searchForIdsAndCount(Long storagePoolId, String storagePoolName, Long zoneId,
|
||||||
|
|||||||
@ -28,6 +28,7 @@ import java.util.stream.Collectors;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.naming.ConfigurationException;
|
import javax.naming.ConfigurationException;
|
||||||
|
|
||||||
|
import com.cloud.storage.Storage;
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
import com.cloud.utils.db.Filter;
|
import com.cloud.utils.db.Filter;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
@ -35,7 +36,6 @@ import org.apache.commons.collections.CollectionUtils;
|
|||||||
import com.cloud.host.Status;
|
import com.cloud.host.Status;
|
||||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||||
import com.cloud.storage.ScopeType;
|
import com.cloud.storage.ScopeType;
|
||||||
import com.cloud.storage.Storage;
|
|
||||||
import com.cloud.storage.StoragePoolHostVO;
|
import com.cloud.storage.StoragePoolHostVO;
|
||||||
import com.cloud.storage.StoragePoolStatus;
|
import com.cloud.storage.StoragePoolStatus;
|
||||||
import com.cloud.storage.StoragePoolTagVO;
|
import com.cloud.storage.StoragePoolTagVO;
|
||||||
@ -622,6 +622,28 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase<StoragePoolVO, Long>
|
|||||||
return sc.list();
|
return sc.list();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<StoragePoolVO> findZoneWideStoragePoolsByHypervisorAndPoolType(long dataCenterId, HypervisorType hypervisorType, Storage.StoragePoolType poolType) {
|
||||||
|
QueryBuilder<StoragePoolVO> sc = QueryBuilder.create(StoragePoolVO.class);
|
||||||
|
sc.and(sc.entity().getDataCenterId(), Op.EQ, dataCenterId);
|
||||||
|
sc.and(sc.entity().getStatus(), Op.EQ, StoragePoolStatus.Up);
|
||||||
|
sc.and(sc.entity().getScope(), Op.EQ, ScopeType.ZONE);
|
||||||
|
sc.and(sc.entity().getHypervisor(), Op.EQ, hypervisorType);
|
||||||
|
sc.and(sc.entity().getPoolType(), Op.EQ, poolType);
|
||||||
|
return sc.list();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<StoragePoolVO> findClusterWideStoragePoolsByHypervisorAndPoolType(long clusterId, HypervisorType hypervisorType, Storage.StoragePoolType poolType) {
|
||||||
|
QueryBuilder<StoragePoolVO> sc = QueryBuilder.create(StoragePoolVO.class);
|
||||||
|
sc.and(sc.entity().getClusterId(), Op.EQ, clusterId);
|
||||||
|
sc.and(sc.entity().getStatus(), Op.EQ, StoragePoolStatus.Up);
|
||||||
|
sc.and(sc.entity().getScope(), Op.EQ, ScopeType.CLUSTER);
|
||||||
|
sc.and(sc.entity().getHypervisor(), Op.EQ, hypervisorType);
|
||||||
|
sc.and(sc.entity().getPoolType(), Op.EQ, poolType);
|
||||||
|
return sc.list();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deletePoolTags(long poolId) {
|
public void deletePoolTags(long poolId) {
|
||||||
_tagsDao.deleteTags(poolId);
|
_tagsDao.deleteTags(poolId);
|
||||||
@ -660,6 +682,16 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase<StoragePoolVO, Long>
|
|||||||
return listBy(sc);
|
return listBy(sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StoragePoolVO findPoolByZoneAndPath(long zoneId, String datastorePath) {
|
||||||
|
SearchCriteria<StoragePoolVO> sc = AllFieldSearch.create();
|
||||||
|
sc.setParameters("datacenterId", zoneId);
|
||||||
|
if (datastorePath != null) {
|
||||||
|
sc.addAnd("path", Op.LIKE, "%/" + datastorePath);
|
||||||
|
}
|
||||||
|
return findOneBy(sc);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<StoragePoolVO> listStoragePoolsWithActiveVolumesByOfferingId(long offeringId) {
|
public List<StoragePoolVO> listStoragePoolsWithActiveVolumesByOfferingId(long offeringId) {
|
||||||
TransactionLegacy txn = TransactionLegacy.currentTxn();
|
TransactionLegacy txn = TransactionLegacy.currentTxn();
|
||||||
|
|||||||
@ -100,6 +100,9 @@ public class TemplateDataFactoryImpl implements TemplateDataFactory {
|
|||||||
@Override
|
@Override
|
||||||
public TemplateInfo getTemplate(long templateId, DataStore store) {
|
public TemplateInfo getTemplate(long templateId, DataStore store) {
|
||||||
VMTemplateVO templ = imageDataDao.findById(templateId);
|
VMTemplateVO templ = imageDataDao.findById(templateId);
|
||||||
|
if (templ == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
if (store == null && !templ.isDirectDownload()) {
|
if (store == null && !templ.isDirectDownload()) {
|
||||||
TemplateObject tmpl = TemplateObject.getTemplate(templ, null, null);
|
TemplateObject tmpl = TemplateObject.getTemplate(templ, null, null);
|
||||||
return tmpl;
|
return tmpl;
|
||||||
|
|||||||
@ -82,6 +82,10 @@ public class TemplateObject implements TemplateInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void configure(VMTemplateVO template, DataStore dataStore) {
|
protected void configure(VMTemplateVO template, DataStore dataStore) {
|
||||||
|
if (template == null) {
|
||||||
|
String msg = String.format("Template Object is not properly initialised %s", this.toString());
|
||||||
|
logger.warn(msg);
|
||||||
|
}
|
||||||
imageVO = template;
|
imageVO = template;
|
||||||
this.dataStore = dataStore;
|
this.dataStore = dataStore;
|
||||||
}
|
}
|
||||||
@ -98,6 +102,10 @@ public class TemplateObject implements TemplateInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public VMTemplateVO getImage() {
|
public VMTemplateVO getImage() {
|
||||||
|
if (imageVO == null) {
|
||||||
|
String msg = String.format("Template Object is not properly initialised %s", this.toString());
|
||||||
|
logger.error(msg);
|
||||||
|
} // somehow the nullpointer is needed : refacter needed!?!
|
||||||
return imageVO;
|
return imageVO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -42,7 +42,9 @@ import com.cloud.storage.StoragePool;
|
|||||||
import com.cloud.storage.StoragePoolHostVO;
|
import com.cloud.storage.StoragePoolHostVO;
|
||||||
import com.cloud.storage.StorageService;
|
import com.cloud.storage.StorageService;
|
||||||
import com.cloud.storage.dao.StoragePoolHostDao;
|
import com.cloud.storage.dao.StoragePoolHostDao;
|
||||||
|
import com.cloud.utils.Pair;
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
|
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener;
|
import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener;
|
||||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||||
@ -54,7 +56,9 @@ import org.apache.logging.log4j.Logger;
|
|||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class DefaultHostListener implements HypervisorHostListener {
|
public class DefaultHostListener implements HypervisorHostListener {
|
||||||
protected Logger logger = LogManager.getLogger(getClass());
|
protected Logger logger = LogManager.getLogger(getClass());
|
||||||
@ -126,7 +130,9 @@ public class DefaultHostListener implements HypervisorHostListener {
|
|||||||
@Override
|
@Override
|
||||||
public boolean hostConnect(long hostId, long poolId) throws StorageConflictException {
|
public boolean hostConnect(long hostId, long poolId) throws StorageConflictException {
|
||||||
StoragePool pool = (StoragePool) this.dataStoreMgr.getDataStore(poolId, DataStoreRole.Primary);
|
StoragePool pool = (StoragePool) this.dataStoreMgr.getDataStore(poolId, DataStoreRole.Primary);
|
||||||
ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(true, pool);
|
Pair<Map<String, String>, Boolean> nfsMountOpts = storageManager.getStoragePoolNFSMountOpts(pool, null);
|
||||||
|
|
||||||
|
ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(true, pool, nfsMountOpts.first());
|
||||||
cmd.setWait(modifyStoragePoolCommandWait);
|
cmd.setWait(modifyStoragePoolCommandWait);
|
||||||
logger.debug(String.format("Sending modify storage pool command to agent: %d for storage pool: %d with timeout %d seconds",
|
logger.debug(String.format("Sending modify storage pool command to agent: %d for storage pool: %d with timeout %d seconds",
|
||||||
hostId, poolId, cmd.getWait()));
|
hostId, poolId, cmd.getWait()));
|
||||||
@ -139,7 +145,7 @@ public class DefaultHostListener implements HypervisorHostListener {
|
|||||||
if (!answer.getResult()) {
|
if (!answer.getResult()) {
|
||||||
String msg = "Unable to attach storage pool" + poolId + " to the host" + hostId;
|
String msg = "Unable to attach storage pool" + poolId + " to the host" + hostId;
|
||||||
alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, pool.getDataCenterId(), pool.getPodId(), msg, msg);
|
alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, pool.getDataCenterId(), pool.getPodId(), msg, msg);
|
||||||
throw new CloudRuntimeException("Unable establish connection from storage head to storage pool " + pool.getId() + " due to " + answer.getDetails() +
|
throw new CloudRuntimeException("Unable to establish connection from storage head to storage pool " + pool.getId() + " due to " + answer.getDetails() +
|
||||||
pool.getId());
|
pool.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -505,9 +505,11 @@ public class VolumeServiceImpl implements VolumeService {
|
|||||||
_snapshotStoreDao.remove(snapStoreVo.getId());
|
_snapshotStoreDao.remove(snapStoreVo.getId());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (!StoragePoolType.StorPool.equals(storagePoolVO.getPoolType())) {
|
||||||
_snapshotStoreDao.remove(snapStoreVo.getId());
|
_snapshotStoreDao.remove(snapStoreVo.getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
snapshotApiService.markVolumeSnapshotsAsDestroyed(vo);
|
snapshotApiService.markVolumeSnapshotsAsDestroyed(vo);
|
||||||
} else {
|
} else {
|
||||||
vo.processEvent(Event.OperationFailed);
|
vo.processEvent(Event.OperationFailed);
|
||||||
|
|||||||
@ -346,7 +346,7 @@ public class VeeamClient {
|
|||||||
String type = pair.second();
|
String type = pair.second();
|
||||||
String path = url.replace(apiURI.toString(), "");
|
String path = url.replace(apiURI.toString(), "");
|
||||||
if (type.equals("RestoreSession")) {
|
if (type.equals("RestoreSession")) {
|
||||||
return checkIfRestoreSessionFinished(type, path);
|
checkIfRestoreSessionFinished(type, path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -362,17 +362,29 @@ public class VeeamClient {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean checkIfRestoreSessionFinished(String type, String path) throws IOException {
|
|
||||||
for (int j = 0; j < this.restoreTimeout; j++) {
|
/**
|
||||||
|
* Checks the status of the restore session. Checked states are "Success" and "Failure".<br/>
|
||||||
|
* There is also a timeout defined in the global configuration, backup.plugin.veeam.restore.timeout,<br/>
|
||||||
|
* that is used to wait for the restore to complete before throwing a {@link CloudRuntimeException}.
|
||||||
|
*/
|
||||||
|
protected void checkIfRestoreSessionFinished(String type, String path) throws IOException {
|
||||||
|
for (int j = 0; j < restoreTimeout; j++) {
|
||||||
HttpResponse relatedResponse = get(path);
|
HttpResponse relatedResponse = get(path);
|
||||||
RestoreSession session = parseRestoreSessionResponse(relatedResponse);
|
RestoreSession session = parseRestoreSessionResponse(relatedResponse);
|
||||||
if (session.getResult().equals("Success")) {
|
if (session.getResult().equals("Success")) {
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (session.getResult().equalsIgnoreCase("Failed")) {
|
if (session.getResult().equalsIgnoreCase("Failed")) {
|
||||||
String sessionUid = session.getUid();
|
String sessionUid = session.getUid();
|
||||||
|
LOG.error(String.format("Failed to restore backup [%s] of VM [%s] due to [%s].",
|
||||||
|
sessionUid, session.getVmDisplayName(),
|
||||||
|
getRestoreVmErrorDescription(StringUtils.substringAfterLast(sessionUid, ":"))));
|
||||||
throw new CloudRuntimeException(String.format("Restore job [%s] failed.", sessionUid));
|
throw new CloudRuntimeException(String.format("Restore job [%s] failed.", sessionUid));
|
||||||
}
|
}
|
||||||
|
LOG.debug(String.format("Waiting %s seconds, out of a total of %s seconds, for the restore backup process to finish.", j, restoreTimeout));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
} catch (InterruptedException ignored) {
|
} catch (InterruptedException ignored) {
|
||||||
@ -931,6 +943,29 @@ public class VeeamClient {
|
|||||||
return new Pair<>(result.first(), restoreLocation);
|
return new Pair<>(result.first(), restoreLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to retrieve the error's description of the Veeam restore task that resulted in an error.
|
||||||
|
* @param uid Session uid in Veeam of the restore process;
|
||||||
|
* @return the description found in Veeam about the cause of error in the restore process.
|
||||||
|
*/
|
||||||
|
protected String getRestoreVmErrorDescription(String uid) {
|
||||||
|
LOG.debug(String.format("Trying to find the cause of error in the restore process [%s].", uid));
|
||||||
|
List<String> cmds = Arrays.asList(
|
||||||
|
String.format("$restoreUid = '%s'", uid),
|
||||||
|
"$restore = Get-VBRRestoreSession -Id $restoreUid",
|
||||||
|
"if ($restore) {",
|
||||||
|
"Write-Output $restore.Description",
|
||||||
|
"} else {",
|
||||||
|
"Write-Output 'Cannot find restore session with provided uid $restoreUid'",
|
||||||
|
"}"
|
||||||
|
);
|
||||||
|
Pair<Boolean, String> result = executePowerShellCommands(cmds);
|
||||||
|
if (result != null && result.first()) {
|
||||||
|
return result.second();
|
||||||
|
}
|
||||||
|
return String.format("Failed to get the description of the failed restore session [%s]. Please contact an administrator.", uid);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isLegacyServer() {
|
private boolean isLegacyServer() {
|
||||||
return this.veeamServerVersion != null && (this.veeamServerVersion > 0 && this.veeamServerVersion < 11);
|
return this.veeamServerVersion != null && (this.veeamServerVersion > 0 && this.veeamServerVersion < 11);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -59,6 +59,8 @@ public class VeeamClientTest {
|
|||||||
private VeeamClient mockClient;
|
private VeeamClient mockClient;
|
||||||
private static final SimpleDateFormat newDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
private static final SimpleDateFormat newDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
|
|
||||||
|
private VeeamClient mock = Mockito.mock(VeeamClient.class);
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public WireMockRule wireMockRule = new WireMockRule(9399);
|
public WireMockRule wireMockRule = new WireMockRule(9399);
|
||||||
|
|
||||||
@ -163,7 +165,7 @@ public class VeeamClientTest {
|
|||||||
Mockito.when(mockClient.get(Mockito.anyString())).thenReturn(httpResponse);
|
Mockito.when(mockClient.get(Mockito.anyString())).thenReturn(httpResponse);
|
||||||
Mockito.when(mockClient.parseRestoreSessionResponse(httpResponse)).thenReturn(restoreSession);
|
Mockito.when(mockClient.parseRestoreSessionResponse(httpResponse)).thenReturn(restoreSession);
|
||||||
Mockito.when(restoreSession.getResult()).thenReturn("No Success");
|
Mockito.when(restoreSession.getResult()).thenReturn("No Success");
|
||||||
Mockito.when(mockClient.checkIfRestoreSessionFinished(Mockito.eq("RestoreTest"), Mockito.eq("any"))).thenCallRealMethod();
|
Mockito.doCallRealMethod().when(mockClient).checkIfRestoreSessionFinished(Mockito.eq("RestoreTest"), Mockito.eq("any"));
|
||||||
mockClient.checkIfRestoreSessionFinished("RestoreTest", "any");
|
mockClient.checkIfRestoreSessionFinished("RestoreTest", "any");
|
||||||
fail();
|
fail();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -172,6 +174,42 @@ public class VeeamClientTest {
|
|||||||
Mockito.verify(mockClient, times(10)).get(Mockito.anyString());
|
Mockito.verify(mockClient, times(10)).get(Mockito.anyString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getRestoreVmErrorDescriptionTestFindErrorDescription() {
|
||||||
|
Pair<Boolean, String> response = new Pair<>(true, "Example of error description found in Veeam.");
|
||||||
|
Mockito.when(mock.getRestoreVmErrorDescription("uuid")).thenCallRealMethod();
|
||||||
|
Mockito.when(mock.executePowerShellCommands(Mockito.any())).thenReturn(response);
|
||||||
|
String result = mock.getRestoreVmErrorDescription("uuid");
|
||||||
|
Assert.assertEquals("Example of error description found in Veeam.", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getRestoreVmErrorDescriptionTestNotFindErrorDescription() {
|
||||||
|
Pair<Boolean, String> response = new Pair<>(true, "Cannot find restore session with provided uid uuid");
|
||||||
|
Mockito.when(mock.getRestoreVmErrorDescription("uuid")).thenCallRealMethod();
|
||||||
|
Mockito.when(mock.executePowerShellCommands(Mockito.any())).thenReturn(response);
|
||||||
|
String result = mock.getRestoreVmErrorDescription("uuid");
|
||||||
|
Assert.assertEquals("Cannot find restore session with provided uid uuid", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getRestoreVmErrorDescriptionTestWhenPowerShellOutputIsNull() {
|
||||||
|
Mockito.when(mock.getRestoreVmErrorDescription("uuid")).thenCallRealMethod();
|
||||||
|
Mockito.when(mock.executePowerShellCommands(Mockito.any())).thenReturn(null);
|
||||||
|
String result = mock.getRestoreVmErrorDescription("uuid");
|
||||||
|
Assert.assertEquals("Failed to get the description of the failed restore session [uuid]. Please contact an administrator.", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getRestoreVmErrorDescriptionTestWhenPowerShellOutputIsFalse() {
|
||||||
|
Pair<Boolean, String> response = new Pair<>(false, null);
|
||||||
|
Mockito.when(mock.getRestoreVmErrorDescription("uuid")).thenCallRealMethod();
|
||||||
|
Mockito.when(mock.executePowerShellCommands(Mockito.any())).thenReturn(response);
|
||||||
|
String result = mock.getRestoreVmErrorDescription("uuid");
|
||||||
|
Assert.assertEquals("Failed to get the description of the failed restore session [uuid]. Please contact an administrator.", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void verifyBackupMetrics(Map<String, Backup.Metric> metrics) {
|
private void verifyBackupMetrics(Map<String, Backup.Metric> metrics) {
|
||||||
Assert.assertEquals(2, metrics.size());
|
Assert.assertEquals(2, metrics.size());
|
||||||
|
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
package com.cloud.hypervisor.kvm.resource;
|
package com.cloud.hypervisor.kvm.resource;
|
||||||
|
|
||||||
|
import static com.cloud.host.Host.HOST_INSTANCE_CONVERSION;
|
||||||
import static com.cloud.host.Host.HOST_VOLUME_ENCRYPTION;
|
import static com.cloud.host.Host.HOST_VOLUME_ENCRYPTION;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
@ -306,6 +307,16 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||||||
|
|
||||||
public static final String TUNGSTEN_PATH = "scripts/vm/network/tungsten";
|
public static final String TUNGSTEN_PATH = "scripts/vm/network/tungsten";
|
||||||
|
|
||||||
|
public static final String INSTANCE_CONVERSION_SUPPORTED_CHECK_CMD = "virt-v2v --version";
|
||||||
|
// virt-v2v --version => sample output: virt-v2v 1.42.0rhel=8,release=22.module+el8.10.0+1590+a67ab969
|
||||||
|
public static final String OVF_EXPORT_SUPPORTED_CHECK_CMD = "ovftool --version";
|
||||||
|
// ovftool --version => sample output: VMware ovftool 4.6.0 (build-21452615)
|
||||||
|
public static final String OVF_EXPORT_TOOl_GET_VERSION_CMD = "ovftool --version | awk '{print $3}'";
|
||||||
|
|
||||||
|
public static final String WINDOWS_GUEST_CONVERSION_SUPPORTED_CHECK_CMD = "rpm -qa | grep -i virtio-win";
|
||||||
|
public static final String UBUNTU_WINDOWS_GUEST_CONVERSION_SUPPORTED_CHECK_CMD = "dpkg -l virtio-win";
|
||||||
|
public static final String UBUNTU_NBDKIT_PKG_CHECK_CMD = "dpkg -l nbdkit";
|
||||||
|
|
||||||
private String modifyVlanPath;
|
private String modifyVlanPath;
|
||||||
private String versionStringPath;
|
private String versionStringPath;
|
||||||
private String patchScriptPath;
|
private String patchScriptPath;
|
||||||
@ -3647,6 +3658,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||||||
cmd.setIqn(getIqn());
|
cmd.setIqn(getIqn());
|
||||||
cmd.getHostDetails().put(HOST_VOLUME_ENCRYPTION, String.valueOf(hostSupportsVolumeEncryption()));
|
cmd.getHostDetails().put(HOST_VOLUME_ENCRYPTION, String.valueOf(hostSupportsVolumeEncryption()));
|
||||||
cmd.setHostTags(getHostTags());
|
cmd.setHostTags(getHostTags());
|
||||||
|
cmd.getHostDetails().put(HOST_INSTANCE_CONVERSION, String.valueOf(hostSupportsInstanceConversion()));
|
||||||
HealthCheckResult healthCheckResult = getHostHealthCheckResult();
|
HealthCheckResult healthCheckResult = getHostHealthCheckResult();
|
||||||
if (healthCheckResult != HealthCheckResult.IGNORE) {
|
if (healthCheckResult != HealthCheckResult.IGNORE) {
|
||||||
cmd.setHostHealthCheckResult(healthCheckResult == HealthCheckResult.SUCCESS);
|
cmd.setHostHealthCheckResult(healthCheckResult == HealthCheckResult.SUCCESS);
|
||||||
@ -5163,6 +5175,48 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hostSupportsInstanceConversion() {
|
||||||
|
int exitValue = Script.runSimpleBashScriptForExitValue(INSTANCE_CONVERSION_SUPPORTED_CHECK_CMD);
|
||||||
|
if (isUbuntuHost() && exitValue == 0) {
|
||||||
|
exitValue = Script.runSimpleBashScriptForExitValue(UBUNTU_NBDKIT_PKG_CHECK_CMD);
|
||||||
|
}
|
||||||
|
return exitValue == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hostSupportsWindowsGuestConversion() {
|
||||||
|
if (isUbuntuHost()) {
|
||||||
|
int exitValue = Script.runSimpleBashScriptForExitValue(UBUNTU_WINDOWS_GUEST_CONVERSION_SUPPORTED_CHECK_CMD);
|
||||||
|
return exitValue == 0;
|
||||||
|
}
|
||||||
|
int exitValue = Script.runSimpleBashScriptForExitValue(WINDOWS_GUEST_CONVERSION_SUPPORTED_CHECK_CMD);
|
||||||
|
return exitValue == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hostSupportsOvfExport() {
|
||||||
|
int exitValue = Script.runSimpleBashScriptForExitValue(OVF_EXPORT_SUPPORTED_CHECK_CMD);
|
||||||
|
return exitValue == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean ovfExportToolSupportsParallelThreads() {
|
||||||
|
String ovfExportToolVersion = Script.runSimpleBashScript(OVF_EXPORT_TOOl_GET_VERSION_CMD);
|
||||||
|
if (StringUtils.isBlank(ovfExportToolVersion)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String[] ovfExportToolVersions = ovfExportToolVersion.trim().split("\\.");
|
||||||
|
if (ovfExportToolVersions.length > 1) {
|
||||||
|
try {
|
||||||
|
int majorVersion = Integer.parseInt(ovfExportToolVersions[0]);
|
||||||
|
int minorVersion = Integer.parseInt(ovfExportToolVersions[1]);
|
||||||
|
//ovftool version >= 4.4 supports parallel threads
|
||||||
|
if (majorVersion > 4 || (majorVersion == 4 && minorVersion >= 4)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
protected void setCpuTopology(CpuModeDef cmd, int vCpusInDef, Map<String, String> details) {
|
protected void setCpuTopology(CpuModeDef cmd, int vCpusInDef, Map<String, String> details) {
|
||||||
if (!enableManuallySettingCpuTopologyOnKvmVm) {
|
if (!enableManuallySettingCpuTopologyOnKvmVm) {
|
||||||
LOGGER.debug(String.format("Skipping manually setting CPU topology on VM's XML due to it is disabled in agent.properties {\"property\": \"%s\", \"value\": %s}.",
|
LOGGER.debug(String.format("Skipping manually setting CPU topology on VM's XML due to it is disabled in agent.properties {\"property\": \"%s\", \"value\": %s}.",
|
||||||
|
|||||||
@ -16,6 +16,12 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
package com.cloud.hypervisor.kvm.resource;
|
package com.cloud.hypervisor.kvm.resource;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
|
||||||
public class LibvirtStoragePoolDef {
|
public class LibvirtStoragePoolDef {
|
||||||
public enum PoolType {
|
public enum PoolType {
|
||||||
ISCSI("iscsi"), NETFS("netfs"), loggerICAL("logical"), DIR("dir"), RBD("rbd"), GLUSTERFS("glusterfs"), POWERFLEX("powerflex");
|
ISCSI("iscsi"), NETFS("netfs"), loggerICAL("logical"), DIR("dir"), RBD("rbd"), GLUSTERFS("glusterfs"), POWERFLEX("powerflex");
|
||||||
@ -55,6 +61,7 @@ public class LibvirtStoragePoolDef {
|
|||||||
private String _authUsername;
|
private String _authUsername;
|
||||||
private AuthenticationType _authType;
|
private AuthenticationType _authType;
|
||||||
private String _secretUuid;
|
private String _secretUuid;
|
||||||
|
private Set<String> _nfsMountOpts = new HashSet<>();
|
||||||
|
|
||||||
public LibvirtStoragePoolDef(PoolType type, String poolName, String uuid, String host, int port, String dir, String targetPath) {
|
public LibvirtStoragePoolDef(PoolType type, String poolName, String uuid, String host, int port, String dir, String targetPath) {
|
||||||
_poolType = type;
|
_poolType = type;
|
||||||
@ -75,6 +82,15 @@ public class LibvirtStoragePoolDef {
|
|||||||
_targetPath = targetPath;
|
_targetPath = targetPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LibvirtStoragePoolDef(PoolType type, String poolName, String uuid, String host, String dir, String targetPath, List<String> nfsMountOpts) {
|
||||||
|
this(type, poolName, uuid, host, dir, targetPath);
|
||||||
|
if (CollectionUtils.isNotEmpty(nfsMountOpts)) {
|
||||||
|
for (String nfsMountOpt : nfsMountOpts) {
|
||||||
|
this._nfsMountOpts.add(nfsMountOpt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public LibvirtStoragePoolDef(PoolType type, String poolName, String uuid, String sourceHost, int sourcePort, String dir, String authUsername, AuthenticationType authType,
|
public LibvirtStoragePoolDef(PoolType type, String poolName, String uuid, String sourceHost, int sourcePort, String dir, String authUsername, AuthenticationType authType,
|
||||||
String secretUuid) {
|
String secretUuid) {
|
||||||
_poolType = type;
|
_poolType = type;
|
||||||
@ -124,28 +140,47 @@ public class LibvirtStoragePoolDef {
|
|||||||
return _authType;
|
return _authType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<String> getNfsMountOpts() {
|
||||||
|
return _nfsMountOpts;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder storagePoolBuilder = new StringBuilder();
|
StringBuilder storagePoolBuilder = new StringBuilder();
|
||||||
if (_poolType == PoolType.GLUSTERFS) {
|
String poolTypeXML;
|
||||||
/* libvirt mounts a Gluster volume, similar to NFS */
|
switch (_poolType) {
|
||||||
storagePoolBuilder.append("<pool type='netfs'>\n");
|
case NETFS:
|
||||||
|
if (_nfsMountOpts != null) {
|
||||||
|
poolTypeXML = "netfs' xmlns:fs='http://libvirt.org/schemas/storagepool/fs/1.0";
|
||||||
} else {
|
} else {
|
||||||
storagePoolBuilder.append("<pool type='");
|
poolTypeXML = _poolType.toString();
|
||||||
storagePoolBuilder.append(_poolType);
|
|
||||||
storagePoolBuilder.append("'>\n");
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case GLUSTERFS:
|
||||||
|
/* libvirt mounts a Gluster volume, similar to NFS */
|
||||||
|
poolTypeXML = "netfs";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
poolTypeXML = _poolType.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
storagePoolBuilder.append("<pool type='");
|
||||||
|
storagePoolBuilder.append(poolTypeXML);
|
||||||
|
storagePoolBuilder.append("'>\n");
|
||||||
|
|
||||||
storagePoolBuilder.append("<name>" + _poolName + "</name>\n");
|
storagePoolBuilder.append("<name>" + _poolName + "</name>\n");
|
||||||
if (_uuid != null)
|
if (_uuid != null)
|
||||||
storagePoolBuilder.append("<uuid>" + _uuid + "</uuid>\n");
|
storagePoolBuilder.append("<uuid>" + _uuid + "</uuid>\n");
|
||||||
if (_poolType == PoolType.NETFS) {
|
|
||||||
|
switch (_poolType) {
|
||||||
|
case NETFS:
|
||||||
storagePoolBuilder.append("<source>\n");
|
storagePoolBuilder.append("<source>\n");
|
||||||
storagePoolBuilder.append("<host name='" + _sourceHost + "'/>\n");
|
storagePoolBuilder.append("<host name='" + _sourceHost + "'/>\n");
|
||||||
storagePoolBuilder.append("<dir path='" + _sourceDir + "'/>\n");
|
storagePoolBuilder.append("<dir path='" + _sourceDir + "'/>\n");
|
||||||
storagePoolBuilder.append("</source>\n");
|
storagePoolBuilder.append("</source>\n");
|
||||||
}
|
break;
|
||||||
if (_poolType == PoolType.RBD) {
|
|
||||||
|
case RBD:
|
||||||
storagePoolBuilder.append("<source>\n");
|
storagePoolBuilder.append("<source>\n");
|
||||||
for (String sourceHost : _sourceHost.split(",")) {
|
for (String sourceHost : _sourceHost.split(",")) {
|
||||||
storagePoolBuilder.append("<host name='");
|
storagePoolBuilder.append("<host name='");
|
||||||
@ -164,8 +199,9 @@ public class LibvirtStoragePoolDef {
|
|||||||
storagePoolBuilder.append("</auth>\n");
|
storagePoolBuilder.append("</auth>\n");
|
||||||
}
|
}
|
||||||
storagePoolBuilder.append("</source>\n");
|
storagePoolBuilder.append("</source>\n");
|
||||||
}
|
break;
|
||||||
if (_poolType == PoolType.GLUSTERFS) {
|
|
||||||
|
case GLUSTERFS:
|
||||||
storagePoolBuilder.append("<source>\n");
|
storagePoolBuilder.append("<source>\n");
|
||||||
storagePoolBuilder.append("<host name='");
|
storagePoolBuilder.append("<host name='");
|
||||||
storagePoolBuilder.append(_sourceHost);
|
storagePoolBuilder.append(_sourceHost);
|
||||||
@ -181,12 +217,21 @@ public class LibvirtStoragePoolDef {
|
|||||||
storagePoolBuilder.append(_poolType);
|
storagePoolBuilder.append(_poolType);
|
||||||
storagePoolBuilder.append("'/>\n");
|
storagePoolBuilder.append("'/>\n");
|
||||||
storagePoolBuilder.append("</source>\n");
|
storagePoolBuilder.append("</source>\n");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_poolType != PoolType.RBD && _poolType != PoolType.POWERFLEX) {
|
if (_poolType != PoolType.RBD && _poolType != PoolType.POWERFLEX) {
|
||||||
storagePoolBuilder.append("<target>\n");
|
storagePoolBuilder.append("<target>\n");
|
||||||
storagePoolBuilder.append("<path>" + _targetPath + "</path>\n");
|
storagePoolBuilder.append("<path>" + _targetPath + "</path>\n");
|
||||||
storagePoolBuilder.append("</target>\n");
|
storagePoolBuilder.append("</target>\n");
|
||||||
}
|
}
|
||||||
|
if (_poolType == PoolType.NETFS && _nfsMountOpts != null) {
|
||||||
|
storagePoolBuilder.append("<fs:mount_opts>\n");
|
||||||
|
for (String options : _nfsMountOpts) {
|
||||||
|
storagePoolBuilder.append("<fs:option name='" + options + "'/>\n");
|
||||||
|
}
|
||||||
|
storagePoolBuilder.append("</fs:mount_opts>\n");
|
||||||
|
}
|
||||||
storagePoolBuilder.append("</pool>\n");
|
storagePoolBuilder.append("</pool>\n");
|
||||||
return storagePoolBuilder.toString();
|
return storagePoolBuilder.toString();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,6 +38,19 @@ import org.xml.sax.SAXException;
|
|||||||
public class LibvirtStoragePoolXMLParser {
|
public class LibvirtStoragePoolXMLParser {
|
||||||
protected Logger logger = LogManager.getLogger(getClass());
|
protected Logger logger = LogManager.getLogger(getClass());
|
||||||
|
|
||||||
|
private List<String> getNFSMountOptsFromRootElement(Element rootElement) {
|
||||||
|
List<String> nfsMountOpts = new ArrayList<>();
|
||||||
|
Element mountOpts = (Element) rootElement.getElementsByTagName("fs:mount_opts").item(0);
|
||||||
|
if (mountOpts != null) {
|
||||||
|
NodeList options = mountOpts.getElementsByTagName("fs:option");
|
||||||
|
for (int i = 0; i < options.getLength(); i++) {
|
||||||
|
Element option = (Element) options.item(i);
|
||||||
|
nfsMountOpts.add(option.getAttribute("name"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nfsMountOpts;
|
||||||
|
}
|
||||||
|
|
||||||
public LibvirtStoragePoolDef parseStoragePoolXML(String poolXML) {
|
public LibvirtStoragePoolDef parseStoragePoolXML(String poolXML) {
|
||||||
DocumentBuilder builder;
|
DocumentBuilder builder;
|
||||||
try {
|
try {
|
||||||
@ -95,12 +108,16 @@ public class LibvirtStoragePoolXMLParser {
|
|||||||
poolName, uuid, host, port, path, targetPath);
|
poolName, uuid, host, port, path, targetPath);
|
||||||
} else {
|
} else {
|
||||||
String path = getAttrValue("dir", "path", source);
|
String path = getAttrValue("dir", "path", source);
|
||||||
|
|
||||||
Element target = (Element)rootElement.getElementsByTagName("target").item(0);
|
Element target = (Element)rootElement.getElementsByTagName("target").item(0);
|
||||||
String targetPath = getTagValue("path", target);
|
String targetPath = getTagValue("path", target);
|
||||||
|
|
||||||
|
if (type.equalsIgnoreCase("netfs")) {
|
||||||
|
List<String> nfsMountOpts = getNFSMountOptsFromRootElement(rootElement);
|
||||||
|
return new LibvirtStoragePoolDef(LibvirtStoragePoolDef.PoolType.valueOf(type.toUpperCase()), poolName, uuid, host, path, targetPath, nfsMountOpts);
|
||||||
|
} else {
|
||||||
return new LibvirtStoragePoolDef(LibvirtStoragePoolDef.PoolType.valueOf(type.toUpperCase()), poolName, uuid, host, path, targetPath);
|
return new LibvirtStoragePoolDef(LibvirtStoragePoolDef.PoolType.valueOf(type.toUpperCase()), poolName, uuid, host, path, targetPath);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} catch (ParserConfigurationException e) {
|
} catch (ParserConfigurationException e) {
|
||||||
logger.debug(e.toString());
|
logger.debug(e.toString());
|
||||||
} catch (SAXException e) {
|
} catch (SAXException e) {
|
||||||
|
|||||||
@ -0,0 +1,57 @@
|
|||||||
|
//
|
||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you under the Apache License, Version 2.0 (the
|
||||||
|
// "License"); you may not use this file except in compliance
|
||||||
|
// with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing,
|
||||||
|
// software distributed under the License is distributed on an
|
||||||
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations
|
||||||
|
// under the License.
|
||||||
|
//
|
||||||
|
package com.cloud.hypervisor.kvm.resource.wrapper;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import com.cloud.agent.api.Answer;
|
||||||
|
import com.cloud.agent.api.CheckConvertInstanceAnswer;
|
||||||
|
import com.cloud.agent.api.CheckConvertInstanceCommand;
|
||||||
|
import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
|
||||||
|
import com.cloud.resource.CommandWrapper;
|
||||||
|
import com.cloud.resource.ResourceWrapper;
|
||||||
|
|
||||||
|
@ResourceWrapper(handles = CheckConvertInstanceCommand.class)
|
||||||
|
public class LibvirtCheckConvertInstanceCommandWrapper extends CommandWrapper<CheckConvertInstanceCommand, Answer, LibvirtComputingResource> {
|
||||||
|
|
||||||
|
private static final Logger s_logger = Logger.getLogger(LibvirtCheckConvertInstanceCommandWrapper.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Answer execute(CheckConvertInstanceCommand cmd, LibvirtComputingResource serverResource) {
|
||||||
|
if (!serverResource.hostSupportsInstanceConversion()) {
|
||||||
|
String msg = String.format("Cannot convert the instance from VMware as the virt-v2v binary is not found on host %s. " +
|
||||||
|
"Please install virt-v2v%s on the host before attempting the instance conversion.", serverResource.getPrivateIp(), serverResource.isUbuntuHost()? ", nbdkit" : "");
|
||||||
|
s_logger.info(msg);
|
||||||
|
return new CheckConvertInstanceAnswer(cmd, false, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd.getCheckWindowsGuestConversionSupport() && !serverResource.hostSupportsWindowsGuestConversion()) {
|
||||||
|
String msg = String.format("Cannot convert the instance from VMware as the virtio-win package is not found on host %s. " +
|
||||||
|
"Please install virtio-win package on the host before attempting the windows guest instance conversion.", serverResource.getPrivateIp());
|
||||||
|
s_logger.info(msg);
|
||||||
|
return new CheckConvertInstanceAnswer(cmd, false, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serverResource.hostSupportsOvfExport()) {
|
||||||
|
return new CheckConvertInstanceAnswer(cmd, true, true, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CheckConvertInstanceAnswer(cmd, true, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -62,8 +62,6 @@ public class LibvirtConvertInstanceCommandWrapper extends CommandWrapper<Convert
|
|||||||
private static final List<Hypervisor.HypervisorType> supportedInstanceConvertSourceHypervisors =
|
private static final List<Hypervisor.HypervisorType> supportedInstanceConvertSourceHypervisors =
|
||||||
List.of(Hypervisor.HypervisorType.VMware);
|
List.of(Hypervisor.HypervisorType.VMware);
|
||||||
|
|
||||||
protected static final String checkIfConversionIsSupportedCommand = "which virt-v2v";
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Answer execute(ConvertInstanceCommand cmd, LibvirtComputingResource serverResource) {
|
public Answer execute(ConvertInstanceCommand cmd, LibvirtComputingResource serverResource) {
|
||||||
RemoteInstanceTO sourceInstance = cmd.getSourceInstance();
|
RemoteInstanceTO sourceInstance = cmd.getSourceInstance();
|
||||||
@ -74,9 +72,9 @@ public class LibvirtConvertInstanceCommandWrapper extends CommandWrapper<Convert
|
|||||||
DataStoreTO conversionTemporaryLocation = cmd.getConversionTemporaryLocation();
|
DataStoreTO conversionTemporaryLocation = cmd.getConversionTemporaryLocation();
|
||||||
long timeout = (long) cmd.getWait() * 1000;
|
long timeout = (long) cmd.getWait() * 1000;
|
||||||
|
|
||||||
if (!isInstanceConversionSupportedOnHost()) {
|
if (cmd.getCheckConversionSupport() && !serverResource.hostSupportsInstanceConversion()) {
|
||||||
String msg = String.format("Cannot convert the instance %s from VMware as the virt-v2v binary is not found. " +
|
String msg = String.format("Cannot convert the instance %s from VMware as the virt-v2v binary is not found. " +
|
||||||
"Please install virt-v2v on the host before attempting the instance conversion", sourceInstanceName);
|
"Please install virt-v2v%s on the host before attempting the instance conversion.", sourceInstanceName, serverResource.isUbuntuHost()? ", nbdkit" : "");
|
||||||
logger.info(msg);
|
logger.info(msg);
|
||||||
return new ConvertInstanceAnswer(cmd, false, msg);
|
return new ConvertInstanceAnswer(cmd, false, msg);
|
||||||
}
|
}
|
||||||
@ -94,18 +92,48 @@ public class LibvirtConvertInstanceCommandWrapper extends CommandWrapper<Convert
|
|||||||
|
|
||||||
logger.info(String.format("Attempting to convert the instance %s from %s to KVM",
|
logger.info(String.format("Attempting to convert the instance %s from %s to KVM",
|
||||||
sourceInstanceName, sourceHypervisorType));
|
sourceInstanceName, sourceHypervisorType));
|
||||||
final String convertInstanceUrl = getConvertInstanceUrl(sourceInstance);
|
|
||||||
final String temporaryConvertUuid = UUID.randomUUID().toString();
|
|
||||||
final String temporaryPasswordFilePath = createTemporaryPasswordFileAndRetrievePath(sourceInstance);
|
|
||||||
final String temporaryConvertPath = temporaryStoragePool.getLocalPath();
|
final String temporaryConvertPath = temporaryStoragePool.getLocalPath();
|
||||||
|
|
||||||
|
String ovfTemplateDirOnConversionLocation;
|
||||||
|
String sourceOVFDirPath;
|
||||||
|
boolean ovfExported = false;
|
||||||
|
if (cmd.getExportOvfToConversionLocation()) {
|
||||||
|
String exportInstanceOVAUrl = getExportInstanceOVAUrl(sourceInstance);
|
||||||
|
if (StringUtils.isBlank(exportInstanceOVAUrl)) {
|
||||||
|
String err = String.format("Couldn't export OVA for the VM %s, due to empty url", sourceInstanceName);
|
||||||
|
logger.error(err);
|
||||||
|
return new ConvertInstanceAnswer(cmd, false, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
int noOfThreads = cmd.getThreadsCountToExportOvf();
|
||||||
|
if (noOfThreads > 1 && !serverResource.ovfExportToolSupportsParallelThreads()) {
|
||||||
|
noOfThreads = 0;
|
||||||
|
}
|
||||||
|
ovfTemplateDirOnConversionLocation = UUID.randomUUID().toString();
|
||||||
|
temporaryStoragePool.createFolder(ovfTemplateDirOnConversionLocation);
|
||||||
|
sourceOVFDirPath = String.format("%s/%s/", temporaryConvertPath, ovfTemplateDirOnConversionLocation);
|
||||||
|
ovfExported = exportOVAFromVMOnVcenter(exportInstanceOVAUrl, sourceOVFDirPath, noOfThreads, timeout);
|
||||||
|
if (!ovfExported) {
|
||||||
|
String err = String.format("Export OVA for the VM %s failed", sourceInstanceName);
|
||||||
|
logger.error(err);
|
||||||
|
return new ConvertInstanceAnswer(cmd, false, err);
|
||||||
|
}
|
||||||
|
sourceOVFDirPath = String.format("%s%s/", sourceOVFDirPath, sourceInstanceName);
|
||||||
|
} else {
|
||||||
|
ovfTemplateDirOnConversionLocation = cmd.getTemplateDirOnConversionLocation();
|
||||||
|
sourceOVFDirPath = String.format("%s/%s/", temporaryConvertPath, ovfTemplateDirOnConversionLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info(String.format("Attempting to convert the OVF %s of the instance %s from %s to KVM", ovfTemplateDirOnConversionLocation, sourceInstanceName, sourceHypervisorType));
|
||||||
|
final String temporaryConvertUuid = UUID.randomUUID().toString();
|
||||||
boolean verboseModeEnabled = serverResource.isConvertInstanceVerboseModeEnabled();
|
boolean verboseModeEnabled = serverResource.isConvertInstanceVerboseModeEnabled();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
boolean result = performInstanceConversion(convertInstanceUrl, sourceInstanceName, temporaryPasswordFilePath,
|
boolean result = performInstanceConversion(sourceOVFDirPath, temporaryConvertPath, temporaryConvertUuid,
|
||||||
temporaryConvertPath, temporaryConvertUuid, timeout, verboseModeEnabled);
|
timeout, verboseModeEnabled);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
String err = String.format("The virt-v2v conversion of the instance %s failed. " +
|
String err = String.format("The virt-v2v conversion for the OVF %s failed. " +
|
||||||
"Please check the agent logs for the virt-v2v output", sourceInstanceName);
|
"Please check the agent logs for the virt-v2v output", ovfTemplateDirOnConversionLocation);
|
||||||
logger.error(err);
|
logger.error(err);
|
||||||
return new ConvertInstanceAnswer(cmd, false, err);
|
return new ConvertInstanceAnswer(cmd, false, err);
|
||||||
}
|
}
|
||||||
@ -130,8 +158,11 @@ public class LibvirtConvertInstanceCommandWrapper extends CommandWrapper<Convert
|
|||||||
logger.error(error, e);
|
logger.error(error, e);
|
||||||
return new ConvertInstanceAnswer(cmd, false, error);
|
return new ConvertInstanceAnswer(cmd, false, error);
|
||||||
} finally {
|
} finally {
|
||||||
logger.debug("Cleaning up instance conversion temporary password file");
|
if (ovfExported && StringUtils.isNotBlank(ovfTemplateDirOnConversionLocation)) {
|
||||||
Script.runSimpleBashScript(String.format("rm -rf %s", temporaryPasswordFilePath));
|
String sourceOVFDir = String.format("%s/%s", temporaryConvertPath, ovfTemplateDirOnConversionLocation);
|
||||||
|
logger.debug("Cleaning up exported OVA at dir " + sourceOVFDir);
|
||||||
|
Script.runSimpleBashScript("rm -rf " + sourceOVFDir);
|
||||||
|
}
|
||||||
if (conversionTemporaryLocation instanceof NfsTO) {
|
if (conversionTemporaryLocation instanceof NfsTO) {
|
||||||
logger.debug("Cleaning up secondary storage temporary location");
|
logger.debug("Cleaning up secondary storage temporary location");
|
||||||
storagePoolMgr.deleteStoragePool(temporaryStoragePool.getType(), temporaryStoragePool.getUuid());
|
storagePoolMgr.deleteStoragePool(temporaryStoragePool.getType(), temporaryStoragePool.getUuid());
|
||||||
@ -155,6 +186,27 @@ public class LibvirtConvertInstanceCommandWrapper extends CommandWrapper<Convert
|
|||||||
supportedInstanceConvertSourceHypervisors.contains(sourceHypervisorType);
|
supportedInstanceConvertSourceHypervisors.contains(sourceHypervisorType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getExportInstanceOVAUrl(RemoteInstanceTO sourceInstance) {
|
||||||
|
String url = null;
|
||||||
|
if (sourceInstance.getHypervisorType() == Hypervisor.HypervisorType.VMware) {
|
||||||
|
url = getExportOVAUrlFromRemoteInstance(sourceInstance);
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getExportOVAUrlFromRemoteInstance(RemoteInstanceTO vmwareInstance) {
|
||||||
|
String vcenter = vmwareInstance.getVcenterHost();
|
||||||
|
String username = vmwareInstance.getVcenterUsername();
|
||||||
|
String password = vmwareInstance.getVcenterPassword();
|
||||||
|
String datacenter = vmwareInstance.getDatacenterName();
|
||||||
|
String vm = vmwareInstance.getInstanceName();
|
||||||
|
|
||||||
|
String encodedUsername = encodeUsername(username);
|
||||||
|
String encodedPassword = encodeUsername(password);
|
||||||
|
return String.format("vi://%s:%s@%s/%s/vm/%s",
|
||||||
|
encodedUsername, encodedPassword, vcenter, datacenter, vm);
|
||||||
|
}
|
||||||
|
|
||||||
protected List<KVMPhysicalDisk> getTemporaryDisksFromParsedXml(KVMStoragePool pool, LibvirtDomainXMLParser xmlParser, String convertedBasePath) {
|
protected List<KVMPhysicalDisk> getTemporaryDisksFromParsedXml(KVMStoragePool pool, LibvirtDomainXMLParser xmlParser, String convertedBasePath) {
|
||||||
List<LibvirtVMDef.DiskDef> disksDefs = xmlParser.getDisks();
|
List<LibvirtVMDef.DiskDef> disksDefs = xmlParser.getDisks();
|
||||||
disksDefs = disksDefs.stream().filter(x -> x.getDiskType() == LibvirtVMDef.DiskDef.DiskType.FILE &&
|
disksDefs = disksDefs.stream().filter(x -> x.getDiskType() == LibvirtVMDef.DiskDef.DiskType.FILE &&
|
||||||
@ -204,11 +256,6 @@ public class LibvirtConvertInstanceCommandWrapper extends CommandWrapper<Convert
|
|||||||
Script.runSimpleBashScript(String.format("rm -f %s/%s*.xml", temporaryStoragePool.getLocalPath(), temporaryConvertUuid));
|
Script.runSimpleBashScript(String.format("rm -f %s/%s*.xml", temporaryStoragePool.getLocalPath(), temporaryConvertUuid));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isInstanceConversionSupportedOnHost() {
|
|
||||||
int exitValue = Script.runSimpleBashScriptForExitValue(checkIfConversionIsSupportedCommand);
|
|
||||||
return exitValue == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void sanitizeDisksPath(List<LibvirtVMDef.DiskDef> disks) {
|
protected void sanitizeDisksPath(List<LibvirtVMDef.DiskDef> disks) {
|
||||||
for (LibvirtVMDef.DiskDef disk : disks) {
|
for (LibvirtVMDef.DiskDef disk : disks) {
|
||||||
String[] diskPathParts = disk.getDiskPath().split("/");
|
String[] diskPathParts = disk.getDiskPath().split("/");
|
||||||
@ -234,6 +281,11 @@ public class LibvirtConvertInstanceCommandWrapper extends CommandWrapper<Convert
|
|||||||
logger.error(err);
|
logger.error(err);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (destinationPool.getType() != Storage.StoragePoolType.NetworkFilesystem) {
|
||||||
|
String err = String.format("Storage pool by URI: %s is not an NFS storage", poolPath);
|
||||||
|
logger.error(err);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
KVMPhysicalDisk sourceDisk = temporaryDisks.get(i);
|
KVMPhysicalDisk sourceDisk = temporaryDisks.get(i);
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
String msg = String.format("Trying to copy converted instance disk number %s from the temporary location %s" +
|
String msg = String.format("Trying to copy converted instance disk number %s from the temporary location %s" +
|
||||||
@ -305,25 +357,45 @@ public class LibvirtConvertInstanceCommandWrapper extends CommandWrapper<Convert
|
|||||||
String sourceHostIp = null;
|
String sourceHostIp = null;
|
||||||
String sourcePath = null;
|
String sourcePath = null;
|
||||||
String storagePoolMountPoint = Script.runSimpleBashScript(String.format("mount | grep %s", storagePool.getLocalPath()));
|
String storagePoolMountPoint = Script.runSimpleBashScript(String.format("mount | grep %s", storagePool.getLocalPath()));
|
||||||
|
logger.debug(String.format("NFS Storage pool: %s - local path: %s, mount point: %s", storagePool.getUuid(), storagePool.getLocalPath(), storagePoolMountPoint));
|
||||||
if (StringUtils.isNotEmpty(storagePoolMountPoint)) {
|
if (StringUtils.isNotEmpty(storagePoolMountPoint)) {
|
||||||
String[] res = storagePoolMountPoint.strip().split(" ");
|
String[] res = storagePoolMountPoint.strip().split(" ");
|
||||||
res = res[0].split(":");
|
res = res[0].split(":");
|
||||||
|
if (res.length > 1) {
|
||||||
sourceHostIp = res[0].strip();
|
sourceHostIp = res[0].strip();
|
||||||
sourcePath = res[1].strip();
|
sourcePath = res[1].strip();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return new Pair<>(sourceHostIp, sourcePath);
|
return new Pair<>(sourceHostIp, sourcePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean performInstanceConversion(String convertInstanceUrl, String sourceInstanceName,
|
private boolean exportOVAFromVMOnVcenter(String vmExportUrl,
|
||||||
String temporaryPasswordFilePath,
|
String targetOvfDir,
|
||||||
|
int noOfThreads,
|
||||||
|
long timeout) {
|
||||||
|
Script script = new Script("ovftool", timeout, logger);
|
||||||
|
script.add("--noSSLVerify");
|
||||||
|
if (noOfThreads > 1) {
|
||||||
|
script.add(String.format("--parallelThreads=%s", noOfThreads));
|
||||||
|
}
|
||||||
|
script.add(vmExportUrl);
|
||||||
|
script.add(targetOvfDir);
|
||||||
|
|
||||||
|
String logPrefix = "export ovf";
|
||||||
|
OutputInterpreter.LineByLineOutputLogger outputLogger = new OutputInterpreter.LineByLineOutputLogger(logger, logPrefix);
|
||||||
|
script.execute(outputLogger);
|
||||||
|
int exitValue = script.getExitValue();
|
||||||
|
return exitValue == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean performInstanceConversion(String sourceOVFDirPath,
|
||||||
String temporaryConvertFolder,
|
String temporaryConvertFolder,
|
||||||
String temporaryConvertUuid,
|
String temporaryConvertUuid,
|
||||||
long timeout, boolean verboseModeEnabled) {
|
long timeout, boolean verboseModeEnabled) {
|
||||||
Script script = new Script("virt-v2v", timeout, logger);
|
Script script = new Script("virt-v2v", timeout, logger);
|
||||||
script.add("--root", "first");
|
script.add("--root", "first");
|
||||||
script.add("-ic", convertInstanceUrl);
|
script.add("-i", "ova");
|
||||||
script.add(sourceInstanceName);
|
script.add(sourceOVFDirPath);
|
||||||
script.add("--password-file", temporaryPasswordFilePath);
|
|
||||||
script.add("-o", "local");
|
script.add("-o", "local");
|
||||||
script.add("-os", temporaryConvertFolder);
|
script.add("-os", temporaryConvertFolder);
|
||||||
script.add("-of", "qcow2");
|
script.add("-of", "qcow2");
|
||||||
@ -332,44 +404,13 @@ public class LibvirtConvertInstanceCommandWrapper extends CommandWrapper<Convert
|
|||||||
script.add("-v");
|
script.add("-v");
|
||||||
}
|
}
|
||||||
|
|
||||||
String logPrefix = String.format("virt-v2v source: %s %s progress", convertInstanceUrl, sourceInstanceName);
|
String logPrefix = String.format("virt-v2v ovf source: %s progress", sourceOVFDirPath);
|
||||||
OutputInterpreter.LineByLineOutputLogger outputLogger = new OutputInterpreter.LineByLineOutputLogger(logger, logPrefix);
|
OutputInterpreter.LineByLineOutputLogger outputLogger = new OutputInterpreter.LineByLineOutputLogger(logger, logPrefix);
|
||||||
script.execute(outputLogger);
|
script.execute(outputLogger);
|
||||||
int exitValue = script.getExitValue();
|
int exitValue = script.getExitValue();
|
||||||
return exitValue == 0;
|
return exitValue == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String createTemporaryPasswordFileAndRetrievePath(RemoteInstanceTO sourceInstance) {
|
|
||||||
String password = null;
|
|
||||||
if (sourceInstance.getHypervisorType() == Hypervisor.HypervisorType.VMware) {
|
|
||||||
password = sourceInstance.getVcenterPassword();
|
|
||||||
}
|
|
||||||
String passwordFile = String.format("/tmp/vmw-%s", UUID.randomUUID());
|
|
||||||
String msg = String.format("Creating a temporary password file for VMware instance %s conversion on: %s", sourceInstance.getInstanceName(), passwordFile);
|
|
||||||
logger.debug(msg);
|
|
||||||
Script.runSimpleBashScriptForExitValueAvoidLogging(String.format("echo \"%s\" > %s", password, passwordFile));
|
|
||||||
return passwordFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getConvertInstanceUrl(RemoteInstanceTO sourceInstance) {
|
|
||||||
String url = null;
|
|
||||||
if (sourceInstance.getHypervisorType() == Hypervisor.HypervisorType.VMware) {
|
|
||||||
url = getConvertInstanceUrlFromVmware(sourceInstance);
|
|
||||||
}
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getConvertInstanceUrlFromVmware(RemoteInstanceTO vmwareInstance) {
|
|
||||||
String vcenter = vmwareInstance.getVcenterHost();
|
|
||||||
String datacenter = vmwareInstance.getDatacenterName();
|
|
||||||
String username = vmwareInstance.getVcenterUsername();
|
|
||||||
String host = vmwareInstance.getHostName();
|
|
||||||
String cluster = vmwareInstance.getClusterName();
|
|
||||||
|
|
||||||
String encodedUsername = encodeUsername(username);
|
|
||||||
return String.format("vpx://%s@%s/%s/%s/%s?no_verify=1",
|
|
||||||
encodedUsername, vcenter, datacenter, cluster, host);
|
|
||||||
}
|
|
||||||
protected LibvirtDomainXMLParser parseMigratedVMXmlDomain(String installPath) throws IOException {
|
protected LibvirtDomainXMLParser parseMigratedVMXmlDomain(String installPath) throws IOException {
|
||||||
String xmlPath = String.format("%s.xml", installPath);
|
String xmlPath = String.format("%s.xml", installPath);
|
||||||
if (!new File(xmlPath).exists()) {
|
if (!new File(xmlPath).exists()) {
|
||||||
|
|||||||
@ -25,6 +25,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
import org.apache.cloudstack.utils.cryptsetup.KeyFile;
|
import org.apache.cloudstack.utils.cryptsetup.KeyFile;
|
||||||
import org.apache.cloudstack.utils.qemu.QemuImg;
|
import org.apache.cloudstack.utils.qemu.QemuImg;
|
||||||
import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
|
import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
|
||||||
@ -34,6 +35,7 @@ import org.apache.cloudstack.utils.qemu.QemuObject;
|
|||||||
import org.apache.commons.codec.binary.Base64;
|
import org.apache.commons.codec.binary.Base64;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.libvirt.Connect;
|
import org.libvirt.Connect;
|
||||||
import org.libvirt.LibvirtException;
|
import org.libvirt.LibvirtException;
|
||||||
import org.libvirt.Secret;
|
import org.libvirt.Secret;
|
||||||
@ -283,9 +285,9 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private StoragePool createNetfsStoragePool(PoolType fsType, Connect conn, String uuid, String host, String path) throws LibvirtException {
|
private StoragePool createNetfsStoragePool(PoolType fsType, Connect conn, String uuid, String host, String path, List<String> nfsMountOpts) throws LibvirtException {
|
||||||
String targetPath = _mountPoint + File.separator + uuid;
|
String targetPath = _mountPoint + File.separator + uuid;
|
||||||
LibvirtStoragePoolDef spd = new LibvirtStoragePoolDef(fsType, uuid, uuid, host, path, targetPath);
|
LibvirtStoragePoolDef spd = new LibvirtStoragePoolDef(fsType, uuid, uuid, host, path, targetPath, nfsMountOpts);
|
||||||
_storageLayer.mkdir(targetPath);
|
_storageLayer.mkdir(targetPath);
|
||||||
StoragePool sp = null;
|
StoragePool sp = null;
|
||||||
try {
|
try {
|
||||||
@ -374,6 +376,42 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<String> getNFSMountOptsFromDetails(StoragePoolType type, Map<String, String> details) {
|
||||||
|
List<String> nfsMountOpts = null;
|
||||||
|
if (!type.equals(StoragePoolType.NetworkFilesystem) || details == null) {
|
||||||
|
return nfsMountOpts;
|
||||||
|
}
|
||||||
|
if (details.containsKey(ApiConstants.NFS_MOUNT_OPTIONS)) {
|
||||||
|
nfsMountOpts = Arrays.asList(details.get(ApiConstants.NFS_MOUNT_OPTIONS).replaceAll("\\s", "").split(","));
|
||||||
|
}
|
||||||
|
return nfsMountOpts;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean destroyStoragePoolOnNFSMountOptionsChange(StoragePool sp, Connect conn, List<String> nfsMountOpts) {
|
||||||
|
try {
|
||||||
|
LibvirtStoragePoolDef poolDef = getStoragePoolDef(conn, sp);
|
||||||
|
Set poolNfsMountOpts = poolDef.getNfsMountOpts();
|
||||||
|
boolean mountOptsDiffer = false;
|
||||||
|
if (poolNfsMountOpts.size() != nfsMountOpts.size()) {
|
||||||
|
mountOptsDiffer = true;
|
||||||
|
} else {
|
||||||
|
for (String nfsMountOpt : nfsMountOpts) {
|
||||||
|
if (!poolNfsMountOpts.contains(nfsMountOpt)) {
|
||||||
|
mountOptsDiffer = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mountOptsDiffer) {
|
||||||
|
sp.destroy();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (LibvirtException e) {
|
||||||
|
logger.error("Failure in destroying the pre-existing storage pool for changing the NFS mount options" + e);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private StoragePool createRBDStoragePool(Connect conn, String uuid, String host, int port, String userInfo, String path) {
|
private StoragePool createRBDStoragePool(Connect conn, String uuid, String host, int port, String userInfo, String path) {
|
||||||
|
|
||||||
LibvirtStoragePoolDef spd;
|
LibvirtStoragePoolDef spd;
|
||||||
@ -671,12 +709,21 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
|
|||||||
} catch (LibvirtException e) {
|
} catch (LibvirtException e) {
|
||||||
logger.error("Failure in attempting to see if an existing storage pool might be using the path of the pool to be created:" + e);
|
logger.error("Failure in attempting to see if an existing storage pool might be using the path of the pool to be created:" + e);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> nfsMountOpts = getNFSMountOptsFromDetails(type, details);
|
||||||
|
if (sp != null && CollectionUtils.isNotEmpty(nfsMountOpts) &&
|
||||||
|
destroyStoragePoolOnNFSMountOptionsChange(sp, conn, nfsMountOpts)) {
|
||||||
|
sp = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sp == null) {
|
||||||
|
|
||||||
logger.debug("Attempting to create storage pool " + name);
|
logger.debug("Attempting to create storage pool " + name);
|
||||||
|
|
||||||
if (type == StoragePoolType.NetworkFilesystem) {
|
if (type == StoragePoolType.NetworkFilesystem) {
|
||||||
try {
|
try {
|
||||||
sp = createNetfsStoragePool(PoolType.NETFS, conn, name, host, path);
|
sp = createNetfsStoragePool(PoolType.NETFS, conn, name, host, path, nfsMountOpts);
|
||||||
} catch (LibvirtException e) {
|
} catch (LibvirtException e) {
|
||||||
logger.error("Failed to create netfs mount: " + host + ":" + path , e);
|
logger.error("Failed to create netfs mount: " + host + ":" + path , e);
|
||||||
logger.error(e.getStackTrace());
|
logger.error(e.getStackTrace());
|
||||||
@ -684,7 +731,7 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
|
|||||||
}
|
}
|
||||||
} else if (type == StoragePoolType.Gluster) {
|
} else if (type == StoragePoolType.Gluster) {
|
||||||
try {
|
try {
|
||||||
sp = createNetfsStoragePool(PoolType.GLUSTERFS, conn, name, host, path);
|
sp = createNetfsStoragePool(PoolType.GLUSTERFS, conn, name, host, path, null);
|
||||||
} catch (LibvirtException e) {
|
} catch (LibvirtException e) {
|
||||||
logger.error("Failed to create glusterfs mount: " + host + ":" + path , e);
|
logger.error("Failed to create glusterfs mount: " + host + ":" + path , e);
|
||||||
logger.error(e.getStackTrace());
|
logger.error(e.getStackTrace());
|
||||||
|
|||||||
@ -19,6 +19,9 @@
|
|||||||
|
|
||||||
package com.cloud.hypervisor.kvm.resource;
|
package com.cloud.hypervisor.kvm.resource;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
import com.cloud.hypervisor.kvm.resource.LibvirtStoragePoolDef.PoolType;
|
import com.cloud.hypervisor.kvm.resource.LibvirtStoragePoolDef.PoolType;
|
||||||
import com.cloud.hypervisor.kvm.resource.LibvirtStoragePoolDef.AuthenticationType;
|
import com.cloud.hypervisor.kvm.resource.LibvirtStoragePoolDef.AuthenticationType;
|
||||||
@ -47,6 +50,14 @@ public class LibvirtStoragePoolDefTest extends TestCase {
|
|||||||
assertEquals(port, pool.getSourcePort());
|
assertEquals(port, pool.getSourcePort());
|
||||||
assertEquals(dir, pool.getSourceDir());
|
assertEquals(dir, pool.getSourceDir());
|
||||||
assertEquals(targetPath, pool.getTargetPath());
|
assertEquals(targetPath, pool.getTargetPath());
|
||||||
|
|
||||||
|
List<String> nfsMountOpts = new ArrayList<>();
|
||||||
|
nfsMountOpts.add("vers=4.1");
|
||||||
|
nfsMountOpts.add("nconnect=4");
|
||||||
|
pool = new LibvirtStoragePoolDef(type, name, uuid, host, dir, targetPath, nfsMountOpts);
|
||||||
|
assertTrue(pool.getNfsMountOpts().contains("vers=4.1"));
|
||||||
|
assertTrue(pool.getNfsMountOpts().contains("nconnect=4"));
|
||||||
|
assertEquals(pool.getNfsMountOpts().size(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -57,11 +68,37 @@ public class LibvirtStoragePoolDefTest extends TestCase {
|
|||||||
String host = "127.0.0.1";
|
String host = "127.0.0.1";
|
||||||
String dir = "/export/primary";
|
String dir = "/export/primary";
|
||||||
String targetPath = "/mnt/" + uuid;
|
String targetPath = "/mnt/" + uuid;
|
||||||
|
List<String> nfsMountOpts = new ArrayList<>();
|
||||||
|
nfsMountOpts.add("vers=4.1");
|
||||||
|
nfsMountOpts.add("nconnect=4");
|
||||||
|
|
||||||
LibvirtStoragePoolDef pool = new LibvirtStoragePoolDef(type, name, uuid, host, dir, targetPath);
|
LibvirtStoragePoolDef pool = new LibvirtStoragePoolDef(type, name, uuid, host, dir, targetPath, nfsMountOpts);
|
||||||
|
|
||||||
String expectedXml = "<pool type='" + type.toString() + "'>\n<name>" + name + "</name>\n<uuid>" + uuid + "</uuid>\n" +
|
String expectedXml = "<pool type='" + type.toString() + "' xmlns:fs='http://libvirt.org/schemas/storagepool/fs/1.0'>\n" +
|
||||||
|
"<name>" +name + "</name>\n<uuid>" + uuid + "</uuid>\n" +
|
||||||
"<source>\n<host name='" + host + "'/>\n<dir path='" + dir + "'/>\n</source>\n<target>\n" +
|
"<source>\n<host name='" + host + "'/>\n<dir path='" + dir + "'/>\n</source>\n<target>\n" +
|
||||||
|
"<path>" + targetPath + "</path>\n</target>\n" +
|
||||||
|
"<fs:mount_opts>\n<fs:option name='vers=4.1'/>\n<fs:option name='nconnect=4'/>\n</fs:mount_opts>\n</pool>\n";
|
||||||
|
|
||||||
|
assertEquals(expectedXml, pool.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGlusterFSStoragePool() {
|
||||||
|
PoolType type = PoolType.GLUSTERFS;
|
||||||
|
String name = "myGFSPool";
|
||||||
|
String uuid = "89a605bc-d470-4637-b3df-27388be452f5";
|
||||||
|
String host = "127.0.0.1";
|
||||||
|
String dir = "/export/primary";
|
||||||
|
String targetPath = "/mnt/" + uuid;
|
||||||
|
List<String> nfsMountOpts = new ArrayList<>();
|
||||||
|
|
||||||
|
LibvirtStoragePoolDef pool = new LibvirtStoragePoolDef(type, name, uuid, host, dir, targetPath, nfsMountOpts);
|
||||||
|
|
||||||
|
String expectedXml = "<pool type='netfs'>\n" +
|
||||||
|
"<name>" +name + "</name>\n<uuid>" + uuid + "</uuid>\n" +
|
||||||
|
"<source>\n<host name='" + host + "'/>\n<dir path='" + dir + "'/>\n" +
|
||||||
|
"<format type='glusterfs'/>\n</source>\n<target>\n" +
|
||||||
"<path>" + targetPath + "</path>\n</target>\n</pool>\n";
|
"<path>" + targetPath + "</path>\n</target>\n</pool>\n";
|
||||||
|
|
||||||
assertEquals(expectedXml, pool.toString());
|
assertEquals(expectedXml, pool.toString());
|
||||||
|
|||||||
@ -30,7 +30,7 @@ public class LibvirtStoragePoolXMLParserTest extends TestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParseNfsStoragePoolXML() {
|
public void testParseNfsStoragePoolXML() {
|
||||||
String poolXML = "<pool type='netfs'>\n" +
|
String poolXML = "<pool type='netfs' xmlns:fs='http://libvirt.org/schemas/storagepool/fs/1.0'>\n" +
|
||||||
" <name>feff06b5-84b2-3258-b5f9-1953217295de</name>\n" +
|
" <name>feff06b5-84b2-3258-b5f9-1953217295de</name>\n" +
|
||||||
" <uuid>feff06b5-84b2-3258-b5f9-1953217295de</uuid>\n" +
|
" <uuid>feff06b5-84b2-3258-b5f9-1953217295de</uuid>\n" +
|
||||||
" <capacity unit='bytes'>111111111</capacity>\n" +
|
" <capacity unit='bytes'>111111111</capacity>\n" +
|
||||||
@ -49,12 +49,18 @@ public class LibvirtStoragePoolXMLParserTest extends TestCase {
|
|||||||
" <group>0</group>\n" +
|
" <group>0</group>\n" +
|
||||||
" </permissions>\n" +
|
" </permissions>\n" +
|
||||||
" </target>\n" +
|
" </target>\n" +
|
||||||
|
" <fs:mount_opts>\n" +
|
||||||
|
" <fs:option name='nconnect=8'/>\n" +
|
||||||
|
" <fs:option name='vers=4.1'/>\n" +
|
||||||
|
" </fs:mount_opts>\n" +
|
||||||
"</pool>";
|
"</pool>";
|
||||||
|
|
||||||
LibvirtStoragePoolXMLParser parser = new LibvirtStoragePoolXMLParser();
|
LibvirtStoragePoolXMLParser parser = new LibvirtStoragePoolXMLParser();
|
||||||
LibvirtStoragePoolDef pool = parser.parseStoragePoolXML(poolXML);
|
LibvirtStoragePoolDef pool = parser.parseStoragePoolXML(poolXML);
|
||||||
|
|
||||||
Assert.assertEquals("10.11.12.13", pool.getSourceHost());
|
assertEquals("10.11.12.13", pool.getSourceHost());
|
||||||
|
assertTrue(pool.getNfsMountOpts().contains("vers=4.1"));
|
||||||
|
assertTrue(pool.getNfsMountOpts().contains("nconnect=8"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@ -0,0 +1,67 @@
|
|||||||
|
//
|
||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you under the Apache License, Version 2.0 (the
|
||||||
|
// "License"); you may not use this file except in compliance
|
||||||
|
// with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing,
|
||||||
|
// software distributed under the License is distributed on an
|
||||||
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations
|
||||||
|
// under the License.
|
||||||
|
//
|
||||||
|
package com.cloud.hypervisor.kvm.resource.wrapper;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.mockito.Spy;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
|
import com.cloud.agent.api.Answer;
|
||||||
|
import com.cloud.agent.api.CheckConvertInstanceCommand;
|
||||||
|
import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class LibvirtCheckConvertInstanceCommandWrapperTest {
|
||||||
|
|
||||||
|
@Spy
|
||||||
|
private LibvirtCheckConvertInstanceCommandWrapper checkConvertInstanceCommandWrapper = Mockito.spy(LibvirtCheckConvertInstanceCommandWrapper.class);
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private LibvirtComputingResource libvirtComputingResourceMock;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
CheckConvertInstanceCommand checkConvertInstanceCommandMock;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckInstanceCommand_success() {
|
||||||
|
Mockito.when(libvirtComputingResourceMock.hostSupportsInstanceConversion()).thenReturn(true);
|
||||||
|
Answer answer = checkConvertInstanceCommandWrapper.execute(checkConvertInstanceCommandMock, libvirtComputingResourceMock);
|
||||||
|
assertTrue(answer.getResult());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckInstanceCommand_failure() {
|
||||||
|
Mockito.when(libvirtComputingResourceMock.hostSupportsInstanceConversion()).thenReturn(false);
|
||||||
|
Answer answer = checkConvertInstanceCommandWrapper.execute(checkConvertInstanceCommandMock, libvirtComputingResourceMock);
|
||||||
|
assertFalse(answer.getResult());
|
||||||
|
assertTrue(StringUtils.isNotBlank(answer.getDetails()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -71,12 +71,6 @@ public class LibvirtConvertInstanceCommandWrapperTest {
|
|||||||
|
|
||||||
private static final String secondaryPoolUrl = "nfs://192.168.1.1/secondary";
|
private static final String secondaryPoolUrl = "nfs://192.168.1.1/secondary";
|
||||||
private static final String vmName = "VmToImport";
|
private static final String vmName = "VmToImport";
|
||||||
private static final String hostName = "VmwareHost1";
|
|
||||||
private static final String vmwareVcenter = "192.168.1.2";
|
|
||||||
private static final String vmwareDatacenter = "Datacenter";
|
|
||||||
private static final String vmwareCluster = "Cluster";
|
|
||||||
private static final String vmwareUsername = "administrator@vsphere.local";
|
|
||||||
private static final String vmwarePassword = "password";
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
@ -88,15 +82,6 @@ public class LibvirtConvertInstanceCommandWrapperTest {
|
|||||||
Mockito.when(temporaryPool.listPhysicalDisks()).thenReturn(Arrays.asList(physicalDisk1, physicalDisk2));
|
Mockito.when(temporaryPool.listPhysicalDisks()).thenReturn(Arrays.asList(physicalDisk1, physicalDisk2));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testIsInstanceConversionSupportedOnHost() {
|
|
||||||
try (MockedStatic<Script> ignored = Mockito.mockStatic(Script.class)) {
|
|
||||||
Mockito.when(Script.runSimpleBashScriptForExitValue(LibvirtConvertInstanceCommandWrapper.checkIfConversionIsSupportedCommand)).thenReturn(0);
|
|
||||||
boolean supported = convertInstanceCommandWrapper.isInstanceConversionSupportedOnHost();
|
|
||||||
Assert.assertTrue(supported);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAreSourceAndDestinationHypervisorsSupported() {
|
public void testAreSourceAndDestinationHypervisorsSupported() {
|
||||||
boolean supported = convertInstanceCommandWrapper.areSourceAndDestinationHypervisorsSupported(Hypervisor.HypervisorType.VMware, Hypervisor.HypervisorType.KVM);
|
boolean supported = convertInstanceCommandWrapper.areSourceAndDestinationHypervisorsSupported(Hypervisor.HypervisorType.VMware, Hypervisor.HypervisorType.KVM);
|
||||||
@ -190,6 +175,7 @@ public class LibvirtConvertInstanceCommandWrapperTest {
|
|||||||
Mockito.when(destDisk.getPath()).thenReturn("xyz");
|
Mockito.when(destDisk.getPath()).thenReturn("xyz");
|
||||||
Mockito.when(storagePoolManager.getStoragePool(Storage.StoragePoolType.NetworkFilesystem, destinationPoolUuid))
|
Mockito.when(storagePoolManager.getStoragePool(Storage.StoragePoolType.NetworkFilesystem, destinationPoolUuid))
|
||||||
.thenReturn(destinationPool);
|
.thenReturn(destinationPool);
|
||||||
|
Mockito.when(destinationPool.getType()).thenReturn(Storage.StoragePoolType.NetworkFilesystem);
|
||||||
Mockito.when(storagePoolManager.copyPhysicalDisk(Mockito.eq(sourceDisk), Mockito.anyString(), Mockito.eq(destinationPool), Mockito.anyInt()))
|
Mockito.when(storagePoolManager.copyPhysicalDisk(Mockito.eq(sourceDisk), Mockito.anyString(), Mockito.eq(destinationPool), Mockito.anyInt()))
|
||||||
.thenReturn(destDisk);
|
.thenReturn(destDisk);
|
||||||
|
|
||||||
@ -243,21 +229,16 @@ public class LibvirtConvertInstanceCommandWrapperTest {
|
|||||||
RemoteInstanceTO remoteInstanceTO = Mockito.mock(RemoteInstanceTO.class);
|
RemoteInstanceTO remoteInstanceTO = Mockito.mock(RemoteInstanceTO.class);
|
||||||
Mockito.when(remoteInstanceTO.getHypervisorType()).thenReturn(hypervisorType);
|
Mockito.when(remoteInstanceTO.getHypervisorType()).thenReturn(hypervisorType);
|
||||||
Mockito.when(remoteInstanceTO.getInstanceName()).thenReturn(vmName);
|
Mockito.when(remoteInstanceTO.getInstanceName()).thenReturn(vmName);
|
||||||
Mockito.when(remoteInstanceTO.getHostName()).thenReturn(hostName);
|
|
||||||
Mockito.when(remoteInstanceTO.getVcenterHost()).thenReturn(vmwareVcenter);
|
|
||||||
Mockito.when(remoteInstanceTO.getDatacenterName()).thenReturn(vmwareDatacenter);
|
|
||||||
Mockito.when(remoteInstanceTO.getClusterName()).thenReturn(vmwareCluster);
|
|
||||||
Mockito.when(remoteInstanceTO.getVcenterUsername()).thenReturn(vmwareUsername);
|
|
||||||
Mockito.when(remoteInstanceTO.getVcenterPassword()).thenReturn(vmwarePassword);
|
|
||||||
return remoteInstanceTO;
|
return remoteInstanceTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ConvertInstanceCommand getConvertInstanceCommand(RemoteInstanceTO remoteInstanceTO, Hypervisor.HypervisorType hypervisorType) {
|
private ConvertInstanceCommand getConvertInstanceCommand(RemoteInstanceTO remoteInstanceTO, Hypervisor.HypervisorType hypervisorType, boolean checkConversionSupport) {
|
||||||
ConvertInstanceCommand cmd = Mockito.mock(ConvertInstanceCommand.class);
|
ConvertInstanceCommand cmd = Mockito.mock(ConvertInstanceCommand.class);
|
||||||
Mockito.when(cmd.getSourceInstance()).thenReturn(remoteInstanceTO);
|
Mockito.when(cmd.getSourceInstance()).thenReturn(remoteInstanceTO);
|
||||||
Mockito.when(cmd.getDestinationHypervisorType()).thenReturn(hypervisorType);
|
Mockito.when(cmd.getDestinationHypervisorType()).thenReturn(hypervisorType);
|
||||||
Mockito.when(cmd.getWait()).thenReturn(14400);
|
Mockito.when(cmd.getWait()).thenReturn(14400);
|
||||||
Mockito.when(cmd.getConversionTemporaryLocation()).thenReturn(secondaryDataStore);
|
Mockito.when(cmd.getConversionTemporaryLocation()).thenReturn(secondaryDataStore);
|
||||||
|
Mockito.when(cmd.getCheckConversionSupport()).thenReturn(checkConversionSupport);
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,8 +246,8 @@ public class LibvirtConvertInstanceCommandWrapperTest {
|
|||||||
public void testExecuteConvertUnsupportedOnTheHost() {
|
public void testExecuteConvertUnsupportedOnTheHost() {
|
||||||
try (MockedStatic<Script> ignored = Mockito.mockStatic(Script.class)) {
|
try (MockedStatic<Script> ignored = Mockito.mockStatic(Script.class)) {
|
||||||
RemoteInstanceTO remoteInstanceTO = getRemoteInstanceTO(Hypervisor.HypervisorType.VMware);
|
RemoteInstanceTO remoteInstanceTO = getRemoteInstanceTO(Hypervisor.HypervisorType.VMware);
|
||||||
ConvertInstanceCommand cmd = getConvertInstanceCommand(remoteInstanceTO, Hypervisor.HypervisorType.KVM);
|
ConvertInstanceCommand cmd = getConvertInstanceCommand(remoteInstanceTO, Hypervisor.HypervisorType.KVM, true);
|
||||||
Mockito.when(Script.runSimpleBashScriptForExitValue(LibvirtConvertInstanceCommandWrapper.checkIfConversionIsSupportedCommand)).thenReturn(1);
|
Mockito.when(Script.runSimpleBashScriptForExitValue(LibvirtComputingResource.INSTANCE_CONVERSION_SUPPORTED_CHECK_CMD)).thenReturn(1);
|
||||||
Answer answer = convertInstanceCommandWrapper.execute(cmd, libvirtComputingResourceMock);
|
Answer answer = convertInstanceCommandWrapper.execute(cmd, libvirtComputingResourceMock);
|
||||||
Assert.assertFalse(answer.getResult());
|
Assert.assertFalse(answer.getResult());
|
||||||
}
|
}
|
||||||
@ -276,8 +257,8 @@ public class LibvirtConvertInstanceCommandWrapperTest {
|
|||||||
public void testExecuteConvertUnsupportedHypervisors() {
|
public void testExecuteConvertUnsupportedHypervisors() {
|
||||||
try (MockedStatic<Script> ignored = Mockito.mockStatic(Script.class)) {
|
try (MockedStatic<Script> ignored = Mockito.mockStatic(Script.class)) {
|
||||||
RemoteInstanceTO remoteInstanceTO = getRemoteInstanceTO(Hypervisor.HypervisorType.XenServer);
|
RemoteInstanceTO remoteInstanceTO = getRemoteInstanceTO(Hypervisor.HypervisorType.XenServer);
|
||||||
ConvertInstanceCommand cmd = getConvertInstanceCommand(remoteInstanceTO, Hypervisor.HypervisorType.KVM);
|
ConvertInstanceCommand cmd = getConvertInstanceCommand(remoteInstanceTO, Hypervisor.HypervisorType.KVM, true);
|
||||||
Mockito.when(Script.runSimpleBashScriptForExitValue(LibvirtConvertInstanceCommandWrapper.checkIfConversionIsSupportedCommand)).thenReturn(0);
|
Mockito.when(Script.runSimpleBashScriptForExitValue(LibvirtComputingResource.INSTANCE_CONVERSION_SUPPORTED_CHECK_CMD)).thenReturn(0);
|
||||||
Answer answer = convertInstanceCommandWrapper.execute(cmd, libvirtComputingResourceMock);
|
Answer answer = convertInstanceCommandWrapper.execute(cmd, libvirtComputingResourceMock);
|
||||||
Assert.assertFalse(answer.getResult());
|
Assert.assertFalse(answer.getResult());
|
||||||
}
|
}
|
||||||
@ -286,7 +267,7 @@ public class LibvirtConvertInstanceCommandWrapperTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testExecuteConvertFailure() {
|
public void testExecuteConvertFailure() {
|
||||||
RemoteInstanceTO remoteInstanceTO = getRemoteInstanceTO(Hypervisor.HypervisorType.VMware);
|
RemoteInstanceTO remoteInstanceTO = getRemoteInstanceTO(Hypervisor.HypervisorType.VMware);
|
||||||
ConvertInstanceCommand cmd = getConvertInstanceCommand(remoteInstanceTO, Hypervisor.HypervisorType.KVM);
|
ConvertInstanceCommand cmd = getConvertInstanceCommand(remoteInstanceTO, Hypervisor.HypervisorType.KVM, true);
|
||||||
String localMountPoint = "/mnt/xyz";
|
String localMountPoint = "/mnt/xyz";
|
||||||
Mockito.when(temporaryPool.getLocalPath()).thenReturn(localMountPoint);
|
Mockito.when(temporaryPool.getLocalPath()).thenReturn(localMountPoint);
|
||||||
|
|
||||||
@ -296,15 +277,15 @@ public class LibvirtConvertInstanceCommandWrapperTest {
|
|||||||
Mockito.when(mock.getExitValue()).thenReturn(1);
|
Mockito.when(mock.getExitValue()).thenReturn(1);
|
||||||
})
|
})
|
||||||
) {
|
) {
|
||||||
Mockito.when(Script.runSimpleBashScriptForExitValue(LibvirtConvertInstanceCommandWrapper.checkIfConversionIsSupportedCommand)).thenReturn(0);
|
Mockito.when(libvirtComputingResourceMock.hostSupportsInstanceConversion()).thenReturn(true);
|
||||||
Mockito.when(Script.runSimpleBashScriptForExitValueAvoidLogging(Mockito.anyString())).thenReturn(0);
|
Mockito.when(Script.runSimpleBashScriptForExitValue(LibvirtComputingResource.INSTANCE_CONVERSION_SUPPORTED_CHECK_CMD)).thenReturn(0);
|
||||||
|
Mockito.when(Script.runSimpleBashScriptForExitValue(Mockito.anyString())).thenReturn(0);
|
||||||
Mockito.when(Script.runSimpleBashScript(Mockito.anyString())).thenReturn("");
|
Mockito.when(Script.runSimpleBashScript(Mockito.anyString())).thenReturn("");
|
||||||
|
|
||||||
Answer answer = convertInstanceCommandWrapper.execute(cmd, libvirtComputingResourceMock);
|
Answer answer = convertInstanceCommandWrapper.execute(cmd, libvirtComputingResourceMock);
|
||||||
Assert.assertFalse(answer.getResult());
|
Assert.assertFalse(answer.getResult());
|
||||||
Mockito.verify(convertInstanceCommandWrapper).performInstanceConversion(Mockito.anyString(),
|
Mockito.verify(convertInstanceCommandWrapper).performInstanceConversion(Mockito.anyString(),
|
||||||
Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyLong(), Mockito.anyBoolean());
|
Mockito.anyString(), Mockito.anyString(), Mockito.anyLong(), Mockito.anyBoolean());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,91 @@
|
|||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you under the Apache License, Version 2.0 (the
|
||||||
|
// "License"); you may not use this file except in compliance
|
||||||
|
// with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing,
|
||||||
|
// software distributed under the License is distributed on an
|
||||||
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations
|
||||||
|
// under the License.
|
||||||
|
|
||||||
|
package com.cloud.hypervisor.kvm.storage;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.libvirt.Connect;
|
||||||
|
import org.libvirt.StoragePool;
|
||||||
|
import org.libvirt.StoragePoolInfo;
|
||||||
|
import org.mockito.MockedStatic;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.mockito.Spy;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
|
import com.cloud.hypervisor.kvm.resource.LibvirtConnection;
|
||||||
|
import com.cloud.hypervisor.kvm.resource.LibvirtStoragePoolDef;
|
||||||
|
import com.cloud.storage.Storage;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class LibvirtStorageAdaptorTest {
|
||||||
|
|
||||||
|
private MockedStatic<LibvirtConnection> libvirtConnectionMockedStatic;
|
||||||
|
|
||||||
|
private AutoCloseable closeable;
|
||||||
|
|
||||||
|
@Spy
|
||||||
|
static LibvirtStorageAdaptor libvirtStorageAdaptor = new LibvirtStorageAdaptor(null);
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void initMocks() {
|
||||||
|
closeable = MockitoAnnotations.openMocks(this);
|
||||||
|
libvirtConnectionMockedStatic = Mockito.mockStatic(LibvirtConnection.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() throws Exception {
|
||||||
|
libvirtConnectionMockedStatic.close();
|
||||||
|
closeable.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = CloudRuntimeException.class)
|
||||||
|
public void testCreateStoragePoolWithNFSMountOpts() throws Exception {
|
||||||
|
LibvirtStoragePoolDef.PoolType type = LibvirtStoragePoolDef.PoolType.NETFS;
|
||||||
|
String name = "Primary1";
|
||||||
|
String uuid = String.valueOf(UUID.randomUUID());
|
||||||
|
String host = "127.0.0.1";
|
||||||
|
String dir = "/export/primary";
|
||||||
|
String targetPath = "/mnt/" + uuid;
|
||||||
|
|
||||||
|
String poolXml = "<pool type='" + type.toString() + "' xmlns:fs='http://libvirt.org/schemas/storagepool/fs/1.0'>\n" +
|
||||||
|
"<name>" +name + "</name>\n<uuid>" + uuid + "</uuid>\n" +
|
||||||
|
"<source>\n<host name='" + host + "'/>\n<dir path='" + dir + "'/>\n</source>\n<target>\n" +
|
||||||
|
"<path>" + targetPath + "</path>\n</target>\n" +
|
||||||
|
"<fs:mount_opts>\n<fs:option name='vers=4.1'/>\n<fs:option name='nconnect=4'/>\n</fs:mount_opts>\n</pool>\n";
|
||||||
|
|
||||||
|
Connect conn = Mockito.mock(Connect.class);
|
||||||
|
StoragePool sp = Mockito.mock(StoragePool.class);
|
||||||
|
StoragePoolInfo spinfo = Mockito.mock(StoragePoolInfo.class);
|
||||||
|
Mockito.when(LibvirtConnection.getConnection()).thenReturn(conn);
|
||||||
|
Mockito.when(conn.storagePoolLookupByUUIDString(uuid)).thenReturn(sp);
|
||||||
|
Mockito.when(sp.isActive()).thenReturn(1);
|
||||||
|
Mockito.when(sp.getXMLDesc(0)).thenReturn(poolXml);
|
||||||
|
|
||||||
|
Map<String, String> details = new HashMap<>();
|
||||||
|
details.put("nfsmountopts", "vers=4.1, nconnect=4");
|
||||||
|
KVMStoragePool pool = libvirtStorageAdaptor.createStoragePool(uuid, null, 0, dir, null, Storage.StoragePoolType.NetworkFilesystem, details);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -18,6 +18,8 @@ package com.cloud.hypervisor.guru;
|
|||||||
|
|
||||||
import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
|
import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.net.URI;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -27,10 +29,12 @@ import java.util.UUID;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import com.cloud.agent.api.to.NfsTO;
|
||||||
import com.cloud.hypervisor.vmware.mo.DatastoreMO;
|
import com.cloud.hypervisor.vmware.mo.DatastoreMO;
|
||||||
import com.cloud.hypervisor.vmware.mo.HostMO;
|
import com.cloud.hypervisor.vmware.mo.HostMO;
|
||||||
import com.cloud.hypervisor.vmware.util.VmwareClient;
|
import com.cloud.hypervisor.vmware.util.VmwareClient;
|
||||||
import com.cloud.hypervisor.vmware.util.VmwareHelper;
|
import com.cloud.hypervisor.vmware.util.VmwareHelper;
|
||||||
|
import com.cloud.utils.script.Script;
|
||||||
import com.cloud.vm.VmDetailConstants;
|
import com.cloud.vm.VmDetailConstants;
|
||||||
import com.vmware.vim25.VirtualMachinePowerState;
|
import com.vmware.vim25.VirtualMachinePowerState;
|
||||||
import org.apache.cloudstack.acl.ControlledEntity;
|
import org.apache.cloudstack.acl.ControlledEntity;
|
||||||
@ -41,12 +45,14 @@ import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
|
|||||||
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
|
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
|
||||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||||
import org.apache.cloudstack.framework.config.Configurable;
|
import org.apache.cloudstack.framework.config.Configurable;
|
||||||
|
import org.apache.cloudstack.storage.NfsMountManager;
|
||||||
import org.apache.cloudstack.storage.command.CopyCommand;
|
import org.apache.cloudstack.storage.command.CopyCommand;
|
||||||
import org.apache.cloudstack.storage.command.DeleteCommand;
|
import org.apache.cloudstack.storage.command.DeleteCommand;
|
||||||
import org.apache.cloudstack.storage.command.DownloadCommand;
|
import org.apache.cloudstack.storage.command.DownloadCommand;
|
||||||
import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
|
import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
|
||||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||||
|
import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
|
||||||
import org.apache.cloudstack.storage.to.VolumeObjectTO;
|
import org.apache.cloudstack.storage.to.VolumeObjectTO;
|
||||||
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
|
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
|
||||||
import org.apache.cloudstack.utils.volume.VirtualMachineDiskInfo;
|
import org.apache.cloudstack.utils.volume.VirtualMachineDiskInfo;
|
||||||
@ -148,16 +154,22 @@ import com.cloud.vm.VirtualMachineProfile;
|
|||||||
import com.cloud.vm.dao.UserVmDao;
|
import com.cloud.vm.dao.UserVmDao;
|
||||||
import com.cloud.vm.dao.VMInstanceDao;
|
import com.cloud.vm.dao.VMInstanceDao;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
import com.vmware.vim25.DistributedVirtualPort;
|
||||||
|
import com.vmware.vim25.DistributedVirtualSwitchPortConnection;
|
||||||
|
import com.vmware.vim25.DistributedVirtualSwitchPortCriteria;
|
||||||
import com.vmware.vim25.ManagedObjectReference;
|
import com.vmware.vim25.ManagedObjectReference;
|
||||||
|
import com.vmware.vim25.VMwareDVSPortSetting;
|
||||||
import com.vmware.vim25.VirtualDevice;
|
import com.vmware.vim25.VirtualDevice;
|
||||||
import com.vmware.vim25.VirtualDeviceBackingInfo;
|
import com.vmware.vim25.VirtualDeviceBackingInfo;
|
||||||
import com.vmware.vim25.VirtualDeviceConnectInfo;
|
import com.vmware.vim25.VirtualDeviceConnectInfo;
|
||||||
import com.vmware.vim25.VirtualDisk;
|
import com.vmware.vim25.VirtualDisk;
|
||||||
import com.vmware.vim25.VirtualDiskFlatVer2BackingInfo;
|
import com.vmware.vim25.VirtualDiskFlatVer2BackingInfo;
|
||||||
import com.vmware.vim25.VirtualEthernetCard;
|
import com.vmware.vim25.VirtualEthernetCard;
|
||||||
|
import com.vmware.vim25.VirtualEthernetCardDistributedVirtualPortBackingInfo;
|
||||||
import com.vmware.vim25.VirtualEthernetCardNetworkBackingInfo;
|
import com.vmware.vim25.VirtualEthernetCardNetworkBackingInfo;
|
||||||
import com.vmware.vim25.VirtualMachineConfigSummary;
|
import com.vmware.vim25.VirtualMachineConfigSummary;
|
||||||
import com.vmware.vim25.VirtualMachineRuntimeInfo;
|
import com.vmware.vim25.VirtualMachineRuntimeInfo;
|
||||||
|
import com.vmware.vim25.VmwareDistributedVirtualSwitchVlanIdSpec;
|
||||||
|
|
||||||
public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Configurable {
|
public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Configurable {
|
||||||
private static final Gson GSON = GsonHelper.getGson();
|
private static final Gson GSON = GsonHelper.getGson();
|
||||||
@ -186,6 +198,7 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
|||||||
@Inject DiskOfferingDao diskOfferingDao;
|
@Inject DiskOfferingDao diskOfferingDao;
|
||||||
@Inject PhysicalNetworkDao physicalNetworkDao;
|
@Inject PhysicalNetworkDao physicalNetworkDao;
|
||||||
@Inject StoragePoolHostDao storagePoolHostDao;
|
@Inject StoragePoolHostDao storagePoolHostDao;
|
||||||
|
@Inject NfsMountManager mountManager;
|
||||||
|
|
||||||
protected VMwareGuru() {
|
protected VMwareGuru() {
|
||||||
super();
|
super();
|
||||||
@ -531,11 +544,29 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
|||||||
/**
|
/**
|
||||||
* Get pool ID from datastore UUID
|
* Get pool ID from datastore UUID
|
||||||
*/
|
*/
|
||||||
private Long getPoolIdFromDatastoreUuid(String datastoreUuid) {
|
private Long getPoolIdFromDatastoreUuid(long zoneId, String datastoreUuid) {
|
||||||
|
StoragePoolVO pool = null;
|
||||||
|
try {
|
||||||
String poolUuid = UuidUtils.normalize(datastoreUuid);
|
String poolUuid = UuidUtils.normalize(datastoreUuid);
|
||||||
StoragePoolVO pool = _storagePoolDao.findByUuid(poolUuid);
|
s_logger.info("Trying to find pool by UUID: " + poolUuid);
|
||||||
|
pool = _storagePoolDao.findByUuid(poolUuid);
|
||||||
|
} catch (CloudRuntimeException ex) {
|
||||||
|
s_logger.warn("Unable to get pool by datastore UUID: " + ex.getMessage());
|
||||||
|
}
|
||||||
if (pool == null) {
|
if (pool == null) {
|
||||||
throw new CloudRuntimeException("Couldn't find storage pool " + poolUuid);
|
s_logger.info("Trying to find pool by path: " + datastoreUuid);
|
||||||
|
pool = _storagePoolDao.findPoolByZoneAndPath(zoneId, datastoreUuid);
|
||||||
|
}
|
||||||
|
if (pool == null && datastoreUuid.startsWith("-iqn") && datastoreUuid.endsWith("-0")) {
|
||||||
|
String iScsiName = "/iqn" + datastoreUuid.substring(4, datastoreUuid.length() - 2) + "/0";
|
||||||
|
s_logger.info("Trying to find volume by iScsi name: " + iScsiName);
|
||||||
|
VolumeVO volumeVO = _volumeDao.findOneByIScsiName(iScsiName);
|
||||||
|
if (volumeVO != null) {
|
||||||
|
pool = _storagePoolDao.findById(volumeVO.getPoolId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pool == null) {
|
||||||
|
throw new CloudRuntimeException("Couldn't find storage pool " + datastoreUuid);
|
||||||
}
|
}
|
||||||
return pool.getId();
|
return pool.getId();
|
||||||
}
|
}
|
||||||
@ -543,13 +574,13 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
|||||||
/**
|
/**
|
||||||
* Get pool ID for disk
|
* Get pool ID for disk
|
||||||
*/
|
*/
|
||||||
private Long getPoolId(VirtualDisk disk) {
|
private Long getPoolId(long zoneId, VirtualDisk disk) {
|
||||||
VirtualDeviceBackingInfo backing = disk.getBacking();
|
VirtualDeviceBackingInfo backing = disk.getBacking();
|
||||||
checkBackingInfo(backing);
|
checkBackingInfo(backing);
|
||||||
VirtualDiskFlatVer2BackingInfo info = (VirtualDiskFlatVer2BackingInfo)backing;
|
VirtualDiskFlatVer2BackingInfo info = (VirtualDiskFlatVer2BackingInfo)backing;
|
||||||
String[] fileNameParts = info.getFileName().split(" ");
|
String[] fileNameParts = info.getFileName().split(" ");
|
||||||
String datastoreUuid = StringUtils.substringBetween(fileNameParts[0], "[", "]");
|
String datastoreUuid = StringUtils.substringBetween(fileNameParts[0], "[", "]");
|
||||||
return getPoolIdFromDatastoreUuid(datastoreUuid);
|
return getPoolIdFromDatastoreUuid(zoneId, datastoreUuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -586,12 +617,12 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
|||||||
/**
|
/**
|
||||||
* Get template pool ID
|
* Get template pool ID
|
||||||
*/
|
*/
|
||||||
private Long getTemplatePoolId(VirtualMachineMO template) throws Exception {
|
private Long getTemplatePoolId(long zoneId, VirtualMachineMO template) throws Exception {
|
||||||
VirtualMachineConfigSummary configSummary = template.getConfigSummary();
|
VirtualMachineConfigSummary configSummary = template.getConfigSummary();
|
||||||
String vmPathName = configSummary.getVmPathName();
|
String vmPathName = configSummary.getVmPathName();
|
||||||
String[] pathParts = vmPathName.split(" ");
|
String[] pathParts = vmPathName.split(" ");
|
||||||
String dataStoreUuid = pathParts[0].replace("[", "").replace("]", "");
|
String dataStoreUuid = pathParts[0].replace("[", "").replace("]", "");
|
||||||
return getPoolIdFromDatastoreUuid(dataStoreUuid);
|
return getPoolIdFromDatastoreUuid(zoneId, dataStoreUuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -641,14 +672,14 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
|||||||
/**
|
/**
|
||||||
* Get template ID for VM being imported. If it is not found, it is created
|
* Get template ID for VM being imported. If it is not found, it is created
|
||||||
*/
|
*/
|
||||||
private Long getImportingVMTemplate(List<VirtualDisk> virtualDisks, DatacenterMO dcMo, String vmInternalName, Long guestOsId, long accountId, Map<VirtualDisk, VolumeVO> disksMapping, Backup backup) throws Exception {
|
private Long getImportingVMTemplate(List<VirtualDisk> virtualDisks, long zoneId, DatacenterMO dcMo, String vmInternalName, Long guestOsId, long accountId, Map<VirtualDisk, VolumeVO> disksMapping, Backup backup) throws Exception {
|
||||||
for (VirtualDisk disk : virtualDisks) {
|
for (VirtualDisk disk : virtualDisks) {
|
||||||
if (isRootDisk(disk, disksMapping, backup)) {
|
if (isRootDisk(disk, disksMapping, backup)) {
|
||||||
VolumeVO volumeVO = disksMapping.get(disk);
|
VolumeVO volumeVO = disksMapping.get(disk);
|
||||||
if (volumeVO == null) {
|
if (volumeVO == null) {
|
||||||
String templatePath = getRootDiskTemplatePath(disk);
|
String templatePath = getRootDiskTemplatePath(disk);
|
||||||
VirtualMachineMO template = getTemplate(dcMo, templatePath);
|
VirtualMachineMO template = getTemplate(dcMo, templatePath);
|
||||||
Long poolId = getTemplatePoolId(template);
|
Long poolId = getTemplatePoolId(zoneId, template);
|
||||||
Long templateSize = getTemplateSize(template, vmInternalName, disksMapping, backup);
|
Long templateSize = getTemplateSize(template, vmInternalName, disksMapping, backup);
|
||||||
long templateId = getTemplateId(templatePath, vmInternalName, guestOsId, accountId);
|
long templateId = getTemplateId(templatePath, vmInternalName, guestOsId, accountId);
|
||||||
updateTemplateRef(templateId, poolId, templatePath, templateSize);
|
updateTemplateRef(templateId, poolId, templatePath, templateSize);
|
||||||
@ -742,7 +773,11 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
|||||||
protected VolumeVO updateVolume(VirtualDisk disk, Map<VirtualDisk, VolumeVO> disksMapping, VirtualMachineMO vmToImport, Long poolId, VirtualMachine vm) throws Exception {
|
protected VolumeVO updateVolume(VirtualDisk disk, Map<VirtualDisk, VolumeVO> disksMapping, VirtualMachineMO vmToImport, Long poolId, VirtualMachine vm) throws Exception {
|
||||||
VolumeVO volume = disksMapping.get(disk);
|
VolumeVO volume = disksMapping.get(disk);
|
||||||
String volumeName = getVolumeName(disk, vmToImport);
|
String volumeName = getVolumeName(disk, vmToImport);
|
||||||
|
if (volume.get_iScsiName() != null) {
|
||||||
|
volume.setPath(String.format("[%s] %s.vmdk", volumeName, volumeName));
|
||||||
|
} else {
|
||||||
volume.setPath(volumeName);
|
volume.setPath(volumeName);
|
||||||
|
}
|
||||||
volume.setPoolId(poolId);
|
volume.setPoolId(poolId);
|
||||||
VirtualMachineDiskInfo diskInfo = getDiskInfo(vmToImport, poolId, volumeName);
|
VirtualMachineDiskInfo diskInfo = getDiskInfo(vmToImport, poolId, volumeName);
|
||||||
volume.setChainInfo(GSON.toJson(diskInfo));
|
volume.setChainInfo(GSON.toJson(diskInfo));
|
||||||
@ -777,7 +812,7 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
|||||||
|
|
||||||
String operation = "";
|
String operation = "";
|
||||||
for (VirtualDisk disk : virtualDisks) {
|
for (VirtualDisk disk : virtualDisks) {
|
||||||
Long poolId = getPoolId(disk);
|
Long poolId = getPoolId(zoneId, disk);
|
||||||
Volume volume = null;
|
Volume volume = null;
|
||||||
if (disksMapping.containsKey(disk) && disksMapping.get(disk) != null) {
|
if (disksMapping.containsKey(disk) && disksMapping.get(disk) != null) {
|
||||||
volume = updateVolume(disk, disksMapping, vmToImport, poolId, vmInstanceVO);
|
volume = updateVolume(disk, disksMapping, vmToImport, poolId, vmInstanceVO);
|
||||||
@ -901,8 +936,13 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
|||||||
Map<String, NetworkVO> mapping = new HashMap<>();
|
Map<String, NetworkVO> mapping = new HashMap<>();
|
||||||
for (String networkName : vmNetworkNames) {
|
for (String networkName : vmNetworkNames) {
|
||||||
NetworkVO networkVO = getGuestNetworkFromNetworkMorName(networkName, accountId, zoneId, domainId);
|
NetworkVO networkVO = getGuestNetworkFromNetworkMorName(networkName, accountId, zoneId, domainId);
|
||||||
logger.debug(String.format("Mapping network name [%s] to networkVO [id: %s].", networkName, networkVO.getUuid()));
|
URI broadcastUri = networkVO.getBroadcastUri();
|
||||||
mapping.put(networkName, networkVO);
|
if (broadcastUri == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String vlan = broadcastUri.getHost();
|
||||||
|
logger.debug(String.format("Mapping network vlan [%s] to networkVO [id: %s].", vlan, networkVO.getUuid()));
|
||||||
|
mapping.put(vlan, networkVO);
|
||||||
}
|
}
|
||||||
return mapping;
|
return mapping;
|
||||||
}
|
}
|
||||||
@ -912,7 +952,7 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
|||||||
*/
|
*/
|
||||||
private NetworkMO getNetworkMO(VirtualEthernetCard nic, VmwareContext context) {
|
private NetworkMO getNetworkMO(VirtualEthernetCard nic, VmwareContext context) {
|
||||||
VirtualDeviceConnectInfo connectable = nic.getConnectable();
|
VirtualDeviceConnectInfo connectable = nic.getConnectable();
|
||||||
VirtualEthernetCardNetworkBackingInfo info = (VirtualEthernetCardNetworkBackingInfo)nic.getBacking();
|
VirtualEthernetCardNetworkBackingInfo info = (VirtualEthernetCardNetworkBackingInfo) nic.getBacking();
|
||||||
ManagedObjectReference networkMor = info.getNetwork();
|
ManagedObjectReference networkMor = info.getNetwork();
|
||||||
if (networkMor == null) {
|
if (networkMor == null) {
|
||||||
throw new CloudRuntimeException("Could not find network for NIC on: " + nic.getMacAddress());
|
throw new CloudRuntimeException("Could not find network for NIC on: " + nic.getMacAddress());
|
||||||
@ -920,22 +960,80 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
|||||||
return new NetworkMO(context, networkMor);
|
return new NetworkMO(context, networkMor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Pair<String, String> getNicMacAddressAndNetworkName(VirtualDevice nicDevice, VmwareContext context) throws Exception {
|
private Pair<String, String> getNicMacAddressAndVlan(VirtualDevice nicDevice, VmwareContext context) throws Exception {
|
||||||
VirtualEthernetCard nic = (VirtualEthernetCard)nicDevice;
|
VirtualEthernetCard nic = (VirtualEthernetCard)nicDevice;
|
||||||
String macAddress = nic.getMacAddress();
|
String macAddress = nic.getMacAddress();
|
||||||
NetworkMO networkMO = getNetworkMO(nic, context);
|
VirtualDeviceBackingInfo backing = nic.getBacking();
|
||||||
String networkName = networkMO.getName();
|
if (backing instanceof VirtualEthernetCardNetworkBackingInfo) {
|
||||||
return new Pair<>(macAddress, networkName);
|
VirtualEthernetCardNetworkBackingInfo backingInfo = (VirtualEthernetCardNetworkBackingInfo) backing;
|
||||||
|
String deviceName = backingInfo.getDeviceName();
|
||||||
|
String vlan = getVlanFromDeviceName(deviceName);
|
||||||
|
return new Pair<>(macAddress, vlan);
|
||||||
|
} else if (backing instanceof VirtualEthernetCardDistributedVirtualPortBackingInfo) {
|
||||||
|
VirtualEthernetCardDistributedVirtualPortBackingInfo portInfo = (VirtualEthernetCardDistributedVirtualPortBackingInfo) backing;
|
||||||
|
DistributedVirtualSwitchPortConnection port = portInfo.getPort();
|
||||||
|
String portKey = port.getPortKey();
|
||||||
|
String portGroupKey = port.getPortgroupKey();
|
||||||
|
String dvSwitchUuid = port.getSwitchUuid();
|
||||||
|
String vlan = getVlanFromDvsPort(context, dvSwitchUuid, portGroupKey, portKey);
|
||||||
|
return new Pair<>(macAddress, vlan);
|
||||||
|
}
|
||||||
|
return new Pair<>(macAddress, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getVlanFromDeviceName(String networkName) {
|
||||||
|
String prefix = "cloud.guest.";
|
||||||
|
if (!networkName.startsWith(prefix)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String nameWithoutPrefix = networkName.replace(prefix, "");
|
||||||
|
String[] parts = nameWithoutPrefix.split("\\.");
|
||||||
|
String vlan = parts[0];
|
||||||
|
return vlan;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getVlanFromDvsPort(VmwareContext context, String dvSwitchUuid, String portGroupKey, String portKey) {
|
||||||
|
try {
|
||||||
|
ManagedObjectReference dvSwitchManager = context.getVimClient().getServiceContent().getDvSwitchManager();
|
||||||
|
ManagedObjectReference dvSwitch = context.getVimClient().getService().queryDvsByUuid(dvSwitchManager, dvSwitchUuid);
|
||||||
|
|
||||||
|
// Get all ports
|
||||||
|
DistributedVirtualSwitchPortCriteria criteria = new DistributedVirtualSwitchPortCriteria();
|
||||||
|
criteria.setInside(true);
|
||||||
|
criteria.getPortgroupKey().add(portGroupKey);
|
||||||
|
List<DistributedVirtualPort> dvPorts = context.getVimClient().getService().fetchDVPorts(dvSwitch, criteria);
|
||||||
|
|
||||||
|
for (DistributedVirtualPort dvPort : dvPorts) {
|
||||||
|
if (!portKey.equals(dvPort.getKey())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
VMwareDVSPortSetting settings = (VMwareDVSPortSetting) dvPort.getConfig().getSetting();
|
||||||
|
VmwareDistributedVirtualSwitchVlanIdSpec vlanId = (VmwareDistributedVirtualSwitchVlanIdSpec) settings.getVlan();
|
||||||
|
s_logger.debug("Found port " + dvPort.getKey() + " with vlan " + vlanId.getVlanId());
|
||||||
|
return String.valueOf(vlanId.getVlanId());
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
s_logger.error("Got exception while get vlan from DVS port: " + ex.getMessage());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void syncVMNics(VirtualDevice[] nicDevices, DatacenterMO dcMo, Map<String, NetworkVO> networksMapping, VMInstanceVO vm) throws Exception {
|
private void syncVMNics(VirtualDevice[] nicDevices, DatacenterMO dcMo, Map<String, NetworkVO> networksMapping, VMInstanceVO vm) throws Exception {
|
||||||
VmwareContext context = dcMo.getContext();
|
VmwareContext context = dcMo.getContext();
|
||||||
List<NicVO> allNics = nicDao.listByVmId(vm.getId());
|
List<NicVO> allNics = nicDao.listByVmId(vm.getId());
|
||||||
for (VirtualDevice nicDevice : nicDevices) {
|
for (VirtualDevice nicDevice : nicDevices) {
|
||||||
Pair<String, String> pair = getNicMacAddressAndNetworkName(nicDevice, context);
|
Pair<String, String> pair = getNicMacAddressAndVlan(nicDevice, context);
|
||||||
String macAddress = pair.first();
|
String macAddress = pair.first();
|
||||||
String networkName = pair.second();
|
String vlanId = pair.second();
|
||||||
NetworkVO networkVO = networksMapping.get(networkName);
|
if (vlanId == null) {
|
||||||
|
s_logger.warn(String.format("vlanId for MAC address [%s] is null", macAddress));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
NetworkVO networkVO = networksMapping.get(vlanId);
|
||||||
|
if (networkVO == null) {
|
||||||
|
s_logger.warn(String.format("Cannot find network for MAC address [%s] and vlanId [%s]", macAddress, vlanId));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
NicVO nicVO = nicDao.findByNetworkIdAndMacAddressIncludingRemoved(networkVO.getId(), macAddress);
|
NicVO nicVO = nicDao.findByNetworkIdAndMacAddressIncludingRemoved(networkVO.getId(), macAddress);
|
||||||
if (nicVO != null) {
|
if (nicVO != null) {
|
||||||
logger.warn(String.format("Find NIC in DB with networkId [%s] and MAC Address [%s], so this NIC will be removed from list of unmapped NICs of VM [id: %s, name: %s].",
|
logger.warn(String.format("Find NIC in DB with networkId [%s] and MAC Address [%s], so this NIC will be removed from list of unmapped NICs of VM [id: %s, name: %s].",
|
||||||
@ -1066,7 +1164,7 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
|||||||
|
|
||||||
long guestOsId = getImportingVMGuestOs(configSummary);
|
long guestOsId = getImportingVMGuestOs(configSummary);
|
||||||
long serviceOfferingId = getImportingVMServiceOffering(configSummary, runtimeInfo);
|
long serviceOfferingId = getImportingVMServiceOffering(configSummary, runtimeInfo);
|
||||||
long templateId = getImportingVMTemplate(virtualDisks, dcMo, vmInternalName, guestOsId, accountId, disksMapping, backup);
|
long templateId = getImportingVMTemplate(virtualDisks, zoneId, dcMo, vmInternalName, guestOsId, accountId, disksMapping, backup);
|
||||||
|
|
||||||
VMInstanceVO vm = getVM(vmInternalName, templateId, guestOsId, serviceOfferingId, zoneId, accountId, userId, domainId);
|
VMInstanceVO vm = getVM(vmInternalName, templateId, guestOsId, serviceOfferingId, zoneId, accountId, userId, domainId);
|
||||||
syncVMVolumes(vm, virtualDisks, disksMapping, vmToImport, backup);
|
syncVMVolumes(vm, virtualDisks, disksMapping, vmToImport, backup);
|
||||||
@ -1248,7 +1346,13 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
|||||||
DatacenterMO dataCenterMO) throws Exception {
|
DatacenterMO dataCenterMO) throws Exception {
|
||||||
HostMO sourceHost = vmMo.getRunningHost();
|
HostMO sourceHost = vmMo.getRunningHost();
|
||||||
String cloneName = UUID.randomUUID().toString();
|
String cloneName = UUID.randomUUID().toString();
|
||||||
DatastoreMO datastoreMO = vmMo.getAllDatastores().get(0); //pick the first datastore
|
List<DatastoreMO> vmDatastores = vmMo.getAllDatastores();
|
||||||
|
if (CollectionUtils.isEmpty(vmDatastores)) {
|
||||||
|
String err = String.format("Unable to fetch datastores, could not clone VM %s for migration from VMware", vmName);
|
||||||
|
s_logger.error(err);
|
||||||
|
throw new CloudRuntimeException(err);
|
||||||
|
}
|
||||||
|
DatastoreMO datastoreMO = vmDatastores.get(0); //pick the first datastore
|
||||||
ManagedObjectReference morPool = vmMo.getRunningHost().getHyperHostOwnerResourcePool();
|
ManagedObjectReference morPool = vmMo.getRunningHost().getHyperHostOwnerResourcePool();
|
||||||
boolean result = vmMo.createFullClone(cloneName, dataCenterMO.getVmFolder(), morPool, datastoreMO.getMor(), Storage.ProvisioningType.THIN);
|
boolean result = vmMo.createFullClone(cloneName, dataCenterMO.getVmFolder(), morPool, datastoreMO.getMor(), Storage.ProvisioningType.THIN);
|
||||||
VirtualMachineMO clonedVM = dataCenterMO.findVm(cloneName);
|
VirtualMachineMO clonedVM = dataCenterMO.findVm(cloneName);
|
||||||
@ -1257,14 +1361,23 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
|||||||
logger.error(err);
|
logger.error(err);
|
||||||
throw new CloudRuntimeException(err);
|
throw new CloudRuntimeException(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
relocateClonedVMToSourceHost(clonedVM, sourceHost);
|
relocateClonedVMToSourceHost(clonedVM, sourceHost);
|
||||||
return clonedVM;
|
return clonedVM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String createOVFTemplateOfVM(VirtualMachineMO vmMO, DataStoreTO convertLocation, int threadsCountToExportOvf) throws Exception {
|
||||||
|
String dataStoreUrl = getDataStoreUrlForTemplate(convertLocation);
|
||||||
|
String vmOvfName = UUID.randomUUID().toString();
|
||||||
|
String vmOvfCreationPath = createDirOnStorage(vmOvfName, dataStoreUrl, null);
|
||||||
|
logger.debug(String.format("Creating OVF %s for the VM %s at %s", vmOvfName, vmMO.getName(), vmOvfCreationPath));
|
||||||
|
vmMO.exportVm(vmOvfCreationPath, vmOvfName, false, false, threadsCountToExportOvf);
|
||||||
|
logger.debug(String.format("Created OVF %s for the VM %s at %s", vmOvfName, vmMO.getName(), vmOvfCreationPath));
|
||||||
|
return vmOvfName;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UnmanagedInstanceTO cloneHypervisorVMOutOfBand(String hostIp, String vmName,
|
public Pair<UnmanagedInstanceTO, Boolean> getHypervisorVMOutOfBandAndCloneIfRequired(String hostIp, String vmName, Map<String, String> params) {
|
||||||
Map<String, String> params) {
|
|
||||||
logger.debug(String.format("Cloning VM %s on external vCenter %s", vmName, hostIp));
|
|
||||||
String vcenter = params.get(VmDetailConstants.VMWARE_VCENTER_HOST);
|
String vcenter = params.get(VmDetailConstants.VMWARE_VCENTER_HOST);
|
||||||
String datacenter = params.get(VmDetailConstants.VMWARE_DATACENTER_NAME);
|
String datacenter = params.get(VmDetailConstants.VMWARE_DATACENTER_NAME);
|
||||||
String username = params.get(VmDetailConstants.VMWARE_VCENTER_USERNAME);
|
String username = params.get(VmDetailConstants.VMWARE_VCENTER_USERNAME);
|
||||||
@ -1275,25 +1388,46 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
|||||||
DatacenterMO dataCenterMO = new DatacenterMO(context, datacenter);
|
DatacenterMO dataCenterMO = new DatacenterMO(context, datacenter);
|
||||||
VirtualMachineMO vmMo = dataCenterMO.findVm(vmName);
|
VirtualMachineMO vmMo = dataCenterMO.findVm(vmName);
|
||||||
if (vmMo == null) {
|
if (vmMo == null) {
|
||||||
String err = String.format("Cannot find VM with name %s on %s/%s", vmName, vcenter, datacenter);
|
String err = String.format("Cannot find VM with name %s on vCenter %s/%s", vmName, vcenter, datacenter);
|
||||||
logger.error(err);
|
logger.error(err);
|
||||||
throw new CloudRuntimeException(err);
|
throw new CloudRuntimeException(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
VirtualMachinePowerState sourceVmPowerState = vmMo.getPowerState();
|
VirtualMachinePowerState sourceVmPowerState = vmMo.getPowerState();
|
||||||
if (sourceVmPowerState == VirtualMachinePowerState.POWERED_ON && isWindowsVm(vmMo)) {
|
|
||||||
logger.debug(String.format("VM %s is a Windows VM and its Running, cannot be imported." +
|
if (sourceVmPowerState == VirtualMachinePowerState.POWERED_OFF) {
|
||||||
"Please gracefully shut it down before attempting the import",
|
// Don't clone for powered off VMs, can export OVF from it
|
||||||
vmName));
|
UnmanagedInstanceTO instanceTO = VmwareHelper.getUnmanagedInstance(vmMo.getRunningHost(), vmMo);
|
||||||
|
return new Pair<>(instanceTO, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sourceVmPowerState == VirtualMachinePowerState.POWERED_ON) {
|
||||||
|
if (isWindowsVm(vmMo)) {
|
||||||
|
String err = String.format("VM %s is a Windows VM and its Running, cannot be imported." +
|
||||||
|
" Please gracefully shut it down before attempting the import", vmName);
|
||||||
|
logger.error(err);
|
||||||
|
throw new CloudRuntimeException(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isVMOnStandaloneHost(vmMo)) { // or datacenter.equalsIgnoreCase("ha-datacenter")? [Note: default datacenter name on standalone host: ha-datacenter]
|
||||||
|
String err = String.format("VM %s might be on standalone host and is Running, cannot be imported." +
|
||||||
|
" Please shut it down before attempting the import", vmName);
|
||||||
|
logger.error(err);
|
||||||
|
throw new CloudRuntimeException(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug(String.format("Cloning VM %s at VMware host %s on vCenter %s", vmName, hostIp, vcenter));
|
||||||
VirtualMachineMO clonedVM = createCloneFromSourceVM(vmName, vmMo, dataCenterMO);
|
VirtualMachineMO clonedVM = createCloneFromSourceVM(vmName, vmMo, dataCenterMO);
|
||||||
logger.debug(String.format("VM %s cloned successfully", vmName));
|
logger.debug(String.format("VM %s cloned successfully, to VM %s", vmName, clonedVM.getName()));
|
||||||
UnmanagedInstanceTO clonedInstance = VmwareHelper.getUnmanagedInstance(vmMo.getRunningHost(), clonedVM);
|
UnmanagedInstanceTO clonedInstance = VmwareHelper.getUnmanagedInstance(vmMo.getRunningHost(), clonedVM);
|
||||||
setNicsFromSourceVM(clonedInstance, vmMo);
|
setDisksFromSourceVM(clonedInstance, vmMo);
|
||||||
clonedInstance.setCloneSourcePowerState(sourceVmPowerState == VirtualMachinePowerState.POWERED_ON ? UnmanagedInstanceTO.PowerState.PowerOn : UnmanagedInstanceTO.PowerState.PowerOff);
|
clonedInstance.setCloneSourcePowerState(sourceVmPowerState == VirtualMachinePowerState.POWERED_ON ? UnmanagedInstanceTO.PowerState.PowerOn : UnmanagedInstanceTO.PowerState.PowerOff);
|
||||||
return clonedInstance;
|
return new Pair<>(clonedInstance, true);
|
||||||
|
} catch (CloudRuntimeException cre) {
|
||||||
|
throw cre;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
String err = String.format("Error cloning VM: %s from external vCenter %s: %s", vmName, vcenter, e.getMessage());
|
String err = String.format("Error while finding or cloning VM: %s from vCenter %s: %s", vmName, vcenter, e.getMessage());
|
||||||
logger.error(err, e);
|
logger.error(err, e);
|
||||||
throw new CloudRuntimeException(err, e);
|
throw new CloudRuntimeException(err, e);
|
||||||
}
|
}
|
||||||
@ -1304,7 +1438,12 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
|||||||
return sourceInstance.getOperatingSystem().toLowerCase().contains("windows");
|
return sourceInstance.getOperatingSystem().toLowerCase().contains("windows");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setNicsFromSourceVM(UnmanagedInstanceTO clonedInstance, VirtualMachineMO vmMo) throws Exception {
|
private boolean isVMOnStandaloneHost(VirtualMachineMO vmMo) throws Exception {
|
||||||
|
UnmanagedInstanceTO sourceInstance = VmwareHelper.getUnmanagedInstance(vmMo.getRunningHost(), vmMo);
|
||||||
|
return StringUtils.isEmpty(sourceInstance.getClusterName());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setDisksFromSourceVM(UnmanagedInstanceTO clonedInstance, VirtualMachineMO vmMo) throws Exception {
|
||||||
UnmanagedInstanceTO sourceInstance = VmwareHelper.getUnmanagedInstance(vmMo.getRunningHost(), vmMo);
|
UnmanagedInstanceTO sourceInstance = VmwareHelper.getUnmanagedInstance(vmMo.getRunningHost(), vmMo);
|
||||||
List<UnmanagedInstanceTO.Disk> sourceDisks = sourceInstance.getDisks();
|
List<UnmanagedInstanceTO.Disk> sourceDisks = sourceInstance.getDisks();
|
||||||
List<UnmanagedInstanceTO.Disk> clonedDisks = clonedInstance.getDisks();
|
List<UnmanagedInstanceTO.Disk> clonedDisks = clonedInstance.getDisks();
|
||||||
@ -1316,12 +1455,40 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean removeClonedHypervisorVMOutOfBand(String hostIp, String vmName, Map<String, String> params) {
|
public String createVMTemplateOutOfBand(String hostIp, String vmName, Map<String, String> params, DataStoreTO templateLocation, int threadsCountToExportOvf) {
|
||||||
logger.debug(String.format("Removing VM %s on external vCenter %s", vmName, hostIp));
|
|
||||||
String vcenter = params.get(VmDetailConstants.VMWARE_VCENTER_HOST);
|
String vcenter = params.get(VmDetailConstants.VMWARE_VCENTER_HOST);
|
||||||
String datacenter = params.get(VmDetailConstants.VMWARE_DATACENTER_NAME);
|
String datacenter = params.get(VmDetailConstants.VMWARE_DATACENTER_NAME);
|
||||||
String username = params.get(VmDetailConstants.VMWARE_VCENTER_USERNAME);
|
String username = params.get(VmDetailConstants.VMWARE_VCENTER_USERNAME);
|
||||||
String password = params.get(VmDetailConstants.VMWARE_VCENTER_PASSWORD);
|
String password = params.get(VmDetailConstants.VMWARE_VCENTER_PASSWORD);
|
||||||
|
logger.debug(String.format("Creating template of the VM %s at VMware host %s on vCenter %s", vmName, hostIp, vcenter));
|
||||||
|
|
||||||
|
try {
|
||||||
|
VmwareContext context = connectToVcenter(vcenter, username, password);
|
||||||
|
DatacenterMO dataCenterMO = new DatacenterMO(context, datacenter);
|
||||||
|
VirtualMachineMO vmMo = dataCenterMO.findVm(vmName);
|
||||||
|
if (vmMo == null) {
|
||||||
|
String err = String.format("Cannot find VM with name %s on vCenter %s/%s, to create template file", vmName, vcenter, datacenter);
|
||||||
|
logger.error(err);
|
||||||
|
throw new CloudRuntimeException(err);
|
||||||
|
}
|
||||||
|
String ovaTemplate = createOVFTemplateOfVM(vmMo, templateLocation, threadsCountToExportOvf);
|
||||||
|
logger.debug(String.format("OVF %s created successfully on the datastore", ovaTemplate));
|
||||||
|
return ovaTemplate;
|
||||||
|
} catch (Exception e) {
|
||||||
|
String err = String.format("Error create template file of the VM: %s from vCenter %s: %s", vmName, vcenter, e.getMessage());
|
||||||
|
logger.error(err, e);
|
||||||
|
throw new CloudRuntimeException(err, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean removeClonedHypervisorVMOutOfBand(String hostIp, String vmName, Map<String, String> params) {
|
||||||
|
String vcenter = params.get(VmDetailConstants.VMWARE_VCENTER_HOST);
|
||||||
|
String datacenter = params.get(VmDetailConstants.VMWARE_DATACENTER_NAME);
|
||||||
|
String username = params.get(VmDetailConstants.VMWARE_VCENTER_USERNAME);
|
||||||
|
String password = params.get(VmDetailConstants.VMWARE_VCENTER_PASSWORD);
|
||||||
|
logger.debug(String.format("Removing cloned VM %s at VMware host %s on vCenter %s", vmName, hostIp, vcenter));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
VmwareContext context = connectToVcenter(vcenter, username, password);
|
VmwareContext context = connectToVcenter(vcenter, username, password);
|
||||||
DatacenterMO dataCenterMO = new DatacenterMO(context, datacenter);
|
DatacenterMO dataCenterMO = new DatacenterMO(context, datacenter);
|
||||||
@ -1332,11 +1499,97 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
|||||||
logger.error(err);
|
logger.error(err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return vmMo.destroy();
|
return vmMo.destroy();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
String err = String.format("Error destroying external VM %s: %s", vmName, e.getMessage());
|
String err = String.format("Error destroying cloned VM %s: %s", vmName, e.getMessage());
|
||||||
logger.error(err, e);
|
logger.error(err, e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean removeVMTemplateOutOfBand(DataStoreTO templateLocation, String templateDir) {
|
||||||
|
logger.debug(String.format("Removing template %s", templateDir));
|
||||||
|
|
||||||
|
try {
|
||||||
|
String dataStoreUrl = getDataStoreUrlForTemplate(templateLocation);
|
||||||
|
return deleteDirOnStorage(templateDir, dataStoreUrl, null);
|
||||||
|
} catch (Exception e) {
|
||||||
|
String err = String.format("Error removing template file %s: %s", templateDir, e.getMessage());
|
||||||
|
logger.error(err, e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getDataStoreUrlForTemplate(DataStoreTO templateLocation) {
|
||||||
|
String dataStoreUrl = null;
|
||||||
|
if (templateLocation instanceof NfsTO) {
|
||||||
|
NfsTO nfsStore = (NfsTO) templateLocation;
|
||||||
|
dataStoreUrl = nfsStore.getUrl();
|
||||||
|
} else if (templateLocation instanceof PrimaryDataStoreTO) {
|
||||||
|
PrimaryDataStoreTO primaryDataStoreTO = (PrimaryDataStoreTO) templateLocation;
|
||||||
|
if (primaryDataStoreTO.getPoolType().equals(Storage.StoragePoolType.NetworkFilesystem)) {
|
||||||
|
String psHost = primaryDataStoreTO.getHost();
|
||||||
|
String psPath = primaryDataStoreTO.getPath();
|
||||||
|
dataStoreUrl = "nfs://" + psHost + File.separator + psPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataStoreUrl == null) {
|
||||||
|
throw new CloudRuntimeException("Only NFS storage is supported for template creation");
|
||||||
|
}
|
||||||
|
|
||||||
|
return dataStoreUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String createDirOnStorage(String dirName, String nfsStorageUrl, String nfsVersion) throws Exception {
|
||||||
|
String mountPoint = mountManager.getMountPoint(nfsStorageUrl, nfsVersion);
|
||||||
|
logger.debug("Create dir storage location - url: " + nfsStorageUrl + ", mount point: " + mountPoint + ", dir: " + dirName);
|
||||||
|
String dirMountPath = mountPoint + File.separator + dirName;
|
||||||
|
createDir(dirMountPath);
|
||||||
|
return dirMountPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createDir(String dirName) throws Exception {
|
||||||
|
synchronized (dirName.intern()) {
|
||||||
|
Script command = new Script("mkdir", logger);
|
||||||
|
command.add("-p");
|
||||||
|
command.add(dirName);
|
||||||
|
String cmdResult = command.execute();
|
||||||
|
if (cmdResult != null) {
|
||||||
|
String msg = "Unable to create directory: " + dirName + ", error msg: " + cmdResult;
|
||||||
|
logger.error(msg);
|
||||||
|
throw new Exception(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean deleteDirOnStorage(String dirName, String nfsStorageUrl, String nfsVersion) throws Exception {
|
||||||
|
try {
|
||||||
|
String mountPoint = mountManager.getMountPoint(nfsStorageUrl, nfsVersion);
|
||||||
|
logger.debug("Delete dir storage location - url: " + nfsStorageUrl + ", mount point: " + mountPoint + ", dir: " + dirName);
|
||||||
|
String dirMountPath = mountPoint + File.separator + dirName;
|
||||||
|
deleteDir(dirMountPath);
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
String err = String.format("Unable to delete dir %s: %s", dirName, e.getMessage());
|
||||||
|
logger.error(err, e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deleteDir(String dirName) throws Exception {
|
||||||
|
synchronized (dirName.intern()) {
|
||||||
|
Script command = new Script("rm", logger);
|
||||||
|
command.add("-rf");
|
||||||
|
command.add(dirName);
|
||||||
|
String cmdResult = command.execute();
|
||||||
|
if (cmdResult != null) {
|
||||||
|
String msg = "Unable to delete directory: " + dirName + ", error msg: " + cmdResult;
|
||||||
|
logger.error(msg);
|
||||||
|
throw new Exception(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,21 +17,37 @@
|
|||||||
package com.cloud.hypervisor.guru;
|
package com.cloud.hypervisor.guru;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
import static org.mockito.Mockito.withSettings;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.storage.NfsMountManager;
|
||||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||||
|
import org.apache.cloudstack.vm.UnmanagedInstanceTO;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
import org.junit.AfterClass;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockedConstruction;
|
||||||
|
import org.mockito.MockedStatic;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
import org.mockito.Spy;
|
import org.mockito.Spy;
|
||||||
@ -41,9 +57,19 @@ import org.springframework.test.context.support.AnnotationConfigContextLoader;
|
|||||||
|
|
||||||
import com.cloud.agent.api.Command;
|
import com.cloud.agent.api.Command;
|
||||||
import com.cloud.agent.api.MigrateVmToPoolCommand;
|
import com.cloud.agent.api.MigrateVmToPoolCommand;
|
||||||
|
import com.cloud.agent.api.to.DataStoreTO;
|
||||||
|
import com.cloud.agent.api.to.NfsTO;
|
||||||
import com.cloud.dc.ClusterDetailsDao;
|
import com.cloud.dc.ClusterDetailsDao;
|
||||||
import com.cloud.host.HostVO;
|
import com.cloud.host.HostVO;
|
||||||
import com.cloud.host.dao.HostDao;
|
import com.cloud.host.dao.HostDao;
|
||||||
|
import com.cloud.hypervisor.vmware.mo.DatacenterMO;
|
||||||
|
import com.cloud.hypervisor.vmware.mo.DatastoreMO;
|
||||||
|
import com.cloud.hypervisor.vmware.mo.HostMO;
|
||||||
|
import com.cloud.hypervisor.vmware.mo.VirtualMachineMO;
|
||||||
|
import com.cloud.hypervisor.vmware.util.VmwareClient;
|
||||||
|
import com.cloud.hypervisor.vmware.util.VmwareContext;
|
||||||
|
import com.cloud.hypervisor.vmware.util.VmwareHelper;
|
||||||
|
import com.cloud.storage.Storage;
|
||||||
import com.cloud.storage.Storage.ProvisioningType;
|
import com.cloud.storage.Storage.ProvisioningType;
|
||||||
import com.cloud.storage.StoragePool;
|
import com.cloud.storage.StoragePool;
|
||||||
import com.cloud.storage.StoragePoolHostVO;
|
import com.cloud.storage.StoragePoolHostVO;
|
||||||
@ -51,8 +77,15 @@ import com.cloud.storage.Volume;
|
|||||||
import com.cloud.storage.VolumeVO;
|
import com.cloud.storage.VolumeVO;
|
||||||
import com.cloud.storage.dao.StoragePoolHostDao;
|
import com.cloud.storage.dao.StoragePoolHostDao;
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
|
import com.cloud.utils.UuidUtils;
|
||||||
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
import com.cloud.vm.VirtualMachine;
|
import com.cloud.vm.VirtualMachine;
|
||||||
import com.cloud.vm.VirtualMachineManager;
|
import com.cloud.vm.VirtualMachineManager;
|
||||||
|
import com.cloud.vm.VmDetailConstants;
|
||||||
|
import com.vmware.vim25.ManagedObjectReference;
|
||||||
|
import com.vmware.vim25.ServiceContent;
|
||||||
|
import com.vmware.vim25.VimPortType;
|
||||||
|
import com.vmware.vim25.VirtualMachinePowerState;
|
||||||
|
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
@ContextConfiguration(loader = AnnotationConfigContextLoader.class)
|
@ContextConfiguration(loader = AnnotationConfigContextLoader.class)
|
||||||
@ -79,6 +112,21 @@ public class VMwareGuruTest {
|
|||||||
|
|
||||||
AutoCloseable closeable;
|
AutoCloseable closeable;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
NfsMountManager mountManager;
|
||||||
|
|
||||||
|
private static MockedStatic<VmwareHelper> mockedVmwareHelper;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void init() {
|
||||||
|
mockedVmwareHelper = Mockito.mockStatic(VmwareHelper.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void close() {
|
||||||
|
mockedVmwareHelper.close();
|
||||||
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void testSetUp() throws Exception {
|
public void testSetUp() throws Exception {
|
||||||
closeable = MockitoAnnotations.openMocks(this);
|
closeable = MockitoAnnotations.openMocks(this);
|
||||||
@ -155,4 +203,415 @@ public class VMwareGuruTest {
|
|||||||
|
|
||||||
assertEquals(expected, result);
|
assertEquals(expected, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected=CloudRuntimeException.class)
|
||||||
|
public void testCloneHypervisorVM_NoExternalVM() throws Exception {
|
||||||
|
String vCenterHost = "10.1.1.2";
|
||||||
|
String datacenterName = "datacenter";
|
||||||
|
String hostIp = "10.1.1.3";
|
||||||
|
String vmName = "test-vm";
|
||||||
|
Map<String, String> params = new HashMap<>();
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_HOST, vCenterHost);
|
||||||
|
params.put(VmDetailConstants.VMWARE_DATACENTER_NAME, datacenterName);
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_USERNAME, "username");
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_PASSWORD, "password");
|
||||||
|
|
||||||
|
ManagedObjectReference mor = Mockito.mock(ManagedObjectReference.class);
|
||||||
|
ServiceContent serviceContent = Mockito.mock(ServiceContent.class);
|
||||||
|
VimPortType vimPort = Mockito.mock(VimPortType.class);
|
||||||
|
VmwareClient vimClient = spy(new VmwareClient(vCenterHost));
|
||||||
|
VmwareContext vmwareContext = spy(new VmwareContext(vimClient, vCenterHost));
|
||||||
|
Mockito.doReturn(vimClient).when(vmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(vmwareContext).getRootFolder();
|
||||||
|
Mockito.doReturn(mor).when(vimClient).getDecendentMoRef(any(ManagedObjectReference.class), anyString(), anyString());
|
||||||
|
DatacenterMO dataCenterMO = spy(new DatacenterMO(vmwareContext, datacenterName));
|
||||||
|
|
||||||
|
try (MockedConstruction<VmwareClient> ignored1 = Mockito.mockConstruction(VmwareClient.class, withSettings().spiedInstance(vimClient), (mockVmwareClient, contextVmwareClient) -> {
|
||||||
|
Mockito.doReturn(vimPort).when(mockVmwareClient).getService();
|
||||||
|
Mockito.doReturn(serviceContent).when(mockVmwareClient).getServiceContent();
|
||||||
|
Mockito.doNothing().when(mockVmwareClient).connect(anyString(), anyString(), anyString());
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareClient).getRootFolder();
|
||||||
|
}); MockedConstruction<VmwareContext> ignored2 = Mockito.mockConstruction(VmwareContext.class, withSettings().spiedInstance(vmwareContext), (mockVmwareContext, contextVmwareContext) -> {
|
||||||
|
Mockito.doReturn(vimClient).when(mockVmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareContext).getRootFolder();
|
||||||
|
}); MockedConstruction<DatacenterMO> ignored3 = Mockito.mockConstruction(DatacenterMO.class, withSettings().spiedInstance(dataCenterMO), (mockDatacenterMO, contextDatacenterMO) -> {
|
||||||
|
Mockito.doReturn(null).when(mockDatacenterMO).findVm(vmName);
|
||||||
|
})) {
|
||||||
|
vMwareGuru.getHypervisorVMOutOfBandAndCloneIfRequired(hostIp, vmName, params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected=CloudRuntimeException.class)
|
||||||
|
public void testCloneHypervisorVM_WindowsVMRunning() throws Exception {
|
||||||
|
String vCenterHost = "10.1.1.2";
|
||||||
|
String datacenterName = "datacenter";
|
||||||
|
String hostIp = "10.1.1.3";
|
||||||
|
String vmName = "test-vm";
|
||||||
|
Map<String, String> params = new HashMap<>();
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_HOST, vCenterHost);
|
||||||
|
params.put(VmDetailConstants.VMWARE_DATACENTER_NAME, datacenterName);
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_USERNAME, "username");
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_PASSWORD, "password");
|
||||||
|
|
||||||
|
ManagedObjectReference mor = Mockito.mock(ManagedObjectReference.class);
|
||||||
|
ServiceContent serviceContent = Mockito.mock(ServiceContent.class);
|
||||||
|
VimPortType vimPort = Mockito.mock(VimPortType.class);
|
||||||
|
VmwareClient vimClient = spy(new VmwareClient(vCenterHost));
|
||||||
|
VmwareContext vmwareContext = spy(new VmwareContext(vimClient, vCenterHost));
|
||||||
|
Mockito.doReturn(vimClient).when(vmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(vmwareContext).getRootFolder();
|
||||||
|
Mockito.doReturn(mor).when(vimClient).getDecendentMoRef(any(ManagedObjectReference.class), anyString(), anyString());
|
||||||
|
DatacenterMO dataCenterMO = spy(new DatacenterMO(vmwareContext, datacenterName));
|
||||||
|
VirtualMachineMO vmMo = Mockito.mock(VirtualMachineMO.class);
|
||||||
|
HostMO hostMo = Mockito.mock(HostMO.class);
|
||||||
|
Mockito.doReturn(VirtualMachinePowerState.POWERED_ON).when(vmMo).getPowerState();
|
||||||
|
Mockito.doReturn(hostMo).when(vmMo).getRunningHost();
|
||||||
|
UnmanagedInstanceTO instance = Mockito.mock(UnmanagedInstanceTO.class);
|
||||||
|
Mockito.doReturn("Windows 2019").when(instance).getOperatingSystem();
|
||||||
|
when(VmwareHelper.getUnmanagedInstance(hostMo, vmMo)).thenReturn(instance);
|
||||||
|
|
||||||
|
try (MockedConstruction<VmwareClient> ignored1 = Mockito.mockConstruction(VmwareClient.class, withSettings().spiedInstance(vimClient), (mockVmwareClient, contextVmwareClient) -> {
|
||||||
|
Mockito.doReturn(vimPort).when(mockVmwareClient).getService();
|
||||||
|
Mockito.doReturn(serviceContent).when(mockVmwareClient).getServiceContent();
|
||||||
|
Mockito.doNothing().when(mockVmwareClient).connect(anyString(), anyString(), anyString());
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareClient).getRootFolder();
|
||||||
|
}); MockedConstruction<VmwareContext> ignored2 = Mockito.mockConstruction(VmwareContext.class, withSettings().spiedInstance(vmwareContext), (mockVmwareContext, contextVmwareContext) -> {
|
||||||
|
Mockito.doReturn(vimClient).when(mockVmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareContext).getRootFolder();
|
||||||
|
}); MockedConstruction<DatacenterMO> ignored3 = Mockito.mockConstruction(DatacenterMO.class, withSettings().spiedInstance(dataCenterMO), (mockDatacenterMO, contextDatacenterMO) -> {
|
||||||
|
Mockito.doReturn(vmMo).when(mockDatacenterMO).findVm(vmName);
|
||||||
|
})) {
|
||||||
|
vMwareGuru.getHypervisorVMOutOfBandAndCloneIfRequired(hostIp, vmName, params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected=CloudRuntimeException.class)
|
||||||
|
public void testCloneHypervisorVM_GetDatastoresFailed() throws Exception {
|
||||||
|
String vCenterHost = "10.1.1.2";
|
||||||
|
String datacenterName = "datacenter";
|
||||||
|
String hostIp = "10.1.1.3";
|
||||||
|
String vmName = "test-vm";
|
||||||
|
Map<String, String> params = new HashMap<>();
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_HOST, vCenterHost);
|
||||||
|
params.put(VmDetailConstants.VMWARE_DATACENTER_NAME, datacenterName);
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_USERNAME, "username");
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_PASSWORD, "password");
|
||||||
|
|
||||||
|
ManagedObjectReference mor = Mockito.mock(ManagedObjectReference.class);
|
||||||
|
ServiceContent serviceContent = Mockito.mock(ServiceContent.class);
|
||||||
|
VimPortType vimPort = Mockito.mock(VimPortType.class);
|
||||||
|
VmwareClient vimClient = spy(new VmwareClient(vCenterHost));
|
||||||
|
VmwareContext vmwareContext = spy(new VmwareContext(vimClient, vCenterHost));
|
||||||
|
Mockito.doReturn(vimClient).when(vmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(vmwareContext).getRootFolder();
|
||||||
|
Mockito.doReturn(mor).when(vimClient).getDecendentMoRef(any(ManagedObjectReference.class), anyString(), anyString());
|
||||||
|
DatacenterMO dataCenterMO = spy(new DatacenterMO(vmwareContext, datacenterName));
|
||||||
|
VirtualMachineMO vmMo = Mockito.mock(VirtualMachineMO.class);
|
||||||
|
HostMO hostMo = Mockito.mock(HostMO.class);
|
||||||
|
Mockito.doReturn(VirtualMachinePowerState.POWERED_ON).when(vmMo).getPowerState();
|
||||||
|
Mockito.doReturn(hostMo).when(vmMo).getRunningHost();
|
||||||
|
UnmanagedInstanceTO instance = Mockito.mock(UnmanagedInstanceTO.class);
|
||||||
|
Mockito.doReturn("CentOS").when(instance).getOperatingSystem();
|
||||||
|
Mockito.doReturn("test-cluster").when(instance).getClusterName();
|
||||||
|
when(VmwareHelper.getUnmanagedInstance(hostMo, vmMo)).thenReturn(instance);
|
||||||
|
List<DatastoreMO> datastores = new ArrayList<>();
|
||||||
|
Mockito.doReturn(datastores).when(vmMo).getAllDatastores();
|
||||||
|
|
||||||
|
try (MockedConstruction<VmwareClient> ignored1 = Mockito.mockConstruction(VmwareClient.class, withSettings().spiedInstance(vimClient), (mockVmwareClient, contextVmwareClient) -> {
|
||||||
|
Mockito.doReturn(vimPort).when(mockVmwareClient).getService();
|
||||||
|
Mockito.doReturn(serviceContent).when(mockVmwareClient).getServiceContent();
|
||||||
|
Mockito.doNothing().when(mockVmwareClient).connect(anyString(), anyString(), anyString());
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareClient).getRootFolder();
|
||||||
|
}); MockedConstruction<VmwareContext> ignored2 = Mockito.mockConstruction(VmwareContext.class, withSettings().spiedInstance(vmwareContext), (mockVmwareContext, contextVmwareContext) -> {
|
||||||
|
Mockito.doReturn(vimClient).when(mockVmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareContext).getRootFolder();
|
||||||
|
}); MockedConstruction<DatacenterMO> ignored3 = Mockito.mockConstruction(DatacenterMO.class, withSettings().spiedInstance(dataCenterMO), (mockDatacenterMO, contextDatacenterMO) -> {
|
||||||
|
Mockito.doReturn(vmMo).when(mockDatacenterMO).findVm(vmName);
|
||||||
|
})) {
|
||||||
|
vMwareGuru.getHypervisorVMOutOfBandAndCloneIfRequired(hostIp, vmName, params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected=CloudRuntimeException.class)
|
||||||
|
public void testCloneHypervisorVM_CloneVMFailed() throws Exception {
|
||||||
|
String vCenterHost = "10.1.1.2";
|
||||||
|
String datacenterName = "datacenter";
|
||||||
|
String hostIp = "10.1.1.3";
|
||||||
|
String vmName = "test-vm";
|
||||||
|
Map<String, String> params = new HashMap<>();
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_HOST, vCenterHost);
|
||||||
|
params.put(VmDetailConstants.VMWARE_DATACENTER_NAME, datacenterName);
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_USERNAME, "username");
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_PASSWORD, "password");
|
||||||
|
|
||||||
|
ManagedObjectReference mor = Mockito.mock(ManagedObjectReference.class);
|
||||||
|
ServiceContent serviceContent = Mockito.mock(ServiceContent.class);
|
||||||
|
VimPortType vimPort = Mockito.mock(VimPortType.class);
|
||||||
|
VmwareClient vimClient = spy(new VmwareClient(vCenterHost));
|
||||||
|
VmwareContext vmwareContext = spy(new VmwareContext(vimClient, vCenterHost));
|
||||||
|
Mockito.doReturn(vimClient).when(vmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(vmwareContext).getRootFolder();
|
||||||
|
Mockito.doReturn(mor).when(vimClient).getDecendentMoRef(any(ManagedObjectReference.class), anyString(), anyString());
|
||||||
|
DatacenterMO dataCenterMO = spy(new DatacenterMO(vmwareContext, datacenterName));
|
||||||
|
VirtualMachineMO vmMo = Mockito.mock(VirtualMachineMO.class);
|
||||||
|
HostMO hostMo = Mockito.mock(HostMO.class);
|
||||||
|
Mockito.doReturn(VirtualMachinePowerState.POWERED_ON).when(vmMo).getPowerState();
|
||||||
|
Mockito.doReturn(hostMo).when(vmMo).getRunningHost();
|
||||||
|
Mockito.doReturn(mor).when(hostMo).getHyperHostOwnerResourcePool();
|
||||||
|
UnmanagedInstanceTO instance = Mockito.mock(UnmanagedInstanceTO.class);
|
||||||
|
Mockito.doReturn("CentOS").when(instance).getOperatingSystem();
|
||||||
|
Mockito.doReturn("test-cluster").when(instance).getClusterName();
|
||||||
|
when(VmwareHelper.getUnmanagedInstance(hostMo, vmMo)).thenReturn(instance);
|
||||||
|
DatastoreMO datastoreMO = Mockito.mock(DatastoreMO.class);
|
||||||
|
Mockito.doReturn(mor).when(datastoreMO).getMor();
|
||||||
|
List<DatastoreMO> datastores = new ArrayList<>();
|
||||||
|
datastores.add(datastoreMO);
|
||||||
|
Mockito.doReturn(datastores).when(vmMo).getAllDatastores();
|
||||||
|
Mockito.lenient().doReturn(false).when(vmMo).createFullClone(anyString(), any(ManagedObjectReference.class), any(ManagedObjectReference.class), any(ManagedObjectReference.class), any(Storage.ProvisioningType.class));
|
||||||
|
|
||||||
|
try (MockedConstruction<VmwareClient> ignored1 = Mockito.mockConstruction(VmwareClient.class, withSettings().spiedInstance(vimClient), (mockVmwareClient, contextVmwareClient) -> {
|
||||||
|
Mockito.doReturn(vimPort).when(mockVmwareClient).getService();
|
||||||
|
Mockito.doReturn(serviceContent).when(mockVmwareClient).getServiceContent();
|
||||||
|
Mockito.doNothing().when(mockVmwareClient).connect(anyString(), anyString(), anyString());
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareClient).getRootFolder();
|
||||||
|
}); MockedConstruction<VmwareContext> ignored2 = Mockito.mockConstruction(VmwareContext.class, withSettings().spiedInstance(vmwareContext), (mockVmwareContext, contextVmwareContext) -> {
|
||||||
|
Mockito.doReturn(vimClient).when(mockVmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareContext).getRootFolder();
|
||||||
|
}); MockedConstruction<DatacenterMO> ignored3 = Mockito.mockConstruction(DatacenterMO.class, withSettings().spiedInstance(dataCenterMO), (mockDatacenterMO, contextDatacenterMO) -> {
|
||||||
|
Mockito.doReturn(vmMo).when(mockDatacenterMO).findVm(anyString());
|
||||||
|
Mockito.doReturn(mor).when(mockDatacenterMO).getVmFolder();
|
||||||
|
Mockito.doReturn(mor).when(mockDatacenterMO).getMor();
|
||||||
|
})) {
|
||||||
|
vMwareGuru.getHypervisorVMOutOfBandAndCloneIfRequired(hostIp, vmName, params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCloneHypervisorVM() throws Exception {
|
||||||
|
String vCenterHost = "10.1.1.2";
|
||||||
|
String datacenterName = "datacenter";
|
||||||
|
String hostIp = "10.1.1.3";
|
||||||
|
String vmName = "test-vm";
|
||||||
|
Map<String, String> params = new HashMap<>();
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_HOST, vCenterHost);
|
||||||
|
params.put(VmDetailConstants.VMWARE_DATACENTER_NAME, datacenterName);
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_USERNAME, "username");
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_PASSWORD, "password");
|
||||||
|
|
||||||
|
ManagedObjectReference mor = Mockito.mock(ManagedObjectReference.class);
|
||||||
|
ServiceContent serviceContent = Mockito.mock(ServiceContent.class);
|
||||||
|
VimPortType vimPort = Mockito.mock(VimPortType.class);
|
||||||
|
VmwareClient vimClient = spy(new VmwareClient(vCenterHost));
|
||||||
|
VmwareContext vmwareContext = spy(new VmwareContext(vimClient, vCenterHost));
|
||||||
|
Mockito.doReturn(vimClient).when(vmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(vmwareContext).getRootFolder();
|
||||||
|
Mockito.doReturn(mor).when(vimClient).getDecendentMoRef(any(ManagedObjectReference.class), anyString(), anyString());
|
||||||
|
DatacenterMO dataCenterMO = spy(new DatacenterMO(vmwareContext, datacenterName));
|
||||||
|
VirtualMachineMO vmMo = Mockito.mock(VirtualMachineMO.class);
|
||||||
|
HostMO hostMo = Mockito.mock(HostMO.class);
|
||||||
|
Mockito.doReturn(VirtualMachinePowerState.POWERED_ON).when(vmMo).getPowerState();
|
||||||
|
Mockito.doReturn(hostMo).when(vmMo).getRunningHost();
|
||||||
|
Mockito.doReturn(mor).when(hostMo).getHyperHostOwnerResourcePool();
|
||||||
|
Mockito.doReturn(mor).when(hostMo).getMor();
|
||||||
|
DatastoreMO datastoreMO = Mockito.mock(DatastoreMO.class);
|
||||||
|
Mockito.doReturn(mor).when(datastoreMO).getMor();
|
||||||
|
List<DatastoreMO> datastores = new ArrayList<>();
|
||||||
|
datastores.add(datastoreMO);
|
||||||
|
Mockito.doReturn(datastores).when(vmMo).getAllDatastores();
|
||||||
|
Mockito.lenient().doReturn(true).when(vmMo).createFullClone(anyString(), any(ManagedObjectReference.class), any(ManagedObjectReference.class), any(ManagedObjectReference.class), any(Storage.ProvisioningType.class));
|
||||||
|
UnmanagedInstanceTO instance = Mockito.mock(UnmanagedInstanceTO.class);
|
||||||
|
Mockito.doReturn("CentOS").when(instance).getOperatingSystem();
|
||||||
|
Mockito.doReturn("test-cluster").when(instance).getClusterName();
|
||||||
|
when(VmwareHelper.getUnmanagedInstance(hostMo, vmMo)).thenReturn(instance);
|
||||||
|
UnmanagedInstanceTO.Disk disk = Mockito.mock(UnmanagedInstanceTO.Disk.class);
|
||||||
|
Mockito.doReturn("1").when(disk).getDiskId();
|
||||||
|
List<UnmanagedInstanceTO.Disk> disks = new ArrayList<>();
|
||||||
|
disks.add(disk);
|
||||||
|
Mockito.doReturn(disks).when(instance).getDisks();
|
||||||
|
|
||||||
|
try (MockedConstruction<VmwareClient> ignored1 = Mockito.mockConstruction(VmwareClient.class, withSettings().spiedInstance(vimClient), (mockVmwareClient, contextVmwareClient) -> {
|
||||||
|
Mockito.doReturn(vimPort).when(mockVmwareClient).getService();
|
||||||
|
Mockito.doReturn(serviceContent).when(mockVmwareClient).getServiceContent();
|
||||||
|
Mockito.doNothing().when(mockVmwareClient).connect(anyString(), anyString(), anyString());
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareClient).getRootFolder();
|
||||||
|
}); MockedConstruction<VmwareContext> ignored2 = Mockito.mockConstruction(VmwareContext.class, withSettings().spiedInstance(vmwareContext), (mockVmwareContext, contextVmwareContext) -> {
|
||||||
|
Mockito.doReturn(vimClient).when(mockVmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareContext).getRootFolder();
|
||||||
|
}); MockedConstruction<DatacenterMO> ignored3 = Mockito.mockConstruction(DatacenterMO.class, withSettings().spiedInstance(dataCenterMO), (mockDatacenterMO, contextDatacenterMO) -> {
|
||||||
|
Mockito.doReturn(vmMo).when(mockDatacenterMO).findVm(anyString());
|
||||||
|
Mockito.doReturn(mor).when(mockDatacenterMO).getVmFolder();
|
||||||
|
Mockito.doReturn(mor).when(mockDatacenterMO).getMor();
|
||||||
|
})) {
|
||||||
|
Pair<UnmanagedInstanceTO, Boolean> clonedVm = vMwareGuru.getHypervisorVMOutOfBandAndCloneIfRequired(hostIp, vmName, params);
|
||||||
|
assertNotNull(clonedVm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected=CloudRuntimeException.class)
|
||||||
|
public void testCreateVMTemplateFileOutOfBand_NoClonedVM() throws Exception {
|
||||||
|
String vCenterHost = "10.1.1.2";
|
||||||
|
String datacenterName = "datacenter";
|
||||||
|
String hostIp = "10.1.1.3";
|
||||||
|
String vmName = "cloned-test-vm";
|
||||||
|
Map<String, String> params = new HashMap<>();
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_HOST, vCenterHost);
|
||||||
|
params.put(VmDetailConstants.VMWARE_DATACENTER_NAME, datacenterName);
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_USERNAME, "username");
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_PASSWORD, "password");
|
||||||
|
|
||||||
|
DataStoreTO dataStore = Mockito.mock(DataStoreTO.class);
|
||||||
|
ManagedObjectReference mor = Mockito.mock(ManagedObjectReference.class);
|
||||||
|
ServiceContent serviceContent = Mockito.mock(ServiceContent.class);
|
||||||
|
VimPortType vimPort = Mockito.mock(VimPortType.class);
|
||||||
|
VmwareClient vimClient = spy(new VmwareClient(vCenterHost));
|
||||||
|
VmwareContext vmwareContext = spy(new VmwareContext(vimClient, vCenterHost));
|
||||||
|
Mockito.doReturn(vimClient).when(vmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(vmwareContext).getRootFolder();
|
||||||
|
Mockito.doReturn(mor).when(vimClient).getDecendentMoRef(any(ManagedObjectReference.class), anyString(), anyString());
|
||||||
|
DatacenterMO dataCenterMO = spy(new DatacenterMO(vmwareContext, datacenterName));
|
||||||
|
|
||||||
|
try (MockedConstruction<VmwareClient> ignored1 = Mockito.mockConstruction(VmwareClient.class, withSettings().spiedInstance(vimClient), (mockVmwareClient, contextVmwareClient) -> {
|
||||||
|
Mockito.doReturn(vimPort).when(mockVmwareClient).getService();
|
||||||
|
Mockito.doReturn(serviceContent).when(mockVmwareClient).getServiceContent();
|
||||||
|
Mockito.doNothing().when(mockVmwareClient).connect(anyString(), anyString(), anyString());
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareClient).getRootFolder();
|
||||||
|
}); MockedConstruction<VmwareContext> ignored2 = Mockito.mockConstruction(VmwareContext.class, withSettings().spiedInstance(vmwareContext), (mockVmwareContext, contextVmwareContext) -> {
|
||||||
|
Mockito.doReturn(vimClient).when(mockVmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareContext).getRootFolder();
|
||||||
|
}); MockedConstruction<DatacenterMO> ignored3 = Mockito.mockConstruction(DatacenterMO.class, withSettings().spiedInstance(dataCenterMO), (mockDatacenterMO, contextDatacenterMO) -> {
|
||||||
|
Mockito.doReturn(null).when(mockDatacenterMO).findVm(vmName);
|
||||||
|
})) {
|
||||||
|
vMwareGuru.createVMTemplateOutOfBand(hostIp, vmName, params, dataStore, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateVMTemplateFileOutOfBand() throws Exception {
|
||||||
|
String vCenterHost = "10.1.1.2";
|
||||||
|
String datacenterName = "datacenter";
|
||||||
|
String hostIp = "10.1.1.3";
|
||||||
|
String vmName = "cloned-test-vm";
|
||||||
|
Map<String, String> params = new HashMap<>();
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_HOST, vCenterHost);
|
||||||
|
params.put(VmDetailConstants.VMWARE_DATACENTER_NAME, datacenterName);
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_USERNAME, "username");
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_PASSWORD, "password");
|
||||||
|
|
||||||
|
ManagedObjectReference mor = Mockito.mock(ManagedObjectReference.class);
|
||||||
|
ServiceContent serviceContent = Mockito.mock(ServiceContent.class);
|
||||||
|
VimPortType vimPort = Mockito.mock(VimPortType.class);
|
||||||
|
VmwareClient vimClient = spy(new VmwareClient(vCenterHost));
|
||||||
|
VmwareContext vmwareContext = spy(new VmwareContext(vimClient, vCenterHost));
|
||||||
|
Mockito.doReturn(vimClient).when(vmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(vmwareContext).getRootFolder();
|
||||||
|
Mockito.doReturn(mor).when(vimClient).getDecendentMoRef(any(ManagedObjectReference.class), anyString(), anyString());
|
||||||
|
DatacenterMO dataCenterMO = spy(new DatacenterMO(vmwareContext, datacenterName));
|
||||||
|
VirtualMachineMO vmMo = Mockito.mock(VirtualMachineMO.class);
|
||||||
|
Mockito.doNothing().when(vmMo).exportVm(anyString(), anyString(), anyBoolean(), anyBoolean(), anyInt());
|
||||||
|
NfsTO dataStore = Mockito.mock(NfsTO.class);
|
||||||
|
Mockito.doReturn("nfs://10.1.1.4/testdir").when(dataStore).getUrl();
|
||||||
|
|
||||||
|
try (MockedConstruction<VmwareClient> ignored1 = Mockito.mockConstruction(VmwareClient.class, withSettings().spiedInstance(vimClient), (mockVmwareClient, contextVmwareClient) -> {
|
||||||
|
Mockito.doReturn(vimPort).when(mockVmwareClient).getService();
|
||||||
|
Mockito.doReturn(serviceContent).when(mockVmwareClient).getServiceContent();
|
||||||
|
Mockito.doNothing().when(mockVmwareClient).connect(anyString(), anyString(), anyString());
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareClient).getRootFolder();
|
||||||
|
}); MockedConstruction<VmwareContext> ignored2 = Mockito.mockConstruction(VmwareContext.class, withSettings().spiedInstance(vmwareContext), (mockVmwareContext, contextVmwareContext) -> {
|
||||||
|
Mockito.doReturn(vimClient).when(mockVmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareContext).getRootFolder();
|
||||||
|
}); MockedConstruction<DatacenterMO> ignored3 = Mockito.mockConstruction(DatacenterMO.class, withSettings().spiedInstance(dataCenterMO), (mockDatacenterMO, contextDatacenterMO) -> {
|
||||||
|
Mockito.doReturn(vmMo).when(mockDatacenterMO).findVm(vmName);
|
||||||
|
})) {
|
||||||
|
String vmTemplate = vMwareGuru.createVMTemplateOutOfBand(hostIp, vmName, params, dataStore, -1);
|
||||||
|
assertNotNull(vmTemplate);
|
||||||
|
assertTrue(UuidUtils.isUuid(vmTemplate));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveClonedHypervisorVM_NoClonedVM() throws Exception {
|
||||||
|
String vCenterHost = "10.1.1.2";
|
||||||
|
String datacenterName = "datacenter";
|
||||||
|
String hostIp = "10.1.1.3";
|
||||||
|
String vmName = "cloned-test-vm";
|
||||||
|
Map<String, String> params = new HashMap<>();
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_HOST, vCenterHost);
|
||||||
|
params.put(VmDetailConstants.VMWARE_DATACENTER_NAME, datacenterName);
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_USERNAME, "username");
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_PASSWORD, "password");
|
||||||
|
|
||||||
|
ManagedObjectReference mor = Mockito.mock(ManagedObjectReference.class);
|
||||||
|
ServiceContent serviceContent = Mockito.mock(ServiceContent.class);
|
||||||
|
VimPortType vimPort = Mockito.mock(VimPortType.class);
|
||||||
|
VmwareClient vimClient = spy(new VmwareClient(vCenterHost));
|
||||||
|
VmwareContext vmwareContext = spy(new VmwareContext(vimClient, vCenterHost));
|
||||||
|
Mockito.doReturn(vimClient).when(vmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(vmwareContext).getRootFolder();
|
||||||
|
Mockito.doReturn(mor).when(vimClient).getDecendentMoRef(any(ManagedObjectReference.class), anyString(), anyString());
|
||||||
|
DatacenterMO dataCenterMO = spy(new DatacenterMO(vmwareContext, datacenterName));
|
||||||
|
|
||||||
|
try (MockedConstruction<VmwareClient> ignored1 = Mockito.mockConstruction(VmwareClient.class, withSettings().spiedInstance(vimClient), (mockVmwareClient, contextVmwareClient) -> {
|
||||||
|
Mockito.doReturn(vimPort).when(mockVmwareClient).getService();
|
||||||
|
Mockito.doReturn(serviceContent).when(mockVmwareClient).getServiceContent();
|
||||||
|
Mockito.doNothing().when(mockVmwareClient).connect(anyString(), anyString(), anyString());
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareClient).getRootFolder();
|
||||||
|
}); MockedConstruction<VmwareContext> ignored2 = Mockito.mockConstruction(VmwareContext.class, withSettings().spiedInstance(vmwareContext), (mockVmwareContext, contextVmwareContext) -> {
|
||||||
|
Mockito.doReturn(vimClient).when(mockVmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareContext).getRootFolder();
|
||||||
|
}); MockedConstruction<DatacenterMO> ignored3 = Mockito.mockConstruction(DatacenterMO.class, withSettings().spiedInstance(dataCenterMO), (mockDatacenterMO, contextDatacenterMO) -> {
|
||||||
|
Mockito.doReturn(null).when(mockDatacenterMO).findVm(vmName);
|
||||||
|
})) {
|
||||||
|
boolean result = vMwareGuru.removeClonedHypervisorVMOutOfBand(hostIp, vmName, params);
|
||||||
|
assertFalse(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveClonedHypervisorVM() throws Exception {
|
||||||
|
String vCenterHost = "10.1.1.2";
|
||||||
|
String datacenterName = "datacenter";
|
||||||
|
String hostIp = "10.1.1.3";
|
||||||
|
String vmName = "cloned-test-vm";
|
||||||
|
Map<String, String> params = new HashMap<>();
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_HOST, vCenterHost);
|
||||||
|
params.put(VmDetailConstants.VMWARE_DATACENTER_NAME, datacenterName);
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_USERNAME, "username");
|
||||||
|
params.put(VmDetailConstants.VMWARE_VCENTER_PASSWORD, "password");
|
||||||
|
|
||||||
|
ManagedObjectReference mor = Mockito.mock(ManagedObjectReference.class);
|
||||||
|
ServiceContent serviceContent = Mockito.mock(ServiceContent.class);
|
||||||
|
VimPortType vimPort = Mockito.mock(VimPortType.class);
|
||||||
|
VmwareClient vimClient = spy(new VmwareClient(vCenterHost));
|
||||||
|
VmwareContext vmwareContext = spy(new VmwareContext(vimClient, vCenterHost));
|
||||||
|
Mockito.doReturn(vimClient).when(vmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(vmwareContext).getRootFolder();
|
||||||
|
Mockito.doReturn(mor).when(vimClient).getDecendentMoRef(any(ManagedObjectReference.class), anyString(), anyString());
|
||||||
|
DatacenterMO dataCenterMO = spy(new DatacenterMO(vmwareContext, datacenterName));
|
||||||
|
VirtualMachineMO vmMo = Mockito.mock(VirtualMachineMO.class);
|
||||||
|
Mockito.doReturn(true).when(vmMo).destroy();
|
||||||
|
|
||||||
|
try (MockedConstruction<VmwareClient> ignored1 = Mockito.mockConstruction(VmwareClient.class, withSettings().spiedInstance(vimClient), (mockVmwareClient, contextVmwareClient) -> {
|
||||||
|
Mockito.doReturn(vimPort).when(mockVmwareClient).getService();
|
||||||
|
Mockito.doReturn(serviceContent).when(mockVmwareClient).getServiceContent();
|
||||||
|
Mockito.doNothing().when(mockVmwareClient).connect(anyString(), anyString(), anyString());
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareClient).getRootFolder();
|
||||||
|
}); MockedConstruction<VmwareContext> ignored2 = Mockito.mockConstruction(VmwareContext.class, withSettings().spiedInstance(vmwareContext), (mockVmwareContext, contextVmwareContext) -> {
|
||||||
|
Mockito.doReturn(vimClient).when(mockVmwareContext).getVimClient();
|
||||||
|
Mockito.doReturn(mor).when(mockVmwareContext).getRootFolder();
|
||||||
|
}); MockedConstruction<DatacenterMO> ignored3 = Mockito.mockConstruction(DatacenterMO.class, withSettings().spiedInstance(dataCenterMO), (mockDatacenterMO, contextDatacenterMO) -> {
|
||||||
|
Mockito.doReturn(vmMo).when(mockDatacenterMO).findVm(vmName);
|
||||||
|
})) {
|
||||||
|
boolean result = vMwareGuru.removeClonedHypervisorVMOutOfBand(hostIp, vmName, params);
|
||||||
|
assertTrue(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveVMTemplateFileOutOfBand() throws Exception {
|
||||||
|
NfsTO dataStore = Mockito.mock(NfsTO.class);
|
||||||
|
Mockito.doReturn("nfs://10.1.1.4/testdir").when(dataStore).getUrl();
|
||||||
|
String templateDir = "f887b7b3-3d1f-4a7d-93e5-3147f58866c6";
|
||||||
|
boolean result = vMwareGuru.removeVMTemplateOutOfBand(dataStore, templateDir);
|
||||||
|
assertTrue(result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -62,6 +62,7 @@ import org.apache.cloudstack.diagnostics.DiagnosticsService;
|
|||||||
import org.apache.cloudstack.hypervisor.xenserver.ExtraConfigurationUtility;
|
import org.apache.cloudstack.hypervisor.xenserver.ExtraConfigurationUtility;
|
||||||
import org.apache.cloudstack.storage.command.browser.ListDataStoreObjectsAnswer;
|
import org.apache.cloudstack.storage.command.browser.ListDataStoreObjectsAnswer;
|
||||||
import org.apache.cloudstack.storage.command.browser.ListDataStoreObjectsCommand;
|
import org.apache.cloudstack.storage.command.browser.ListDataStoreObjectsCommand;
|
||||||
|
import org.apache.cloudstack.storage.configdrive.ConfigDrive;
|
||||||
import org.apache.cloudstack.storage.to.TemplateObjectTO;
|
import org.apache.cloudstack.storage.to.TemplateObjectTO;
|
||||||
import org.apache.cloudstack.storage.to.VolumeObjectTO;
|
import org.apache.cloudstack.storage.to.VolumeObjectTO;
|
||||||
import org.apache.cloudstack.utils.security.ParserUtils;
|
import org.apache.cloudstack.utils.security.ParserUtils;
|
||||||
@ -221,6 +222,8 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S
|
|||||||
|
|
||||||
private final static String VM_NAME_ISO_SUFFIX = "-ISO";
|
private final static String VM_NAME_ISO_SUFFIX = "-ISO";
|
||||||
|
|
||||||
|
private final static String VM_NAME_CONFIGDRIVE_ISO_SUFFIX = "-CONFIGDRIVE-ISO";
|
||||||
|
|
||||||
private final static String VM_FILE_ISO_SUFFIX = ".iso";
|
private final static String VM_FILE_ISO_SUFFIX = ".iso";
|
||||||
public final static int DEFAULTDOMRSSHPORT = 3922;
|
public final static int DEFAULTDOMRSSHPORT = 3922;
|
||||||
|
|
||||||
@ -1018,12 +1021,13 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S
|
|||||||
protected SR createIsoSRbyURI(final Connection conn, final URI uri, final String vmName, final boolean shared) {
|
protected SR createIsoSRbyURI(final Connection conn, final URI uri, final String vmName, final boolean shared) {
|
||||||
try {
|
try {
|
||||||
final Map<String, String> deviceConfig = new HashMap<String, String>();
|
final Map<String, String> deviceConfig = new HashMap<String, String>();
|
||||||
|
final boolean isConfigDrive = uri.toString().endsWith(ConfigDrive.CONFIGDRIVEDIR);
|
||||||
String path = uri.getPath();
|
String path = uri.getPath();
|
||||||
path = path.replace("//", "/");
|
path = path.replace("//", "/");
|
||||||
deviceConfig.put("location", uri.getHost() + ":" + path);
|
deviceConfig.put("location", uri.getHost() + ":" + path);
|
||||||
final Host host = Host.getByUuid(conn, _host.getUuid());
|
final Host host = Host.getByUuid(conn, _host.getUuid());
|
||||||
final SR sr = SR.create(conn, host, deviceConfig, new Long(0), uri.getHost() + path, "iso", "iso", "iso", shared, new HashMap<String, String>());
|
final SR sr = SR.create(conn, host, deviceConfig, new Long(0), uri.getHost() + path, "iso", "iso", "iso", shared, new HashMap<String, String>());
|
||||||
sr.setNameLabel(conn, vmName + "-ISO");
|
sr.setNameLabel(conn, vmName + (isConfigDrive ? VM_NAME_CONFIGDRIVE_ISO_SUFFIX: VM_NAME_ISO_SUFFIX));
|
||||||
sr.setNameDescription(conn, deviceConfig.get("location"));
|
sr.setNameDescription(conn, deviceConfig.get("location"));
|
||||||
|
|
||||||
sr.scan(conn);
|
sr.scan(conn);
|
||||||
@ -2646,9 +2650,10 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S
|
|||||||
return scsiid;
|
return scsiid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SR getISOSRbyVmName(final Connection conn, final String vmName) {
|
public SR getISOSRbyVmName(final Connection conn, final String vmName, boolean isConfigDrive) {
|
||||||
try {
|
try {
|
||||||
final Set<SR> srs = SR.getByNameLabel(conn, vmName + "-ISO");
|
final Set<SR> srs = SR.getByNameLabel(conn, vmName +
|
||||||
|
(isConfigDrive ? VM_NAME_CONFIGDRIVE_ISO_SUFFIX : VM_NAME_ISO_SUFFIX));
|
||||||
if (srs.size() == 0) {
|
if (srs.size() == 0) {
|
||||||
return null;
|
return null;
|
||||||
} else if (srs.size() == 1) {
|
} else if (srs.size() == 1) {
|
||||||
@ -2695,9 +2700,20 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S
|
|||||||
} catch (final URISyntaxException e) {
|
} catch (final URISyntaxException e) {
|
||||||
throw new CloudRuntimeException("isoURL is wrong: " + isoURL);
|
throw new CloudRuntimeException("isoURL is wrong: " + isoURL);
|
||||||
}
|
}
|
||||||
isoSR = getISOSRbyVmName(conn, vmName);
|
isoSR = getISOSRbyVmName(conn, vmName, false);
|
||||||
if (isoSR == null) {
|
if (isoSR == null) {
|
||||||
isoSR = createIsoSRbyURI(conn, uri, vmName, false);
|
isoSR = createIsoSRbyURI(conn, uri, vmName, false);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
String description = isoSR.getNameDescription(conn);
|
||||||
|
if (description.endsWith(ConfigDrive.CONFIGDRIVEDIR)) {
|
||||||
|
throw new CloudRuntimeException(String.format("VM %s already has %s ISO attached. Please " +
|
||||||
|
"stop-start VM to allow attaching-detaching both ISOs", vmName, ConfigDrive.CONFIGDRIVEDIR));
|
||||||
|
}
|
||||||
|
} catch (XenAPIException | XmlRpcException e) {
|
||||||
|
throw new CloudRuntimeException(String.format("Unable to retrieve name description for the already " +
|
||||||
|
"attached ISO on VM %s", vmName));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final String isoName = isoURL.substring(index + 1);
|
final String isoName = isoURL.substring(index + 1);
|
||||||
@ -5665,7 +5681,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S
|
|||||||
logger.debug("Attaching config drive iso device for the VM " + vmName + " In host " + ipAddr);
|
logger.debug("Attaching config drive iso device for the VM " + vmName + " In host " + ipAddr);
|
||||||
Set<VM> vms = VM.getByNameLabel(conn, vmName);
|
Set<VM> vms = VM.getByNameLabel(conn, vmName);
|
||||||
|
|
||||||
SR sr = getSRByNameLabel(conn, vmName + VM_NAME_ISO_SUFFIX);
|
SR sr = getSRByNameLabel(conn, vmName + VM_NAME_CONFIGDRIVE_ISO_SUFFIX);
|
||||||
//Here you will find only two vdis with the <vmname>.iso.
|
//Here you will find only two vdis with the <vmname>.iso.
|
||||||
//one is from source host and second from dest host
|
//one is from source host and second from dest host
|
||||||
Set<VDI> vdis = VDI.getByNameLabel(conn, vmName + VM_FILE_ISO_SUFFIX);
|
Set<VDI> vdis = VDI.getByNameLabel(conn, vmName + VM_FILE_ISO_SUFFIX);
|
||||||
|
|||||||
@ -142,8 +142,10 @@ public final class CitrixStopCommandWrapper extends CommandWrapper<StopCommand,
|
|||||||
networks.add(vif.getNetwork(conn));
|
networks.add(vif.getNetwork(conn));
|
||||||
}
|
}
|
||||||
vm.destroy(conn);
|
vm.destroy(conn);
|
||||||
final SR sr = citrixResourceBase.getISOSRbyVmName(conn, command.getVmName());
|
final SR sr = citrixResourceBase.getISOSRbyVmName(conn, command.getVmName(), false);
|
||||||
citrixResourceBase.removeSR(conn, sr);
|
citrixResourceBase.removeSR(conn, sr);
|
||||||
|
final SR configDriveSR = citrixResourceBase.getISOSRbyVmName(conn, command.getVmName(), true);
|
||||||
|
citrixResourceBase.removeSR(conn, configDriveSR);
|
||||||
// Disable any VLAN networks that aren't used
|
// Disable any VLAN networks that aren't used
|
||||||
// anymore
|
// anymore
|
||||||
for (final Network network : networks) {
|
for (final Network network : networks) {
|
||||||
|
|||||||
@ -36,6 +36,17 @@ write_files:
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
sysctl net.ipv4.conf.default.arp_announce=0
|
||||||
|
sysctl net.ipv4.conf.default.arp_ignore=0
|
||||||
|
sysctl net.ipv4.conf.all.arp_announce=0
|
||||||
|
sysctl net.ipv4.conf.all.arp_ignore=0
|
||||||
|
sysctl net.ipv4.conf.eth0.arp_announce=0
|
||||||
|
sysctl net.ipv4.conf.eth0.arp_ignore=0
|
||||||
|
sed -i "s/net.ipv4.conf.default.arp_announce =.*$/net.ipv4.conf.default.arp_announce = 0/" /etc/sysctl.conf
|
||||||
|
sed -i "s/net.ipv4.conf.default.arp_ignore =.*$/net.ipv4.conf.default.arp_ignore = 0/" /etc/sysctl.conf
|
||||||
|
sed -i "s/net.ipv4.conf.all.arp_announce =.*$/net.ipv4.conf.all.arp_announce = 0/" /etc/sysctl.conf
|
||||||
|
sed -i "s/net.ipv4.conf.all.arp_ignore =.*$/net.ipv4.conf.all.arp_ignore = 0/" /etc/sysctl.conf
|
||||||
|
|
||||||
ISO_MOUNT_DIR=/mnt/k8sdisk
|
ISO_MOUNT_DIR=/mnt/k8sdisk
|
||||||
BINARIES_DIR=${ISO_MOUNT_DIR}/
|
BINARIES_DIR=${ISO_MOUNT_DIR}/
|
||||||
K8S_CONFIG_SCRIPTS_COPY_DIR=/tmp/k8sconfigscripts/
|
K8S_CONFIG_SCRIPTS_COPY_DIR=/tmp/k8sconfigscripts/
|
||||||
|
|||||||
@ -56,6 +56,17 @@ write_files:
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
sysctl net.ipv4.conf.default.arp_announce=0
|
||||||
|
sysctl net.ipv4.conf.default.arp_ignore=0
|
||||||
|
sysctl net.ipv4.conf.all.arp_announce=0
|
||||||
|
sysctl net.ipv4.conf.all.arp_ignore=0
|
||||||
|
sysctl net.ipv4.conf.eth0.arp_announce=0
|
||||||
|
sysctl net.ipv4.conf.eth0.arp_ignore=0
|
||||||
|
sed -i "s/net.ipv4.conf.default.arp_announce =.*$/net.ipv4.conf.default.arp_announce = 0/" /etc/sysctl.conf
|
||||||
|
sed -i "s/net.ipv4.conf.default.arp_ignore =.*$/net.ipv4.conf.default.arp_ignore = 0/" /etc/sysctl.conf
|
||||||
|
sed -i "s/net.ipv4.conf.all.arp_announce =.*$/net.ipv4.conf.all.arp_announce = 0/" /etc/sysctl.conf
|
||||||
|
sed -i "s/net.ipv4.conf.all.arp_ignore =.*$/net.ipv4.conf.all.arp_ignore = 0/" /etc/sysctl.conf
|
||||||
|
|
||||||
ISO_MOUNT_DIR=/mnt/k8sdisk
|
ISO_MOUNT_DIR=/mnt/k8sdisk
|
||||||
BINARIES_DIR=${ISO_MOUNT_DIR}/
|
BINARIES_DIR=${ISO_MOUNT_DIR}/
|
||||||
K8S_CONFIG_SCRIPTS_COPY_DIR=/tmp/k8sconfigscripts/
|
K8S_CONFIG_SCRIPTS_COPY_DIR=/tmp/k8sconfigscripts/
|
||||||
|
|||||||
@ -36,6 +36,17 @@ write_files:
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
sysctl net.ipv4.conf.default.arp_announce=0
|
||||||
|
sysctl net.ipv4.conf.default.arp_ignore=0
|
||||||
|
sysctl net.ipv4.conf.all.arp_announce=0
|
||||||
|
sysctl net.ipv4.conf.all.arp_ignore=0
|
||||||
|
sysctl net.ipv4.conf.eth0.arp_announce=0
|
||||||
|
sysctl net.ipv4.conf.eth0.arp_ignore=0
|
||||||
|
sed -i "s/net.ipv4.conf.default.arp_announce =.*$/net.ipv4.conf.default.arp_announce = 0/" /etc/sysctl.conf
|
||||||
|
sed -i "s/net.ipv4.conf.default.arp_ignore =.*$/net.ipv4.conf.default.arp_ignore = 0/" /etc/sysctl.conf
|
||||||
|
sed -i "s/net.ipv4.conf.all.arp_announce =.*$/net.ipv4.conf.all.arp_announce = 0/" /etc/sysctl.conf
|
||||||
|
sed -i "s/net.ipv4.conf.all.arp_ignore =.*$/net.ipv4.conf.all.arp_ignore = 0/" /etc/sysctl.conf
|
||||||
|
|
||||||
ISO_MOUNT_DIR=/mnt/k8sdisk
|
ISO_MOUNT_DIR=/mnt/k8sdisk
|
||||||
BINARIES_DIR=${ISO_MOUNT_DIR}/
|
BINARIES_DIR=${ISO_MOUNT_DIR}/
|
||||||
K8S_CONFIG_SCRIPTS_COPY_DIR=/tmp/k8sconfigscripts/
|
K8S_CONFIG_SCRIPTS_COPY_DIR=/tmp/k8sconfigscripts/
|
||||||
|
|||||||
@ -412,6 +412,10 @@ public class CloudStackPrimaryDataStoreLifeCycleImpl implements PrimaryDataStore
|
|||||||
throw new CloudRuntimeException("Storage has already been added as local storage");
|
throw new CloudRuntimeException("Storage has already been added as local storage");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.warn("Unable to establish a connection between " + h + " and " + primarystore, e);
|
logger.warn("Unable to establish a connection between " + h + " and " + primarystore, e);
|
||||||
|
String reason = storageMgr.getStoragePoolMountFailureReason(e.getMessage());
|
||||||
|
if (reason != null) {
|
||||||
|
throw new CloudRuntimeException(reason);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -427,7 +431,7 @@ public class CloudStackPrimaryDataStoreLifeCycleImpl implements PrimaryDataStore
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean attachZone(DataStore dataStore, ZoneScope scope, HypervisorType hypervisorType) {
|
public boolean attachZone(DataStore dataStore, ZoneScope scope, HypervisorType hypervisorType) {
|
||||||
List<HostVO> hosts = _resourceMgr.listAllUpAndEnabledHostsInOneZoneByHypervisor(hypervisorType, scope.getScopeId());
|
List<HostVO> hosts = _resourceMgr.listAllUpHostsInOneZoneByHypervisor(hypervisorType, scope.getScopeId());
|
||||||
logger.debug("In createPool. Attaching the pool to each of the hosts.");
|
logger.debug("In createPool. Attaching the pool to each of the hosts.");
|
||||||
List<HostVO> poolHosts = new ArrayList<HostVO>();
|
List<HostVO> poolHosts = new ArrayList<HostVO>();
|
||||||
for (HostVO host : hosts) {
|
for (HostVO host : hosts) {
|
||||||
@ -439,6 +443,10 @@ public class CloudStackPrimaryDataStoreLifeCycleImpl implements PrimaryDataStore
|
|||||||
throw new CloudRuntimeException("Storage has already been added as local storage to host: " + host.getName());
|
throw new CloudRuntimeException("Storage has already been added as local storage to host: " + host.getName());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.warn("Unable to establish a connection between " + host + " and " + dataStore, e);
|
logger.warn("Unable to establish a connection between " + host + " and " + dataStore, e);
|
||||||
|
String reason = storageMgr.getStoragePoolMountFailureReason(e.getMessage());
|
||||||
|
if (reason != null) {
|
||||||
|
throw new CloudRuntimeException(reason);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (poolHosts.isEmpty()) {
|
if (poolHosts.isEmpty()) {
|
||||||
@ -459,8 +467,8 @@ public class CloudStackPrimaryDataStoreLifeCycleImpl implements PrimaryDataStore
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean cancelMaintain(DataStore store) {
|
public boolean cancelMaintain(DataStore store) {
|
||||||
dataStoreHelper.cancelMaintain(store);
|
|
||||||
storagePoolAutmation.cancelMaintain(store);
|
storagePoolAutmation.cancelMaintain(store);
|
||||||
|
dataStoreHelper.cancelMaintain(store);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -34,6 +34,7 @@ import com.cloud.storage.Storage;
|
|||||||
import com.cloud.storage.StorageManager;
|
import com.cloud.storage.StorageManager;
|
||||||
import com.cloud.storage.StorageManagerImpl;
|
import com.cloud.storage.StorageManagerImpl;
|
||||||
import com.cloud.storage.dao.StoragePoolHostDao;
|
import com.cloud.storage.dao.StoragePoolHostDao;
|
||||||
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope;
|
import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
||||||
@ -57,7 +58,6 @@ import org.mockito.Mockito;
|
|||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
import org.springframework.test.util.ReflectionTestUtils;
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@ -171,4 +171,23 @@ public class CloudStackPrimaryDataStoreLifeCycleImplTest extends TestCase {
|
|||||||
public void testAttachCluster() throws Exception {
|
public void testAttachCluster() throws Exception {
|
||||||
Assert.assertTrue(_cloudStackPrimaryDataStoreLifeCycle.attachCluster(store, new ClusterScope(1L, 1L, 1L)));
|
Assert.assertTrue(_cloudStackPrimaryDataStoreLifeCycle.attachCluster(store, new ClusterScope(1L, 1L, 1L)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAttachClusterException() throws Exception {
|
||||||
|
String exceptionString = "Mount failed due to incorrect mount options.";
|
||||||
|
String mountFailureReason = "Incorrect mount option specified.";
|
||||||
|
|
||||||
|
CloudRuntimeException exception = new CloudRuntimeException(exceptionString);
|
||||||
|
StorageManager storageManager = Mockito.mock(StorageManager.class);
|
||||||
|
Mockito.when(storageManager.connectHostToSharedPool(Mockito.anyLong(), Mockito.anyLong())).thenThrow(exception);
|
||||||
|
Mockito.when(storageManager.getStoragePoolMountFailureReason(exceptionString)).thenReturn(mountFailureReason);
|
||||||
|
ReflectionTestUtils.setField(_cloudStackPrimaryDataStoreLifeCycle, "storageMgr", storageManager);
|
||||||
|
|
||||||
|
try {
|
||||||
|
_cloudStackPrimaryDataStoreLifeCycle.attachCluster(store, new ClusterScope(1L, 1L, 1L));
|
||||||
|
Assert.fail();
|
||||||
|
} catch (Exception e) {
|
||||||
|
Assert.assertEquals(e.getMessage(), mountFailureReason);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1192,7 +1192,7 @@ public class ScaleIOPrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canCopy(DataObject srcData, DataObject destData) {
|
public boolean canCopy(DataObject srcData, DataObject destData) {
|
||||||
DataStore srcStore = destData.getDataStore();
|
DataStore srcStore = srcData.getDataStore();
|
||||||
DataStore destStore = destData.getDataStore();
|
DataStore destStore = destData.getDataStore();
|
||||||
if ((srcStore.getRole() == DataStoreRole.Primary && (srcData.getType() == DataObjectType.TEMPLATE || srcData.getType() == DataObjectType.VOLUME))
|
if ((srcStore.getRole() == DataStoreRole.Primary && (srcData.getType() == DataObjectType.TEMPLATE || srcData.getType() == DataObjectType.VOLUME))
|
||||||
&& (destStore.getRole() == DataStoreRole.Primary && destData.getType() == DataObjectType.VOLUME)) {
|
&& (destStore.getRole() == DataStoreRole.Primary && destData.getType() == DataObjectType.VOLUME)) {
|
||||||
|
|||||||
@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.cloudstack.storage.datastore.api;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class StorPoolSnapshotDef implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
private String name;
|
||||||
|
private Integer deleteAfter;
|
||||||
|
private Map<String, String> tags;
|
||||||
|
private Boolean bind;
|
||||||
|
private Integer iops;
|
||||||
|
private String rename;
|
||||||
|
private transient String volumeName;
|
||||||
|
|
||||||
|
public StorPoolSnapshotDef(String volumeName, Integer deleteAfter, Map<String, String> tags) {
|
||||||
|
super();
|
||||||
|
this.volumeName = volumeName;
|
||||||
|
this.deleteAfter = deleteAfter;
|
||||||
|
this.tags = tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StorPoolSnapshotDef(String name, Integer deleteAfter, Map<String, String> tags, Boolean bind, Integer iops,
|
||||||
|
String rename) {
|
||||||
|
super();
|
||||||
|
this.name = name;
|
||||||
|
this.deleteAfter = deleteAfter;
|
||||||
|
this.tags = tags;
|
||||||
|
this.bind = bind;
|
||||||
|
this.iops = iops;
|
||||||
|
this.rename = rename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
public Integer getDeleteAfter() {
|
||||||
|
return deleteAfter;
|
||||||
|
}
|
||||||
|
public void setDeleteAfter(Integer deleteAfter) {
|
||||||
|
this.deleteAfter = deleteAfter;
|
||||||
|
}
|
||||||
|
public Map<String, String> getTags() {
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
|
public void setTags(Map<String, String> tags) {
|
||||||
|
this.tags = tags;
|
||||||
|
}
|
||||||
|
public Boolean getBind() {
|
||||||
|
return bind;
|
||||||
|
}
|
||||||
|
public void setBind(Boolean bind) {
|
||||||
|
this.bind = bind;
|
||||||
|
}
|
||||||
|
public Integer getIops() {
|
||||||
|
return iops;
|
||||||
|
}
|
||||||
|
public void setIops(Integer iops) {
|
||||||
|
this.iops = iops;
|
||||||
|
}
|
||||||
|
public String getRename() {
|
||||||
|
return rename;
|
||||||
|
}
|
||||||
|
public void setRename(String rename) {
|
||||||
|
this.rename = rename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVolumeName() {
|
||||||
|
return volumeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVolumeName(String volumeName) {
|
||||||
|
this.volumeName = volumeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.cloudstack.storage.datastore.driver;
|
package org.apache.cloudstack.storage.datastore.driver;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -31,6 +32,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
|||||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
|
import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector;
|
import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector;
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver;
|
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
|
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo;
|
import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo;
|
||||||
@ -42,6 +44,7 @@ import org.apache.cloudstack.storage.command.CommandResult;
|
|||||||
import org.apache.cloudstack.storage.command.CopyCmdAnswer;
|
import org.apache.cloudstack.storage.command.CopyCmdAnswer;
|
||||||
import org.apache.cloudstack.storage.command.CreateObjectAnswer;
|
import org.apache.cloudstack.storage.command.CreateObjectAnswer;
|
||||||
import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
|
import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
|
||||||
|
import org.apache.cloudstack.storage.datastore.api.StorPoolSnapshotDef;
|
||||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
|
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
|
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
|
||||||
@ -86,6 +89,8 @@ import com.cloud.server.ResourceTag;
|
|||||||
import com.cloud.server.ResourceTag.ResourceObjectType;
|
import com.cloud.server.ResourceTag.ResourceObjectType;
|
||||||
import com.cloud.storage.DataStoreRole;
|
import com.cloud.storage.DataStoreRole;
|
||||||
import com.cloud.storage.ResizeVolumePayload;
|
import com.cloud.storage.ResizeVolumePayload;
|
||||||
|
import com.cloud.storage.Snapshot;
|
||||||
|
import com.cloud.storage.SnapshotVO;
|
||||||
import com.cloud.storage.Storage.StoragePoolType;
|
import com.cloud.storage.Storage.StoragePoolType;
|
||||||
import com.cloud.storage.StorageManager;
|
import com.cloud.storage.StorageManager;
|
||||||
import com.cloud.storage.StoragePool;
|
import com.cloud.storage.StoragePool;
|
||||||
@ -94,6 +99,7 @@ import com.cloud.storage.VMTemplateStoragePoolVO;
|
|||||||
import com.cloud.storage.Volume;
|
import com.cloud.storage.Volume;
|
||||||
import com.cloud.storage.VolumeDetailVO;
|
import com.cloud.storage.VolumeDetailVO;
|
||||||
import com.cloud.storage.VolumeVO;
|
import com.cloud.storage.VolumeVO;
|
||||||
|
import com.cloud.storage.dao.SnapshotDao;
|
||||||
import com.cloud.storage.dao.SnapshotDetailsDao;
|
import com.cloud.storage.dao.SnapshotDetailsDao;
|
||||||
import com.cloud.storage.dao.SnapshotDetailsVO;
|
import com.cloud.storage.dao.SnapshotDetailsVO;
|
||||||
import com.cloud.storage.dao.StoragePoolHostDao;
|
import com.cloud.storage.dao.StoragePoolHostDao;
|
||||||
@ -133,9 +139,11 @@ public class StorPoolPrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
@Inject
|
@Inject
|
||||||
private HostDao hostDao;
|
private HostDao hostDao;
|
||||||
@Inject
|
@Inject
|
||||||
private ResourceTagDao _resourceTagDao;
|
private ResourceTagDao resourceTagDao;
|
||||||
@Inject
|
@Inject
|
||||||
private SnapshotDetailsDao _snapshotDetailsDao;
|
private SnapshotDetailsDao snapshotDetailsDao;
|
||||||
|
@Inject
|
||||||
|
private SnapshotDao snapshotDao;
|
||||||
@Inject
|
@Inject
|
||||||
private SnapshotDataStoreDao snapshotDataStoreDao;
|
private SnapshotDataStoreDao snapshotDataStoreDao;
|
||||||
@Inject
|
@Inject
|
||||||
@ -402,7 +410,7 @@ public class StorPoolPrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
SpConnectionDesc conn = StorPoolUtil.getSpConnection(dataStore.getUuid(), dataStore.getId(), storagePoolDetailsDao, primaryStoreDao);
|
SpConnectionDesc conn = StorPoolUtil.getSpConnection(dataStore.getUuid(), dataStore.getId(), storagePoolDetailsDao, primaryStoreDao);
|
||||||
|
tryToSnapshotVolumeBeforeDelete(vinfo, dataStore, name, conn);
|
||||||
SpApiResponse resp = StorPoolUtil.volumeDelete(name, conn);
|
SpApiResponse resp = StorPoolUtil.volumeDelete(name, conn);
|
||||||
if (resp.getError() == null) {
|
if (resp.getError() == null) {
|
||||||
updateStoragePool(dataStore.getId(), - vinfo.getSize());
|
updateStoragePool(dataStore.getId(), - vinfo.getSize());
|
||||||
@ -432,6 +440,54 @@ public class StorPoolPrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
callback.complete(res);
|
callback.complete(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void tryToSnapshotVolumeBeforeDelete(VolumeInfo vinfo, DataStore dataStore, String name, SpConnectionDesc conn) {
|
||||||
|
Integer deleteAfter = StorPoolConfigurationManager.DeleteAfterInterval.valueIn(dataStore.getId());
|
||||||
|
if (deleteAfter != null && deleteAfter > 0 && vinfo.getPassphraseId() == null) {
|
||||||
|
createTemporarySnapshot(vinfo, name, deleteAfter, conn);
|
||||||
|
} else {
|
||||||
|
StorPoolUtil.spLog("The volume [%s] is not marked to be snapshot. Check the global setting `storpool.delete.after.interval` or the volume is encrypted [%s]", name, deleteAfter, vinfo.getPassphraseId() != null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createTemporarySnapshot(VolumeInfo vinfo, String name, Integer deleteAfter, SpConnectionDesc conn) {
|
||||||
|
Map<String, String> tags = new HashMap<>();
|
||||||
|
tags.put("cs", StorPoolUtil.DELAY_DELETE);
|
||||||
|
StorPoolSnapshotDef snapshot = new StorPoolSnapshotDef(name, deleteAfter, tags);
|
||||||
|
StorPoolUtil.spLog("Creating backup snapshot before delete the volume [%s]", vinfo.getName());
|
||||||
|
SpApiResponse snapshotResponse = StorPoolUtil.volumeSnapshot(snapshot, conn);
|
||||||
|
if (snapshotResponse.getError() == null) {
|
||||||
|
String snapshotName = StorPoolUtil.getSnapshotNameFromResponse(snapshotResponse, false, StorPoolUtil.GLOBAL_ID);
|
||||||
|
String snapshotPath = StorPoolUtil.devPath(snapshotName);
|
||||||
|
SnapshotVO snapshotVo = createSnapshotVo(vinfo, snapshotName);
|
||||||
|
createSnapshotOnPrimaryVo(vinfo, snapshotVo, snapshotPath);
|
||||||
|
SnapshotDetailsVO snapshotDetails = new SnapshotDetailsVO(snapshotVo.getId(), StorPoolUtil.SP_DELAY_DELETE, "~" + snapshotName, true);
|
||||||
|
snapshotDetailsDao.persist(snapshotDetails);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createSnapshotOnPrimaryVo(VolumeInfo vinfo, SnapshotVO snapshotVo, String snapshotPath) {
|
||||||
|
SnapshotDataStoreVO snapshotOnPrimaryVo = new SnapshotDataStoreVO();
|
||||||
|
snapshotOnPrimaryVo.setSnapshotId(snapshotVo.getId());
|
||||||
|
snapshotOnPrimaryVo.setDataStoreId(vinfo.getDataCenterId());
|
||||||
|
snapshotOnPrimaryVo.setRole(vinfo.getDataStore().getRole());
|
||||||
|
snapshotOnPrimaryVo.setVolumeId(vinfo.getId());
|
||||||
|
snapshotOnPrimaryVo.setSize(vinfo.getSize());
|
||||||
|
snapshotOnPrimaryVo.setPhysicalSize(vinfo.getSize());
|
||||||
|
snapshotOnPrimaryVo.setInstallPath(snapshotPath);
|
||||||
|
snapshotOnPrimaryVo.setState(ObjectInDataStoreStateMachine.State.Ready);
|
||||||
|
snapshotDataStoreDao.persist(snapshotOnPrimaryVo);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SnapshotVO createSnapshotVo(VolumeInfo vinfo, String snapshotName) {
|
||||||
|
SnapshotVO snapshotVo = new SnapshotVO(vinfo.getDataCenterId(), vinfo.getAccountId(), vinfo.getDomainId(), vinfo.getId(),
|
||||||
|
vinfo.getDiskOfferingId(), snapshotName,
|
||||||
|
(short)Snapshot.Type.RECURRING.ordinal(), Snapshot.Type.RECURRING.name(),
|
||||||
|
vinfo.getSize(), vinfo.getMinIops(), vinfo.getMaxIops(), vinfo.getHypervisorType(), Snapshot.LocationType.PRIMARY);
|
||||||
|
snapshotVo.setState(com.cloud.storage.Snapshot.State.BackedUp);
|
||||||
|
snapshotVo = snapshotDao.persist(snapshotVo);
|
||||||
|
return snapshotVo;
|
||||||
|
}
|
||||||
|
|
||||||
private void logDataObject(final String pref, DataObject data) {
|
private void logDataObject(final String pref, DataObject data) {
|
||||||
final DataStore dstore = data.getDataStore();
|
final DataStore dstore = data.getDataStore();
|
||||||
String name = null;
|
String name = null;
|
||||||
@ -474,7 +530,7 @@ public class StorPoolPrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
try {
|
try {
|
||||||
if (srcType == DataObjectType.SNAPSHOT && dstType == DataObjectType.VOLUME) {
|
if (srcType == DataObjectType.SNAPSHOT && dstType == DataObjectType.VOLUME) {
|
||||||
SnapshotInfo sinfo = (SnapshotInfo)srcData;
|
SnapshotInfo sinfo = (SnapshotInfo)srcData;
|
||||||
final String snapshotName = StorPoolHelper.getSnapshotName(srcData.getId(), srcData.getUuid(), snapshotDataStoreDao, _snapshotDetailsDao);
|
final String snapshotName = StorPoolHelper.getSnapshotName(srcData.getId(), srcData.getUuid(), snapshotDataStoreDao, snapshotDetailsDao);
|
||||||
|
|
||||||
VolumeInfo vinfo = (VolumeInfo)dstData;
|
VolumeInfo vinfo = (VolumeInfo)dstData;
|
||||||
final String volumeName = vinfo.getUuid();
|
final String volumeName = vinfo.getUuid();
|
||||||
@ -492,9 +548,12 @@ public class StorPoolPrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
StorPoolUtil.spLog("Created volume=%s with uuid=%s from snapshot=%s with uuid=%s", StorPoolUtil.getNameFromResponse(resp, false), to.getUuid(), snapshotName, sinfo.getUuid());
|
StorPoolUtil.spLog("Created volume=%s with uuid=%s from snapshot=%s with uuid=%s", StorPoolUtil.getNameFromResponse(resp, false), to.getUuid(), snapshotName, sinfo.getUuid());
|
||||||
} else if (resp.getError().getName().equals("objectDoesNotExist")) {
|
} else if (resp.getError().getName().equals("objectDoesNotExist")) {
|
||||||
//check if snapshot is on secondary storage
|
//check if snapshot is on secondary storage
|
||||||
StorPoolUtil.spLog("Snapshot %s does not exists on StorPool, will try to create a volume from a snopshot on secondary storage", snapshotName);
|
StorPoolUtil.spLog("Snapshot %s does not exists on StorPool, will try to create a volume from a snapshot on secondary storage", snapshotName);
|
||||||
SnapshotDataStoreVO snap = getSnapshotImageStoreRef(sinfo.getId(), vinfo.getDataCenterId());
|
SnapshotDataStoreVO snap = getSnapshotImageStoreRef(sinfo.getId(), vinfo.getDataCenterId());
|
||||||
if (snap != null && StorPoolStorageAdaptor.getVolumeNameFromPath(snap.getInstallPath(), false) == null) {
|
SnapshotDetailsVO snapshotDetail = snapshotDetailsDao.findDetail(sinfo.getId(), StorPoolUtil.SP_DELAY_DELETE);
|
||||||
|
if (snapshotDetail != null) {
|
||||||
|
err = String.format("Could not create volume from snapshot due to: %s", resp.getError());
|
||||||
|
} else if (snap != null && StorPoolStorageAdaptor.getVolumeNameFromPath(snap.getInstallPath(), false) == null) {
|
||||||
resp = StorPoolUtil.volumeCreate(srcData.getUuid(), null, size, null, "no", "snapshot", sinfo.getBaseVolume().getMaxIops(), conn);
|
resp = StorPoolUtil.volumeCreate(srcData.getUuid(), null, size, null, "no", "snapshot", sinfo.getBaseVolume().getMaxIops(), conn);
|
||||||
if (resp.getError() == null) {
|
if (resp.getError() == null) {
|
||||||
VolumeObjectTO dstTO = (VolumeObjectTO) dstData.getTO();
|
VolumeObjectTO dstTO = (VolumeObjectTO) dstData.getTO();
|
||||||
@ -515,11 +574,11 @@ public class StorPoolPrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
err = String.format("Could not freeze Storpool volume %s. Error: %s", srcData.getUuid(), resp2.getError());
|
err = String.format("Could not freeze Storpool volume %s. Error: %s", srcData.getUuid(), resp2.getError());
|
||||||
} else {
|
} else {
|
||||||
String name = StorPoolUtil.getNameFromResponse(resp, false);
|
String name = StorPoolUtil.getNameFromResponse(resp, false);
|
||||||
SnapshotDetailsVO snapshotDetails = _snapshotDetailsDao.findDetail(sinfo.getId(), sinfo.getUuid());
|
SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(sinfo.getId(), sinfo.getUuid());
|
||||||
if (snapshotDetails != null) {
|
if (snapshotDetails != null) {
|
||||||
StorPoolHelper.updateSnapshotDetailsValue(snapshotDetails.getId(), StorPoolUtil.devPath(name), "snapshot");
|
StorPoolHelper.updateSnapshotDetailsValue(snapshotDetails.getId(), StorPoolUtil.devPath(name), "snapshot");
|
||||||
}else {
|
}else {
|
||||||
StorPoolHelper.addSnapshotDetails(sinfo.getId(), sinfo.getUuid(), StorPoolUtil.devPath(name), _snapshotDetailsDao);
|
StorPoolHelper.addSnapshotDetails(sinfo.getId(), sinfo.getUuid(), StorPoolUtil.devPath(name), snapshotDetailsDao);
|
||||||
}
|
}
|
||||||
resp = StorPoolUtil.volumeCreate(volumeName, StorPoolUtil.getNameFromResponse(resp, true), size, null, null, "volume", sinfo.getBaseVolume().getMaxIops(), conn);
|
resp = StorPoolUtil.volumeCreate(volumeName, StorPoolUtil.getNameFromResponse(resp, true), size, null, null, "volume", sinfo.getBaseVolume().getMaxIops(), conn);
|
||||||
if (resp.getError() == null) {
|
if (resp.getError() == null) {
|
||||||
@ -549,8 +608,10 @@ public class StorPoolPrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
err = String.format("Could not create Storpool volume %s from snapshot %s. Error: %s", volumeName, snapshotName, resp.getError());
|
err = String.format("Could not create Storpool volume %s from snapshot %s. Error: %s", volumeName, snapshotName, resp.getError());
|
||||||
}
|
}
|
||||||
} else if (srcType == DataObjectType.SNAPSHOT && dstType == DataObjectType.SNAPSHOT) {
|
} else if (srcType == DataObjectType.SNAPSHOT && dstType == DataObjectType.SNAPSHOT) {
|
||||||
|
SnapshotInfo sinfo = (SnapshotInfo)srcData;
|
||||||
|
SnapshotDetailsVO snapshotDetail = snapshotDetailsDao.findDetail(sinfo.getId(), StorPoolUtil.SP_DELAY_DELETE);
|
||||||
// bypass secondary storage
|
// bypass secondary storage
|
||||||
if (StorPoolConfigurationManager.BypassSecondaryStorage.value()) {
|
if (StorPoolConfigurationManager.BypassSecondaryStorage.value() || snapshotDetail != null) {
|
||||||
SnapshotObjectTO snapshot = (SnapshotObjectTO) srcData.getTO();
|
SnapshotObjectTO snapshot = (SnapshotObjectTO) srcData.getTO();
|
||||||
answer = new CopyCmdAnswer(snapshot);
|
answer = new CopyCmdAnswer(snapshot);
|
||||||
} else {
|
} else {
|
||||||
@ -987,9 +1048,9 @@ public class StorPoolPrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
SnapshotObjectTO snapTo = (SnapshotObjectTO)snapshot.getTO();
|
SnapshotObjectTO snapTo = (SnapshotObjectTO)snapshot.getTO();
|
||||||
snapTo.setPath(StorPoolUtil.devPath(name.split("~")[1]));
|
snapTo.setPath(StorPoolUtil.devPath(name.split("~")[1]));
|
||||||
answer = new CreateObjectAnswer(snapTo);
|
answer = new CreateObjectAnswer(snapTo);
|
||||||
StorPoolHelper.addSnapshotDetails(snapshot.getId(), snapshot.getUuid(), snapTo.getPath(), _snapshotDetailsDao);
|
StorPoolHelper.addSnapshotDetails(snapshot.getId(), snapshot.getUuid(), snapTo.getPath(), snapshotDetailsDao);
|
||||||
//add primary storage of snapshot
|
//add primary storage of snapshot
|
||||||
StorPoolHelper.addSnapshotDetails(snapshot.getId(), StorPoolUtil.SP_STORAGE_POOL_ID, String.valueOf(snapshot.getDataStore().getId()), _snapshotDetailsDao);
|
StorPoolHelper.addSnapshotDetails(snapshot.getId(), StorPoolUtil.SP_STORAGE_POOL_ID, String.valueOf(snapshot.getDataStore().getId()), snapshotDetailsDao);
|
||||||
StorPoolUtil.spLog("StorpoolPrimaryDataStoreDriverImpl.takeSnapshot: snapshot: name=%s, uuid=%s, volume: name=%s, uuid=%s", name, snapshot.getUuid(), volumeName, vinfo.getUuid());
|
StorPoolUtil.spLog("StorpoolPrimaryDataStoreDriverImpl.takeSnapshot: snapshot: name=%s, uuid=%s, volume: name=%s, uuid=%s", name, snapshot.getUuid(), volumeName, vinfo.getUuid());
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -1004,7 +1065,7 @@ public class StorPoolPrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
@Override
|
@Override
|
||||||
public void revertSnapshot(final SnapshotInfo snapshot, final SnapshotInfo snapshotOnPrimaryStore, final AsyncCompletionCallback<CommandResult> callback) {
|
public void revertSnapshot(final SnapshotInfo snapshot, final SnapshotInfo snapshotOnPrimaryStore, final AsyncCompletionCallback<CommandResult> callback) {
|
||||||
final VolumeInfo vinfo = snapshot.getBaseVolume();
|
final VolumeInfo vinfo = snapshot.getBaseVolume();
|
||||||
final String snapshotName = StorPoolHelper.getSnapshotName(snapshot.getId(), snapshot.getUuid(), snapshotDataStoreDao, _snapshotDetailsDao);
|
final String snapshotName = StorPoolHelper.getSnapshotName(snapshot.getId(), snapshot.getUuid(), snapshotDataStoreDao, snapshotDetailsDao);
|
||||||
final String volumeName = StorPoolStorageAdaptor.getVolumeNameFromPath(vinfo.getPath(), true);
|
final String volumeName = StorPoolStorageAdaptor.getVolumeNameFromPath(vinfo.getPath(), true);
|
||||||
StorPoolUtil.spLog("StorpoolPrimaryDataStoreDriverImpl.revertSnapshot: snapshot: name=%s, uuid=%s, volume: name=%s, uuid=%s", snapshotName, snapshot.getUuid(), volumeName, vinfo.getUuid());
|
StorPoolUtil.spLog("StorpoolPrimaryDataStoreDriverImpl.revertSnapshot: snapshot: name=%s, uuid=%s, volume: name=%s, uuid=%s", snapshotName, snapshot.getUuid(), volumeName, vinfo.getUuid());
|
||||||
String err = null;
|
String err = null;
|
||||||
@ -1059,7 +1120,7 @@ public class StorPoolPrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String getVcPolicyTag(Long vmId) {
|
private String getVcPolicyTag(Long vmId) {
|
||||||
ResourceTag resourceTag = vmId != null ? _resourceTagDao.findByKey(vmId, ResourceObjectType.UserVm, StorPoolUtil.SP_VC_POLICY) : null;
|
ResourceTag resourceTag = vmId != null ? resourceTagDao.findByKey(vmId, ResourceObjectType.UserVm, StorPoolUtil.SP_VC_POLICY) : null;
|
||||||
return resourceTag != null ? resourceTag.getValue() : "";
|
return resourceTag != null ? resourceTag.getValue() : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -28,18 +28,28 @@ import java.util.concurrent.TimeUnit;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.State;
|
||||||
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||||
|
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
|
||||||
|
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
|
||||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
|
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||||
import org.apache.cloudstack.storage.datastore.util.StorPoolUtil;
|
import org.apache.cloudstack.storage.datastore.util.StorPoolUtil;
|
||||||
import org.apache.cloudstack.storage.snapshot.StorPoolConfigurationManager;
|
import org.apache.cloudstack.storage.snapshot.StorPoolConfigurationManager;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import com.cloud.storage.DataStoreRole;
|
||||||
|
import com.cloud.storage.SnapshotVO;
|
||||||
|
import com.cloud.storage.dao.SnapshotDao;
|
||||||
|
import com.cloud.storage.dao.SnapshotDetailsDao;
|
||||||
|
import com.cloud.storage.dao.SnapshotDetailsVO;
|
||||||
import com.cloud.utils.NumbersUtil;
|
import com.cloud.utils.NumbersUtil;
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
import com.cloud.utils.component.ManagerBase;
|
import com.cloud.utils.component.ManagerBase;
|
||||||
import com.cloud.utils.concurrency.NamedThreadFactory;
|
import com.cloud.utils.concurrency.NamedThreadFactory;
|
||||||
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
import com.google.gson.JsonArray;
|
import com.google.gson.JsonArray;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
@ -52,6 +62,12 @@ public class StorPoolStatsCollector extends ManagerBase {
|
|||||||
private StoragePoolDetailsDao storagePoolDetailsDao;
|
private StoragePoolDetailsDao storagePoolDetailsDao;
|
||||||
@Inject
|
@Inject
|
||||||
private ConfigurationDao configurationDao;
|
private ConfigurationDao configurationDao;
|
||||||
|
@Inject
|
||||||
|
private SnapshotDao snapshotDao;
|
||||||
|
@Inject
|
||||||
|
private SnapshotDataStoreDao snapshotDataStoreDao;
|
||||||
|
@Inject
|
||||||
|
private SnapshotDetailsDao snapshotDetailsDao;
|
||||||
|
|
||||||
private ScheduledExecutorService executor;
|
private ScheduledExecutorService executor;
|
||||||
|
|
||||||
@ -67,7 +83,7 @@ public class StorPoolStatsCollector extends ManagerBase {
|
|||||||
public boolean start() {
|
public boolean start() {
|
||||||
List<StoragePoolVO> spPools = storagePoolDao.findPoolsByProvider(StorPoolUtil.SP_PROVIDER_NAME);
|
List<StoragePoolVO> spPools = storagePoolDao.findPoolsByProvider(StorPoolUtil.SP_PROVIDER_NAME);
|
||||||
if (CollectionUtils.isNotEmpty(spPools)) {
|
if (CollectionUtils.isNotEmpty(spPools)) {
|
||||||
executor = Executors.newScheduledThreadPool(2,new NamedThreadFactory("StorPoolStatsCollector"));
|
executor = Executors.newScheduledThreadPool(3, new NamedThreadFactory("StorPoolStatsCollector"));
|
||||||
long storageStatsInterval = NumbersUtil.parseLong(configurationDao.getValue("storage.stats.interval"), 60000L);
|
long storageStatsInterval = NumbersUtil.parseLong(configurationDao.getValue("storage.stats.interval"), 60000L);
|
||||||
long volumeStatsInterval = NumbersUtil.parseLong(configurationDao.getValue("volume.stats.interval"), 60000L);
|
long volumeStatsInterval = NumbersUtil.parseLong(configurationDao.getValue("volume.stats.interval"), 60000L);
|
||||||
|
|
||||||
@ -77,6 +93,13 @@ public class StorPoolStatsCollector extends ManagerBase {
|
|||||||
if (StorPoolConfigurationManager.StorageStatsInterval.value() > 0 && storageStatsInterval > 0) {
|
if (StorPoolConfigurationManager.StorageStatsInterval.value() > 0 && storageStatsInterval > 0) {
|
||||||
executor.scheduleAtFixedRate(new StorPoolStorageStatsMonitorTask(), 120, StorPoolConfigurationManager.StorageStatsInterval.value(), TimeUnit.SECONDS);
|
executor.scheduleAtFixedRate(new StorPoolStorageStatsMonitorTask(), 120, StorPoolConfigurationManager.StorageStatsInterval.value(), TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
|
for (StoragePoolVO pool: spPools) {
|
||||||
|
Integer deleteAfter = StorPoolConfigurationManager.DeleteAfterInterval.valueIn(pool.getId());
|
||||||
|
if (deleteAfter != null && deleteAfter > 0) {
|
||||||
|
executor.scheduleAtFixedRate(new StorPoolSnapshotsWithDelayDelete(), 120, StorPoolConfigurationManager.ListSnapshotsWithDeleteAfterInterval.value(), TimeUnit.SECONDS);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -182,4 +205,90 @@ public class StorPoolStatsCollector extends ManagerBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class StorPoolSnapshotsWithDelayDelete implements Runnable {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
List<StoragePoolVO> spPools = storagePoolDao.findPoolsByProvider(StorPoolUtil.SP_PROVIDER_NAME);
|
||||||
|
if (CollectionUtils.isNotEmpty(spPools)) {
|
||||||
|
Map<Long, StoragePoolVO> onePoolForZone = new HashMap<>();
|
||||||
|
for (StoragePoolVO storagePoolVO : spPools) {
|
||||||
|
onePoolForZone.put(storagePoolVO.getDataCenterId(), storagePoolVO);
|
||||||
|
}
|
||||||
|
for (StoragePoolVO storagePool : onePoolForZone.values()) {
|
||||||
|
List<SnapshotDetailsVO> snapshotsDetails = snapshotDetailsDao.findDetailsByZoneAndKey(storagePool.getDataCenterId(), StorPoolUtil.SP_DELAY_DELETE);
|
||||||
|
if (CollectionUtils.isEmpty(snapshotsDetails)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Map<String, String> snapshotsWithDelayDelete = new HashMap<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
logger.debug(String.format("Collecting snapshots marked to be deleted for zone [%s]", storagePool.getDataCenterId()));
|
||||||
|
JsonArray arr = StorPoolUtil.snapshotsListAllClusters(StorPoolUtil.getSpConnection(storagePool.getUuid(),
|
||||||
|
storagePool.getId(), storagePoolDetailsDao, storagePoolDao));
|
||||||
|
snapshotsWithDelayDelete.putAll(getSnapshotsMarkedForDeletion(arr));
|
||||||
|
logger.debug(String.format("Found snapshot details [%s] and snapshots on StorPool with delay delete flag [%s]", snapshotsDetails, snapshotsWithDelayDelete));
|
||||||
|
syncSnapshots(snapshotsDetails, snapshotsWithDelayDelete);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.debug("Could not fetch the snapshots with delay delete flag " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void syncSnapshots(List<SnapshotDetailsVO> snapshotsDetails,
|
||||||
|
Map<String, String> snapshotsWithDelayDelete) {
|
||||||
|
for (SnapshotDetailsVO snapshotDetailsVO : snapshotsDetails) {
|
||||||
|
if (!snapshotsWithDelayDelete.containsKey(snapshotDetailsVO.getValue())) {
|
||||||
|
StorPoolUtil.spLog("The snapshot [%s] with delayDelete flag is no longer on StorPool. Removing it from CloudStack", snapshotDetailsVO.getValue());
|
||||||
|
SnapshotDataStoreVO ss = snapshotDataStoreDao
|
||||||
|
.findBySourceSnapshot(snapshotDetailsVO.getResourceId(), DataStoreRole.Primary);
|
||||||
|
if (ss != null) {
|
||||||
|
ss.setState(State.Destroyed);
|
||||||
|
snapshotDataStoreDao.update(ss.getId(), ss);
|
||||||
|
}
|
||||||
|
SnapshotVO snap = snapshotDao.findById(snapshotDetailsVO.getResourceId());
|
||||||
|
if (snap != null) {
|
||||||
|
snap.setState(com.cloud.storage.Snapshot.State.Destroyed);
|
||||||
|
snapshotDao.update(snap.getId(), snap);
|
||||||
|
}
|
||||||
|
snapshotDetailsDao.remove(snapshotDetailsVO.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, String> getSnapshotsMarkedForDeletion(JsonArray arr) {
|
||||||
|
for (JsonElement jsonElement : arr) {
|
||||||
|
JsonObject error = jsonElement.getAsJsonObject().getAsJsonObject("error");
|
||||||
|
if (error != null) {
|
||||||
|
throw new CloudRuntimeException(String.format("Could not collect the snapshots marked for deletion from all storage nodes due to: [%s]", error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Map<String, String> snapshotsWithDelayDelete = new HashMap<>();
|
||||||
|
for (JsonElement jsonElement : arr) {
|
||||||
|
JsonObject response = jsonElement.getAsJsonObject().getAsJsonObject("response");
|
||||||
|
if (response == null) {
|
||||||
|
return snapshotsWithDelayDelete;
|
||||||
|
}
|
||||||
|
collectSnapshots(snapshotsWithDelayDelete, response);
|
||||||
|
}
|
||||||
|
logger.debug("Found snapshots on StorPool" + snapshotsWithDelayDelete);
|
||||||
|
return snapshotsWithDelayDelete;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void collectSnapshots(Map<String, String> snapshotsWithDelayDelete, JsonObject response) {
|
||||||
|
JsonArray snapshots = response.getAsJsonObject().getAsJsonArray("data");
|
||||||
|
for (JsonElement snapshot : snapshots) {
|
||||||
|
String name = snapshot.getAsJsonObject().get("name").getAsString();
|
||||||
|
JsonObject tags = snapshot.getAsJsonObject().get("tags").getAsJsonObject();
|
||||||
|
if (!StringUtils.startsWith(name, "*") && StringUtils.containsNone(name, "@") && tags != null && !tags.entrySet().isEmpty()) {
|
||||||
|
String tag = tags.getAsJsonPrimitive("cs").getAsString();
|
||||||
|
if (tag != null && tag.equals(StorPoolUtil.DELAY_DELETE)) {
|
||||||
|
snapshotsWithDelayDelete.put(name, tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,6 +28,8 @@ import com.google.gson.JsonElement;
|
|||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
import com.google.gson.JsonPrimitive;
|
import com.google.gson.JsonPrimitive;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.storage.datastore.api.StorPoolSnapshotDef;
|
||||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO;
|
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO;
|
||||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
|
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
|
||||||
@ -125,6 +127,15 @@ public class StorPoolUtil {
|
|||||||
|
|
||||||
public static final String SP_VOLUME_ON_CLUSTER = "SP_VOLUME_ON_CLUSTER";
|
public static final String SP_VOLUME_ON_CLUSTER = "SP_VOLUME_ON_CLUSTER";
|
||||||
|
|
||||||
|
private static final String DATA = "data";
|
||||||
|
|
||||||
|
private static final String CLUSTERS = "clusters";
|
||||||
|
|
||||||
|
public static final String SP_DELAY_DELETE = "SP_DELAY_DELETE";
|
||||||
|
|
||||||
|
public static final String DELAY_DELETE = "delayDelete";
|
||||||
|
|
||||||
|
|
||||||
public static enum StorpoolRights {
|
public static enum StorpoolRights {
|
||||||
RO("ro"), RW("rw"), DETACH("detach");
|
RO("ro"), RW("rw"), DETACH("detach");
|
||||||
|
|
||||||
@ -417,27 +428,31 @@ public class StorPoolUtil {
|
|||||||
public static JsonArray snapshotsList(SpConnectionDesc conn) {
|
public static JsonArray snapshotsList(SpConnectionDesc conn) {
|
||||||
SpApiResponse resp = GET("MultiCluster/SnapshotsList", conn);
|
SpApiResponse resp = GET("MultiCluster/SnapshotsList", conn);
|
||||||
JsonObject obj = resp.fullJson.getAsJsonObject();
|
JsonObject obj = resp.fullJson.getAsJsonObject();
|
||||||
JsonArray data = obj.getAsJsonArray("data");
|
return obj.getAsJsonArray(DATA);
|
||||||
return data;
|
}
|
||||||
|
|
||||||
|
public static JsonArray snapshotsListAllClusters(SpConnectionDesc conn) {
|
||||||
|
SpApiResponse resp = GET("MultiCluster/AllClusters/SnapshotsList", conn);
|
||||||
|
JsonObject obj = resp.fullJson.getAsJsonObject();
|
||||||
|
return obj.getAsJsonObject(DATA).getAsJsonArray(CLUSTERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JsonArray volumesList(SpConnectionDesc conn) {
|
public static JsonArray volumesList(SpConnectionDesc conn) {
|
||||||
SpApiResponse resp = GET("MultiCluster/VolumesList", conn);
|
SpApiResponse resp = GET("MultiCluster/VolumesList", conn);
|
||||||
JsonObject obj = resp.fullJson.getAsJsonObject();
|
JsonObject obj = resp.fullJson.getAsJsonObject();
|
||||||
JsonArray data = obj.getAsJsonArray("data");
|
return obj.getAsJsonArray(DATA);
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JsonArray volumesSpace(SpConnectionDesc conn) {
|
public static JsonArray volumesSpace(SpConnectionDesc conn) {
|
||||||
SpApiResponse resp = GET("MultiCluster/AllClusters/VolumesSpace", conn);
|
SpApiResponse resp = GET("MultiCluster/AllClusters/VolumesSpace", conn);
|
||||||
JsonObject obj = resp.fullJson.getAsJsonObject();
|
JsonObject obj = resp.fullJson.getAsJsonObject();
|
||||||
return obj.getAsJsonObject("data").getAsJsonArray("clusters");
|
return obj.getAsJsonObject(DATA).getAsJsonArray(CLUSTERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JsonArray templatesStats(SpConnectionDesc conn) {
|
public static JsonArray templatesStats(SpConnectionDesc conn) {
|
||||||
SpApiResponse resp = GET("MultiCluster/AllClusters/VolumeTemplatesStatus", conn);
|
SpApiResponse resp = GET("MultiCluster/AllClusters/VolumeTemplatesStatus", conn);
|
||||||
JsonObject obj = resp.fullJson.getAsJsonObject();
|
JsonObject obj = resp.fullJson.getAsJsonObject();
|
||||||
return obj.getAsJsonObject("data").getAsJsonArray("clusters");
|
return obj.getAsJsonObject(DATA).getAsJsonArray(CLUSTERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean objectExists(SpApiError err) {
|
private static boolean objectExists(SpApiError err) {
|
||||||
@ -454,7 +469,7 @@ public class StorPoolUtil {
|
|||||||
if (resp.getError() != null && !objectExists(resp.getError())) {
|
if (resp.getError() != null && !objectExists(resp.getError())) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
JsonObject data = obj.getAsJsonArray("data").get(0).getAsJsonObject();
|
JsonObject data = obj.getAsJsonArray(DATA).get(0).getAsJsonObject();
|
||||||
return data.getAsJsonPrimitive("size").getAsLong();
|
return data.getAsJsonPrimitive("size").getAsLong();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -462,7 +477,7 @@ public class StorPoolUtil {
|
|||||||
SpApiResponse resp = GET("MultiCluster/Snapshot/" + name, conn);
|
SpApiResponse resp = GET("MultiCluster/Snapshot/" + name, conn);
|
||||||
JsonObject obj = resp.fullJson.getAsJsonObject();
|
JsonObject obj = resp.fullJson.getAsJsonObject();
|
||||||
|
|
||||||
JsonObject data = obj.getAsJsonArray("data").get(0).getAsJsonObject();
|
JsonObject data = obj.getAsJsonArray(DATA).get(0).getAsJsonObject();
|
||||||
JsonPrimitive clusterId = data.getAsJsonPrimitive("clusterId");
|
JsonPrimitive clusterId = data.getAsJsonPrimitive("clusterId");
|
||||||
return clusterId != null ? clusterId.getAsString() : null;
|
return clusterId != null ? clusterId.getAsString() : null;
|
||||||
}
|
}
|
||||||
@ -471,7 +486,7 @@ public class StorPoolUtil {
|
|||||||
SpApiResponse resp = GET("MultiCluster/Volume/" + name, conn);
|
SpApiResponse resp = GET("MultiCluster/Volume/" + name, conn);
|
||||||
JsonObject obj = resp.fullJson.getAsJsonObject();
|
JsonObject obj = resp.fullJson.getAsJsonObject();
|
||||||
|
|
||||||
JsonObject data = obj.getAsJsonArray("data").get(0).getAsJsonObject();
|
JsonObject data = obj.getAsJsonArray(DATA).get(0).getAsJsonObject();
|
||||||
JsonPrimitive clusterId = data.getAsJsonPrimitive("clusterId");
|
JsonPrimitive clusterId = data.getAsJsonPrimitive("clusterId");
|
||||||
return clusterId != null ? clusterId.getAsString() : null;
|
return clusterId != null ? clusterId.getAsString() : null;
|
||||||
}
|
}
|
||||||
@ -580,6 +595,10 @@ public class StorPoolUtil {
|
|||||||
return POST("MultiCluster/VolumeSnapshot/" + volumeName, json, conn);
|
return POST("MultiCluster/VolumeSnapshot/" + volumeName, json, conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static SpApiResponse volumeSnapshot(StorPoolSnapshotDef snapshot, SpConnectionDesc conn) {
|
||||||
|
return POST("MultiCluster/VolumeSnapshot/" + snapshot.getVolumeName(), snapshot, conn);
|
||||||
|
}
|
||||||
|
|
||||||
public static SpApiResponse volumesGroupSnapshot(final List<VolumeObjectTO> volumeTOs, final String vmUuid,
|
public static SpApiResponse volumesGroupSnapshot(final List<VolumeObjectTO> volumeTOs, final String vmUuid,
|
||||||
final String snapshotName, String csTag, SpConnectionDesc conn) {
|
final String snapshotName, String csTag, SpConnectionDesc conn) {
|
||||||
Map<String, Object> json = new LinkedHashMap<>();
|
Map<String, Object> json = new LinkedHashMap<>();
|
||||||
@ -639,7 +658,7 @@ public class StorPoolUtil {
|
|||||||
|
|
||||||
public static String getSnapshotNameFromResponse(SpApiResponse resp, boolean tildeNeeded, String globalIdOrRemote) {
|
public static String getSnapshotNameFromResponse(SpApiResponse resp, boolean tildeNeeded, String globalIdOrRemote) {
|
||||||
JsonObject obj = resp.fullJson.getAsJsonObject();
|
JsonObject obj = resp.fullJson.getAsJsonObject();
|
||||||
JsonPrimitive data = obj.getAsJsonObject("data").getAsJsonPrimitive(globalIdOrRemote);
|
JsonPrimitive data = obj.getAsJsonObject(DATA).getAsJsonPrimitive(globalIdOrRemote);
|
||||||
String name = data != null ? data.getAsString() : null;
|
String name = data != null ? data.getAsString() : null;
|
||||||
name = name != null ? !tildeNeeded ? name : "~" + name : name;
|
name = name != null ? !tildeNeeded ? name : "~" + name : name;
|
||||||
return name;
|
return name;
|
||||||
@ -647,7 +666,7 @@ public class StorPoolUtil {
|
|||||||
|
|
||||||
public static String getNameFromResponse(SpApiResponse resp, boolean tildeNeeded) {
|
public static String getNameFromResponse(SpApiResponse resp, boolean tildeNeeded) {
|
||||||
JsonObject obj = resp.fullJson.getAsJsonObject();
|
JsonObject obj = resp.fullJson.getAsJsonObject();
|
||||||
JsonPrimitive data = obj.getAsJsonObject("data").getAsJsonPrimitive("name");
|
JsonPrimitive data = obj.getAsJsonObject(DATA).getAsJsonPrimitive("name");
|
||||||
String name = data != null ? data.getAsString() : null;
|
String name = data != null ? data.getAsString() : null;
|
||||||
name = name != null ? name.startsWith("~") && !tildeNeeded ? name.split("~")[1] : name : name;
|
name = name != null ? name.startsWith("~") && !tildeNeeded ? name.split("~")[1] : name : name;
|
||||||
return name;
|
return name;
|
||||||
|
|||||||
@ -149,18 +149,21 @@ public class StorPoolDataMotionStrategy implements DataMotionStrategy {
|
|||||||
public StrategyPriority canHandle(DataObject srcData, DataObject destData) {
|
public StrategyPriority canHandle(DataObject srcData, DataObject destData) {
|
||||||
DataObjectType srcType = srcData.getType();
|
DataObjectType srcType = srcData.getType();
|
||||||
DataObjectType dstType = destData.getType();
|
DataObjectType dstType = destData.getType();
|
||||||
if (srcType == DataObjectType.SNAPSHOT && dstType == DataObjectType.TEMPLATE
|
if (srcType == DataObjectType.SNAPSHOT && dstType == DataObjectType.TEMPLATE) {
|
||||||
&& StorPoolConfigurationManager.BypassSecondaryStorage.value()) {
|
|
||||||
SnapshotInfo sinfo = (SnapshotInfo) srcData;
|
SnapshotInfo sinfo = (SnapshotInfo) srcData;
|
||||||
VolumeInfo volume = sinfo.getBaseVolume();
|
VolumeInfo volume = sinfo.getBaseVolume();
|
||||||
StoragePoolVO storagePool = _storagePool.findById(volume.getPoolId());
|
StoragePoolVO storagePool = _storagePool.findById(volume.getPoolId());
|
||||||
if (!storagePool.getStorageProviderName().equals(StorPoolUtil.SP_PROVIDER_NAME)) {
|
if (!storagePool.getStorageProviderName().equals(StorPoolUtil.SP_PROVIDER_NAME)) {
|
||||||
return StrategyPriority.CANT_HANDLE;
|
return StrategyPriority.CANT_HANDLE;
|
||||||
}
|
}
|
||||||
|
SnapshotDetailsVO snapshotDetail = _snapshotDetailsDao.findDetail(sinfo.getId(), StorPoolUtil.SP_DELAY_DELETE);
|
||||||
|
if (snapshotDetail != null) {
|
||||||
|
throw new CloudRuntimeException("Cannot create a template from the last snapshot of deleted volume. You can only restore the volume.");
|
||||||
|
}
|
||||||
String snapshotName = StorPoolHelper.getSnapshotName(sinfo.getId(), sinfo.getUuid(), _snapshotStoreDao,
|
String snapshotName = StorPoolHelper.getSnapshotName(sinfo.getId(), sinfo.getUuid(), _snapshotStoreDao,
|
||||||
_snapshotDetailsDao);
|
_snapshotDetailsDao);
|
||||||
StorPoolUtil.spLog("StorPoolDataMotionStrategy.canHandle snapshot name=%s", snapshotName);
|
StorPoolUtil.spLog("StorPoolDataMotionStrategy.canHandle snapshot name=%s", snapshotName);
|
||||||
if (snapshotName != null) {
|
if (snapshotName != null && StorPoolConfigurationManager.BypassSecondaryStorage.value()) {
|
||||||
return StrategyPriority.HIGHEST;
|
return StrategyPriority.HIGHEST;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,6 +44,16 @@ public class StorPoolConfigurationManager implements Configurable {
|
|||||||
"The interval in seconds to get StorPool template statistics",
|
"The interval in seconds to get StorPool template statistics",
|
||||||
false);
|
false);
|
||||||
|
|
||||||
|
public static final ConfigKey<Integer> DeleteAfterInterval = new ConfigKey<>("Advanced", Integer.class,
|
||||||
|
"storpool.delete.after.interval", "0",
|
||||||
|
"The interval (in seconds) after the StorPool snapshot will be deleted",
|
||||||
|
false, ConfigKey.Scope.StoragePool);
|
||||||
|
|
||||||
|
public static final ConfigKey<Integer> ListSnapshotsWithDeleteAfterInterval = new ConfigKey<>("Advanced", Integer.class,
|
||||||
|
"storpool.list.snapshots.delete.after.interval", "360",
|
||||||
|
"The interval (in seconds) to fetch the StorPool snapshots with deleteAfter flag",
|
||||||
|
false);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getConfigComponentName() {
|
public String getConfigComponentName() {
|
||||||
return StorPoolConfigurationManager.class.getSimpleName();
|
return StorPoolConfigurationManager.class.getSimpleName();
|
||||||
@ -51,6 +61,6 @@ public class StorPoolConfigurationManager implements Configurable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConfigKey<?>[] getConfigKeys() {
|
public ConfigKey<?>[] getConfigKeys() {
|
||||||
return new ConfigKey<?>[] { BypassSecondaryStorage, StorPoolClusterId, AlternativeEndPointEnabled, AlternativeEndpoint, VolumesStatsInterval, StorageStatsInterval };
|
return new ConfigKey<?>[] { BypassSecondaryStorage, StorPoolClusterId, AlternativeEndPointEnabled, AlternativeEndpoint, VolumesStatsInterval, StorageStatsInterval, DeleteAfterInterval, ListSnapshotsWithDeleteAfterInterval };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -117,6 +117,8 @@ public class StorPoolSnapshotStrategy implements SnapshotStrategy {
|
|||||||
if (resp.getError() != null) {
|
if (resp.getError() != null) {
|
||||||
final String err = String.format("Failed to clean-up Storpool snapshot %s. Error: %s", name, resp.getError());
|
final String err = String.format("Failed to clean-up Storpool snapshot %s. Error: %s", name, resp.getError());
|
||||||
StorPoolUtil.spLog(err);
|
StorPoolUtil.spLog(err);
|
||||||
|
markSnapshotAsDestroyedIfAlreadyRemoved(snapshotId, resp);
|
||||||
|
throw new CloudRuntimeException(err);
|
||||||
} else {
|
} else {
|
||||||
res = deleteSnapshotFromDbIfNeeded(snapshotVO, zoneId);
|
res = deleteSnapshotFromDbIfNeeded(snapshotVO, zoneId);
|
||||||
StorPoolUtil.spLog("StorpoolSnapshotStrategy.deleteSnapshot: executed successfully=%s, snapshot uuid=%s, name=%s", res, snapshotVO.getUuid(), name);
|
StorPoolUtil.spLog("StorpoolSnapshotStrategy.deleteSnapshot: executed successfully=%s, snapshot uuid=%s, name=%s", res, snapshotVO.getUuid(), name);
|
||||||
@ -130,6 +132,16 @@ public class StorPoolSnapshotStrategy implements SnapshotStrategy {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void markSnapshotAsDestroyedIfAlreadyRemoved(Long snapshotId, SpApiResponse resp) {
|
||||||
|
if (resp.getError().getName().equals("objectDoesNotExist")) {
|
||||||
|
SnapshotDataStoreVO snapshotOnPrimary = _snapshotStoreDao.findBySourceSnapshot(snapshotId, DataStoreRole.Primary);
|
||||||
|
if (snapshotOnPrimary != null) {
|
||||||
|
snapshotOnPrimary.setState(State.Destroyed);
|
||||||
|
_snapshotStoreDao.update(snapshotOnPrimary.getId(), snapshotOnPrimary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StrategyPriority canHandle(Snapshot snapshot, Long zoneId, SnapshotOperation op) {
|
public StrategyPriority canHandle(Snapshot snapshot, Long zoneId, SnapshotOperation op) {
|
||||||
logger.debug(String.format("StorpoolSnapshotStrategy.canHandle: snapshot=%s, uuid=%s, op=%s", snapshot.getName(), snapshot.getUuid(), op));
|
logger.debug(String.format("StorpoolSnapshotStrategy.canHandle: snapshot=%s, uuid=%s, op=%s", snapshot.getName(), snapshot.getUuid(), op));
|
||||||
@ -167,7 +179,7 @@ public class StorPoolSnapshotStrategy implements SnapshotStrategy {
|
|||||||
boolean resultIsSet = false;
|
boolean resultIsSet = false;
|
||||||
try {
|
try {
|
||||||
while (snapshot != null &&
|
while (snapshot != null &&
|
||||||
(snapshot.getState() == Snapshot.State.Destroying || snapshot.getState() == Snapshot.State.Destroyed || snapshot.getState() == Snapshot.State.Error)) {
|
(snapshot.getState() == Snapshot.State.Destroying || snapshot.getState() == Snapshot.State.Destroyed || snapshot.getState() == Snapshot.State.Error || snapshot.getState() == Snapshot.State.BackedUp)) {
|
||||||
SnapshotInfo child = snapshot.getChild();
|
SnapshotInfo child = snapshot.getChild();
|
||||||
|
|
||||||
if (child != null) {
|
if (child != null) {
|
||||||
@ -331,9 +343,21 @@ public class StorPoolSnapshotStrategy implements SnapshotStrategy {
|
|||||||
} else {
|
} else {
|
||||||
snapshotZoneDao.removeSnapshotFromZones(snapshotVO.getId());
|
snapshotZoneDao.removeSnapshotFromZones(snapshotVO.getId());
|
||||||
}
|
}
|
||||||
|
if (CollectionUtils.isNotEmpty(retrieveSnapshotEntries(snapshotId, null))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
updateSnapshotToDestroyed(snapshotVO);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<SnapshotInfo> retrieveSnapshotEntries(long snapshotId, Long zoneId) {
|
||||||
|
return snapshotDataFactory.getSnapshots(snapshotId, zoneId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateSnapshotToDestroyed(SnapshotVO snapshotVo) {
|
||||||
|
snapshotVo.setState(Snapshot.State.Destroyed);
|
||||||
|
_snapshotDao.update(snapshotVo.getId(), snapshotVo);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SnapshotInfo takeSnapshot(SnapshotInfo snapshot) {
|
public SnapshotInfo takeSnapshot(SnapshotInfo snapshot) {
|
||||||
|
|||||||
@ -33,6 +33,7 @@ import org.apache.cloudstack.api.ServerApiException;
|
|||||||
import org.apache.cloudstack.api.response.DomainResponse;
|
import org.apache.cloudstack.api.response.DomainResponse;
|
||||||
import org.apache.cloudstack.api.response.LinkAccountToLdapResponse;
|
import org.apache.cloudstack.api.response.LinkAccountToLdapResponse;
|
||||||
import org.apache.cloudstack.api.response.LinkDomainToLdapResponse;
|
import org.apache.cloudstack.api.response.LinkDomainToLdapResponse;
|
||||||
|
import org.apache.cloudstack.api.response.RoleResponse;
|
||||||
import org.apache.cloudstack.ldap.LdapManager;
|
import org.apache.cloudstack.ldap.LdapManager;
|
||||||
import org.apache.cloudstack.ldap.LdapUser;
|
import org.apache.cloudstack.ldap.LdapUser;
|
||||||
import org.apache.cloudstack.ldap.NoLdapUserMatchingQueryException;
|
import org.apache.cloudstack.ldap.NoLdapUserMatchingQueryException;
|
||||||
@ -61,9 +62,12 @@ public class LinkAccountToLdapCmd extends BaseCmd {
|
|||||||
@Parameter(name = ApiConstants.ADMIN, type = CommandType.STRING, required = false, description = "domain admin username in LDAP ")
|
@Parameter(name = ApiConstants.ADMIN, type = CommandType.STRING, required = false, description = "domain admin username in LDAP ")
|
||||||
private String admin;
|
private String admin;
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.ACCOUNT_TYPE, type = CommandType.INTEGER, required = true, description = "Type of the account to auto import. Specify 0 for user and 2 for "
|
@Parameter(name = ApiConstants.ACCOUNT_TYPE, type = CommandType.INTEGER, required = false, description = "Type of the account to auto import. Specify 0 for user and 2 for "
|
||||||
+ "domain admin")
|
+ "domain admin")
|
||||||
private int accountType;
|
private Integer accountType;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.ROLE_ID, type = CommandType.UUID, entityType = RoleResponse.class, required = false, description = "Creates the account under the specified role.", since="4.19.1")
|
||||||
|
private Long roleId;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private LdapManager _ldapManager;
|
private LdapManager _ldapManager;
|
||||||
@ -132,7 +136,14 @@ public class LinkAccountToLdapCmd extends BaseCmd {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Account.Type getAccountType() {
|
public Account.Type getAccountType() {
|
||||||
return Account.Type.getFromValue(accountType);
|
if (accountType == null) {
|
||||||
|
return RoleType.getAccountTypeByRole(roleService.findRole(roleId), null);
|
||||||
|
}
|
||||||
|
return RoleType.getAccountTypeByRole(roleService.findRole(roleId), Account.Type.getFromValue(accountType.intValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getRoleId() {
|
||||||
|
return RoleType.getRoleByAccountType(roleId, getAccountType());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -449,11 +449,12 @@ public class LdapManagerImpl extends ComponentLifecycleBase implements LdapManag
|
|||||||
Validate.notEmpty(cmd.getLdapDomain(), "ldapDomain cannot be empty, please supply a GROUP or OU name");
|
Validate.notEmpty(cmd.getLdapDomain(), "ldapDomain cannot be empty, please supply a GROUP or OU name");
|
||||||
Validate.notNull(cmd.getType(), "type cannot be null. It should either be GROUP or OU");
|
Validate.notNull(cmd.getType(), "type cannot be null. It should either be GROUP or OU");
|
||||||
Validate.notEmpty(cmd.getLdapDomain(), "GROUP or OU name cannot be empty");
|
Validate.notEmpty(cmd.getLdapDomain(), "GROUP or OU name cannot be empty");
|
||||||
|
Validate.isTrue(cmd.getAccountType() != null || cmd.getRoleId() != null, "Either account type or role ID must be given");
|
||||||
|
|
||||||
LinkType linkType = LdapManager.LinkType.valueOf(cmd.getType().toUpperCase());
|
LinkType linkType = LdapManager.LinkType.valueOf(cmd.getType().toUpperCase());
|
||||||
Account account = accountDao.findActiveAccount(cmd.getAccountName(),cmd.getDomainId());
|
Account account = accountDao.findActiveAccount(cmd.getAccountName(),cmd.getDomainId());
|
||||||
if (account == null) {
|
if (account == null) {
|
||||||
account = new AccountVO(cmd.getAccountName(), cmd.getDomainId(), null, cmd.getAccountType(), UUID.randomUUID().toString());
|
account = new AccountVO(cmd.getAccountName(), cmd.getDomainId(), null, cmd.getAccountType(), cmd.getRoleId(), UUID.randomUUID().toString());
|
||||||
accountDao.persist((AccountVO)account);
|
accountDao.persist((AccountVO)account);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5162,7 +5162,7 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||||||
} else if (instance.getHostName() != null) {
|
} else if (instance.getHostName() != null) {
|
||||||
response.setHostName(instance.getHostName());
|
response.setHostName(instance.getHostName());
|
||||||
}
|
}
|
||||||
response.setPowerState(instance.getPowerState().toString());
|
response.setPowerState((instance.getPowerState() != null)? instance.getPowerState().toString() : UnmanagedInstanceTO.PowerState.PowerUnknown.toString());
|
||||||
response.setCpuCores(instance.getCpuCores());
|
response.setCpuCores(instance.getCpuCores());
|
||||||
response.setCpuSpeed(instance.getCpuSpeed());
|
response.setCpuSpeed(instance.getCpuSpeed());
|
||||||
response.setCpuCoresPerSocket(instance.getCpuCoresPerSocket());
|
response.setCpuCoresPerSocket(instance.getCpuCoresPerSocket());
|
||||||
|
|||||||
@ -2989,6 +2989,16 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
|
|||||||
return new Pair<>(pools, pools.size());
|
return new Pair<>(pools, pools.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setPoolResponseNFSMountOptions(StoragePoolResponse poolResponse, Long poolId) {
|
||||||
|
if (Storage.StoragePoolType.NetworkFilesystem.toString().equals(poolResponse.getType()) &&
|
||||||
|
HypervisorType.KVM.toString().equals(poolResponse.getHypervisor())) {
|
||||||
|
StoragePoolDetailVO detail = _storagePoolDetailsDao.findDetail(poolId, ApiConstants.NFS_MOUNT_OPTIONS);
|
||||||
|
if (detail != null) {
|
||||||
|
poolResponse.setNfsMountOpts(detail.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private ListResponse<StoragePoolResponse> createStoragesPoolResponse(Pair<List<StoragePoolJoinVO>, Integer> storagePools) {
|
private ListResponse<StoragePoolResponse> createStoragesPoolResponse(Pair<List<StoragePoolJoinVO>, Integer> storagePools) {
|
||||||
ListResponse<StoragePoolResponse> response = new ListResponse<>();
|
ListResponse<StoragePoolResponse> response = new ListResponse<>();
|
||||||
|
|
||||||
@ -3010,6 +3020,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
|
|||||||
poolResponse.setCaps(caps);
|
poolResponse.setCaps(caps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
setPoolResponseNFSMountOptions(poolResponse, poolUuidToIdMap.get(poolResponse.getId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
response.setResponses(poolResponses, storagePools.second());
|
response.setResponses(poolResponses, storagePools.second());
|
||||||
@ -4818,7 +4829,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
|
|||||||
boolean showRemovedISO = cmd.getShowRemoved();
|
boolean showRemovedISO = cmd.getShowRemoved();
|
||||||
Account caller = CallContext.current().getCallingAccount();
|
Account caller = CallContext.current().getCallingAccount();
|
||||||
|
|
||||||
boolean listAll = cmd.listAll();
|
boolean listAll = false;
|
||||||
if (isoFilter != null && isoFilter == TemplateFilter.all) {
|
if (isoFilter != null && isoFilter == TemplateFilter.all) {
|
||||||
if (caller.getType() == Account.Type.NORMAL) {
|
if (caller.getType() == Account.Type.NORMAL) {
|
||||||
throw new InvalidParameterValueException("Filter " + TemplateFilter.all + " can be specified by admin only");
|
throw new InvalidParameterValueException("Filter " + TemplateFilter.all + " can be specified by admin only");
|
||||||
|
|||||||
@ -247,7 +247,7 @@ public class HostJoinDaoImpl extends GenericDaoBase<HostJoinVO, Long> implements
|
|||||||
host.getHypervisorType() == Hypervisor.HypervisorType.Custom)) {
|
host.getHypervisorType() == Hypervisor.HypervisorType.Custom)) {
|
||||||
//only kvm has the requirement to return host details
|
//only kvm has the requirement to return host details
|
||||||
try {
|
try {
|
||||||
hostResponse.setDetails(hostDetails);
|
hostResponse.setDetails(hostDetails, host.getHypervisorType());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.debug("failed to get host details", e);
|
logger.debug("failed to get host details", e);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,16 +34,21 @@ import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
|
|||||||
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
||||||
import org.apache.cloudstack.query.QueryService;
|
import org.apache.cloudstack.query.QueryService;
|
||||||
|
|
||||||
|
import com.cloud.api.ApiDBUtils;
|
||||||
import com.cloud.api.ApiResponseHelper;
|
import com.cloud.api.ApiResponseHelper;
|
||||||
import com.cloud.api.query.vo.SnapshotJoinVO;
|
import com.cloud.api.query.vo.SnapshotJoinVO;
|
||||||
|
import com.cloud.storage.GuestOS;
|
||||||
import com.cloud.storage.Snapshot;
|
import com.cloud.storage.Snapshot;
|
||||||
import com.cloud.storage.VMTemplateStorageResourceAssoc;
|
import com.cloud.storage.VMTemplateStorageResourceAssoc;
|
||||||
|
import com.cloud.storage.Volume.Type;
|
||||||
|
import com.cloud.storage.VolumeVO;
|
||||||
import com.cloud.user.Account;
|
import com.cloud.user.Account;
|
||||||
import com.cloud.user.AccountService;
|
import com.cloud.user.AccountService;
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
import com.cloud.utils.db.Filter;
|
import com.cloud.utils.db.Filter;
|
||||||
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 com.cloud.vm.VMInstanceVO;
|
||||||
|
|
||||||
public class SnapshotJoinDaoImpl extends GenericDaoBaseWithTagInformation<SnapshotJoinVO, SnapshotResponse> implements SnapshotJoinDao {
|
public class SnapshotJoinDaoImpl extends GenericDaoBaseWithTagInformation<SnapshotJoinVO, SnapshotResponse> implements SnapshotJoinDao {
|
||||||
|
|
||||||
@ -121,6 +126,16 @@ public class SnapshotJoinDaoImpl extends GenericDaoBaseWithTagInformation<Snapsh
|
|||||||
snapshotResponse.setVolumeName(snapshot.getVolumeName());
|
snapshotResponse.setVolumeName(snapshot.getVolumeName());
|
||||||
snapshotResponse.setVolumeType(snapshot.getVolumeType().name());
|
snapshotResponse.setVolumeType(snapshot.getVolumeType().name());
|
||||||
snapshotResponse.setVirtualSize(snapshot.getVolumeSize());
|
snapshotResponse.setVirtualSize(snapshot.getVolumeSize());
|
||||||
|
VolumeVO volume = ApiDBUtils.findVolumeById(snapshot.getVolumeId());
|
||||||
|
if (volume != null && volume.getVolumeType() == Type.ROOT && volume.getInstanceId() != null) {
|
||||||
|
VMInstanceVO vm = ApiDBUtils.findVMInstanceById(volume.getInstanceId());
|
||||||
|
if (vm != null) {
|
||||||
|
GuestOS guestOS = ApiDBUtils.findGuestOSById(vm.getGuestOSId());
|
||||||
|
if (guestOS != null) {
|
||||||
|
snapshotResponse.setOsTypeId(guestOS.getUuid());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
snapshotResponse.setZoneId(snapshot.getDataCenterUuid());
|
snapshotResponse.setZoneId(snapshot.getDataCenterUuid());
|
||||||
snapshotResponse.setZoneName(snapshot.getDataCenterName());
|
snapshotResponse.setZoneName(snapshot.getDataCenterName());
|
||||||
|
|||||||
@ -474,9 +474,9 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
|||||||
|
|
||||||
private long _defaultPageSize = Long.parseLong(Config.DefaultPageSize.getDefaultValue());
|
private long _defaultPageSize = Long.parseLong(Config.DefaultPageSize.getDefaultValue());
|
||||||
private static final String DOMAIN_NAME_PATTERN = "^((?!-)[A-Za-z0-9-]{1,63}(?<!-)\\.)+[A-Za-z]{1,63}$";
|
private static final String DOMAIN_NAME_PATTERN = "^((?!-)[A-Za-z0-9-]{1,63}(?<!-)\\.)+[A-Za-z]{1,63}$";
|
||||||
protected Set<String> configValuesForValidation;
|
private Set<String> configValuesForValidation = new HashSet<String>();
|
||||||
private Set<String> weightBasedParametersForValidation;
|
private Set<String> weightBasedParametersForValidation = new HashSet<String>();
|
||||||
private Set<String> overprovisioningFactorsForValidation;
|
private Set<String> overprovisioningFactorsForValidation = new HashSet<String>();
|
||||||
|
|
||||||
public static final ConfigKey<Boolean> SystemVMUseLocalStorage = new ConfigKey<Boolean>(Boolean.class, "system.vm.use.local.storage", "Advanced", "false",
|
public static final ConfigKey<Boolean> SystemVMUseLocalStorage = new ConfigKey<Boolean>(Boolean.class, "system.vm.use.local.storage", "Advanced", "false",
|
||||||
"Indicates whether to use local storage pools or shared storage pools for system VMs.", false, ConfigKey.Scope.Zone, null);
|
"Indicates whether to use local storage pools or shared storage pools for system VMs.", false, ConfigKey.Scope.Zone, null);
|
||||||
@ -513,6 +513,11 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
|||||||
public static final ConfigKey<Boolean> ALLOW_DOMAIN_ADMINS_TO_CREATE_TAGGED_OFFERINGS = new ConfigKey<>(Boolean.class, "allow.domain.admins.to.create.tagged.offerings", "Advanced",
|
public static final ConfigKey<Boolean> ALLOW_DOMAIN_ADMINS_TO_CREATE_TAGGED_OFFERINGS = new ConfigKey<>(Boolean.class, "allow.domain.admins.to.create.tagged.offerings", "Advanced",
|
||||||
"false", "Allow domain admins to create offerings with tags.", true, ConfigKey.Scope.Account, null);
|
"false", "Allow domain admins to create offerings with tags.", true, ConfigKey.Scope.Account, null);
|
||||||
|
|
||||||
|
public static final ConfigKey<Long> DELETE_QUERY_BATCH_SIZE = new ConfigKey<>("Advanced", Long.class, "delete.query.batch.size", "0",
|
||||||
|
"Indicates the limit applied while deleting entries in bulk. With this, the delete query will apply the limit as many times as necessary," +
|
||||||
|
" to delete all the entries. This is advised when retaining several days of records, which can lead to slowness. <= 0 means that no limit will " +
|
||||||
|
"be applied. Default value is 0. For now, this is used for deletion of vm & volume stats only.", true);
|
||||||
|
|
||||||
private static final String IOPS_READ_RATE = "IOPS Read";
|
private static final String IOPS_READ_RATE = "IOPS Read";
|
||||||
private static final String IOPS_WRITE_RATE = "IOPS Write";
|
private static final String IOPS_WRITE_RATE = "IOPS Write";
|
||||||
private static final String BYTES_READ_RATE = "Bytes Read";
|
private static final String BYTES_READ_RATE = "Bytes Read";
|
||||||
@ -537,8 +542,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void populateConfigValuesForValidationSet() {
|
protected void populateConfigValuesForValidationSet() {
|
||||||
configValuesForValidation = new HashSet<String>();
|
|
||||||
configValuesForValidation.add("event.purge.interval");
|
configValuesForValidation.add("event.purge.interval");
|
||||||
configValuesForValidation.add("account.cleanup.interval");
|
configValuesForValidation.add("account.cleanup.interval");
|
||||||
configValuesForValidation.add("alert.wait");
|
configValuesForValidation.add("alert.wait");
|
||||||
@ -566,10 +570,10 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
|||||||
configValuesForValidation.add(StorageManager.STORAGE_POOL_CLIENT_MAX_CONNECTIONS.key());
|
configValuesForValidation.add(StorageManager.STORAGE_POOL_CLIENT_MAX_CONNECTIONS.key());
|
||||||
configValuesForValidation.add(UserDataManager.VM_USERDATA_MAX_LENGTH_STRING);
|
configValuesForValidation.add(UserDataManager.VM_USERDATA_MAX_LENGTH_STRING);
|
||||||
configValuesForValidation.add(UnmanagedVMsManager.RemoteKvmInstanceDisksCopyTimeout.key());
|
configValuesForValidation.add(UnmanagedVMsManager.RemoteKvmInstanceDisksCopyTimeout.key());
|
||||||
|
configValuesForValidation.add(UnmanagedVMsManager.ConvertVmwareInstanceToKvmTimeout.key());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void weightBasedParametersForValidation() {
|
private void weightBasedParametersForValidation() {
|
||||||
weightBasedParametersForValidation = new HashSet<String>();
|
|
||||||
weightBasedParametersForValidation.add(AlertManager.CPUCapacityThreshold.key());
|
weightBasedParametersForValidation.add(AlertManager.CPUCapacityThreshold.key());
|
||||||
weightBasedParametersForValidation.add(AlertManager.StorageAllocatedCapacityThreshold.key());
|
weightBasedParametersForValidation.add(AlertManager.StorageAllocatedCapacityThreshold.key());
|
||||||
weightBasedParametersForValidation.add(AlertManager.StorageCapacityThreshold.key());
|
weightBasedParametersForValidation.add(AlertManager.StorageCapacityThreshold.key());
|
||||||
@ -589,11 +593,9 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
|||||||
weightBasedParametersForValidation.add(CapacityManager.SecondaryStorageCapacityThreshold.key());
|
weightBasedParametersForValidation.add(CapacityManager.SecondaryStorageCapacityThreshold.key());
|
||||||
weightBasedParametersForValidation.add(ClusterDrsService.ClusterDrsImbalanceThreshold.key());
|
weightBasedParametersForValidation.add(ClusterDrsService.ClusterDrsImbalanceThreshold.key());
|
||||||
weightBasedParametersForValidation.add(ClusterDrsService.ClusterDrsImbalanceSkipThreshold.key());
|
weightBasedParametersForValidation.add(ClusterDrsService.ClusterDrsImbalanceSkipThreshold.key());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void overProvisioningFactorsForValidation() {
|
private void overProvisioningFactorsForValidation() {
|
||||||
overprovisioningFactorsForValidation = new HashSet<String>();
|
|
||||||
overprovisioningFactorsForValidation.add(CapacityManager.MemOverprovisioningFactor.key());
|
overprovisioningFactorsForValidation.add(CapacityManager.MemOverprovisioningFactor.key());
|
||||||
overprovisioningFactorsForValidation.add(CapacityManager.CpuOverprovisioningFactor.key());
|
overprovisioningFactorsForValidation.add(CapacityManager.CpuOverprovisioningFactor.key());
|
||||||
overprovisioningFactorsForValidation.add(CapacityManager.StorageOverprovisioningFactor.key());
|
overprovisioningFactorsForValidation.add(CapacityManager.StorageOverprovisioningFactor.key());
|
||||||
@ -1180,8 +1182,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
|||||||
return new Pair<Configuration, String>(_configDao.findByName(name), newValue);
|
return new Pair<Configuration, String>(_configDao.findByName(name), newValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String validateConfigurationValue(final String name, String value, final String scope) {
|
protected String validateConfigurationValue(final String name, String value, final String scope) {
|
||||||
|
|
||||||
final ConfigurationVO cfg = _configDao.findByName(name);
|
final ConfigurationVO cfg = _configDao.findByName(name);
|
||||||
if (cfg == null) {
|
if (cfg == null) {
|
||||||
logger.error("Missing configuration variable " + name + " in configuration table");
|
logger.error("Missing configuration variable " + name + " in configuration table");
|
||||||
@ -1263,23 +1264,24 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type.equals(Integer.class) && NetworkModel.MACIdentifier.key().equalsIgnoreCase(name)) {
|
if (type.equals(Integer.class)) {
|
||||||
try {
|
try {
|
||||||
final int val = Integer.parseInt(value);
|
final int val = Integer.parseInt(value);
|
||||||
|
if (NetworkModel.MACIdentifier.key().equalsIgnoreCase(name)) {
|
||||||
//The value need to be between 0 to 255 because the mac generation needs a value of 8 bit
|
//The value need to be between 0 to 255 because the mac generation needs a value of 8 bit
|
||||||
//0 value is considered as disable.
|
//0 value is considered as disable.
|
||||||
if(val < 0 || val > 255){
|
if(val < 0 || val > 255){
|
||||||
throw new InvalidParameterValueException(name+" value should be between 0 and 255. 0 value will disable this feature");
|
throw new InvalidParameterValueException(name + " value should be between 0 and 255. 0 value will disable this feature");
|
||||||
}
|
|
||||||
} catch (final NumberFormatException e) {
|
|
||||||
logger.error("There was an error trying to parse the integer value for:" + name);
|
|
||||||
throw new InvalidParameterValueException("There was an error trying to parse the integer value for:" + name);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type.equals(Integer.class) && configValuesForValidation.contains(name)) {
|
if (UnmanagedVMsManager.ThreadsOnMSToImportVMwareVMFiles.key().equalsIgnoreCase(name) || UnmanagedVMsManager.ThreadsOnKVMHostToImportVMwareVMFiles.key().equalsIgnoreCase(name)) {
|
||||||
try {
|
if (val > 10) {
|
||||||
final int val = Integer.parseInt(value);
|
throw new InvalidParameterValueException("Please enter a value between 0 and 10 for the configuration parameter: " + name + ", -1 will disable it");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configValuesForValidation.contains(name)) {
|
||||||
if (val <= 0) {
|
if (val <= 0) {
|
||||||
throw new InvalidParameterValueException("Please enter a positive value for the configuration parameter:" + name);
|
throw new InvalidParameterValueException("Please enter a positive value for the configuration parameter:" + name);
|
||||||
}
|
}
|
||||||
@ -1299,9 +1301,10 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
|||||||
throw new InvalidParameterValueException("Please enter a value less than 1048576 for the configuration parameter:" + name);
|
throw new InvalidParameterValueException("Please enter a value less than 1048576 for the configuration parameter:" + name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} catch (final NumberFormatException e) {
|
} catch (final NumberFormatException e) {
|
||||||
logger.error("There was an error trying to parse the integer value for:" + name);
|
logger.error("There was an error trying to parse the integer value for configuration parameter: " + name);
|
||||||
throw new InvalidParameterValueException("There was an error trying to parse the integer value for:" + name);
|
throw new InvalidParameterValueException("There was an error trying to parse the integer value for configuration parameter: " + name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1312,8 +1315,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
|||||||
throw new InvalidParameterValueException("Please enter a value between 0 and 1 for the configuration parameter: " + name);
|
throw new InvalidParameterValueException("Please enter a value between 0 and 1 for the configuration parameter: " + name);
|
||||||
}
|
}
|
||||||
} catch (final NumberFormatException e) {
|
} catch (final NumberFormatException e) {
|
||||||
logger.error("There was an error trying to parse the float value for:" + name);
|
logger.error("There was an error trying to parse the float value for configuration parameter: " + name);
|
||||||
throw new InvalidParameterValueException("There was an error trying to parse the float value for:" + name);
|
throw new InvalidParameterValueException("There was an error trying to parse the float value for configuration parameter: " + name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4799,6 +4802,9 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
|||||||
newIp6Gateway = MoreObjects.firstNonNull(newIp6Gateway, network.getIp6Gateway());
|
newIp6Gateway = MoreObjects.firstNonNull(newIp6Gateway, network.getIp6Gateway());
|
||||||
newIp6Cidr = MoreObjects.firstNonNull(newIp6Cidr, network.getIp6Cidr());
|
newIp6Cidr = MoreObjects.firstNonNull(newIp6Cidr, network.getIp6Cidr());
|
||||||
_networkModel.checkIp6Parameters(newIp6StartIp, newIp6EndIp, newIp6Gateway, newIp6Cidr);
|
_networkModel.checkIp6Parameters(newIp6StartIp, newIp6EndIp, newIp6Gateway, newIp6Cidr);
|
||||||
|
if (!GuestType.Shared.equals(network.getGuestType())) {
|
||||||
|
_networkModel.checkIp6CidrSizeEqualTo64(newIp6Cidr);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -5277,6 +5283,10 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
|||||||
endIpv6 = ObjectUtils.allNull(endIpv6, currentEndIPv6) ? null : MoreObjects.firstNonNull(endIpv6, currentEndIPv6);
|
endIpv6 = ObjectUtils.allNull(endIpv6, currentEndIPv6) ? null : MoreObjects.firstNonNull(endIpv6, currentEndIPv6);
|
||||||
|
|
||||||
_networkModel.checkIp6Parameters(startIpv6, endIpv6, ip6Gateway, ip6Cidr);
|
_networkModel.checkIp6Parameters(startIpv6, endIpv6, ip6Gateway, ip6Cidr);
|
||||||
|
final Network network = _networkModel.getNetwork(vlanRange.getNetworkId());
|
||||||
|
if (!GuestType.Shared.equals(network.getGuestType())) {
|
||||||
|
_networkModel.checkIp6CidrSizeEqualTo64(ip6Cidr);
|
||||||
|
}
|
||||||
|
|
||||||
if (!ObjectUtils.allNull(startIpv6, endIpv6) && ObjectUtils.anyNull(startIpv6, endIpv6)) {
|
if (!ObjectUtils.allNull(startIpv6, endIpv6) && ObjectUtils.anyNull(startIpv6, endIpv6)) {
|
||||||
throw new InvalidParameterValueException(String.format("Invalid IPv6 range %s-%s", startIpv6, endIpv6));
|
throw new InvalidParameterValueException(String.format("Invalid IPv6 range %s-%s", startIpv6, endIpv6));
|
||||||
@ -7862,9 +7872,10 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
|||||||
@Override
|
@Override
|
||||||
public ConfigKey<?>[] getConfigKeys() {
|
public ConfigKey<?>[] getConfigKeys() {
|
||||||
return new ConfigKey<?>[] {SystemVMUseLocalStorage, IOPS_MAX_READ_LENGTH, IOPS_MAX_WRITE_LENGTH,
|
return new ConfigKey<?>[] {SystemVMUseLocalStorage, IOPS_MAX_READ_LENGTH, IOPS_MAX_WRITE_LENGTH,
|
||||||
BYTES_MAX_READ_LENGTH, BYTES_MAX_WRITE_LENGTH, ADD_HOST_ON_SERVICE_RESTART_KVM, SET_HOST_DOWN_TO_MAINTENANCE, VM_SERVICE_OFFERING_MAX_CPU_CORES,
|
BYTES_MAX_READ_LENGTH, BYTES_MAX_WRITE_LENGTH, ADD_HOST_ON_SERVICE_RESTART_KVM, SET_HOST_DOWN_TO_MAINTENANCE,
|
||||||
VM_SERVICE_OFFERING_MAX_RAM_SIZE, MIGRATE_VM_ACROSS_CLUSTERS, ENABLE_ACCOUNT_SETTINGS_FOR_DOMAIN,
|
VM_SERVICE_OFFERING_MAX_CPU_CORES, VM_SERVICE_OFFERING_MAX_RAM_SIZE, MIGRATE_VM_ACROSS_CLUSTERS,
|
||||||
ENABLE_DOMAIN_SETTINGS_FOR_CHILD_DOMAIN, ALLOW_DOMAIN_ADMINS_TO_CREATE_TAGGED_OFFERINGS, AllowNonRFC1918CompliantIPs
|
ENABLE_ACCOUNT_SETTINGS_FOR_DOMAIN, ENABLE_DOMAIN_SETTINGS_FOR_CHILD_DOMAIN,
|
||||||
|
ALLOW_DOMAIN_ADMINS_TO_CREATE_TAGGED_OFFERINGS, DELETE_QUERY_BATCH_SIZE
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -22,7 +22,6 @@ import javax.inject.Inject;
|
|||||||
import javax.naming.ConfigurationException;
|
import javax.naming.ConfigurationException;
|
||||||
|
|
||||||
import org.apache.cloudstack.consoleproxy.ConsoleAccessManager;
|
import org.apache.cloudstack.consoleproxy.ConsoleAccessManager;
|
||||||
|
|
||||||
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
||||||
import org.apache.cloudstack.framework.security.keys.KeysManager;
|
import org.apache.cloudstack.framework.security.keys.KeysManager;
|
||||||
import org.apache.cloudstack.framework.security.keystore.KeystoreManager;
|
import org.apache.cloudstack.framework.security.keystore.KeystoreManager;
|
||||||
@ -31,6 +30,7 @@ import com.cloud.agent.AgentManager;
|
|||||||
import com.cloud.agent.api.GetVncPortAnswer;
|
import com.cloud.agent.api.GetVncPortAnswer;
|
||||||
import com.cloud.agent.api.GetVncPortCommand;
|
import com.cloud.agent.api.GetVncPortCommand;
|
||||||
import com.cloud.agent.api.StartupProxyCommand;
|
import com.cloud.agent.api.StartupProxyCommand;
|
||||||
|
import com.cloud.deploy.DeploymentPlanner;
|
||||||
import com.cloud.host.HostVO;
|
import com.cloud.host.HostVO;
|
||||||
import com.cloud.host.dao.HostDao;
|
import com.cloud.host.dao.HostDao;
|
||||||
import com.cloud.info.ConsoleProxyInfo;
|
import com.cloud.info.ConsoleProxyInfo;
|
||||||
@ -40,7 +40,9 @@ import com.cloud.utils.component.ManagerBase;
|
|||||||
import com.cloud.vm.ConsoleProxyVO;
|
import com.cloud.vm.ConsoleProxyVO;
|
||||||
import com.cloud.vm.UserVmVO;
|
import com.cloud.vm.UserVmVO;
|
||||||
import com.cloud.vm.VMInstanceVO;
|
import com.cloud.vm.VMInstanceVO;
|
||||||
|
import com.cloud.vm.VirtualMachine;
|
||||||
import com.cloud.vm.VirtualMachineManager;
|
import com.cloud.vm.VirtualMachineManager;
|
||||||
|
import com.cloud.vm.VirtualMachineProfile;
|
||||||
import com.cloud.vm.dao.ConsoleProxyDao;
|
import com.cloud.vm.dao.ConsoleProxyDao;
|
||||||
import com.cloud.vm.dao.UserVmDao;
|
import com.cloud.vm.dao.UserVmDao;
|
||||||
import com.cloud.vm.dao.VMInstanceDao;
|
import com.cloud.vm.dao.VMInstanceDao;
|
||||||
@ -180,6 +182,11 @@ public class AgentBasedConsoleProxyManager extends ManagerBase implements Consol
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startProxyForHA(VirtualMachine vm, Map<VirtualMachineProfile.Param, Object> params,
|
||||||
|
DeploymentPlanner planner) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean destroyProxy(long proxyVmId) {
|
public boolean destroyProxy(long proxyVmId) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -16,11 +16,20 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
package com.cloud.consoleproxy;
|
package com.cloud.consoleproxy;
|
||||||
|
|
||||||
import com.cloud.utils.component.Manager;
|
import java.util.Map;
|
||||||
import com.cloud.vm.ConsoleProxyVO;
|
|
||||||
|
|
||||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||||
|
|
||||||
|
import com.cloud.deploy.DeploymentPlanner;
|
||||||
|
import com.cloud.exception.ConcurrentOperationException;
|
||||||
|
import com.cloud.exception.InsufficientCapacityException;
|
||||||
|
import com.cloud.exception.OperationTimedoutException;
|
||||||
|
import com.cloud.exception.ResourceUnavailableException;
|
||||||
|
import com.cloud.utils.component.Manager;
|
||||||
|
import com.cloud.vm.ConsoleProxyVO;
|
||||||
|
import com.cloud.vm.VirtualMachine;
|
||||||
|
import com.cloud.vm.VirtualMachineProfile;
|
||||||
|
|
||||||
public interface ConsoleProxyManager extends Manager, ConsoleProxyService {
|
public interface ConsoleProxyManager extends Manager, ConsoleProxyService {
|
||||||
|
|
||||||
int DEFAULT_PROXY_CAPACITY = 50;
|
int DEFAULT_PROXY_CAPACITY = 50;
|
||||||
@ -53,6 +62,10 @@ public interface ConsoleProxyManager extends Manager, ConsoleProxyService {
|
|||||||
|
|
||||||
ConsoleProxyVO startProxy(long proxyVmId, boolean ignoreRestartSetting);
|
ConsoleProxyVO startProxy(long proxyVmId, boolean ignoreRestartSetting);
|
||||||
|
|
||||||
|
void startProxyForHA(VirtualMachine vm, Map<VirtualMachineProfile.Param, Object> params, DeploymentPlanner planner)
|
||||||
|
throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException,
|
||||||
|
OperationTimedoutException;
|
||||||
|
|
||||||
boolean stopProxy(long proxyVmId);
|
boolean stopProxy(long proxyVmId);
|
||||||
|
|
||||||
boolean rebootProxy(long proxyVmId);
|
boolean rebootProxy(long proxyVmId);
|
||||||
|
|||||||
@ -74,6 +74,9 @@ import com.cloud.dc.dao.DataCenterDao;
|
|||||||
import com.cloud.dc.dao.HostPodDao;
|
import com.cloud.dc.dao.HostPodDao;
|
||||||
import com.cloud.deploy.DataCenterDeployment;
|
import com.cloud.deploy.DataCenterDeployment;
|
||||||
import com.cloud.deploy.DeployDestination;
|
import com.cloud.deploy.DeployDestination;
|
||||||
|
import com.cloud.deploy.DeploymentPlanner;
|
||||||
|
import com.cloud.event.ActionEvent;
|
||||||
|
import com.cloud.event.EventTypes;
|
||||||
import com.cloud.exception.ConcurrentOperationException;
|
import com.cloud.exception.ConcurrentOperationException;
|
||||||
import com.cloud.exception.InsufficientAddressCapacityException;
|
import com.cloud.exception.InsufficientAddressCapacityException;
|
||||||
import com.cloud.exception.InsufficientCapacityException;
|
import com.cloud.exception.InsufficientCapacityException;
|
||||||
@ -491,6 +494,14 @@ public class ConsoleProxyManagerImpl extends ManagerBase implements ConsoleProxy
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@ActionEvent(eventType = EventTypes.EVENT_PROXY_START, eventDescription = "restarting console proxy VM for HA", async = true)
|
||||||
|
public void startProxyForHA(VirtualMachine vm, Map<VirtualMachineProfile.Param, Object> params,
|
||||||
|
DeploymentPlanner planner) throws InsufficientCapacityException, ResourceUnavailableException,
|
||||||
|
ConcurrentOperationException, OperationTimedoutException {
|
||||||
|
virtualMachineManager.advanceStart(vm.getUuid(), params, planner);
|
||||||
|
}
|
||||||
|
|
||||||
public ConsoleProxyVO assignProxyFromRunningPool(long dataCenterId) {
|
public ConsoleProxyVO assignProxyFromRunningPool(long dataCenterId) {
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
|
|||||||
@ -28,6 +28,8 @@ import java.util.concurrent.TimeUnit;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.naming.ConfigurationException;
|
import javax.naming.ConfigurationException;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.api.ApiCommandResourceType;
|
||||||
|
import org.apache.cloudstack.context.CallContext;
|
||||||
import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService;
|
import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver;
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider;
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider;
|
||||||
@ -64,13 +66,14 @@ import com.cloud.host.HostVO;
|
|||||||
import com.cloud.host.Status;
|
import com.cloud.host.Status;
|
||||||
import com.cloud.host.dao.HostDao;
|
import com.cloud.host.dao.HostDao;
|
||||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||||
|
import com.cloud.network.VpcVirtualNetworkApplianceService;
|
||||||
import com.cloud.resource.ResourceManager;
|
import com.cloud.resource.ResourceManager;
|
||||||
import com.cloud.server.ManagementServer;
|
import com.cloud.server.ManagementServer;
|
||||||
import com.cloud.service.ServiceOfferingVO;
|
import com.cloud.service.ServiceOfferingVO;
|
||||||
import com.cloud.service.dao.ServiceOfferingDao;
|
import com.cloud.service.dao.ServiceOfferingDao;
|
||||||
|
import com.cloud.storage.Storage.StoragePoolType;
|
||||||
import com.cloud.storage.StorageManager;
|
import com.cloud.storage.StorageManager;
|
||||||
import com.cloud.storage.VolumeVO;
|
import com.cloud.storage.VolumeVO;
|
||||||
import com.cloud.storage.Storage.StoragePoolType;
|
|
||||||
import com.cloud.storage.dao.GuestOSCategoryDao;
|
import com.cloud.storage.dao.GuestOSCategoryDao;
|
||||||
import com.cloud.storage.dao.GuestOSDao;
|
import com.cloud.storage.dao.GuestOSDao;
|
||||||
import com.cloud.storage.dao.VolumeDao;
|
import com.cloud.storage.dao.VolumeDao;
|
||||||
@ -79,6 +82,7 @@ import com.cloud.user.AccountManager;
|
|||||||
import com.cloud.utils.component.ManagerBase;
|
import com.cloud.utils.component.ManagerBase;
|
||||||
import com.cloud.utils.concurrency.NamedThreadFactory;
|
import com.cloud.utils.concurrency.NamedThreadFactory;
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
|
import com.cloud.vm.UserVmManager;
|
||||||
import com.cloud.vm.VMInstanceVO;
|
import com.cloud.vm.VMInstanceVO;
|
||||||
import com.cloud.vm.VirtualMachine;
|
import com.cloud.vm.VirtualMachine;
|
||||||
import com.cloud.vm.VirtualMachineManager;
|
import com.cloud.vm.VirtualMachineManager;
|
||||||
@ -142,6 +146,10 @@ public class HighAvailabilityManagerImpl extends ManagerBase implements Configur
|
|||||||
VolumeDao volumeDao;
|
VolumeDao volumeDao;
|
||||||
@Inject
|
@Inject
|
||||||
DataStoreProviderManager dataStoreProviderMgr;
|
DataStoreProviderManager dataStoreProviderMgr;
|
||||||
|
@Inject
|
||||||
|
VpcVirtualNetworkApplianceService routerService;
|
||||||
|
@Inject
|
||||||
|
UserVmManager userVmManager;
|
||||||
|
|
||||||
long _serverId;
|
long _serverId;
|
||||||
|
|
||||||
@ -435,6 +443,36 @@ public class HighAvailabilityManagerImpl extends ManagerBase implements Configur
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void startVm(VirtualMachine vm, Map<VirtualMachineProfile.Param, Object> params,
|
||||||
|
DeploymentPlanner planner) throws InsufficientCapacityException, ResourceUnavailableException,
|
||||||
|
ConcurrentOperationException, OperationTimedoutException {
|
||||||
|
CallContext ctx = CallContext.register(CallContext.current(), ApiCommandResourceType.VirtualMachine);
|
||||||
|
ctx.setEventResourceId(vm.getId());
|
||||||
|
try {
|
||||||
|
switch (vm.getType()) {
|
||||||
|
case DomainRouter:
|
||||||
|
ctx.setEventResourceType(ApiCommandResourceType.DomainRouter);
|
||||||
|
routerService.startRouterForHA(vm, params, planner);
|
||||||
|
break;
|
||||||
|
case ConsoleProxy:
|
||||||
|
ctx.setEventResourceType(ApiCommandResourceType.ConsoleProxy);
|
||||||
|
consoleProxyManager.startProxyForHA(vm, params, planner);
|
||||||
|
break;
|
||||||
|
case SecondaryStorageVm:
|
||||||
|
ctx.setEventResourceType(ApiCommandResourceType.SystemVm);
|
||||||
|
secondaryStorageVmManager.startSecStorageVmForHA(vm, params, planner);
|
||||||
|
break;
|
||||||
|
case User:
|
||||||
|
userVmManager.startVirtualMachineForHA(vm, params, planner);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
_itMgr.advanceStart(vm.getUuid(), params, planner);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
CallContext.unregister();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected Long restart(final HaWorkVO work) {
|
protected Long restart(final HaWorkVO work) {
|
||||||
logger.debug("RESTART with HAWORK");
|
logger.debug("RESTART with HAWORK");
|
||||||
List<HaWorkVO> items = _haDao.listFutureHaWorkForVm(work.getInstanceId(), work.getId());
|
List<HaWorkVO> items = _haDao.listFutureHaWorkForVm(work.getInstanceId(), work.getId());
|
||||||
@ -626,10 +664,10 @@ public class HighAvailabilityManagerImpl extends ManagerBase implements Configur
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// First try starting the vm with its original planner, if it doesn't succeed send HAPlanner as its an emergency.
|
// First try starting the vm with its original planner, if it doesn't succeed send HAPlanner as its an emergency.
|
||||||
_itMgr.advanceStart(vm.getUuid(), params, null);
|
startVm(vm, params, null);
|
||||||
}catch (InsufficientCapacityException e){
|
} catch (InsufficientCapacityException e){
|
||||||
logger.warn("Failed to deploy vm " + vmId + " with original planner, sending HAPlanner");
|
logger.warn("Failed to deploy vm " + vmId + " with original planner, sending HAPlanner");
|
||||||
_itMgr.advanceStart(vm.getUuid(), params, _haPlanners.get(0));
|
startVm(vm, params, _haPlanners.get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
VMInstanceVO started = _instanceDao.findById(vm.getId());
|
VMInstanceVO started = _instanceDao.findById(vm.getId());
|
||||||
@ -651,7 +689,7 @@ public class HighAvailabilityManagerImpl extends ManagerBase implements Configur
|
|||||||
} catch (final ResourceUnavailableException e) {
|
} catch (final ResourceUnavailableException e) {
|
||||||
logger.warn("Unable to restart " + vm.toString() + " due to " + e.getMessage());
|
logger.warn("Unable to restart " + vm.toString() + " due to " + e.getMessage());
|
||||||
_alertMgr.sendAlert(alertType, vm.getDataCenterId(), vm.getPodIdToDeployIn(), "Unable to restart " + vm.getHostName() + " which was running on host " +
|
_alertMgr.sendAlert(alertType, vm.getDataCenterId(), vm.getPodIdToDeployIn(), "Unable to restart " + vm.getHostName() + " which was running on host " +
|
||||||
hostDesc, "The Storage is unavailable for trying to restart VM, name: " + vm.getHostName() + ", id: " + vmId + " which was running on host " + hostDesc);
|
hostDesc, "The resource is unavailable for trying to restart VM, name: " + vm.getHostName() + ", id: " + vmId + " which was running on host " + hostDesc);
|
||||||
} catch (ConcurrentOperationException e) {
|
} catch (ConcurrentOperationException e) {
|
||||||
logger.warn("Unable to restart " + vm.toString() + " due to " + e.getMessage());
|
logger.warn("Unable to restart " + vm.toString() + " due to " + e.getMessage());
|
||||||
_alertMgr.sendAlert(alertType, vm.getDataCenterId(), vm.getPodIdToDeployIn(), "Unable to restart " + vm.getHostName() + " which was running on host " +
|
_alertMgr.sendAlert(alertType, vm.getDataCenterId(), vm.getPodIdToDeployIn(), "Unable to restart " + vm.getHostName() + " which was running on host " +
|
||||||
@ -659,7 +697,7 @@ public class HighAvailabilityManagerImpl extends ManagerBase implements Configur
|
|||||||
} catch (OperationTimedoutException e) {
|
} catch (OperationTimedoutException e) {
|
||||||
logger.warn("Unable to restart " + vm.toString() + " due to " + e.getMessage());
|
logger.warn("Unable to restart " + vm.toString() + " due to " + e.getMessage());
|
||||||
_alertMgr.sendAlert(alertType, vm.getDataCenterId(), vm.getPodIdToDeployIn(), "Unable to restart " + vm.getHostName() + " which was running on host " +
|
_alertMgr.sendAlert(alertType, vm.getDataCenterId(), vm.getPodIdToDeployIn(), "Unable to restart " + vm.getHostName() + " which was running on host " +
|
||||||
hostDesc, "The Storage is unavailable for trying to restart VM, name: " + vm.getHostName() + ", id: " + vmId + " which was running on host " + hostDesc);
|
hostDesc, "The operation timed out while trying to restart VM, name: " + vm.getHostName() + ", id: " + vmId + " which was running on host " + hostDesc);
|
||||||
}
|
}
|
||||||
vm = _itMgr.findById(vm.getId());
|
vm = _itMgr.findById(vm.getId());
|
||||||
work.setUpdateTime(vm.getUpdated());
|
work.setUpdateTime(vm.getUpdated());
|
||||||
|
|||||||
@ -44,6 +44,7 @@ import org.apache.commons.collections.MapUtils;
|
|||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import com.cloud.agent.api.Command;
|
import com.cloud.agent.api.Command;
|
||||||
|
import com.cloud.agent.api.to.DataStoreTO;
|
||||||
import com.cloud.agent.api.to.DiskTO;
|
import com.cloud.agent.api.to.DiskTO;
|
||||||
import com.cloud.agent.api.to.NicTO;
|
import com.cloud.agent.api.to.NicTO;
|
||||||
import com.cloud.agent.api.to.VirtualMachineTO;
|
import com.cloud.agent.api.to.VirtualMachineTO;
|
||||||
@ -420,7 +421,7 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UnmanagedInstanceTO cloneHypervisorVMOutOfBand(String hostIp, String vmName, Map<String, String> params) {
|
public Pair<UnmanagedInstanceTO, Boolean> getHypervisorVMOutOfBandAndCloneIfRequired(String hostIp, String vmName, Map<String, String> params) {
|
||||||
logger.error("Unsupported operation: cannot clone external VM");
|
logger.error("Unsupported operation: cannot clone external VM");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -430,4 +431,16 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis
|
|||||||
logger.error("Unsupported operation: cannot remove external VM");
|
logger.error("Unsupported operation: cannot remove external VM");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String createVMTemplateOutOfBand(String hostIp, String vmName, Map<String, String> params, DataStoreTO templateLocation, int threadsCountToExportOvf) {
|
||||||
|
logger.error("Unsupported operation: cannot create template file");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean removeVMTemplateOutOfBand(DataStoreTO templateLocation, String templateDir) {
|
||||||
|
logger.error("Unsupported operation: cannot remove template file");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2387,7 +2387,9 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi
|
|||||||
throw new InvalidParameterValueException("endIPv6 is not in ip6cidr indicated network!");
|
throw new InvalidParameterValueException("endIPv6 is not in ip6cidr indicated network!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkIp6CidrSizeEqualTo64(String ip6Cidr) {
|
||||||
int cidrSize = NetUtils.getIp6CidrSize(ip6Cidr);
|
int cidrSize = NetUtils.getIp6CidrSize(ip6Cidr);
|
||||||
// we only support cidr == 64
|
// we only support cidr == 64
|
||||||
if (cidrSize != 64) {
|
if (cidrSize != 64) {
|
||||||
|
|||||||
@ -37,7 +37,6 @@ import java.util.Map;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.naming.ConfigurationException;
|
import javax.naming.ConfigurationException;
|
||||||
@ -1591,6 +1590,9 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
|
|||||||
endIPv6 = startIPv6;
|
endIPv6 = startIPv6;
|
||||||
}
|
}
|
||||||
_networkModel.checkIp6Parameters(startIPv6, endIPv6, ip6Gateway, ip6Cidr);
|
_networkModel.checkIp6Parameters(startIPv6, endIPv6, ip6Gateway, ip6Cidr);
|
||||||
|
if (!GuestType.Shared.equals(ntwkOff.getGuestType())) {
|
||||||
|
_networkModel.checkIp6CidrSizeEqualTo64(ip6Cidr);
|
||||||
|
}
|
||||||
|
|
||||||
if (zone.getNetworkType() != NetworkType.Advanced || ntwkOff.getGuestType() != Network.GuestType.Shared) {
|
if (zone.getNetworkType() != NetworkType.Advanced || ntwkOff.getGuestType() != Network.GuestType.Shared) {
|
||||||
throw new InvalidParameterValueException("Can only support create IPv6 network with advance shared network!");
|
throw new InvalidParameterValueException("Can only support create IPv6 network with advance shared network!");
|
||||||
@ -2278,6 +2280,9 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
|
|||||||
Long associatedNetworkId = cmd.getAssociatedNetworkId();
|
Long associatedNetworkId = cmd.getAssociatedNetworkId();
|
||||||
String networkFilterStr = cmd.getNetworkFilter();
|
String networkFilterStr = cmd.getNetworkFilter();
|
||||||
|
|
||||||
|
boolean applyManualPagination = CollectionUtils.isNotEmpty(supportedServicesStr) ||
|
||||||
|
Boolean.TRUE.equals(canUseForDeploy);
|
||||||
|
|
||||||
String vlanId = null;
|
String vlanId = null;
|
||||||
if (cmd instanceof ListNetworksCmdByAdmin) {
|
if (cmd instanceof ListNetworksCmdByAdmin) {
|
||||||
vlanId = ((ListNetworksCmdByAdmin)cmd).getVlan();
|
vlanId = ((ListNetworksCmdByAdmin)cmd).getVlan();
|
||||||
@ -2363,7 +2368,13 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
|
|||||||
isRecursive = true;
|
isRecursive = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Filter searchFilter = new Filter(NetworkVO.class, "id", false, null, null);
|
Long offset = cmd.getStartIndex();
|
||||||
|
Long limit = cmd.getPageSizeVal();
|
||||||
|
if (applyManualPagination) {
|
||||||
|
offset = null;
|
||||||
|
limit = null;
|
||||||
|
}
|
||||||
|
Filter searchFilter = new Filter(NetworkVO.class, "id", false, offset, limit);
|
||||||
SearchBuilder<NetworkVO> sb = _networksDao.createSearchBuilder();
|
SearchBuilder<NetworkVO> sb = _networksDao.createSearchBuilder();
|
||||||
|
|
||||||
if (forVpc != null) {
|
if (forVpc != null) {
|
||||||
@ -2418,112 +2429,122 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
|
|||||||
sb.join("associatedNetworkSearch", associatedNetworkSearch, sb.entity().getId(), associatedNetworkSearch.entity().getResourceId(), JoinBuilder.JoinType.INNER);
|
sb.join("associatedNetworkSearch", associatedNetworkSearch, sb.entity().getId(), associatedNetworkSearch.entity().getResourceId(), JoinBuilder.JoinType.INNER);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<NetworkVO> networksToReturn = new ArrayList<NetworkVO>();
|
SearchCriteria<NetworkVO> mainSearchCriteria = createNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId,
|
||||||
|
guestIpType, trafficType, physicalNetworkId, networkOfferingId, aclType, restartRequired,
|
||||||
|
specifyIpRanges, vpcId, tags, display, vlanId, associatedNetworkId);
|
||||||
|
SearchCriteria<NetworkVO> additionalSearchCriteria = _networksDao.createSearchCriteria();
|
||||||
|
|
||||||
if (isSystem == null || !isSystem) {
|
if (isSystem == null || !isSystem) {
|
||||||
if (!permittedAccounts.isEmpty()) {
|
if (!permittedAccounts.isEmpty()) {
|
||||||
if (Arrays.asList(Network.NetworkFilter.Account, Network.NetworkFilter.AccountDomain, Network.NetworkFilter.All).contains(networkFilter)) {
|
if (Arrays.asList(Network.NetworkFilter.Account, Network.NetworkFilter.AccountDomain, Network.NetworkFilter.All).contains(networkFilter)) {
|
||||||
//get account level networks
|
//get account level networks
|
||||||
networksToReturn.addAll(listAccountSpecificNetworks(buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, networkOfferingId,
|
additionalSearchCriteria.addOr("id", SearchCriteria.Op.SC,
|
||||||
aclType, skipProjectNetworks, restartRequired, specifyIpRanges, vpcId, tags, display, vlanId, associatedNetworkId), searchFilter, permittedAccounts));
|
getAccountSpecificNetworksSearchCriteria(sb, permittedAccounts, skipProjectNetworks));
|
||||||
}
|
}
|
||||||
if (domainId != null && Arrays.asList(Network.NetworkFilter.Domain, Network.NetworkFilter.AccountDomain, Network.NetworkFilter.All).contains(networkFilter)) {
|
if (domainId != null && Arrays.asList(Network.NetworkFilter.Domain, Network.NetworkFilter.AccountDomain, Network.NetworkFilter.All).contains(networkFilter)) {
|
||||||
//get domain level networks
|
//get domain level networks
|
||||||
networksToReturn.addAll(listDomainLevelNetworks(buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, networkOfferingId,
|
SearchCriteria<NetworkVO> domainLevelSC = getDomainLevelNetworksSearchCriteria(sb, domainId, false);
|
||||||
aclType, true, restartRequired, specifyIpRanges, vpcId, tags, display, vlanId, associatedNetworkId), searchFilter, domainId, false));
|
if (domainLevelSC != null) {
|
||||||
|
additionalSearchCriteria.addOr("id", SearchCriteria.Op.SC, domainLevelSC);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (Arrays.asList(Network.NetworkFilter.Shared, Network.NetworkFilter.All).contains(networkFilter)) {
|
if (Arrays.asList(Network.NetworkFilter.Shared, Network.NetworkFilter.All).contains(networkFilter)) {
|
||||||
// get shared networks
|
// get shared networks
|
||||||
List<NetworkVO> sharedNetworks = listSharedNetworks(buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, networkOfferingId,
|
SearchCriteria<NetworkVO> sharedNetworksSC = getSharedNetworksSearchCriteria(sb, permittedAccounts);
|
||||||
aclType, true, restartRequired, specifyIpRanges, vpcId, tags, display, vlanId, associatedNetworkId), searchFilter, permittedAccounts);
|
if (sharedNetworksSC != null) {
|
||||||
addNetworksToReturnIfNotExist(networksToReturn, sharedNetworks);
|
additionalSearchCriteria.addOr("id", SearchCriteria.Op.SC, sharedNetworksSC);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (Arrays.asList(Network.NetworkFilter.Account, Network.NetworkFilter.AccountDomain, Network.NetworkFilter.All).contains(networkFilter)) {
|
if (Arrays.asList(Network.NetworkFilter.Account, Network.NetworkFilter.AccountDomain, Network.NetworkFilter.All).contains(networkFilter)) {
|
||||||
//add account specific networks
|
//add account specific networks
|
||||||
networksToReturn.addAll(listAccountSpecificNetworksByDomainPath(buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, networkOfferingId,
|
additionalSearchCriteria.addOr("id", SearchCriteria.Op.SC,
|
||||||
aclType, skipProjectNetworks, restartRequired, specifyIpRanges, vpcId, tags, display, vlanId, associatedNetworkId), searchFilter, path, isRecursive));
|
getAccountSpecificNetworksByDomainPathSearchCriteria(sb, path, isRecursive,
|
||||||
|
skipProjectNetworks));
|
||||||
}
|
}
|
||||||
if (Arrays.asList(Network.NetworkFilter.Domain, Network.NetworkFilter.AccountDomain, Network.NetworkFilter.All).contains(networkFilter)) {
|
if (Arrays.asList(Network.NetworkFilter.Domain, Network.NetworkFilter.AccountDomain, Network.NetworkFilter.All).contains(networkFilter)) {
|
||||||
//add domain specific networks of domain + parent domains
|
//add domain specific networks of domain + parent domains
|
||||||
networksToReturn.addAll(listDomainSpecificNetworksByDomainPath(buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, networkOfferingId,
|
SearchCriteria<NetworkVO> domainSpecificNetworksByDomainPathSC =
|
||||||
aclType, true, restartRequired, specifyIpRanges, vpcId, tags, display, vlanId, associatedNetworkId), searchFilter, path, isRecursive));
|
getDomainSpecificNetworksByDomainPathSearchCriteria(sb, path, isRecursive);
|
||||||
|
if (domainSpecificNetworksByDomainPathSC != null) {
|
||||||
|
additionalSearchCriteria.addOr("id", SearchCriteria.Op.SC, domainSpecificNetworksByDomainPathSC);
|
||||||
|
}
|
||||||
//add networks of subdomains
|
//add networks of subdomains
|
||||||
if (domainId == null) {
|
if (domainId == null) {
|
||||||
networksToReturn.addAll(listDomainLevelNetworks(buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, networkOfferingId,
|
SearchCriteria<NetworkVO> domainLevelSC = getDomainLevelNetworksSearchCriteria(sb, caller.getDomainId(), true);
|
||||||
aclType, true, restartRequired, specifyIpRanges, vpcId, tags, display, vlanId, associatedNetworkId), searchFilter, caller.getDomainId(), true));
|
if (domainLevelSC != null) {
|
||||||
|
additionalSearchCriteria.addOr("id", SearchCriteria.Op.SC, domainLevelSC);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Arrays.asList(Network.NetworkFilter.Shared, Network.NetworkFilter.All).contains(networkFilter)) {
|
if (Arrays.asList(Network.NetworkFilter.Shared, Network.NetworkFilter.All).contains(networkFilter)) {
|
||||||
// get shared networks
|
// get shared networks
|
||||||
List<NetworkVO> sharedNetworks = listSharedNetworksByDomainPath(buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, networkOfferingId,
|
SearchCriteria<NetworkVO> sharedNetworksSC = getSharedNetworksByDomainPathSearchCriteria(sb, path, isRecursive);
|
||||||
aclType, true, restartRequired, specifyIpRanges, vpcId, tags, display, vlanId, associatedNetworkId), searchFilter, path, isRecursive);
|
if (sharedNetworksSC != null) {
|
||||||
addNetworksToReturnIfNotExist(networksToReturn, sharedNetworks);
|
additionalSearchCriteria.addOr("id", SearchCriteria.Op.SC, sharedNetworksSC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (CollectionUtils.isNotEmpty(additionalSearchCriteria.getValues())) {
|
||||||
|
mainSearchCriteria.addAnd("id", SearchCriteria.Op.SC, additionalSearchCriteria);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
networksToReturn = _networksDao.search(buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, networkOfferingId,
|
if (skipProjectNetworks) {
|
||||||
null, true, restartRequired, specifyIpRanges, vpcId, tags, display, vlanId, associatedNetworkId), searchFilter);
|
mainSearchCriteria.setJoinParameters("accountSearch", "typeNEQ", Account.Type.PROJECT);
|
||||||
|
} else {
|
||||||
|
mainSearchCriteria.setJoinParameters("accountSearch", "typeEQ", Account.Type.PROJECT);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
Pair<List<NetworkVO>, Integer> result = _networksDao.searchAndCount(mainSearchCriteria, searchFilter);
|
||||||
|
List<NetworkVO> networksToReturn = result.first();
|
||||||
|
|
||||||
if (supportedServicesStr != null && !supportedServicesStr.isEmpty() && !networksToReturn.isEmpty()) {
|
if (supportedServicesStr != null && !supportedServicesStr.isEmpty() && !networksToReturn.isEmpty()) {
|
||||||
List<NetworkVO> supportedNetworks = new ArrayList<NetworkVO>();
|
List<NetworkVO> supportedNetworks = new ArrayList<>();
|
||||||
Service[] suppportedServices = new Service[supportedServicesStr.size()];
|
Service[] supportedServices = new Service[supportedServicesStr.size()];
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (String supportedServiceStr : supportedServicesStr) {
|
for (String supportedServiceStr : supportedServicesStr) {
|
||||||
Service service = Service.getService(supportedServiceStr);
|
Service service = Service.getService(supportedServiceStr);
|
||||||
if (service == null) {
|
if (service == null) {
|
||||||
throw new InvalidParameterValueException("Invalid service specified " + supportedServiceStr);
|
throw new InvalidParameterValueException("Invalid service specified " + supportedServiceStr);
|
||||||
} else {
|
} else {
|
||||||
suppportedServices[i] = service;
|
supportedServices[i] = service;
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (NetworkVO network : networksToReturn) {
|
for (NetworkVO network : networksToReturn) {
|
||||||
if (areServicesSupportedInNetwork(network.getId(), suppportedServices)) {
|
if (areServicesSupportedInNetwork(network.getId(), supportedServices)) {
|
||||||
supportedNetworks.add(network);
|
supportedNetworks.add(network);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
networksToReturn = supportedNetworks;
|
networksToReturn = supportedNetworks;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canUseForDeploy != null) {
|
if (canUseForDeploy != null) {
|
||||||
List<NetworkVO> networksForDeploy = new ArrayList<NetworkVO>();
|
List<NetworkVO> networksForDeploy = new ArrayList<>();
|
||||||
for (NetworkVO network : networksToReturn) {
|
for (NetworkVO network : networksToReturn) {
|
||||||
if (_networkModel.canUseForDeploy(network) == canUseForDeploy) {
|
if (_networkModel.canUseForDeploy(network) == canUseForDeploy) {
|
||||||
networksForDeploy.add(network);
|
networksForDeploy.add(network);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
networksToReturn = networksForDeploy;
|
networksToReturn = networksForDeploy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (applyManualPagination) {
|
||||||
//Now apply pagination
|
//Now apply pagination
|
||||||
List<? extends Network> wPagination = com.cloud.utils.StringUtils.applyPagination(networksToReturn, cmd.getStartIndex(), cmd.getPageSizeVal());
|
List<? extends Network> wPagination = com.cloud.utils.StringUtils.applyPagination(networksToReturn, cmd.getStartIndex(), cmd.getPageSizeVal());
|
||||||
if (wPagination != null) {
|
if (wPagination != null) {
|
||||||
Pair<List<? extends Network>, Integer> listWPagination = new Pair<List<? extends Network>, Integer>(wPagination, networksToReturn.size());
|
Pair<List<? extends Network>, Integer> listWPagination = new Pair<>(wPagination, networksToReturn.size());
|
||||||
return listWPagination;
|
return listWPagination;
|
||||||
}
|
}
|
||||||
|
return new Pair<>(networksToReturn, networksToReturn.size());
|
||||||
return new Pair<List<? extends Network>, Integer>(networksToReturn, networksToReturn.size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addNetworksToReturnIfNotExist(final List<NetworkVO> networksToReturn, final List<NetworkVO> sharedNetworks) {
|
return new Pair<>(result.first(), result.second());
|
||||||
Set<Long> networkIds = networksToReturn.stream()
|
|
||||||
.map(NetworkVO::getId)
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
List<NetworkVO> sharedNetworksToReturn = sharedNetworks.stream()
|
|
||||||
.filter(network -> ! networkIds.contains(network.getId()))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
networksToReturn.addAll(sharedNetworksToReturn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private SearchCriteria<NetworkVO> buildNetworkSearchCriteria(SearchBuilder<NetworkVO> sb, String keyword, Long id,
|
private SearchCriteria<NetworkVO> createNetworkSearchCriteria(SearchBuilder<NetworkVO> sb, String keyword, Long id,
|
||||||
Boolean isSystem, Long zoneId, String guestIpType, String trafficType, Long physicalNetworkId,
|
Boolean isSystem, Long zoneId, String guestIpType, String trafficType, Long physicalNetworkId,
|
||||||
Long networkOfferingId, String aclType, boolean skipProjectNetworks, Boolean restartRequired,
|
Long networkOfferingId, String aclType, Boolean restartRequired,
|
||||||
Boolean specifyIpRanges, Long vpcId, Map<String, String> tags, Boolean display, String vlanId, Long associatedNetworkId) {
|
Boolean specifyIpRanges, Long vpcId, Map<String, String> tags, Boolean display, String vlanId, Long associatedNetworkId) {
|
||||||
|
|
||||||
SearchCriteria<NetworkVO> sc = sb.create();
|
SearchCriteria<NetworkVO> sc = sb.create();
|
||||||
@ -2566,12 +2587,6 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
|
|||||||
sc.addAnd("physicalNetworkId", SearchCriteria.Op.EQ, physicalNetworkId);
|
sc.addAnd("physicalNetworkId", SearchCriteria.Op.EQ, physicalNetworkId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (skipProjectNetworks) {
|
|
||||||
sc.setJoinParameters("accountSearch", "typeNEQ", Account.Type.PROJECT);
|
|
||||||
} else {
|
|
||||||
sc.setJoinParameters("accountSearch", "typeEQ", Account.Type.PROJECT);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (restartRequired != null) {
|
if (restartRequired != null) {
|
||||||
sc.addAnd("restartRequired", SearchCriteria.Op.EQ, restartRequired);
|
sc.addAnd("restartRequired", SearchCriteria.Op.EQ, restartRequired);
|
||||||
}
|
}
|
||||||
@ -2612,8 +2627,8 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
|
|||||||
return sc;
|
return sc;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<NetworkVO> listDomainLevelNetworks(SearchCriteria<NetworkVO> sc, Filter searchFilter, long domainId, boolean parentDomainsOnly) {
|
private SearchCriteria<NetworkVO> getDomainLevelNetworksSearchCriteria(SearchBuilder<NetworkVO> sb, long domainId, boolean parentDomainsOnly) {
|
||||||
List<Long> networkIds = new ArrayList<Long>();
|
List<Long> networkIds = new ArrayList<>();
|
||||||
Set<Long> allowedDomains = _domainMgr.getDomainParentIds(domainId);
|
Set<Long> allowedDomains = _domainMgr.getDomainParentIds(domainId);
|
||||||
List<NetworkDomainVO> maps = _networkDomainDao.listDomainNetworkMapByDomain(allowedDomains.toArray());
|
List<NetworkDomainVO> maps = _networkDomainDao.listDomainNetworkMapByDomain(allowedDomains.toArray());
|
||||||
|
|
||||||
@ -2628,48 +2643,55 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!networkIds.isEmpty()) {
|
if (!networkIds.isEmpty()) {
|
||||||
SearchCriteria<NetworkVO> domainSC = _networksDao.createSearchCriteria();
|
SearchCriteria<NetworkVO> domainSC = sb.create();
|
||||||
|
domainSC.setJoinParameters("accountSearch", "typeNEQ", Account.Type.PROJECT);
|
||||||
domainSC.addAnd("id", SearchCriteria.Op.IN, networkIds.toArray());
|
domainSC.addAnd("id", SearchCriteria.Op.IN, networkIds.toArray());
|
||||||
domainSC.addAnd("aclType", SearchCriteria.Op.EQ, ACLType.Domain.toString());
|
domainSC.addAnd("aclType", SearchCriteria.Op.EQ, ACLType.Domain.toString());
|
||||||
|
return domainSC;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
sc.addAnd("id", SearchCriteria.Op.SC, domainSC);
|
private SearchCriteria<NetworkVO> getAccountSpecificNetworksSearchCriteria(SearchBuilder<NetworkVO> sb,
|
||||||
return _networksDao.search(sc, searchFilter);
|
List<Long> permittedAccounts, boolean skipProjectNetworks) {
|
||||||
|
SearchCriteria<NetworkVO> accountSC = sb.create();
|
||||||
|
if (skipProjectNetworks) {
|
||||||
|
accountSC.setJoinParameters("accountSearch", "typeNEQ", Account.Type.PROJECT);
|
||||||
} else {
|
} else {
|
||||||
return new ArrayList<NetworkVO>();
|
accountSC.setJoinParameters("accountSearch", "typeEQ", Account.Type.PROJECT);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private List<NetworkVO> listAccountSpecificNetworks(SearchCriteria<NetworkVO> sc, Filter searchFilter, List<Long> permittedAccounts) {
|
|
||||||
SearchCriteria<NetworkVO> accountSC = _networksDao.createSearchCriteria();
|
|
||||||
if (!permittedAccounts.isEmpty()) {
|
if (!permittedAccounts.isEmpty()) {
|
||||||
accountSC.addAnd("accountId", SearchCriteria.Op.IN, permittedAccounts.toArray());
|
accountSC.addAnd("accountId", SearchCriteria.Op.IN, permittedAccounts.toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
accountSC.addAnd("aclType", SearchCriteria.Op.EQ, ACLType.Account.toString());
|
accountSC.addAnd("aclType", SearchCriteria.Op.EQ, ACLType.Account.toString());
|
||||||
|
return accountSC;
|
||||||
sc.addAnd("id", SearchCriteria.Op.SC, accountSC);
|
|
||||||
return _networksDao.search(sc, searchFilter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<NetworkVO> listAccountSpecificNetworksByDomainPath(SearchCriteria<NetworkVO> sc, Filter searchFilter, String path, boolean isRecursive) {
|
private SearchCriteria<NetworkVO> getAccountSpecificNetworksByDomainPathSearchCriteria(SearchBuilder<NetworkVO> sb,
|
||||||
SearchCriteria<NetworkVO> accountSC = _networksDao.createSearchCriteria();
|
String path, boolean isRecursive, boolean skipProjectNetworks) {
|
||||||
|
SearchCriteria<NetworkVO> accountSC = sb.create();
|
||||||
|
if (skipProjectNetworks) {
|
||||||
|
accountSC.setJoinParameters("accountSearch", "typeNEQ", Account.Type.PROJECT);
|
||||||
|
} else {
|
||||||
|
accountSC.setJoinParameters("accountSearch", "typeEQ", Account.Type.PROJECT);
|
||||||
|
}
|
||||||
accountSC.addAnd("aclType", SearchCriteria.Op.EQ, ACLType.Account.toString());
|
accountSC.addAnd("aclType", SearchCriteria.Op.EQ, ACLType.Account.toString());
|
||||||
|
|
||||||
if (path != null) {
|
if (path != null) {
|
||||||
if (isRecursive) {
|
if (isRecursive) {
|
||||||
sc.setJoinParameters("domainSearch", "path", path + "%");
|
accountSC.setJoinParameters("domainSearch", "path", path + "%");
|
||||||
} else {
|
} else {
|
||||||
sc.setJoinParameters("domainSearch", "path", path);
|
accountSC.setJoinParameters("domainSearch", "path", path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sc.addAnd("id", SearchCriteria.Op.SC, accountSC);
|
return accountSC;
|
||||||
return _networksDao.search(sc, searchFilter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<NetworkVO> listDomainSpecificNetworksByDomainPath(SearchCriteria<NetworkVO> sc, Filter searchFilter, String path, boolean isRecursive) {
|
private SearchCriteria<NetworkVO> getDomainSpecificNetworksByDomainPathSearchCriteria(SearchBuilder<NetworkVO> sb,
|
||||||
|
String path, boolean isRecursive) {
|
||||||
|
|
||||||
Set<Long> allowedDomains = new HashSet<Long>();
|
Set<Long> allowedDomains = new HashSet<>();
|
||||||
if (path != null) {
|
if (path != null) {
|
||||||
if (isRecursive) {
|
if (isRecursive) {
|
||||||
allowedDomains = _domainMgr.getDomainChildrenIds(path);
|
allowedDomains = _domainMgr.getDomainChildrenIds(path);
|
||||||
@ -2679,7 +2701,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Long> networkIds = new ArrayList<Long>();
|
List<Long> networkIds = new ArrayList<>();
|
||||||
|
|
||||||
List<NetworkDomainVO> maps = _networkDomainDao.listDomainNetworkMapByDomain(allowedDomains.toArray());
|
List<NetworkDomainVO> maps = _networkDomainDao.listDomainNetworkMapByDomain(allowedDomains.toArray());
|
||||||
|
|
||||||
@ -2688,30 +2710,28 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!networkIds.isEmpty()) {
|
if (!networkIds.isEmpty()) {
|
||||||
SearchCriteria<NetworkVO> domainSC = _networksDao.createSearchCriteria();
|
SearchCriteria<NetworkVO> domainSC = sb.create();
|
||||||
|
domainSC.setJoinParameters("accountSearch", "typeNEQ", Account.Type.PROJECT);
|
||||||
domainSC.addAnd("id", SearchCriteria.Op.IN, networkIds.toArray());
|
domainSC.addAnd("id", SearchCriteria.Op.IN, networkIds.toArray());
|
||||||
domainSC.addAnd("aclType", SearchCriteria.Op.EQ, ACLType.Domain.toString());
|
domainSC.addAnd("aclType", SearchCriteria.Op.EQ, ACLType.Domain.toString());
|
||||||
|
return domainSC;
|
||||||
sc.addAnd("id", SearchCriteria.Op.SC, domainSC);
|
|
||||||
return _networksDao.search(sc, searchFilter);
|
|
||||||
} else {
|
|
||||||
return new ArrayList<NetworkVO>();
|
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<NetworkVO> listSharedNetworks(SearchCriteria<NetworkVO> sc, Filter searchFilter, List<Long> permittedAccounts) {
|
private SearchCriteria<NetworkVO> getSharedNetworksSearchCriteria(SearchBuilder<NetworkVO> sb, List<Long> permittedAccounts) {
|
||||||
List<Long> sharedNetworkIds = _networkPermissionDao.listPermittedNetworkIdsByAccounts(permittedAccounts);
|
List<Long> sharedNetworkIds = _networkPermissionDao.listPermittedNetworkIdsByAccounts(permittedAccounts);
|
||||||
if (!sharedNetworkIds.isEmpty()) {
|
if (!sharedNetworkIds.isEmpty()) {
|
||||||
SearchCriteria<NetworkVO> ssc = _networksDao.createSearchCriteria();
|
SearchCriteria<NetworkVO> ssc = sb.create();
|
||||||
|
ssc.setJoinParameters("accountSearch", "typeNEQ", Account.Type.PROJECT);
|
||||||
ssc.addAnd("id", SearchCriteria.Op.IN, sharedNetworkIds.toArray());
|
ssc.addAnd("id", SearchCriteria.Op.IN, sharedNetworkIds.toArray());
|
||||||
sc.addAnd("id", SearchCriteria.Op.SC, ssc);
|
return ssc;
|
||||||
return _networksDao.search(sc, searchFilter);
|
|
||||||
}
|
}
|
||||||
return new ArrayList<NetworkVO>();
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<NetworkVO> listSharedNetworksByDomainPath(SearchCriteria<NetworkVO> sc, Filter searchFilter, String path, boolean isRecursive) {
|
private SearchCriteria<NetworkVO> getSharedNetworksByDomainPathSearchCriteria(SearchBuilder<NetworkVO> sb, String path, boolean isRecursive) {
|
||||||
Set<Long> allowedDomains = new HashSet<Long>();
|
Set<Long> allowedDomains = new HashSet<>();
|
||||||
if (path != null) {
|
if (path != null) {
|
||||||
if (isRecursive) {
|
if (isRecursive) {
|
||||||
allowedDomains = _domainMgr.getDomainChildrenIds(path);
|
allowedDomains = _domainMgr.getDomainChildrenIds(path);
|
||||||
@ -2733,13 +2753,13 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
|
|||||||
|
|
||||||
List<Long> sharedNetworkIds = _networkPermissionDao.listPermittedNetworkIdsByAccounts(allowedAccountsList);
|
List<Long> sharedNetworkIds = _networkPermissionDao.listPermittedNetworkIdsByAccounts(allowedAccountsList);
|
||||||
if (!sharedNetworkIds.isEmpty()) {
|
if (!sharedNetworkIds.isEmpty()) {
|
||||||
SearchCriteria<NetworkVO> ssc = _networksDao.createSearchCriteria();
|
SearchCriteria<NetworkVO> ssc = sb.create();
|
||||||
|
ssc.setJoinParameters("accountSearch", "typeNEQ", Account.Type.PROJECT);
|
||||||
ssc.addAnd("id", SearchCriteria.Op.IN, sharedNetworkIds.toArray());
|
ssc.addAnd("id", SearchCriteria.Op.IN, sharedNetworkIds.toArray());
|
||||||
sc.addAnd("id", SearchCriteria.Op.SC, ssc);
|
return ssc;
|
||||||
return _networksDao.search(sc, searchFilter);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new ArrayList<NetworkVO>();
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -444,6 +444,7 @@ public abstract class GuestNetworkGuru extends AdapterBase implements NetworkGur
|
|||||||
} else {
|
} else {
|
||||||
guestIp = _ipAddrMgr.acquireGuestIpAddress(network, nic.getRequestedIPv4());
|
guestIp = _ipAddrMgr.acquireGuestIpAddress(network, nic.getRequestedIPv4());
|
||||||
}
|
}
|
||||||
|
nic.setIpv4AllocationRaceCheck(true);
|
||||||
}
|
}
|
||||||
if (guestIp == null && network.getGuestType() != GuestType.L2 && !_networkModel.listNetworkOfferingServices(network.getNetworkOfferingId()).isEmpty()) {
|
if (guestIp == null && network.getGuestType() != GuestType.L2 && !_networkModel.listNetworkOfferingServices(network.getNetworkOfferingId()).isEmpty()) {
|
||||||
throw new InsufficientVirtualNetworkCapacityException("Unable to acquire Guest IP" + " address for network " + network, DataCenter.class,
|
throw new InsufficientVirtualNetworkCapacityException("Unable to acquire Guest IP" + " address for network " + network, DataCenter.class,
|
||||||
|
|||||||
@ -122,6 +122,7 @@ import com.cloud.dc.dao.DataCenterDao;
|
|||||||
import com.cloud.dc.dao.HostPodDao;
|
import com.cloud.dc.dao.HostPodDao;
|
||||||
import com.cloud.dc.dao.VlanDao;
|
import com.cloud.dc.dao.VlanDao;
|
||||||
import com.cloud.deploy.DeployDestination;
|
import com.cloud.deploy.DeployDestination;
|
||||||
|
import com.cloud.deploy.DeploymentPlanner;
|
||||||
import com.cloud.domain.Domain;
|
import com.cloud.domain.Domain;
|
||||||
import com.cloud.event.ActionEvent;
|
import com.cloud.event.ActionEvent;
|
||||||
import com.cloud.event.ActionEventUtils;
|
import com.cloud.event.ActionEventUtils;
|
||||||
@ -2439,7 +2440,7 @@ Configurable, StateListener<VirtualMachine.State, VirtualMachine.Event, VirtualM
|
|||||||
protected void finalizeNetworkRulesForNetwork(final Commands cmds, final DomainRouterVO router, final Provider provider, final Long guestNetworkId) {
|
protected void finalizeNetworkRulesForNetwork(final Commands cmds, final DomainRouterVO router, final Provider provider, final Long guestNetworkId) {
|
||||||
logger.debug("Resending ipAssoc, port forwarding, load balancing rules as a part of Virtual router start");
|
logger.debug("Resending ipAssoc, port forwarding, load balancing rules as a part of Virtual router start");
|
||||||
|
|
||||||
final ArrayList<? extends PublicIpAddress> publicIps = getPublicIpsToApply(router, provider, guestNetworkId);
|
final ArrayList<? extends PublicIpAddress> publicIps = getPublicIpsToApply(provider, guestNetworkId);
|
||||||
final List<FirewallRule> firewallRulesEgress = new ArrayList<FirewallRule>();
|
final List<FirewallRule> firewallRulesEgress = new ArrayList<FirewallRule>();
|
||||||
final List<FirewallRule> ipv6firewallRules = new ArrayList<>();
|
final List<FirewallRule> ipv6firewallRules = new ArrayList<>();
|
||||||
|
|
||||||
@ -2646,7 +2647,7 @@ Configurable, StateListener<VirtualMachine.State, VirtualMachine.Event, VirtualM
|
|||||||
protected void finalizeIpAssocForNetwork(final Commands cmds, final VirtualRouter router, final Provider provider, final Long guestNetworkId,
|
protected void finalizeIpAssocForNetwork(final Commands cmds, final VirtualRouter router, final Provider provider, final Long guestNetworkId,
|
||||||
final Map<String, String> vlanMacAddress) {
|
final Map<String, String> vlanMacAddress) {
|
||||||
|
|
||||||
final ArrayList<? extends PublicIpAddress> publicIps = getPublicIpsToApply(router, provider, guestNetworkId);
|
final ArrayList<? extends PublicIpAddress> publicIps = getPublicIpsToApply(provider, guestNetworkId);
|
||||||
|
|
||||||
if (publicIps != null && !publicIps.isEmpty()) {
|
if (publicIps != null && !publicIps.isEmpty()) {
|
||||||
logger.debug("Found " + publicIps.size() + " ip(s) to apply as a part of domR " + router + " start.");
|
logger.debug("Found " + publicIps.size() + " ip(s) to apply as a part of domR " + router + " start.");
|
||||||
@ -2657,18 +2658,10 @@ Configurable, StateListener<VirtualMachine.State, VirtualMachine.Event, VirtualM
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ArrayList<? extends PublicIpAddress> getPublicIpsToApply(final VirtualRouter router, final Provider provider, final Long guestNetworkId,
|
protected ArrayList<? extends PublicIpAddress> getPublicIpsToApply(final Provider provider, final Long guestNetworkId,
|
||||||
final com.cloud.network.IpAddress.State... skipInStates) {
|
final com.cloud.network.IpAddress.State... skipInStates) {
|
||||||
final long ownerId = router.getAccountId();
|
|
||||||
final List<? extends IpAddress> userIps;
|
|
||||||
|
|
||||||
final Network guestNetwork = _networkDao.findById(guestNetworkId);
|
final List<? extends IpAddress> userIps = _networkModel.listPublicIpsAssignedToGuestNtwk(guestNetworkId, null);
|
||||||
if (guestNetwork.getGuestType() == GuestType.Shared) {
|
|
||||||
// ignore the account id for the shared network
|
|
||||||
userIps = _networkModel.listPublicIpsAssignedToGuestNtwk(guestNetworkId, null);
|
|
||||||
} else {
|
|
||||||
userIps = _networkModel.listPublicIpsAssignedToGuestNtwk(ownerId, guestNetworkId, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<PublicIp> allPublicIps = new ArrayList<PublicIp>();
|
final List<PublicIp> allPublicIps = new ArrayList<PublicIp>();
|
||||||
if (userIps != null && !userIps.isEmpty()) {
|
if (userIps != null && !userIps.isEmpty()) {
|
||||||
@ -3008,6 +3001,14 @@ Configurable, StateListener<VirtualMachine.State, VirtualMachine.Event, VirtualM
|
|||||||
return virtualRouter;
|
return virtualRouter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@ActionEvent(eventType = EventTypes.EVENT_ROUTER_START, eventDescription = "restarting router VM for HA", async = true)
|
||||||
|
public void startRouterForHA(VirtualMachine vm, Map<Param, Object> params, DeploymentPlanner planner)
|
||||||
|
throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException,
|
||||||
|
OperationTimedoutException {
|
||||||
|
_itMgr.advanceStart(vm.getUuid(), params, planner);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<VirtualRouter> getRoutersForNetwork(final long networkId) {
|
public List<VirtualRouter> getRoutersForNetwork(final long networkId) {
|
||||||
final List<DomainRouterVO> routers = _routerDao.findByNetwork(networkId);
|
final List<DomainRouterVO> routers = _routerDao.findByNetwork(networkId);
|
||||||
|
|||||||
@ -757,7 +757,7 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (domainRouterVO.getState() == State.Starting || domainRouterVO.getState() == State.Running) {
|
if (domainRouterVO.getState() == State.Starting || domainRouterVO.getState() == State.Running) {
|
||||||
final ArrayList<? extends PublicIpAddress> publicIps = getPublicIpsToApply(domainRouterVO, provider, guestNetworkId, IpAddress.State.Releasing);
|
final ArrayList<? extends PublicIpAddress> publicIps = getPublicIpsToApply(provider, guestNetworkId, IpAddress.State.Releasing);
|
||||||
|
|
||||||
if (publicIps != null && !publicIps.isEmpty()) {
|
if (publicIps != null && !publicIps.isEmpty()) {
|
||||||
logger.debug("Found " + publicIps.size() + " ip(s) to apply as a part of domR " + domainRouterVO + " start.");
|
logger.debug("Found " + publicIps.size() + " ip(s) to apply as a part of domR " + domainRouterVO + " start.");
|
||||||
|
|||||||
@ -3371,6 +3371,15 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
|
|||||||
return sc.list();
|
return sc.list();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<HostVO> listAllUpHostsInOneZoneByHypervisor(final HypervisorType type, final long dcId) {
|
||||||
|
final QueryBuilder<HostVO> sc = QueryBuilder.create(HostVO.class);
|
||||||
|
sc.and(sc.entity().getHypervisorType(), Op.EQ, type);
|
||||||
|
sc.and(sc.entity().getDataCenterId(), Op.EQ, dcId);
|
||||||
|
sc.and(sc.entity().getStatus(), Op.EQ, Status.Up);
|
||||||
|
return sc.list();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<HostVO> listAllUpAndEnabledHostsInOneZone(final long dcId) {
|
public List<HostVO> listAllUpAndEnabledHostsInOneZone(final long dcId) {
|
||||||
final QueryBuilder<HostVO> sc = QueryBuilder.create(HostVO.class);
|
final QueryBuilder<HostVO> sc = QueryBuilder.create(HostVO.class);
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
package com.cloud.server;
|
package com.cloud.server;
|
||||||
|
|
||||||
|
import static com.cloud.configuration.ConfigurationManagerImpl.DELETE_QUERY_BATCH_SIZE;
|
||||||
import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
|
import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
|
||||||
|
|
||||||
import java.lang.management.ManagementFactory;
|
import java.lang.management.ManagementFactory;
|
||||||
@ -282,11 +283,6 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
|
|||||||
protected static ConfigKey<Boolean> vmStatsCollectUserVMOnly = new ConfigKey<>("Advanced", Boolean.class, "vm.stats.user.vm.only", "false",
|
protected static ConfigKey<Boolean> vmStatsCollectUserVMOnly = new ConfigKey<>("Advanced", Boolean.class, "vm.stats.user.vm.only", "false",
|
||||||
"When set to 'false' stats for system VMs will be collected otherwise stats collection will be done only for user VMs", true);
|
"When set to 'false' stats for system VMs will be collected otherwise stats collection will be done only for user VMs", true);
|
||||||
|
|
||||||
protected static ConfigKey<Long> vmStatsRemoveBatchSize = new ConfigKey<>("Advanced", Long.class, "vm.stats.remove.batch.size", "0", "Indicates the" +
|
|
||||||
" limit applied to delete vm_stats entries while running the clean-up task. With this, ACS will run the delete query, applying the limit, as many times as necessary" +
|
|
||||||
" to delete all entries older than the value defined in vm.stats.max.retention.time. This is advised when retaining several days of records, which can lead to slowness" +
|
|
||||||
" on the delete query. Zero (0) means that no limit will be applied, therefore, the query will run once and without limit, keeping the default behavior.", true);
|
|
||||||
|
|
||||||
protected static ConfigKey<Boolean> vmDiskStatsRetentionEnabled = new ConfigKey<>("Advanced", Boolean.class, "vm.disk.stats.retention.enabled", "false",
|
protected static ConfigKey<Boolean> vmDiskStatsRetentionEnabled = new ConfigKey<>("Advanced", Boolean.class, "vm.disk.stats.retention.enabled", "false",
|
||||||
"When set to 'true' stats for VM disks will be stored in the database otherwise disk stats will not be stored", true);
|
"When set to 'true' stats for VM disks will be stored in the database otherwise disk stats will not be stored", true);
|
||||||
|
|
||||||
@ -1965,7 +1961,7 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
|
|||||||
logger.trace("Removing older VM stats records.");
|
logger.trace("Removing older VM stats records.");
|
||||||
Date now = new Date();
|
Date now = new Date();
|
||||||
Date limit = DateUtils.addMinutes(now, -maxRetentionTime);
|
Date limit = DateUtils.addMinutes(now, -maxRetentionTime);
|
||||||
vmStatsDao.removeAllByTimestampLessThan(limit, vmStatsRemoveBatchSize.value());
|
vmStatsDao.removeAllByTimestampLessThan(limit, DELETE_QUERY_BATCH_SIZE.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1984,7 +1980,7 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
|
|||||||
logger.trace("Removing older Volume stats records.");
|
logger.trace("Removing older Volume stats records.");
|
||||||
Date now = new Date();
|
Date now = new Date();
|
||||||
Date limit = DateUtils.addMinutes(now, -maxRetentionTime);
|
Date limit = DateUtils.addMinutes(now, -maxRetentionTime);
|
||||||
volumeStatsDao.removeAllByTimestampLessThan(limit);
|
volumeStatsDao.removeAllByTimestampLessThan(limit, DELETE_QUERY_BATCH_SIZE.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2139,7 +2135,7 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConfigKey<?>[] getConfigKeys() {
|
public ConfigKey<?>[] getConfigKeys() {
|
||||||
return new ConfigKey<?>[] {vmDiskStatsInterval, vmDiskStatsIntervalMin, vmNetworkStatsInterval, vmNetworkStatsIntervalMin, StatsTimeout, statsOutputUri, vmStatsRemoveBatchSize,
|
return new ConfigKey<?>[] {vmDiskStatsInterval, vmDiskStatsIntervalMin, vmNetworkStatsInterval, vmNetworkStatsIntervalMin, StatsTimeout, statsOutputUri,
|
||||||
vmStatsIncrementMetrics, vmStatsMaxRetentionTime, vmStatsCollectUserVMOnly, vmDiskStatsRetentionEnabled, vmDiskStatsMaxRetentionTime,
|
vmStatsIncrementMetrics, vmStatsMaxRetentionTime, vmStatsCollectUserVMOnly, vmDiskStatsRetentionEnabled, vmDiskStatsMaxRetentionTime,
|
||||||
MANAGEMENT_SERVER_STATUS_COLLECTION_INTERVAL,
|
MANAGEMENT_SERVER_STATUS_COLLECTION_INTERVAL,
|
||||||
DATABASE_SERVER_STATUS_COLLECTION_INTERVAL,
|
DATABASE_SERVER_STATUS_COLLECTION_INTERVAL,
|
||||||
|
|||||||
@ -410,6 +410,8 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
|
|||||||
|
|
||||||
private final Map<String, HypervisorHostListener> hostListeners = new HashMap<>();
|
private final Map<String, HypervisorHostListener> hostListeners = new HashMap<>();
|
||||||
|
|
||||||
|
private static final String NFS_MOUNT_OPTIONS_INCORRECT = "An incorrect mount option was specified";
|
||||||
|
|
||||||
public boolean share(VMInstanceVO vm, List<VolumeVO> vols, HostVO host, boolean cancelPreviousShare) throws StorageUnavailableException {
|
public boolean share(VMInstanceVO vm, List<VolumeVO> vols, HostVO host, boolean cancelPreviousShare) throws StorageUnavailableException {
|
||||||
|
|
||||||
// if pool is in maintenance and it is the ONLY pool available; reject
|
// if pool is in maintenance and it is the ONLY pool available; reject
|
||||||
@ -836,6 +838,53 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
|
|||||||
return String.format("%s-%s-%s", StringUtils.trim(host.getName()), "local", storagePoolInformation.getUuid().split("-")[0]);
|
return String.format("%s-%s-%s", StringUtils.trim(host.getName()), "local", storagePoolInformation.getUuid().split("-")[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void checkNfsMountOptions(String nfsMountOpts) throws InvalidParameterValueException {
|
||||||
|
String[] options = nfsMountOpts.replaceAll("\\s", "").split(",");
|
||||||
|
Map<String, String> optionsMap = new HashMap<>();
|
||||||
|
for (String option : options) {
|
||||||
|
String[] keyValue = option.split("=");
|
||||||
|
if (keyValue.length > 2) {
|
||||||
|
throw new InvalidParameterValueException("Invalid value for NFS option " + keyValue[0]);
|
||||||
|
}
|
||||||
|
if (optionsMap.containsKey(keyValue[0])) {
|
||||||
|
throw new InvalidParameterValueException("Duplicate NFS option values found for option " + keyValue[0]);
|
||||||
|
}
|
||||||
|
optionsMap.put(keyValue[0], null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void checkNFSMountOptionsForCreate(Map<String, String> details, HypervisorType hypervisorType, String scheme) throws InvalidParameterValueException {
|
||||||
|
if (!details.containsKey(ApiConstants.NFS_MOUNT_OPTIONS)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!hypervisorType.equals(HypervisorType.KVM) && !hypervisorType.equals(HypervisorType.Simulator)) {
|
||||||
|
throw new InvalidParameterValueException("NFS options can not be set for the hypervisor type " + hypervisorType);
|
||||||
|
}
|
||||||
|
if (!"nfs".equals(scheme)) {
|
||||||
|
throw new InvalidParameterValueException("NFS options can only be set on pool type " + StoragePoolType.NetworkFilesystem);
|
||||||
|
}
|
||||||
|
checkNfsMountOptions(details.get(ApiConstants.NFS_MOUNT_OPTIONS));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void checkNFSMountOptionsForUpdate(Map<String, String> details, StoragePoolVO pool, Long accountId) throws InvalidParameterValueException {
|
||||||
|
if (!details.containsKey(ApiConstants.NFS_MOUNT_OPTIONS)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!_accountMgr.isRootAdmin(accountId)) {
|
||||||
|
throw new PermissionDeniedException("Only root admin can modify nfs options");
|
||||||
|
}
|
||||||
|
if (!pool.getHypervisor().equals(HypervisorType.KVM) && !pool.getHypervisor().equals((HypervisorType.Simulator))) {
|
||||||
|
throw new InvalidParameterValueException("NFS options can only be set for the hypervisor type " + HypervisorType.KVM);
|
||||||
|
}
|
||||||
|
if (!pool.getPoolType().equals(StoragePoolType.NetworkFilesystem)) {
|
||||||
|
throw new InvalidParameterValueException("NFS options can only be set on pool type " + StoragePoolType.NetworkFilesystem);
|
||||||
|
}
|
||||||
|
if (!pool.isInMaintenance()) {
|
||||||
|
throw new InvalidParameterValueException("The storage pool should be in maintenance mode to edit nfs options");
|
||||||
|
}
|
||||||
|
checkNfsMountOptions(details.get(ApiConstants.NFS_MOUNT_OPTIONS));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PrimaryDataStoreInfo createPool(CreateStoragePoolCmd cmd) throws ResourceInUseException, IllegalArgumentException, UnknownHostException, ResourceUnavailableException {
|
public PrimaryDataStoreInfo createPool(CreateStoragePoolCmd cmd) throws ResourceInUseException, IllegalArgumentException, UnknownHostException, ResourceUnavailableException {
|
||||||
String providerName = cmd.getStorageProviderName();
|
String providerName = cmd.getStorageProviderName();
|
||||||
@ -900,6 +949,8 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
|
|||||||
}
|
}
|
||||||
|
|
||||||
Map<String, String> details = extractApiParamAsMap(cmd.getDetails());
|
Map<String, String> details = extractApiParamAsMap(cmd.getDetails());
|
||||||
|
checkNFSMountOptionsForCreate(details, hypervisorType, uriParams.get("scheme"));
|
||||||
|
|
||||||
DataCenterVO zone = _dcDao.findById(cmd.getZoneId());
|
DataCenterVO zone = _dcDao.findById(cmd.getZoneId());
|
||||||
if (zone == null) {
|
if (zone == null) {
|
||||||
throw new InvalidParameterValueException("unable to find zone by id " + zoneId);
|
throw new InvalidParameterValueException("unable to find zone by id " + zoneId);
|
||||||
@ -1082,6 +1133,9 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
|
|||||||
throw new IllegalArgumentException("Unable to find storage pool with ID: " + id);
|
throw new IllegalArgumentException("Unable to find storage pool with ID: " + id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<String, String> inputDetails = extractApiParamAsMap(cmd.getDetails());
|
||||||
|
checkNFSMountOptionsForUpdate(inputDetails, pool, cmd.getEntityOwnerId());
|
||||||
|
|
||||||
String name = cmd.getName();
|
String name = cmd.getName();
|
||||||
if(StringUtils.isNotBlank(name)) {
|
if(StringUtils.isNotBlank(name)) {
|
||||||
logger.debug("Updating Storage Pool name to: " + name);
|
logger.debug("Updating Storage Pool name to: " + name);
|
||||||
@ -1125,12 +1179,9 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
|
|||||||
}
|
}
|
||||||
|
|
||||||
// retrieve current details and merge/overlay input to capture changes
|
// retrieve current details and merge/overlay input to capture changes
|
||||||
Map<String, String> inputDetails = extractApiParamAsMap(cmd.getDetails());
|
|
||||||
Map<String, String> details = null;
|
Map<String, String> details = null;
|
||||||
if (inputDetails == null) {
|
|
||||||
details = _storagePoolDetailsDao.listDetailsKeyPairs(id);
|
|
||||||
} else {
|
|
||||||
details = _storagePoolDetailsDao.listDetailsKeyPairs(id);
|
details = _storagePoolDetailsDao.listDetailsKeyPairs(id);
|
||||||
|
if (inputDetails != null) {
|
||||||
details.putAll(inputDetails);
|
details.putAll(inputDetails);
|
||||||
changes = true;
|
changes = true;
|
||||||
}
|
}
|
||||||
@ -1229,6 +1280,32 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
|
|||||||
return deleteDataStoreInternal(sPool, forced);
|
return deleteDataStoreInternal(sPool, forced);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Pair<Map<String, String>, Boolean> getStoragePoolNFSMountOpts(StoragePool pool, Map<String, String> details) {
|
||||||
|
boolean details_added = false;
|
||||||
|
if (!pool.getPoolType().equals(Storage.StoragePoolType.NetworkFilesystem)) {
|
||||||
|
return new Pair<>(details, details_added);
|
||||||
|
}
|
||||||
|
|
||||||
|
StoragePoolDetailVO nfsMountOpts = _storagePoolDetailsDao.findDetail(pool.getId(), ApiConstants.NFS_MOUNT_OPTIONS);
|
||||||
|
if (nfsMountOpts != null) {
|
||||||
|
if (details == null) {
|
||||||
|
details = new HashMap<>();
|
||||||
|
}
|
||||||
|
details.put(ApiConstants.NFS_MOUNT_OPTIONS, nfsMountOpts.getValue());
|
||||||
|
details_added = true;
|
||||||
|
}
|
||||||
|
return new Pair<>(details, details_added);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStoragePoolMountFailureReason(String reason) {
|
||||||
|
if (reason.toLowerCase().contains(NFS_MOUNT_OPTIONS_INCORRECT.toLowerCase())) {
|
||||||
|
return NFS_MOUNT_OPTIONS_INCORRECT;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean checkIfDataStoreClusterCanbeDeleted(StoragePoolVO sPool, boolean forced) {
|
private boolean checkIfDataStoreClusterCanbeDeleted(StoragePoolVO sPool, boolean forced) {
|
||||||
List<StoragePoolVO> childStoragePools = _storagePoolDao.listChildStoragePoolsInDatastoreCluster(sPool.getId());
|
List<StoragePoolVO> childStoragePools = _storagePoolDao.listChildStoragePoolsInDatastoreCluster(sPool.getId());
|
||||||
boolean canDelete = true;
|
boolean canDelete = true;
|
||||||
@ -3796,7 +3873,6 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
|
|||||||
MountDisabledStoragePool,
|
MountDisabledStoragePool,
|
||||||
VmwareCreateCloneFull,
|
VmwareCreateCloneFull,
|
||||||
VmwareAllowParallelExecution,
|
VmwareAllowParallelExecution,
|
||||||
ConvertVmwareInstanceToKvmTimeout,
|
|
||||||
DataStoreDownloadFollowRedirects
|
DataStoreDownloadFollowRedirects
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,6 +20,7 @@ package com.cloud.storage;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
@ -28,6 +29,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
|||||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager;
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager;
|
||||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||||
|
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
@ -49,6 +51,7 @@ import com.cloud.storage.dao.VolumeDao;
|
|||||||
import com.cloud.user.Account;
|
import com.cloud.user.Account;
|
||||||
import com.cloud.user.User;
|
import com.cloud.user.User;
|
||||||
import com.cloud.user.dao.UserDao;
|
import com.cloud.user.dao.UserDao;
|
||||||
|
import com.cloud.utils.Pair;
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
import com.cloud.vm.ConsoleProxyVO;
|
import com.cloud.vm.ConsoleProxyVO;
|
||||||
import com.cloud.vm.DomainRouterVO;
|
import com.cloud.vm.DomainRouterVO;
|
||||||
@ -89,6 +92,8 @@ public class StoragePoolAutomationImpl implements StoragePoolAutomation {
|
|||||||
@Inject
|
@Inject
|
||||||
PrimaryDataStoreDao primaryDataStoreDao;
|
PrimaryDataStoreDao primaryDataStoreDao;
|
||||||
@Inject
|
@Inject
|
||||||
|
StoragePoolDetailsDao storagePoolDetailsDao;
|
||||||
|
@Inject
|
||||||
DataStoreManager dataStoreMgr;
|
DataStoreManager dataStoreMgr;
|
||||||
@Inject
|
@Inject
|
||||||
protected ResourceManager _resourceMgr;
|
protected ResourceManager _resourceMgr;
|
||||||
@ -319,14 +324,25 @@ public class StoragePoolAutomationImpl implements StoragePoolAutomation {
|
|||||||
if (hosts == null || hosts.size() == 0) {
|
if (hosts == null || hosts.size() == 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Pair<Map<String, String>, Boolean> nfsMountOpts = storageManager.getStoragePoolNFSMountOpts(pool, null);
|
||||||
// add heartbeat
|
// add heartbeat
|
||||||
for (HostVO host : hosts) {
|
for (HostVO host : hosts) {
|
||||||
ModifyStoragePoolCommand msPoolCmd = new ModifyStoragePoolCommand(true, pool);
|
ModifyStoragePoolCommand msPoolCmd = new ModifyStoragePoolCommand(true, pool, nfsMountOpts.first());
|
||||||
final Answer answer = agentMgr.easySend(host.getId(), msPoolCmd);
|
final Answer answer = agentMgr.easySend(host.getId(), msPoolCmd);
|
||||||
if (answer == null || !answer.getResult()) {
|
if (answer == null || !answer.getResult()) {
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("ModifyStoragePool add failed due to " + ((answer == null) ? "answer null" : answer.getDetails()));
|
logger.debug("ModifyStoragePool add failed due to " + ((answer == null) ? "answer null" : answer.getDetails()));
|
||||||
}
|
}
|
||||||
|
if (answer != null && nfsMountOpts.second()) {
|
||||||
|
logger.error(String.format("Unable to attach storage pool to the host %s due to %s", host, answer.getDetails()));
|
||||||
|
StringBuilder exceptionSB = new StringBuilder("Unable to attach storage pool to the host ").append(host.getName());
|
||||||
|
String reason = storageManager.getStoragePoolMountFailureReason(answer.getDetails());
|
||||||
|
if (reason!= null) {
|
||||||
|
exceptionSB.append(". ").append(reason).append(".");
|
||||||
|
}
|
||||||
|
throw new CloudRuntimeException(exceptionSB.toString());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("ModifyStoragePool add succeeded");
|
logger.debug("ModifyStoragePool add succeeded");
|
||||||
|
|||||||
@ -17,16 +17,24 @@
|
|||||||
package com.cloud.storage.secondary;
|
package com.cloud.storage.secondary;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||||
|
|
||||||
import com.cloud.agent.api.Command;
|
import com.cloud.agent.api.Command;
|
||||||
import com.cloud.agent.api.StartupCommand;
|
import com.cloud.agent.api.StartupCommand;
|
||||||
|
import com.cloud.deploy.DeploymentPlanner;
|
||||||
|
import com.cloud.exception.ConcurrentOperationException;
|
||||||
|
import com.cloud.exception.InsufficientCapacityException;
|
||||||
|
import com.cloud.exception.OperationTimedoutException;
|
||||||
|
import com.cloud.exception.ResourceUnavailableException;
|
||||||
import com.cloud.host.HostVO;
|
import com.cloud.host.HostVO;
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
import com.cloud.utils.component.Manager;
|
import com.cloud.utils.component.Manager;
|
||||||
import com.cloud.vm.SecondaryStorageVm;
|
import com.cloud.vm.SecondaryStorageVm;
|
||||||
import com.cloud.vm.SecondaryStorageVmVO;
|
import com.cloud.vm.SecondaryStorageVmVO;
|
||||||
|
import com.cloud.vm.VirtualMachine;
|
||||||
|
import com.cloud.vm.VirtualMachineProfile;
|
||||||
|
|
||||||
public interface SecondaryStorageVmManager extends Manager {
|
public interface SecondaryStorageVmManager extends Manager {
|
||||||
|
|
||||||
@ -47,6 +55,10 @@ public interface SecondaryStorageVmManager extends Manager {
|
|||||||
|
|
||||||
public SecondaryStorageVmVO startSecStorageVm(long ssVmVmId);
|
public SecondaryStorageVmVO startSecStorageVm(long ssVmVmId);
|
||||||
|
|
||||||
|
void startSecStorageVmForHA(VirtualMachine vm, Map<VirtualMachineProfile.Param, Object> params,
|
||||||
|
DeploymentPlanner planner) throws InsufficientCapacityException, ResourceUnavailableException,
|
||||||
|
ConcurrentOperationException, OperationTimedoutException;
|
||||||
|
|
||||||
public boolean stopSecStorageVm(long ssVmVmId);
|
public boolean stopSecStorageVm(long ssVmVmId);
|
||||||
|
|
||||||
public boolean rebootSecStorageVm(long ssVmVmId);
|
public boolean rebootSecStorageVm(long ssVmVmId);
|
||||||
|
|||||||
@ -3266,6 +3266,14 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
_itMgr.advanceStart(vm.getUuid(), null, null);
|
_itMgr.advanceStart(vm.getUuid(), null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@ActionEvent(eventType = EventTypes.EVENT_VM_START, eventDescription = "restarting VM for HA", async = true)
|
||||||
|
public void startVirtualMachineForHA(VirtualMachine vm, Map<VirtualMachineProfile.Param, Object> params,
|
||||||
|
DeploymentPlanner planner) throws InsufficientCapacityException, ResourceUnavailableException,
|
||||||
|
ConcurrentOperationException, OperationTimedoutException {
|
||||||
|
_itMgr.advanceStart(vm.getUuid(), params, planner);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ActionEvent(eventType = EventTypes.EVENT_VM_REBOOT, eventDescription = "rebooting Vm", async = true)
|
@ActionEvent(eventType = EventTypes.EVENT_VM_REBOOT, eventDescription = "rebooting Vm", async = true)
|
||||||
public UserVm rebootVirtualMachine(RebootVMCmd cmd) throws InsufficientCapacityException, ResourceUnavailableException, ResourceAllocationException {
|
public UserVm rebootVirtualMachine(RebootVMCmd cmd) throws InsufficientCapacityException, ResourceUnavailableException, ResourceAllocationException {
|
||||||
@ -8672,10 +8680,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VM_STOP, vm.getAccountId(), vm.getDataCenterId(),
|
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VM_STOP, vm.getAccountId(), vm.getDataCenterId(),
|
||||||
vm.getId(), vm.getHostName(), vm.getServiceOfferingId(), vm.getTemplateId(),
|
vm.getId(), vm.getHostName(), vm.getServiceOfferingId(), vm.getTemplateId(),
|
||||||
vm.getHypervisorType().toString(), VirtualMachine.class.getName(), vm.getUuid(), vm.isDisplayVm());
|
vm.getHypervisorType().toString(), VirtualMachine.class.getName(), vm.getUuid(), vm.isDisplayVm());
|
||||||
|
|
||||||
resourceCountDecrement(vm.getAccountId(), vm.isDisplayVm(), offering, template);
|
resourceCountDecrement(vm.getAccountId(), vm.isDisplayVm(), offering, template);
|
||||||
resourceNotDecremented = false;
|
resourceNotDecremented = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// VM destroy usage event
|
// VM destroy usage event
|
||||||
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VM_DESTROY, vm.getAccountId(), vm.getDataCenterId(),
|
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VM_DESTROY, vm.getAccountId(), vm.getDataCenterId(),
|
||||||
vm.getId(), vm.getHostName(), vm.getServiceOfferingId(), vm.getTemplateId(),
|
vm.getId(), vm.getHostName(), vm.getServiceOfferingId(), vm.getTemplateId(),
|
||||||
|
|||||||
@ -464,7 +464,7 @@ public class ClusterDrsServiceImpl extends ManagerBase implements ClusterDrsServ
|
|||||||
Map<Host, Boolean> requiresStorageMotion = hostsForMigrationOfVM.third();
|
Map<Host, Boolean> requiresStorageMotion = hostsForMigrationOfVM.third();
|
||||||
|
|
||||||
for (Host destHost : compatibleDestinationHosts) {
|
for (Host destHost : compatibleDestinationHosts) {
|
||||||
if (!suitableDestinationHosts.contains(destHost)) {
|
if (!suitableDestinationHosts.contains(destHost) || cluster.getId() != destHost.getClusterId()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Ternary<Double, Double, Double> metrics = algorithm.getMetrics(cluster.getId(), vm,
|
Ternary<Double, Double, Double> metrics = algorithm.getMetrics(cluster.getId(), vm,
|
||||||
|
|||||||
@ -19,6 +19,8 @@ package org.apache.cloudstack.vm;
|
|||||||
|
|
||||||
import com.cloud.agent.AgentManager;
|
import com.cloud.agent.AgentManager;
|
||||||
import com.cloud.agent.api.Answer;
|
import com.cloud.agent.api.Answer;
|
||||||
|
import com.cloud.agent.api.CheckConvertInstanceAnswer;
|
||||||
|
import com.cloud.agent.api.CheckConvertInstanceCommand;
|
||||||
import com.cloud.agent.api.CheckVolumeAnswer;
|
import com.cloud.agent.api.CheckVolumeAnswer;
|
||||||
import com.cloud.agent.api.CheckVolumeCommand;
|
import com.cloud.agent.api.CheckVolumeCommand;
|
||||||
import com.cloud.agent.api.ConvertInstanceAnswer;
|
import com.cloud.agent.api.ConvertInstanceAnswer;
|
||||||
@ -95,7 +97,6 @@ import com.cloud.storage.ScopeType;
|
|||||||
import com.cloud.storage.Snapshot;
|
import com.cloud.storage.Snapshot;
|
||||||
import com.cloud.storage.SnapshotVO;
|
import com.cloud.storage.SnapshotVO;
|
||||||
import com.cloud.storage.Storage;
|
import com.cloud.storage.Storage;
|
||||||
import com.cloud.storage.StorageManager;
|
|
||||||
import com.cloud.storage.StoragePool;
|
import com.cloud.storage.StoragePool;
|
||||||
import com.cloud.storage.VMTemplateStoragePoolVO;
|
import com.cloud.storage.VMTemplateStoragePoolVO;
|
||||||
import com.cloud.storage.VMTemplateVO;
|
import com.cloud.storage.VMTemplateVO;
|
||||||
@ -689,7 +690,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
// Check for duplicate hostname in network, get all vms hostNames in the network
|
// Check for duplicate hostname in network, get all vms hostNames in the network
|
||||||
List<String> hostNames = vmDao.listDistinctHostNames(network.getId());
|
List<String> hostNames = vmDao.listDistinctHostNames(network.getId());
|
||||||
if (CollectionUtils.isNotEmpty(hostNames) && hostNames.contains(hostName)) {
|
if (CollectionUtils.isNotEmpty(hostNames) && hostNames.contains(hostName)) {
|
||||||
throw new InvalidParameterValueException(String.format("VM with Name [%s] already exists in the network [%s] domain [%s]. Cannot import another VM with the same name. Pleasy try again with a different name.", hostName, network, network.getNetworkDomain()));
|
throw new InvalidParameterValueException(String.format("VM with Name [%s] already exists in the network [%s] domain [%s]. Cannot import another VM with the same name. Please try again with a different name.", hostName, network, network.getNetworkDomain()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1564,17 +1565,30 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
return userVm;
|
return userVm;
|
||||||
}
|
}
|
||||||
|
|
||||||
private UnmanagedInstanceTO cloneSourceVmwareUnmanagedInstance(String vcenter, String datacenterName, String username, String password, String clusterName, String sourceHostName, String sourceVM) {
|
private Pair<UnmanagedInstanceTO, Boolean> getSourceVmwareUnmanagedInstance(String vcenter, String datacenterName, String username,
|
||||||
|
String password, String clusterName, String sourceHostName,
|
||||||
|
String sourceVM) {
|
||||||
HypervisorGuru vmwareGuru = hypervisorGuruManager.getGuru(Hypervisor.HypervisorType.VMware);
|
HypervisorGuru vmwareGuru = hypervisorGuruManager.getGuru(Hypervisor.HypervisorType.VMware);
|
||||||
|
|
||||||
Map<String, String> params = createParamsForTemplateFromVmwareVmMigration(vcenter, datacenterName,
|
Map<String, String> params = createParamsForTemplateFromVmwareVmMigration(vcenter, datacenterName,
|
||||||
username, password, clusterName, sourceHostName, sourceVM);
|
username, password, clusterName, sourceHostName, sourceVM);
|
||||||
|
|
||||||
return vmwareGuru.cloneHypervisorVMOutOfBand(sourceHostName, sourceVM, params);
|
return vmwareGuru.getHypervisorVMOutOfBandAndCloneIfRequired(sourceHostName, sourceVM, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String createOvfTemplateOfSourceVmwareUnmanagedInstance(String vcenter, String datacenterName, String username,
|
||||||
|
String password, String clusterName, String sourceHostName,
|
||||||
|
String sourceVMwareInstanceName, DataStoreTO convertLocation, int threadsCountToExportOvf) {
|
||||||
|
HypervisorGuru vmwareGuru = hypervisorGuruManager.getGuru(Hypervisor.HypervisorType.VMware);
|
||||||
|
|
||||||
|
Map<String, String> params = createParamsForTemplateFromVmwareVmMigration(vcenter, datacenterName,
|
||||||
|
username, password, clusterName, sourceHostName, sourceVMwareInstanceName);
|
||||||
|
|
||||||
|
return vmwareGuru.createVMTemplateOutOfBand(sourceHostName, sourceVMwareInstanceName, params, convertLocation, threadsCountToExportOvf);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected UserVm importUnmanagedInstanceFromVmwareToKvm(DataCenter zone, Cluster destinationCluster, VMTemplateVO template,
|
protected UserVm importUnmanagedInstanceFromVmwareToKvm(DataCenter zone, Cluster destinationCluster, VMTemplateVO template,
|
||||||
String sourceVM, String displayName, String hostName,
|
String sourceVMName, String displayName, String hostName,
|
||||||
Account caller, Account owner, long userId,
|
Account caller, Account owner, long userId,
|
||||||
ServiceOfferingVO serviceOffering, Map<String, Long> dataDiskOfferingMap,
|
ServiceOfferingVO serviceOffering, Map<String, Long> dataDiskOfferingMap,
|
||||||
Map<String, Long> nicNetworkMap, Map<String, Network.IpAddresses> nicIpAddressMap,
|
Map<String, Long> nicNetworkMap, Map<String, Network.IpAddresses> nicIpAddressMap,
|
||||||
@ -1601,7 +1615,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
if (existingVcenterId != null) {
|
if (existingVcenterId != null) {
|
||||||
VmwareDatacenterVO existingDC = vmwareDatacenterDao.findById(existingVcenterId);
|
VmwareDatacenterVO existingDC = vmwareDatacenterDao.findById(existingVcenterId);
|
||||||
if (existingDC == null) {
|
if (existingDC == null) {
|
||||||
String err = String.format("Cannot find any existing Vmware DC with ID %s", existingVcenterId);
|
String err = String.format("Cannot find any existing VMware DC with ID %s", existingVcenterId);
|
||||||
logger.error(err);
|
logger.error(err);
|
||||||
throw new CloudRuntimeException(err);
|
throw new CloudRuntimeException(err);
|
||||||
}
|
}
|
||||||
@ -1611,21 +1625,52 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
password = existingDC.getPassword();
|
password = existingDC.getPassword();
|
||||||
}
|
}
|
||||||
|
|
||||||
UnmanagedInstanceTO clonedInstance = null;
|
boolean isClonedInstance = false;
|
||||||
|
UnmanagedInstanceTO sourceVMwareInstance = null;
|
||||||
|
DataStoreTO temporaryConvertLocation = null;
|
||||||
|
String ovfTemplateOnConvertLocation = null;
|
||||||
try {
|
try {
|
||||||
|
HostVO convertHost = selectInstanceConversionKVMHostInCluster(destinationCluster, convertInstanceHostId);
|
||||||
|
CheckConvertInstanceAnswer conversionSupportAnswer = checkConversionSupportOnHost(convertHost, sourceVMName, false);
|
||||||
|
logger.debug(String.format("The host %s (%s) is selected to execute the conversion of the instance %s" +
|
||||||
|
" from VMware to KVM ", convertHost.getId(), convertHost.getName(), sourceVMName));
|
||||||
|
|
||||||
|
temporaryConvertLocation = selectInstanceConversionTemporaryLocation(destinationCluster, convertStoragePoolId);
|
||||||
|
List<StoragePoolVO> convertStoragePools = findInstanceConversionStoragePoolsInCluster(destinationCluster);
|
||||||
|
long importStartTime = System.currentTimeMillis();
|
||||||
|
Pair<UnmanagedInstanceTO, Boolean> sourceInstanceDetails = getSourceVmwareUnmanagedInstance(vcenter, datacenterName, username, password, clusterName, sourceHostName, sourceVMName);
|
||||||
|
sourceVMwareInstance = sourceInstanceDetails.first();
|
||||||
|
isClonedInstance = sourceInstanceDetails.second();
|
||||||
|
boolean isWindowsVm = sourceVMwareInstance.getOperatingSystem().toLowerCase().contains("windows");
|
||||||
|
if (isWindowsVm) {
|
||||||
|
checkConversionSupportOnHost(convertHost, sourceVMName, true);
|
||||||
|
}
|
||||||
|
|
||||||
String instanceName = getGeneratedInstanceName(owner);
|
String instanceName = getGeneratedInstanceName(owner);
|
||||||
clonedInstance = cloneSourceVmwareUnmanagedInstance(vcenter, datacenterName, username, password,
|
checkNetworkingBeforeConvertingVmwareInstance(zone, owner, instanceName, hostName, sourceVMwareInstance, nicNetworkMap, nicIpAddressMap, forced);
|
||||||
clusterName, sourceHostName, sourceVM);
|
UnmanagedInstanceTO convertedInstance;
|
||||||
checkNetworkingBeforeConvertingVmwareInstance(zone, owner, instanceName, hostName, clonedInstance, nicNetworkMap, nicIpAddressMap, forced);
|
if (cmd.getForceMsToImportVmFiles() || !conversionSupportAnswer.isOvfExportSupported()) {
|
||||||
UnmanagedInstanceTO convertedInstance = convertVmwareInstanceToKVM(vcenter, datacenterName, clusterName, username, password,
|
// Uses MS for OVF export to temporary conversion location
|
||||||
sourceHostName, clonedInstance, destinationCluster, convertInstanceHostId, convertStoragePoolId);
|
int noOfThreads = UnmanagedVMsManager.ThreadsOnMSToImportVMwareVMFiles.value();
|
||||||
sanitizeConvertedInstance(convertedInstance, clonedInstance);
|
ovfTemplateOnConvertLocation = createOvfTemplateOfSourceVmwareUnmanagedInstance(vcenter, datacenterName, username, password,
|
||||||
|
clusterName, sourceHostName, sourceVMwareInstance.getName(), temporaryConvertLocation, noOfThreads);
|
||||||
|
convertedInstance = convertVmwareInstanceToKVMWithOVFOnConvertLocation(sourceVMName, sourceVMwareInstance, convertHost, convertStoragePools,
|
||||||
|
temporaryConvertLocation, ovfTemplateOnConvertLocation);
|
||||||
|
} else {
|
||||||
|
// Uses KVM Host for OVF export to temporary conversion location, through ovftool
|
||||||
|
convertedInstance = convertVmwareInstanceToKVMAfterExportingOVFToConvertLocation(sourceVMName, sourceVMwareInstance, convertHost, convertStoragePools,
|
||||||
|
temporaryConvertLocation, vcenter, username, password, datacenterName);
|
||||||
|
}
|
||||||
|
|
||||||
|
sanitizeConvertedInstance(convertedInstance, sourceVMwareInstance);
|
||||||
UserVm userVm = importVirtualMachineInternal(convertedInstance, instanceName, zone, destinationCluster, null,
|
UserVm userVm = importVirtualMachineInternal(convertedInstance, instanceName, zone, destinationCluster, null,
|
||||||
template, displayName, hostName, caller, owner, userId,
|
template, displayName, hostName, caller, owner, userId,
|
||||||
serviceOffering, dataDiskOfferingMap,
|
serviceOffering, dataDiskOfferingMap,
|
||||||
nicNetworkMap, nicIpAddressMap,
|
nicNetworkMap, nicIpAddressMap,
|
||||||
details, false, forced, false);
|
details, false, forced, false);
|
||||||
logger.debug(String.format("VM %s imported successfully", sourceVM));
|
long timeElapsedInSecs = (System.currentTimeMillis() - importStartTime) / 1000;
|
||||||
|
logger.debug(String.format("VMware VM %s imported successfully to CloudStack instance %s (%s), Time taken: %d secs, OVF files imported from %s, Source VMware VM details - OS: %s, PowerState: %s, Disks: %s, NICs: %s",
|
||||||
|
sourceVMName, instanceName, displayName, timeElapsedInSecs, (ovfTemplateOnConvertLocation != null)? "MS" : "KVM Host", sourceVMwareInstance.getOperatingSystem(), sourceVMwareInstance.getPowerState(), sourceVMwareInstance.getDisks(), sourceVMwareInstance.getNics()));
|
||||||
return userVm;
|
return userVm;
|
||||||
} catch (CloudRuntimeException e) {
|
} catch (CloudRuntimeException e) {
|
||||||
logger.error(String.format("Error importing VM: %s", e.getMessage()), e);
|
logger.error(String.format("Error importing VM: %s", e.getMessage()), e);
|
||||||
@ -1633,20 +1678,25 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
cmd.getEventDescription(), null, null, 0);
|
cmd.getEventDescription(), null, null, 0);
|
||||||
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
|
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
|
||||||
} finally {
|
} finally {
|
||||||
removeClonedInstance(vcenter, datacenterName, username, password, sourceHostName, clonedInstance.getName(), sourceVM);
|
if (isClonedInstance && sourceVMwareInstance != null) {
|
||||||
|
removeClonedInstance(vcenter, datacenterName, username, password, sourceHostName, sourceVMwareInstance.getName(), sourceVMName);
|
||||||
|
}
|
||||||
|
if (temporaryConvertLocation != null && StringUtils.isNotBlank(ovfTemplateOnConvertLocation)) {
|
||||||
|
removeTemplate(temporaryConvertLocation, ovfTemplateOnConvertLocation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkNetworkingBeforeConvertingVmwareInstance(DataCenter zone, Account owner, String instanceName,
|
private void checkNetworkingBeforeConvertingVmwareInstance(DataCenter zone, Account owner, String instanceName,
|
||||||
String hostName, UnmanagedInstanceTO clonedInstance,
|
String hostName, UnmanagedInstanceTO sourceVMwareInstance,
|
||||||
Map<String, Long> nicNetworkMap,
|
Map<String, Long> nicNetworkMap,
|
||||||
Map<String, Network.IpAddresses> nicIpAddressMap,
|
Map<String, Network.IpAddresses> nicIpAddressMap,
|
||||||
boolean forced) {
|
boolean forced) {
|
||||||
List<UnmanagedInstanceTO.Nic> nics = clonedInstance.getNics();
|
List<UnmanagedInstanceTO.Nic> nics = sourceVMwareInstance.getNics();
|
||||||
List<Long> networkIds = new ArrayList<>(nicNetworkMap.values());
|
List<Long> networkIds = new ArrayList<>(nicNetworkMap.values());
|
||||||
if (nics.size() != networkIds.size()) {
|
if (nics.size() != networkIds.size()) {
|
||||||
String msg = String.format("Different number of nics found on instance %s: %s vs %s nics provided",
|
String msg = String.format("Different number of nics found on instance %s: %s vs %s nics provided",
|
||||||
clonedInstance.getName(), nics.size(), networkIds.size());
|
sourceVMwareInstance.getName(), nics.size(), networkIds.size());
|
||||||
logger.error(msg);
|
logger.error(msg);
|
||||||
throw new CloudRuntimeException(msg);
|
throw new CloudRuntimeException(msg);
|
||||||
}
|
}
|
||||||
@ -1674,8 +1724,8 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
private void checkUnmanagedNicAndNetworkMacAddressForImport(NetworkVO network, UnmanagedInstanceTO.Nic nic, boolean forced) {
|
private void checkUnmanagedNicAndNetworkMacAddressForImport(NetworkVO network, UnmanagedInstanceTO.Nic nic, boolean forced) {
|
||||||
NicVO existingNic = nicDao.findByNetworkIdAndMacAddress(network.getId(), nic.getMacAddress());
|
NicVO existingNic = nicDao.findByNetworkIdAndMacAddress(network.getId(), nic.getMacAddress());
|
||||||
if (existingNic != null && !forced) {
|
if (existingNic != null && !forced) {
|
||||||
String err = String.format("NIC with MAC address = %s exists on network with ID = %s and forced flag is disabled",
|
String err = String.format("NIC with MAC address %s already exists on network with ID %s and forced flag is disabled. " +
|
||||||
nic.getMacAddress(), network.getId());
|
"Retry with forced flag enabled if a new MAC address to be generated.", nic.getMacAddress(), network.getUuid());
|
||||||
logger.error(err);
|
logger.error(err);
|
||||||
throw new CloudRuntimeException(err);
|
throw new CloudRuntimeException(err);
|
||||||
}
|
}
|
||||||
@ -1690,38 +1740,44 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
return VirtualMachineName.getVmName(id, owner.getId(), instanceSuffix);
|
return VirtualMachineName.getVmName(id, owner.getId(), instanceSuffix);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sanitizeConvertedInstance(UnmanagedInstanceTO convertedInstance, UnmanagedInstanceTO clonedInstance) {
|
private void sanitizeConvertedInstance(UnmanagedInstanceTO convertedInstance, UnmanagedInstanceTO sourceVMwareInstance) {
|
||||||
convertedInstance.setCpuCores(clonedInstance.getCpuCores());
|
convertedInstance.setCpuCores(sourceVMwareInstance.getCpuCores());
|
||||||
convertedInstance.setCpuSpeed(clonedInstance.getCpuSpeed());
|
convertedInstance.setCpuSpeed(sourceVMwareInstance.getCpuSpeed());
|
||||||
convertedInstance.setCpuCoresPerSocket(clonedInstance.getCpuCoresPerSocket());
|
convertedInstance.setCpuCoresPerSocket(sourceVMwareInstance.getCpuCoresPerSocket());
|
||||||
convertedInstance.setMemory(clonedInstance.getMemory());
|
convertedInstance.setMemory(sourceVMwareInstance.getMemory());
|
||||||
convertedInstance.setPowerState(UnmanagedInstanceTO.PowerState.PowerOff);
|
convertedInstance.setPowerState(UnmanagedInstanceTO.PowerState.PowerOff);
|
||||||
List<UnmanagedInstanceTO.Disk> convertedInstanceDisks = convertedInstance.getDisks();
|
List<UnmanagedInstanceTO.Disk> convertedInstanceDisks = convertedInstance.getDisks();
|
||||||
List<UnmanagedInstanceTO.Disk> clonedInstanceDisks = clonedInstance.getDisks();
|
List<UnmanagedInstanceTO.Disk> sourceVMwareInstanceDisks = sourceVMwareInstance.getDisks();
|
||||||
for (int i = 0; i < convertedInstanceDisks.size(); i++) {
|
for (int i = 0; i < convertedInstanceDisks.size(); i++) {
|
||||||
UnmanagedInstanceTO.Disk disk = convertedInstanceDisks.get(i);
|
UnmanagedInstanceTO.Disk disk = convertedInstanceDisks.get(i);
|
||||||
disk.setDiskId(clonedInstanceDisks.get(i).getDiskId());
|
disk.setDiskId(sourceVMwareInstanceDisks.get(i).getDiskId());
|
||||||
}
|
}
|
||||||
List<UnmanagedInstanceTO.Nic> convertedInstanceNics = convertedInstance.getNics();
|
List<UnmanagedInstanceTO.Nic> convertedInstanceNics = convertedInstance.getNics();
|
||||||
List<UnmanagedInstanceTO.Nic> clonedInstanceNics = clonedInstance.getNics();
|
List<UnmanagedInstanceTO.Nic> sourceVMwareInstanceNics = sourceVMwareInstance.getNics();
|
||||||
if (CollectionUtils.isEmpty(convertedInstanceNics) && CollectionUtils.isNotEmpty(clonedInstanceNics)) {
|
if (CollectionUtils.isEmpty(convertedInstanceNics) && CollectionUtils.isNotEmpty(sourceVMwareInstanceNics)) {
|
||||||
for (UnmanagedInstanceTO.Nic nic : clonedInstanceNics) {
|
for (UnmanagedInstanceTO.Nic nic : sourceVMwareInstanceNics) {
|
||||||
// In case the NICs information is not parsed from the converted XML domain, use the cloned instance NICs with virtio adapter
|
// In case the NICs information is not parsed from the converted XML domain, use the cloned instance NICs with virtio adapter
|
||||||
nic.setAdapterType("virtio");
|
nic.setAdapterType("virtio");
|
||||||
}
|
}
|
||||||
convertedInstance.setNics(clonedInstanceNics);
|
convertedInstance.setNics(sourceVMwareInstanceNics);
|
||||||
} else {
|
|
||||||
for (int i = 0; i < convertedInstanceNics.size(); i++) {
|
for (int i = 0; i < convertedInstanceNics.size(); i++) {
|
||||||
UnmanagedInstanceTO.Nic nic = convertedInstanceNics.get(i);
|
UnmanagedInstanceTO.Nic nic = convertedInstanceNics.get(i);
|
||||||
nic.setNicId(clonedInstanceNics.get(i).getNicId());
|
nic.setNicId(sourceVMwareInstanceNics.get(i).getNicId());
|
||||||
|
}
|
||||||
|
} else if (CollectionUtils.isNotEmpty(convertedInstanceNics) && CollectionUtils.isNotEmpty(sourceVMwareInstanceNics)
|
||||||
|
&& convertedInstanceNics.size() == sourceVMwareInstanceNics.size()) {
|
||||||
|
for (int i = 0; i < convertedInstanceNics.size(); i++) {
|
||||||
|
UnmanagedInstanceTO.Nic nic = convertedInstanceNics.get(i);
|
||||||
|
nic.setNicId(sourceVMwareInstanceNics.get(i).getNicId());
|
||||||
|
if (nic.getMacAddress() == null) {
|
||||||
|
nic.setMacAddress(sourceVMwareInstanceNics.get(i).getMacAddress());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeClonedInstance(String vcenter, String datacenterName,
|
private void removeClonedInstance(String vcenter, String datacenterName, String username, String password,
|
||||||
String username, String password,
|
String sourceHostName, String clonedInstanceName, String sourceVM) {
|
||||||
String sourceHostName, String clonedInstanceName,
|
|
||||||
String sourceVM) {
|
|
||||||
HypervisorGuru vmwareGuru = hypervisorGuruManager.getGuru(Hypervisor.HypervisorType.VMware);
|
HypervisorGuru vmwareGuru = hypervisorGuruManager.getGuru(Hypervisor.HypervisorType.VMware);
|
||||||
Map<String, String> params = createParamsForRemoveClonedInstance(vcenter, datacenterName, username, password, sourceVM);
|
Map<String, String> params = createParamsForRemoveClonedInstance(vcenter, datacenterName, username, password, sourceVM);
|
||||||
boolean result = vmwareGuru.removeClonedHypervisorVMOutOfBand(sourceHostName, clonedInstanceName, params);
|
boolean result = vmwareGuru.removeClonedHypervisorVMOutOfBand(sourceHostName, clonedInstanceName, params);
|
||||||
@ -1731,10 +1787,23 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
logger.warn(msg);
|
logger.warn(msg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
logger.debug(String.format("Removed the cloned instance %s from VMWare datacenter %s:%s",
|
logger.debug(String.format("Removed the cloned instance %s from VMWare datacenter %s/%s",
|
||||||
clonedInstanceName, vcenter, datacenterName));
|
clonedInstanceName, vcenter, datacenterName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void removeTemplate(DataStoreTO convertLocation, String ovfTemplateOnConvertLocation) {
|
||||||
|
HypervisorGuru vmwareGuru = hypervisorGuruManager.getGuru(Hypervisor.HypervisorType.VMware);
|
||||||
|
boolean result = vmwareGuru.removeVMTemplateOutOfBand(convertLocation, ovfTemplateOnConvertLocation);
|
||||||
|
if (!result) {
|
||||||
|
String msg = String.format("Could not remove the template file %s on datastore %s",
|
||||||
|
ovfTemplateOnConvertLocation, convertLocation.getUrl());
|
||||||
|
logger.warn(msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
logger.debug(String.format("Removed the template file %s on datastore %s",
|
||||||
|
ovfTemplateOnConvertLocation, convertLocation.getUrl()));
|
||||||
|
}
|
||||||
|
|
||||||
private Map<String, String> createParamsForRemoveClonedInstance(String vcenter, String datacenterName, String username,
|
private Map<String, String> createParamsForRemoveClonedInstance(String vcenter, String datacenterName, String username,
|
||||||
String password, String sourceVM) {
|
String password, String sourceVM) {
|
||||||
Map<String, String> params = new HashMap<>();
|
Map<String, String> params = new HashMap<>();
|
||||||
@ -1745,7 +1814,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
private HostVO selectInstanceConvertionKVMHostInCluster(Cluster destinationCluster, Long convertInstanceHostId) {
|
private HostVO selectInstanceConversionKVMHostInCluster(Cluster destinationCluster, Long convertInstanceHostId) {
|
||||||
if (convertInstanceHostId != null) {
|
if (convertInstanceHostId != null) {
|
||||||
HostVO selectedHost = hostDao.findById(convertInstanceHostId);
|
HostVO selectedHost = hostDao.findById(convertInstanceHostId);
|
||||||
if (selectedHost == null) {
|
if (selectedHost == null) {
|
||||||
@ -1762,41 +1831,61 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
}
|
}
|
||||||
return selectedHost;
|
return selectedHost;
|
||||||
}
|
}
|
||||||
List<HostVO> hosts = hostDao.listByClusterAndHypervisorType(destinationCluster.getId(), destinationCluster.getHypervisorType());
|
// Auto select host with conversion capability
|
||||||
if (CollectionUtils.isEmpty(hosts)) {
|
List<HostVO> hosts = hostDao.listByClusterHypervisorTypeAndHostCapability(destinationCluster.getId(), destinationCluster.getHypervisorType(), Host.HOST_INSTANCE_CONVERSION);
|
||||||
String err = String.format("Could not find any running %s host in cluster %s",
|
if (CollectionUtils.isNotEmpty(hosts)) {
|
||||||
|
return hosts.get(new Random().nextInt(hosts.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try without host capability check
|
||||||
|
hosts = hostDao.listByClusterAndHypervisorType(destinationCluster.getId(), destinationCluster.getHypervisorType());
|
||||||
|
if (CollectionUtils.isNotEmpty(hosts)) {
|
||||||
|
return hosts.get(new Random().nextInt(hosts.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
String err = String.format("Could not find any suitable %s host in cluster %s to perform the instance conversion",
|
||||||
destinationCluster.getHypervisorType(), destinationCluster.getName());
|
destinationCluster.getHypervisorType(), destinationCluster.getName());
|
||||||
logger.error(err);
|
logger.error(err);
|
||||||
throw new CloudRuntimeException(err);
|
throw new CloudRuntimeException(err);
|
||||||
}
|
}
|
||||||
List<HostVO> filteredHosts = hosts.stream()
|
|
||||||
.filter(x -> x.getResourceState() == ResourceState.Enabled)
|
private CheckConvertInstanceAnswer checkConversionSupportOnHost(HostVO convertHost, String sourceVM, boolean checkWindowsGuestConversionSupport) {
|
||||||
.collect(Collectors.toList());
|
logger.debug(String.format("Checking the %s conversion support on the host %s (%s)", checkWindowsGuestConversionSupport? "windows guest" : "", convertHost.getId(), convertHost.getName()));
|
||||||
if (CollectionUtils.isEmpty(filteredHosts)) {
|
CheckConvertInstanceCommand cmd = new CheckConvertInstanceCommand(checkWindowsGuestConversionSupport);
|
||||||
String err = String.format("Could not find a %s host in cluster %s to perform the instance conversion",
|
int timeoutSeconds = 60;
|
||||||
destinationCluster.getHypervisorType(), destinationCluster.getName());
|
cmd.setWait(timeoutSeconds);
|
||||||
|
|
||||||
|
CheckConvertInstanceAnswer checkConvertInstanceAnswer;
|
||||||
|
try {
|
||||||
|
checkConvertInstanceAnswer = (CheckConvertInstanceAnswer) agentManager.send(convertHost.getId(), cmd);
|
||||||
|
} catch (AgentUnavailableException | OperationTimedoutException e) {
|
||||||
|
String err = String.format("Failed to check %s conversion support on the host %s for converting instance %s from VMware to KVM due to: %s",
|
||||||
|
checkWindowsGuestConversionSupport? "windows guest" : "", convertHost.getName(), sourceVM, e.getMessage());
|
||||||
logger.error(err);
|
logger.error(err);
|
||||||
throw new CloudRuntimeException(err);
|
throw new CloudRuntimeException(err);
|
||||||
}
|
}
|
||||||
return filteredHosts.get(new Random().nextInt(filteredHosts.size()));
|
|
||||||
|
if (!checkConvertInstanceAnswer.getResult()) {
|
||||||
|
String err = String.format("The host %s doesn't support conversion of instance %s from VMware to KVM due to: %s",
|
||||||
|
convertHost.getName(), sourceVM, checkConvertInstanceAnswer.getDetails());
|
||||||
|
logger.error(err);
|
||||||
|
throw new CloudRuntimeException(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
private UnmanagedInstanceTO convertVmwareInstanceToKVM(String vcenter, String datacenterName, String clusterName,
|
return checkConvertInstanceAnswer;
|
||||||
String username, String password, String hostName,
|
}
|
||||||
UnmanagedInstanceTO clonedInstance, Cluster destinationCluster,
|
|
||||||
Long convertInstanceHostId, Long convertStoragePoolId) {
|
|
||||||
HostVO convertHost = selectInstanceConvertionKVMHostInCluster(destinationCluster, convertInstanceHostId);
|
|
||||||
String vmName = clonedInstance.getName();
|
|
||||||
logger.debug(String.format("The host %s (%s) is selected to execute the conversion of the instance %s" +
|
|
||||||
" from VMware to KVM ", convertHost.getId(), convertHost.getName(), vmName));
|
|
||||||
|
|
||||||
RemoteInstanceTO remoteInstanceTO = new RemoteInstanceTO(hostName, vmName,
|
private UnmanagedInstanceTO convertVmwareInstanceToKVMWithOVFOnConvertLocation(String sourceVM, UnmanagedInstanceTO sourceVMwareInstance, HostVO convertHost,
|
||||||
vcenter, datacenterName, clusterName, username, password);
|
List<StoragePoolVO> convertStoragePools, DataStoreTO temporaryConvertLocation,
|
||||||
DataStoreTO temporaryConvertLocation = selectInstanceConversionTemporaryLocation(destinationCluster, convertStoragePoolId, convertHost);
|
String ovfTemplateDirConvertLocation) {
|
||||||
List<String> destinationStoragePools = selectInstanceConvertionStoragePools(destinationCluster, clonedInstance.getDisks());
|
logger.debug(String.format("Delegating the conversion of instance %s from VMware to KVM to the host %s (%s) using OVF %s on conversion datastore",
|
||||||
|
sourceVM, convertHost.getId(), convertHost.getName(), ovfTemplateDirConvertLocation));
|
||||||
|
|
||||||
|
RemoteInstanceTO remoteInstanceTO = new RemoteInstanceTO(sourceVM);
|
||||||
|
List<String> destinationStoragePools = selectInstanceConversionStoragePools(convertStoragePools, sourceVMwareInstance.getDisks());
|
||||||
ConvertInstanceCommand cmd = new ConvertInstanceCommand(remoteInstanceTO,
|
ConvertInstanceCommand cmd = new ConvertInstanceCommand(remoteInstanceTO,
|
||||||
Hypervisor.HypervisorType.KVM, destinationStoragePools, temporaryConvertLocation);
|
Hypervisor.HypervisorType.KVM, destinationStoragePools, temporaryConvertLocation, ovfTemplateDirConvertLocation, false, false);
|
||||||
int timeoutSeconds = StorageManager.ConvertVmwareInstanceToKvmTimeout.value() * 60 * 60;
|
int timeoutSeconds = UnmanagedVMsManager.ConvertVmwareInstanceToKvmTimeout.value() * 60 * 60;
|
||||||
cmd.setWait(timeoutSeconds);
|
cmd.setWait(timeoutSeconds);
|
||||||
|
|
||||||
Answer convertAnswer;
|
Answer convertAnswer;
|
||||||
@ -1810,17 +1899,68 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!convertAnswer.getResult()) {
|
if (!convertAnswer.getResult()) {
|
||||||
String err = String.format("The convert process failed for instance %s from Vmware to KVM on host %s: %s",
|
String err = String.format("The convert process failed for instance %s from VMware to KVM on host %s: %s",
|
||||||
vmName, convertHost.getName(), convertAnswer.getDetails());
|
sourceVM, convertHost.getName(), convertAnswer.getDetails());
|
||||||
logger.error(err);
|
logger.error(err);
|
||||||
throw new CloudRuntimeException(err);
|
throw new CloudRuntimeException(err);
|
||||||
}
|
}
|
||||||
return ((ConvertInstanceAnswer) convertAnswer).getConvertedInstance();
|
return ((ConvertInstanceAnswer) convertAnswer).getConvertedInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> selectInstanceConvertionStoragePools(Cluster destinationCluster, List<UnmanagedInstanceTO.Disk> disks) {
|
private UnmanagedInstanceTO convertVmwareInstanceToKVMAfterExportingOVFToConvertLocation(String sourceVM, UnmanagedInstanceTO sourceVMwareInstance, HostVO convertHost,
|
||||||
|
List<StoragePoolVO> convertStoragePools, DataStoreTO temporaryConvertLocation,
|
||||||
|
String vcenterHost, String vcenterUsername, String vcenterPassword, String datacenterName) {
|
||||||
|
logger.debug(String.format("Delegating the conversion of instance %s from VMware to KVM to the host %s (%s) after OVF export through ovftool",
|
||||||
|
sourceVM, convertHost.getId(), convertHost.getName()));
|
||||||
|
|
||||||
|
RemoteInstanceTO remoteInstanceTO = new RemoteInstanceTO(sourceVMwareInstance.getName(), vcenterHost, vcenterUsername, vcenterPassword, datacenterName);
|
||||||
|
List<String> destinationStoragePools = selectInstanceConversionStoragePools(convertStoragePools, sourceVMwareInstance.getDisks());
|
||||||
|
ConvertInstanceCommand cmd = new ConvertInstanceCommand(remoteInstanceTO,
|
||||||
|
Hypervisor.HypervisorType.KVM, destinationStoragePools, temporaryConvertLocation, null, false, true);
|
||||||
|
int timeoutSeconds = UnmanagedVMsManager.ConvertVmwareInstanceToKvmTimeout.value() * 60 * 60;
|
||||||
|
cmd.setWait(timeoutSeconds);
|
||||||
|
int noOfThreads = UnmanagedVMsManager.ThreadsOnKVMHostToImportVMwareVMFiles.value();
|
||||||
|
if (noOfThreads == 0) {
|
||||||
|
// Use no. of threads as the disks count
|
||||||
|
noOfThreads = sourceVMwareInstance.getDisks().size();
|
||||||
|
}
|
||||||
|
cmd.setThreadsCountToExportOvf(noOfThreads);
|
||||||
|
|
||||||
|
Answer convertAnswer;
|
||||||
|
try {
|
||||||
|
convertAnswer = agentManager.send(convertHost.getId(), cmd);
|
||||||
|
} catch (AgentUnavailableException | OperationTimedoutException e) {
|
||||||
|
String err = String.format("Could not send the convert instance command to host %s (%s) due to: %s",
|
||||||
|
convertHost.getId(), convertHost.getName(), e.getMessage());
|
||||||
|
logger.error(err, e);
|
||||||
|
throw new CloudRuntimeException(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!convertAnswer.getResult()) {
|
||||||
|
String err = String.format("The convert process failed for instance %s from VMware to KVM on host %s: %s",
|
||||||
|
sourceVM, convertHost.getName(), convertAnswer.getDetails());
|
||||||
|
logger.error(err);
|
||||||
|
throw new CloudRuntimeException(err);
|
||||||
|
}
|
||||||
|
return ((ConvertInstanceAnswer) convertAnswer).getConvertedInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<StoragePoolVO> findInstanceConversionStoragePoolsInCluster(Cluster destinationCluster) {
|
||||||
|
List<StoragePoolVO> pools = new ArrayList<>();
|
||||||
|
List<StoragePoolVO> clusterPools = primaryDataStoreDao.findClusterWideStoragePoolsByHypervisorAndPoolType(destinationCluster.getId(), Hypervisor.HypervisorType.KVM, Storage.StoragePoolType.NetworkFilesystem);
|
||||||
|
pools.addAll(clusterPools);
|
||||||
|
List<StoragePoolVO> zonePools = primaryDataStoreDao.findZoneWideStoragePoolsByHypervisorAndPoolType(destinationCluster.getDataCenterId(), Hypervisor.HypervisorType.KVM, Storage.StoragePoolType.NetworkFilesystem);
|
||||||
|
pools.addAll(zonePools);
|
||||||
|
if (pools.isEmpty()) {
|
||||||
|
String msg = String.format("Cannot find suitable storage pools in cluster %s for the conversion", destinationCluster.getName());
|
||||||
|
logger.error(msg);
|
||||||
|
throw new CloudRuntimeException(msg);
|
||||||
|
}
|
||||||
|
return pools;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> selectInstanceConversionStoragePools(List<StoragePoolVO> pools, List<UnmanagedInstanceTO.Disk> disks) {
|
||||||
List<String> storagePools = new ArrayList<>(disks.size());
|
List<String> storagePools = new ArrayList<>(disks.size());
|
||||||
List<StoragePoolVO> pools = primaryDataStoreDao.listPoolsByCluster(destinationCluster.getId());
|
|
||||||
//TODO: Choose pools by capacity
|
//TODO: Choose pools by capacity
|
||||||
for (UnmanagedInstanceTO.Disk disk : disks) {
|
for (UnmanagedInstanceTO.Disk disk : disks) {
|
||||||
Long capacity = disk.getCapacity();
|
Long capacity = disk.getCapacity();
|
||||||
@ -1834,7 +1974,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
throw new CloudRuntimeException(msg);
|
throw new CloudRuntimeException(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected DataStoreTO selectInstanceConversionTemporaryLocation(Cluster destinationCluster, Long convertStoragePoolId, HostVO convertHost) {
|
protected DataStoreTO selectInstanceConversionTemporaryLocation(Cluster destinationCluster, Long convertStoragePoolId) {
|
||||||
if (convertStoragePoolId != null) {
|
if (convertStoragePoolId != null) {
|
||||||
StoragePoolVO selectedStoragePool = primaryDataStoreDao.findById(convertStoragePoolId);
|
StoragePoolVO selectedStoragePool = primaryDataStoreDao.findById(convertStoragePoolId);
|
||||||
if (selectedStoragePool == null) {
|
if (selectedStoragePool == null) {
|
||||||
@ -1845,11 +1985,10 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
logFailureAndThrowException(String.format("Cannot use the storage pool %s for the instance conversion as " +
|
logFailureAndThrowException(String.format("Cannot use the storage pool %s for the instance conversion as " +
|
||||||
"it is not in the scope of the cluster %s", selectedStoragePool.getName(), destinationCluster.getName()));
|
"it is not in the scope of the cluster %s", selectedStoragePool.getName(), destinationCluster.getName()));
|
||||||
}
|
}
|
||||||
if (selectedStoragePool.getScope() == ScopeType.HOST &&
|
if (selectedStoragePool.getScope() == ScopeType.HOST) {
|
||||||
storagePoolHostDao.findByPoolHost(selectedStoragePool.getId(), convertHost.getId()) == null) {
|
logFailureAndThrowException(String.format("The storage pool %s is a local storage pool and not supported for temporary conversion location, cluster and zone wide NFS storage pools are supported", selectedStoragePool.getName()));
|
||||||
logFailureAndThrowException(String.format("The storage pool %s is not a local storage pool for the host %s", selectedStoragePool.getName(), convertHost.getName()));
|
|
||||||
} else if (selectedStoragePool.getPoolType() != Storage.StoragePoolType.NetworkFilesystem) {
|
} else if (selectedStoragePool.getPoolType() != Storage.StoragePoolType.NetworkFilesystem) {
|
||||||
logFailureAndThrowException(String.format("The storage pool %s is not supported for temporary conversion location, supported pools are NFS storage pools", selectedStoragePool.getName()));
|
logFailureAndThrowException(String.format("The storage pool %s is not supported for temporary conversion location, only NFS storage pools are supported", selectedStoragePool.getName()));
|
||||||
}
|
}
|
||||||
return dataStoreManager.getPrimaryDataStore(convertStoragePoolId).getTO();
|
return dataStoreManager.getPrimaryDataStore(convertStoragePoolId).getTO();
|
||||||
} else {
|
} else {
|
||||||
@ -2538,7 +2677,10 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
public ConfigKey<?>[] getConfigKeys() {
|
public ConfigKey<?>[] getConfigKeys() {
|
||||||
return new ConfigKey<?>[]{
|
return new ConfigKey<?>[]{
|
||||||
UnmanageVMPreserveNic,
|
UnmanageVMPreserveNic,
|
||||||
RemoteKvmInstanceDisksCopyTimeout
|
RemoteKvmInstanceDisksCopyTimeout,
|
||||||
|
ConvertVmwareInstanceToKvmTimeout,
|
||||||
|
ThreadsOnMSToImportVMwareVMFiles,
|
||||||
|
ThreadsOnKVMHostToImportVMwareVMFiles
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,6 +24,8 @@ import com.cloud.dc.dao.DataCenterIpAddressDao;
|
|||||||
import com.cloud.dc.dao.DedicatedResourceDao;
|
import com.cloud.dc.dao.DedicatedResourceDao;
|
||||||
import com.cloud.dc.dao.HostPodDao;
|
import com.cloud.dc.dao.HostPodDao;
|
||||||
import com.cloud.dc.dao.VlanDao;
|
import com.cloud.dc.dao.VlanDao;
|
||||||
|
import com.cloud.domain.Domain;
|
||||||
|
import com.cloud.domain.dao.DomainDao;
|
||||||
import com.cloud.exception.InvalidParameterValueException;
|
import com.cloud.exception.InvalidParameterValueException;
|
||||||
import com.cloud.host.dao.HostDao;
|
import com.cloud.host.dao.HostDao;
|
||||||
import com.cloud.network.Network;
|
import com.cloud.network.Network;
|
||||||
@ -34,63 +36,63 @@ import com.cloud.network.dao.IPAddressDao;
|
|||||||
import com.cloud.network.dao.NsxProviderDao;
|
import com.cloud.network.dao.NsxProviderDao;
|
||||||
import com.cloud.network.dao.PhysicalNetworkDao;
|
import com.cloud.network.dao.PhysicalNetworkDao;
|
||||||
import com.cloud.network.element.NsxProviderVO;
|
import com.cloud.network.element.NsxProviderVO;
|
||||||
|
import com.cloud.offering.DiskOffering;
|
||||||
import com.cloud.offering.NetworkOffering;
|
import com.cloud.offering.NetworkOffering;
|
||||||
import com.cloud.offerings.NetworkOfferingVO;
|
import com.cloud.offerings.NetworkOfferingVO;
|
||||||
import com.cloud.offerings.dao.NetworkOfferingDao;
|
import com.cloud.offerings.dao.NetworkOfferingDao;
|
||||||
|
import com.cloud.storage.DiskOfferingVO;
|
||||||
import com.cloud.storage.StorageManager;
|
import com.cloud.storage.StorageManager;
|
||||||
import com.cloud.storage.dao.VMTemplateZoneDao;
|
import com.cloud.storage.dao.VMTemplateZoneDao;
|
||||||
import com.cloud.storage.dao.VolumeDao;
|
import com.cloud.storage.dao.VolumeDao;
|
||||||
|
import com.cloud.user.Account;
|
||||||
|
import com.cloud.user.User;
|
||||||
|
import com.cloud.utils.db.EntityManager;
|
||||||
|
import com.cloud.utils.db.SearchCriteria;
|
||||||
import com.cloud.utils.net.NetUtils;
|
import com.cloud.utils.net.NetUtils;
|
||||||
import com.cloud.vm.dao.VMInstanceDao;
|
import com.cloud.vm.dao.VMInstanceDao;
|
||||||
import org.apache.cloudstack.annotation.dao.AnnotationDao;
|
import org.apache.cloudstack.annotation.dao.AnnotationDao;
|
||||||
import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd;
|
import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd;
|
||||||
|
import org.apache.cloudstack.api.command.admin.offering.UpdateDiskOfferingCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.zone.DeleteZoneCmd;
|
import org.apache.cloudstack.api.command.admin.zone.DeleteZoneCmd;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
|
import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
|
||||||
import org.apache.cloudstack.framework.config.ConfigDepot;
|
import org.apache.cloudstack.framework.config.ConfigDepot;
|
||||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||||
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
|
import org.apache.cloudstack.framework.config.impl.ConfigurationVO;
|
||||||
import com.cloud.domain.Domain;
|
|
||||||
import com.cloud.domain.dao.DomainDao;
|
|
||||||
import com.cloud.offering.DiskOffering;
|
|
||||||
import com.cloud.storage.DiskOfferingVO;
|
|
||||||
import com.cloud.user.Account;
|
|
||||||
import com.cloud.user.User;
|
|
||||||
import com.cloud.utils.db.EntityManager;
|
|
||||||
import com.cloud.utils.db.SearchCriteria;
|
|
||||||
import org.apache.cloudstack.api.command.admin.offering.UpdateDiskOfferingCmd;
|
|
||||||
import org.apache.cloudstack.resourcedetail.DiskOfferingDetailVO;
|
import org.apache.cloudstack.resourcedetail.DiskOfferingDetailVO;
|
||||||
import org.apache.cloudstack.resourcedetail.dao.DiskOfferingDetailsDao;
|
import org.apache.cloudstack.resourcedetail.dao.DiskOfferingDetailsDao;
|
||||||
|
import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
|
||||||
|
import org.apache.cloudstack.vm.UnmanagedVMsManager;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockedStatic;
|
import org.mockito.MockedStatic;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
|
import org.mockito.Spy;
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
import org.springframework.test.util.ReflectionTestUtils;
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import org.mockito.InjectMocks;
|
|
||||||
import org.mockito.Spy;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyLong;
|
import static org.mockito.ArgumentMatchers.anyLong;
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
import static org.mockito.Mockito.lenient;
|
|
||||||
import static org.mockito.Mockito.anyString;
|
|
||||||
import static org.mockito.Mockito.anyBoolean;
|
import static org.mockito.Mockito.anyBoolean;
|
||||||
import static org.mockito.Mockito.doNothing;
|
|
||||||
import static org.mockito.Mockito.nullable;
|
|
||||||
import static org.mockito.Mockito.anyMap;
|
|
||||||
import static org.mockito.Mockito.anyList;
|
|
||||||
import static org.mockito.Mockito.anyInt;
|
import static org.mockito.Mockito.anyInt;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.anyList;
|
||||||
|
import static org.mockito.Mockito.anyMap;
|
||||||
|
import static org.mockito.Mockito.anyString;
|
||||||
|
import static org.mockito.Mockito.doNothing;
|
||||||
|
import static org.mockito.Mockito.lenient;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.nullable;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
public class ConfigurationManagerImplTest {
|
public class ConfigurationManagerImplTest {
|
||||||
@ -109,6 +111,8 @@ public class ConfigurationManagerImplTest {
|
|||||||
@Mock
|
@Mock
|
||||||
Domain domainMock;
|
Domain domainMock;
|
||||||
@Mock
|
@Mock
|
||||||
|
DataCenterDao zoneDaoMock;
|
||||||
|
@Mock
|
||||||
DomainDao domainDaoMock;
|
DomainDao domainDaoMock;
|
||||||
@Mock
|
@Mock
|
||||||
EntityManager entityManagerMock;
|
EntityManager entityManagerMock;
|
||||||
@ -457,6 +461,65 @@ public class ConfigurationManagerImplTest {
|
|||||||
Assert.assertNotNull(offering);
|
Assert.assertNotNull(offering);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testValidateInvalidConfiguration() {
|
||||||
|
Mockito.doReturn(null).when(configDao).findByName(Mockito.anyString());
|
||||||
|
String msg = configurationManagerImplSpy.validateConfigurationValue("test.config.name", "testvalue", ConfigKey.Scope.Global.toString());
|
||||||
|
Assert.assertEquals("Invalid configuration variable.", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateInvalidScopeForConfiguration() {
|
||||||
|
ConfigurationVO cfg = mock(ConfigurationVO.class);
|
||||||
|
when(cfg.getScope()).thenReturn(ConfigKey.Scope.Account.toString());
|
||||||
|
Mockito.doReturn(cfg).when(configDao).findByName(Mockito.anyString());
|
||||||
|
String msg = configurationManagerImplSpy.validateConfigurationValue("test.config.name", "testvalue", ConfigKey.Scope.Domain.toString());
|
||||||
|
Assert.assertEquals("Invalid scope id provided for the parameter test.config.name", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testValidateConfig_ThreadsOnKVMHostToTransferVMwareVMFiles_Failure() {
|
||||||
|
ConfigurationVO cfg = mock(ConfigurationVO.class);
|
||||||
|
when(cfg.getScope()).thenReturn(ConfigKey.Scope.Global.toString());
|
||||||
|
ConfigKey<Integer> configKey = UnmanagedVMsManager.ThreadsOnKVMHostToImportVMwareVMFiles;
|
||||||
|
Mockito.doReturn(cfg).when(configDao).findByName(Mockito.anyString());
|
||||||
|
Mockito.doReturn(configKey).when(configurationManagerImplSpy._configDepot).get(configKey.key());
|
||||||
|
configurationManagerImplSpy.validateConfigurationValue(configKey.key(), "11", configKey.scope().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateConfig_ThreadsOnKVMHostToTransferVMwareVMFiles_Success() {
|
||||||
|
ConfigurationVO cfg = mock(ConfigurationVO.class);
|
||||||
|
when(cfg.getScope()).thenReturn(ConfigKey.Scope.Global.toString());
|
||||||
|
ConfigKey<Integer> configKey = UnmanagedVMsManager.ThreadsOnKVMHostToImportVMwareVMFiles;
|
||||||
|
Mockito.doReturn(cfg).when(configDao).findByName(Mockito.anyString());
|
||||||
|
Mockito.doReturn(configKey).when(configurationManagerImplSpy._configDepot).get(configKey.key());
|
||||||
|
String msg = configurationManagerImplSpy.validateConfigurationValue(configKey.key(), "10", configKey.scope().toString());
|
||||||
|
Assert.assertNull(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testValidateConfig_ConvertVmwareInstanceToKvmTimeout_Failure() {
|
||||||
|
ConfigurationVO cfg = mock(ConfigurationVO.class);
|
||||||
|
when(cfg.getScope()).thenReturn(ConfigKey.Scope.Global.toString());
|
||||||
|
ConfigKey<Integer> configKey = UnmanagedVMsManager.ConvertVmwareInstanceToKvmTimeout;
|
||||||
|
Mockito.doReturn(cfg).when(configDao).findByName(Mockito.anyString());
|
||||||
|
Mockito.doReturn(configKey).when(configurationManagerImplSpy._configDepot).get(configKey.key());
|
||||||
|
configurationManagerImplSpy.populateConfigValuesForValidationSet();
|
||||||
|
configurationManagerImplSpy.validateConfigurationValue(configKey.key(), "0", configKey.scope().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateConfig_ConvertVmwareInstanceToKvmTimeout_Success() {
|
||||||
|
ConfigurationVO cfg = mock(ConfigurationVO.class);
|
||||||
|
when(cfg.getScope()).thenReturn(ConfigKey.Scope.Global.toString());
|
||||||
|
ConfigKey<Integer> configKey = UnmanagedVMsManager.ConvertVmwareInstanceToKvmTimeout;
|
||||||
|
Mockito.doReturn(cfg).when(configDao).findByName(Mockito.anyString());
|
||||||
|
Mockito.doReturn(configKey).when(configurationManagerImplSpy._configDepot).get(configKey.key());
|
||||||
|
configurationManagerImplSpy.populateConfigValuesForValidationSet();
|
||||||
|
String msg = configurationManagerImplSpy.validateConfigurationValue(configKey.key(), "9", configKey.scope().toString());
|
||||||
|
Assert.assertNull(msg);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void validateDomainTestInvalidIdThrowException() {
|
public void validateDomainTestInvalidIdThrowException() {
|
||||||
Mockito.doReturn(null).when(domainDaoMock).findById(invalidId);
|
Mockito.doReturn(null).when(domainDaoMock).findById(invalidId);
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user