Rev 35 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
#!/usr/bin/env perl
# All functions related to maniplating/reporting on cluster
# part of havirt.
# Copyright 2024 Daily Data, Inc.
#
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
# conditions are met:
#
# Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
# Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the distribution.
# Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
# NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# v0.0.1 20240602 RWR
# Initial setup
#
# v1.2.0 20240826 RWR
# Added some code to migrate domains if node placed in maintenance mode
# Added a lot of 'verbose' print lines, and modified for new flag structure
#
package cluster;
use warnings;
use strict;
# define the version number
# see https://metacpan.org/pod/release/JPEACOCK/version-0.97/lib/version.pod
use version;
our $VERSION = version->declare("1.2.0");
use Data::Dumper;
use Exporter;
our @ISA = qw( Exporter );
our @EXPORT = qw(
&list
&iscsi
);
sub help {
my @return;
push @return, 'cluster status';
push @return, "\t[--format|-f screen|tsv] - displays some stats on cluster resources used";
push @return, 'cluster iscsi';
push @return, "\tdisplays list of all iSCSI targets 'known' by system";
push @return, 'cluster iscsi add ip-or-dns-name';
push @return, "\tAdds iscsi target to system";
push @return, 'cluster iscsi delete ip-or-dns-name';
push @return, "\tDelete iSCSI target processed by system. ip-or-dns-name MUST be exact";
push @return, 'cluster iscsi update [node ...]';
push @return, "\tPerforms an update to add new iSCSI targets on one or more nodes";
push @return, "\tScans all iSCSI targets, looking for new shares on each, then performs";
push @return, "\ta login, adding it to the node. DOES NOT delete old targets at this";
push @return, "\ttime. If no nodes passed in, will perform function on all nodes not";
push @return, "\tin maintenance mode";
return join( "\n", @return ) . "\n";
}
sub status {
my $return = '';
&main::readDB();
my @header = ('Node','Threads','Memory','Domains','vcpu','mem_used', 'Status' );
my @data;
my $usedmem = 0;
my $usedcpu = 0;
my $availmem = 0;
my $availcpu = 0;
my $totalDomains = 0;
my $maintenance = 0;
foreach my $node (sort keys %{ $main::statusDB->{'node'} } ) {
my $memory = 0;
my $vcpus = 0;
my $count = 0;
foreach my $domain ( keys %{ $main::statusDB->{'nodePopulation'}->{$node}->{'running'} } ) {
$memory += $main::statusDB->{'virt'}->{$domain}->{'memory'};
$vcpus += $main::statusDB->{'virt'}->{$domain}->{'vcpu'};
$count++;
}
push @data, [ $node,$main::statusDB->{'node'}->{$node}->{cpu_count},$main::statusDB->{'node'}->{$node}->{memory},$count,$vcpus,$memory, $main::statusDB->{'node'}->{$node}->{maintenance} ? 'Maintenance' : 'Online' ];
$usedmem += $memory;
$usedcpu += $vcpus;
$totalDomains += $count;
$availmem += $main::statusDB->{'node'}->{$node}->{memory};
$availcpu += $main::statusDB->{'node'}->{$node}->{cpu_count};
$maintenance += $main::statusDB->{'node'}->{$node}->{maintenance} ? 0 : 1;
} # outer for
push @data, [ 'Total',$availcpu,$availmem,$totalDomains,$usedcpu,$usedmem, $maintenance ];
return &main::report( \@header, \@data );
}
# perform various functions on iSCSI target definitions
# on all nodes
sub iscsi {
my $action = shift;
my @return;
if ( $action && $action eq 'add' ) {
&main::readDB(1);
while ( my $target = shift ) {
$main::statusDB->{'cluster'}->{'iscsi'}->{$target} = '';
}
&main::writeDB();
} elsif ( $action && $action eq 'delete' ) {
my $target = shift;
&main::readDB(1);
delete $main::statusDB->{'cluster'}->{'iscsi'}->{$target} if exists $main::statusDB->{'cluster'}->{'iscsi'}->{$target};
&main::writeDB();
} elsif ( $action && $action eq 'update' ) {
&main::readDB();
# if they did not give us a node, do all of them
@_ = keys %{ $main::statusDB->{'node'} } unless @_;
while ( my $node = shift ) { # process each node on stack
if ( $main::statusDB->{'node'}->{$node}->{'maintenance'} ) {
print "Not processing node $node since it is in maintenance mode\n" if $main::config->{'flags'}->{'verbose'};
} else { # actually do the work
push @return, &updateISCITargets( $node );
}
} # while
}
&main::readDB();
push @return, "iSCSI targets are";
if ( $main::statusDB->{'cluster'}->{'iscsi'} ) {
push @return, join( "\n", keys %{ $main::statusDB->{'cluster'}->{'iscsi'} } );
} else {
push @return, "None Defined";
}
return join( "\n", @return ) . "\n";
}
# updates iSCSI targets on $node
# scans each target defined and compares it to the current session
# adding new targets if they exist
# NOTE: does not delete targets which no longer exist on server
sub updateISCITargets {
my $node = shift;
my $command;
my %targets;
my @return;
push @return, "Processing iSCSI targets on $node";
print Dumper( keys %{ $main::statusDB->{'cluster'}->{'iscsi'} } ) if $main::config->{'flags'}->{'debug'};
foreach my $server (keys %{ $main::statusDB->{'cluster'}->{'iscsi'} } ) {
print "\n" . '-'x40 . "\nGetting targets on server $server\n" . '-'x40 . "\n" if $main::config->{'flags'}->{'verbose'};
$command = &main::makeCommand( $node, "iscsiadm -m discovery -t st -p $server" );
my @list = `$command`;
chomp @list;
# @list contains lines of type
# 10.19.209.2:3260,1 iqn.2014-11.net.dailydata.castor:simon0
# split them apart and add them to the hash
foreach my $entry ( @list ) {
my ( $portal, $targetName ) = split( ' ', $entry );
# $portal has some extra info after a comma, so clean it up
$portal =~ m/^([0-9:.]+)/;
$portal = $1;
# some targets return multiple IP's for a given name, so
# only add them if they are in this IP
$targets{ $targetName } = $portal if $portal =~ m/^$server/;
print "$targetName\t$targets{ $targetName }\n" if $main::config->{'flags'}->{'verbose'};
} # foreach
} # while
print "\n" . '-'x40 . "\nGetting active sessions\n". '-'x40 . "\n" if $main::config->{'flags'}->{'verbose'};
# now, get active sessions so we can filter them
$command = &main::makeCommand( $node, "iscsiadm -m session" );
my @activeSessions = `$command`;;
chomp @activeSessions;
foreach my $session ( @activeSessions ) {
$session =~ m/^.*[^0-9:.]([0-9,:.]+).*(iqn\S*)/;
my ( $portal,$targetName ) = ( $1,$2 );
print "$portal\t$targetName" if $main::config->{'flags'}->{'verbose'};
if ( exists( $targets{$targetName} ) ) {
print "\tNOT updating\n" if $main::config->{'flags'}->{'verbose'};
delete $targets{ $targetName };
} else {
print "Needs to be added\n" if $main::config->{'flags'}->{'verbose'};
}
}
# check if we have any new entries and bail if not
if ( scalar keys %targets ) {
# We have new entries, so run them;
foreach my $targetName ( sort keys %targets ) {
my $portal = $targets{$targetName};
push @return, "Adding $targetName";
$command = &main::makeCommand( $node, "iscsiadm -m node --targetname '$targetName' --portal '$portal' --login" );
if ( $main::config->{'flags'}->{'dryrun'} ) {
push @return, $command;
} else {
`$command`;
}
}
} else {
push @return, "No new entries";
}
return join( "\n", @return ) . "\n";
} # updateISCITargets
Generated by GNU Enscript 1.6.5.90.