package Anvil::Tools::Striker; # # This module contains methods used to handle common Striker (webUI) tasks. # use strict; use warnings; use Data::Dumper; use JSON; use Scalar::Util qw(weaken isweak); use Text::Diff; our $VERSION = "3.0.0"; my $THIS_FILE = "Striker.pm"; ### Methods; # check_httpd_conf - Deprecated # generate_manifest # get_fence_data # get_local_repo # get_peer_data # get_ups_data # load_manifest # parse_all_status_json =pod =encoding utf8 =head1 NAME Anvil::Tools::Striker Provides all methods related to the Striker WebUI. =head1 SYNOPSIS use Anvil::Tools; # Get a common object handle on all Anvil::Tools modules. my $anvil = Anvil::Tools->new(); # Access to methods using '$anvil->Striker->X'. # # Example using 'system_call()'; =head1 METHODS Methods in this module; =cut sub new { my $class = shift; my $self = {}; bless $self, $class; return ($self); } # Get a handle on the Anvil::Tools object. I know that technically that is a sibling module, but it makes more # sense in this case to think of it as a parent. sub parent { my $self = shift; my $parent = shift; $self->{HANDLE}{TOOLS} = $parent if $parent; # Defend against memory leads. See Scalar::Util'. if (not isweak($self->{HANDLE}{TOOLS})) { weaken($self->{HANDLE}{TOOLS}); } return ($self->{HANDLE}{TOOLS}); } ############################################################################################################# # Public methods # ############################################################################################################# =head2 check_httpd_conf This checks the apache configuration file to ensure it's setup for the Striker dashboard and RPM repository. This method does nothing if called on non-striker dashboard. This method takes no parameters. =cut sub check_httpd_conf { my $self = shift; my $parameter = shift; my $anvil = $self->parent; my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Striker->check_httpd_conf()" }}); if (not -s $anvil->data->{path}{data}{httpd_conf}) { # The apache config file doesn't exist or is empty; abort. return(0); } my $is_write = 0; my $write_shell_call = $anvil->data->{path}{exe}{augtool}." --new <data->{path}{data}{httpd_conf}."/IfModule[arg='dir_module']/directive[.='DirectoryIndex']/arg[1]"; $read_shell_call = $anvil->data->{path}{exe}{augtool}." <System->call({ shell_call => $read_shell_call }); $anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $read_shell_call, shell_output => $shell_output, shell_return_code => $shell_return_code } }); if (($shell_return_code == 0) and ($shell_output =~ /^\//)) { $is_write = 1; # Set DirectoryIndex to cgi-bin/striker. $write_shell_call .= "set ".$augtool_path." cgi-bin/striker\n"; } my $header_name = "Access-Control-Allow-Origin"; $augtool_path = "/files".$anvil->data->{path}{data}{httpd_conf}."/Directory[arg='\"/var/www/cgi-bin\"']/directive[.='Header']"; $read_shell_call = $anvil->data->{path}{exe}{augtool}." <System->call({ shell_call => $read_shell_call }); $anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $read_shell_call, shell_output => $shell_output, shell_return_code => $shell_return_code } }); if (($shell_return_code == 0) and (not $shell_output =~ /^\//)) { $is_write = 1; my $last_header_arg = $augtool_path."[last()]/arg"; # Add header Access-Control-Allow-Origin "all" to cgi-bin scripts. $write_shell_call .= "set ".$augtool_path."[last()+1] Header\n"; $write_shell_call .= "set ".$last_header_arg."[1] set\n"; $write_shell_call .= "set ".$last_header_arg."[2] ".$header_name."\n"; $write_shell_call .= "set ".$last_header_arg."[3] \\\"*\\\"\n"; } $augtool_path = "/files".$anvil->data->{path}{data}{httpd_conf}."/Directory[arg='\"/var/www/html\"']/IfModule"; $read_shell_call = $anvil->data->{path}{exe}{augtool}." <System->call({ shell_call => $read_shell_call }); $anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $read_shell_call, shell_output => $shell_output, shell_return_code => $shell_return_code } }); if (($shell_return_code == 0) and (not $shell_output =~ /^\//)) { $is_write = 1; my $last_ifmodule_directive = $augtool_path."[last()]/directive"; my $new_directive = $last_ifmodule_directive."[last()+1]"; my $rewriteengine_directive = "RewriteEngine"; my $rewritecond_directive = "RewriteCond"; my $rewriterule_directive = "RewriteRule"; # Insert rewrite rules to redirect /page to /page.html. # Create IfModule block to avoid setting the rewrite rules when the rewrite module isn't available. $write_shell_call .= "set ".$augtool_path."[last()+1]/arg[1] rewrite_module\n"; # Turn on the rewrite engine to enable rewriting. $write_shell_call .= "set ".$new_directive." ".$rewriteengine_directive."\n"; $write_shell_call .= "set ".$last_ifmodule_directive."[.='".$rewriteengine_directive."']/arg[1] on\n"; my $last_rewriterule_arg = $last_ifmodule_directive."[.='".$rewriterule_directive."'][last()]/arg"; # Set rule #1: remove all trailing slashes from the URI. $write_shell_call .= "set ".$new_directive." ".$rewriterule_directive."\n"; $write_shell_call .= "set ".$last_rewriterule_arg."[1] ^(.*)/+\$\n"; $write_shell_call .= "set ".$last_rewriterule_arg."[2] \\\$1\n"; my $last_rewritecond_arg = $last_ifmodule_directive."[.='".$rewritecond_directive."'][last()]/arg"; # Set rule #2: redirect to [basename].html if it exists. $write_shell_call .= "set ".$new_directive." ".$rewritecond_directive."\n"; $write_shell_call .= "set ".$last_rewritecond_arg."[1] %{REQUEST_FILENAME}.html\n"; $write_shell_call .= "set ".$last_rewritecond_arg."[2] -f\n"; $write_shell_call .= "set ".$new_directive." ".$rewriterule_directive."\n"; $write_shell_call .= "set ".$last_rewriterule_arg."[1] ![^/]+[.]html\$\n"; $write_shell_call .= "set ".$last_rewriterule_arg."[2] %{REQUEST_FILENAME}.html\n"; $write_shell_call .= "set ".$last_rewriterule_arg."[3] [L]\n"; } # Attempt to setup forwarding from the Apache server to the Striker UI API. $augtool_path = "/files".$anvil->data->{path}{data}{httpd_conf}."/Location[arg='\"/api\"']"; $read_shell_call = $anvil->data->{path}{exe}{augtool}." <System->call({ shell_call => $read_shell_call }); $anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $read_shell_call, shell_output => $shell_output, shell_return_code => $shell_return_code } }); if (($shell_return_code == 0) and (not $shell_output =~ /^\//)) { $is_write = 1; my $new_ifmodule_directive = $augtool_path."/IfModule[arg='proxy_module']"; my $striker_ui_api_url = "http://localhost:8080/api"; $write_shell_call .= "set ".$augtool_path =~ s/(Location)[^\s]+$/$1/r."[last()+1]/arg[1] '\"/api\"'\n"; $write_shell_call .= "set ".$augtool_path."/IfModule[last()+1]/arg[1] 'proxy_module'\n"; $write_shell_call .= "set ".$new_ifmodule_directive."/directive[last()+1] 'ProxyPass'\n"; $write_shell_call .= "set ".$new_ifmodule_directive."/directive[.='ProxyPass']/arg[1] '".$striker_ui_api_url."'\n"; } if ($is_write) { $write_shell_call .= "save\nquit\nEOF\n"; ($shell_output, $shell_return_code) = $anvil->System->call({ shell_call => $write_shell_call }); $anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $write_shell_call, shell_output => $shell_output, shell_return_code => $shell_return_code } }); my $new_httpd_conf = $anvil->data->{path}{data}{httpd_conf}.".augnew"; if (not -s $new_httpd_conf) { # No new conf file created; abort. return(0); } my $diff_output = diff $anvil->data->{path}{data}{httpd_conf}, $new_httpd_conf, { STYLE => 'Unified' }; $anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => { diff_output => $diff_output } }); # Test the new config file before overwriting. $read_shell_call = $anvil->data->{path}{exe}{httpd}." -t -f ".$new_httpd_conf; ($shell_output, $shell_return_code) = $anvil->System->call({ shell_call => $read_shell_call }); $anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $read_shell_call, shell_output => $shell_output, shell_return_code => $shell_return_code } }); if ($shell_return_code == 0) { # No issues found during the test; proceed to overwriting. $anvil->Storage->backup({ debug => $debug, file => $anvil->data->{path}{data}{httpd_conf} }); $write_shell_call = $anvil->data->{path}{exe}{mv}." -f ".$new_httpd_conf." ".$anvil->data->{path}{data}{httpd_conf}; ($shell_output, $shell_return_code) = $anvil->System->call({ shell_call => $write_shell_call }); $anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $write_shell_call, shell_output => $shell_output, shell_return_code => $shell_return_code } }); $anvil->Storage->change_mode({ debug => $debug, path => $anvil->data->{path}{data}{httpd_conf}, mode => "0644" }); $anvil->Storage->change_owner({ debug => $debug, path => $anvil->data->{path}{data}{httpd_conf}, user => "root", group => "root" }); $anvil->System->restart_daemon({ debug => $debug, daemon => $anvil->data->{sys}{daemon}{httpd} }); } else { # Found issues during the test; clean up. $write_shell_call = $anvil->data->{path}{exe}{rm}." -f ".$new_httpd_conf; ($shell_output, $shell_return_code) = $anvil->System->call({ shell_call => $write_shell_call }); $anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $write_shell_call, shell_output => $shell_output, shell_return_code => $shell_return_code } }); } } return(0); } =head2 generate_manifest This reads the CGI data coming from the manifest form to generate the manifest XML. On success, the C<< manifest_uuid >>, and C<< manifest_uuid >> are returned. If there's a problem, C<< !!error!! >> is returned. Parameters; =head3 dns (optional) This is a comma-separated list of DNS servers to use. =head3 domain (required) This is the domain name to use for this Anvil! node. =head3 manifest_uuid (optional) This allows updating an existing mannifest, or specifying the manifest UUID to use for the new manifest. =head3 mtu (optional) This allows specifying a custome MTU (maximum transmission unit) size. Only use this if you know all network devices support this MTU size! =head3 ntp (optional) This allows specifying a custom NTP (network time protocol) server to use to sync the subnode's time against. =head3 prefix (required) This is the node's descriptive prefix (usually 1~5 characters). =head3 sequence (required) This is an integer, 1 or higher, indication the node's sequence number. =cut sub generate_manifest { my $self = shift; my $parameter = shift; my $anvil = $self->parent; my $debug = $parameter->{debug} // 3; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Striker->generate_manifest()" }}); my $network_dns = $parameter->{dns} // ""; my $domain = $parameter->{domain} // ""; my $manifest_uuid = $parameter->{manifest_uuid} // ""; my $network_mtu = $parameter->{mtu} // ""; my $network_ntp = $parameter->{ntp} // ""; my $name_prefix = $parameter->{prefix} // ""; my $padded_sequence = $parameter->{sequence} // ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { network_dns => $network_dns, domain => $domain, manifest_uuid => $manifest_uuid, network_mtu => $network_mtu, network_ntp => $network_ntp, name_prefix => $name_prefix, padded_sequence => $padded_sequence, }}); if (not $domain) { # No target... $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Striker->generate_manifest()", parameter => "domain" }}); return('!!error!!', '!!error!!'); } if (not $name_prefix) { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Striker->generate_manifest()", parameter => "name_prefix" }}); return('!!error!!', '!!error!!'); } if (not $padded_sequence) { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Striker->generate_manifest()", parameter => "padded_sequence" }}); return('!!error!!', '!!error!!'); } $anvil->Database->get_upses({debug => $debug}); $anvil->Database->get_fences({debug => $debug}); if (not $manifest_uuid) { # Don't proceed, we'd get an invalid manifest. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "warning_0159"}); return('!!error!!'); } if ($manifest_uuid eq "new") { $manifest_uuid = ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { manifest_uuid => $manifest_uuid }}); } if (length($padded_sequence) == 1) { $padded_sequence = sprintf("%02d", $padded_sequence); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { padded_sequence => $padded_sequence }}); } my $anvil_name = $name_prefix."-anvil-".$padded_sequence; my $node1_name = $name_prefix."-a".$padded_sequence."n01"; my $node2_name = $name_prefix."-a".$padded_sequence."n02"; my $machines = {}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { anvil_name => $anvil_name, node1_name => $node1_name, node2_name => $node2_name, }}); my $manifest_xml = ' '; foreach my $network ("bcn", "ifn", "sn", "mn") { my $count_key = $network."_count"; my $count_value = $parameter->{$count_key} // $anvil->data->{cgi}{$count_key}{value}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "${count_key}" => $count_value }}); foreach my $i (1..$count_value) { my $network_name = $network.$i; my $network_key = $network_name."_network"; my $network_value = $parameter->{$network_key} // $anvil->data->{cgi}{$network_key}{value}; my $subnet_key = $network_name."_subnet"; my $subnet_value = $parameter->{$subnet_key} // $anvil->data->{cgi}{$subnet_key}{value}; my $gateway_key = $network_name."_gateway"; my $gateway_value = $parameter->{$gateway_key} // $anvil->data->{cgi}{$gateway_key}{value}; $manifest_xml .= ' '."\n"; # While we're here, gather the network data for the machines. foreach my $machine ("node1", "node2") { # Record the network my $ip_key = $machine."_".$network_name."_ip"; my $ip_value = ($parameter->{$ip_key} // $anvil->data->{cgi}{$ip_key}{value}) // ""; $machines->{$machine}{network}{$network_name} = $ip_value; # On the first loop (bcn1), pull in the other information as well. if (($network eq "bcn") && ($i eq "1")) { # Get the IP. my $ipmi_ip_key = $machine."_ipmi_ip"; my $ipmi_ip_value = ($parameter->{$ipmi_ip_key} // $anvil->data->{cgi}{$ipmi_ip_key}{value}) // ""; $machines->{$machine}{ipmi_ip} = $ipmi_ip_value; # Find the UPSes. foreach my $ups_name (sort {$a cmp $b} keys %{$anvil->data->{upses}{ups_name}}) { my $ups_key = $machine."_ups_".$ups_name; my $ups_value = ($parameter->{$ups_key} // $anvil->data->{cgi}{$ups_key}{value}) // ""; $machines->{$machine}{ups}{$ups_name} = $ups_value ? "1" : "0"; } # Find the Fence devices. foreach my $fence_name (sort {$a cmp $b} keys %{$anvil->data->{fences}{fence_name}}) { my $fence_key = $machine."_fence_".$fence_name; my $fence_value = ($parameter->{$fence_key} // $anvil->data->{cgi}{$fence_key}{value}) // ""; $machines->{$machine}{fence}{$fence_name} = $fence_value; } } } } } $manifest_xml .= ' '; # We don't store information about the UPS as it may change over time. We just need the reference. foreach my $ups_name (sort {$a cmp $b} keys %{$anvil->data->{upses}{ups_name}}) { $manifest_xml .= ' '; } $manifest_xml .= ' '; # We don't store information about the UPS as it may change over time. We just need the reference. foreach my $fence_name (sort {$a cmp $b} keys %{$anvil->data->{fences}{fence_name}}) { $manifest_xml .= ' '; } $manifest_xml .= ' '; # Now record the info about the machines. foreach my $machine (sort {$a cmp $b} keys %{$machines}) { my $host_name = ""; if ($machine eq "node1") { $host_name = $node1_name; } if ($machine eq "node2") { $host_name = $node2_name; } $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_name => $host_name }}); $manifest_xml .= ' <'.$machine.' name="'.$host_name.'" ipmi_ip="'.$machines->{$machine}{ipmi_ip}.'"> '; foreach my $network_name (sort {$a cmp $b} keys %{$machines->{$machine}{network}}) { $manifest_xml .= ' '; } $manifest_xml .= ' '; foreach my $ups_name (sort {$a cmp $b} keys %{$machines->{$machine}{ups}}) { $manifest_xml .= ' '; } $manifest_xml .= ' '; foreach my $fence_name (sort {$a cmp $b} keys %{$machines->{$machine}{fence}}) { $manifest_xml .= ' '; } $manifest_xml .= ' '; } $manifest_xml .= ' '; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { manifest_xml => $manifest_xml }}); # Now save the manifest! ($manifest_uuid) = $anvil->Database->insert_or_update_manifests({ debug => $debug, manifest_uuid => $manifest_uuid, manifest_name => $anvil_name, manifest_xml => $manifest_xml, }); return($manifest_uuid, $anvil_name); } =head2 get_fence_data This parses the unified metadata file from the avaialable fence_devices on this host. If the unified file (location stored in C<< path::data::fences_unified_metadata >>, default is C<< /tmp/fences_unified_metadata.xml >> is not found or fails to parse, C<< 1 >> is returned. If the file is successfully parsed. C<< 0 >> is returned. The parsed data is stored under C<< fence_data::::... >>. =cut sub get_fence_data { my $self = shift; my $parameter = shift; my $anvil = $self->parent; my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Striker->get_fence_data()" }}); my $parsed_xml = ""; my $xml_body = $anvil->Storage->read_file({ debug => $debug, file => $anvil->data->{path}{data}{fences_unified_metadata}, }); # Globally replace \fI (opening underline) with '[' and \fP (closing underline) with ']'. $xml_body =~ s/\\fI/[/gs; $xml_body =~ s/\\fP/]/gs; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { xml_body => $xml_body }}); if ($xml_body =~ /<\?xml version="1.0" \?>/gs) { my $xml = XML::Simple->new(); eval { $parsed_xml = $xml->XMLin($xml_body, KeyAttr => { key => 'name' }, ForceArray => []) }; if ($@) { chomp $@; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0111", variables => { xml_body => $xml_body, eval_error => $@, }}); # Clear the error so it doesn't propogate out to a future 'die' and confuse things. $@ = ''; return(1); } } else { $anvil->nice_exit({exit_code => 1}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0112"}); return(1); } foreach my $agent_ref (@{$parsed_xml->{agent}}) { my $fence_agent = $agent_ref->{name}; $anvil->data->{fence_data}{$fence_agent}{description} = $agent_ref->{'resource-agent'}->{longdesc}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "fence_data::${fence_agent}::description" => $anvil->data->{fence_data}{$fence_agent}{description}, }}); if (exists $agent_ref->{'resource-agent'}->{'symlink'}) { if (ref($agent_ref->{'resource-agent'}->{'symlink'}) eq "ARRAY") { foreach my $hash_ref (@{$agent_ref->{'resource-agent'}->{'symlink'}}) { my $name = $hash_ref->{name}; $anvil->data->{fence_data}{$fence_agent}{'symlink'}{$name} = $hash_ref->{shortdesc}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "fence_data::${fence_agent}::symlink::${name}" => $anvil->data->{fence_data}{$fence_agent}{'symlink'}{$name}, }}); } } else { my $name = $agent_ref->{'resource-agent'}->{'symlink'}->{name}; $anvil->data->{fence_data}{$fence_agent}{'symlink'}{$name} = $agent_ref->{'resource-agent'}->{'symlink'}->{shortdesc}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "fence_data::${fence_agent}::symlink::${name}" => $anvil->data->{fence_data}{$fence_agent}{'symlink'}{$name}, }}); } } foreach my $hash_ref (@{$agent_ref->{'resource-agent'}->{parameters}{parameter}}) { # We ignore some parameters that are not useful parameters in our case. my $name = $hash_ref->{name}; next if $name =~ /debug/; next if $name eq "delay"; next if $name eq "help"; next if $name eq "version"; next if $name eq "separator"; next if $name eq "plug"; next if $name =~ /snmp(.*?)_path/; next if $name eq "verbose"; my $unique = exists $hash_ref->{unique} ? $hash_ref->{unique} : 0; my $required = exists $hash_ref->{required} ? $hash_ref->{required} : 0; my $deprecated = exists $hash_ref->{deprecated} ? $hash_ref->{deprecated} : 0; my $obsoletes = exists $hash_ref->{obsoletes} ? $hash_ref->{obsoletes} : 0; $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{unique} = $unique; $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{required} = $required; $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{deprecated} = $deprecated; $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{obsoletes} = $obsoletes; $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{description} = $hash_ref->{shortdesc}->{content}; $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{description} =~ s/\n/ /g; $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{switches} = defined $hash_ref->{getopt}->{mixed} ? $hash_ref->{getopt}->{mixed} : ""; $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{content_type} = $hash_ref->{content}->{type}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "fence_data::${fence_agent}::parameters::${name}::unique" => $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{unique}, "fence_data::${fence_agent}::parameters::${name}::required" => $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{required}, "fence_data::${fence_agent}::parameters::${name}::deprecated" => $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{deprecated}, "fence_data::${fence_agent}::parameters::${name}::obsoletes" => $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{obsoletes}, "fence_data::${fence_agent}::parameters::${name}::description" => $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{description}, "fence_data::${fence_agent}::parameters::${name}::switches" => $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{switches}, "fence_data::${fence_agent}::parameters::${name}::content_type" => $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{content_type}, }}); # Make it easier to tranlate a switch to a parameter name. if (($anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{switches}) and (not $deprecated)) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { fence_agent => $fence_agent, name => $name, }}); foreach my $switch (split/,/, $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{switches}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { '>> switch' => $switch }}); $switch =~ s/=.*$//; $switch =~ s/\s//g; $switch =~ s/^-{1,2}//; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { '<< switch' => $switch }}); $anvil->data->{fence_data}{$fence_agent}{switch}{$switch}{name} = $name; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "fence_data::${fence_agent}::switch::${switch}::name" => $anvil->data->{fence_data}{$fence_agent}{switch}{$switch}{name}, }}); } } # 'action' is a string, but it has a set list of allowed values, so we manually switch it to a 'select' for the web interface if ($name eq "action") { $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{'default'} = exists $hash_ref->{content}->{'default'} ? $hash_ref->{content}->{'default'} : ""; $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{content_type} = "select"; $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{options} = []; # Read the action #print "Agent: [".$fence_agent."]; actions (default: [".$anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{'default'}."]);\n"; foreach my $array_ref (sort {$a cmp $b} @{$agent_ref->{'resource-agent'}->{actions}->{action}}) { # There are several options that don't make sense for us. next if $array_ref->{name} eq "list"; next if $array_ref->{name} eq "monitor"; next if $array_ref->{name} eq "manpage"; next if $array_ref->{name} eq "status"; next if $array_ref->{name} eq "validate-all"; next if $array_ref->{name} eq "list-status"; next if $array_ref->{name} eq "metadata"; next if $array_ref->{name} eq "on"; push @{$anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{options}}, $array_ref->{name}; } foreach my $option (sort {$a cmp $b} @{$anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{options}}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { option => $option }}); } } elsif ($anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{content_type} eq "string") { $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{'default'} = exists $hash_ref->{content}->{'default'} ? $hash_ref->{content}->{'default'} : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "fence_data::${fence_agent}::parameters::${name}::default" => $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{'default'}, }}); } elsif ($anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{content_type} eq "select") { $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{options} = []; foreach my $option_ref (@{$hash_ref->{content}->{option}}) { push @{$anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{options}}, $option_ref->{value}; } foreach my $option (sort {$a cmp $b} @{$anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{options}}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { option => $option }}); } } elsif ($anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{content_type} eq "boolean") { # Nothing to collect here. } elsif ($anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{content_type} eq "second") { # Nothing to collect here. $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{'default'} = exists $hash_ref->{content}->{'default'} ? $hash_ref->{content}->{'default'} : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "fence_data::${fence_agent}::parameters::${name}::default" => $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{'default'}, }}); } elsif ($anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{content_type} eq "integer") { # Nothing to collect here. $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{'default'} = exists $hash_ref->{content}->{'default'} ? $hash_ref->{content}->{'default'} : "";; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "fence_data::${fence_agent}::parameters::${name}::default" => $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{'default'}, }}); } # If this obsoletes another parameter, mark it as such. $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{replacement} = "" if not exists $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{replacement}; if ($obsoletes) { $anvil->data->{fence_data}{$fence_agent}{parameters}{$obsoletes}{replacement} = $name; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "fence_data::${fence_agent}::parameters::${obsoletes}::replacement" => $anvil->data->{fence_data}{$fence_agent}{parameters}{$obsoletes}{replacement}, }}); } } $anvil->data->{fence_data}{$fence_agent}{actions} = []; foreach my $hash_ref (@{$agent_ref->{'resource-agent'}->{actions}{action}}) { push @{$anvil->data->{fence_data}{$fence_agent}{actions}}, $hash_ref->{name}; } foreach my $action (sort {$a cmp $b} @{$anvil->data->{fence_data}{$fence_agent}{actions}}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { action => $action }}); } } # ScanCore will load this to check nodes that are not accessible. To reduce load, as this is an # expensive call, this time is set so a caller can decide if the data should be updated. $anvil->data->{sys}{fence_data_updated} = time; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::fence_data_updated" => $anvil->data->{sys}{fence_data_updated}, }}); return(0); } =head2 get_local_repo This builds the body of an RPM repo for the local machine. If, for some reason, this machine can't be used as a repo, an empty string will be returned. The method takes no paramters. =cut sub get_local_repo { my $self = shift; my $parameter = shift; my $anvil = $self->parent; my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Striker->get_local_repo()" }}); # What is the repo directory? my $document_root = ""; my $httpd_conf = $anvil->Storage->read_file({file => $anvil->data->{path}{data}{httpd_conf} }); foreach my $line (split/\n/, $httpd_conf) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }}); if ($line =~ /^DocumentRoot\s+"(\/.*?)"/) { $document_root = $1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { document_root => $document_root }}); last; } } $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { document_root => $document_root }}); if (not $document_root) { # Problem with apache. return(""); } $anvil->Storage->scan_directory({ debug => $debug, directory => $document_root, recursive => 1, no_files => 1, search_for => "repodata", }); my $directory = ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "scan::searched" => $anvil->data->{scan}{searched} }}); if ($anvil->data->{scan}{searched}) { $directory = $anvil->data->{scan}{searched}; $directory =~ s/^$document_root//; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { directory => $directory }}); } $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { directory => $directory }}); if (not $directory) { # No repo found. return(""); } # What are my IPs? $anvil->Network->get_ips(); my $base_url = ""; my $host = $anvil->Get->short_host_name(); foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{$host}{interface}}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { interface => $interface }}); if ($anvil->data->{network}{$host}{interface}{$interface}{ip}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "network::local::interface::${interface}::ip" => $anvil->data->{network}{$host}{interface}{$interface}{ip} }}); if (not $base_url) { $base_url = "baseurl=http://".$anvil->data->{network}{$host}{interface}{$interface}{ip}.$directory; } else { $base_url .= "\n http://".$anvil->data->{network}{$host}{interface}{$interface}{ip}.$directory; } } } $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { base_url => $base_url }}); ### NOTE: The 'module_hotfixes=1' is needed until we can figure out how to add libssh2 to ### 'modules.yaml' (from the RHEL 8.x repodata). See: ### - https://docs.fedoraproject.org/en-US/modularity/making-modules/defining-modules/ ### - https://docs.fedoraproject.org/en-US/modularity/hosting-modules/ # Create the local repo file body my $repo = "[".$anvil->Get->short_host_name."-repo] name=Repo on ".$anvil->Get->host_name." ".$base_url." enabled=1 gpgcheck=0 timeout=5 skip_if_unavailable=1 module_hotfixes=1"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { repo => $repo }}); return($repo); } =head2 get_peer_data This calls the C<< call_striker-get-peer-data >> program to try to connect to the target (as C<< root >>). This method returns a string variable and a hash reference. The string variable will be C<< 1 >> if we connected successfully, C<< 0 >> if not. The hash reference will contain parsed details about the peer, assuming it connected. If the connection failed, the hash reference will exist but the values will be empty. Keys in the hash; * C<< host_uuid >> - The host's UUID. * C<< host_name >> - The host's current (static) host name. * C<< host_os >> - This is the host's operating system and version. The OS is returned as C<< rhel >> or C<< centos >>. The version is returned as C<< 8.x >>. * C<< internet >> - This indicates if the target was found to have a a working Internet connection. * C<< os_registered >> - This indicates if the OS is registered with Red Hat (if the OS is C<< rhel >>). It will be C<< yes >>, C<< no >> or C<< unknown >>. my ($connected, $data) = $anvil->Striker->get_peer_data({target => 10.255.1.218, password => "Initial1"}); if ($connected) { print "Hostname: [".$data->{host_name}."], host UUID: [".$data->{host_uuid}."]\n"; } Parameters; =head3 password (required) This is the target machine's C<< root >> password. =head3 port (optional, default 22) This is the TCP port to use when connecting to the target =head3 target (required, IPv4 address) This is the current IP address of the target machine. =cut sub get_peer_data { my $self = shift; my $parameter = shift; my $anvil = $self->parent; my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Striker->get_peer_data()" }}); my $target = defined $parameter->{target} ? $parameter->{target} : ""; my $password = defined $parameter->{password} ? $parameter->{password} : ""; my $port = defined $parameter->{port} ? $parameter->{port} : 22; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { target => $target, password => $anvil->Log->is_secure($password), port => $port, }}); # Store the password. my $connected = 0; my $data = { host_uuid => "", host_name => "", host_os => "", internet => 0, os_registered => "", }; if (not $target) { # No target... $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Striker->get_peer_data()", parameter => "target" }}); return($connected, $data); } # Record the password in the database so that we don't pass it over the command line. my $state_uuid = $anvil->Database->insert_or_update_states({ debug => $debug, file => $THIS_FILE, line => __LINE__, state_name => "peer::".$target."::password", state_note => $password, uuid => $anvil->data->{sys}{host_uuid}, # Only write to our DB, no reason to store elsewhere }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { state_uuid => $state_uuid }}); my ($output, $return_code) = $anvil->System->call({ debug => $debug, shell_call => $anvil->data->{path}{exe}{'call_striker-get-peer-data'}." --target root\@".$target.":".$port." --state-uuid ".$state_uuid, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { output => $output, return_code => $return_code, }}); # Pull out the details foreach my $line (split/\n/, $output) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }}); if ($line =~ /connected=(.*)$/) { # We collect this, but apparently not for any real reason... $connected = $1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { connected => $connected }}); } if ($line =~ /host_name=(.*)$/) { # We collect this, but apparently not for any real reason... $data->{host_name} = $1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'data->{host_name}' => $data->{host_name} }}); } if ($line =~ /host_uuid=(.*)$/) { $data->{host_uuid} = $1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'data->{host_uuid}' => $data->{host_uuid} }}); } if ($line =~ /host_os=(.*)$/) { $data->{host_os} = $1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'data->{host_os}' => $data->{host_os} }}); } if ($line =~ /os_registered=(.*)$/) { $data->{os_registered} = $1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'data->{os_registered}' => $data->{os_registered} }}); } if ($line =~ /internet=(.*)$/) { $data->{internet} = $1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'data->{internet}' => $data->{internet} }}); } } $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { connected => $connected, 'data->{host_name}' => $data->{host_name}, 'data->{host_uuid}' => $data->{host_uuid}, 'data->{host_os}' => $data->{host_os}, 'data->{internet}' => $data->{internet}, 'data->{os_registered}' => $data->{os_registered}, }}); # Make sure the database entry is gone (striker-get-peer-data should have removed it, but lets be safe). my $query = "DELETE FROM states WHERE state_name = ".$anvil->Database->quote("peer::".$target."::password").";"; $anvil->Database->write({uuid => $anvil->data->{sys}{host_uuid}, debug => 3, query => $query, source => $THIS_FILE, line => __LINE__}); # Verify that the host UUID is actually valid. if (not $anvil->Validate->uuid({uuid => $data->{host_uuid}})) { $data->{host_uuid} = ""; } return($connected, $data); } =head2 get_ups_data This parses the special C<< ups_X >> string keys to create a list of supported UPSes (in ScanCore and Install Manifests). Parsed data is stored in; * C<< ups_data::::agent >> * C<< ups_data::::brand >> * C<< ups_data::::description >> The language used is the language returned by C<< Words->language() >>. This method takes no parameters. =cut sub get_ups_data { my $self = shift; my $parameter = shift; my $anvil = $self->parent; my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Striker->get_ups_data()" }}); # In case we've loaded the data before, clear it. if (exists $anvil->data->{ups_data}) { delete $anvil->data->{ups_data}; } my $language = $anvil->Words->language(); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { language => $language }}); foreach my $word_file (sort {$a cmp $b} keys %{$anvil->data->{words}}) { # Now loop through all keys looking for 'ups_*'. foreach my $key (sort {$a cmp $b} keys %{$anvil->data->{words}{$word_file}{language}{$language}{key}}) { next if $key !~ /^ups_(\d+)/; # If we're here, we've got a UPS. my $description = $anvil->data->{words}{$word_file}{language}{$language}{key}{$key}{content}; my $brand = $anvil->data->{words}{$word_file}{language}{$language}{key}{$key}{brand}; my $agent = $anvil->data->{words}{$word_file}{language}{$language}{key}{$key}{agent}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 's1:brand' => $brand, 's2:agent' => $agent, 's3:description' => $description, }}); $anvil->data->{ups_data}{$key}{agent} = $agent; $anvil->data->{ups_data}{$key}{brand} = $brand; $anvil->data->{ups_data}{$key}{description} = $description; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "s1:ups_data::${key}::agent" => $anvil->data->{ups_data}{$key}{agent}, "s2:ups_data::${key}::brand" => $anvil->data->{ups_data}{$key}{brand}, "s3:ups_data::${key}::description" => $anvil->data->{ups_data}{$key}{description}, }}); # Make it easy to convert the agent to the brand. $anvil->data->{ups_agent}{$agent}{brand} = $brand; $anvil->data->{ups_agent}{$agent}{key} = $key; $anvil->data->{ups_agent}{$agent}{description} = $description; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "ups_agent::${agent}::brand" => $anvil->data->{ups_agent}{$agent}{brand}, "ups_agent::${agent}::key" => $anvil->data->{ups_agent}{$agent}{key}, "ups_agent::${agent}::description" => $anvil->data->{ups_agent}{$agent}{description}, }}); } } return(0); } =head2 load_manifest This takes a manifest UUID and loads and parses it. If the manifest is loaded, C<< 0 >> is returned. C<< 1 >> is returned on error. The loaded data is stored in a hash as: manifests::manifest_uuid::::manifest_name = manifests::manifest_uuid::::manifest_last_ran = manifests::manifest_uuid::::manifest_xml = manifests::manifest_uuid::::manifest_note = manifests::manifest_uuid::::modified_date = The following hash is used to facilitate manifest name to UUID look up. manifests::name_to_uuid:: = The parsed manifest XML is stored as ( == node1, node2 or dr1): manifests::manifest_uuid::::parsed::name = manifests::manifest_uuid::::parsed::domain = manifests::manifest_uuid::::parsed::prefix = manifests::manifest_uuid::::parsed::sequence = manifests::manifest_uuid::::parsed::upses::::uuid = ups_uuid of named UPS> manifests::manifest_uuid::::parsed::fences::::uuid = fence_uuid of named fence device> manifests::manifest_uuid::::parsed::networks::dns = manifests::manifest_uuid::::parsed::networks::ntp = manifests::manifest_uuid::::parsed::networks::mtu = manifests::manifest_uuid::::parsed::networks::count::bcn = manifests::manifest_uuid::::parsed::networks::count::sn = manifests::manifest_uuid::::parsed::networks::count::ifn = manifests::manifest_uuid::::parsed::networks::name::::network = manifests::manifest_uuid::::parsed::networks::name::::subnet = manifests::manifest_uuid::::parsed::networks::name::::gateway = manifests::manifest_uuid::::parsed::machine::::name = manifests::manifest_uuid::::parsed::machine::::ipmi_ip = manifests::manifest_uuid::::parsed::machine::::fence::::port = <'port' name/number (see fence agent man page) manifests::manifest_uuid::::parsed::machine::::ups::::used = <1 if powered by USB, 0 if not> manifests::manifest_uuid::::parsed::machine::::network::::ip = B: The machines to use in each role is selected when the manifest is run. Unlike in M2, the manifest does not store machine-specific information (like MAC addresses, etc). The chosen machines at run time contain that information. Similarly, passwords are NOT stored in the manifest, and passed when the manifest is run. Parameters; =head3 manifest_uuid (required) This is the manifest UUID to load. =cut sub load_manifest { my $self = shift; my $parameter = shift; my $anvil = $self->parent; my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Striker->load_manifest()" }}); my $manifest_uuid = defined $parameter->{manifest_uuid} ? $parameter->{manifest_uuid} : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { manifest_uuid => $manifest_uuid, }}); if (not $manifest_uuid) { # Didn't get a UUID $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Striker->load_manifest()", parameter => "manifest_uuid" }}); return(1); } elsif (not $anvil->Validate->uuid({uuid => $manifest_uuid})) { # UUID isn't valid $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0130", variables => { method => "Striker->load_manifest()", parameter => "manifest_uuid", uuid => $manifest_uuid}}); return(1); } my $query = " SELECT manifest_name, manifest_last_ran, manifest_xml, manifest_note, ROUND(extract(epoch FROM modified_date)) FROM manifests WHERE manifest_uuid = ".$anvil->Database->quote($manifest_uuid)." ;"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); my $count = @{$results}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { results => $results, count => $count, }}); my $manifest_template = ""; if ($count) { my $manifest_name = $results->[0]->[0]; my $manifest_last_ran = $results->[0]->[1]; my $manifest_xml = $results->[0]->[2]; my $manifest_note = $results->[0]->[3]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { manifest_name => $manifest_name, manifest_last_ran => $manifest_last_ran, manifest_xml => $manifest_xml, manifest_note => $manifest_note, }}); # Record the data. $anvil->data->{manifests}{$manifest_uuid}{manifest_name} = $manifest_name; $anvil->data->{manifests}{$manifest_uuid}{manifest_last_ran} = $manifest_last_ran; $anvil->data->{manifests}{$manifest_uuid}{manifest_xml} = $manifest_xml; $anvil->data->{manifests}{$manifest_uuid}{manifest_note} = $manifest_note; $anvil->data->{manifests}{name_to_uuid}{$manifest_name} = $manifest_uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "manifests::${manifest_uuid}::manifest_name" => $anvil->data->{manifests}{$manifest_uuid}{manifest_name}, "manifests::${manifest_uuid}::manifest_last_ran" => $anvil->data->{manifests}{$manifest_uuid}{manifest_last_ran}, "manifests::${manifest_uuid}::manifest_xml" => $anvil->data->{manifests}{$manifest_uuid}{manifest_xml}, "manifests::${manifest_uuid}::manifest_note" => $anvil->data->{manifests}{$manifest_uuid}{manifest_note}, "manifests::name_to_uuid::${manifest_name}" => $anvil->data->{manifests}{name_to_uuid}{$manifest_name}, }}); # Whoever is calling us will want the fence data, so load it as well. $anvil->Database->get_fences({debug => $debug}); # Parse the XML. local $@; my $parsed_xml = ""; my $xml = XML::Simple->new(); my $test = eval { $parsed_xml = $xml->XMLin($manifest_xml, KeyAttr => { key => 'name' }, ForceArray => []) }; if (not $test) { chomp $@; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0111", variables => { xml_body => $manifest_xml, eval_error => $@, }}); return(1); } $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{domain} = $parsed_xml->{domain}; $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{name} = $parsed_xml->{name}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "manifests::manifest_uuid::${manifest_uuid}::parsed::domain" => $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{domain}, "manifests::manifest_uuid::${manifest_uuid}::parsed::name" => $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{name}, }}); my ($prefix, $sequence) = ($anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{name} =~ /^(.*?)-anvil-(\d+)$/); $sequence = sprintf("%02d", $sequence); $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{prefix} = $prefix; $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{sequence} = $sequence; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "manifests::manifest_uuid::${manifest_uuid}::parsed::prefix" => $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{prefix}, "manifests::manifest_uuid::${manifest_uuid}::parsed::sequence" => $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{sequence}, }}); if (ref($parsed_xml->{upses}{ups}) eq "HASH") { # Only a single ups device my $ups_name = $parsed_xml->{upses}{ups}{name}; $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{upses}{$ups_name}{uuid} = $parsed_xml->{upses}{ups}{uuid}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "manifests::manifest_uuid::${manifest_uuid}::parsed::upses::${ups_name}::uuid" => $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{upses}{$ups_name}{uuid}, }}); } elsif (ref($parsed_xml->{fences}{fence}) eq "ARRAY") { # Two or more UPSes foreach my $hash_ref (@{$parsed_xml->{upses}{ups}}) { my $ups_name = $hash_ref->{name}; $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{upses}{$ups_name}{uuid} = $hash_ref->{uuid}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "manifests::manifest_uuid::${manifest_uuid}::parsed::upses::${ups_name}::uuid" => $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{upses}{$ups_name}{uuid}, }}); } } if (ref($parsed_xml->{fences}{fence}) eq "HASH") { # Only a single fence device my $fence_name = $parsed_xml->{fences}{fence}{name}; $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{fences}{$fence_name}{uuid} = $parsed_xml->{fences}{fence}{uuid}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "manifests::manifest_uuid::${manifest_uuid}::parsed::fences::${fence_name}::uuid" => $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{fences}{$fence_name}{uuid}, }}); } elsif (ref($parsed_xml->{fences}{fence}) eq "ARRAY") { # Two or more fence devices. foreach my $hash_ref (@{$parsed_xml->{fences}{fence}}) { my $fence_name = $hash_ref->{name}; $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{fences}{$fence_name}{uuid} = $hash_ref->{uuid}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "manifests::manifest_uuid::${manifest_uuid}::parsed::fences::${fence_name}::uuid" => $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{fences}{$fence_name}{uuid}, }}); } } $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{dns} = $parsed_xml->{networks}{dns}; $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{ntp} = $parsed_xml->{networks}{ntp}; $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{mtu} = $parsed_xml->{networks}{mtu}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "manifests::manifest_uuid::${manifest_uuid}::parsed::networks::dns" => $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{dns}, "manifests::manifest_uuid::${manifest_uuid}::parsed::networks::ntp" => $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{ntp}, "manifests::manifest_uuid::${manifest_uuid}::parsed::networks::mtu" => $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{mtu}, }}); my $bcn_count = 0; my $sn_count = 0; my $ifn_count = 0; foreach my $hash_ref (@{$parsed_xml->{networks}{network}}) { my $network_name = $hash_ref->{name}; $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{name}{$network_name}{network} = $hash_ref->{network}; $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{name}{$network_name}{subnet} = $hash_ref->{subnet}; $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{name}{$network_name}{gateway} = $hash_ref->{gateway}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "manifests::manifest_uuid::${manifest_uuid}::parsed::networks::name::${network_name}::network" => $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{name}{$network_name}{network}, "manifests::manifest_uuid::${manifest_uuid}::parsed::networks::name::${network_name}::subnet" => $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{name}{$network_name}{subnet}, "manifests::manifest_uuid::${manifest_uuid}::parsed::networks::name::${network_name}::gateway" => $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{name}{$network_name}{gateway}, }}); if ($network_name =~ /^bcn/) { $bcn_count++; } elsif ($network_name =~ /^sn/) { $sn_count++; } elsif ($network_name =~ /^ifn/) { $ifn_count++; } } $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{count}{bcn} = $bcn_count; $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{count}{sn} = $sn_count; $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{count}{ifn} = $ifn_count; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "manifests::manifest_uuid::${manifest_uuid}::parsed::networks::count::bcn" => $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{count}{bcn}, "manifests::manifest_uuid::${manifest_uuid}::parsed::networks::count::sn" => $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{count}{sn}, "manifests::manifest_uuid::${manifest_uuid}::parsed::networks::count::ifn" => $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{count}{ifn}, }}); foreach my $machine (sort {$a cmp $b} keys %{$parsed_xml->{machines}}) { $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine}{name} = $parsed_xml->{machines}{$machine}{name}; $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine}{ipmi_ip} = defined $parsed_xml->{machines}{$machine}{ipmi_ip} ? $parsed_xml->{machines}{$machine}{ipmi_ip} : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "manifests::manifest_uuid::${manifest_uuid}::parsed::machine::${machine}::name" => $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine}{name}, "manifests::manifest_uuid::${manifest_uuid}::parsed::machine::${machine}::ipmi_ip" => $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine}{ipmi_ip}, }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "ref(parsed_xml->{machines}{$machine}{upses}{ups})" => ref($parsed_xml->{machines}{$machine}{upses}{ups}), }}); if (ref($parsed_xml->{machines}{$machine}{upses}{ups}) eq "HASH") { my $ups_name = $parsed_xml->{machines}{$machine}{upses}{ups}{name}; $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine}{ups}{$ups_name}{used} = $parsed_xml->{machines}{$machine}{upses}{ups}{used}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "manifests::manifest_uuid::${manifest_uuid}::parsed::machine::${machine}::ups::${ups_name}::used" => $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine}{ups}{$ups_name}{used}, }}); } elsif (ref($parsed_xml->{machines}{$machine}{upses}{ups}) eq "ARRAY") { foreach my $hash_ref (@{$parsed_xml->{machines}{$machine}{upses}{ups}}) { my $ups_name = $hash_ref->{name}; $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine}{ups}{$ups_name}{used} = $hash_ref->{used}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "manifests::manifest_uuid::${manifest_uuid}::parsed::machine::${machine}::ups::${ups_name}::used" => $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine}{ups}{$ups_name}{used}, }}); } } $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "ref(parsed_xml->{machines}{$machine}{fences}{fence})" => ref($parsed_xml->{machines}{$machine}{fences}{fence}), }}); if (ref($parsed_xml->{machines}{$machine}{fences}{fence}) eq "HASH") { my $fence_name = $parsed_xml->{machines}{$machine}{fences}{fence}{name}; $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine}{fence}{$fence_name}{port} = $parsed_xml->{machines}{$machine}{fences}{fence}{port}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "manifests::manifest_uuid::${manifest_uuid}::parsed::machine::${machine}::fence::${fence_name}::port" => $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine}{fence}{$fence_name}{port}, }}); } elsif (ref($parsed_xml->{machines}{$machine}{fences}{fence}) eq "ARRAY") { foreach my $hash_ref (@{$parsed_xml->{machines}{$machine}{fences}{fence}}) { my $fence_name = $hash_ref->{name}; $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine}{fence}{$fence_name}{port} = $hash_ref->{port}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "manifests::manifest_uuid::${manifest_uuid}::parsed::machine::${machine}::fence::${fence_name}::port" => $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine}{fence}{$fence_name}{port}, }}); } } foreach my $hash_ref (@{$parsed_xml->{machines}{$machine}{networks}{network}}) { my $network_name = $hash_ref->{name}; $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine}{network}{$network_name}{ip} = $hash_ref->{ip}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "manifests::manifest_uuid::${manifest_uuid}::parsed::machine::${machine}::network::${network_name}::ip" => $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine}{network}{$network_name}{ip}, }}); } } } else { # Not found. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "warning_0042", variables => { table => "manifests", column => "manifest_uuid", value => $manifest_uuid, }}); return(1); } return(0); } =head2 parse_all_status_json This parses the c<< all_status.json >> file is a way that Striker can more readily use. If the read or parse failes, C<< 1 >> is returned. Otherwise C<< 0 >> is returned. This method doesn't take any parameters. =cut sub parse_all_status_json { my $self = shift; my $parameter = shift; my $anvil = $self->parent; my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Striker->parse_all_status_json()" }}); # Read it in my $json_file = $anvil->data->{path}{directories}{status}."/".$anvil->data->{path}{json}{all_status}; if (not -e $json_file) { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0105", variables => { file => $json_file }}); return(1); } my $body = $anvil->Storage->read_file({debug => $debug, file => $json_file}); if ($body eq "!!error!!") { return(1); } my $json = JSON->new->allow_nonref; my $data = $json->decode($body); if (exists $anvil->data->{json}{all_status}) { delete $anvil->data->{json}{all_status}; } # We're going to look for matches as we go, so look $anvil->Network->load_ips({ debug => $debug, host => $anvil->Get->short_host_name(), host_uuid => $anvil->data->{sys}{host_uuid}, }); # We'll be adding data to this JSON file over time. So this will be an ever evolving method. foreach my $host_hash (@{$data->{hosts}}) { my $host_name = $host_hash->{name}; my $short_name = $host_hash->{short_name}; $anvil->data->{json}{all_status}{hosts}{$host_name}{host_uuid} = $host_hash->{host_uuid}; $anvil->data->{json}{all_status}{hosts}{$host_name}{type} = $host_hash->{type}; $anvil->data->{json}{all_status}{hosts}{$host_name}{short_host_name} = $host_hash->{short_name}; $anvil->data->{json}{all_status}{hosts}{$host_name}{configured} = $host_hash->{configured}; $anvil->data->{json}{all_status}{hosts}{$host_name}{ssh_fingerprint} = $host_hash->{ssh_fingerprint}; $anvil->data->{json}{all_status}{hosts}{$host_name}{matched_interface} = $host_hash->{matched_interface}; $anvil->data->{json}{all_status}{hosts}{$host_name}{matched_ip_address} = $host_hash->{matched_ip_address}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "json::all_status::hosts::${host_name}::host_uuid" => $anvil->data->{json}{all_status}{hosts}{$host_name}{host_uuid}, "json::all_status::hosts::${host_name}::type" => $anvil->data->{json}{all_status}{hosts}{$host_name}{type}, "json::all_status::hosts::${host_name}::short_host_name" => $anvil->data->{json}{all_status}{hosts}{$host_name}{short_host_name}, "json::all_status::hosts::${host_name}::configured" => $anvil->data->{json}{all_status}{hosts}{$host_name}{configured}, "json::all_status::hosts::${host_name}::ssh_fingerprint" => $anvil->data->{json}{all_status}{hosts}{$host_name}{ssh_fingerprint}, "json::all_status::hosts::${host_name}::matched_interface" => $anvil->data->{json}{all_status}{hosts}{$host_name}{matched_interface}, "json::all_status::hosts::${host_name}::matched_ip_address" => $anvil->data->{json}{all_status}{hosts}{$host_name}{matched_ip_address}, }}); # Find what interface on this host we can use to talk to it (if we're not looking at ourselves). my $matched_interface = ""; my $matched_ip_address = ""; if ($host_name ne $anvil->Get->host_name) { $anvil->Network->load_ips({ debug => $debug, host => $short_name, host_uuid => $anvil->data->{json}{all_status}{hosts}{$host_name}{host_uuid}, }); my ($match) = $anvil->Network->find_matches({ debug => 3, first => $anvil->Get->short_host_name(), second => $short_name, source => $THIS_FILE, line => __LINE__, }); if ($match) { # Yup! my $match_found = 0; foreach my $interface (sort {$a cmp $b} keys %{$match->{$short_name}}) { $matched_interface = $interface; $matched_ip_address = $match->{$short_name}{$interface}{ip_address}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { matched_interface => $matched_interface, matched_ip_address => $matched_ip_address, }}); last; } } } $anvil->data->{json}{all_status}{hosts}{$host_name}{matched_interface} = $matched_interface; $anvil->data->{json}{all_status}{hosts}{$host_name}{matched_ip_address} = $matched_ip_address; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "json::all_status::hosts::${host_name}::matched_interface" => $anvil->data->{json}{all_status}{hosts}{$host_name}{matched_interface}, "json::all_status::hosts::${host_name}::matched_ip_address" => $anvil->data->{json}{all_status}{hosts}{$host_name}{matched_ip_address}, }}); foreach my $interface_hash (@{$host_hash->{network_interfaces}}) { my $interface_name = $interface_hash->{name}; my $interface_type = $interface_hash->{type}; my $mac_address = $interface_hash->{mac_address}; my $ip_address = $interface_hash->{ip_address}; my $subnet_mask = $interface_hash->{subnet_mask}; my $default_gateway = $interface_hash->{default_gateway}; my $gateway = $interface_hash->{gateway}; my $dns = $interface_hash->{dns}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { interface_name => $interface_name, interface_type => $interface_type, mac_address => $mac_address, ip_address => $ip_address, subnet_mask => $subnet_mask, default_gateway => $default_gateway, gateway => $gateway, dns => $dns, }}); # This lets us easily map interface names to types. $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface_name_to_type}{$interface_name} = $interface_type; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "json::all_status::hosts::${host_name}::network_interface_name_to_type::${interface_name}" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface_name_to_type}{$interface_name}, }}); # Record the rest of the data. $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{uuid} = $interface_hash->{uuid}; $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{mtu} = $interface_hash->{mtu}; $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{mac_address} = $interface_hash->{mac_address}; $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{ip_address} = $interface_hash->{ip_address}; $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{subnet_mask} = $interface_hash->{subnet_mask}; $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{default_gateway} = $interface_hash->{default_gateway}; $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{gateway} = $interface_hash->{gateway}; $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{dns} = $interface_hash->{dns}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::uuid" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{uuid}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::mtu" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{mtu}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::mac_address" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{mac_address}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::ip_address" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{ip_address}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::subnet_mask" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{subnet_mask}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::default_gateway" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{default_gateway}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::gateway" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{gateway}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::dns" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{dns}, }}); if ((exists $interface_hash->{connected_interfaces}) && (ref($interface_hash->{connected_interfaces}) eq "ARRAY")) { my $connected_interfaces_count = @{$interface_hash->{connected_interfaces}}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { connected_interfaces_count => $connected_interfaces_count }}); foreach my $connected_interface_name (sort {$a cmp $b} @{$interface_hash->{connected_interfaces}}) { # We'll sort out the types after $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{connected_interfaces}{$connected_interface_name}{type} = ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::connected_interfaces::${connected_interface_name}::type" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{connected_interfaces}{$connected_interface_name}{type}, }}); } } if ($interface_type eq "bridge") { $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{bridge_id} = $interface_hash->{bridge_id}; $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{stp_enabled} = $interface_hash->{stp_enabled}; my $say_stp_enabled = $interface_hash->{stp_enabled}; if (($say_stp_enabled eq "0") or ($say_stp_enabled eq "disabled")) { $say_stp_enabled = $anvil->Words->string({key => "unit_0020"}); } elsif (($say_stp_enabled eq "1") or ($say_stp_enabled eq "enabled_kernel")) { $say_stp_enabled = $anvil->Words->string({key => "unit_0021"}); } elsif (($say_stp_enabled eq "2") or ($say_stp_enabled eq "enabled_userland")) { $say_stp_enabled = $anvil->Words->string({key => "unit_0022"}); } $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{say_stp_enabled} = $interface_hash->{say_stp_enabled}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::bridge_id" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{bridge_id}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::stp_enabled" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{stp_enabled}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::say_stp_enabled" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{say_stp_enabled}, }}); } elsif ($interface_type eq "bond") { $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{mode} = $interface_hash->{mode}; $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{active_interface} = $interface_hash->{active_interface}; $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{primary_interface} = $interface_hash->{primary_interface}; $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{primary_reselect} = $interface_hash->{primary_reselect}; $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{up_delay} = $interface_hash->{up_delay}; $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{down_delay} = $interface_hash->{down_delay}; $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{operational} = $interface_hash->{operational}; $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{mii_polling_interval} = $interface_hash->{mii_polling_interval}." ".$anvil->Words->string({key => "suffix_0012"}); $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{bridge_uuid} = $interface_hash->{bridge_uuid}; $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{bridge_name} = $interface_hash->{bridge_name}; # Translate some values my $say_mode = $interface_hash->{mode}; if (($say_mode eq "0") or ($say_mode eq "balance-rr")) { $say_mode = $anvil->Words->string({key => "unit_0006"}); } elsif (($say_mode eq "1") or ($say_mode eq "active-backup")) { $say_mode = $anvil->Words->string({key => "unit_0007"}); } elsif (($say_mode eq "2") or ($say_mode eq "balanced-xor")) { $say_mode = $anvil->Words->string({key => "unit_0008"}); } elsif (($say_mode eq "3") or ($say_mode eq "broadcast")) { $say_mode = $anvil->Words->string({key => "unit_0009"}); } elsif (($say_mode eq "4") or ($say_mode eq "802.3ad")) { $say_mode = $anvil->Words->string({key => "unit_0010"}); } elsif (($say_mode eq "5") or ($say_mode eq "balanced-tlb")) { $say_mode = $anvil->Words->string({key => "unit_0011"}); } elsif (($say_mode eq "6") or ($say_mode eq "balanced-alb")) { $say_mode = $anvil->Words->string({key => "unit_0012"}); } my $say_operational = $interface_hash->{operational}; if ($say_operational eq "up") { $say_operational = $anvil->Words->string({key => "unit_0001"}); } elsif ($say_operational eq "down") { $say_operational = $anvil->Words->string({key => "unit_0002"}); } elsif ($say_operational eq "unknown") { $say_operational = $anvil->Words->string({key => "unit_0004"}); } my $say_primary_reselect = $interface_hash->{primary_reselect}; if (($say_primary_reselect eq "always") or ($say_primary_reselect eq "0")) { $say_primary_reselect = $anvil->Words->string({key => "unit_0017"}); } elsif (($say_primary_reselect eq "better") or ($say_primary_reselect eq "1")) { $say_primary_reselect = $anvil->Words->string({key => "unit_0018"}); } elsif (($say_primary_reselect eq "failure") or ($say_primary_reselect eq "2")) { $say_primary_reselect = $anvil->Words->string({key => "unit_0019"}); } $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{say_up_delay} = $interface_hash->{up_delay}." ".$anvil->Words->string({key => "suffix_0012"}); $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{say_down_delay} = $interface_hash->{say_down_delay}." ".$anvil->Words->string({key => "suffix_0012"}); $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{say_mode} = $say_mode; $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{say_operational} = $say_operational; $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{say_primary_reselect} = $say_primary_reselect; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::mode" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{mode}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::active_interface" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{active_interface}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::primary_interface" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{primary_interface}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::primary_reselect" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{primary_reselect}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::up_delay" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{up_delay}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::down_delay" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{down_delay}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::operational" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{operational}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::mii_polling_interval" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{mii_polling_interval}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::bridge_uuid" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{bridge_uuid}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::bridge_name" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{bridge_name}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::say_up_delay" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{say_up_delay}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::say_down_delay" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{say_down_delay}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::say_mode" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{say_mode}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::say_operational" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{say_operational}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::say_primary_reselect" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{say_primary_reselect}, }}); } else { $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{speed} = $interface_hash->{speed}; $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{link_state} = $interface_hash->{link_state}; $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{operational} = $interface_hash->{operational}; $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{duplex} = $interface_hash->{duplex}; $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{medium} = $interface_hash->{medium}; $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{bond_uuid} = $interface_hash->{bond_uuid}; $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{bond_name} = $interface_hash->{bond_name}; $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{bridge_uuid} = $interface_hash->{bridge_uuid}; $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{bridge_name} = $interface_hash->{bridge_name}; $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{changed_order} = $interface_hash->{changed_order}; my $say_speed = $anvil->Convert->add_commas({number => $interface_hash->{speed}})." ".$anvil->Words->string({key => "suffix_0050"}); if ($interface_hash->{speed} >= 1000) { # Report in Gbps $say_speed = $anvil->Convert->add_commas({number => ($interface_hash->{speed} / 1000)})." ".$anvil->Words->string({key => "suffix_0051"}); } my $say_duplex = $interface_hash->{duplex}; if ($say_duplex eq "full") { $say_duplex = $anvil->Words->string({key => "unit_0015"}); } elsif ($say_duplex eq "half") { $say_duplex = $anvil->Words->string({key => "unit_0016"}); } elsif ($say_duplex eq "unknown") { $say_duplex = $anvil->Words->string({key => "unit_0004"}); } my $say_link_state = $interface_hash->{link_state}; if ($say_link_state eq "1") { $say_link_state = $anvil->Words->string({key => "unit_0013"}); } elsif ($say_link_state eq "0") { $say_link_state = $anvil->Words->string({key => "unit_0014"}); } my $say_operational = $interface_hash->{operational}; if ($say_operational eq "up") { $say_operational = $anvil->Words->string({key => "unit_0013"}); } elsif ($say_operational eq "down") { $say_operational = $anvil->Words->string({key => "unit_0014"}); } elsif ($say_operational eq "unknown") { $say_operational = $anvil->Words->string({key => "unit_0004"}); } # This will be flushed out later. For now, we just send out what we've got. my $say_medium = $interface_hash->{medium}; $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{say_speed} = $say_speed; $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{say_duplex} = $say_duplex; $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{say_link_state} = $say_link_state; $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{say_operationa} = $say_operational; $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{say_medium} = $say_medium; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::speed" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{speed}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::link_state" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{link_state}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::operational" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{operational}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::duplex" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{duplex}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::medium" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{medium}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::bond_uuid" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{bond_uuid}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::bond_name" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{bond_name}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::bridge_uuid" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{bridge_uuid}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::bridge_name" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{bridge_name}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::changed_order" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{changed_order}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::say_speed" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{say_speed}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::say_duplex" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{say_duplex}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::say_link_state" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{say_link_state}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::say_operationa" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{say_operationa}, "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::say_medium" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{say_medium}, }}); } } } foreach my $host_name (sort {$a cmp $b} keys %{$anvil->data->{json}{all_status}{hosts}}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_name => $host_name }}); foreach my $interface_type (sort {$a cmp $b} keys %{$anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { interface_type => $interface_type }}); foreach my $interface_name (sort {$a cmp $b} keys %{$anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { interface_name => $interface_name }}); foreach my $connected_interface_name (sort {$a cmp $b} keys %{$anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{connected_interfaces}}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { connected_interface_name => $connected_interface_name }}); if (defined $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface_name_to_type}{$connected_interface_name}) { $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{connected_interfaces}{$connected_interface_name}{type} = $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface_name_to_type}{$connected_interface_name}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "json::all_status::hosts::${host_name}::network_interface::${interface_type}::${interface_name}::connected_interfaces::${connected_interface_name}::type" => $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{$interface_type}{$interface_name}{connected_interfaces}{$connected_interface_name}{type}, }}); } } } } } return(0); } 1;