Subversion Repositories havirt

Rev

Rev 41 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 41 Rev 42
Line 26... Line 26...
26
#
26
#
27
# v1.2.0 20240826 RWR
27
# v1.2.0 20240826 RWR
28
# Added some code to migrate domains if node placed in maintenance mode
28
# Added some code to migrate domains if node placed in maintenance mode
29
# Added a lot of 'verbose' print lines, and modified for new flag structure
29
# Added a lot of 'verbose' print lines, and modified for new flag structure
30
#
30
#
-
 
31
# v1.3.0 20250511 RWR
-
 
32
# Added balance function. If called, will attempt to balance a cluster so that the variance is lower than balance_max_variance 
-
 
33
# (new entry in config file). --dryrun will simply display the commands sent, and --nodryrun will execute them.
-
 
34
 
31
 
35
 
32
 
36
 
33
package cluster;
37
package cluster;
34
 
38
 
35
use warnings;
39
use warnings;
36
use strict;  
40
use strict;  
37
 
41
 
38
# define the version number
42
# define the version number
39
# see https://metacpan.org/pod/release/JPEACOCK/version-0.97/lib/version.pod
43
# see https://metacpan.org/pod/release/JPEACOCK/version-0.97/lib/version.pod
40
use version;
44
use version;
41
our $VERSION = version->declare("1.2.0");
45
our $VERSION = version->declare("1.3.0");
42
 
46
 
43
 
47
 
44
use Data::Dumper;
48
use Data::Dumper;
45
 
49
 
46
use Exporter;
50
use Exporter;
Line 67... Line 71...
67
   push @return, "\tPerforms an update to add new iSCSI targets on one or more nodes";
71
   push @return, "\tPerforms an update to add new iSCSI targets on one or more nodes";
68
   push @return, "\tScans all iSCSI targets, looking for new shares on each, then performs";
72
   push @return, "\tScans all iSCSI targets, looking for new shares on each, then performs";
69
   push @return, "\ta login, adding it to the node. DOES NOT delete old targets at this";
73
   push @return, "\ta login, adding it to the node. DOES NOT delete old targets at this";
70
   push @return, "\ttime. If no nodes passed in, will perform function on all nodes not";
74
   push @return, "\ttime. If no nodes passed in, will perform function on all nodes not";
71
   push @return, "\tin maintenance mode";
75
   push @return, "\tin maintenance mode";
-
 
76
   push @return, 'cluster balance';
-
 
77
   push @return, "\tAttempts to balance node memory usage by migrating domains to less used";
-
 
78
   push @return, "\tnodes. If a node is in maintenance mode, will attempt to move all domains";
-
 
79
   push @return, "\toff of it and balance them on the other nodes";
72
 
80
 
73
   return join( "\n", @return ) . "\n";
81
   return join( "\n", @return ) . "\n";
74
}
82
}
75
 
83
 
76
sub getClusterStats {
-
 
77
   my $return = {};
-
 
78
   foreach my $node (sort keys %{ $main::statusDB->{'node'} } ) {
-
 
79
      $return->{'nodes'}->{$node}->{'node_memory'} = $main::statusDB->{'node'}->{$node}->{'memory'};
-
 
80
      $return->{'nodes'}->{$node}->{'node_vcpu'} = $main::statusDB->{'node'}->{$node}->{'cpu_count'};
-
 
81
      $return->{'nodes'}->{$node}->{'node_maintenance'} = $main::statusDB->{'node'}->{$node}->{'maintenance'};
-
 
82
 
-
 
83
      $return->{'nodes'}->{$node}->{'domain_memory'} = 0;
-
 
84
      $return->{'nodes'}->{$node}->{'domain_vcpu'} = 0;
-
 
85
      $return->{'nodes'}->{$node}->{'domain_count'} = 0;
-
 
86
      foreach my $domain ( keys %{ $main::statusDB->{'nodePopulation'}->{$node}->{'running'} } ) {
-
 
87
         $return->{'nodes'}->{$node}->{'domain_memory'} += $main::statusDB->{'virt'}->{$domain}->{'memory'};
-
 
88
         $return->{'nodes'}->{$node}->{'domain_vcpu'} += $main::statusDB->{'virt'}->{$domain}->{'vcpu'};
-
 
89
         $return->{'nodes'}->{$node}->{'domain_count'}++;
-
 
90
         $return->{'nodes'}->{$node}->{'domains'}->{$domain}->{'memory'} = $main::statusDB->{'virt'}->{$domain}->{'memory'};
-
 
91
         $return->{'nodes'}->{$node}->{'domains'}->{$domain}->{'vcpu'} = $main::statusDB->{'virt'}->{$domain}->{'vcpu'};
-
 
92
      }
-
 
93
      if ( ! $main::statusDB->{'node'}->{$node}->{'maintenance'} ) { # do not include node resources if maintenance set
-
 
94
         $return->{'total_memory'} += $return->{'nodes'}->{$node}->{'node_memory'};
-
 
95
         $return->{'total_vcpu'} += $return->{'nodes'}->{$node}->{'node_vcpu'};
-
 
96
      }
-
 
97
      $return->{'total_count'} += $return->{'nodes'}->{$node}->{'domain_count'};
-
 
98
      $return->{'domain_memory'} += $return->{'nodes'}->{$node}->{'domain_memory'};
-
 
99
      $return->{'domain_vcpu'} += $return->{'nodes'}->{$node}->{'domain_vcpu'};
-
 
100
 
-
 
101
   }
-
 
102
   return $return;
-
 
103
}
-
 
104
 
-
 
105
sub status {
84
sub status {
106
   my $return = '';
85
   my $return = '';
107
   &main::readDB();
86
   &main::readDB();
108
   my @header = ('Node','Threads','Memory','Domains','vcpu','mem_used', 'Status' );
87
   my @header = ('Node','Threads','Memory','Domains','vcpu','mem_used', 'Status' );
109
   my @data;
88
   my @data;
Line 238... Line 217...
238
      push @return, "No new entries";
217
      push @return, "No new entries";
239
   }
218
   }
240
   return join( "\n", @return ) . "\n";
219
   return join( "\n", @return ) . "\n";
241
} # updateISCITargets
220
} # updateISCITargets
242
 
221
 
-
 
222
# calculate stats about the cluster, including the amount of memory/cpu used, the standard deviation
-
 
223
# and variance. Used mainly to balance cluster
-
 
224
sub getClusterStats {
-
 
225
   my $return = {};
-
 
226
   $return->{'cluster'}->{'memory'} = 0;
-
 
227
   $return->{'cluster'}->{'used_memory'} = 0;
-
 
228
   $return->{'cluster'}->{'count'} = 0;
-
 
229
   $return->{'cluster'}->{'used_vcpu'} = 0;
-
 
230
   $return->{'cluster'}->{'domain_count'} = 0;
-
 
231
   foreach my $node (sort keys %{ $main::statusDB->{'node'} } ) {
-
 
232
      # only count nodes which are not in maintenance as part of the cluster towards total memory available
-
 
233
      if ( ! $main::statusDB->{'node'}->{$node}->{'maintenance'} ) {
-
 
234
         $return->{'cluster'}->{'memory'} += $main::statusDB->{'node'}->{$node}->{'memory'};
-
 
235
         $return->{'cluster'}->{'vcpu'} += $main::statusDB->{'node'}->{$node}->{'cpu_count'};
-
 
236
         $return->{'cluster'}->{'count'}++;
-
 
237
      } else {
-
 
238
         $return->{'node'}->{$node}->{'maintenance'} = 1;
-
 
239
      }
-
 
240
      $return->{'node'}->{$node}->{'memory'} = $main::statusDB->{'node'}->{$node}->{'memory'};
-
 
241
      $return->{'node'}->{$node}->{'vcpu'} = $main::statusDB->{'node'}->{$node}->{'cpu_count'};
-
 
242
      $return->{'node'}->{$node}->{'used_memory'} = 0;
-
 
243
      $return->{'node'}->{$node}->{'count'} = 0;
-
 
244
      $return->{'node'}->{$node}->{'used_vcpu'} = 0;
-
 
245
      # get individual stats for every domain on the node
-
 
246
      foreach my $domain ( keys %{ $main::statusDB->{'nodePopulation'}->{$node}->{'running'} } ) {
-
 
247
         # track used memory, and count
-
 
248
         $return->{'node'}->{$node}->{'used_memory'} += $main::statusDB->{'virt'}->{$domain}->{'memory'};
-
 
249
         $return->{'node'}->{$node}->{'used_vcpu'} += $main::statusDB->{'virt'}->{$domain}->{'vcpu'};
-
 
250
         $return->{'node'}->{$node}->{'count'}++;
-
 
251
      }
-
 
252
      # calculate the average memory used in the node
-
 
253
      $return->{'node'}->{$node}->{'average_memory'} = $return->{'node'}->{$node}->{'used_memory'} / 
-
 
254
         (
-
 
255
            $main::statusDB->{'node'}->{$node}->{'maintenance'} ? 0.0001 : $main::statusDB->{'node'}->{$node}->{'memory'}
-
 
256
         );
-
 
257
      # add the used memory to the cluster
-
 
258
      $return->{'cluster'}->{'used_memory'} += $return->{'node'}->{$node}->{'used_memory'};
-
 
259
      $return->{'cluster'}->{'used_vcpu'} += $return->{'node'}->{$node}->{'used_vcpu'};
-
 
260
      $return->{'cluster'}->{'domain_count'} += $return->{'node'}->{$node}->{'count'};
-
 
261
   }
-
 
262
   # calculate the deviation for each active node in the cluster
-
 
263
   $return->{'cluster'}->{'average_memory'} = $return->{'cluster'}->{'used_memory'} / $return->{'cluster'}->{'memory'};
-
 
264
   
-
 
265
   # get the deviation for each node
-
 
266
   # variance in the cluster is simply the average of all deviations
-
 
267
   $return->{'cluster'}->{'variance'} = 0;
-
 
268
   foreach my $node (sort keys %{ $main::statusDB->{'node'} } ) {
-
 
269
      # deviation is the square of the difference between this node and the cluster overall
-
 
270
      $return->{'node'}->{$node}->{'deviation'} = (
-
 
271
         $return->{'node'}->{$node}->{'average_memory'} / $return->{'cluster'}->{'average_memory'} 
-
 
272
         ) ** 2;
-
 
273
      # we'll divide by number of active nodes after the loop
-
 
274
      $return->{'cluster'}->{'variance'} += $return->{'node'}->{$node}->{'deviation'};
-
 
275
   }
-
 
276
   $return->{'cluster'}->{'variance'} /= $return->{'cluster'}->{'count'};
-
 
277
   # now, determine how much memory needs to be added (plus) or removed (minus) for each node
-
 
278
   # memory_needed is calculated by taking the total amount of memory and multiplying it by the cluster average memory
-
 
279
   # then subtracting whatever is already used
-
 
280
   foreach my $node (sort keys %{ $main::statusDB->{'node'} } ) {
-
 
281
      if ( $main::statusDB->{'node'}->{$node}->{'maintenance'} ) {
-
 
282
         $return->{'node'}->{$node}->{'memory_needed'} = -1 * $return->{'node'}->{$node}->{'used_memory'};
-
 
283
      } else {
-
 
284
         $return->{'node'}->{$node}->{'memory_needed'} = int (
-
 
285
            ( $return->{'node'}->{$node}->{'memory'} * $return->{'cluster'}->{'average_memory'} ) -
-
 
286
            $return->{'node'}->{$node}->{'used_memory'} 
-
 
287
            );
-
 
288
      }
-
 
289
   }
-
 
290
   return $return;
-
 
291
}
-
 
292
 
-
 
293
sub humanReadable {
-
 
294
   my ( $value, $preferredUnits ) = @_;
-
 
295
   $value *= 1024;
-
 
296
   my @units =  ( '', 'k', 'M', 'G', 'T' );
-
 
297
   $preferredUnits = $units[-1] unless $preferredUnits;
-
 
298
   my $unit = 0;
-
 
299
   while ( $unit < @units && abs($value) > 1023 && lc $units[$unit] ne lc $preferredUnits ) {
-
 
300
      $unit++;
-
 
301
      $value /= 1024;
-
 
302
   }
-
 
303
   return sprintf( '%d%s', $value+0.5, $units[$unit] );
-
 
304
}
-
 
305
 
-
 
306
 
-
 
307
sub percent {
-
 
308
   my ($value, $accuracy) = @_;
-
 
309
   $accuracy = 0 unless $accuracy;
-
 
310
   return sprintf( '%2.' . $accuracy . 'f%%', $value * 100)
-
 
311
}
-
 
312
 
243
# Creates a balance report to show the user what went on
313
# Creates a balance report to show the user what went on
244
# $cluster is a hash created by sub getClusterStats, and possibly modified by
314
# $cluster is a hash created by sub getClusterStats, and possibly modified by
245
# the calling process
315
# the calling process
246
sub showBalanceReport {
316
sub showBalanceReport {
247
   my $cluster = shift;
317
   my $stats = shift;
248
   my $variance = 0;
318
   #die Dumper( $stats ) . "\n";
249
   my $count = 0;
-
 
250
   my @header = ('Node','Threads','Memory(G)','Domains','vcpu_alloc','mem_alloc(G)', 'vcpu%', 'mem%', 'Status', 'StdDev' );
319
   my @header = ('Node','Threads','Memory','Domains','vcpu_alloc','mem_alloc', 'mem_needed', 'vcpu%', 'mem%', 'Status', 'StdDev' );
251
   my @data;
320
   my @data;
252
   foreach my $node ( sort keys %{ $cluster->{'nodes'} } ) {
321
   foreach my $node ( sort keys %{ $stats->{'node'} } ) {
253
      # get standard deviation
-
 
254
      my $stddev = $cluster->{'nodes'}->{$node}->{'node_maintenance'} ? 0 : 
-
 
255
                   (
-
 
256
                      ( $cluster->{'nodes'}->{$node}->{'domain_memory'} / $cluster->{'nodes'}->{$node}->{'node_memory'} * 100 ) - 
-
 
257
                      ( $cluster->{'domain_memory'} / $cluster->{'total_memory'} * 100 )
-
 
258
                   ) ** 2;
-
 
259
                   
-
 
260
      push @data, [
322
      push @data, [
261
         $node, 
323
         $node, 
262
         $cluster->{'nodes'}->{$node}->{'node_vcpu'},
324
         $stats->{'node'}->{$node}->{'vcpu'},
263
         sprintf( '%d', $cluster->{'nodes'}->{$node}->{'node_memory'}/1024/1024 ),
325
         &humanReadable( $stats->{'node'}->{$node}->{'memory'} ),
264
         $cluster->{'nodes'}->{$node}->{'domain_count'},
326
         $stats->{'node'}->{$node}->{'count'},
265
         $cluster->{'nodes'}->{$node}->{'domain_vcpu'},
327
         $stats->{'node'}->{$node}->{'used_vcpu'},
266
         $cluster->{'nodes'}->{$node}->{'domain_memory'}/1024/1024,
328
         &humanReadable( $stats->{'node'}->{$node}->{'used_memory'} ),
-
 
329
         &humanReadable( $stats->{'node'}->{$node}->{'memory_needed'} ),
267
         sprintf( '%2.0f%%', $cluster->{'nodes'}->{$node}->{'domain_vcpu'} / $cluster->{'nodes'}->{$node}->{'node_vcpu'} * 100 ),
330
         &percent( $stats->{'node'}->{$node}->{'used_vcpu'} / $stats->{'node'}->{$node}->{'vcpu'} ),
268
         sprintf( '%2.0f%%', $cluster->{'nodes'}->{$node}->{'domain_memory'} / $cluster->{'nodes'}->{$node}->{'node_memory'} * 100 ),
331
         &percent( $stats->{'node'}->{$node}->{'used_memory'} / $stats->{'node'}->{$node}->{'memory'} ),
269
         $cluster->{'nodes'}->{$node}->{'node_maintenance'} ? 'Maintenance' : '',
332
         $stats->{'node'}->{$node}->{'maintenance'} ? 'Maintenance' : '',
270
         sprintf( "%d", $stddev )
333
         $stats->{'node'}->{$node}->{'deviation'} < 1000 ? sprintf( "%2.2f", $stats->{'node'}->{$node}->{'deviation'} ) : 'undef'
271
      ];
334
      ];
272
      $variance += $stddev;
-
 
273
      $count++;
-
 
274
   }
335
   }
275
   push @data, [
336
   push @data, [
276
         'All', 
337
         'All', 
277
         $cluster->{'total_vcpu'},
338
         $stats->{'cluster'}->{'vcpu'},
278
         sprintf( '%d', $cluster->{'total_memory'}/1024/1024 ),
339
         &humanReadable( $stats->{'cluster'}->{'memory'} ),
279
         $cluster->{'total_count'},
340
         $stats->{'cluster'}->{'domain_count'},
280
         $cluster->{'domain_vcpu'},
341
         $stats->{'cluster'}->{'used_vcpu'},
281
         $cluster->{'domain_memory'}/1024/1024,
342
         &humanReadable( $stats->{'cluster'}->{'used_memory'} ),
-
 
343
         '',
282
         sprintf( '%2.0f%%', $cluster->{'domain_vcpu'} / $cluster->{'total_vcpu'} * 100 ),
344
         &percent( $stats->{'cluster'}->{'used_vcpu'} / $stats->{'cluster'}->{'vcpu'} ),
283
         sprintf( '%2.0f%%', $cluster->{'domain_memory'} / $cluster->{'total_memory'} * 100 ),
345
         &percent( $stats->{'cluster'}->{'used_memory'} / $stats->{'cluster'}->{'memory'} ),
284
         '',
346
         '',
285
         ''
347
         ''
286
      ];
348
      ];
287
   return &main::report( \@header, \@data ),sprintf( "%d", $variance / $count );
349
   return &main::report( \@header, \@data ) . "Variance " . 
-
 
350
      ( $stats->{'cluster'}->{'variance'} < 100 ? sprintf( "%2.2f", $stats->{'cluster'}->{'variance'} + .005 ) : "undef" ) . "\n\n";
-
 
351
}
-
 
352
 
-
 
353
# simulates performing migrations. Simply moves entries from $from to $to in $main::statusDB->{'nodePopulation'}
-
 
354
sub doActions {
-
 
355
   my $actions = shift;
-
 
356
   my $return;
-
 
357
   for ( my $i = 0; $i < @$actions; $i++ ) {
-
 
358
      my ($domain, $source, $target, $size ) = split( "\t", $actions->[$i] );
-
 
359
      $return .= &main::migrate( $domain, $target, $source );
-
 
360
      delete $main::statusDB->{'nodePopulation'}->{$source}->{'running'}->{$domain};
-
 
361
      $main::statusDB->{'nodePopulation'}->{$target}->{'running'}->{$domain} = time;
-
 
362
   }
-
 
363
   &main::forceScan() unless $main::config->{'flags'}->{'dryrun'} || $main::config->{'flags'}->{'testing'};
-
 
364
   return $return;
288
}
365
}
289
 
366
 
290
# attempt to balance the domains on the active (maintenance = false) nodes
367
# attempt to balance the domains on the active (maintenance = false) nodes
291
# basically, we take what is currently working, and calculate the variance
368
# basically, we take what is currently working, and calculate the variance
292
# of it (see https://en.wikipedia.org/wiki/Standard_deviation). If that is
369
# of it (see https://en.wikipedia.org/wiki/Standard_deviation). If that is
293
# over about a 10, we move things around, if possible, then check our variance
370
# over about a 10, we move things around, if possible, then check our variance
294
# again.
371
# again.
295
sub balance {
372
sub balance {
296
   &main::readDB();
373
   &main::readDB();
-
 
374
   my $return;
297
   # get the current cluster status
375
   # get the current cluster status
298
   my $cluster = &getClusterStats();
376
   my $cluster = &getClusterStats();
299
   # for development, turn on verbose
377
   #die Dumper( $cluster ) . "\n";
300
   $main::config->{'flags'}->{'verbose'} = 1;
-
 
301
   # show user what it looks like at first
378
   # show user what it looks like at first
-
 
379
   print "=== Starting Status ===\n\n" . &showBalanceReport( $cluster) unless $main::config->{'flags'}->{'quiet'};
-
 
380
   # we will do a loop to get the variance within our preferred range ($main::config->{ 'balance variance'})
-
 
381
   # however, we will only do a maximum number of iterations ($main::config->{ 'balance maxiterations'})
-
 
382
   my $iterations = defined $main::config->{ 'balance_max_iterations'} && $main::config->{ 'balance_max_iterations'} ? $main::config->{ 'balance_max_iterations'} : 10;
-
 
383
   $main::config->{ 'balance_max_variance'} = 1.1 unless defined $main::config->{ 'balance_max_variance'};
-
 
384
   # continue until our variance is where we want it, or we have tried too many times.
-
 
385
   while ( $iterations-- && $cluster->{'cluster'}->{'variance'} > $main::config->{ 'balance_max_variance'} ) {
302
   if ( $main::config->{'flags'}->{'verbose'} ) {
386
      my $actions = &moveThings( $cluster );
303
      print "Starting Status\n\n";
387
      $return .= &doActions( $actions );
-
 
388
      
304
      my ($report, $variance) =  &showBalanceReport( $cluster) ;
389
      #print Dumper( $actions ) . "\n"; die;
305
      print $report;
390
      # rerun stats
306
      print "Variance is $variance\n";
391
      $cluster = &getClusterStats();
-
 
392
      print &showBalanceReport( $cluster) if $main::config->{'flags'}->{'verbose'} > 1;
307
   }
393
   }
-
 
394
   print "=== Ending Status ===\n\n" . &showBalanceReport( $cluster) unless $main::config->{'flags'}->{'quiet'};
-
 
395
   return $return;
-
 
396
} # balance
-
 
397
 
-
 
398
# finds node which needs to lose ($from) and gain ($to) the most. Then, goes through $from and finds the largest
-
 
399
# domain which will fit on $to until exhausted.
-
 
400
# as each domain is found, appends to $actions (array pointer). The format of each entry is a tab separated
-
 
401
# list of domain name, node from, node to, domain size
-
 
402
# returns the modified $actions
-
 
403
sub moveThings {
-
 
404
   my $stats = shift;
308
   
405
   
-
 
406
   my $actions = [];
-
 
407
   # find largest and smallest node differences
-
 
408
   my $transfer;
-
 
409
   my $from = '';
-
 
410
   my $to = '';
-
 
411
   # find smallest and largest "memory needed" in group. Note that if a node has too much, the number is negative and
-
 
412
   # for too little (ie, needs additional), the number is positive
-
 
413
   foreach my $node (keys %{$stats->{'node'} } ) {
-
 
414
      #print "Checking $node\n";
-
 
415
      if ( $from ) {
-
 
416
         $from = $node if $stats->{'node'}->{$from}->{'memory_needed'} > $stats->{'node'}->{$node}->{'memory_needed'};
-
 
417
         $to = $node if $stats->{'node'}->{$to}->{'memory_needed'} < $stats->{'node'}->{$node}->{'memory_needed'};
-
 
418
      } else { # just initialize everything to this node
-
 
419
         $from = $to = $node;
-
 
420
      } #if .. else
-
 
421
   } # foreach
-
 
422
   # this is a poor mans min. we want to transfer the least number of bytes, ie what $from can spare, or what $to can accept
-
 
423
   # we need the smallest of what $from can give and $to can accept
-
 
424
   $transfer = abs( abs( $stats->{'node'}->{$from}->{'memory_needed'} ) > abs( $stats->{'node'}->{$to}->{'memory_needed'} ) ?
-
 
425
               $stats->{'node'}->{$to}->{'memory_needed'} : $stats->{'node'}->{$from}->{'memory_needed'} );
-
 
426
   # die "Transfer " . &humanReadable($transfer) ." bytes from $from to $to\n";
-
 
427
   
-
 
428
   # get array of domains running on $from, sorted by the size of the domain (descending, ie largest on top )
-
 
429
   # basically, get all keys from $main::statusDB->{'nodePopulation'}->{$from}->{'running'}, then sort them by looking them
-
 
430
   # up in $main::statusDB->{'virt'} and retrieving the amount of RAM
-
 
431
   my @sortedDomains = sort
309
   die;
432
      {
-
 
433
         $main::statusDB->{'virt'}->{$b}->{'memory'} <=> $main::statusDB->{'virt'}->{$a}->{'memory'}
-
 
434
      } keys %{ $main::statusDB->{'nodePopulation'}->{$from}->{'running'} };
-
 
435
   # now, "move" (fake move) largest domain that will fit into $to, and repeat until we can not do it anymore
310
   #die Dumper( $cluster ) . "\n";
436
   while ( $transfer ) {
311
   return "This function not implemented yet\n";
437
      my $thisDomain = shift @sortedDomains;
-
 
438
      last unless $thisDomain; # we ran out of domains
-
 
439
      next unless $main::statusDB->{'virt'}->{$thisDomain}->{'memory'} <= $transfer;
-
 
440
      push @$actions, join( "\t", ( $thisDomain, $from, $to, $main::statusDB->{'virt'}->{$thisDomain}->{'memory'} ) );
-
 
441
      $transfer -= $main::statusDB->{'virt'}->{$thisDomain}->{'memory'};
-
 
442
   }
-
 
443
      
-
 
444
   return $actions;
312
}
445
}
313
 
-