diff --git a/Anvil/Tools/DRBD.pm b/Anvil/Tools/DRBD.pm index 806dd2b8..89c683c6 100755 --- a/Anvil/Tools/DRBD.pm +++ b/Anvil/Tools/DRBD.pm @@ -78,7 +78,6 @@ sub parent This finds all of the configured '/dev/drbdX' devices and maps them to their resource names. - Parameters; =head3 password (optional) @@ -116,13 +115,8 @@ sub get_devices target => $target, }}); - # Clear the hash where we'll store the data. - if (exists $anvil->data->{drbd}{'dump-xml'}) - { - delete $anvil->data->{drbd}{'dump-xml'}; - } - # Is this a local call or a remote call? + my $host = $anvil->_short_hostname; my $shell_call = $anvil->data->{path}{exe}{drbdadm}." dump-xml"; my $output = ""; if (($target) && ($target ne "local") && ($target ne $anvil->_hostname) && ($target ne $anvil->_short_hostname)) @@ -136,7 +130,9 @@ sub get_devices password => $password, remote_user => $remote_user, }); + $host = $target; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + host => $host, error => $error, output => $output, "drbd::drbdadm-xml::return_code" => $anvil->data->{drbd}{'drbdadm-xml'}{return_code}, @@ -152,6 +148,12 @@ sub get_devices }}); } + # Clear the hash where we'll store the data. + if (exists $anvil->data->{drbd}{config}{$host}) + { + delete $anvil->data->{drbd}{config}{$host}; + } + my $xml = XML::Simple->new(); my $dump_xml = ""; eval { $dump_xml = $xml->XMLin($output, KeyAttr => {}, ForceArray => 1) }; @@ -167,9 +169,10 @@ sub get_devices } #print Dumper $dump_xml; - $anvil->data->{drbd}{config}{'auto-promote'} = 0; - $anvil->data->{drbd}{host}{'local'} = ""; - $anvil->data->{drbd}{host}{peer} = ""; + $anvil->data->{drbd}{config}{$host}{'auto-promote'} = 0; + $anvil->data->{drbd}{config}{$host}{host} = ""; + $anvil->data->{drbd}{config}{$host}{peer} = ""; + $anvil->data->{drbd}{config}{$host}{nodes} = {}; foreach my $hash_ref (@{$dump_xml->{resource}}) { @@ -178,20 +181,20 @@ sub get_devices { foreach my $host_href (@{$connection_href->{host}}) { - my $host = $host_href->{name}; - my $port = $host_href->{address}->[0]->{port}; - my $ip_address = $host_href->{address}->[0]->{content}; - $anvil->data->{drbd}{config}{$this_resource}{connection}{$host}{ip_family} = $host_href->{address}->[0]->{family}; - $anvil->data->{drbd}{config}{$this_resource}{connection}{$host}{ip_address} = $host_href->{address}->[0]->{content}; - $anvil->data->{drbd}{config}{$this_resource}{connection}{$host}{port} = $port; - $anvil->data->{drbd}{ip_addresses}{$ip_address} = 1; - $anvil->data->{drbd}{tcp_ports}{$port} = 1; + my $this_host = $host_href->{name}; + my $port = $host_href->{address}->[0]->{port}; + my $ip_address = $host_href->{address}->[0]->{content}; + $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{connection}{$this_host}{ip_family} = $host_href->{address}->[0]->{family}; + $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{connection}{$this_host}{ip_address} = $host_href->{address}->[0]->{content}; + $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{connection}{$this_host}{port} = $port; + $anvil->data->{drbd}{config}{$host}{ip_addresses}{$ip_address} = $this_host; + $anvil->data->{drbd}{config}{$host}{tcp_ports}{$port} = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "drbd::config::${this_resource}::connection::${host}::ip_family" => $anvil->data->{drbd}{config}{$this_resource}{connection}{$host}{ip_family}, - "drbd::config::${this_resource}::connection::${host}::ip_address" => $anvil->data->{drbd}{config}{$this_resource}{connection}{$host}{ip_address}, - "drbd::config::${this_resource}::connection::${host}::port" => $anvil->data->{drbd}{config}{$this_resource}{connection}{$host}{port}, - "drbd::ip_addresses::${ip_address}" => $anvil->data->{drbd}{ip_addresses}{$ip_address}, - "drbd::tcp_ports::${port}" => $anvil->data->{drbd}{tcp_ports}{$port}, + "drbd::config::${host}::resource::${this_resource}::connection::${this_host}::ip_family" => $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{connection}{$this_host}{ip_family}, + "drbd::config::${host}::resource::${this_resource}::connection::${this_host}::ip_address" => $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{connection}{$this_host}{ip_address}, + "drbd::config::${host}::resource::${this_resource}::connection::${this_host}::port" => $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{connection}{$this_host}{port}, + "drbd::config::${host}::ip_addresses::${ip_address}" => $anvil->data->{drbd}{config}{$host}{ip_addresses}{$ip_address}, + "drbd::config::${host}::tcp_ports::${port}" => $anvil->data->{drbd}{config}{$host}{tcp_ports}{$port}, }}); } foreach my $section_href (@{$connection_href->{section}}) @@ -200,9 +203,9 @@ sub get_devices foreach my $option_href (@{$section_href->{option}}) { my $variable = $option_href->{name}; - $anvil->data->{drbd}{config}{$this_resource}{section}{$section}{$variable} = $option_href->{value}; + $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{section}{$section}{$variable} = $option_href->{value}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "drbd::config::${this_resource}::section::${section}::${variable}" => $anvil->data->{drbd}{config}{$this_resource}{section}{$section}{$variable}, + "drbd::config::${host}::resource::${this_resource}::section::${section}::${variable}" => $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{section}{$section}{$variable}, }}); } } @@ -211,37 +214,41 @@ sub get_devices foreach my $host_href (@{$hash_ref->{host}}) { ### TODO: Handle external metadata - my $host = $host_href->{name}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host => $host }}); - if (($host eq $anvil->_hostname) or ($host eq $anvil->_short_hostname)) + my $this_host = $host_href->{name}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + this_host => $this_host, + '$anvil->_hostname' => $anvil->_hostname, + '$anvil->_short_hostname' => $anvil->_short_hostname, + }}); + if (($this_host eq $anvil->_hostname) or ($this_host eq $anvil->_short_hostname)) { - $anvil->data->{drbd}{host}{'local'} = $host; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'drbd::host::local' => $anvil->data->{drbd}{host}{'local'} }}); + $anvil->data->{drbd}{config}{$host}{host} = $this_host; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "drbd::config::${host}::host" => $anvil->data->{drbd}{config}{$host}{host} }}); } foreach my $volume_href (@{$host_href->{volume}}) { - my $volume = $volume_href->{vnr}; - my $drbd_path = $volume_href->{device}->[0]->{content}; - my $lv_path = $volume_href->{disk}->[0]; - $anvil->data->{drbd}{config}{$this_resource}{volume}{$volume}{drbd_path} = $drbd_path; - $anvil->data->{drbd}{config}{$this_resource}{volume}{$volume}{drbd_minor} = $volume_href->{device}->[0]->{minor}; - $anvil->data->{drbd}{config}{$this_resource}{volume}{$volume}{'meta-disk'} = $volume_href->{'meta-disk'}->[0]; - $anvil->data->{drbd}{config}{$this_resource}{volume}{$volume}{backing_lv} = $lv_path; + my $volume = $volume_href->{vnr}; + my $drbd_path = $volume_href->{device}->[0]->{content}; + my $lv_path = $volume_href->{disk}->[0]; + $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{volume}{$volume}{drbd_path} = $drbd_path; + $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{volume}{$volume}{drbd_minor} = $volume_href->{device}->[0]->{minor}; + $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{volume}{$volume}{'meta-disk'} = $volume_href->{'meta-disk'}->[0]; + $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{volume}{$volume}{backing_lv} = $lv_path; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "drbd::config::${this_resource}::volume::${volume}::drbd_path" => $anvil->data->{drbd}{config}{$this_resource}{volume}{$volume}{drbd_path}, - "drbd::config::${this_resource}::volume::${volume}::drbd_minor" => $anvil->data->{drbd}{config}{$this_resource}{volume}{$volume}{drbd_minor}, - "drbd::config::${this_resource}::volume::${volume}::meta-disk" => $anvil->data->{drbd}{config}{$this_resource}{volume}{$volume}{'meta-disk'}, - "drbd::config::${this_resource}::volume::${volume}::backing_lv" => $anvil->data->{drbd}{config}{$this_resource}{volume}{$volume}{backing_lv}, + "drbd::config::${host}::resource::${this_resource}::volume::${volume}::drbd_path" => $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{volume}{$volume}{drbd_path}, + "drbd::config::${host}::resource::${this_resource}::volume::${volume}::drbd_minor" => $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{volume}{$volume}{drbd_minor}, + "drbd::config::${host}::resource::${this_resource}::volume::${volume}::meta-disk" => $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{volume}{$volume}{'meta-disk'}, + "drbd::config::${host}::resource::${this_resource}::volume::${volume}::backing_lv" => $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{volume}{$volume}{backing_lv}, }}); - if (($anvil->data->{drbd}{host}{'local'}) && ($anvil->data->{drbd}{host}{'local'} eq $host)) + if (($anvil->data->{drbd}{config}{$host}{host}) && ($anvil->data->{drbd}{config}{$host}{host} eq $this_host)) { - $anvil->data->{drbd}{'local'}{drbd_path}{$drbd_path}{on} = $lv_path; - $anvil->data->{drbd}{'local'}{drbd_path}{$drbd_path}{resource} = $this_resource; - $anvil->data->{drbd}{'local'}{lv_path}{$lv_path}{under} = $drbd_path; + $anvil->data->{drbd}{config}{$host}{drbd_path}{$drbd_path}{on} = $lv_path; + $anvil->data->{drbd}{config}{$host}{drbd_path}{$drbd_path}{resource} = $this_resource; + $anvil->data->{drbd}{config}{$host}{lv_path}{$lv_path}{under} = $drbd_path; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "drbd::local::drbd_path::${drbd_path}::on" => $anvil->data->{drbd}{'local'}{drbd_path}{$drbd_path}{on}, - "drbd::local::drbd_path::${drbd_path}::resource" => $anvil->data->{drbd}{'local'}{drbd_path}{$drbd_path}{resource}, - "drbd::local::lv_path::${lv_path}::under" => $anvil->data->{drbd}{'local'}{lv_path}{$lv_path}{under}, + "drbd::config::${host}::drbd_path::${drbd_path}::on" => $anvil->data->{drbd}{config}{$host}{drbd_path}{$drbd_path}{on}, + "drbd::config::${host}::drbd_path::${drbd_path}::resource" => $anvil->data->{drbd}{config}{$host}{drbd_path}{$drbd_path}{resource}, + "drbd::config::${host}::lv_path::${lv_path}::under" => $anvil->data->{drbd}{config}{$host}{lv_path}{$lv_path}{under}, }}); } } @@ -252,7 +259,7 @@ sub get_devices ### fencing, and ignore the others. The one with real fencing, we figure out which is ### us (if any) and the other has to be the peer. # Find my peer, if I am myself a node. - if (($anvil->data->{drbd}{host}{'local'}) && (not $anvil->data->{drbd}{host}{peer})) + if (($anvil->data->{drbd}{config}{$host}{host}) && (not $anvil->data->{drbd}{config}{$host}{peer})) { #print Dumper $hash_ref->{connection}; foreach my $hash_ref (@{$hash_ref->{connection}}) @@ -287,14 +294,14 @@ sub get_devices foreach my $host_ref (@{$hash_ref->{host}}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - 'drbd::host::local' => $anvil->data->{drbd}{host}{'local'}, - 'host_ref->name' => $host_ref->{name}, + "drbd::config::${host}::host" => $anvil->data->{drbd}{config}{$host}{host}, + "host_ref->name" => $host_ref->{name}, }}); - next if $host_ref->{name} eq $anvil->data->{drbd}{host}{'local'}; + next if $host_ref->{name} eq $anvil->data->{drbd}{config}{$host}{host}; # Found the peer. - $anvil->data->{drbd}{host}{peer} = $host_ref->{name}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'drbd::host::peer' => $anvil->data->{drbd}{host}{peer} }}); + $anvil->data->{drbd}{config}{$host}{peer} = $host_ref->{name}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "drbd::config::${host}::peer" => $anvil->data->{drbd}{config}{$host}{peer} }}); } } } diff --git a/Anvil/Tools/Server.pm b/Anvil/Tools/Server.pm index 3e51ce41..a37fd8ae 100755 --- a/Anvil/Tools/Server.pm +++ b/Anvil/Tools/Server.pm @@ -75,13 +75,107 @@ sub parent =head2 find -This looks on an Anvil! for what servers are running where. +This will look on the local or a remote machine for the list of servers that are running. +The list is stored as; + server::location::::status = + server::location::::host = + +Parameters; + +=head3 password (optional) + +This is the password to use when connecting to a remote machine. If not set, but C<< target >> is, an attempt to connect without a password will be made. + +=head3 port (optional) + +This is the TCP port to use when connecting to a remote machine. If not set, but C<< target >> is, C<< 22 >> will be used. + +=head3 remote_user (optional, default 'root') + +If C<< target >> is set, this will be the user we connect to the remote machine as. + +=head3 target (optional) + +This is the IP or host name of the machine to read the version of. If this is not set, the local system's version is checked. =cut sub find { + my $self = shift; + my $parameter = shift; + my $anvil = $self->parent; + my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; + + my $password = defined $parameter->{password} ? $parameter->{password} : ""; + my $port = defined $parameter->{port} ? $parameter->{port} : ""; + my $remote_user = defined $parameter->{remote_user} ? $parameter->{remote_user} : "root"; + my $target = defined $parameter->{target} ? $parameter->{target} : "local"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + password => $anvil->Log->secure ? $password : $anvil->Words->string({key => "log_0186"}), + port => $port, + remote_user => $remote_user, + target => $target, + }}); + + my $host_type = $anvil->System->get_host_type({debug => $debug}); + my $host = $anvil->_hostname; + my $virsh_output = ""; + my $return_code = ""; + if (($target) && ($target ne "local") && ($target ne $anvil->_hostname) && ($target ne $anvil->_short_hostname)) + { + # Remote call. + ($host, my $error, my $host_return_code) = $anvil->Remote->call({ + debug => 2, + shell_call => $anvil->data->{path}{exe}{hostnamectl}." --static", + target => $target, + remote_user => "root", + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + host => $host, + error => $error, + host_return_code => $host_return_code, + }}); + ($virsh_output, $error, $return_code) = $anvil->Remote->call({ + debug => 2, + shell_call => $anvil->data->{path}{exe}{virsh}." list --all", + target => $target, + remote_user => "root", + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + virsh_output => $virsh_output, + error => $error, + return_code => $return_code, + }}); + } + else + { + ($virsh_output, my $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{virsh}." list --all"}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + virsh_output => $virsh_output, + return_code => $return_code, + }}); + } + + foreach my $line (split/\n/, $virsh_output) + { + $line = $anvil->Words->clean_spaces({string => $line}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }}); + + if ($line =~ /^\d+ (.*) (.*?)$/) + { + my $server_name = $1; + $anvil->data->{server}{location}{$server_name}{status} = $2; + $anvil->data->{server}{location}{$server_name}{host} = $host; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "server::location::${server_name}::status" => $anvil->data->{server}{location}{$server_name}{status}, + "server::location::${server_name}::host" => $anvil->data->{server}{location}{$server_name}{host}, + }}); + } + } + + return(0); } =head2 get_status @@ -146,7 +240,13 @@ sub get_status $anvil->data->{server}{$server}{from_memory}{host} = ""; # We're going to map DRBD devices to resources, so we need to collect that data now. - $anvil->DRBD->get_devices({debug => $debug}); + $anvil->DRBD->get_devices({ + debug => $debug, + password => $password, + port => $port, + remote_user => $remote_user, + target => $target, + }); # Is this a local call or a remote call? my $shell_call = $anvil->data->{path}{exe}{virsh}." dumpxml ".$server; @@ -189,6 +289,7 @@ sub get_status $anvil->data->{server}{$server}{from_memory}{host} = $host; $anvil->Server->_parse_definition({ debug => $debug, + host => $host, server => $server, source => "from_memory", definition => $anvil->data->{server}{$server}{from_memory}{xml}, @@ -206,7 +307,7 @@ sub get_status file => $anvil->data->{path}{directories}{shared}{definitions}."/".$server.".xml", }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "server::${server}::disk::xml" => $anvil->data->{server}{$server}{disk}{xml}, + "server::${server}::from_disk::xml" => $anvil->data->{server}{$server}{from_disk}{xml}, }}); if (($anvil->data->{server}{$server}{from_disk}{xml} eq "!!errer!!") or (not $anvil->data->{server}{$server}{from_disk}{xml})) { @@ -217,6 +318,7 @@ sub get_status { $anvil->Server->_parse_definition({ debug => $debug, + host => $host, server => $server, source => "from_disk", definition => $anvil->data->{server}{$server}{from_disk}{xml}, @@ -249,9 +351,12 @@ sub _parse_definition my $server = defined $parameter->{server} ? $parameter->{server} : ""; my $source = defined $parameter->{source} ? $parameter->{source} : ""; my $definition = defined $parameter->{definition} ? $parameter->{definition} : ""; + my $host = defined $parameter->{host} ? $parameter->{host} : $anvil->_short_hostname; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + server => $server, source => $source, definition => $definition, + host => $host, }}); if (not $server) @@ -408,15 +513,15 @@ sub _parse_definition my $address_port = $hash_ref->{address}->[0]->{port}; # Store - $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{source}{mode} = $hash_ref->{source}->[0]->{mode}; - $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{source}{path} = $hash_ref->{source}->[0]->{path}; - $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{alias} = $hash_ref->{alias}->[0]->{name}; + $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{source}{mode} = defined $hash_ref->{source}->[0]->{mode} ? $hash_ref->{source}->[0]->{mode} : ""; + $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{source}{path} = defined $hash_ref->{source}->[0]->{path} ? $hash_ref->{source}->[0]->{path} : ""; + $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{alias} = defined $hash_ref->{alias}->[0]->{name} ? $hash_ref->{alias}->[0]->{name} : ""; $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{address}{type} = $address_type; $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{address}{bus} = $address_bus; $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{address}{controller} = $address_controller; $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{address}{port} = $address_port; $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{target}{type} = $hash_ref->{target}->[0]->{type}; - $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{target}{'state'} = $hash_ref->{target}->[0]->{'state'}; + $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{target}{'state'} = defined $hash_ref->{target}->[0]->{'state'} ? $hash_ref->{target}->[0]->{'state'} : ""; $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{target}{name} = $hash_ref->{target}->[0]->{name}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "server::${server}::${source}::device::channel::unix::source::mode" => $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{source}{mode}, @@ -447,13 +552,13 @@ sub _parse_definition my $address_port = $hash_ref->{address}->[0]->{port}; # Store - $anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{alias} = $hash_ref->{alias}->[0]->{name}; + $anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{alias} = defined $hash_ref->{alias}->[0]->{name} ? $hash_ref->{alias}->[0]->{name} : ""; $anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{address}{type} = $address_type; $anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{address}{bus} = $address_bus; $anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{address}{controller} = $address_controller; $anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{address}{port} = $address_port; $anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{target}{type} = $hash_ref->{target}->[0]->{type}; - $anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{target}{'state'} = $hash_ref->{target}->[0]->{'state'}; + $anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{target}{'state'} = defined $hash_ref->{target}->[0]->{'state'} ? $hash_ref->{target}->[0]->{'state'} : ""; $anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{target}{name} = $hash_ref->{target}->[0]->{name}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "server::${server}::${source}::device::channel::spicevmc::alias" => $anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{alias}, @@ -479,9 +584,9 @@ sub _parse_definition foreach my $hash_ref (@{$server_xml->{devices}->[0]->{console}}) { $anvil->data->{server}{$server}{$source}{device}{console}{type} = $hash_ref->{type}; - $anvil->data->{server}{$server}{$source}{device}{console}{tty} = $hash_ref->{tty}; - $anvil->data->{server}{$server}{$source}{device}{console}{alias} = $hash_ref->{alias}->[0]->{name}; - $anvil->data->{server}{$server}{$source}{device}{console}{source} = $hash_ref->{source}->[0]->{path}; + $anvil->data->{server}{$server}{$source}{device}{console}{tty} = defined $hash_ref->{tty} ? $hash_ref->{tty} : ""; + $anvil->data->{server}{$server}{$source}{device}{console}{alias} = defined $hash_ref->{alias}->[0]->{name} ? $hash_ref->{alias}->[0]->{name} : ""; + $anvil->data->{server}{$server}{$source}{device}{console}{source} = defined $hash_ref->{source}->[0]->{path} ? $hash_ref->{source}->[0]->{path} : ""; $anvil->data->{server}{$server}{$source}{device}{console}{target_type} = $hash_ref->{target}->[0]->{type}; $anvil->data->{server}{$server}{$source}{device}{console}{target_port} = $hash_ref->{target}->[0]->{port}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { @@ -532,7 +637,7 @@ sub _parse_definition } # Store the data - $anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{alias} = $hash_ref->{alias}->[0]->{name}; + $anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{alias} = defined $hash_ref->{alias}->[0]->{name} ? $hash_ref->{alias}->[0]->{name} : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "server::${server}::${source}::device::controller::${type}::index::${index}::alias" => $anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{alias}, }}); @@ -594,7 +699,7 @@ sub _parse_definition #print Dumper $hash_ref; my $device = $hash_ref->{device}; my $type = $hash_ref->{type}; - my $alias = $hash_ref->{alias}->[0]->{name}; + my $alias = defined $hash_ref->{alias}->[0]->{name} ? $hash_ref->{alias}->[0]->{name} : ""; my $device_target = $hash_ref->{target}->[0]->{dev}; my $device_bus = $hash_ref->{target}->[0]->{bus}; my $address_type = $hash_ref->{address}->[0]->{type}; @@ -660,15 +765,23 @@ sub _parse_definition "server::${server}::${source}::device::${device}::target::${device_target}::driver::cache" => $anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{driver}{cache}, }}); - $anvil->data->{server}{$server}{device}{$device_path}{on_lv} = defined $anvil->data->{drbd}{'local'}{drbd_path}{$device_path}{on} ? $anvil->data->{drbd}{'local'}{drbd_path}{$device_path}{on} : ""; - $anvil->data->{server}{$server}{device}{$device_path}{resource} = defined $anvil->data->{drbd}{'local'}{drbd_path}{$device_path}{resource} ? $anvil->data->{drbd}{'local'}{drbd_path}{$device_path}{resource} : ""; + $anvil->data->{server}{$server}{device}{$device_path}{on_lv} = defined $anvil->data->{drbd}{config}{$host}{drbd_path}{$device_path}{on} ? $anvil->data->{drbd}{config}{$host}{drbd_path}{$device_path}{on} : ""; + $anvil->data->{server}{$server}{device}{$device_path}{resource} = defined $anvil->data->{drbd}{config}{$host}{drbd_path}{$device_path}{resource} ? $anvil->data->{drbd}{config}{$host}{drbd_path}{$device_path}{resource} : ""; $anvil->data->{server}{$server}{device}{$device_path}{target} = $device_target; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + host => $host, "server::${server}::device::${device_path}::on_lv" => $anvil->data->{server}{$server}{device}{$device_path}{on_lv}, "server::${server}::device::${device_path}::resource" => $anvil->data->{server}{$server}{device}{$device_path}{resource}, "server::${server}::device::${device_path}::target" => $anvil->data->{server}{$server}{device}{$device_path}{target}, }}); + # Keep a list of DRBD resources used by this server. + my $drbd_resource = $anvil->data->{server}{$server}{device}{$device_path}{resource}; + $anvil->data->{server}{$server}{drbd}{resource}{$drbd_resource} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "server::${server}::drbd::resource::${drbd_resource}" => $anvil->data->{server}{$server}{drbd}{resource}{$drbd_resource}, + }}); + ### TODO: Store the parts in some format that allows representing it better to the user and easier to find "open slots". # $anvil->data->{server}{$server}{$source}{address}{$device_bus}{bus}{$address_bus}{bus}{$address_bus}{slot}{$address_slot}{function}{$address_function}{domain} = $address_domain; # $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { @@ -704,8 +817,8 @@ sub _parse_definition my $mac = $hash_ref->{mac}->[0]->{address}; $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{bridge} = $hash_ref->{source}->[0]->{bridge}; - $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{alias} = $hash_ref->{alias}->[0]->{name}; - $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{target} = $hash_ref->{target}->[0]->{dev}; + $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{alias} = defined $hash_ref->{alias}->[0]->{name} ? $hash_ref->{alias}->[0]->{name} : ""; + $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{target} = defined $hash_ref->{target}->[0]->{dev} ? $hash_ref->{target}->[0]->{dev} : ""; $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{model} = $hash_ref->{model}->[0]->{type}; $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{address}{bus} = $hash_ref->{address}->[0]->{bus}; $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{address}{domain} = $hash_ref->{address}->[0]->{domain}; diff --git a/Anvil/Tools/System.pm b/Anvil/Tools/System.pm index cfbd9a68..272dbccc 100644 --- a/Anvil/Tools/System.pm +++ b/Anvil/Tools/System.pm @@ -625,22 +625,46 @@ sub check_storage # Do a scan, if requested. if ($scan) { - my ($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $anvil->data->{path}{exe}{pvscan}." && ".$anvil->data->{path}{exe}{vgscan}." && ".$anvil->data->{path}{exe}{lvscan}}); + my ($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $anvil->data->{path}{exe}{pvscan}." 2>/dev/null"}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - output => $output, - return_code => $return_code, + output => $output, + return_code => $return_code, + redirect_stderr => 0, + }}); + + $output = ""; + $return_code = ""; + ($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $anvil->data->{path}{exe}{vgscan}." 2>/dev/null"}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + output => $output, + return_code => $return_code, + redirect_stderr => 0, + }}); + + $output = ""; + $return_code = ""; + ($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $anvil->data->{path}{exe}{lvscan}." 2>/dev/null"}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + output => $output, + return_code => $return_code, + redirect_stderr => 0, }}); } + ### NOTE: In case: 'lvm.conf -> filter = [ "r|/dev/drbd.*|" ]' isn't set, we'll get warnings about + ### DRBD devices being "wrong medium type" when Secondary. We check for and ignore these + ### warnings. # Gather PV data. - my ($pvs_output, $pvs_return_code) = $anvil->System->call({debug => $debug, shell_call => $anvil->data->{path}{exe}{pvs}." --units b --noheadings --separator \\\#\\\!\\\# -o pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pv_used,pv_uuid"}); + my ($pvs_output, $pvs_return_code) = $anvil->System->call({debug => $debug, shell_call => $anvil->data->{path}{exe}{pvs}." --units b --noheadings --separator \\\#\\\!\\\# -o pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pv_used,pv_uuid 2>/dev/null"}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { pvs_output => $pvs_output, pvs_return_code => $pvs_return_code, + redirect_stderr => 0, }}); foreach my $line (split/\n/, $pvs_output) { $line = $anvil->Words->clean_spaces({string => $line}); + next if $line =~ /Wrong medium type/i; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }}); my ($this_pv, $used_by_vg, $format, $attributes, $total_size, $free_size, $used_size, $uuid) = (split /#!#/, $line); @@ -665,14 +689,16 @@ sub check_storage } # Gather VG data. - my ($vgs_output, $vgs_return_code) = $anvil->System->call({debug => $debug, shell_call => $anvil->data->{path}{exe}{vgs}." --units b --noheadings --separator \\\#\\\!\\\# -o vg_name,vg_attr,vg_extent_size,vg_extent_count,vg_uuid,vg_size,vg_free_count,vg_free,pv_name"}); + my ($vgs_output, $vgs_return_code) = $anvil->System->call({debug => $debug, shell_call => $anvil->data->{path}{exe}{vgs}." --units b --noheadings --separator \\\#\\\!\\\# -o vg_name,vg_attr,vg_extent_size,vg_extent_count,vg_uuid,vg_size,vg_free_count,vg_free,pv_name 2>/dev/null"}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { vgs_output => $vgs_output, vgs_return_code => $vgs_return_code, + redirect_stderr => 0, }}); foreach my $line (split/\n/, $vgs_output) { $line = $anvil->Words->clean_spaces({string => $line}); + next if $line =~ /Wrong medium type/i; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }}); my ($this_vg, $attributes, $pe_size, $total_pe, $uuid, $vg_size, $free_pe, $vg_free, $pv_name) = split /#!#/, $line; @@ -718,14 +744,16 @@ sub check_storage } # And finally, the LV data. - my ($lvs_output, $lvs_return_code) = $anvil->System->call({debug => $debug, shell_call => $anvil->data->{path}{exe}{lvs}." --units b --noheadings --separator \\\#\\\!\\\# -o lv_name,vg_name,lv_attr,lv_size,lv_uuid,lv_path,devices"}); + my ($lvs_output, $lvs_return_code) = $anvil->System->call({debug => $debug, shell_call => $anvil->data->{path}{exe}{lvs}." --units b --noheadings --separator \\\#\\\!\\\# -o lv_name,vg_name,lv_attr,lv_size,lv_uuid,lv_path,devices 2>/dev/null"}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { lvs_output => $lvs_output, lvs_return_code => $lvs_return_code, + redirect_stderr => 0, }}); foreach my $line (split/\n/, $lvs_output) { $line = $anvil->Words->clean_spaces({string => $line}); + next if $line =~ /Wrong medium type/i; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }}); my ($lv_name, $on_vg, $attributes, $total_size, $uuid, $path, $devices) = (split /#!#/, $line); @@ -1502,7 +1530,7 @@ sub is_local my $is_local = 0; if (($host eq $anvil->_hostname) or ($host eq $anvil->_short_hostname) or - ($host eq "localhost") or + ($host eq "localhost") or ($host eq "127.0.0.1")) { # It's local diff --git a/ocf/alteeve/server b/ocf/alteeve/server index c38e2a23..27a646ab 100755 --- a/ocf/alteeve/server +++ b/ocf/alteeve/server @@ -315,6 +315,14 @@ sub start_server # Make sure things are sane. validate_all($anvil); + # Is the server already running somewhere? + find_server($anvil); + #$anvil->Server->find({server => $server}); + + ### TODO: + my $host = $anvil->_short_hostname; + print "I am: [".$anvil->data->{drbd}{config}{$host}{host}."]. my peer is: [".$anvil->data->{drbd}{config}{$host}{peer}."]\n"; + die; # If we're still alive, then we didn't see the server in the list of running servers, which is really weird. @@ -322,6 +330,77 @@ sub start_server $anvil->nice_exit({exit_code => 1}); } +# This uses the DRBD information to find other peers and see if the server is running on them. +sub find_server +{ + my ($anvil) = @_; + + my $server = $anvil->data->{environment}{OCF_RESKEY_name}; + my $host = $anvil->_short_hostname; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "log_0415", variables => { server => $server }}); + foreach my $ip_address (sort {$a cmp $b} keys %{$anvil->data->{drbd}{config}{$host}{ip_addresses}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ip_address => $ip_address }}); + $anvil->Server->find({ + debug => 3, + target => $ip_address, + remote_user => "root", + }); + } + + foreach my $this_server (sort {$a cmp $b} keys %{$anvil->data->{server}{location}}) + { + my $status = $anvil->data->{server}{location}{$this_server}{status}; + my $host = $anvil->data->{server}{location}{$this_server}{host}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + this_server => $this_server, + status => $status, + host => $host, + }}); + } + if ((exists $anvil->data->{server}{location}{$server}) && ($anvil->data->{server}{location}{$server}{host})) + { + # The server is running. If it is running here, exit with success. If it's running elsewhere, + # exit with a failure. + my $status = $anvil->data->{server}{location}{$server}{status}; + my $host = $anvil->data->{server}{location}{$server}{host}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + status => $status, + host => $host, + }}); + + if ($host eq $anvil->_hostname) + { + # Already running, we're good, and we're done. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "log_0416", variables => { server => $server }}); + $anvil->nice_exit({exit_code => 0}); + } + elsif ($host =~ /dr(\d+)$/) + { + # The server is running elsewhere. If the peer host is DR, exit with + # OCF_ERR_CONFIGURED (6) so that pacemaker doesn't try to also start the server on + # the other node, because we don't know the state of it here. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "log_0417", variables => { + server => $server, + host => $host, + }}); + $anvil->nice_exit({exit_code => 6}); + } + else + { + # It looks like it's running on the peer. So we'll exit OCF_ERR_INSTALLED (5) to tell + # pacemaker to try to start it on our peer. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "log_0418", variables => { + server => $server, + host => $host, + }}); + $anvil->nice_exit({exit_code => 6}); + } + } + + return(0); +} + # This shuts down the server if possible. sub stop_server { @@ -350,7 +429,7 @@ sub server_status { # Set a sane default of 20 seconds. $anvil->data->{environment}{OCF_RESKEY_CRM_meta_timeout} = 20000; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, priority => "warn", key => "log_0331", variables => { logout => $anvil->data->{environment}{OCF_RESKEY_CRM_meta_timeout} }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, priority => "warn", key => "log_0331", variables => { timeout => $anvil->data->{environment}{OCF_RESKEY_CRM_meta_timeout} }}); } $anvil->nice_exit({exit_code => 0}); @@ -391,8 +470,8 @@ sub validate_all ### if the server is running elsewhere. # Read in an parse the server's XML. - $anvil->System->check_storage({debug => 3}); - $anvil->Server->get_status({debug => 3, server => $anvil->data->{environment}{OCF_RESKEY_name}}); + $anvil->System->check_storage({debug => 2}); + $anvil->Server->get_status({debug => 2, server => $anvil->data->{environment}{OCF_RESKEY_name}}); # Is the name in the definition file what we expect (and did we read the XML data at all)? validate_name($anvil); @@ -525,12 +604,28 @@ sub validate_storage_drbd # Now check storage. my $server = $anvil->data->{environment}{OCF_RESKEY_name}; my $source = "from_disk"; + my $host = $anvil->_short_hostname; + + # Did I find a resource for each disk? + foreach my $device_path (sort {$a cmp $b} keys %{$anvil->data->{server}{$server}{device}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "server::${server}::device::${device_path}::resource" => $anvil->data->{server}{$server}{device}{$device_path}{resource}, + }}); + if (not $anvil->data->{server}{$server}{device}{$device_path}{resource}) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 0, level => 0, priority => "err", key => "log_0414", variables => { drbd_device => $device_path }}); + $anvil->nice_exit({exit_code => 5}); + } + } + foreach my $device_target (sort {$a cmp $b} keys %{$anvil->data->{server}{$server}{$source}{device}{disk}{target}}) { my $drbd_device = $anvil->data->{server}{$server}{$source}{device}{disk}{target}{$device_target}{path}; - my $drbd_resource = $anvil->data->{drbd}{'local'}{drbd_path}{$drbd_device}{resource}; - my $on_lv = $anvil->data->{drbd}{'local'}{drbd_path}{$drbd_device}{on}; + my $drbd_resource = $anvil->data->{drbd}{config}{$host}{drbd_path}{$drbd_device}{resource}; + my $on_lv = $anvil->data->{drbd}{config}{$host}{drbd_path}{$drbd_device}{on}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + host => $host, drbd_device => $drbd_device, drbd_resource => $drbd_resource, on_lv => $on_lv, @@ -567,9 +662,8 @@ sub validate_storage_drbd } - print "I am: [".$anvil->data->{drbd}{host}{'local'}."]. my peer is: [".$anvil->data->{drbd}{host}{peer}."]\n"; - - die; + ### NOTE: Checking/Managing firewall ports is expensive option, so DRBD ports are permanently opened + ### when a resource is created. return(0); } diff --git a/share/words.xml b/share/words.xml index f9df9452..33ba305d 100644 --- a/share/words.xml +++ b/share/words.xml @@ -731,6 +731,11 @@ Failed to promote the DRBD resource: [#!variable!resource!#] primary. Expected a The server: [#!variable!server!#] is already on this node in the state: [#!variable!state!#], aborting the migration request. The logical volume: [#!variable!lv_path!#] is inactive. Attempting to activate it now. + The DRBD device: [#!variable!drbd_device!#] wasn't found in any DRBD resources on this machine. + - Seeing if the server: [#!variable!server!#] is running already. + The server: [#!variable!server!#] is already running. Exiting successfully. + The server: [#!variable!server!#] is already running on: [#!variable!host!#]. This appears to be a DR host, which is outside pacemaker. Exiting with OCF_ERR_CONFIGURED (6) to prevent pacemaker from trying to start the server on the other node. + The server: [#!variable!server!#] is already running on: [#!variable!host!#]. This appears to be our peer. Exiting with OCF_ERR_INSTALLED (5) to tell pacemaker to try to start it on the other node. Test