- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I am able to add the disks linearly like below:
my $vmSpec = VirtualMachineConfigSpec->new(deviceChange => [$devSpecs[0]]);
$vmView->ReconfigVM(spec => $vmSpec);
my $vmSpec = VirtualMachineConfigSpec->new(deviceChange => [$devSpecs[1]]);
$vmView->ReconfigVM(spec => $vmSpec);
my $vmSpec = VirtualMachineConfigSpec->new(deviceChange => [$devSpecs[2]]);
$vmView->ReconfigVM(spec => $vmSpec);
However, when I attempt to add all the disks at once I get a SOAP fault
my $vmSpec = VirtualMachineConfigSpec->new(deviceChange => \@devSpecs);
$vmView->ReconfigVM(spec => $vmSpec);
The Error:
SOAP Fault:
-----------
Fault string: Cannot complete the operation because the file or folder /vmfs/volumes/ba5e81fe-201a6c4e/paul-vm1/paul-vm1_0_3.vmdk already exists
Fault detail: FileAlreadyExistsPAULWORK>clear
Is there anyone out there that knows what is going on?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I've created new disks before in bulk. Are you adding or creating disks? Got more of your code to show?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I did not want to do a code dump, but here you go
- package VManagement;
- # Paul Givens
- # Evaluator Group
- # 6/11/2013
- # A package for manipulaing virtual machines through vSphere
- # Public functions
- # addDisks
- use strict;
- use warnings;
- # I do not know why this lib is needed, delete it for a fun time
- use lib "/usr/lib/vmware-vcli/apps";
- use Exporter;
- use VMware::VIRuntime;
- use AppUtil::VMUtil;
- # Making a module
- our @ISA = qw( Exporter );
- our @EXPORT_OK = qw( addDisks );
- our @EXPORT = qw( addDisks );
- # Declarations
- sub addDisks;
- sub atomicAddDisks;
- # addDisks
- # a function to add disks to a virtual machine
- sub addDisks{
- # Getting arguments
- (my $viServer, my $login, my $password, my $verbose) = @_;
- # Setting the global variables
- $ENV{VI_SERVER} ="$viServer";
- $ENV{VI_USERNAME} ="$login";
- $ENV{VI_PASSWORD} ="$password";
- # Connecting
- Opts::parse();
- Opts::validate();
- Util::connect();
- # TEST start
- my @diskSizes = (1,2,1);
- my @datastores = ("zebi1n", "zebi1n", "zebi1n");
- # TEST stop
- if ($verbose) {print "Connected to server\n";}
- atomicAddDisks("paul-vm1", \@diskSizes, \@datastores, $verbose);
- # Disconnecting
- Util::disconnect();
- }
- sub atomicAddDisks{
- # Getting arguments
- (my $vmName, my $diskSizesRef, my $datastoresRef, my $verbose) = @_;
- # Dereferencing
- my @diskSizes = @$diskSizesRef;
- my @datastores = @$datastoresRef;
- # Kb to Gb conversion factor
- my $scsiNum = 0;
- my @devSpecs = ();
- my $vmView = Vim::find_entity_view(view_type => 'VirtualMachine',
- filter => { 'name' => $vmName } );
- my $vmDevices = $vmView->config->hardware->device;
- my $diskFilename;
- my $diskFilenameIncrement = 0;
- my $diskFilenameCur;
- my $diskNum = 0;
- foreach my $vmDevice (@$vmDevices) {
- # Adjusting the diskNum for disks already present
- if (ref($vmDevice) eq 'VirtualDisk') {
- $diskNum++;
- }
- }
- # Search virtual SCSI controller
- my $controller;
- my $numController = 0;
- foreach my $vmDevice (@$vmDevices) {
- if (ref($vmDevice) =~/VirtualBusLogicController|VirtualLsiLogicController|VirtualLsiLogicSASController|ParaVirtualSCSIController/) {
- Util::trace(1, "SCSI controller found : $&\n");
- $numController++;
- $controller = $vmDevice;
- }
- }
- my $controllerKey = $controller->key;
- # Set new unit number (7 cannot be used, and limit is 15)
- my $unitNum;
- my $vdiskNumber = $#{$controller->device} + 1;
- if ($vdiskNumber < 7) {
- $unitNum = $vdiskNumber;
- }
- elsif ($vdiskNumber == 15) {
- die "ERR: one SCSI controller cannot have more than 15 virtual disks\n";
- }
- else {
- $unitNum = $vdiskNumber + 1;
- }
- for(my $i = 0; $i < @datastores; $i++) {
- # Conversion to GB
- my $disksize = $diskSizes[$i] * 1048576;
- my $datastore = $datastores[$i];
- # Increase the disk number to represent the machine to be added
- $diskNum++;
- $diskFilename = "[$datastore] paul-vm1/paul-vm1_" . "$scsiNum" . "_" . $unitNum . ".vmdk";
- # Build virtual spec data object
- my $diskMode = VMUtils::get_diskmode(
- nopersist => "",
- independent => ""
- );
- if ($verbose){
- print "SPECS\n";
- print "\tVM Name:\t$vmName\n";
- print "\tDisk Name:\t$diskFilename\n";
- print "\tController Key:\t$controllerKey\n";
- print "\tUnit Number\t$unitNum\n";
- print "\tDisk Size\t$disksize\n";
- }
- my $devSpec = VMUtils::get_vdisk_spec(
- vm => $vmView,
- backingtype => 'regular',
- diskMode => $diskMode,
- fileName => $diskFilename,
- controllerKey => $controllerKey,
- unitNumber => $unitNum,
- size => $disksize);
- ###########################################
- # Run ReconfigVM method (in VMUtils package)
- # with previously defined specs
- ###########################################
- push(@devSpecs, $devSpec);
- #increase the unit number for each device
- $unitNum++;
- }
- my $vmSpec = VirtualMachineConfigSpec->new(deviceChange => \@devSpecs);
- $vmView->ReconfigVM(spec => $vmSpec);
- #my $vmSpec = VirtualMachineConfigSpec->new(deviceChange => [$devSpecs[0]]);
- #$vmView->ReconfigVM(spec => $vmSpec);
- #my $vmSpec = VirtualMachineConfigSpec->new(deviceChange => [$devSpecs[1]]);
- #$vmView->ReconfigVM(spec => $vmSpec);
- #my $vmSpec = VirtualMachineConfigSpec->new(deviceChange => [$devSpecs[2]]);
- #$vmView->ReconfigVM(spec => $vmSpec);
- }
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Since you're adding an existing VMDK, any chance you're adding it twice or it's already attached to that VM?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I dont think so, If that was true, why could I add the three individual machines by array index as apposed to passing it the array of three items
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Do this, add "print Dumper($vmSpec)" before line 150. We can eyeball the spec sent to the API.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I did a dump like you said and it was very helpful. I needed to add the code below to make it work
Turns out that I need a unique key for every disk that I am adding. Thank you for your help
my $disk = VirtualDisk->new(
controllerKey => $devSpec->device->controllerKey,
unitNumber => $devSpec->device->unitNumber,
key => -1 *($i + 1),
backing => $devSpec->device->backing,
capacityInKB => $devSpec->device->capacityInKB,
);
$devSpec = VirtualDeviceConfigSpec->new(
operation => $devSpec->operation,
fileOperation => $devSpec->fileOperation,
device => $disk,
);
Is there a better way to do it than this
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
"key => -1" works fine for me:
Since I am adding a bunch of pre-existing disks, what I do is this:
- locate the disks based on the datastore and folder location using datastore browser (SearchDatastoreSubFolders call).
- do an inventory of the controllers so that I can reference the controller keys when needed
- do an inventory of the virtual disks currently attached to the vm (so that I know if adding more disk to a particular virtual node makes sense).
then loop through the diks that you have found from the datastore and are supposedly attaching disks to.
my $backing = @$disks[$i]->diskType->new (
diskMode => 'independent_persistent',
fileName => $result->folderPath . @$disks[$i]->path,
);
my $connectInfo = VirtualDeviceConnectInfo->new (
allowGuestControl => 0,
connected => 1,
startConnected => 1,
);
my $devInfo = VirtualDisk->new (
backing => $backing,
controllerKey => $ctrlKey,
unitNumber => $unit,
connectable => $connectInfo,
key => -1,
capacityInKB => @$disks[$i]->capacityKb,
);
$devspec[$i] = VirtualDeviceConfigSpec->new(
operation => VirtualDeviceConfigSpecOperation->new('add'),
device => $devInfo,
);
Once finish the loop, construct the $spec and run reconfigVM (or reconfigVM_task):
my $spec = VirtualMachineConfigSpec->new(deviceChange => [@devspec] );
if (@devspec) {
print "Reconfig VM with disk changes...\n";
# Asynchronous vs Synchronous execution
#eval { $vm->ReconfigVM(spec => $spec); };
eval { $vm->ReconfigVM_Task(spec => $spec); };
if ($@) { print "Reconfiguration failed.\n $@";}
else {print "Disks added successfully.\n"; }
} else { print "Nothing to add!\n"};