VMware {code} Community
joshames
Enthusiast
Enthusiast

Help with creating baremetal VM on Storage DRS Cluster (vSphere SDK)

Hello,

 

I would appreciate any help from anyone who has successfully built a baremetal VM on a Storage DRS Cluster in the vSphere SDK.  I am using c#.

I can clone vm's fine on the Storage DRS cluster, but when I am creating a baremetal VM, I am having issues with the ConfigSpec and the PodSelectionSpec.  Specifically, what do I put for the Datastore and fileName properties of the VirtualDiskFlatVer2BackingInfo properties.  I get an error that I have an incorrect parameter in the ConfigSpec and PodSelectionSpec.  Here is some code to create the PodSelectionSpec:

StorageDrsPodSelectionSpec podSelectionSpec = new StorageDrsPodSelectionSpec();

podSelectionSpec.StoragePod = vmOBJ.DataStore.Item2;

StoragePlacementSpec podPlacement = new StoragePlacementSpec();

podPlacement.DisallowPrerequisiteMoves = true;

podPlacement.Folder = vmOBJ.Folder.Item2;

podPlacement.Type = "create";

podPlacement.ConfigSpec = (VirtualMachineConfigSpec)Session["ConfigSpec"];

podPlacement.ResourcePool = vmOBJ.ResourcePool.Item2;

podPlacement.Host = hostMoref;

 

VmPodConfigForPlacement vmPodConfig = new VmPodConfigForPlacement();

vmPodConfig.StoragePod = vmOBJ.DataStore.Item2;

List<PodDiskLocator> podDiskConfig = new List<PodDiskLocator>();

VirtualMachineConfigSpec tempcfgspec = (VirtualMachineConfigSpec)Session["ConfigSpec"];

VirtualDeviceConfigSpec[] tempVDCfg = tempcfgspec.DeviceChange;

foreach (VirtualDeviceConfigSpec vd in tempVDCfg)

{

VirtualDevice VD = vd.Device;

if (VD.DeviceInfo.Label.Equals("Disk"))

{

PodDiskLocator temppodloc = new PodDiskLocator();

temppodloc.DiskId = vd.Device.Key;

VirtualDiskFlatVer2BackingInfo flatBack = new VirtualDiskFlatVer2BackingInfo();

flatBack.ThinProvisioned = true;

flatBack.DiskMode = "persistent";

flatBack.Datastore = null;

flatBack.FileName = "";

temppodloc.DiskBackingInfo = flatBack;

podDiskConfig.Add(temppodloc);

}

}

vmPodConfig.Disk = podDiskConfig.ToArray();

podSelectionSpec.InitialVmConfig = new VmPodConfigForPlacement[]{ vmPodConfig };

podPlacement.PodSelectionSpec = podSelectionSpec;

 

And here is the code to create the backinginfo:

VirtualDiskFlatVer2BackingInfo backInfo = new VirtualDiskFlatVer2BackingInfo();

backInfo.ThinProvisioned = thinProvisioned;

backInfo.DiskMode = "persistent";

backInfo.Datastore = null;

backInfo.FileName = "";

VirtualDisk tempDisk = new VirtualDisk();

tempDisk.Backing = backInfo;

tempDisk.CapacityInKB = size;

tempDisk.ControllerKey = controllerKey;

tempDisk.Key = (1 + i);

tempDisk.UnitNumber = unitNumber;

tempDisk.DeviceInfo = new Description();

tempDisk.DeviceInfo.Label = "Disk";

tempDisk.DeviceInfo.Summary = "Disk";

VirtualDeviceConfigSpec tempConfigSpec = new VirtualDeviceConfigSpec();

tempConfigSpec.Device = tempDisk;

tempConfigSpec.FileOperation = VirtualDeviceConfigSpecFileOperation.create;

tempConfigSpec.Operation = VirtualDeviceConfigSpecOperation.add;

 

I realize that there is a lot going on but what I can't find the answer to, is how do I let vSphere choose the datastore and what do I need to have in there to create a VM on a Storage DRS Cluster?

Reply
0 Kudos
5 Replies
benyoungnz
Contributor
Contributor

With my version of this i am doing the following 

1) Find a datastore via my GetStorageRecommendation function (code below), this will retun an array of StoragePlacementAction / recommnedations of which i always use the first item

 

2) Pass the first StoragePlacementAction to get the GetDataStoreName (code below) returns a string

 

3) Use this datstore name on your diskfileBacking.fileName, remember to add the [ ] around the DataStore name, i.e  "[" + dataStoreName+ "]"; - or combine into above function if you do not intend on using GetDataStoreName for anything else/create a function wrap the dataStorename to add this if reusing elsewhere

 

public List<ClusterRecommendation> GetStorageRecommendation(string PodName, ManagedObjectReference resPool, ManagedObjectReference folderRef, VirtualMachineConfigSpec vmConfig)

        {

            ManagedObjectReference srmRef = cb._connection._sic.storageResourceManager;

            ManagedObjectReference osSRDS = cb._svcUtil.getEntityByName("StoragePod", PodName);

            var podSel = new StorageDrsPodSelectionSpec();

            podSel.storagePod = osSRDS;

            var spSpec = new StoragePlacementSpec();

            spSpec.type = "create";

            spSpec.resourcePool = resPool;

            spSpec.folder = folderRef;

            spSpec.configSpec = vmConfig;

            spSpec.podSelectionSpec = podSel;

            var rec = cb._connection._service.RecommendDatastores(srmRef, spSpec);

            var crs = new List<ClusterRecommendation>();

            crs.AddRange(rec.recommendations);

            return crs;

        }

        public List<ClusterRecommendation> GetStorageRecommendation(string PodName, ManagedObjectReference resPool, ManagedObjectReference folderRef, VirtualMachineConfigSpec vmConfig)
        {
 
 
            ManagedObjectReference srmRef = cb._connection._sic.storageResourceManager;
            ManagedObjectReference osSRDS = cb._svcUtil.getEntityByName("StoragePod", PodName);
            var podSel = new StorageDrsPodSelectionSpec();
            podSel.storagePod = osSRDS;
 
            var spSpec = new StoragePlacementSpec();
            spSpec.type = "create";
            spSpec.resourcePool = resPool;
            spSpec.folder = folderRef;
            spSpec.configSpec = vmConfig;
            spSpec.podSelectionSpec = podSel;
 
 
            var rec = cb._connection._service.RecommendDatastores(srmRef, spSpec);
 
            var crs = new List<ClusterRecommendation>();
 
            crs.AddRange(rec.recommendations);
 
            return crs;
        }

 

 public string GetDataStoreName(StoragePlacementAction pa)

        {

            ObjectContent[] ds = cb.getServiceUtil().GetObjectProperties(

                                                        null, pa.destination,

                                                        new String[] { "name" });

            if (!ds.Any()) throw new Exception("Datastore not found");

            return ds[0].propSet[0].val.ToString();

        }

Reply
0 Kudos
joshames
Enthusiast
Enthusiast

benyoungnz

Thanks for the reply.  So, if I am understanding your method correctly, you first gather all the required info then call a RecommendDatastores() and you use the resulting recommendation to go back and input the datastore name into the filebacking filename and Datastore fields?  or do you leave datastore blank?

Also, do you use the name to populate the VirtualMachineFileInfo.vmpathname?

And then after you have everything populated, I assume you will go back and use the first key and run ApplyStorageDRSRecommendation_Task(key);?

Please let me know if my thinking of how your program is set up is correct.

Thanks for your reply.

Reply
0 Kudos
benyoungnz
Contributor
Contributor

Below is the function i use to return a VirtualDeviceConfigSpec / disk as i often provision one or more disks on the machine at the same time/provisioning step based on user requirements. Once i have that disk it is added to my list of other devices which then is converted to an array and set on the VirtualMachineConfigSpec such as  vmConfigSpec.deviceChange = deviceConfigSpec.ToArray(); - deviceConfigSpec is my list as above

Been a while since i looked at the code but turns out i then just call the CreateVM_Task assuming my logic here was that i already had the recommendations made to me for each of the virtual disks just prior via the GetStorageRecommendation functions - may or may not be the right thing to do but certainly works well

public VirtualDeviceConfigSpec createVirtualDisk(String volName,
                                                    int diskCtlrKey,
                                                    int diskSizeMB, int unitNumber)
        {
            String volumeName = getVolumeName(volName);
            VirtualDeviceConfigSpec diskSpec = new VirtualDeviceConfigSpec();
 
            diskSpec.fileOperation = VirtualDeviceConfigSpecFileOperation.create;
            diskSpec.fileOperationSpecified = true;
            diskSpec.operation = VirtualDeviceConfigSpecOperation.add;
            diskSpec.operationSpecified = true;
 
            VirtualDisk disk = new VirtualDisk();
            VirtualDiskFlatVer2BackingInfo diskfileBacking = new VirtualDiskFlatVer2BackingInfo();
 
            diskfileBacking.fileName = volumeName;
            diskfileBacking.diskMode = "persistent";
            diskfileBacking.eagerlyScrub = true;
            diskfileBacking.eagerlyScrubSpecified = true;
 
            disk.key = unitNumber;
            disk.controllerKey = diskCtlrKey;
            disk.unitNumber = unitNumber;
            disk.backing = diskfileBacking;
            disk.capacityInKB = diskSizeMB * 1024;
            disk.controllerKeySpecified = true;
            disk.unitNumberSpecified = true;
 
 
            diskSpec.device = disk;
 
            return diskSpec;
        }

public VirtualDeviceConfigSpec createVirtualDisk(String volName,

                                                    int diskCtlrKey,

                                                    int diskSizeMB, int unitNumber)

        {

            String volumeName = getVolumeName(volName);

            VirtualDeviceConfigSpec diskSpec = new VirtualDeviceConfigSpec();

            diskSpec.fileOperation = VirtualDeviceConfigSpecFileOperation.create;

            diskSpec.fileOperationSpecified = true;

            diskSpec.operation = VirtualDeviceConfigSpecOperation.add;

            diskSpec.operationSpecified = true;

            VirtualDisk disk = new VirtualDisk();

            VirtualDiskFlatVer2BackingInfo diskfileBacking = new VirtualDiskFlatVer2BackingInfo();

            diskfileBacking.fileName = volumeName;

            diskfileBacking.diskMode = "persistent";

            diskfileBacking.eagerlyScrub = true;

            diskfileBacking.eagerlyScrubSpecified = true;

            disk.key = unitNumber;

            disk.controllerKey = diskCtlrKey;

            disk.unitNumber = unitNumber;

            disk.backing = diskfileBacking;

            disk.capacityInKB = diskSizeMB * 1024;

            disk.controllerKeySpecified = true;

            disk.unitNumberSpecified = true;

            diskSpec.device = disk;

            return diskSpec;

        }

Reply
0 Kudos
joshames
Enthusiast
Enthusiast

oh ok got it. So you are bypassing the applystoragedrsrecommendations_task completely.  This might have to be the way I end up doing it.  I just don't understand why it doesn't work the other way, but it doesn't matter if I understand as long as I get it working.  At the end of the day no one will know the difference lol.  Have you seen and performance issues relating to not letting the drs cluster do the work?
Reply
0 Kudos
benyoungnz
Contributor
Contributor

It seems that way yeh - i can't remember if that was intentional or if i tried the other way first and it frustrated me so i then came up with this method - as you say the end result is the same, would be easy enough to try the other way first - not noticed any performance difference in terms of deployment time etc

Reply
0 Kudos