Search code examples
perlwhile-loopvmware-tools

Perl while loop not behaving as expected


I am using a while loop with a sleep inside to check when a an event has occured(i am launching a Virtual Machine, and then using the loop to wait and be sure that it is powered on and booted).

My loop is as follows:

my $vm_powerState = $vm_view->runtime->powerState->val;
my $vm_toolsStatus = $vm_view->guest->toolsStatus->val;
while (
    ($vm_powerState ne "poweredOn")
 && ($vm_toolsStatus ne "toolsOk")
) {
    debug($vmname);
    $vm_view = Vim::find_entity_view(
        view_type => 'VirtualMachine',
        filter => {"config.name" => $vmname }
    );
    debug ($vm_powerState . "\nbla\n" . $vm_toolsStatus);
    # $vm_toolsStatus = $vm_view->guest->toolsStatus->val
    if (my $ref = eval { $vm_view->can("guest")} )
    {
        print "OK\n";
        print $vm_view->guest->toolsStatus->val;
        $vm_toolsStatus = $vm_view->guest->toolsStatus->val;
    }
    $vm_powerState = $vm_view->runtime->powerState->val if (defined($vm_view));
    debug($vm_powerState . "\n\nbla222\n\n" . $vm_toolsStatus);
    debug("...");
    sleep(1);
}
debug ($vm_toolsStatus);
debug ("VM is ON");

In brief, i get the state of the VM(poweredOff and toolsNotRunning by default), and then loop until they both have good values(poweredOn and toolsOk). Should work, right?

Well, no. The first loop after powerState changes to poweredOn, the loop ends, even though toolsStatus is "toolsNotRunning".

Here's the main part of my output:

$VAR1 = \'VM TESTVM2is being turned on';
$VAR1 = \'Waiting for the VM to turn on and boot, it might take some time';
$VAR1 = \'TESTVM2';
$VAR1 = \'poweredOff
bla
toolsNotRunning';
OK
toolsNotRunning$VAR1 = \'poweredOn

bla222

toolsNotRunning';
$VAR1 = \'...';
$VAR1 = \'toolsNotRunning';
$VAR1 = \'VM is ON';

As you can see, the program exits right after the value of powerState is poweredOn, even though the second condition of the while loop is clearly not met.

Why would that happen???


Solution

  • ($vm_powerState ne "poweredOn") && ($vm_toolsStatus ne "toolsOk")
    FALSE && TRUE
    FALSE
    

    You should have used || instead of &&.

    !(A && B) is equivalent to (!A || !B)

    A better way to write this loop would be:

    until ($vm_powerState eq "poweredOn" && $vm_toolsStatus eq "toolsOk") {
      ...
    }