mirror of https://github.com/apache/cloudstack.git
Merge branch 'master' into storage-offering-domains-zones
This commit is contained in:
commit
8cff58d3b8
|
|
@ -0,0 +1,45 @@
|
|||
// 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.to;
|
||||
|
||||
public class DpdkTO {
|
||||
|
||||
private String path;
|
||||
private String port;
|
||||
private String mode;
|
||||
|
||||
public DpdkTO() {
|
||||
}
|
||||
|
||||
public DpdkTO(String path, String port, String mode) {
|
||||
this.path = path;
|
||||
this.port = port;
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public String getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public String getMode() {
|
||||
return mode;
|
||||
}
|
||||
}
|
||||
|
|
@ -30,7 +30,7 @@ public class NicTO extends NetworkTO {
|
|||
String nicUuid;
|
||||
List<String> nicSecIps;
|
||||
Map<NetworkOffering.Detail, String> details;
|
||||
boolean dpdkDisabled;
|
||||
boolean dpdkEnabled;
|
||||
|
||||
public NicTO() {
|
||||
super();
|
||||
|
|
@ -111,11 +111,11 @@ public class NicTO extends NetworkTO {
|
|||
this.details = details;
|
||||
}
|
||||
|
||||
public boolean isDpdkDisabled() {
|
||||
return dpdkDisabled;
|
||||
public boolean isDpdkEnabled() {
|
||||
return dpdkEnabled;
|
||||
}
|
||||
|
||||
public void setDpdkDisabled(boolean dpdkDisabled) {
|
||||
this.dpdkDisabled = dpdkDisabled;
|
||||
public void setDpdkEnabled(boolean dpdkEnabled) {
|
||||
this.dpdkEnabled = dpdkEnabled;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -219,6 +219,7 @@ public class ApiConstants {
|
|||
public static final String OFFER_HA = "offerha";
|
||||
public static final String IS_SYSTEM_OFFERING = "issystem";
|
||||
public static final String IS_DEFAULT_USE = "defaultuse";
|
||||
public static final String OLD_FORMAT = "oldformat";
|
||||
public static final String OP = "op";
|
||||
public static final String OS_CATEGORY_ID = "oscategoryid";
|
||||
public static final String OS_TYPE_ID = "ostypeid";
|
||||
|
|
|
|||
|
|
@ -435,7 +435,7 @@ public interface ResponseGenerator {
|
|||
|
||||
UsageRecordResponse createUsageResponse(Usage usageRecord);
|
||||
|
||||
UsageRecordResponse createUsageResponse(Usage usageRecord, Map<String, Set<ResourceTagResponse>> resourceTagResponseMap);
|
||||
UsageRecordResponse createUsageResponse(Usage usageRecord, Map<String, Set<ResourceTagResponse>> resourceTagResponseMap, boolean oldFormat);
|
||||
|
||||
public Map<String, Set<ResourceTagResponse>> getUsageResourceTags();
|
||||
|
||||
|
|
|
|||
|
|
@ -82,6 +82,9 @@ public class ListUsageRecordsCmd extends BaseListCmd {
|
|||
@Parameter(name = ApiConstants.INCLUDE_TAGS, type = CommandType.BOOLEAN, description = "Flag to enable display of Tags for a resource")
|
||||
private Boolean includeTags;
|
||||
|
||||
@Parameter(name = ApiConstants.OLD_FORMAT, type = CommandType.BOOLEAN, description = "Flag to enable description rendered in old format which uses internal database IDs instead of UUIDs. False by default.")
|
||||
private Boolean oldFormat;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
|
@ -146,6 +149,9 @@ public class ListUsageRecordsCmd extends BaseListCmd {
|
|||
this.usageId = usageId;
|
||||
}
|
||||
|
||||
public boolean getOldFormat() {
|
||||
return oldFormat != null && oldFormat;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
|
|
@ -168,7 +174,7 @@ public class ListUsageRecordsCmd extends BaseListCmd {
|
|||
resourceTagResponseMap = _responseGenerator.getUsageResourceTags();
|
||||
}
|
||||
for (Usage usageRecord : usageRecords.first()) {
|
||||
UsageRecordResponse usageResponse = _responseGenerator.createUsageResponse(usageRecord, resourceTagResponseMap);
|
||||
UsageRecordResponse usageResponse = _responseGenerator.createUsageResponse(usageRecord, resourceTagResponseMap, getOldFormat());
|
||||
if (usageResponse != null) {
|
||||
usageResponse.setObjectName("usagerecord");
|
||||
usageResponses.add(usageResponse);
|
||||
|
|
|
|||
|
|
@ -77,8 +77,8 @@ public class UsageRecordResponse extends BaseResponseWithTagInformation implemen
|
|||
private String virtualMachineId;
|
||||
|
||||
@SerializedName(ApiConstants.NAME)
|
||||
@Param(description = "virtual machine name")
|
||||
private String vmName;
|
||||
@Param(description = "resource or virtual machine name")
|
||||
private String resourceName;
|
||||
|
||||
@SerializedName("offeringid")
|
||||
@Param(description = "offering ID")
|
||||
|
|
@ -186,8 +186,8 @@ public class UsageRecordResponse extends BaseResponseWithTagInformation implemen
|
|||
this.virtualMachineId = virtualMachineId;
|
||||
}
|
||||
|
||||
public void setVmName(String vmName) {
|
||||
this.vmName = vmName;
|
||||
public void setResourceName(String name) {
|
||||
this.resourceName = name;
|
||||
}
|
||||
|
||||
public void setOfferingId(String offeringId) {
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ public class UsageTypes {
|
|||
responseList.add(new UsageTypeResponse(VM_DISK_BYTES_READ, "VM Disk usage(Bytes Read)"));
|
||||
responseList.add(new UsageTypeResponse(VM_DISK_BYTES_WRITE, "VM Disk usage(Bytes Write)"));
|
||||
responseList.add(new UsageTypeResponse(VM_SNAPSHOT, "VM Snapshot storage usage"));
|
||||
responseList.add(new UsageTypeResponse(VOLUME_SECONDARY, "Volume on secondary storage usage"));
|
||||
responseList.add(new UsageTypeResponse(VM_SNAPSHOT_ON_PRIMARY, "VM Snapshot on primary storage usage"));
|
||||
return responseList;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.cloud.agent.api.to.DpdkTO;
|
||||
import com.cloud.agent.api.to.VirtualMachineTO;
|
||||
|
||||
public class MigrateCommand extends Command {
|
||||
|
|
@ -37,6 +38,15 @@ public class MigrateCommand extends Command {
|
|||
private VirtualMachineTO vmTO;
|
||||
private boolean executeInSequence = false;
|
||||
private List<MigrateDiskInfo> migrateDiskInfoList = new ArrayList<>();
|
||||
private Map<String, DpdkTO> dpdkInterfaceMapping = new HashMap<>();
|
||||
|
||||
public Map<String, DpdkTO> getDpdkInterfaceMapping() {
|
||||
return dpdkInterfaceMapping;
|
||||
}
|
||||
|
||||
public void setDpdkInterfaceMapping(Map<String, DpdkTO> dpdkInterfaceMapping) {
|
||||
this.dpdkInterfaceMapping = dpdkInterfaceMapping;
|
||||
}
|
||||
|
||||
protected MigrateCommand() {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,15 @@
|
|||
|
||||
package com.cloud.agent.api;
|
||||
|
||||
import com.cloud.agent.api.to.DpdkTO;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class PrepareForMigrationAnswer extends Answer {
|
||||
|
||||
private Map<String, DpdkTO> dpdkInterfaceMapping = new HashMap<>();
|
||||
|
||||
protected PrepareForMigrationAnswer() {
|
||||
}
|
||||
|
||||
|
|
@ -34,4 +42,12 @@ public class PrepareForMigrationAnswer extends Answer {
|
|||
public PrepareForMigrationAnswer(PrepareForMigrationCommand cmd) {
|
||||
super(cmd, true, null);
|
||||
}
|
||||
|
||||
public void setDpdkInterfaceMapping(Map<String, DpdkTO> mapping) {
|
||||
this.dpdkInterfaceMapping = mapping;
|
||||
}
|
||||
|
||||
public Map<String, DpdkTO> getDpdkInterfaceMapping() {
|
||||
return this.dpdkInterfaceMapping;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
package com.cloud.agent.api;
|
||||
|
||||
import com.cloud.agent.api.to.DpdkTO;
|
||||
import com.cloud.agent.api.to.GPUDeviceTO;
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
|
||||
|
|
@ -34,6 +35,15 @@ public class StopCommand extends RebootCommand {
|
|||
boolean checkBeforeCleanup = false;
|
||||
String controlIp = null;
|
||||
boolean forceStop = false;
|
||||
private Map<String, DpdkTO> dpdkInterfaceMapping;
|
||||
|
||||
public Map<String, DpdkTO> getDpdkInterfaceMapping() {
|
||||
return dpdkInterfaceMapping;
|
||||
}
|
||||
|
||||
public void setDpdkInterfaceMapping(Map<String, DpdkTO> dpdkInterfaceMapping) {
|
||||
this.dpdkInterfaceMapping = dpdkInterfaceMapping;
|
||||
}
|
||||
/**
|
||||
* On KVM when using iSCSI-based managed storage, if the user shuts a VM down from the guest OS (as opposed to doing so from CloudStack),
|
||||
* we need to pass to the KVM agent a list of applicable iSCSI volumes that need to be disconnected.
|
||||
|
|
|
|||
|
|
@ -39,7 +39,8 @@ import java.util.concurrent.TimeUnit;
|
|||
import javax.inject.Inject;
|
||||
import javax.naming.ConfigurationException;
|
||||
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import com.cloud.agent.api.PrepareForMigrationAnswer;
|
||||
import com.cloud.agent.api.to.DpdkTO;
|
||||
import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
|
||||
import org.apache.cloudstack.api.command.admin.vm.MigrateVMCmd;
|
||||
import org.apache.cloudstack.api.command.admin.volume.MigrateVolumeCmdByAdmin;
|
||||
|
|
@ -1118,8 +1119,6 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||
|
||||
vmGuru.finalizeDeployment(cmds, vmProfile, dest, ctx);
|
||||
|
||||
addExtraConfig(vmTO);
|
||||
|
||||
work = _workDao.findById(work.getId());
|
||||
if (work == null || work.getStep() != Step.Prepare) {
|
||||
throw new ConcurrentOperationException("Work steps have been changed: " + work);
|
||||
|
|
@ -1284,15 +1283,6 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||
}
|
||||
}
|
||||
|
||||
private void addExtraConfig(VirtualMachineTO vmTO) {
|
||||
Map<String, String> details = vmTO.getDetails();
|
||||
for (String key : details.keySet()) {
|
||||
if (key.startsWith(ApiConstants.EXTRA_CONFIG)) {
|
||||
vmTO.addExtraConfig(key, details.get(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// for managed storage on KVM, need to make sure the path field of the volume in question is populated with the IQN
|
||||
private void handlePath(final DiskTO[] disks, final HypervisorType hypervisorType) {
|
||||
if (hypervisorType != HypervisorType.KVM) {
|
||||
|
|
@ -2362,6 +2352,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||
}
|
||||
|
||||
boolean migrated = false;
|
||||
Map<String, DpdkTO> dpdkInterfaceMapping = null;
|
||||
try {
|
||||
final boolean isWindows = _guestOsCategoryDao.findById(_guestOsDao.findById(vm.getGuestOSId()).getCategoryId()).getName().equalsIgnoreCase("Windows");
|
||||
final MigrateCommand mc = new MigrateCommand(vm.getInstanceName(), dest.getHost().getPrivateIpAddress(), isWindows, to, getExecuteInSequence(vm.getHypervisorType()));
|
||||
|
|
@ -2370,6 +2361,11 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||
mc.setAutoConvergence(kvmAutoConvergence);
|
||||
mc.setHostGuid(dest.getHost().getGuid());
|
||||
|
||||
dpdkInterfaceMapping = ((PrepareForMigrationAnswer) pfma).getDpdkInterfaceMapping();
|
||||
if (MapUtils.isNotEmpty(dpdkInterfaceMapping)) {
|
||||
mc.setDpdkInterfaceMapping(dpdkInterfaceMapping);
|
||||
}
|
||||
|
||||
try {
|
||||
final Answer ma = _agentMgr.send(vm.getLastHostId(), mc);
|
||||
if (ma == null || !ma.getResult()) {
|
||||
|
|
@ -2396,7 +2392,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||
if (!checkVmOnHost(vm, dstHostId)) {
|
||||
s_logger.error("Unable to complete migration for " + vm);
|
||||
try {
|
||||
_agentMgr.send(srcHostId, new Commands(cleanup(vm)), null);
|
||||
_agentMgr.send(srcHostId, new Commands(cleanup(vm, dpdkInterfaceMapping)), null);
|
||||
} catch (final AgentUnavailableException e) {
|
||||
s_logger.error("AgentUnavailableException while cleanup on source host: " + srcHostId);
|
||||
}
|
||||
|
|
@ -2417,7 +2413,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||
"Unable to migrate vm " + vm.getInstanceName() + " from host " + fromHost.getName() + " in zone " + dest.getDataCenter().getName() + " and pod " +
|
||||
dest.getPod().getName(), "Migrate Command failed. Please check logs.");
|
||||
try {
|
||||
_agentMgr.send(dstHostId, new Commands(cleanup(vm)), null);
|
||||
_agentMgr.send(dstHostId, new Commands(cleanup(vm, dpdkInterfaceMapping)), null);
|
||||
} catch (final AgentUnavailableException ae) {
|
||||
s_logger.info("Looks like the destination Host is unavailable for cleanup");
|
||||
}
|
||||
|
|
@ -3106,9 +3102,12 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||
}
|
||||
}
|
||||
|
||||
public Command cleanup(final VirtualMachine vm) {
|
||||
public Command cleanup(final VirtualMachine vm, Map<String, DpdkTO> dpdkInterfaceMapping) {
|
||||
StopCommand cmd = new StopCommand(vm, getExecuteInSequence(vm.getHypervisorType()), false);
|
||||
cmd.setControlIp(getControlNicIpForVM(vm));
|
||||
if (MapUtils.isNotEmpty(dpdkInterfaceMapping)) {
|
||||
cmd.setDpdkInterfaceMapping(dpdkInterfaceMapping);
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ public class UsageEventVO implements UsageEvent {
|
|||
private String resourceType;
|
||||
|
||||
@Column(name = "processed")
|
||||
boolean processed;
|
||||
private boolean processed;
|
||||
|
||||
@Column(name = "virtual_size")
|
||||
private Long virtualSize;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,10 @@
|
|||
-- Schema upgrade from 4.12.0.0 to 4.13.0.0
|
||||
--;
|
||||
|
||||
-- Add support for VMware 6.7
|
||||
INSERT IGNORE INTO `cloud`.`hypervisor_capabilities` (uuid, hypervisor_type, hypervisor_version, max_guests_limit, security_group_enabled, max_data_volumes_limit, max_hosts_per_cluster, storage_motion_supported, vm_snapshot_enabled) values (UUID(), 'VMware', '6.7', 128, 0, 13, 32, 1, 1);
|
||||
INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) SELECT UUID(),'VMware', '6.7', guest_os_name, guest_os_id, utc_timestamp(), 0 FROM `cloud`.`guest_os_hypervisor` WHERE hypervisor_type='VMware' AND hypervisor_version='6.5';
|
||||
|
||||
-- DPDK client and server mode support
|
||||
ALTER TABLE `cloud`.`service_offering_details` CHANGE COLUMN `value` `value` TEXT NOT NULL;
|
||||
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ public class QuotaTypes extends UsageTypes {
|
|||
quotaTypeList.put(VM_DISK_BYTES_READ, new QuotaTypes(VM_DISK_BYTES_READ, "VM_DISK_BYTES_READ", "GB", "VM Disk usage(Bytes Read)"));
|
||||
quotaTypeList.put(VM_DISK_BYTES_WRITE, new QuotaTypes(VM_DISK_BYTES_WRITE, "VPN_USERS", "GB", "VM Disk usage(Bytes Write)"));
|
||||
quotaTypeList.put(VM_SNAPSHOT, new QuotaTypes(VM_SNAPSHOT, "VM_SNAPSHOT", "GB-Month", "VM Snapshot storage usage"));
|
||||
quotaTypeList.put(VOLUME_SECONDARY, new QuotaTypes(VOLUME_SECONDARY, "VOLUME_SECONDARY", "GB-Month", "Volume secondary storage usage"));
|
||||
quotaTypeList.put(VM_SNAPSHOT_ON_PRIMARY, new QuotaTypes(VM_SNAPSHOT_ON_PRIMARY, "VM_SNAPSHOT_ON_PRIMARY", "GB-Month", "VM Snapshot primary storage usage"));
|
||||
quotaTypeList.put(CPU_CLOCK_RATE, new QuotaTypes(CPU_CLOCK_RATE, "CPU_CLOCK_RATE", "Compute-Month", "Quota tariff for using 1 CPU of clock rate 100MHz"));
|
||||
quotaTypeList.put(CPU_NUMBER, new QuotaTypes(CPU_NUMBER, "CPU_NUMBER", "Compute-Month", "Quota tariff for running VM that has 1vCPU"));
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ import com.cloud.utils.component.Adapter;
|
|||
|
||||
import java.util.Map;
|
||||
|
||||
public interface DPDKDriver extends Adapter {
|
||||
public interface DpdkDriver extends Adapter {
|
||||
|
||||
/**
|
||||
* Get the next DPDK port name to be created
|
||||
|
|
@ -37,17 +37,17 @@ public interface DPDKDriver extends Adapter {
|
|||
/**
|
||||
* Add OVS port (if it does not exist) to bridge with DPDK support
|
||||
*/
|
||||
void addDpdkPort(String bridgeName, String port, String vlan, DPDKHelper.VHostUserMode vHostUserMode, String dpdkOvsPath);
|
||||
void addDpdkPort(String bridgeName, String port, String vlan, DpdkHelper.VHostUserMode vHostUserMode, String dpdkOvsPath);
|
||||
|
||||
/**
|
||||
* Since DPDK user client/server mode, retrieve the guest interfaces mode from the DPDK vHost User mode
|
||||
*/
|
||||
String getGuestInterfacesModeFromDPDKVhostUserMode(DPDKHelper.VHostUserMode dpdKvHostUserMode);
|
||||
String getGuestInterfacesModeFromDpdkVhostUserMode(DpdkHelper.VHostUserMode dpdKvHostUserMode);
|
||||
|
||||
/**
|
||||
* Get DPDK vHost User mode from extra config. If it is not present, server is returned as default
|
||||
*/
|
||||
DPDKHelper.VHostUserMode getDPDKvHostUserMode(Map<String, String> extraConfig);
|
||||
DpdkHelper.VHostUserMode getDpdkvHostUserMode(Map<String, String> extraConfig);
|
||||
|
||||
/**
|
||||
* Check for additional extra 'dpdk-interface' configurations, return them appended
|
||||
|
|
@ -25,15 +25,15 @@ import org.apache.log4j.Logger;
|
|||
|
||||
import java.util.Map;
|
||||
|
||||
public class DPDKDriverImpl extends AdapterBase implements DPDKDriver {
|
||||
public class DpdkDriverImpl extends AdapterBase implements DpdkDriver {
|
||||
static final String DPDK_PORT_PREFIX = "csdpdk-";
|
||||
|
||||
private final String dpdkPortVhostUserType = "dpdkvhostuser";
|
||||
private final String dpdkPortVhostUserClientType = "dpdkvhostuserclient";
|
||||
|
||||
private static final Logger s_logger = Logger.getLogger(DPDKDriver.class);
|
||||
private static final Logger s_logger = Logger.getLogger(DpdkDriver.class);
|
||||
|
||||
public DPDKDriverImpl() {
|
||||
public DpdkDriverImpl() {
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -64,8 +64,8 @@ public class DPDKDriverImpl extends AdapterBase implements DPDKDriver {
|
|||
/**
|
||||
* Add OVS port (if it does not exist) to bridge with DPDK support
|
||||
*/
|
||||
public void addDpdkPort(String bridgeName, String port, String vlan, DPDKHelper.VHostUserMode vHostUserMode, String dpdkOvsPath) {
|
||||
String type = vHostUserMode == DPDKHelper.VHostUserMode.SERVER ?
|
||||
public void addDpdkPort(String bridgeName, String port, String vlan, DpdkHelper.VHostUserMode vHostUserMode, String dpdkOvsPath) {
|
||||
String type = vHostUserMode == DpdkHelper.VHostUserMode.SERVER ?
|
||||
dpdkPortVhostUserType :
|
||||
dpdkPortVhostUserClientType;
|
||||
|
||||
|
|
@ -74,7 +74,7 @@ public class DPDKDriverImpl extends AdapterBase implements DPDKDriver {
|
|||
"vlan_mode=access tag=%s " +
|
||||
"-- set Interface %s type=%s", bridgeName, port, vlan, port, type));
|
||||
|
||||
if (vHostUserMode == DPDKHelper.VHostUserMode.CLIENT) {
|
||||
if (vHostUserMode == DpdkHelper.VHostUserMode.CLIENT) {
|
||||
stringBuilder.append(String.format(" options:vhost-server-path=%s/%s",
|
||||
dpdkOvsPath, port));
|
||||
}
|
||||
|
|
@ -87,17 +87,17 @@ public class DPDKDriverImpl extends AdapterBase implements DPDKDriver {
|
|||
/**
|
||||
* Since DPDK user client/server mode, retrieve the guest interfaces mode from the DPDK vHost User mode
|
||||
*/
|
||||
public String getGuestInterfacesModeFromDPDKVhostUserMode(DPDKHelper.VHostUserMode dpdKvHostUserMode) {
|
||||
return dpdKvHostUserMode == DPDKHelper.VHostUserMode.CLIENT ? "server" : "client";
|
||||
public String getGuestInterfacesModeFromDpdkVhostUserMode(DpdkHelper.VHostUserMode dpdKvHostUserMode) {
|
||||
return dpdKvHostUserMode == DpdkHelper.VHostUserMode.CLIENT ? "server" : "client";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get DPDK vHost User mode from extra config. If it is not present, server is returned as default
|
||||
*/
|
||||
public DPDKHelper.VHostUserMode getDPDKvHostUserMode(Map<String, String> extraConfig) {
|
||||
return extraConfig.containsKey(DPDKHelper.DPDK_VHOST_USER_MODE) ?
|
||||
DPDKHelper.VHostUserMode.fromValue(extraConfig.get(DPDKHelper.DPDK_VHOST_USER_MODE)) :
|
||||
DPDKHelper.VHostUserMode.SERVER;
|
||||
public DpdkHelper.VHostUserMode getDpdkvHostUserMode(Map<String, String> extraConfig) {
|
||||
return extraConfig.containsKey(DpdkHelper.DPDK_VHOST_USER_MODE) ?
|
||||
DpdkHelper.VHostUserMode.fromValue(extraConfig.get(DpdkHelper.DPDK_VHOST_USER_MODE)) :
|
||||
DpdkHelper.VHostUserMode.SERVER;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -106,7 +106,7 @@ public class DPDKDriverImpl extends AdapterBase implements DPDKDriver {
|
|||
public String getExtraDpdkProperties(Map<String, String> extraConfig) {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
for (String key : extraConfig.keySet()) {
|
||||
if (key.startsWith(DPDKHelper.DPDK_INTERFACE_PREFIX)) {
|
||||
if (key.startsWith(DpdkHelper.DPDK_INTERFACE_PREFIX)) {
|
||||
stringBuilder.append(extraConfig.get(key));
|
||||
}
|
||||
}
|
||||
|
|
@ -46,7 +46,7 @@ import javax.xml.parsers.DocumentBuilder;
|
|||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import com.cloud.hypervisor.kvm.dpdk.DPDKHelper;
|
||||
import com.cloud.hypervisor.kvm.dpdk.DpdkHelper;
|
||||
import com.cloud.resource.RequestWrapper;
|
||||
import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
|
||||
import org.apache.cloudstack.storage.to.TemplateObjectTO;
|
||||
|
|
@ -2070,7 +2070,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||
vm.setPlatformEmulator(vmTO.getPlatformEmulator());
|
||||
|
||||
Map<String, String> extraConfig = vmTO.getExtraConfig();
|
||||
if (dpdkSupport && (!extraConfig.containsKey(DPDKHelper.DPDK_NUMA) || !extraConfig.containsKey(DPDKHelper.DPDK_HUGE_PAGES))) {
|
||||
if (dpdkSupport && (!extraConfig.containsKey(DpdkHelper.DPDK_NUMA) || !extraConfig.containsKey(DpdkHelper.DPDK_HUGE_PAGES))) {
|
||||
s_logger.info("DPDK is enabled but it needs extra configurations for CPU NUMA and Huge Pages for VM deployment");
|
||||
}
|
||||
|
||||
|
|
@ -2107,7 +2107,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||
grd.setVcpuNum(vcpus);
|
||||
vm.addComp(grd);
|
||||
|
||||
if (!extraConfig.containsKey(DPDKHelper.DPDK_NUMA)) {
|
||||
if (!extraConfig.containsKey(DpdkHelper.DPDK_NUMA)) {
|
||||
final CpuModeDef cmd = new CpuModeDef();
|
||||
cmd.setMode(_guestCpuMode);
|
||||
cmd.setModel(_guestCpuModel);
|
||||
|
|
@ -2235,7 +2235,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||
if (MapUtils.isNotEmpty(extraConfig)) {
|
||||
StringBuilder extraConfigBuilder = new StringBuilder();
|
||||
for (String key : extraConfig.keySet()) {
|
||||
if (!key.startsWith(DPDKHelper.DPDK_INTERFACE_PREFIX) && !key.equals(DPDKHelper.DPDK_VHOST_USER_MODE)) {
|
||||
if (!key.startsWith(DpdkHelper.DPDK_INTERFACE_PREFIX) && !key.equals(DpdkHelper.DPDK_VHOST_USER_MODE)) {
|
||||
extraConfigBuilder.append(extraConfig.get(key));
|
||||
}
|
||||
}
|
||||
|
|
@ -2706,7 +2706,10 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||
|
||||
final KVMHostInfo info = new KVMHostInfo(_dom0MinMem, _dom0OvercommitMem);
|
||||
|
||||
final String capabilities = String.join(",", info.getCapabilities());
|
||||
String capabilities = String.join(",", info.getCapabilities());
|
||||
if (dpdkSupport) {
|
||||
capabilities += ",dpdk";
|
||||
}
|
||||
|
||||
final StartupRoutingCommand cmd =
|
||||
new StartupRoutingCommand(info.getCpus(), info.getCpuSpeed(), info.getTotalMemory(), info.getReservedMemory(), capabilities, _hypervisorType,
|
||||
|
|
|
|||
|
|
@ -224,9 +224,13 @@ public class LibvirtDomainXMLParser {
|
|||
def.defEthernet(dev, mac, NicModel.valueOf(model.toUpperCase()), scriptPath, networkRateKBps);
|
||||
} else if (type.equals("vhostuser")) {
|
||||
String sourcePort = getAttrValue("source", "path", nic);
|
||||
String[] sourcePathParts = sourcePort.split("/");
|
||||
String port = sourcePathParts[sourcePathParts.length - 1];
|
||||
String mode = getAttrValue("source", "mode", nic);
|
||||
int lastSlashIndex = sourcePort.lastIndexOf("/");
|
||||
String ovsPath = sourcePort.substring(0,lastSlashIndex);
|
||||
String port = sourcePort.substring(lastSlashIndex + 1);
|
||||
def.setDpdkSourcePort(port);
|
||||
def.setDpdkOvsPath(ovsPath);
|
||||
def.setInterfaceMode(mode);
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(slot)) {
|
||||
|
|
|
|||
|
|
@ -963,7 +963,7 @@ public class LibvirtVMDef {
|
|||
}
|
||||
|
||||
public static class InterfaceDef {
|
||||
enum GuestNetType {
|
||||
public enum GuestNetType {
|
||||
BRIDGE("bridge"), DIRECT("direct"), NETWORK("network"), USER("user"), ETHERNET("ethernet"), INTERNAL("internal"), VHOSTUSER("vhostuser");
|
||||
String _type;
|
||||
|
||||
|
|
@ -1176,10 +1176,24 @@ public class LibvirtVMDef {
|
|||
_dpdkSourcePort = port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
public String getDpdkOvsPath() {
|
||||
return _dpdkSourcePath;
|
||||
}
|
||||
|
||||
public void setDpdkOvsPath(String path) {
|
||||
_dpdkSourcePath = path;
|
||||
}
|
||||
|
||||
public String getInterfaceMode() {
|
||||
return _interfaceMode;
|
||||
}
|
||||
|
||||
public void setInterfaceMode(String mode) {
|
||||
_interfaceMode = mode;
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
StringBuilder netBuilder = new StringBuilder();
|
||||
netBuilder.append("<interface type='" + _netType + "'>\n");
|
||||
if (_netType == GuestNetType.BRIDGE) {
|
||||
netBuilder.append("<source bridge='" + _sourceName + "'/>\n");
|
||||
} else if (_netType == GuestNetType.NETWORK) {
|
||||
|
|
@ -1233,6 +1247,14 @@ public class LibvirtVMDef {
|
|||
if (_slot != null) {
|
||||
netBuilder.append(String.format("<address type='pci' domain='0x0000' bus='0x00' slot='0x%02x' function='0x0'/>\n", _slot));
|
||||
}
|
||||
return netBuilder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder netBuilder = new StringBuilder();
|
||||
netBuilder.append("<interface type='" + _netType + "'>\n");
|
||||
netBuilder.append(getContent());
|
||||
netBuilder.append("</interface>\n");
|
||||
return netBuilder.toString();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,9 +24,9 @@ import java.util.Map;
|
|||
|
||||
import javax.naming.ConfigurationException;
|
||||
|
||||
import com.cloud.hypervisor.kvm.dpdk.DPDKDriver;
|
||||
import com.cloud.hypervisor.kvm.dpdk.DPDKDriverImpl;
|
||||
import com.cloud.hypervisor.kvm.dpdk.DPDKHelper;
|
||||
import com.cloud.hypervisor.kvm.dpdk.DpdkDriver;
|
||||
import com.cloud.hypervisor.kvm.dpdk.DpdkDriverImpl;
|
||||
import com.cloud.hypervisor.kvm.dpdk.DpdkHelper;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
|
|
@ -44,7 +44,7 @@ import com.cloud.utils.script.Script;
|
|||
public class OvsVifDriver extends VifDriverBase {
|
||||
private static final Logger s_logger = Logger.getLogger(OvsVifDriver.class);
|
||||
private int _timeout;
|
||||
private DPDKDriver dpdkDriver;
|
||||
private DpdkDriver dpdkDriver;
|
||||
|
||||
@Override
|
||||
public void configure(Map<String, Object> params) throws ConfigurationException {
|
||||
|
|
@ -59,7 +59,7 @@ public class OvsVifDriver extends VifDriverBase {
|
|||
|
||||
String dpdk = (String) params.get("openvswitch.dpdk.enabled");
|
||||
if (StringUtils.isNotBlank(dpdk) && Boolean.parseBoolean(dpdk)) {
|
||||
dpdkDriver = new DPDKDriverImpl();
|
||||
dpdkDriver = new DpdkDriverImpl();
|
||||
}
|
||||
|
||||
String value = (String)params.get("scripts.timeout");
|
||||
|
|
@ -87,12 +87,34 @@ public class OvsVifDriver extends VifDriverBase {
|
|||
s_logger.debug("done looking for pifs, no more bridges");
|
||||
}
|
||||
|
||||
/**
|
||||
* Plug interface with DPDK support:
|
||||
* - Create a new port with DPDK support for the interface
|
||||
* - Set the 'intf' path to the new port
|
||||
*/
|
||||
protected void plugDPDKInterface(InterfaceDef intf, String trafficLabel, Map<String, String> extraConfig,
|
||||
String vlanId, String guestOsType, NicTO nic, String nicAdapter) {
|
||||
s_logger.debug("DPDK support enabled: configuring per traffic label " + trafficLabel);
|
||||
String dpdkOvsPath = _libvirtComputingResource.dpdkOvsPath;
|
||||
if (StringUtils.isBlank(dpdkOvsPath)) {
|
||||
throw new CloudRuntimeException("DPDK is enabled on the host but no OVS path has been provided");
|
||||
}
|
||||
String port = dpdkDriver.getNextDpdkPort();
|
||||
DpdkHelper.VHostUserMode dpdKvHostUserMode = dpdkDriver.getDpdkvHostUserMode(extraConfig);
|
||||
dpdkDriver.addDpdkPort(_pifs.get(trafficLabel), port, vlanId, dpdKvHostUserMode, dpdkOvsPath);
|
||||
String interfaceMode = dpdkDriver.getGuestInterfacesModeFromDpdkVhostUserMode(dpdKvHostUserMode);
|
||||
intf.defDpdkNet(dpdkOvsPath, port, nic.getMac(),
|
||||
getGuestNicModel(guestOsType, nicAdapter), 0,
|
||||
dpdkDriver.getExtraDpdkProperties(extraConfig),
|
||||
interfaceMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InterfaceDef plug(NicTO nic, String guestOsType, String nicAdapter, Map<String, String> extraConfig) throws InternalErrorException, LibvirtException {
|
||||
s_logger.debug("plugging nic=" + nic);
|
||||
|
||||
LibvirtVMDef.InterfaceDef intf = new LibvirtVMDef.InterfaceDef();
|
||||
if (!_libvirtComputingResource.dpdkSupport || nic.isDpdkDisabled()) {
|
||||
if (!_libvirtComputingResource.dpdkSupport || !nic.isDpdkEnabled()) {
|
||||
// Let libvirt handle OVS ports creation when DPDK property is disabled or when it is enabled but disabled for the nic
|
||||
// For DPDK support, libvirt does not handle ports creation, invoke 'addDpdkPort' method
|
||||
intf.setVirtualPortType("openvswitch");
|
||||
|
|
@ -114,20 +136,8 @@ public class OvsVifDriver extends VifDriverBase {
|
|||
if ((nic.getBroadcastType() == Networks.BroadcastDomainType.Vlan || nic.getBroadcastType() == Networks.BroadcastDomainType.Pvlan) &&
|
||||
!vlanId.equalsIgnoreCase("untagged")) {
|
||||
if (trafficLabel != null && !trafficLabel.isEmpty()) {
|
||||
if (_libvirtComputingResource.dpdkSupport && !nic.isDpdkDisabled()) {
|
||||
s_logger.debug("DPDK support enabled: configuring per traffic label " + trafficLabel);
|
||||
String dpdkOvsPath = _libvirtComputingResource.dpdkOvsPath;
|
||||
if (StringUtils.isBlank(dpdkOvsPath)) {
|
||||
throw new CloudRuntimeException("DPDK is enabled on the host but no OVS path has been provided");
|
||||
}
|
||||
String port = dpdkDriver.getNextDpdkPort();
|
||||
DPDKHelper.VHostUserMode dpdKvHostUserMode = dpdkDriver.getDPDKvHostUserMode(extraConfig);
|
||||
dpdkDriver.addDpdkPort(_pifs.get(trafficLabel), port, vlanId, dpdKvHostUserMode, dpdkOvsPath);
|
||||
String interfaceMode = dpdkDriver.getGuestInterfacesModeFromDPDKVhostUserMode(dpdKvHostUserMode);
|
||||
intf.defDpdkNet(dpdkOvsPath, port, nic.getMac(),
|
||||
getGuestNicModel(guestOsType, nicAdapter), 0,
|
||||
dpdkDriver.getExtraDpdkProperties(extraConfig),
|
||||
interfaceMode);
|
||||
if (_libvirtComputingResource.dpdkSupport && nic.isDpdkEnabled()) {
|
||||
plugDPDKInterface(intf, trafficLabel, extraConfig, vlanId, guestOsType, nic, nicAdapter);
|
||||
} else {
|
||||
s_logger.debug("creating a vlan dev and bridge for guest traffic per traffic label " + trafficLabel);
|
||||
intf.defBridgeNet(_pifs.get(trafficLabel), null, nic.getMac(), getGuestNicModel(guestOsType, nicAdapter), networkRateKBps);
|
||||
|
|
@ -180,7 +190,7 @@ public class OvsVifDriver extends VifDriverBase {
|
|||
@Override
|
||||
public void unplug(InterfaceDef iface) {
|
||||
// Libvirt apparently takes care of this, see BridgeVifDriver unplug
|
||||
if (_libvirtComputingResource.dpdkSupport) {
|
||||
if (_libvirtComputingResource.dpdkSupport && StringUtils.isNotBlank(iface.getDpdkSourcePort())) {
|
||||
// If DPDK is enabled, we'll need to cleanup the port as libvirt won't
|
||||
String dpdkPort = iface.getDpdkSourcePort();
|
||||
String cmd = String.format("ovs-vsctl del-port %s", dpdkPort);
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ import javax.xml.transform.TransformerFactory;
|
|||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
|
||||
import com.cloud.agent.api.to.DpdkTO;
|
||||
import org.apache.commons.collections.MapUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
|
@ -153,6 +154,11 @@ public final class LibvirtMigrateCommandWrapper extends CommandWrapper<MigrateCo
|
|||
xmlDesc = replaceStorage(xmlDesc, mapMigrateStorage, migrateStorageManaged);
|
||||
}
|
||||
|
||||
Map<String, DpdkTO> dpdkPortsMapping = command.getDpdkInterfaceMapping();
|
||||
if (MapUtils.isNotEmpty(dpdkPortsMapping)) {
|
||||
xmlDesc = replaceDpdkInterfaces(xmlDesc, dpdkPortsMapping);
|
||||
}
|
||||
|
||||
dconn = libvirtUtilitiesHelper.retrieveQemuConnection(destinationUri);
|
||||
|
||||
//run migration in thread so we can monitor it
|
||||
|
|
@ -283,6 +289,76 @@ public final class LibvirtMigrateCommandWrapper extends CommandWrapper<MigrateCo
|
|||
return new MigrateAnswer(command, result == null, result, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace DPDK source path and target before migrations
|
||||
*/
|
||||
protected String replaceDpdkInterfaces(String xmlDesc, Map<String, DpdkTO> dpdkPortsMapping) throws TransformerException, ParserConfigurationException, IOException, SAXException {
|
||||
InputStream in = IOUtils.toInputStream(xmlDesc);
|
||||
|
||||
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
|
||||
Document doc = docBuilder.parse(in);
|
||||
|
||||
// Get the root element
|
||||
Node domainNode = doc.getFirstChild();
|
||||
|
||||
NodeList domainChildNodes = domainNode.getChildNodes();
|
||||
|
||||
for (int i = 0; i < domainChildNodes.getLength(); i++) {
|
||||
Node domainChildNode = domainChildNodes.item(i);
|
||||
|
||||
if ("devices".equals(domainChildNode.getNodeName())) {
|
||||
NodeList devicesChildNodes = domainChildNode.getChildNodes();
|
||||
|
||||
for (int x = 0; x < devicesChildNodes.getLength(); x++) {
|
||||
Node deviceChildNode = devicesChildNodes.item(x);
|
||||
|
||||
if ("interface".equals(deviceChildNode.getNodeName())) {
|
||||
Node interfaceNode = deviceChildNode;
|
||||
NamedNodeMap attributes = interfaceNode.getAttributes();
|
||||
Node interfaceTypeAttr = attributes.getNamedItem("type");
|
||||
|
||||
if ("vhostuser".equals(interfaceTypeAttr.getNodeValue())) {
|
||||
NodeList diskChildNodes = interfaceNode.getChildNodes();
|
||||
|
||||
String mac = null;
|
||||
for (int y = 0; y < diskChildNodes.getLength(); y++) {
|
||||
Node diskChildNode = diskChildNodes.item(y);
|
||||
if (!"mac".equals(diskChildNode.getNodeName())) {
|
||||
continue;
|
||||
}
|
||||
mac = diskChildNode.getAttributes().getNamedItem("address").getNodeValue();
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(mac)) {
|
||||
DpdkTO to = dpdkPortsMapping.get(mac);
|
||||
|
||||
for (int z = 0; z < diskChildNodes.getLength(); z++) {
|
||||
Node diskChildNode = diskChildNodes.item(z);
|
||||
|
||||
if ("target".equals(diskChildNode.getNodeName())) {
|
||||
Node targetNode = diskChildNode;
|
||||
Node targetNodeAttr = targetNode.getAttributes().getNamedItem("dev");
|
||||
targetNodeAttr.setNodeValue(to.getPort());
|
||||
} else if ("source".equals(diskChildNode.getNodeName())) {
|
||||
Node sourceNode = diskChildNode;
|
||||
NamedNodeMap attrs = sourceNode.getAttributes();
|
||||
Node path = attrs.getNamedItem("path");
|
||||
path.setNodeValue(to.getPath() + "/" + to.getPort());
|
||||
Node mode = attrs.getNamedItem("mode");
|
||||
mode.setNodeValue(to.getMode());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return getXml(doc);
|
||||
}
|
||||
|
||||
/**
|
||||
* In case of a local file, it deletes the file on the source host/storage pool. Otherwise (for instance iScsi) it disconnects the disk on the source storage pool. </br>
|
||||
* This method must be executed after a successful migration to a target storage pool, cleaning up the source storage.
|
||||
|
|
|
|||
|
|
@ -22,20 +22,28 @@ package com.cloud.hypervisor.kvm.resource.wrapper;
|
|||
import com.cloud.agent.api.Answer;
|
||||
import com.cloud.agent.api.PrepareForMigrationAnswer;
|
||||
import com.cloud.agent.api.PrepareForMigrationCommand;
|
||||
import com.cloud.agent.api.to.DpdkTO;
|
||||
import com.cloud.agent.api.to.DiskTO;
|
||||
import com.cloud.agent.api.to.NicTO;
|
||||
import com.cloud.agent.api.to.VirtualMachineTO;
|
||||
import com.cloud.exception.InternalErrorException;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef.GuestNetType;
|
||||
import com.cloud.hypervisor.kvm.storage.KVMStoragePoolManager;
|
||||
import com.cloud.resource.CommandWrapper;
|
||||
import com.cloud.resource.ResourceWrapper;
|
||||
import com.cloud.storage.Volume;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.utils.script.Script;
|
||||
import org.apache.commons.collections.MapUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.libvirt.Connect;
|
||||
import org.libvirt.LibvirtException;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@ResourceWrapper(handles = PrepareForMigrationCommand.class)
|
||||
public final class LibvirtPrepareForMigrationCommandWrapper extends CommandWrapper<PrepareForMigrationCommand, Answer, LibvirtComputingResource> {
|
||||
|
|
@ -56,6 +64,8 @@ public final class LibvirtPrepareForMigrationCommandWrapper extends CommandWrapp
|
|||
|
||||
final NicTO[] nics = vm.getNics();
|
||||
|
||||
Map<String, DpdkTO> dpdkInterfaceMapping = new HashMap<>();
|
||||
|
||||
boolean skipDisconnect = false;
|
||||
|
||||
final KVMStoragePoolManager storagePoolMgr = libvirtComputingResource.getStoragePoolMgr();
|
||||
|
|
@ -63,8 +73,13 @@ public final class LibvirtPrepareForMigrationCommandWrapper extends CommandWrapp
|
|||
final LibvirtUtilitiesHelper libvirtUtilitiesHelper = libvirtComputingResource.getLibvirtUtilitiesHelper();
|
||||
|
||||
final Connect conn = libvirtUtilitiesHelper.getConnectionByVmName(vm.getName());
|
||||
|
||||
for (final NicTO nic : nics) {
|
||||
libvirtComputingResource.getVifDriver(nic.getType(), nic.getName()).plug(nic, null, "", null);
|
||||
LibvirtVMDef.InterfaceDef interfaceDef = libvirtComputingResource.getVifDriver(nic.getType(), nic.getName()).plug(nic, null, "", vm.getExtraConfig());
|
||||
if (interfaceDef != null && interfaceDef.getNetType() == GuestNetType.VHOSTUSER) {
|
||||
DpdkTO to = new DpdkTO(interfaceDef.getDpdkOvsPath(), interfaceDef.getDpdkSourcePort(), interfaceDef.getInterfaceMode());
|
||||
dpdkInterfaceMapping.put(nic.getMac(), to);
|
||||
}
|
||||
}
|
||||
|
||||
/* setup disks, e.g for iso */
|
||||
|
|
@ -81,12 +96,19 @@ public final class LibvirtPrepareForMigrationCommandWrapper extends CommandWrapp
|
|||
return new PrepareForMigrationAnswer(command, "failed to connect physical disks to host");
|
||||
}
|
||||
|
||||
return new PrepareForMigrationAnswer(command);
|
||||
} catch (final LibvirtException e) {
|
||||
return new PrepareForMigrationAnswer(command, e.toString());
|
||||
} catch (final InternalErrorException e) {
|
||||
return new PrepareForMigrationAnswer(command, e.toString());
|
||||
} catch (final URISyntaxException e) {
|
||||
PrepareForMigrationAnswer answer = new PrepareForMigrationAnswer(command);
|
||||
if (MapUtils.isNotEmpty(dpdkInterfaceMapping)) {
|
||||
answer.setDpdkInterfaceMapping(dpdkInterfaceMapping);
|
||||
}
|
||||
return answer;
|
||||
} catch (final LibvirtException | CloudRuntimeException | InternalErrorException | URISyntaxException e) {
|
||||
if (MapUtils.isNotEmpty(dpdkInterfaceMapping)) {
|
||||
for (DpdkTO to : dpdkInterfaceMapping.values()) {
|
||||
String cmd = String.format("ovs-vsctl del-port %s", to.getPort());
|
||||
s_logger.debug("Removing DPDK port: " + to.getPort());
|
||||
Script.runSimpleBashScript(cmd);
|
||||
}
|
||||
}
|
||||
return new PrepareForMigrationAnswer(command, e.toString());
|
||||
} finally {
|
||||
if (!skipDisconnect) {
|
||||
|
|
|
|||
|
|
@ -69,7 +69,6 @@ public final class LibvirtStartCommandWrapper extends CommandWrapper<StartComman
|
|||
for (final NicTO nic : nics) {
|
||||
if (vmSpec.getType() != VirtualMachine.Type.User) {
|
||||
nic.setPxeDisable(true);
|
||||
nic.setDpdkDisabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,8 +23,12 @@ import java.io.File;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.cloud.agent.api.to.DpdkTO;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.script.Script;
|
||||
import com.cloud.utils.ssh.SshHelper;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.collections.MapUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.libvirt.Connect;
|
||||
import org.libvirt.Domain;
|
||||
|
|
@ -106,11 +110,23 @@ public final class LibvirtStopCommandWrapper extends CommandWrapper<StopCommand,
|
|||
}
|
||||
}
|
||||
|
||||
for (final InterfaceDef iface : ifaces) {
|
||||
// We don't know which "traffic type" is associated with
|
||||
// each interface at this point, so inform all vif drivers
|
||||
for (final VifDriver vifDriver : libvirtComputingResource.getAllVifDrivers()) {
|
||||
vifDriver.unplug(iface);
|
||||
if (CollectionUtils.isEmpty(ifaces)) {
|
||||
Map<String, DpdkTO> dpdkInterfaceMapping = command.getDpdkInterfaceMapping();
|
||||
if (MapUtils.isNotEmpty(dpdkInterfaceMapping)) {
|
||||
for (DpdkTO to : dpdkInterfaceMapping.values()) {
|
||||
String portToRemove = to.getPort();
|
||||
String cmd = String.format("ovs-vsctl del-port %s", portToRemove);
|
||||
s_logger.debug("Removing DPDK port: " + portToRemove);
|
||||
Script.runSimpleBashScript(cmd);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (final InterfaceDef iface : ifaces) {
|
||||
// We don't know which "traffic type" is associated with
|
||||
// each interface at this point, so inform all vif drivers
|
||||
for (final VifDriver vifDriver : libvirtComputingResource.getAllVifDrivers()) {
|
||||
vifDriver.unplug(iface);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,11 +35,11 @@ import java.util.Map;
|
|||
|
||||
@PrepareForTest({ Script.class })
|
||||
@RunWith(PowerMockRunner.class)
|
||||
public class DPDKDriverTest {
|
||||
public class DpdkDriverTest {
|
||||
|
||||
private static final int dpdkPortNumber = 7;
|
||||
|
||||
private DPDKDriver driver = new DPDKDriverImpl();
|
||||
private DpdkDriver driver = new DpdkDriverImpl();
|
||||
|
||||
private Map<String, String> extraConfig;
|
||||
|
||||
|
|
@ -59,7 +59,7 @@ public class DPDKDriverTest {
|
|||
@Test
|
||||
public void testGetDpdkLatestPortNumberUsedExistingDpdkPorts() {
|
||||
Mockito.when(Script.runSimpleBashScript(Matchers.anyString())).
|
||||
thenReturn(DPDKDriverImpl.DPDK_PORT_PREFIX + String.valueOf(dpdkPortNumber));
|
||||
thenReturn(DpdkDriverImpl.DPDK_PORT_PREFIX + String.valueOf(dpdkPortNumber));
|
||||
Assert.assertEquals(dpdkPortNumber, driver.getDpdkLatestPortNumberUsed());
|
||||
}
|
||||
|
||||
|
|
@ -67,47 +67,47 @@ public class DPDKDriverTest {
|
|||
public void testGetNextDpdkPortNoDpdkPorts() {
|
||||
Mockito.when(Script.runSimpleBashScript(Matchers.anyString())).
|
||||
thenReturn(null);
|
||||
String expectedPortName = DPDKDriverImpl.DPDK_PORT_PREFIX + String.valueOf(1);
|
||||
String expectedPortName = DpdkDriverImpl.DPDK_PORT_PREFIX + String.valueOf(1);
|
||||
Assert.assertEquals(expectedPortName, driver.getNextDpdkPort());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetNextDpdkPortExistingDpdkPorts() {
|
||||
Mockito.when(Script.runSimpleBashScript(Matchers.anyString())).
|
||||
thenReturn(DPDKDriverImpl.DPDK_PORT_PREFIX + String.valueOf(dpdkPortNumber));
|
||||
String expectedPortName = DPDKDriverImpl.DPDK_PORT_PREFIX + String.valueOf(dpdkPortNumber + 1);
|
||||
thenReturn(DpdkDriverImpl.DPDK_PORT_PREFIX + String.valueOf(dpdkPortNumber));
|
||||
String expectedPortName = DpdkDriverImpl.DPDK_PORT_PREFIX + String.valueOf(dpdkPortNumber + 1);
|
||||
Assert.assertEquals(expectedPortName, driver.getNextDpdkPort());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetGuestInterfacesModeFromDPDKVhostUserModeClientDPDK() {
|
||||
String guestMode = driver.getGuestInterfacesModeFromDPDKVhostUserMode(DPDKHelper.VHostUserMode.CLIENT);
|
||||
public void testGetGuestInterfacesModeFromDpdkVhostUserModeClientDpdk() {
|
||||
String guestMode = driver.getGuestInterfacesModeFromDpdkVhostUserMode(DpdkHelper.VHostUserMode.CLIENT);
|
||||
Assert.assertEquals("server", guestMode);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetGuestInterfacesModeFromDPDKVhostUserModeServerDPDK() {
|
||||
String guestMode = driver.getGuestInterfacesModeFromDPDKVhostUserMode(DPDKHelper.VHostUserMode.SERVER);
|
||||
public void testGetGuestInterfacesModeFromDpdkVhostUserModeServerDpdk() {
|
||||
String guestMode = driver.getGuestInterfacesModeFromDpdkVhostUserMode(DpdkHelper.VHostUserMode.SERVER);
|
||||
Assert.assertEquals("client", guestMode);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDPDKvHostUserModeServerExtraConfig() {
|
||||
extraConfig.put(DPDKHelper.DPDK_VHOST_USER_MODE, DPDKHelper.VHostUserMode.SERVER.toString());
|
||||
DPDKHelper.VHostUserMode dpdKvHostUserMode = driver.getDPDKvHostUserMode(extraConfig);
|
||||
Assert.assertEquals(DPDKHelper.VHostUserMode.SERVER, dpdKvHostUserMode);
|
||||
public void testGetDpdkvHostUserModeServerExtraConfig() {
|
||||
extraConfig.put(DpdkHelper.DPDK_VHOST_USER_MODE, DpdkHelper.VHostUserMode.SERVER.toString());
|
||||
DpdkHelper.VHostUserMode dpdKvHostUserMode = driver.getDpdkvHostUserMode(extraConfig);
|
||||
Assert.assertEquals(DpdkHelper.VHostUserMode.SERVER, dpdKvHostUserMode);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDPDKvHostUserModeServerClientExtraConfig() {
|
||||
extraConfig.put(DPDKHelper.DPDK_VHOST_USER_MODE, DPDKHelper.VHostUserMode.CLIENT.toString());
|
||||
DPDKHelper.VHostUserMode dpdKvHostUserMode = driver.getDPDKvHostUserMode(extraConfig);
|
||||
Assert.assertEquals(DPDKHelper.VHostUserMode.CLIENT, dpdKvHostUserMode);
|
||||
public void testGetDpdkvHostUserModeServerClientExtraConfig() {
|
||||
extraConfig.put(DpdkHelper.DPDK_VHOST_USER_MODE, DpdkHelper.VHostUserMode.CLIENT.toString());
|
||||
DpdkHelper.VHostUserMode dpdKvHostUserMode = driver.getDpdkvHostUserMode(extraConfig);
|
||||
Assert.assertEquals(DpdkHelper.VHostUserMode.CLIENT, dpdKvHostUserMode);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDPDKvHostUserModeServerEmptyExtraConfig() {
|
||||
DPDKHelper.VHostUserMode dpdKvHostUserMode = driver.getDPDKvHostUserMode(extraConfig);
|
||||
Assert.assertEquals(DPDKHelper.VHostUserMode.SERVER, dpdKvHostUserMode);
|
||||
public void testGetDpdkvHostUserModeServerEmptyExtraConfig() {
|
||||
DpdkHelper.VHostUserMode dpdKvHostUserMode = driver.getDpdkvHostUserMode(extraConfig);
|
||||
Assert.assertEquals(DpdkHelper.VHostUserMode.SERVER, dpdKvHostUserMode);
|
||||
}
|
||||
}
|
||||
|
|
@ -37,6 +37,7 @@ import javax.xml.transform.TransformerException;
|
|||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import com.cloud.agent.api.to.DpdkTO;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.libvirt.Connect;
|
||||
|
|
@ -302,6 +303,146 @@ public class LibvirtMigrateCommandWrapperTest {
|
|||
" </devices>\n" +
|
||||
"</domain>";
|
||||
|
||||
private String sourceDPDKVMToMigrate =
|
||||
"<domain type='kvm' id='17'>\n" +
|
||||
" <name>i-2-33-VM</name>\n" +
|
||||
" <uuid>14c5c052-46cb-4301-a00a-28f6cc1dc605</uuid>\n" +
|
||||
" <description>Other PV (64-bit)</description>\n" +
|
||||
" <memory unit='KiB'>9437184</memory>\n" +
|
||||
" <currentMemory unit='KiB'>9437184</currentMemory>\n" +
|
||||
" <memoryBacking>\n" +
|
||||
" <hugepages/>\n" +
|
||||
" </memoryBacking>\n" +
|
||||
" <vcpu placement='static'>2</vcpu>\n" +
|
||||
" <cputune>\n" +
|
||||
" <shares>4000</shares>\n" +
|
||||
" </cputune>\n" +
|
||||
" <resource>\n" +
|
||||
" <partition>/machine</partition>\n" +
|
||||
" </resource>\n" +
|
||||
" <sysinfo type='smbios'>\n" +
|
||||
" <system>\n" +
|
||||
" <entry name='manufacturer'>Apache Software Foundation</entry>\n" +
|
||||
" <entry name='product'>CloudStack KVM Hypervisor</entry>\n" +
|
||||
" <entry name='uuid'>14c5c052-46cb-4301-a00a-28f6cc1dc605</entry>\n" +
|
||||
" </system>\n" +
|
||||
" </sysinfo>\n" +
|
||||
" <os>\n" +
|
||||
" <type arch='x86_64' machine='pc-i440fx-rhel7.5.0'>hvm</type>\n" +
|
||||
" <boot dev='cdrom'/>\n" +
|
||||
" <boot dev='hd'/>\n" +
|
||||
" <smbios mode='sysinfo'/>\n" +
|
||||
" </os>\n" +
|
||||
" <features>\n" +
|
||||
" <acpi/>\n" +
|
||||
" <apic/>\n" +
|
||||
" <pae/>\n" +
|
||||
" </features>\n" +
|
||||
" <cpu mode='host-passthrough' check='none'>\n" +
|
||||
" <numa>\n" +
|
||||
" <cell id='0' cpus='0' memory='9437184' unit='KiB' memAccess='shared'/>\n" +
|
||||
" </numa>\n" +
|
||||
" </cpu>\n" +
|
||||
" <clock offset='utc'>\n" +
|
||||
" <timer name='kvmclock'/>\n" +
|
||||
" </clock>\n" +
|
||||
" <on_poweroff>destroy</on_poweroff>\n" +
|
||||
" <on_reboot>restart</on_reboot>\n" +
|
||||
" <on_crash>destroy</on_crash>\n" +
|
||||
" <devices>\n" +
|
||||
" <emulator>/usr/libexec/qemu-kvm</emulator>\n" +
|
||||
" <disk type='network' device='disk'>\n" +
|
||||
" <driver name='qemu' type='raw' cache='none'/>\n" +
|
||||
" <auth username='cloudstack'>\n" +
|
||||
" <secret type='ceph' uuid='66afbc07-6fdb-385a-ae25-a9acfbc3684d'/>\n" +
|
||||
" </auth>\n" +
|
||||
" <source protocol='rbd' name='cloudstack/afb1d2e4-01fe-4694-940b-fcf052afa279'>\n" +
|
||||
" <host name='VLAB01-CEPH-MON.ceph.local' port='6789'/>\n" +
|
||||
" </source>\n" +
|
||||
" <target dev='vda' bus='virtio'/>\n" +
|
||||
" <serial>afb1d2e401fe4694940b</serial>\n" +
|
||||
" <alias name='virtio-disk0'/>\n" +
|
||||
" <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>\n" +
|
||||
" </disk>\n" +
|
||||
" <disk type='file' device='cdrom'>\n" +
|
||||
" <target dev='hdc' bus='ide'/>\n" +
|
||||
" <readonly/>\n" +
|
||||
" <alias name='ide0-1-0'/>\n" +
|
||||
" <address type='drive' controller='0' bus='1' target='0' unit='0'/>\n" +
|
||||
" </disk>\n" +
|
||||
" <controller type='usb' index='0' model='piix3-uhci'>\n" +
|
||||
" <alias name='usb'/>\n" +
|
||||
" <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>\n" +
|
||||
" </controller>\n" +
|
||||
" <controller type='pci' index='0' model='pci-root'>\n" +
|
||||
" <alias name='pci.0'/>\n" +
|
||||
" </controller>\n" +
|
||||
" <controller type='ide' index='0'>\n" +
|
||||
" <alias name='ide'/>\n" +
|
||||
" <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>\n" +
|
||||
" </controller>\n" +
|
||||
" <controller type='virtio-serial' index='0'>\n" +
|
||||
" <alias name='virtio-serial0'/>\n" +
|
||||
" <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>\n" +
|
||||
" </controller>\n" +
|
||||
" <interface type='vhostuser'>\n" +
|
||||
" <mac address='02:00:18:91:00:10'/>\n" +
|
||||
" <source type='unix' path='/var/run/libvirt-vhost-user/csdpdk-1' mode='server'/>\n" +
|
||||
" <target dev='csdpdk-1'/>\n" +
|
||||
" <model type='virtio'/>\n" +
|
||||
" <alias name='net0'/>\n" +
|
||||
" <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>\n" +
|
||||
" </interface>\n" +
|
||||
" <serial type='pty'>\n" +
|
||||
" <source path='/dev/pts/0'/>\n" +
|
||||
" <target type='isa-serial' port='0'>\n" +
|
||||
" <model name='isa-serial'/>\n" +
|
||||
" </target>\n" +
|
||||
" <alias name='serial0'/>\n" +
|
||||
" </serial>\n" +
|
||||
" <console type='pty' tty='/dev/pts/0'>\n" +
|
||||
" <source path='/dev/pts/0'/>\n" +
|
||||
" <target type='serial' port='0'/>\n" +
|
||||
" <alias name='serial0'/>\n" +
|
||||
" </console>\n" +
|
||||
" <channel type='unix'>\n" +
|
||||
" <source mode='bind' path='/var/lib/libvirt/qemu/i-2-33-VM.org.qemu.guest_agent.0'/>\n" +
|
||||
" <target type='virtio' name='org.qemu.guest_agent.0' state='disconnected'/>\n" +
|
||||
" <alias name='channel0'/>\n" +
|
||||
" <address type='virtio-serial' controller='0' bus='0' port='1'/>\n" +
|
||||
" </channel>\n" +
|
||||
" <input type='tablet' bus='usb'>\n" +
|
||||
" <alias name='input0'/>\n" +
|
||||
" <address type='usb' bus='0' port='1'/>\n" +
|
||||
" </input>\n" +
|
||||
" <input type='mouse' bus='ps2'>\n" +
|
||||
" <alias name='input1'/>\n" +
|
||||
" </input>\n" +
|
||||
" <input type='keyboard' bus='ps2'>\n" +
|
||||
" <alias name='input2'/>\n" +
|
||||
" </input>\n" +
|
||||
" <graphics type='vnc' port='5900' autoport='yes' listen='198.19.254.10'>\n" +
|
||||
" <listen type='address' address='198.19.254.10'/>\n" +
|
||||
" </graphics>\n" +
|
||||
" <video>\n" +
|
||||
" <model type='cirrus' vram='16384' heads='1' primary='yes'/>\n" +
|
||||
" <alias name='video0'/>\n" +
|
||||
" <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>\n" +
|
||||
" </video>\n" +
|
||||
" <watchdog model='i6300esb' action='none'>\n" +
|
||||
" <alias name='watchdog0'/>\n" +
|
||||
" <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>\n" +
|
||||
" </watchdog>\n" +
|
||||
" <memballoon model='none'>\n" +
|
||||
" <alias name='balloon0'/>\n" +
|
||||
" </memballoon>\n" +
|
||||
" </devices>\n" +
|
||||
" <seclabel type='dynamic' model='dac' relabel='yes'>\n" +
|
||||
" <label>+0:+0</label>\n" +
|
||||
" <imagelabel>+0:+0</imagelabel>\n" +
|
||||
" </seclabel>\n" +
|
||||
"</domain>";
|
||||
|
||||
LibvirtMigrateCommandWrapper libvirtMigrateCmdWrapper = new LibvirtMigrateCommandWrapper();
|
||||
|
||||
final String memInfo = "MemTotal: 5830236 kB\n" +
|
||||
|
|
@ -636,4 +777,16 @@ public class LibvirtMigrateCommandWrapperTest {
|
|||
assertFalse(newXml.contains("/mnt/" + sourcePoolUuid + "/" + disk1SourceFilename));
|
||||
assertFalse(newXml.contains("/mnt/" + sourcePoolUuid + "/" + disk2SourceFilename));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReplaceDPDKPorts() throws ParserConfigurationException, IOException, SAXException, TransformerException {
|
||||
final LibvirtMigrateCommandWrapper lw = new LibvirtMigrateCommandWrapper();
|
||||
Map<String, DpdkTO> dpdkPortMapping = new HashMap<>();
|
||||
DpdkTO to = new DpdkTO("/var/run/libvirt-vhost-user", "csdpdk-7", "client");
|
||||
dpdkPortMapping.put("02:00:18:91:00:10", to);
|
||||
String replaced = lw.replaceDpdkInterfaces(sourceDPDKVMToMigrate, dpdkPortMapping);
|
||||
Assert.assertTrue(replaced.contains("csdpdk-7"));
|
||||
Assert.assertFalse(replaced.contains("csdpdk-1"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
2
pom.xml
2
pom.xml
|
|
@ -160,7 +160,7 @@
|
|||
<cs.servlet.version>4.0.0</cs.servlet.version>
|
||||
<cs.tomcat-embed-core.version>8.0.30</cs.tomcat-embed-core.version>
|
||||
<cs.trilead.version>1.0.0-build221</cs.trilead.version>
|
||||
<cs.vmware.api.version>6.5</cs.vmware.api.version>
|
||||
<cs.vmware.api.version>6.7</cs.vmware.api.version>
|
||||
<cs.xapi.version>6.2.0-3.1</cs.xapi.version>
|
||||
<cs.xml-apis.version>1.4.01</cs.xml-apis.version>
|
||||
<cs.xmlrpc.version>3.1.3</cs.xmlrpc.version>
|
||||
|
|
|
|||
|
|
@ -3263,11 +3263,11 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||
|
||||
@Override
|
||||
public UsageRecordResponse createUsageResponse(Usage usageRecord) {
|
||||
return createUsageResponse(usageRecord, null);
|
||||
return createUsageResponse(usageRecord, null, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UsageRecordResponse createUsageResponse(Usage usageRecord, Map<String, Set<ResourceTagResponse>> resourceTagResponseMap) {
|
||||
public UsageRecordResponse createUsageResponse(Usage usageRecord, Map<String, Set<ResourceTagResponse>> resourceTagResponseMap, boolean oldFormat) {
|
||||
UsageRecordResponse usageRecResponse = new UsageRecordResponse();
|
||||
Account account = ApiDBUtils.findAccountById(usageRecord.getAccountId());
|
||||
if (account.getType() == Account.ACCOUNT_TYPE_PROJECT) {
|
||||
|
|
@ -3297,15 +3297,17 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||
usageRecResponse.setDescription(usageRecord.getDescription());
|
||||
usageRecResponse.setUsage(usageRecord.getUsageDisplay());
|
||||
usageRecResponse.setUsageType(usageRecord.getUsageType());
|
||||
VMInstanceVO vmInstance = null;
|
||||
if (usageRecord.getVmInstanceId() != null) {
|
||||
VMInstanceVO vm = _entityMgr.findByIdIncludingRemoved(VMInstanceVO.class, usageRecord.getVmInstanceId());
|
||||
if (vm != null) {
|
||||
usageRecResponse.setVirtualMachineId(vm.getUuid());
|
||||
vmInstance = _entityMgr.findByIdIncludingRemoved(VMInstanceVO.class, usageRecord.getVmInstanceId());
|
||||
if (vmInstance != null) {
|
||||
usageRecResponse.setVirtualMachineId(vmInstance.getUuid());
|
||||
}
|
||||
}
|
||||
usageRecResponse.setVmName(usageRecord.getVmName());
|
||||
usageRecResponse.setResourceName(usageRecord.getVmName());
|
||||
VMTemplateVO template = null;
|
||||
if (usageRecord.getTemplateId() != null) {
|
||||
VMTemplateVO template = ApiDBUtils.findTemplateById(usageRecord.getTemplateId());
|
||||
template = ApiDBUtils.findTemplateById(usageRecord.getTemplateId());
|
||||
if (template != null) {
|
||||
usageRecResponse.setTemplateId(template.getUuid());
|
||||
}
|
||||
|
|
@ -3320,7 +3322,12 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||
usageRecResponse.setOfferingId(svcOffering.getUuid());
|
||||
}
|
||||
//VM Instance ID
|
||||
VMInstanceVO vm = _entityMgr.findByIdIncludingRemoved(VMInstanceVO.class, usageRecord.getUsageId().toString());
|
||||
VMInstanceVO vm = null;
|
||||
if (usageRecord.getUsageId() != null && usageRecord.getUsageId().equals(usageRecord.getVmInstanceId())) {
|
||||
vm = vmInstance;
|
||||
} else {
|
||||
vm = _entityMgr.findByIdIncludingRemoved(VMInstanceVO.class, usageRecord.getUsageId().toString());
|
||||
}
|
||||
if (vm != null) {
|
||||
resourceType = ResourceTag.ResourceObjectType.UserVm;
|
||||
usageRecResponse.setUsageId(vm.getUuid());
|
||||
|
|
@ -3344,7 +3351,24 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||
} else if(svcOffering.getRamSize() != null) {
|
||||
usageRecResponse.setMemory(svcOffering.getRamSize().longValue());
|
||||
}
|
||||
|
||||
if (!oldFormat) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
if (usageRecord.getUsageType() == UsageTypes.RUNNING_VM) {
|
||||
builder.append("Running VM usage ");
|
||||
} else if(usageRecord.getUsageType() == UsageTypes.ALLOCATED_VM) {
|
||||
builder.append("Allocated VM usage ");
|
||||
}
|
||||
if (vm != null) {
|
||||
builder.append("for ").append(vm.getHostName()).append(" (").append(vm.getInstanceName()).append(", ").append(vm.getUuid()).append(") ");
|
||||
}
|
||||
if (svcOffering != null) {
|
||||
builder.append("using service offering ").append(svcOffering.getName()).append(" (").append(svcOffering.getUuid()).append(") ");
|
||||
}
|
||||
if (template != null) {
|
||||
builder.append("and template ").append(template.getName()).append(" (").append(template.getUuid()).append(")");
|
||||
}
|
||||
usageRecResponse.setDescription(builder.toString());
|
||||
}
|
||||
} else if (usageRecord.getUsageType() == UsageTypes.IP_ADDRESS) {
|
||||
//IP Address ID
|
||||
IPAddressVO ip = _entityMgr.findByIdIncludingRemoved(IPAddressVO.class, usageRecord.getUsageId().toString());
|
||||
|
|
@ -3370,46 +3394,80 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||
//Device Type
|
||||
resourceType = ResourceObjectType.UserVm;
|
||||
usageRecResponse.setType(usageRecord.getType());
|
||||
VMInstanceVO vm = null;
|
||||
HostVO host = null;
|
||||
if (usageRecord.getType().equals("DomainRouter") || usageRecord.getType().equals("UserVm")) {
|
||||
//Domain Router Id
|
||||
VMInstanceVO vm = _entityMgr.findByIdIncludingRemoved(VMInstanceVO.class, usageRecord.getUsageId().toString());
|
||||
vm = _entityMgr.findByIdIncludingRemoved(VMInstanceVO.class, usageRecord.getUsageId().toString());
|
||||
if (vm != null) {
|
||||
resourceId = vm.getId();
|
||||
usageRecResponse.setUsageId(vm.getUuid());
|
||||
}
|
||||
} else {
|
||||
//External Device Host Id
|
||||
HostVO host = _entityMgr.findByIdIncludingRemoved(HostVO.class, usageRecord.getUsageId().toString());
|
||||
host = _entityMgr.findByIdIncludingRemoved(HostVO.class, usageRecord.getUsageId().toString());
|
||||
if (host != null) {
|
||||
usageRecResponse.setUsageId(host.getUuid());
|
||||
}
|
||||
}
|
||||
//Network ID
|
||||
NetworkVO network = null;
|
||||
if((usageRecord.getNetworkId() != null) && (usageRecord.getNetworkId() != 0)) {
|
||||
NetworkVO network = _entityMgr.findByIdIncludingRemoved(NetworkVO.class, usageRecord.getNetworkId().toString());
|
||||
network = _entityMgr.findByIdIncludingRemoved(NetworkVO.class, usageRecord.getNetworkId().toString());
|
||||
if (network != null) {
|
||||
resourceType = ResourceObjectType.Network;
|
||||
resourceId = network.getId();
|
||||
usageRecResponse.setNetworkId(network.getUuid());
|
||||
usageRecResponse.setResourceName(network.getName());
|
||||
}
|
||||
}
|
||||
if (!oldFormat) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
if (usageRecord.getUsageType() == UsageTypes.NETWORK_BYTES_SENT) {
|
||||
builder.append("Bytes sent by network ");
|
||||
} else if (usageRecord.getUsageType() == UsageTypes.NETWORK_BYTES_RECEIVED) {
|
||||
builder.append("Bytes received by network ");
|
||||
}
|
||||
if (network != null) {
|
||||
builder.append(network.getName()).append(" (").append(network.getUuid()).append(") ");
|
||||
}
|
||||
if (vm != null) {
|
||||
builder.append("using router ").append(vm.getInstanceName()).append(" (").append(vm.getUuid()).append(")");
|
||||
} else if (host != null) {
|
||||
builder.append("using host ").append(host.getName()).append(" (").append(host.getUuid()).append(")");
|
||||
}
|
||||
usageRecResponse.setDescription(builder.toString());
|
||||
}
|
||||
} else if (usageRecord.getUsageType() == UsageTypes.VM_DISK_IO_READ || usageRecord.getUsageType() == UsageTypes.VM_DISK_IO_WRITE
|
||||
|| usageRecord.getUsageType() == UsageTypes.VM_DISK_BYTES_READ || usageRecord.getUsageType() == UsageTypes.VM_DISK_BYTES_WRITE) {
|
||||
//Device Type
|
||||
usageRecResponse.setType(usageRecord.getType());
|
||||
resourceType = ResourceObjectType.Volume;
|
||||
//VM Instance Id
|
||||
VMInstanceVO vm = _entityMgr.findByIdIncludingRemoved(VMInstanceVO.class, usageRecord.getVmInstanceId().toString());
|
||||
if (vm != null) {
|
||||
usageRecResponse.setVirtualMachineId(vm.getUuid());
|
||||
}
|
||||
//Volume ID
|
||||
VolumeVO volume = _entityMgr.findByIdIncludingRemoved(VolumeVO.class, usageRecord.getUsageId().toString());
|
||||
if (volume != null) {
|
||||
usageRecResponse.setUsageId(volume.getUuid());
|
||||
resourceId = volume.getId();
|
||||
}
|
||||
|
||||
if (!oldFormat) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
if (usageRecord.getUsageType() == UsageTypes.VM_DISK_IO_READ) {
|
||||
builder.append("Disk I/O read requests");
|
||||
} else if (usageRecord.getUsageType() == UsageTypes.VM_DISK_IO_WRITE) {
|
||||
builder.append("Disk I/O write requests");
|
||||
} else if (usageRecord.getUsageType() == UsageTypes.VM_DISK_BYTES_READ) {
|
||||
builder.append("Disk I/O read bytes");
|
||||
} else if (usageRecord.getUsageType() == UsageTypes.VM_DISK_BYTES_WRITE) {
|
||||
builder.append("Disk I/O write bytes");
|
||||
}
|
||||
if (vmInstance != null) {
|
||||
builder.append(" for VM ").append(vmInstance.getHostName()).append(" (").append(vmInstance.getUuid()).append(")");
|
||||
}
|
||||
if (volume != null) {
|
||||
builder.append(" and volume ").append(volume.getName()).append(" (").append(volume.getUuid()).append(")");
|
||||
}
|
||||
usageRecResponse.setDescription(builder.toString());
|
||||
}
|
||||
} else if (usageRecord.getUsageType() == UsageTypes.VOLUME) {
|
||||
//Volume ID
|
||||
VolumeVO volume = _entityMgr.findByIdIncludingRemoved(VolumeVO.class, usageRecord.getUsageId().toString());
|
||||
|
|
@ -3421,11 +3479,25 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||
//Volume Size
|
||||
usageRecResponse.setSize(usageRecord.getSize());
|
||||
//Disk Offering Id
|
||||
DiskOfferingVO diskOff = null;
|
||||
if (usageRecord.getOfferingId() != null) {
|
||||
DiskOfferingVO diskOff = _entityMgr.findByIdIncludingRemoved(DiskOfferingVO.class, usageRecord.getOfferingId().toString());
|
||||
diskOff = _entityMgr.findByIdIncludingRemoved(DiskOfferingVO.class, usageRecord.getOfferingId().toString());
|
||||
usageRecResponse.setOfferingId(diskOff.getUuid());
|
||||
}
|
||||
|
||||
if (!oldFormat) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append("Volume usage ");
|
||||
if (volume != null) {
|
||||
builder.append("for ").append(volume.getName()).append(" (").append(volume.getUuid()).append(")");
|
||||
}
|
||||
if (diskOff != null) {
|
||||
builder.append(" with disk offering ").append(diskOff.getName()).append(" (").append(diskOff.getUuid()).append(")");
|
||||
}
|
||||
if (template != null) {
|
||||
builder.append(" and template ").append(template.getName()).append(" (").append(template.getUuid()).append(")");
|
||||
}
|
||||
usageRecResponse.setDescription(builder.toString());
|
||||
}
|
||||
} else if (usageRecord.getUsageType() == UsageTypes.TEMPLATE || usageRecord.getUsageType() == UsageTypes.ISO) {
|
||||
//Template/ISO ID
|
||||
VMTemplateVO tmpl = _entityMgr.findByIdIncludingRemoved(VMTemplateVO.class, usageRecord.getUsageId().toString());
|
||||
|
|
@ -3442,7 +3514,19 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||
usageRecResponse.setVirtualSize(usageRecord.getVirtualSize());
|
||||
resourceType = ResourceObjectType.Template;
|
||||
}
|
||||
|
||||
if (!oldFormat) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
if (usageRecord.getUsageType() == UsageTypes.TEMPLATE) {
|
||||
builder.append("Template usage");
|
||||
} else if (usageRecord.getUsageType() == UsageTypes.ISO) {
|
||||
builder.append("ISO usage");
|
||||
}
|
||||
if (tmpl != null) {
|
||||
builder.append(" for ").append(tmpl.getName()).append(" (").append(tmpl.getUuid()).append(") ")
|
||||
.append("with size ").append(usageRecord.getSize()).append(" and virtual size ").append(usageRecord.getVirtualSize());
|
||||
}
|
||||
usageRecResponse.setDescription(builder.toString());
|
||||
}
|
||||
} else if (usageRecord.getUsageType() == UsageTypes.SNAPSHOT) {
|
||||
//Snapshot ID
|
||||
SnapshotVO snap = _entityMgr.findByIdIncludingRemoved(SnapshotVO.class, usageRecord.getUsageId().toString());
|
||||
|
|
@ -3453,7 +3537,15 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||
}
|
||||
//Snapshot Size
|
||||
usageRecResponse.setSize(usageRecord.getSize());
|
||||
|
||||
if (!oldFormat) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append("Snapshot usage ");
|
||||
if (snap != null) {
|
||||
builder.append("for ").append(snap.getName()).append(" (").append(snap.getUuid()).append(") ")
|
||||
.append("with size ").append(usageRecord.getSize());
|
||||
}
|
||||
usageRecResponse.setDescription(builder.toString());
|
||||
}
|
||||
} else if (usageRecord.getUsageType() == UsageTypes.LOAD_BALANCER_POLICY) {
|
||||
//Load Balancer Policy ID
|
||||
LoadBalancerVO lb = _entityMgr.findByIdIncludingRemoved(LoadBalancerVO.class, usageRecord.getUsageId().toString());
|
||||
|
|
@ -3462,6 +3554,14 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||
usageRecResponse.setUsageId(lb.getUuid());
|
||||
resourceId = lb.getId();
|
||||
}
|
||||
if (!oldFormat) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append("Loadbalancer policy usage ");
|
||||
if (lb != null) {
|
||||
builder.append(lb.getName()).append(" (").append(lb.getUuid()).append(")");
|
||||
}
|
||||
usageRecResponse.setDescription(builder.toString());
|
||||
}
|
||||
} else if (usageRecord.getUsageType() == UsageTypes.PORT_FORWARDING_RULE) {
|
||||
//Port Forwarding Rule ID
|
||||
PortForwardingRuleVO pf = _entityMgr.findByIdIncludingRemoved(PortForwardingRuleVO.class, usageRecord.getUsageId().toString());
|
||||
|
|
@ -3470,20 +3570,45 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||
usageRecResponse.setUsageId(pf.getUuid());
|
||||
resourceId = pf.getId();
|
||||
}
|
||||
|
||||
if (!oldFormat) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append("Port forwarding rule usage");
|
||||
if (pf != null) {
|
||||
builder.append(" (").append(pf.getUuid()).append(")");
|
||||
}
|
||||
usageRecResponse.setDescription(builder.toString());
|
||||
}
|
||||
} else if (usageRecord.getUsageType() == UsageTypes.NETWORK_OFFERING) {
|
||||
//Network Offering Id
|
||||
NetworkOfferingVO netOff = _entityMgr.findByIdIncludingRemoved(NetworkOfferingVO.class, usageRecord.getOfferingId().toString());
|
||||
usageRecResponse.setOfferingId(netOff.getUuid());
|
||||
//is Default
|
||||
usageRecResponse.setDefault((usageRecord.getUsageId() == 1) ? true : false);
|
||||
|
||||
usageRecResponse.setDefault(usageRecord.getUsageId() == 1);
|
||||
if (!oldFormat) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append("Network offering ");
|
||||
if (netOff != null) {
|
||||
builder.append(netOff.getName()).append(" (").append(netOff.getUuid()).append(") usage ");
|
||||
}
|
||||
if (vmInstance != null) {
|
||||
builder.append("for VM ").append(vmInstance.getHostName()).append(" (").append(vmInstance.getUuid()).append(") ");
|
||||
}
|
||||
usageRecResponse.setDescription(builder.toString());
|
||||
}
|
||||
} else if (usageRecord.getUsageType() == UsageTypes.VPN_USERS) {
|
||||
//VPN User ID
|
||||
VpnUserVO vpnUser = _entityMgr.findByIdIncludingRemoved(VpnUserVO.class, usageRecord.getUsageId().toString());
|
||||
if (vpnUser != null) {
|
||||
usageRecResponse.setUsageId(vpnUser.getUuid());
|
||||
}
|
||||
if (!oldFormat) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append("VPN usage ");
|
||||
if (vpnUser != null) {
|
||||
builder.append("for user ").append(vpnUser.getUsername()).append(" (").append(vpnUser.getUuid()).append(")");
|
||||
}
|
||||
usageRecResponse.setDescription(builder.toString());
|
||||
}
|
||||
} else if (usageRecord.getUsageType() == UsageTypes.SECURITY_GROUP) {
|
||||
//Security Group Id
|
||||
SecurityGroupVO sg = _entityMgr.findByIdIncludingRemoved(SecurityGroupVO.class, usageRecord.getUsageId().toString());
|
||||
|
|
@ -3492,20 +3617,69 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||
resourceId = sg.getId();
|
||||
usageRecResponse.setUsageId(sg.getUuid());
|
||||
}
|
||||
if (!oldFormat) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append("Security group");
|
||||
if (sg != null) {
|
||||
builder.append(" ").append(sg.getName()).append(" (").append(sg.getUuid()).append(") usage");
|
||||
}
|
||||
if (vmInstance != null) {
|
||||
builder.append(" for VM ").append(vmInstance.getHostName()).append(" (").append(vmInstance.getUuid()).append(")");
|
||||
}
|
||||
usageRecResponse.setDescription(builder.toString());
|
||||
}
|
||||
} else if (usageRecord.getUsageType() == UsageTypes.VM_SNAPSHOT) {
|
||||
VMInstanceVO vm = _entityMgr.findByIdIncludingRemoved(VMInstanceVO.class, usageRecord.getVmInstanceId().toString());
|
||||
resourceType = ResourceObjectType.UserVm;
|
||||
if (vm != null) {
|
||||
resourceId = vm.getId();
|
||||
usageRecResponse.setVmName(vm.getInstanceName());
|
||||
usageRecResponse.setUsageId(vm.getUuid());
|
||||
if (vmInstance != null) {
|
||||
resourceId = vmInstance.getId();
|
||||
usageRecResponse.setResourceName(vmInstance.getInstanceName());
|
||||
usageRecResponse.setUsageId(vmInstance.getUuid());
|
||||
}
|
||||
usageRecResponse.setSize(usageRecord.getSize());
|
||||
if (usageRecord.getOfferingId() != null) {
|
||||
usageRecResponse.setOfferingId(usageRecord.getOfferingId().toString());
|
||||
}
|
||||
if (!oldFormat) {
|
||||
VolumeVO volume = _entityMgr.findByIdIncludingRemoved(VolumeVO.class, usageRecord.getUsageId().toString());
|
||||
DiskOfferingVO diskOff = null;
|
||||
if (usageRecord.getOfferingId() != null) {
|
||||
diskOff = _entityMgr.findByIdIncludingRemoved(DiskOfferingVO.class, usageRecord.getOfferingId());
|
||||
}
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append("VMSnapshot usage");
|
||||
if (vmInstance != null) {
|
||||
builder.append(" for VM ").append(vmInstance.getHostName()).append(" (").append(vmInstance.getUuid()).append(")");
|
||||
}
|
||||
if (volume != null) {
|
||||
builder.append(" with volume ").append(volume.getName()).append(" (").append(volume.getUuid()).append(")");
|
||||
}
|
||||
if (diskOff != null) {
|
||||
builder.append(" using disk offering ").append(diskOff.getName()).append(" (").append(diskOff.getUuid()).append(")");
|
||||
}
|
||||
usageRecResponse.setDescription(builder.toString());
|
||||
}
|
||||
} else if (usageRecord.getUsageType() == UsageTypes.VOLUME_SECONDARY) {
|
||||
VolumeVO volume = _entityMgr.findByIdIncludingRemoved(VolumeVO.class, usageRecord.getUsageId().toString());
|
||||
if (!oldFormat) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append("Volume on secondary storage usage");
|
||||
if (volume != null) {
|
||||
builder.append(" for ").append(volume.getName()).append(" (").append(volume.getUuid()).append(") ")
|
||||
.append("with size ").append(usageRecord.getSize());
|
||||
}
|
||||
usageRecResponse.setDescription(builder.toString());
|
||||
}
|
||||
} else if (usageRecord.getUsageType() == UsageTypes.VM_SNAPSHOT_ON_PRIMARY) {
|
||||
if (!oldFormat) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append("VMSnapshot on primary storage usage");
|
||||
if (vmInstance != null) {
|
||||
builder.append(" for VM ").append(vmInstance.getHostName()).append(" (").append(vmInstance.getUuid()).append(") ")
|
||||
.append("with size ").append(usageRecord.getVirtualSize());
|
||||
}
|
||||
usageRecResponse.setDescription(builder.toString());
|
||||
}
|
||||
}
|
||||
|
||||
if(resourceTagResponseMap != null && resourceTagResponseMap.get(resourceId + ":" + resourceType) != null) {
|
||||
usageRecResponse.setTags(resourceTagResponseMap.get(resourceId + ":" + resourceType));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -849,7 +849,7 @@ public enum Config {
|
|||
"The interval (in milliseconds) when vm stats are retrieved from agents.",
|
||||
null),
|
||||
VmDiskStatsInterval("Advanced", ManagementServer.class, Integer.class, "vm.disk.stats.interval", "0", "Interval (in seconds) to report vm disk statistics.", null),
|
||||
VolumeStatsInterval("Advanced", ManagementServer.class, Integer.class, "volume.stats.interval", "60000", "Interval (in seconds) to report volume statistics.", null),
|
||||
VolumeStatsInterval("Advanced", ManagementServer.class, Integer.class, "volume.stats.interval", "60000", "Interval (in miliseconds) to report volume statistics.", null),
|
||||
VmTransitionWaitInterval(
|
||||
"Advanced",
|
||||
ManagementServer.class,
|
||||
|
|
|
|||
|
|
@ -22,7 +22,9 @@ import java.util.UUID;
|
|||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.cloud.agent.api.Command;
|
||||
|
|
@ -126,6 +128,34 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis
|
|||
return to;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add extra configuration from VM details. Extra configuration is stored as details starting with 'extraconfig'
|
||||
*/
|
||||
private void addExtraConfig(Map<String, String> details, VirtualMachineTO to) {
|
||||
for (String key : details.keySet()) {
|
||||
if (key.startsWith(ApiConstants.EXTRA_CONFIG)) {
|
||||
to.addExtraConfig(key, details.get(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add extra configurations from service offering to the VM TO.
|
||||
* Extra configuration keys are expected in formats:
|
||||
* - "extraconfig-N"
|
||||
* - "extraconfig-CONFIG_NAME"
|
||||
*/
|
||||
protected void addServiceOfferingExtraConfiguration(ServiceOffering offering, VirtualMachineTO to) {
|
||||
List<ServiceOfferingDetailsVO> details = _serviceOfferingDetailsDao.listDetails(offering.getId());
|
||||
if (CollectionUtils.isNotEmpty(details)) {
|
||||
for (ServiceOfferingDetailsVO detail : details) {
|
||||
if (detail.getName().startsWith(ApiConstants.EXTRA_CONFIG)) {
|
||||
to.addExtraConfig(detail.getName(), detail.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected VirtualMachineTO toVirtualMachineTO(VirtualMachineProfile vmProfile) {
|
||||
ServiceOffering offering = _serviceOfferingDao.findById(vmProfile.getId(), vmProfile.getServiceOfferingId());
|
||||
VirtualMachine vm = vmProfile.getVirtualMachine();
|
||||
|
|
@ -169,8 +199,11 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis
|
|||
Map<String, String> detailsInVm = _userVmDetailsDao.listDetailsKeyPairs(vm.getId());
|
||||
if (detailsInVm != null) {
|
||||
to.setDetails(detailsInVm);
|
||||
addExtraConfig(detailsInVm, to);
|
||||
}
|
||||
|
||||
addServiceOfferingExtraConfiguration(offering, to);
|
||||
|
||||
// Set GPU details
|
||||
ServiceOfferingDetailsVO offeringDetail = _serviceOfferingDetailsDao.findDetail(offering.getId(), GPU.Keys.vgpuType.toString());
|
||||
if (offeringDetail != null) {
|
||||
|
|
|
|||
|
|
@ -18,13 +18,12 @@ package com.cloud.hypervisor;
|
|||
|
||||
import com.cloud.agent.api.Command;
|
||||
import com.cloud.agent.api.to.DataObjectType;
|
||||
import com.cloud.agent.api.to.NicTO;
|
||||
import com.cloud.agent.api.to.VirtualMachineTO;
|
||||
import com.cloud.host.HostVO;
|
||||
import com.cloud.host.dao.HostDao;
|
||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||
import com.cloud.hypervisor.kvm.dpdk.DPDKHelper;
|
||||
import com.cloud.offering.ServiceOffering;
|
||||
import com.cloud.service.ServiceOfferingDetailsVO;
|
||||
import com.cloud.hypervisor.kvm.dpdk.DpdkHelper;
|
||||
import com.cloud.storage.DataStoreRole;
|
||||
import com.cloud.storage.GuestOSHypervisorVO;
|
||||
import com.cloud.storage.GuestOSVO;
|
||||
|
|
@ -34,16 +33,14 @@ import com.cloud.utils.Pair;
|
|||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
import com.cloud.vm.VirtualMachineProfile;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.storage.command.CopyCommand;
|
||||
import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.collections.MapUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class KVMGuru extends HypervisorGuruBase implements HypervisorGuru {
|
||||
|
|
@ -54,7 +51,7 @@ public class KVMGuru extends HypervisorGuruBase implements HypervisorGuru {
|
|||
@Inject
|
||||
HostDao _hostDao;
|
||||
@Inject
|
||||
DPDKHelper dpdkHelper;
|
||||
DpdkHelper dpdkHelper;
|
||||
|
||||
public static final Logger s_logger = Logger.getLogger(KVMGuru.class);
|
||||
|
||||
|
|
@ -114,12 +111,18 @@ public class KVMGuru extends HypervisorGuruBase implements HypervisorGuru {
|
|||
public VirtualMachineTO implement(VirtualMachineProfile vm) {
|
||||
VirtualMachineTO to = toVirtualMachineTO(vm);
|
||||
setVmQuotaPercentage(to, vm);
|
||||
addServiceOfferingExtraConfiguration(to, vm);
|
||||
|
||||
if (dpdkHelper.isDPDKvHostUserModeSettingOnServiceOffering(vm)) {
|
||||
if (dpdkHelper.isDpdkvHostUserModeSettingOnServiceOffering(vm)) {
|
||||
dpdkHelper.setDpdkVhostUserMode(to, vm);
|
||||
}
|
||||
|
||||
if (to.getType() == VirtualMachine.Type.User && MapUtils.isNotEmpty(to.getExtraConfig()) &&
|
||||
to.getExtraConfig().containsKey(DpdkHelper.DPDK_NUMA) && to.getExtraConfig().containsKey(DpdkHelper.DPDK_HUGE_PAGES)) {
|
||||
for (final NicTO nic : to.getNics()) {
|
||||
nic.setDpdkEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Determine the VM's OS description
|
||||
GuestOSVO guestOS = _guestOsDao.findByIdIncludingRemoved(vm.getVirtualMachine().getGuestOSId());
|
||||
to.setOs(guestOS.getDisplayName());
|
||||
|
|
@ -137,24 +140,6 @@ public class KVMGuru extends HypervisorGuruBase implements HypervisorGuru {
|
|||
return to;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add extra configurations from service offering to the VM TO.
|
||||
* Extra configuration keys are expected in formats:
|
||||
* - "extraconfig-N"
|
||||
* - "extraconfig-CONFIG_NAME"
|
||||
*/
|
||||
protected void addServiceOfferingExtraConfiguration(VirtualMachineTO to, VirtualMachineProfile vmProfile) {
|
||||
ServiceOffering offering = vmProfile.getServiceOffering();
|
||||
List<ServiceOfferingDetailsVO> details = _serviceOfferingDetailsDao.listDetails(offering.getId());
|
||||
if (CollectionUtils.isNotEmpty(details)) {
|
||||
for (ServiceOfferingDetailsVO detail : details) {
|
||||
if (detail.getName().startsWith(ApiConstants.EXTRA_CONFIG)) {
|
||||
to.addExtraConfig(detail.getName(), detail.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<Boolean, Long> getCommandHostDelegation(long hostId, Command cmd) {
|
||||
if (cmd instanceof StorageSubSystemCommand) {
|
||||
|
|
|
|||
|
|
@ -1,68 +0,0 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package com.cloud.hypervisor.kvm.dpdk;
|
||||
|
||||
import com.cloud.agent.api.to.VirtualMachineTO;
|
||||
import com.cloud.offering.ServiceOffering;
|
||||
import com.cloud.service.ServiceOfferingDetailsVO;
|
||||
import com.cloud.service.dao.ServiceOfferingDetailsDao;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.vm.VirtualMachineProfile;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class DPDKHelperImpl implements DPDKHelper {
|
||||
|
||||
@Inject
|
||||
ServiceOfferingDetailsDao serviceOfferingDetailsDao;
|
||||
|
||||
public static final Logger s_logger = Logger.getLogger(DPDKHelperImpl.class);
|
||||
|
||||
private ServiceOffering getServiceOfferingFromVMProfile(VirtualMachineProfile virtualMachineProfile) {
|
||||
ServiceOffering offering = virtualMachineProfile.getServiceOffering();
|
||||
if (offering == null) {
|
||||
throw new CloudRuntimeException("VM does not have an associated service offering");
|
||||
}
|
||||
return offering;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDPDKvHostUserModeSettingOnServiceOffering(VirtualMachineProfile vm) {
|
||||
ServiceOffering offering = getServiceOfferingFromVMProfile(vm);
|
||||
ServiceOfferingDetailsVO detail = serviceOfferingDetailsDao.findDetail(offering.getId(), DPDK_VHOST_USER_MODE);
|
||||
return detail != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDpdkVhostUserMode(VirtualMachineTO to, VirtualMachineProfile vm) {
|
||||
ServiceOffering offering = getServiceOfferingFromVMProfile(vm);
|
||||
ServiceOfferingDetailsVO detail = serviceOfferingDetailsDao.findDetail(offering.getId(), DPDK_VHOST_USER_MODE);
|
||||
if (detail != null) {
|
||||
String mode = detail.getValue();
|
||||
try {
|
||||
VHostUserMode dpdKvHostUserMode = VHostUserMode.fromValue(mode);
|
||||
to.addExtraConfig(DPDK_VHOST_USER_MODE, dpdKvHostUserMode.toString());
|
||||
} catch (IllegalArgumentException e) {
|
||||
s_logger.error(String.format("DPDK vHost User mode found as a detail for service offering: %s " +
|
||||
"but value: %s is not supported. Supported values: %s, %s",
|
||||
offering.getId(), mode,
|
||||
VHostUserMode.CLIENT.toString(), VHostUserMode.SERVER.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -20,7 +20,7 @@ import com.cloud.agent.api.to.VirtualMachineTO;
|
|||
import com.cloud.vm.VirtualMachineProfile;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
|
||||
public interface DPDKHelper {
|
||||
public interface DpdkHelper {
|
||||
|
||||
String DPDK_VHOST_USER_MODE = "DPDK-VHOSTUSER";
|
||||
String DPDK_NUMA = ApiConstants.EXTRA_CONFIG + "-dpdk-numa";
|
||||
|
|
@ -56,11 +56,26 @@ public interface DPDKHelper {
|
|||
* True if the DPDK vHost user mode setting is part of the VM service offering details, false if not.
|
||||
* @param vm
|
||||
*/
|
||||
boolean isDPDKvHostUserModeSettingOnServiceOffering(VirtualMachineProfile vm);
|
||||
boolean isDpdkvHostUserModeSettingOnServiceOffering(VirtualMachineProfile vm);
|
||||
|
||||
/**
|
||||
* Add DPDK vHost User Mode as extra configuration to the VM TO (if present on the VM service offering details)
|
||||
*/
|
||||
void setDpdkVhostUserMode(VirtualMachineTO to, VirtualMachineProfile vm);
|
||||
|
||||
/**
|
||||
* True if VM is a guest DPDK enabled VM, false if not.
|
||||
* It is determined by:
|
||||
* - VM type is guest
|
||||
* - VM details contains NUMA and Huge pages configurations for DPDK
|
||||
* - VM host contains the DPDK capability
|
||||
*/
|
||||
boolean isVMDpdkEnabled(long vmId);
|
||||
|
||||
/**
|
||||
* True if host is DPDK enabled, false if not.
|
||||
* Host is DPDK enabled when:
|
||||
* - 'dpdk' is part of the host capabilities
|
||||
*/
|
||||
boolean isHostDpdkEnabled(long hostId);
|
||||
}
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
// 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.dpdk;
|
||||
|
||||
import com.cloud.agent.api.to.VirtualMachineTO;
|
||||
import com.cloud.host.HostVO;
|
||||
import com.cloud.host.dao.HostDao;
|
||||
import com.cloud.offering.ServiceOffering;
|
||||
import com.cloud.service.ServiceOfferingDetailsVO;
|
||||
import com.cloud.service.dao.ServiceOfferingDetailsDao;
|
||||
import com.cloud.utils.StringUtils;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.vm.UserVmDetailVO;
|
||||
import com.cloud.vm.VMInstanceVO;
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
import com.cloud.vm.VirtualMachineProfile;
|
||||
import com.cloud.vm.dao.UserVmDetailsDao;
|
||||
import com.cloud.vm.dao.VMInstanceDao;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.List;
|
||||
|
||||
public class DpdkHelperImpl implements DpdkHelper {
|
||||
|
||||
@Inject
|
||||
private ServiceOfferingDetailsDao serviceOfferingDetailsDao;
|
||||
@Inject
|
||||
private HostDao hostDao;
|
||||
@Inject
|
||||
private VMInstanceDao vmInstanceDao;
|
||||
@Inject
|
||||
private UserVmDetailsDao userVmDetailsDao;
|
||||
|
||||
public static final Logger s_logger = Logger.getLogger(DpdkHelperImpl.class);
|
||||
|
||||
private ServiceOffering getServiceOfferingFromVMProfile(VirtualMachineProfile virtualMachineProfile) {
|
||||
ServiceOffering offering = virtualMachineProfile.getServiceOffering();
|
||||
if (offering == null) {
|
||||
throw new CloudRuntimeException("VM does not have an associated service offering");
|
||||
}
|
||||
return offering;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDpdkvHostUserModeSettingOnServiceOffering(VirtualMachineProfile vm) {
|
||||
ServiceOffering offering = getServiceOfferingFromVMProfile(vm);
|
||||
ServiceOfferingDetailsVO detail = serviceOfferingDetailsDao.findDetail(offering.getId(), DPDK_VHOST_USER_MODE);
|
||||
return detail != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDpdkVhostUserMode(VirtualMachineTO to, VirtualMachineProfile vm) {
|
||||
ServiceOffering offering = getServiceOfferingFromVMProfile(vm);
|
||||
ServiceOfferingDetailsVO detail = serviceOfferingDetailsDao.findDetail(offering.getId(), DPDK_VHOST_USER_MODE);
|
||||
if (detail != null) {
|
||||
String mode = detail.getValue();
|
||||
try {
|
||||
VHostUserMode dpdKvHostUserMode = VHostUserMode.fromValue(mode);
|
||||
to.addExtraConfig(DPDK_VHOST_USER_MODE, dpdKvHostUserMode.toString());
|
||||
} catch (IllegalArgumentException e) {
|
||||
s_logger.error(String.format("DPDK vHost User mode found as a detail for service offering: %s " +
|
||||
"but value: %s is not supported. Supported values: %s, %s",
|
||||
offering.getId(), mode,
|
||||
VHostUserMode.CLIENT.toString(), VHostUserMode.SERVER.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVMDpdkEnabled(long vmId) {
|
||||
VMInstanceVO vm = vmInstanceDao.findById(vmId);
|
||||
if (vm == null) {
|
||||
throw new CloudRuntimeException("Could not find VM with id " + vmId);
|
||||
}
|
||||
|
||||
if (vm.getType() != VirtualMachine.Type.User) {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<UserVmDetailVO> details = userVmDetailsDao.listDetails(vm.getId());
|
||||
List<ServiceOfferingDetailsVO> offeringDetails = serviceOfferingDetailsDao.listDetails(vm.getServiceOfferingId());
|
||||
|
||||
if (!hasRequiredDPDKConfigurations(details, offeringDetails)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isHostDpdkEnabled(vm.getHostId());
|
||||
}
|
||||
|
||||
/**
|
||||
* True if VM is DPDK enabled. NUMA and HUGEPAGES configurations must be present on VM or service offering details
|
||||
*/
|
||||
private boolean hasRequiredDPDKConfigurations(List<UserVmDetailVO> details, List<ServiceOfferingDetailsVO> offeringDetails) {
|
||||
if (CollectionUtils.isEmpty(details)) {
|
||||
return hasValidDPDKConfigurationsOnServiceOffering(false, false, offeringDetails);
|
||||
} else {
|
||||
boolean isNumaSet = false;
|
||||
boolean isHugePagesSet = false;
|
||||
for (UserVmDetailVO detail : details) {
|
||||
if (detail.getName().equals(DPDK_NUMA)) {
|
||||
isNumaSet = true;
|
||||
} else if (detail.getName().equals(DPDK_HUGE_PAGES)) {
|
||||
isHugePagesSet = true;
|
||||
}
|
||||
}
|
||||
boolean valid = isNumaSet && isHugePagesSet;
|
||||
if (!valid) {
|
||||
return hasValidDPDKConfigurationsOnServiceOffering(isNumaSet, isHugePagesSet, offeringDetails);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* True if DPDK required configurations are set
|
||||
*/
|
||||
private boolean hasValidDPDKConfigurationsOnServiceOffering(boolean isNumaSet, boolean isHugePagesSet, List<ServiceOfferingDetailsVO> offeringDetails) {
|
||||
if (!CollectionUtils.isEmpty(offeringDetails)) {
|
||||
for (ServiceOfferingDetailsVO detail : offeringDetails) {
|
||||
if (detail.getName().equals(DPDK_NUMA)) {
|
||||
isNumaSet = true;
|
||||
} else if (detail.getName().equals(DPDK_HUGE_PAGES)) {
|
||||
isHugePagesSet = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return isNumaSet && isHugePagesSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHostDpdkEnabled(long hostId) {
|
||||
HostVO host = hostDao.findById(hostId);
|
||||
if (host == null) {
|
||||
throw new CloudRuntimeException("Could not find host with id " + hostId);
|
||||
}
|
||||
return StringUtils.isNotBlank(host.getCapabilities()) && host.getCapabilities().contains("dpdk");
|
||||
}
|
||||
}
|
||||
|
|
@ -37,6 +37,8 @@ import javax.crypto.spec.SecretKeySpec;
|
|||
import javax.inject.Inject;
|
||||
import javax.naming.ConfigurationException;
|
||||
|
||||
import com.cloud.storage.ScopeType;
|
||||
import com.cloud.hypervisor.kvm.dpdk.DpdkHelper;
|
||||
import org.apache.cloudstack.acl.ControlledEntity;
|
||||
import org.apache.cloudstack.affinity.AffinityGroupProcessor;
|
||||
import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
|
||||
|
|
@ -634,7 +636,6 @@ import com.cloud.storage.GuestOSHypervisor;
|
|||
import com.cloud.storage.GuestOSHypervisorVO;
|
||||
import com.cloud.storage.GuestOSVO;
|
||||
import com.cloud.storage.GuestOsCategory;
|
||||
import com.cloud.storage.ScopeType;
|
||||
import com.cloud.storage.StorageManager;
|
||||
import com.cloud.storage.StoragePool;
|
||||
import com.cloud.storage.Volume;
|
||||
|
|
@ -811,6 +812,8 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
|||
private GuestOsDetailsDao _guestOsDetailsDao;
|
||||
@Inject
|
||||
private KeystoreManager _ksMgr;
|
||||
@Inject
|
||||
private DpdkHelper dpdkHelper;
|
||||
|
||||
private LockMasterListener _lockMasterListener;
|
||||
private final ScheduledExecutorService _eventExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("EventChecker"));
|
||||
|
|
@ -1302,6 +1305,10 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
|||
final ExcludeList excludes = new ExcludeList();
|
||||
excludes.addHost(srcHostId);
|
||||
|
||||
if (dpdkHelper.isVMDpdkEnabled(vm.getId())) {
|
||||
excludeNonDPDKEnabledHosts(plan, excludes);
|
||||
}
|
||||
|
||||
// call affinitygroup chain
|
||||
final long vmGroupCount = _affinityGroupVMMapDao.countAffinityGroupsForVm(vm.getId());
|
||||
|
||||
|
|
@ -1334,6 +1341,21 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
|||
return new Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Host, Boolean>>(otherHosts, suitableHosts, requiresStorageMotion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add non DPDK enabled hosts to the avoid list
|
||||
*/
|
||||
private void excludeNonDPDKEnabledHosts(DataCenterDeployment plan, ExcludeList excludes) {
|
||||
long dataCenterId = plan.getDataCenterId();
|
||||
Long clusterId = plan.getClusterId();
|
||||
Long podId = plan.getPodId();
|
||||
List<HostVO> hosts = _hostDao.listAllUpAndEnabledNonHAHosts(Type.Routing, clusterId, podId, dataCenterId, null);
|
||||
for (HostVO host : hosts) {
|
||||
if (!dpdkHelper.isHostDpdkEnabled(host.getId())) {
|
||||
excludes.addHost(host.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasSuitablePoolsForVolume(final VolumeVO volume, final Host host, final VirtualMachineProfile vmProfile) {
|
||||
final DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume.getDiskOfferingId());
|
||||
final DiskProfile diskProfile = new DiskProfile(volume, diskOffering, vmProfile.getHypervisorType());
|
||||
|
|
|
|||
|
|
@ -713,10 +713,8 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||
|
||||
String userSpecifiedName = getVolumeNameFromCommand(cmd);
|
||||
|
||||
VolumeVO volume = commitVolume(cmd, caller, owner, displayVolume, zoneId, diskOfferingId, provisioningType, size, minIops, maxIops, parentVolume, userSpecifiedName,
|
||||
return commitVolume(cmd, caller, owner, displayVolume, zoneId, diskOfferingId, provisioningType, size, minIops, maxIops, parentVolume, userSpecifiedName,
|
||||
_uuidMgr.generateUuid(Volume.class, cmd.getCustomId()));
|
||||
|
||||
return volume;
|
||||
}
|
||||
|
||||
private VolumeVO commitVolume(final CreateVolumeCmd cmd, final Account caller, final Account owner, final Boolean displayVolume, final Long zoneId, final Long diskOfferingId,
|
||||
|
|
@ -1035,6 +1033,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||
// the requested change
|
||||
|
||||
/* If this volume has never been beyond allocated state, short circuit everything and simply update the database. */
|
||||
// We need to publish this event to usage_volume table
|
||||
if (volume.getState() == Volume.State.Allocated) {
|
||||
s_logger.debug("Volume is in the allocated state, but has never been created. Simply updating database with new size and IOPS.");
|
||||
|
||||
|
|
@ -1048,7 +1047,8 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||
}
|
||||
|
||||
_volsDao.update(volume.getId(), volume);
|
||||
|
||||
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_RESIZE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(),
|
||||
volume.getDiskOfferingId(), volume.getTemplateId(), volume.getSize(), Volume.class.getName(), volume.getUuid());
|
||||
return volume;
|
||||
}
|
||||
|
||||
|
|
@ -1125,7 +1125,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||
|
||||
private VolumeVO orchestrateResizeVolume(long volumeId, long currentSize, long newSize, Long newMinIops, Long newMaxIops, Integer newHypervisorSnapshotReserve, Long newDiskOfferingId,
|
||||
boolean shrinkOk) {
|
||||
VolumeVO volume = _volsDao.findById(volumeId);
|
||||
final VolumeVO volume = _volsDao.findById(volumeId);
|
||||
UserVmVO userVm = _userVmDao.findById(volume.getInstanceId());
|
||||
StoragePoolVO storagePool = _storagePoolDao.findById(volume.getPoolId());
|
||||
boolean isManaged = storagePool.isManaged();
|
||||
|
|
@ -1201,14 +1201,8 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||
volService.resizeVolumeOnHypervisor(volumeId, newSize, hosts[0], instanceName);
|
||||
}
|
||||
}
|
||||
|
||||
volume.setSize(newSize);
|
||||
|
||||
_volsDao.update(volume.getId(), volume);
|
||||
}
|
||||
|
||||
volume = _volsDao.findById(volume.getId());
|
||||
|
||||
if (newDiskOfferingId != null) {
|
||||
volume.setDiskOfferingId(newDiskOfferingId);
|
||||
}
|
||||
|
|
@ -1221,20 +1215,18 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||
|
||||
/* Update resource count for the account on primary storage resource */
|
||||
if (!shrinkOk) {
|
||||
_resourceLimitMgr.incrementResourceCount(volume.getAccountId(), ResourceType.primary_storage, volume.isDisplayVolume(), new Long(newSize - currentSize));
|
||||
_resourceLimitMgr.incrementResourceCount(volume.getAccountId(), ResourceType.primary_storage, volume.isDisplayVolume(), newSize - currentSize);
|
||||
} else {
|
||||
_resourceLimitMgr.decrementResourceCount(volume.getAccountId(), ResourceType.primary_storage, volume.isDisplayVolume(), new Long(currentSize - newSize));
|
||||
_resourceLimitMgr.decrementResourceCount(volume.getAccountId(), ResourceType.primary_storage, volume.isDisplayVolume(), currentSize - newSize);
|
||||
}
|
||||
|
||||
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_RESIZE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(),
|
||||
volume.getDiskOfferingId(), volume.getTemplateId(), volume.getSize(), Volume.class.getName(), volume.getUuid());
|
||||
|
||||
return volume;
|
||||
} catch (InterruptedException e) {
|
||||
s_logger.warn("failed get resize volume result", e);
|
||||
throw new CloudRuntimeException(e.getMessage());
|
||||
} catch (ExecutionException e) {
|
||||
s_logger.warn("failed get resize volume result", e);
|
||||
throw new CloudRuntimeException(e.getMessage());
|
||||
|
||||
} catch (Exception e) {
|
||||
s_logger.warn("failed get resize volume result", e);
|
||||
throw new CloudRuntimeException(e.getMessage());
|
||||
throw new CloudRuntimeException("Exception caught during resize volume operation of volume UUID: " + volume.getUuid(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -76,8 +76,7 @@ public class VolumeStateListener implements StateListener<State, Event, Volume>
|
|||
if (transition.getToState() == State.Ready) {
|
||||
if (transition.getCurrentState() == State.Resizing) {
|
||||
// Log usage event for volumes belonging user VM's only
|
||||
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_RESIZE, vol.getAccountId(), vol.getDataCenterId(), vol.getId(), vol.getName(),
|
||||
vol.getDiskOfferingId(), vol.getTemplateId(), vol.getSize(), Volume.class.getName(), vol.getUuid());
|
||||
// For the Resize Volume Event, this publishes an event with an incorrect disk offering ID, so do nothing for now
|
||||
} else {
|
||||
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, vol.getAccountId(), vol.getDataCenterId(), vol.getId(), vol.getName(), vol.getDiskOfferingId(), null, vol.getSize(),
|
||||
Volume.class.getName(), vol.getUuid(), vol.isDisplayVolume());
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ import org.apache.commons.collections.MapUtils;
|
|||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.cloud.hypervisor.kvm.dpdk.DpdkHelper;
|
||||
import com.cloud.agent.AgentManager;
|
||||
import com.cloud.agent.api.Answer;
|
||||
import com.cloud.agent.api.Command;
|
||||
|
|
@ -472,6 +473,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
private TemplateApiService _tmplService;
|
||||
@Inject
|
||||
private ConfigurationDao _configDao;
|
||||
@Inject
|
||||
private DpdkHelper dpdkHelper;
|
||||
|
||||
private ScheduledExecutorService _executor = null;
|
||||
private ScheduledExecutorService _vmIpFetchExecutor = null;
|
||||
|
|
@ -5225,6 +5228,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
}
|
||||
}
|
||||
|
||||
if (dpdkHelper.isVMDpdkEnabled(vm.getId()) && !dpdkHelper.isHostDpdkEnabled(destinationHost.getId())) {
|
||||
throw new CloudRuntimeException("Cannot migrate VM, VM is DPDK enabled VM but destination host is not DPDK enabled");
|
||||
}
|
||||
|
||||
checkHostsDedication(vm, srcHostId, destinationHost.getId());
|
||||
|
||||
// call to core process
|
||||
|
|
|
|||
|
|
@ -79,6 +79,6 @@
|
|||
<property name="name" value="Basic" />
|
||||
</bean>
|
||||
|
||||
<bean id="DPDKHelper" class="com.cloud.hypervisor.kvm.dpdk.DPDKHelperImpl" />
|
||||
<bean id="DPDKHelper" class="com.cloud.hypervisor.kvm.dpdk.DpdkHelperImpl" />
|
||||
|
||||
</beans>
|
||||
|
|
@ -129,17 +129,4 @@ public class KVMGuruTest {
|
|||
guru.setVmQuotaPercentage(vmTO, vmProfile);
|
||||
Mockito.verify(vmTO).setCpuQuotaPercentage(1d);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddServiceOfferingExtraConfigurationDpdkDetails() {
|
||||
guru.addServiceOfferingExtraConfiguration(vmTO, vmProfile);
|
||||
Mockito.verify(vmTO).addExtraConfig(detail1Key, detail1Value);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddServiceOfferingExtraConfigurationEmptyDetails() {
|
||||
Mockito.when(serviceOfferingDetailsDao.listDetails(offeringId)).thenReturn(null);
|
||||
guru.addServiceOfferingExtraConfiguration(vmTO, vmProfile);
|
||||
Mockito.verify(vmTO, Mockito.never()).addExtraConfig(Mockito.anyString(), Mockito.anyString());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,135 +0,0 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package com.cloud.hypervisor.kvm.dpdk;
|
||||
|
||||
import com.cloud.agent.api.to.VirtualMachineTO;
|
||||
import com.cloud.offering.ServiceOffering;
|
||||
import com.cloud.service.ServiceOfferingDetailsVO;
|
||||
import com.cloud.service.dao.ServiceOfferingDetailsDao;
|
||||
import com.cloud.vm.VirtualMachineProfile;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.Spy;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Arrays;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class DPDKHelperImplTest {
|
||||
|
||||
@Mock
|
||||
ServiceOfferingDetailsDao serviceOfferingDetailsDao;
|
||||
|
||||
@Spy
|
||||
@InjectMocks
|
||||
private DPDKHelper dpdkHelper = new DPDKHelperImpl();
|
||||
|
||||
@Mock
|
||||
VirtualMachineTO vmTO;
|
||||
@Mock
|
||||
VirtualMachineProfile vmProfile;
|
||||
@Mock
|
||||
ServiceOfferingDetailsVO dpdkVhostUserModeDetailVO;
|
||||
@Mock
|
||||
ServiceOfferingDetailsVO dpdkNumaDetailVO;
|
||||
@Mock
|
||||
ServiceOfferingDetailsVO dpdkHugePagesDetailVO;
|
||||
@Mock
|
||||
ServiceOffering serviceOffering;
|
||||
|
||||
private String dpdkVhostMode = DPDKHelper.VHostUserMode.SERVER.toString();
|
||||
|
||||
private static final String dpdkNumaConf =
|
||||
"<cpu mode=\"host-passthrough\">\n" +
|
||||
" <numa>\n" +
|
||||
" <cell id=\"0\" cpus=\"0\" memory=\"9437184\" unit=\"KiB\" memAccess=\"shared\"/>\n" +
|
||||
" </numa>\n" +
|
||||
"</cpu>";
|
||||
private static final String dpdkHugePagesConf =
|
||||
"<memoryBacking>\n" +
|
||||
" <hugePages/>\n" +
|
||||
"</memoryBacking>";
|
||||
private static String dpdkNumaValue;
|
||||
private static String dpdkHugePagesValue;
|
||||
private static final Long offeringId = 1L;
|
||||
|
||||
@Before
|
||||
public void setup() throws UnsupportedEncodingException {
|
||||
dpdkHugePagesValue = URLEncoder.encode(dpdkHugePagesConf, "UTF-8");
|
||||
dpdkNumaValue = URLEncoder.encode(dpdkNumaConf, "UTF-8");
|
||||
|
||||
Mockito.when(dpdkVhostUserModeDetailVO.getName()).thenReturn(DPDKHelper.DPDK_VHOST_USER_MODE);
|
||||
Mockito.when(dpdkVhostUserModeDetailVO.getValue()).thenReturn(dpdkVhostMode);
|
||||
Mockito.when(dpdkVhostUserModeDetailVO.getResourceId()).thenReturn(offeringId);
|
||||
Mockito.when(dpdkNumaDetailVO.getName()).thenReturn(DPDKHelper.DPDK_NUMA);
|
||||
Mockito.when(dpdkNumaDetailVO.getResourceId()).thenReturn(offeringId);
|
||||
Mockito.when(dpdkNumaDetailVO.getValue()).thenReturn(dpdkNumaValue);
|
||||
Mockito.when(dpdkHugePagesDetailVO.getName()).thenReturn(DPDKHelper.DPDK_HUGE_PAGES);
|
||||
Mockito.when(dpdkHugePagesDetailVO.getResourceId()).thenReturn(offeringId);
|
||||
Mockito.when(dpdkHugePagesDetailVO.getValue()).thenReturn(dpdkHugePagesValue);
|
||||
|
||||
Mockito.when(serviceOfferingDetailsDao.listDetails(offeringId)).thenReturn(
|
||||
Arrays.asList(dpdkNumaDetailVO, dpdkHugePagesDetailVO, dpdkVhostUserModeDetailVO));
|
||||
Mockito.when(vmProfile.getServiceOffering()).thenReturn(serviceOffering);
|
||||
Mockito.when(serviceOffering.getId()).thenReturn(offeringId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetDpdkVhostUserModeValidDetail() {
|
||||
Mockito.when(serviceOfferingDetailsDao.findDetail(offeringId, DPDKHelper.DPDK_VHOST_USER_MODE)).
|
||||
thenReturn(dpdkVhostUserModeDetailVO);
|
||||
dpdkHelper.setDpdkVhostUserMode(vmTO, vmProfile);
|
||||
Mockito.verify(vmTO).addExtraConfig(DPDKHelper.DPDK_VHOST_USER_MODE, dpdkVhostMode);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetDpdkVhostUserModeInvalidDetail() {
|
||||
Mockito.when(dpdkVhostUserModeDetailVO.getValue()).thenReturn("serverrrr");
|
||||
Mockito.verify(vmTO, Mockito.never()).addExtraConfig(Mockito.anyString(), Mockito.anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetDpdkVhostUserModeNotExistingDetail() {
|
||||
Mockito.when(serviceOfferingDetailsDao.listDetails(offeringId)).thenReturn(
|
||||
Arrays.asList(dpdkNumaDetailVO, dpdkHugePagesDetailVO));
|
||||
Mockito.verify(vmTO, Mockito.never()).addExtraConfig(Mockito.anyString(), Mockito.anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDPDKvHostUserFromValueClient() {
|
||||
DPDKHelper.VHostUserMode mode = DPDKHelper.VHostUserMode.fromValue("client");
|
||||
Assert.assertEquals(DPDKHelper.VHostUserMode.CLIENT, mode);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDPDKvHostUserFromValueServer() {
|
||||
DPDKHelper.VHostUserMode mode = DPDKHelper.VHostUserMode.fromValue("server");
|
||||
Assert.assertEquals(DPDKHelper.VHostUserMode.SERVER, mode);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testDPDKvHostUserFromValueServerInvalid() {
|
||||
DPDKHelper.VHostUserMode.fromValue("serverrrr");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,245 @@
|
|||
// 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.dpdk;
|
||||
|
||||
import com.cloud.agent.api.to.VirtualMachineTO;
|
||||
import com.cloud.host.HostVO;
|
||||
import com.cloud.host.dao.HostDao;
|
||||
import com.cloud.offering.ServiceOffering;
|
||||
import com.cloud.service.ServiceOfferingDetailsVO;
|
||||
import com.cloud.service.dao.ServiceOfferingDetailsDao;
|
||||
import com.cloud.vm.UserVmDetailVO;
|
||||
import com.cloud.vm.VMInstanceVO;
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
import com.cloud.vm.VirtualMachineProfile;
|
||||
import com.cloud.vm.dao.UserVmDetailsDao;
|
||||
import com.cloud.vm.dao.VMInstanceDao;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.Spy;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class DpdkHelperImplTest {
|
||||
|
||||
@Mock
|
||||
ServiceOfferingDetailsDao serviceOfferingDetailsDao;
|
||||
@Mock
|
||||
HostDao hostDao;
|
||||
@Mock
|
||||
VMInstanceDao vmInstanceDao;
|
||||
@Mock
|
||||
UserVmDetailsDao userVmDetailsDao;
|
||||
|
||||
@Spy
|
||||
@InjectMocks
|
||||
private DpdkHelper dpdkHelper = new DpdkHelperImpl();
|
||||
|
||||
@Mock
|
||||
VirtualMachineTO vmTO;
|
||||
@Mock
|
||||
VirtualMachineProfile vmProfile;
|
||||
@Mock
|
||||
ServiceOfferingDetailsVO dpdkVhostUserModeDetailVO;
|
||||
@Mock
|
||||
ServiceOfferingDetailsVO dpdkNumaDetailVO;
|
||||
@Mock
|
||||
ServiceOfferingDetailsVO dpdkHugePagesDetailVO;
|
||||
@Mock
|
||||
ServiceOffering serviceOffering;
|
||||
@Mock
|
||||
UserVmDetailVO dpdkNumaVmDetail;
|
||||
@Mock
|
||||
UserVmDetailVO dpdkHugePagesVmDetail;
|
||||
@Mock
|
||||
HostVO hostVO;
|
||||
@Mock
|
||||
VMInstanceVO vmInstanceVO;
|
||||
|
||||
private String dpdkVhostMode = DpdkHelper.VHostUserMode.SERVER.toString();
|
||||
|
||||
private static final String dpdkNumaConf =
|
||||
"<cpu mode=\"host-passthrough\">\n" +
|
||||
" <numa>\n" +
|
||||
" <cell id=\"0\" cpus=\"0\" memory=\"9437184\" unit=\"KiB\" memAccess=\"shared\"/>\n" +
|
||||
" </numa>\n" +
|
||||
"</cpu>";
|
||||
private static final String dpdkHugePagesConf =
|
||||
"<memoryBacking>\n" +
|
||||
" <hugePages/>\n" +
|
||||
"</memoryBacking>";
|
||||
private static String dpdkNumaValue;
|
||||
private static String dpdkHugePagesValue;
|
||||
private static final Long offeringId = 1L;
|
||||
private static final Long hostId = 1L;
|
||||
private static final String hostCapabilities = "hvm,snapshot";
|
||||
private static final Long vmId = 1L;
|
||||
|
||||
@Before
|
||||
public void setup() throws UnsupportedEncodingException {
|
||||
dpdkHugePagesValue = URLEncoder.encode(dpdkHugePagesConf, "UTF-8");
|
||||
dpdkNumaValue = URLEncoder.encode(dpdkNumaConf, "UTF-8");
|
||||
|
||||
Mockito.when(dpdkVhostUserModeDetailVO.getName()).thenReturn(DpdkHelper.DPDK_VHOST_USER_MODE);
|
||||
Mockito.when(dpdkVhostUserModeDetailVO.getValue()).thenReturn(dpdkVhostMode);
|
||||
Mockito.when(dpdkVhostUserModeDetailVO.getResourceId()).thenReturn(offeringId);
|
||||
Mockito.when(dpdkNumaDetailVO.getName()).thenReturn(DpdkHelper.DPDK_NUMA);
|
||||
Mockito.when(dpdkNumaDetailVO.getResourceId()).thenReturn(offeringId);
|
||||
Mockito.when(dpdkNumaDetailVO.getValue()).thenReturn(dpdkNumaValue);
|
||||
Mockito.when(dpdkHugePagesDetailVO.getName()).thenReturn(DpdkHelper.DPDK_HUGE_PAGES);
|
||||
Mockito.when(dpdkHugePagesDetailVO.getResourceId()).thenReturn(offeringId);
|
||||
Mockito.when(dpdkHugePagesDetailVO.getValue()).thenReturn(dpdkHugePagesValue);
|
||||
|
||||
Mockito.when(serviceOfferingDetailsDao.listDetails(offeringId)).thenReturn(
|
||||
Arrays.asList(dpdkNumaDetailVO, dpdkHugePagesDetailVO, dpdkVhostUserModeDetailVO));
|
||||
Mockito.when(vmProfile.getServiceOffering()).thenReturn(serviceOffering);
|
||||
Mockito.when(serviceOffering.getId()).thenReturn(offeringId);
|
||||
Mockito.when(vmProfile.getServiceOffering()).thenReturn(serviceOffering);
|
||||
Mockito.when(serviceOffering.getId()).thenReturn(offeringId);
|
||||
|
||||
Mockito.when(hostDao.findById(hostId)).thenReturn(hostVO);
|
||||
Mockito.when(hostVO.getCapabilities()).thenReturn(hostCapabilities);
|
||||
|
||||
Mockito.when(vmInstanceDao.findById(vmId)).thenReturn(vmInstanceVO);
|
||||
Mockito.when(vmInstanceVO.getType()).thenReturn(VirtualMachine.Type.User);
|
||||
Mockito.when(vmInstanceVO.getHostId()).thenReturn(hostId);
|
||||
Mockito.when(vmInstanceVO.getServiceOfferingId()).thenReturn(offeringId);
|
||||
Mockito.when(vmInstanceVO.getId()).thenReturn(vmId);
|
||||
|
||||
Mockito.when(dpdkNumaVmDetail.getName()).thenReturn(DpdkHelper.DPDK_NUMA);
|
||||
Mockito.when(dpdkNumaVmDetail.getValue()).thenReturn(dpdkNumaConf);
|
||||
Mockito.when(dpdkHugePagesVmDetail.getName()).thenReturn(DpdkHelper.DPDK_HUGE_PAGES);
|
||||
Mockito.when(dpdkHugePagesVmDetail.getValue()).thenReturn(dpdkHugePagesConf);
|
||||
Mockito.when(userVmDetailsDao.listDetails(vmId)).thenReturn(Arrays.asList(dpdkNumaVmDetail, dpdkHugePagesVmDetail));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetDpdkVhostUserModeValidDetail() {
|
||||
Mockito.when(serviceOfferingDetailsDao.findDetail(offeringId, DpdkHelper.DPDK_VHOST_USER_MODE)).
|
||||
thenReturn(dpdkVhostUserModeDetailVO);
|
||||
dpdkHelper.setDpdkVhostUserMode(vmTO, vmProfile);
|
||||
Mockito.verify(vmTO).addExtraConfig(DpdkHelper.DPDK_VHOST_USER_MODE, dpdkVhostMode);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetDpdkVhostUserModeInvalidDetail() {
|
||||
Mockito.when(dpdkVhostUserModeDetailVO.getValue()).thenReturn("serverrrr");
|
||||
Mockito.verify(vmTO, Mockito.never()).addExtraConfig(Mockito.anyString(), Mockito.anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetDpdkVhostUserModeNotExistingDetail() {
|
||||
Mockito.when(serviceOfferingDetailsDao.listDetails(offeringId)).thenReturn(
|
||||
Arrays.asList(dpdkNumaDetailVO, dpdkHugePagesDetailVO));
|
||||
Mockito.verify(vmTO, Mockito.never()).addExtraConfig(Mockito.anyString(), Mockito.anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDpdkvHostUserFromValueClient() {
|
||||
DpdkHelper.VHostUserMode mode = DpdkHelper.VHostUserMode.fromValue("client");
|
||||
Assert.assertEquals(DpdkHelper.VHostUserMode.CLIENT, mode);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDpdkvHostUserFromValueServer() {
|
||||
DpdkHelper.VHostUserMode mode = DpdkHelper.VHostUserMode.fromValue("server");
|
||||
Assert.assertEquals(DpdkHelper.VHostUserMode.SERVER, mode);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testDpdkvHostUserFromValueServerInvalid() {
|
||||
DpdkHelper.VHostUserMode.fromValue("serverrrr");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsHostDpdkEnabledNonDPDKHost() {
|
||||
Assert.assertFalse(dpdkHelper.isHostDpdkEnabled(hostId));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsHostDpdkEnabledDpdkHost() {
|
||||
Mockito.when(hostVO.getCapabilities()).thenReturn(hostCapabilities + ",dpdk");
|
||||
Assert.assertTrue(dpdkHelper.isHostDpdkEnabled(hostId));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsVMDPDKEnabledDPDKEnabledVM() {
|
||||
Mockito.when(hostVO.getCapabilities()).thenReturn(hostCapabilities + ",dpdk");
|
||||
Assert.assertTrue(dpdkHelper.isVMDpdkEnabled(vmId));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsVMDpdkEnabledGuestType() {
|
||||
Mockito.when(vmInstanceVO.getType()).thenReturn(VirtualMachine.Type.SecondaryStorageVm);
|
||||
Assert.assertFalse(dpdkHelper.isVMDpdkEnabled(vmId));
|
||||
Mockito.verify(dpdkHelper, Mockito.never()).isHostDpdkEnabled(hostId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsVMDpdkEnabledGuestTypeMissingConfigurationOnDetails() {
|
||||
Mockito.when(userVmDetailsDao.listDetails(vmId)).thenReturn(Arrays.asList(dpdkNumaVmDetail));
|
||||
Mockito.when(serviceOfferingDetailsDao.listDetails(offeringId)).thenReturn(new ArrayList<>());
|
||||
Assert.assertFalse(dpdkHelper.isVMDpdkEnabled(vmId));
|
||||
Mockito.verify(dpdkHelper, Mockito.never()).isHostDpdkEnabled(hostId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsVMDpdkEnabledGuestTypeEmptyDetails() {
|
||||
Mockito.when(userVmDetailsDao.listDetails(vmId)).thenReturn(new ArrayList<>());
|
||||
Mockito.when(serviceOfferingDetailsDao.listDetails(offeringId)).thenReturn(new ArrayList<>());
|
||||
Assert.assertFalse(dpdkHelper.isVMDpdkEnabled(vmId));
|
||||
Mockito.verify(dpdkHelper, Mockito.never()).isHostDpdkEnabled(hostId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsVMDpdkEnabledNonDPDKCapabilityOnHost() {
|
||||
Assert.assertFalse(dpdkHelper.isVMDpdkEnabled(vmId));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsVMDpdkEnabledGuestTypeMissingConfigurationOnVmDetails() {
|
||||
Mockito.when(userVmDetailsDao.listDetails(vmId)).thenReturn(Collections.singletonList(dpdkNumaVmDetail));
|
||||
Mockito.when(hostVO.getCapabilities()).thenReturn(hostCapabilities + ",dpdk");
|
||||
Assert.assertTrue(dpdkHelper.isVMDpdkEnabled(vmId));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsVMDpdkEnabledGuestTypeEmptyVmDetails() {
|
||||
Mockito.when(userVmDetailsDao.listDetails(vmId)).thenReturn(new ArrayList<>());
|
||||
Mockito.when(hostVO.getCapabilities()).thenReturn(hostCapabilities + ",dpdk");
|
||||
Assert.assertTrue(dpdkHelper.isVMDpdkEnabled(vmId));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsVMDpdkEnabledGuestTypeMixedConfigurationOnDetails() {
|
||||
Mockito.when(userVmDetailsDao.listDetails(vmId)).thenReturn(Collections.singletonList(dpdkNumaVmDetail));
|
||||
Mockito.when(serviceOfferingDetailsDao.listDetails(offeringId)).thenReturn(Collections.singletonList(dpdkHugePagesDetailVO));
|
||||
Mockito.when(hostVO.getCapabilities()).thenReturn(hostCapabilities + ",dpdk");
|
||||
Assert.assertTrue(dpdkHelper.isVMDpdkEnabled(vmId));
|
||||
}
|
||||
}
|
||||
|
|
@ -784,7 +784,7 @@ body.install-wizard {
|
|||
|
||||
.install-wizard .step {
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
z-index: 11;
|
||||
}
|
||||
|
||||
.install-wizard .step .tooltip-info {
|
||||
|
|
@ -12343,12 +12343,14 @@ div.ui-dialog div.autoscaler div.field-group div.form-container form div.form-it
|
|||
}
|
||||
|
||||
.snapshot .icon,
|
||||
.takeSnapshot .icon {
|
||||
.takeSnapshot .icon,
|
||||
.storageSnapshot .icon {
|
||||
background-position: -36px -91px;
|
||||
}
|
||||
|
||||
.snapshot:hover .icon,
|
||||
.takeSnapshot:hover .icon {
|
||||
.takeSnapshot:hover .icon,
|
||||
.storageSnapshot:hover .icon {
|
||||
background-position: -36px -673px;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -173,12 +173,14 @@
|
|||
}
|
||||
|
||||
.snapshot .icon,
|
||||
.takeSnapshot .icon {
|
||||
.takeSnapshot .icon,
|
||||
.storageSnapshot .icon {
|
||||
background-position: -36px -91px;
|
||||
}
|
||||
|
||||
.snapshot:hover .icon,
|
||||
.takeSnapshot:hover .icon {
|
||||
.takeSnapshot:hover .icon,
|
||||
.storageSnapshot:hover .icon {
|
||||
background-position: -36px -673px;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -194,7 +194,7 @@ body.install-wizard {
|
|||
|
||||
.install-wizard .step {
|
||||
position: relative;
|
||||
z-index: $z-index-install-wizard2;
|
||||
z-index: $z-index-install-wizard3;
|
||||
}
|
||||
|
||||
.install-wizard .step .tooltip-info {
|
||||
|
|
|
|||
|
|
@ -297,6 +297,7 @@ var dictionary = {
|
|||
"label.action.vmsnapshot.create": "VM-Schnappschuss machen",
|
||||
"label.action.vmsnapshot.delete": "VM-Schnappschuss löschen",
|
||||
"label.action.vmsnapshot.revert": "Auf VM-Schnappschuss zurückkehren",
|
||||
"label.action.vmstoragesnapshot.create":"VM Speicher-Schnappschuss machen",
|
||||
"label.actions": "Aktionen",
|
||||
"label.activate.project": "Projekt aktivieren",
|
||||
"label.active.sessions": "Aktive Sitzungen",
|
||||
|
|
@ -1891,6 +1892,7 @@ var dictionary = {
|
|||
"message.action.vmsnapshot.create": "Please confirm that you want to take a snapshot of this instance. <br>Please notice that the instance will be paused during the snapshoting, and resumed after snapshotting, if it runs on KVM.",
|
||||
"message.action.vmsnapshot.delete": "Bitte bestätigen Sie, dass Sie diesen VM Schnappschuss löschen wollen.",
|
||||
"message.action.vmsnapshot.revert": "VM-Schnappschuss zurücksetzen",
|
||||
"message.action.vmstoragesnapshot.create":"Bitte wählen Sie einen Speicher aus, für den ein Schnappschuss erstellt werden soll.",
|
||||
"message.activate.project": "Sind Sie sicher, dass Sie dieses Projekt aktivieren wollen?",
|
||||
"message.add.VPN.gateway": "Bitte bestätigen Sie, dass sie ein VPN Gateway hinzufügen wollen.",
|
||||
"message.add.cluster": "Hinzufügen eines vom Hypervisor verwaltender Clusters für Zone <b><span id=\"zone_name\"></span></b>, Pod <b><span id=\"pod_name\"></span></b>",
|
||||
|
|
|
|||
|
|
@ -302,6 +302,7 @@ var dictionary = {
|
|||
"label.action.vmsnapshot.create":"Take VM Snapshot",
|
||||
"label.action.vmsnapshot.delete":"Delete VM snapshot",
|
||||
"label.action.vmsnapshot.revert":"Revert to VM snapshot",
|
||||
"label.action.vmstoragesnapshot.create":"Take VM volume snapshot",
|
||||
"label.actions":"Actions",
|
||||
"label.activate.project":"Activate Project",
|
||||
"label.active.sessions":"Active Sessions",
|
||||
|
|
@ -534,7 +535,7 @@ var dictionary = {
|
|||
"label.cidr":"CIDR",
|
||||
"label.cidr.account":"CIDR or Account/Security Group",
|
||||
"label.cidr.list":"Source CIDR",
|
||||
"label.cidr.destination.list":"Destination CIDR",
|
||||
"label.cidr.destination.list":"Destination CIDR",
|
||||
"label.cisco.nexus1000v.ip.address":"Nexus 1000v IP Address",
|
||||
"label.cisco.nexus1000v.password":"Nexus 1000v Password",
|
||||
"label.cisco.nexus1000v.username":"Nexus 1000v Username",
|
||||
|
|
@ -1966,6 +1967,7 @@ var dictionary = {
|
|||
"message.action.vmsnapshot.create":"Please confirm that you want to take a snapshot of this instance. <br>Please notice that the instance will be paused during the snapshoting, and resumed after snapshotting, if it runs on KVM.",
|
||||
"message.action.vmsnapshot.delete":"Please confirm that you want to delete this VM snapshot. <br>Please notice that the instance will be paused before the snapshot deletion, and resumed after deletion, if it runs on KVM.",
|
||||
"message.action.vmsnapshot.revert":"Revert VM snapshot",
|
||||
"message.action.vmstoragesnapshot.create":"Please choose a volume that you want to take a snapshot of.",
|
||||
"message.activate.project":"Are you sure you want to activate this project?",
|
||||
"message.add.VPN.gateway":"Please confirm that you want to add a VPN Gateway",
|
||||
"message.add.cluster":"Add a hypervisor managed cluster for zone <b><span id=\"zone_name\"></span></b>, pod <b><span id=\"pod_name\"></span></b>",
|
||||
|
|
|
|||
|
|
@ -314,6 +314,13 @@ cloudStack.docs = {
|
|||
helpCreateInstanceSnapshotMemory: {
|
||||
desc: 'Check this to include CPU/memory state. Does not quiesce the VM. If not checked, the snapshot contain only volumes.'
|
||||
},
|
||||
// Create instance storage snapshot
|
||||
helpCreateInstanceStorageSnapshotVolume: {
|
||||
desc: 'Choose a volume that you want to take a snapshot of'
|
||||
},
|
||||
helpCreateInstanceStorageSnapshotName: {
|
||||
desc: 'Give the snapshot a name. A unique name will be automatically generated if you leave this blank'
|
||||
},
|
||||
// Add disk offering
|
||||
helpDiskOfferingName: {
|
||||
desc: 'Any desired name for the offering',
|
||||
|
|
|
|||
|
|
@ -1054,6 +1054,111 @@
|
|||
}
|
||||
},
|
||||
snapshot: vmSnapshotAction(),
|
||||
storageSnapshot: {
|
||||
messages: {
|
||||
notification: function() {
|
||||
return 'label.action.take.snapshot';
|
||||
}
|
||||
},
|
||||
label: 'label.action.vmstoragesnapshot.create',
|
||||
createForm: {
|
||||
title: 'label.action.vmstoragesnapshot.create',
|
||||
desc: 'message.action.vmstoragesnapshot.create',
|
||||
fields: {
|
||||
volume: {
|
||||
label: 'label.volume',
|
||||
docID: 'helpCreateInstanceStorageSnapshotVolume',
|
||||
select: function(args) {
|
||||
var items = [];
|
||||
var data = {
|
||||
virtualMachineId: args.context.instances[0].id
|
||||
};
|
||||
|
||||
$.ajax({
|
||||
url: createURL('listVolumes'),
|
||||
data: data,
|
||||
dataType: 'json',
|
||||
async: false,
|
||||
success: function(json) {
|
||||
var volumes = json.listvolumesresponse.volume;
|
||||
args.context['volumes'] = volumes;
|
||||
$(volumes).each(function(index, volume) {
|
||||
items.push({
|
||||
id: volume.id,
|
||||
description: volume.name
|
||||
});
|
||||
});
|
||||
|
||||
args.response.success({
|
||||
data: items
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
quiescevm: {
|
||||
label: 'label.quiesce.vm',
|
||||
isBoolean: true,
|
||||
dependsOn: 'volume',
|
||||
isHidden: function(args) {
|
||||
var selectedVolumeId = $('div[role=dialog] form .form-item[rel=volume] select').val();
|
||||
for (var i = 0; i < args.context.volumes.length; i++) {
|
||||
var volume = args.context.volumes[i];
|
||||
if (volume.id === selectedVolumeId) {
|
||||
return volume.quiescevm !== true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
name: {
|
||||
label: 'label.name',
|
||||
docID: 'helpCreateInstanceStorageSnapshotName',
|
||||
isInput: true
|
||||
},
|
||||
asyncBackup: {
|
||||
label: 'label.async.backup',
|
||||
isBoolean: true
|
||||
}
|
||||
}
|
||||
},
|
||||
action: function(args) {
|
||||
var data = {
|
||||
volumeId: args.data.volume,
|
||||
quiescevm: args.data.quiescevm === 'on',
|
||||
asyncBackup: args.data.asyncBackup === 'on'
|
||||
};
|
||||
if (args.data.name != null && args.data.name.length > 0) {
|
||||
$.extend(data, {
|
||||
name: args.data.name
|
||||
});
|
||||
}
|
||||
$.ajax({
|
||||
url: createURL('createSnapshot'),
|
||||
data: data,
|
||||
dataType: 'json',
|
||||
async: true,
|
||||
success: function(json) {
|
||||
var jid = json.createsnapshotresponse.jobid;
|
||||
args.response.success({
|
||||
_custom: {
|
||||
jobId: jid,
|
||||
onComplete: function(json) {
|
||||
var volumeId = json.queryasyncjobresultresponse.jobresult.snapshot.volumeid;
|
||||
var snapshotId = json.queryasyncjobresultresponse.jobresult.snapshot.id;
|
||||
cloudStack.dialog.notice({
|
||||
message: 'Created snapshot for volume ' + volumeId + ' with snapshot ID ' + snapshotId
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
notification: {
|
||||
poll: pollAsyncJobResult
|
||||
}
|
||||
},
|
||||
destroy: vmDestroyAction(),
|
||||
expunge: {
|
||||
label: 'label.action.expunge.instance',
|
||||
|
|
@ -3437,6 +3542,7 @@
|
|||
|
||||
if (jsonObj.hypervisor != 'LXC') {
|
||||
allowedActions.push("snapshot");
|
||||
allowedActions.push("storageSnapshot");
|
||||
}
|
||||
|
||||
allowedActions.push("destroy");
|
||||
|
|
@ -3474,6 +3580,7 @@
|
|||
|
||||
if (jsonObj.hypervisor != 'KVM' && jsonObj.hypervisor != 'LXC') {
|
||||
allowedActions.push("snapshot");
|
||||
allowedActions.push("storageSnapshot");
|
||||
}
|
||||
|
||||
allowedActions.push("scaleUp"); //when vm is stopped, scaleUp is supported for all hypervisors
|
||||
|
|
|
|||
|
|
@ -166,8 +166,7 @@ public class VolumeUsageParser {
|
|||
usageDesc += " (DiskOffering: " + doId + ")";
|
||||
}
|
||||
|
||||
UsageVO usageRecord =
|
||||
new UsageVO(zoneId, account.getId(), account.getDomainId(), usageDesc, usageDisplay + " Hrs", type, new Double(usage), null, null, doId, templateId, volId,
|
||||
UsageVO usageRecord = new UsageVO(zoneId, account.getId(), account.getDomainId(), usageDesc, usageDisplay + " Hrs", type, new Double(usage), null, null, doId, templateId, volId,
|
||||
size, startDate, endDate);
|
||||
s_usageDao.persist(usageRecord);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue