Subversion Repositories havirt

Rev

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

Rev 25 Rev 26
Line 21... Line 21...
21
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
21
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
22
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
 
23
 
24
# v0.0.1 20240602 RWR
24
# v0.0.1 20240602 RWR
25
# Initial setup
25
# Initial setup
-
 
26
#
-
 
27
# v1.2.0 20240826 RWR
-
 
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
-
 
30
#
-
 
31
 
26
 
32
 
27
package domain;
33
package domain;
28
 
34
 
29
use warnings;
35
use warnings;
30
use strict;  
36
use strict;  
31
 
37
 
32
# define the version number
38
# define the version number
33
# see https://metacpan.org/pod/release/JPEACOCK/version-0.97/lib/version.pod
39
# see https://metacpan.org/pod/release/JPEACOCK/version-0.97/lib/version.pod
34
use version;
40
use version;
35
our $VERSION = version->declare("1.0.0");
41
our $VERSION = version->declare("1.2.0");
36
 
42
 
37
 
43
 
38
use Data::Dumper;
44
use Data::Dumper;
39
 
45
 
40
use Exporter;
46
use Exporter;
Line 67... Line 73...
67
   push @return, "\tIf maintenance flag is set, no havirt will refuse any actions";
73
   push @return, "\tIf maintenance flag is set, no havirt will refuse any actions";
68
   return join( "\n", @return ) . "\n";
74
   return join( "\n", @return ) . "\n";
69
}
75
}
70
 
76
 
71
 
77
 
-
 
78
# dipslay a list of domains, which node they are on and some information on them
72
sub list {
79
sub list {
73
   &main::readDB();
80
   &main::readDB();
74
   print Dumper( $main::statusDB->{'nodePopulation'} ) if $main::config->{'flags'}->{'debug'} > 2;
81
   print Dumper( $main::statusDB->{'nodePopulation'} ) if $main::config->{'flags'}->{'debug'} > 2;
75
 
82
 
76
   my @header;
83
   my @header;
Line 118... Line 125...
118
   &main::readDB(1); # loading it for write, so lock
125
   &main::readDB(1); # loading it for write, so lock
119
   unless ( @_ ) {
126
   unless ( @_ ) {
120
      # they didn't pass in anything, so do everything
127
      # they didn't pass in anything, so do everything
121
      @_ = keys %{ $main::statusDB->{'virt'} }
128
      @_ = keys %{ $main::statusDB->{'virt'} }
122
   } # unless
129
   } # unless
123
   print "Preparing to update " . join( "\n", @_ ) . "\n" if $main::config->{'flags'}->{'debug'} > 1;
130
   print "Preparing to update " . join( "\n", @_ ) . "\n" 
-
 
131
      if $main::config->{'flags'}->{'debug'} > 1 or $main::config->{'flags'}->{'verbose'};
124
   while ( my $virt = shift ) {
132
   while ( my $virt = shift ) { # for every domain they passed in
125
      &parseDomain( $virt );
133
      &parseDomain( $virt ); # parse it and update definition
126
      foreach my $field ( @requiredFields ) {
134
      foreach my $field ( @requiredFields ) { # make sure the required fields are in there
127
         $main::statusDB->{'virt'}->{$virt}->{$field} = '' 
135
         $main::statusDB->{'virt'}->{$virt}->{$field} = '' 
128
            unless defined ( $main::statusDB->{'virt'}->{$virt}->{$field} );
136
            unless defined ( $main::statusDB->{'virt'}->{$virt}->{$field} );
129
      } # foreach
137
      } # foreach
130
   } # while
138
   } # while
131
   &main::writeDB( $main::domainDBName, $main::statusDB->{'virt'} );
139
   &main::writeDB( $main::domainDBName, $main::statusDB->{'virt'} );
132
   return "Updated\n";
140
   return "Domain(s) updated\n";
133
}
141
}
134
 
142
 
135
 
143
 
136
# finds one xml value in file.
144
# finds one xml value in file.
137
# since libvirt does not use good xml which can be parsed by
145
# since libvirt does not use good xml which can be parsed by
Line 151... Line 159...
151
# exist, or if force is set, do a dumpxml on the running
159
# exist, or if force is set, do a dumpxml on the running
152
# domain, put it into conf/ and load it.
160
# domain, put it into conf/ and load it.
153
sub parseDomain {
161
sub parseDomain {
154
   my ($virt, $nodePopulations ) = @_;
162
   my ($virt, $nodePopulations ) = @_;
155
   print "Parsing domain $virt in domain.pm:parseDomain\n" if $main::config->{'flags'}->{'debug'};
163
   print "Parsing domain $virt in domain.pm:parseDomain\n" if $main::config->{'flags'}->{'debug'};
-
 
164
   print "\tParsing domain $virt\n" if $main::config->{'flags'}->{'verbose'};
-
 
165
 
156
   my @keysToSave = ( 'uuid', 'memory', 'vcpu','vnc' );
166
   my @keysToSave = ( 'uuid', 'memory', 'vcpu','vnc' );
157
   my $filename = "$main::config->{'conf dir'}/$virt.xml";
167
   my $filename = "$main::config->{'conf dir'}/$virt.xml";
158
   my $xml = &getVirtConfig( $virt, $filename );
168
   my $xml = &getVirtConfig( $virt, $filename );
159
   my ($param,$value) = &getXMLValue( 'uuid', $xml );
169
   my ($param,$value) = &getXMLValue( 'uuid', $xml );
160
   $main::statusDB->{'virt'}->{$virt}->{'uuid'} = $value;
170
   $main::statusDB->{'virt'}->{$virt}->{'uuid'} = $value;
Line 175... Line 185...
175
# return it.
185
# return it.
176
sub getVirtConfig {
186
sub getVirtConfig {
177
   my ($virt,$filename) = @_;
187
   my ($virt,$filename) = @_;
178
   my $return;
188
   my $return;
179
   print "In getVirtConfig looking for $virt with file $filename, force is $main::config->{'flags'}->{'yes'}\n" if $main::config->{'flags'}->{'debug'};
189
   print "In getVirtConfig looking for $virt with file $filename, force is $main::config->{'flags'}->{'yes'}\n" if $main::config->{'flags'}->{'debug'};
180
   if ( -f $filename && ! $main::config->{'flags'}->{'yes'}) {
190
   if ( -f $filename && ! $main::config->{'flags'}->{'force'}) {
181
      open XML, "<$filename" or die "Could not read from $filename: $!\n";
191
      open XML, "<$filename" or die "Could not read from $filename: $!\n";
182
      $return = join( '', <XML> );
192
      $return = join( '', <XML> );
183
      close XML;
193
      close XML;
184
   } else {
194
   } else {
185
      &main::readDB();
195
      &main::readDB();
186
      foreach my $node ( keys %{$main::statusDB->{'nodePopulation'}} ) {
196
      foreach my $node ( keys %{$main::statusDB->{'nodePopulation'}} ) {
187
         print "getVirtConfig Looking on $node for $virt\n" if $main::config->{'flags'}->{'debug'} > 1;;
197
         print "getVirtConfig Looking on $node for $virt\n" if $main::config->{'flags'}->{'debug'} > 1;;
188
         if ( exists( $main::statusDB->{'nodePopulation'}->{$node}->{'running'}->{$virt} ) ) { # we found it
198
         if ( exists( $main::statusDB->{'nodePopulation'}->{$node}->{'running'}->{$virt} ) ) { # we found it
-
 
199
            print "Getting copy of XML file for $virt from $node\n" if $main::config->{'flags'}->{'verbose'};
189
            print "Found $virt on node $node\n" if $main::config->{'flags'}->{'debug'};;
200
            print "Found $virt on node $node\n" if $main::config->{'flags'}->{'debug'};;
190
            my $command = &main::makeCommand($node, "virsh dumpxml $virt");
201
            my $command = &main::makeCommand($node, "virsh dumpxml $virt");
191
            $return = `$command`;
202
            $return = `$command`;
192
            print "Writing config for $virt from $node into $filename\n" if $main::config->{'flags'}->{'debug'};
203
            print "Writing config for $virt from $node into $filename\n" if $main::config->{'flags'}->{'debug'};
193
            open XML,">$filename" or die "Could not write to $filename: $!\n";
204
            open XML,">$filename" or die "Could not write to $filename: $!\n";
Line 197... Line 208...
197
      } # foreach
208
      } # foreach
198
   } # if..else
209
   } # if..else
199
   return $return;
210
   return $return;
200
} # sub getVirtConfig
211
} # sub getVirtConfig
201
 
212
 
-
 
213
 
202
# start a domain
214
# start a domain
203
sub start {
215
sub start {
204
   my ( $virt, $node ) = @_;
216
   my ( $virt, $node ) = @_;
205
   my $return;
217
   my $return;
206
   $node = `hostname` unless $node;
218
   $node = `hostname` unless $node;
207
   chomp $node;
219
   chomp $node;
208
   return "Domain $virt in maintenance mode, can not start\n" if $main::statusDB->{'virt'}->{$virt}->{'maintenance'};
220
   return "Domain $virt in maintenance mode, can not start\n" if $main::statusDB->{'virt'}->{$virt}->{'maintenance'};
209
   return "Node $node in maintenance mode, can not start\n" if $main::statusDB->{'node'}->{$node}->{'maintenance'};
221
   return "Node $node in maintenance mode, can not start\n" if $main::statusDB->{'node'}->{$node}->{'maintenance'};
210
   # these are replaced by the safer findDomain
-
 
211
   #&main::forceScan();
-
 
212
   #&main::readDB();
-
 
213
   if ( my $foundNode = &main::findDomain( $virt ) ) {
222
   if ( my $foundNode = &main::findDomain( $virt ) ) {
214
      die "$virt already running on $foundNode, not starting\n";
223
      die "$virt already running on $foundNode, not starting\n";
215
   }
224
   }
216
   die "I do not have a definition for $virt\n" unless exists( $main::statusDB->{'virt'}->{$virt} );
225
   die "I do not have a definition for $virt\n" unless exists( $main::statusDB->{'virt'}->{$virt} );
217
   print Dumper( $main::statusDB->{'nodePopulation'} ) if $main::config->{'flags'}->{'debug'} > 2;
226
   print Dumper( $main::statusDB->{'nodePopulation'} ) if $main::config->{'flags'}->{'debug'} > 2;
218
   if ( my $error = &main::validateResources( $node, $virt ) ) {
227
   if ( my $error = &main::validateResources( $node, $virt ) ) {
219
      die $error;
228
      die $error;
220
   }
229
   }
221
   my $filename = "$main::config->{'conf dir'}/$virt.xml";
230
   my $filename = "$main::config->{'conf dir'}/$virt.xml";
222
   my $command = &main::makeCommand( $node, "virsh create $filename" );
231
   my $command = &main::makeCommand( $node, "virsh create $filename" );
-
 
232
   print "Starting $virt on $node\n" if $main::config->{'flags'}->{'verbose'};
223
   if ( $main::config->{'flags'}->{'yes'} ) { # we'll actually do it
233
   if ( $main::config->{'flags'}->{'dryrun'} ) { # we'll actually do it
-
 
234
      $return =  $command;;
-
 
235
   } else {
224
      $return = ( &main::executeAndWait( $command, $node, $virt, 1 ) ? 'Success' : 'Can not start');
236
      $return = ( &main::executeAndWait( $command, $node, $virt, 1 ) ? 'Success' : 'Can not start');
225
      &main::forceScan();
237
      &main::forceScan();
226
   } else {
-
 
227
      $return =  $command;;
-
 
228
   }
238
   }
229
   return "$return\n";
239
   return "$return\n";
230
}
240
}
231
 
241
 
232
sub shutdown {
242
sub shutdown {
233
   my $virt = shift;
243
   my $virt = shift;
234
   my $node = '';
244
   my $node = '';
235
   my $return;
245
   my $return;
236
   # these are replaced by the safer findDomain
-
 
237
   #&main::forceScan();
-
 
238
   #&main::readDB();
-
 
239
   $node = &main::findDomain( $virt );
246
   $node = &main::findDomain( $virt );
240
   die "I could not find the domain $virt running\n" unless $node;
247
   die "I could not find the domain $virt running\n" unless $node;
241
   print Dumper( $main::statusDB->{'nodePopulation'} ) if $main::config->{'flags'}->{'debug'} > 2;
248
   print Dumper( $main::statusDB->{'nodePopulation'} ) if $main::config->{'flags'}->{'debug'} > 2;
242
   die "I can not find $virt on any node\n" unless $node;
249
   die "I can not find $virt on any node\n" unless $node;
243
   my $command = &main::makeCommand( $node, "virsh shutdown $virt" );
250
   my $command = &main::makeCommand( $node, "virsh shutdown $virt" );
-
 
251
   print "Attempting to shut down $virt currently on $node\n" if $main::config->{'flags'}->{'verbose'};
244
   if ( $main::config->{'flags'}->{'yes'} ) { # they want us to actually do it
252
   if ( $main::config->{'flags'}->{'dryrun'} ) { # they want us to actually do it
-
 
253
      $return = $command;
-
 
254
   } else {
245
      $return = ( &main::executeAndWait( $command, $node, $virt, 0 ) ? 'Success' : 'Time Out waiting for shutdown');
255
      $return = ( &main::executeAndWait( $command, $node, $virt, 0 ) ? 'Success' : 'Time Out waiting for shutdown');
246
      &main::forceScan();
256
      &main::forceScan();
247
   } else {
-
 
248
      $return = $command;
-
 
249
   }
257
   }
250
   return "$return\n";
258
   return "$return\n";
251
}
259
}
252
 
260
 
-
 
261
# Migrate a single domain
-
 
262
# this is defined in havirt.pm, which is set up to migrate multiple domains
-
 
263
# but has an entry point here for just one
-
 
264
# domain is domain to migrate, target is where to put it
253
sub migrate {
265
sub migrate {
254
   my ( $domain, $target ) = @_;
266
   my ( $domain, $target ) = @_;
255
   if ( my $error = &main::validateResources( $target, $domain ) ) {
267
   if ( my $error = &main::validateResources( $target, $domain ) ) {
256
      die $error;
268
      die $error;
257
   }
269
   }
Line 266... Line 278...
266
      $return++;
278
      $return++;
267
   }
279
   }
268
   return $return;
280
   return $return;
269
}
281
}
270
 
282
 
271
 
-
 
-
 
283
# print MAC address in the correct format
-
 
284
# two character hex digits separated by colons, lower case
272
sub printMac {
285
sub printMac {
273
   my $mac = shift;
286
   my $mac = shift;
274
   my @return;
287
   my @return;
275
   my $separator = ':';
288
   my $separator = ':';
276
   for ( my $i = 0; $i < length( $mac ); $i += 2 ) {
289
   for ( my $i = 0; $i < length( $mac ); $i += 2 ) {
277
      push @return, substr( $mac, $i, 2 );
290
      push @return, substr( $mac, $i, 2 );
278
   }
291
   }
279
   return join( $separator, @return );
292
   return join( $separator, @return );
280
}
293
}
281
      
294
      
282
      
295
 
-
 
296
# generate a random MAC address for new function.
-
 
297
# NOTE: this is not checked for duplication at this time
283
sub makeMac {
298
sub makeMac {
284
   my $numDigits = 12; # 12 hex digits in a mac address
299
   my $numDigits = 12; # 12 hex digits in a mac address
285
   my $macBaseXen = '00163e'; # Xen has 00:16:3E* assigned to it.
300
   my $macBaseXen = '00163e'; # Xen has 00:16:3E* assigned to it.
286
   my $hexDigits = '0123456789abcdef';
301
   my $hexDigits = '0123456789abcdef';
287
 
302
 
Line 323... Line 338...
323
      }
338
      }
324
   }
339
   }
325
   return $return;
340
   return $return;
326
}
341
}
327
 
342
 
-
 
343
 
-
 
344
# put domain in maintenance mode
-
 
345
# in maintenance mode, it can not be started, stopped or migrated by havirt
328
sub maintenance {
346
sub maintenance {
329
   my ( $domain, $action ) = @_;
347
   my ( $domain, $action ) = @_;
330
   &main::readDB(1);
348
   &main::readDB(1);
331
   if ( $action ) {
349
   if ( $action ) {
332
      $main::statusDB->{'virt'}->{$domain}->{'maintenance'} = ( lc( $action ) eq 'on' ) ? 1 : 0;
350
      $main::statusDB->{'virt'}->{$domain}->{'maintenance'} = ( lc( $action ) eq 'on' ) ? 1 : 0;