1

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???

Jim Davis
  • 5,241
  • 1
  • 26
  • 22
Adrian Todorov
  • 289
  • 1
  • 2
  • 11

2 Answers2

3
($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") {
  ...
}
cjm
  • 61,471
  • 9
  • 126
  • 175
  • Wow, ok, i wasn't aware that this is how while conditions were interpreted. Thanks – Adrian Todorov Aug 04 '15 at 15:13
  • @AdrianTodorov, there's nothing special about while conditions. This is basic Boolean algebra. – cjm Aug 04 '15 at 15:14
  • @ThisSuitIsBlackNot, that's a good idea. I keep forgetting Perl has a plain `until` loop. – cjm Aug 04 '15 at 15:16
  • Yes, when if/elsing, it seems logical, but when while-ing, while(!condition1 && !condition2), my interpretation is "until both conditions are false". Using || would imply(again, in my interpretation), "until one of the conditions is false". – Adrian Todorov Aug 04 '15 at 15:16
  • @cjm, is this Perl specific? I am almost certain i've used such a loop in C and i don't remember having any issues.. But maybe i am mistaken. – Adrian Todorov Aug 04 '15 at 15:17
  • 1
    @Adrian Todorov, Re "my interpretation is 'until both conditions are false'", Yet you wrote "while both conditions are true" – ikegami Aug 04 '15 at 15:18
  • @ikegami, what i meant was, loop until both conditions are false. – Adrian Todorov Aug 04 '15 at 15:19
  • 2
    @Adrian Todorov, Re "is this Perl specific?", No. `&&` implements "logical and" in both Perl and C (and Java and JS and SQL and ...) – ikegami Aug 04 '15 at 15:19
  • @Adrian Todorov, Re "what i meant was, loop until both conditions are false", Yet you wrote "loop while both values are wrong". You should have looped while either value is wrong. – ikegami Aug 04 '15 at 15:21
2

You want to loop until

$vm_powerState eq "poweredOn" && $vm_toolsStatus eq "toolsOk"

Which means you want to loop while

!( $vm_powerState eq "poweredOn" && $vm_toolsStatus eq "toolsOk" )

Equivalent:

!( $vm_powerState eq "poweredOn" ) || !( $vm_toolsStatus eq "toolsOk" )

Equivalent:

$vm_powerState ne "poweredOn" || $vm_toolsStatus ne "toolsOk"

In other words, you want to loop as long as either has the wrong value, but you are looping as long as both have the wrong value.

ikegami
  • 367,544
  • 15
  • 269
  • 518