Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import com.cloud.agent.api.PatchSystemVmCommand;
import com.cloud.resource.ServerResourceBase;
import com.cloud.utils.FileUtil;
import com.cloud.utils.LogUtils;
import com.cloud.utils.validation.ChecksumUtil;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.storage.command.CopyCommand;
Expand Down Expand Up @@ -2365,7 +2366,9 @@ protected StartAnswer execute(StartCommand cmd) {
scsiUnitNumber++;
}

VirtualDevice device = VmwareHelper.prepareDiskDevice(vmMo, null, controllerKey, diskChain, volumeDsDetails.first(), deviceNumber, i + 1);
Long maxIops = volumeTO.getIopsWriteRate() + volumeTO.getIopsReadRate();
VirtualDevice device = VmwareHelper.prepareDiskDevice(vmMo, null, controllerKey, diskChain, volumeDsDetails.first(), deviceNumber, i + 1, maxIops);
s_logger.debug(LogUtils.logGsonWithoutException("The following definitions will be used to start the VM: virtual device [%s], volume [%s].", device, volumeTO));

diskStoragePolicyId = volumeTO.getvSphereStoragePolicyId();
if (StringUtils.isNotEmpty(diskStoragePolicyId)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@
import org.apache.cloudstack.storage.command.ResignatureCommand;
import org.apache.cloudstack.storage.command.SnapshotAndCopyAnswer;
import org.apache.cloudstack.storage.command.SnapshotAndCopyCommand;
import org.apache.cloudstack.storage.command.SyncVolumePathCommand;
import org.apache.cloudstack.storage.command.SyncVolumePathAnswer;
import org.apache.cloudstack.storage.command.SyncVolumePathCommand;
import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
import org.apache.cloudstack.storage.to.SnapshotObjectTO;
import org.apache.cloudstack.storage.to.TemplateObjectTO;
Expand Down Expand Up @@ -97,6 +97,7 @@
import com.cloud.storage.Volume;
import com.cloud.storage.template.OVAProcessor;
import com.cloud.template.TemplateManager;
import com.cloud.utils.LogUtils;
import com.cloud.utils.Pair;
import com.cloud.utils.Ternary;
import com.cloud.utils.exception.CloudRuntimeException;
Expand Down Expand Up @@ -2144,7 +2145,7 @@ private Answer attachVolume(Command cmd, DiskTO disk, boolean isAttach, boolean
diskController = vmMo.getRecommendedDiskController(null);
}

vmMo.attachDisk(new String[] { datastoreVolumePath }, morDs, diskController, storagePolicyId);
vmMo.attachDisk(new String[] { datastoreVolumePath }, morDs, diskController, storagePolicyId, volumeTO.getIopsReadRate() + volumeTO.getIopsWriteRate());
VirtualMachineDiskInfoBuilder diskInfoBuilder = vmMo.getDiskInfoBuilder();
VirtualMachineDiskInfo diskInfo = diskInfoBuilder.getDiskInfoByBackingFileBaseName(volumePath, dsMo.getName());
chainInfo = _gson.toJson(diskInfo);
Expand Down Expand Up @@ -2425,7 +2426,7 @@ public Answer dettachVolume(DettachCommand cmd) {

@Override
public Answer createVolume(CreateObjectCommand cmd) {

s_logger.debug(LogUtils.logGsonWithoutException("Executing CreateObjectCommand cmd: [%s].", cmd));
VolumeObjectTO volume = (VolumeObjectTO)cmd.getData();
DataStoreTO primaryStore = volume.getDataStore();
String vSphereStoragePolicyId = volume.getvSphereStoragePolicyId();
Expand Down
24 changes: 24 additions & 0 deletions utils/src/main/java/com/cloud/utils/LogUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,22 @@
package com.cloud.utils;

import java.io.File;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.log4j.Appender;
import org.apache.log4j.FileAppender;
import org.apache.log4j.Logger;
import org.apache.log4j.xml.DOMConfigurator;

import com.google.gson.Gson;

public class LogUtils {
public static final Logger LOGGER = Logger.getLogger(LogUtils.class);
private static final Gson GSON = new Gson();

private static String configFileLocation = null;

Expand Down Expand Up @@ -72,4 +77,23 @@ public static Set<String> getLogFileNames() {
}
return fileNames;
}

public static String logGsonWithoutException(String formatMessage, Object ... objects) {
List<String> gsons = new ArrayList<>();
for (Object object : objects) {
try {
gsons.add(GSON.toJson(object));
} catch (Exception e) {
LOGGER.debug(String.format("Failed to log object [%s] using GSON.", object != null ? object.getClass().getSimpleName() : "null"));
gsons.add("error to decode");
}
}
try {
return String.format(formatMessage, gsons.toArray());
} catch (Exception e) {
String errorMsg = String.format("Failed to log objects using GSON due to: [%s].", e.getMessage());
LOGGER.error(errorMsg, e);
return errorMsg;
}
}
}
39 changes: 39 additions & 0 deletions utils/src/test/java/com/cloud/utils/LogUtilsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// 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.utils;

import static org.junit.Assert.assertEquals;

import org.junit.Test;

public class LogUtilsTest {

@Test
public void logGsonWithoutExceptionTestLogCorrectlyPrimitives() {
String expected = "test primitives: int [1], double [1.11], float [1.2222], boolean [true], null [], char [\"c\"].";
String log = LogUtils.logGsonWithoutException("test primitives: int [%s], double [%s], float [%s], boolean [%s], null [%s], char [%s].",
1, 1.11d, 1.2222f, true, null, 'c');
assertEquals(expected, log);
}

@Test
public void logGsonWithoutExceptionTestPassWrongNumberOfArgs() {
String expected = "Failed to log objects using GSON due to: [Format specifier '%s'].";
String result = LogUtils.logGsonWithoutException("teste wrong [%s] %s args.", "blablabla");
assertEquals(expected, result);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
import com.vmware.vim25.VirtualNicManagerNetConfig;
import com.cloud.hypervisor.vmware.util.VmwareContext;
import com.cloud.hypervisor.vmware.util.VmwareHelper;
import com.cloud.utils.LogUtils;
import com.cloud.utils.Pair;

public class HostMO extends BaseMO implements VmwareHypervisorHost {
Expand Down Expand Up @@ -643,6 +644,7 @@ public VirtualMachineMO findVmOnPeerHyperHost(String name) throws Exception {
@Override
public boolean createVm(VirtualMachineConfigSpec vmSpec) throws Exception {
assert (vmSpec != null);
s_logger.debug(LogUtils.logGsonWithoutException("Creating VM with configuration: [%s].", vmSpec));
DatacenterMO dcMo = new DatacenterMO(_context, getHyperHostDatacenter());
ManagedObjectReference morPool = getHyperHostOwnerResourcePool();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
import com.cloud.offering.NetworkOffering;
import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.utils.ActionDelegate;
import com.cloud.utils.LogUtils;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.Pair;
import com.cloud.utils.cisco.n1kv.vsm.NetconfHelper;
Expand Down Expand Up @@ -1622,6 +1623,7 @@ public static boolean createBlankVm(VmwareHypervisorHost host, String vmName, St
DatacenterMO dataCenterMo = new DatacenterMO(host.getContext(), host.getHyperHostDatacenter());
setVMHardwareVersion(vmConfig, clusterMo, dataCenterMo);

s_logger.debug(LogUtils.logGsonWithoutException("Creating blank VM with configuration [%s].", vmConfig));
if (host.createVm(vmConfig)) {
// Here, when attempting to find the VM, we need to use the name
// with which we created it. This is the only such place where
Expand Down Expand Up @@ -2128,7 +2130,7 @@ public static void createOvfFile(VmwareHypervisorHost host, String diskFileName,
VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec();

// Reconfigure worker VM with datadisk
VirtualDevice device = VmwareHelper.prepareDiskDevice(workerVmMo, null, -1, disks, morDs, -1, 1);
VirtualDevice device = VmwareHelper.prepareDiskDevice(workerVmMo, null, -1, disks, morDs, -1, 1, null);
deviceConfigSpec.setDevice(device);
deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.ADD);
vmConfigSpec.getDeviceChange().add(deviceConfigSpec);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import com.cloud.hypervisor.vmware.util.VmwareContext;
import com.cloud.hypervisor.vmware.util.VmwareHelper;
import com.cloud.utils.ActionDelegate;
import com.cloud.utils.LogUtils;
import com.cloud.utils.Pair;
import com.cloud.utils.Ternary;
import com.cloud.utils.concurrency.NamedThreadFactory;
Expand Down Expand Up @@ -1400,7 +1401,10 @@ public void attachDisk(String[] vmdkDatastorePathChain, ManagedObjectReference m
}

public void attachDisk(String[] vmdkDatastorePathChain, ManagedObjectReference morDs, String diskController, String vSphereStoragePolicyId) throws Exception {
attachDisk(vmdkDatastorePathChain, morDs, diskController, vSphereStoragePolicyId, null);
}

public void attachDisk(String[] vmdkDatastorePathChain, ManagedObjectReference morDs, String diskController, String vSphereStoragePolicyId, Long maxIops) throws Exception {
if(s_logger.isTraceEnabled())
s_logger.trace("vCenter API trace - attachDisk(). target MOR: " + _mor.getValue() + ", vmdkDatastorePath: "
+ GSON.toJson(vmdkDatastorePathChain) + ", datastore: " + morDs.getValue());
Expand Down Expand Up @@ -1430,7 +1434,7 @@ public void attachDisk(String[] vmdkDatastorePathChain, ManagedObjectReference m
}

synchronized (_mor.getValue().intern()) {
VirtualDevice newDisk = VmwareHelper.prepareDiskDevice(this, null, controllerKey, vmdkDatastorePathChain, morDs, unitNumber, 1);
VirtualDevice newDisk = VmwareHelper.prepareDiskDevice(this, null, controllerKey, vmdkDatastorePathChain, morDs, unitNumber, 1, maxIops);
if (StringUtils.isNotBlank(diskController)) {
String vmdkFileName = vmdkDatastorePathChain[0];
updateVmdkAdapter(vmdkFileName, diskController);
Expand Down Expand Up @@ -2099,7 +2103,7 @@ public VirtualMachineMO cloneFromDiskChain(String clonedVmName, int cpuSpeedMHz,
VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec();
VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec();

VirtualDevice device = VmwareHelper.prepareDiskDevice(clonedVmMo, null, -1, disks, morDs, -1, 1);
VirtualDevice device = VmwareHelper.prepareDiskDevice(clonedVmMo, null, -1, disks, morDs, -1, 1, null);

deviceConfigSpec.setDevice(device);
deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.ADD);
Expand Down Expand Up @@ -2133,6 +2137,7 @@ public GuestOsDescriptor getGuestOsDescriptor(String guestOsId) throws Exception
}

public void plugDevice(VirtualDevice device) throws Exception {
s_logger.debug(LogUtils.logGsonWithoutException("Pluging device [%s] to VM [%s].", device, getVmName()));
VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec();
VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec();
deviceConfigSpec.setDevice(device);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import com.cloud.hypervisor.vmware.mo.VirtualEthernetCardType;
import com.cloud.hypervisor.vmware.mo.VirtualMachineMO;
import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost;
import com.cloud.utils.LogUtils;
import com.cloud.utils.Pair;
import com.cloud.utils.Ternary;
import com.cloud.utils.exception.ExceptionUtil;
Expand All @@ -61,6 +62,7 @@
import com.vmware.vim25.PerfCounterInfo;
import com.vmware.vim25.PerfMetricId;
import com.vmware.vim25.ResourceAllocationInfo;
import com.vmware.vim25.StorageIOAllocationInfo;
import com.vmware.vim25.VirtualCdrom;
import com.vmware.vim25.VirtualCdromIsoBackingInfo;
import com.vmware.vim25.VirtualCdromRemotePassthroughBackingInfo;
Expand All @@ -87,7 +89,6 @@
import com.vmware.vim25.VirtualVmxnet3;

public class VmwareHelper {
@SuppressWarnings("unused")
private static final Logger s_logger = Logger.getLogger(VmwareHelper.class);

public static final int MAX_SCSI_CONTROLLER_COUNT = 4;
Expand Down Expand Up @@ -141,7 +142,6 @@ private static VirtualEthernetCard createVirtualEthernetCard(VirtualEthernetCard

public static VirtualDevice prepareNicOpaque(VirtualMachineMO vmMo, VirtualEthernetCardType deviceType, String portGroupName,
String macAddress, int contextNumber, boolean connected, boolean connectOnStart) throws Exception {

assert(vmMo.getRunningHost().hasOpaqueNSXNetwork());

VirtualEthernetCard nic = createVirtualEthernetCard(deviceType);
Expand Down Expand Up @@ -215,8 +215,10 @@ public static VirtualDevice prepareDvNicDevice(VirtualMachineMO vmMo, ManagedObj

// vmdkDatastorePath: [datastore name] vmdkFilePath
public static VirtualDevice prepareDiskDevice(VirtualMachineMO vmMo, VirtualDisk device, int controllerKey, String vmdkDatastorePathChain[],
ManagedObjectReference morDs, int deviceNumber, int contextNumber) throws Exception {

ManagedObjectReference morDs, int deviceNumber, int contextNumber, Long maxIops) throws Exception {
s_logger.debug(LogUtils.logGsonWithoutException("Trying to prepare disk device to virtual machine [%s], using the following details: Virtual device [%s], "
+ "ManagedObjectReference [%s], ControllerKey [%s], VMDK path chain [%s], DeviceNumber [%s], ContextNumber [%s] and max IOPS [%s].",
vmMo, device, morDs, controllerKey, vmdkDatastorePathChain, deviceNumber, contextNumber, maxIops));
assert (vmdkDatastorePathChain != null);
assert (vmdkDatastorePathChain.length >= 1);

Expand All @@ -243,6 +245,13 @@ public static VirtualDevice prepareDiskDevice(VirtualMachineMO vmMo, VirtualDisk
disk.setKey(-contextNumber);
disk.setUnitNumber(deviceNumber);

if (maxIops != null && maxIops > 0) {
s_logger.debug(LogUtils.logGsonWithoutException("Defining [%s] as the max IOPS of disk [%s].", maxIops, disk));
StorageIOAllocationInfo storageIOAllocationInfo = new StorageIOAllocationInfo();
storageIOAllocationInfo.setLimit(maxIops);
disk.setStorageIOAllocation(storageIOAllocationInfo);
}

VirtualDeviceConnectInfo connectInfo = new VirtualDeviceConnectInfo();
connectInfo.setConnected(true);
connectInfo.setStartConnected(true);
Expand All @@ -255,6 +264,9 @@ public static VirtualDevice prepareDiskDevice(VirtualMachineMO vmMo, VirtualDisk
setParentBackingInfo(backingInfo, morDs, parentDisks);
}

s_logger.debug(LogUtils.logGsonWithoutException("Prepared disk device, to attach to virtual machine [%s], has the following details: Virtual device [%s], "
+ "ManagedObjectReference [%s], ControllerKey [%s], VMDK path chain [%s], DeviceNumber [%s], ContextNumber [%s] and max IOPS [%s], is: [%s].",
vmMo, device, morDs, controllerKey, vmdkDatastorePathChain, deviceNumber, contextNumber, maxIops, disk));
return disk;
}

Expand Down Expand Up @@ -750,5 +762,4 @@ public static HostMO getHostMOFromHostName(final VmwareContext context, final St
}
return host;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// 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.vmware.util;

import static org.junit.Assert.assertEquals;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;

import com.cloud.hypervisor.vmware.mo.VirtualMachineMO;
import com.vmware.vim25.VirtualDisk;

@RunWith(MockitoJUnitRunner.class)
public class VmwareHelperTest {
@Mock
private VirtualMachineMO virtualMachineMO;

@Test
public void prepareDiskDeviceTestNotLimitingIOPS() throws Exception {
Mockito.when(virtualMachineMO.getIDEDeviceControllerKey()).thenReturn(1);
VirtualDisk virtualDisk = (VirtualDisk) VmwareHelper.prepareDiskDevice(virtualMachineMO, null, -1, new String[1], null, 0, 0, null);
assertEquals(null, virtualDisk.getStorageIOAllocation());
}

@Test
public void prepareDiskDeviceTestLimitingIOPS() throws Exception {
Mockito.when(virtualMachineMO.getIDEDeviceControllerKey()).thenReturn(1);
VirtualDisk virtualDisk = (VirtualDisk) VmwareHelper.prepareDiskDevice(virtualMachineMO, null, -1, new String[1], null, 0, 0, Long.valueOf(1000));
assertEquals(Long.valueOf(1000), virtualDisk.getStorageIOAllocation().getLimit());
}

@Test
public void prepareDiskDeviceTestLimitingIOPSToZero() throws Exception {
Mockito.when(virtualMachineMO.getIDEDeviceControllerKey()).thenReturn(1);
VirtualDisk virtualDisk = (VirtualDisk) VmwareHelper.prepareDiskDevice(virtualMachineMO, null, -1, new String[1], null, 0, 0, Long.valueOf(0));
assertEquals(null, virtualDisk.getStorageIOAllocation());
}
}