diff --git a/Anvil/Tools.pm b/Anvil/Tools.pm index 3e39c7e7..dd3aacb0 100644 --- a/Anvil/Tools.pm +++ b/Anvil/Tools.pm @@ -1189,6 +1189,7 @@ sub _set_paths stonith_admin => "/usr/sbin/stonith_admin", storcli64 => "/opt/MegaRAID/storcli/storcli64", strings => "/usr/bin/strings", + 'striker-auto-initialize-all' => "/usr/sbin/striker-auto-initialize-all", 'striker-get-peer-data' => "/usr/sbin/striker-get-peer-data", 'striker-initialize-host' => "/usr/sbin/striker-initialize-host", 'striker-manage-install-target' => "/usr/sbin/striker-manage-install-target", diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index 1d9bc06b..96e9d6ee 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -3208,33 +3208,33 @@ WHERE my $job_status = $results->[0]->[10]; my $modified_date = $results->[0]->[11]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - job_host_uuid => $job_host_uuid, - job_command => $job_command, - job_data => $job_data, - job_picked_up_by => $job_picked_up_by, - job_picked_up_at => $job_picked_up_at, - job_updated => $job_updated, - job_name => $job_name, - job_progress => $job_progress, - job_title => $job_title, - job_description => $job_description, - job_status => $job_status, - modified_date => $modified_date, + job_host_uuid => $job_host_uuid, + job_command => $job_command, + job_data => $job_data, + job_picked_up_by => $job_picked_up_by, + job_picked_up_at => $job_picked_up_at, + job_updated => $job_updated, + job_name => $job_name, + job_progress => $job_progress, + job_title => $job_title, + job_description => $job_description, + job_status => $job_status, + modified_date => $modified_date, }}); $return = { - job_host_uuid => $job_host_uuid, - job_command => $job_command, - job_data => $job_data, - job_picked_up_by => $job_picked_up_by, - job_picked_up_at => $job_picked_up_at, - job_updated => $job_updated, - job_name => $job_name, - job_progress => $job_progress, - job_title => $job_title, - job_description => $job_description, - job_status => $job_status, - modified_date => $modified_date, + job_host_uuid => $job_host_uuid, + job_command => $job_command, + job_data => $job_data, + job_picked_up_by => $job_picked_up_by, + job_picked_up_at => $job_picked_up_at, + job_updated => $job_updated, + job_name => $job_name, + job_progress => $job_progress, + job_title => $job_title, + job_description => $job_description, + job_status => $job_status, + modified_date => $modified_date, }; return($return); @@ -3343,18 +3343,18 @@ WHERE } push @{$return}, { - job_uuid => $job_uuid, - job_command => $job_command, - job_data => $job_data, - job_picked_up_by => $job_picked_up_by, - job_picked_up_at => $job_picked_up_at, - job_updated => $job_updated, - job_name => $job_name, - job_progress => $job_progress, - job_title => $job_title, - job_description => $job_description, - job_status => $job_status, - modified_date => $modified_date, + job_uuid => $job_uuid, + job_command => $job_command, + job_data => $job_data, + job_picked_up_by => $job_picked_up_by, + job_picked_up_at => $job_picked_up_at, + job_updated => $job_updated, + job_name => $job_name, + job_progress => $job_progress, + job_title => $job_title, + job_description => $job_description, + job_status => $job_status, + modified_date => $modified_date, }; } @@ -7481,6 +7481,8 @@ Variables can not be passed to this title key. * This is not required when C<< update_progress_only >> is set +B<< Note >>: This can be set to the special C<< scancore_startup >>. When the job status is set to this value, the job will only run when ScanCore next starts up (generally after a reboot). + =head3 job_uuid (optional) This is the C<< job_uuid >> to update. If it is not specified but the C<< job_name >> is, a check will be made to see if an entry already exists. If so, that row will be UPDATEd. If not, a random UUID will be generated and a new entry will be INSERTed. diff --git a/Anvil/Tools/Get.pm b/Anvil/Tools/Get.pm index 1eaf322d..af29567c 100644 --- a/Anvil/Tools/Get.pm +++ b/Anvil/Tools/Get.pm @@ -1063,7 +1063,7 @@ sub cgi # This is a password and we're not logging sensitive data, obfuscate it. $censored_value = $anvil->Words->string({key => "log_0186"}); } - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "cgi::${variable}::$say_value" => $censored_value, }}); } diff --git a/Anvil/Tools/Job.pm b/Anvil/Tools/Job.pm index 3c1bfa62..2ce7438a 100644 --- a/Anvil/Tools/Job.pm +++ b/Anvil/Tools/Job.pm @@ -332,7 +332,7 @@ sub get_job_uuid 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 => "Job->get_job_uuid()" }}); - + my $job_uuid = ""; my $host_uuid = defined $parameter->{host_uuid} ? $parameter->{host_uuid} : $anvil->Get->host_uuid; my $program = defined $parameter->{program} ? $parameter->{program} : ""; diff --git a/Anvil/Tools/Network.pm b/Anvil/Tools/Network.pm index ad30e990..6543d71a 100644 --- a/Anvil/Tools/Network.pm +++ b/Anvil/Tools/Network.pm @@ -1205,22 +1205,22 @@ C<< Note >>: IP addresses that have been deleted will be marked so by C<< ip >> The loaded data will be stored as: -* C<< network::::interface::::ip >> - If an IP address is set -* C<< network::::interface::::subnet_mask >> - If an IP is set -* C<< network::::interface::::mac >> - Always set. -* C<< network::::interface::::default_gateway >> = C<< 0 >> if not the default gateway, C<< 1 >> if so. -* C<< network::::interface::::gateway >> = If the default gateway, this is the gateway IP address. -* C<< network::::interface::::dns >> = If the default gateway, this is the comma-separated list of active DNS servers. +* C<< network::::interface::::ip >> - If an IP address is set +* C<< network::::interface::::subnet_mask >> - If an IP is set +* C<< network::::interface::::mac >> - Always set. +* C<< network::::interface::::default_gateway >> = C<< 0 >> if not the default gateway, C<< 1 >> if so. +* C<< network::::interface::::gateway >> = If the default gateway, this is the gateway IP address. +* C<< network::::interface::::dns >> = If the default gateway, this is the comma-separated list of active DNS servers. Parameters; =head3 clear (optional, default '1') -When set, any previously known information is cleared. Specifically, the C<< network::> >> hash is deleted prior to the load. To prevent this, set this to C<< 0 >>. +When set, any previously known information is cleared. Specifically, the C<< network::> >> hash is deleted prior to the load. To prevent this, set this to C<< 0 >>. =head3 host (optional, default is 'host_uuid' value) -This is the optional C<< target >> string to use in the hash where the data is stored. +This is the optional C<< host >> string to use in the hash where the data is stored. =head3 host_uuid (optional, default 'sys::host_uuid') @@ -1637,6 +1637,15 @@ sub get_ips $anvil->data->{network}{$host}{interface}{$in_iface}{default_gateway} = 0 if not defined $anvil->data->{network}{$host}{interface}{$in_iface}{default_gateway}; $anvil->data->{network}{$host}{interface}{$in_iface}{gateway} = "" if not defined $anvil->data->{network}{$host}{interface}{$in_iface}{gateway}; $anvil->data->{network}{$host}{interface}{$in_iface}{dns} = "" if not defined $anvil->data->{network}{$host}{interface}{$in_iface}{dns}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "network::${host}::interface::${in_iface}::ip" => $anvil->data->{network}{$host}{interface}{$in_iface}{ip}, + "network::${host}::interface::${in_iface}::subnet_mask" => $anvil->data->{network}{$host}{interface}{$in_iface}{subnet_mask}, + "network::${host}::interface::${in_iface}::mac_address" => $anvil->data->{network}{$host}{interface}{$in_iface}{mac_address}, + "network::${host}::interface::${in_iface}::mtu" => $anvil->data->{network}{$host}{interface}{$in_iface}{mtu}, + "network::${host}::interface::${in_iface}::default_gateway" => $anvil->data->{network}{$host}{interface}{$in_iface}{default_gateway}, + "network::${host}::interface::${in_iface}::gateway" => $anvil->data->{network}{$host}{interface}{$in_iface}{gateway}, + "network::${host}::interface::${in_iface}::dns" => $anvil->data->{network}{$host}{interface}{$in_iface}{dns}, + }}); } next if not $in_iface; if ($in_iface eq "lo") diff --git a/Anvil/Tools/Remote.pm b/Anvil/Tools/Remote.pm index f3d84fce..06cd674d 100644 --- a/Anvil/Tools/Remote.pm +++ b/Anvil/Tools/Remote.pm @@ -162,7 +162,7 @@ sub add_target_to_known_hosts { # We don't know about this machine yet, so scan it. my $added = $anvil->Remote->_call_ssh_keyscan({ - debug => $debug, + debug => 2, target => $target, port => $port, user => $user, @@ -171,10 +171,17 @@ sub add_target_to_known_hosts if (not $added) { # Failed to add. :( + + my $say_user = $user; + if (($say_user =~ /^\d+$/) && (getpwuid($user))) + { + $say_user = getpwuid($user); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { say_user => $say_user }}); + } $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0009", variables => { target => $target, port => $port, - user => $user, + user => $say_user, }}); return(1); } @@ -378,7 +385,7 @@ sub call # In case the user is using ports in /etc/ssh/ssh_config, we'll want to check for an entry. $anvil->System->read_ssh_config({deubg => $debug}); - $anvil->data->{hosts}{$target}{port} = "" if not defined $anvil->data->{hosts}{$target}{port}; + $anvil->data->{hosts}{$target}{port} = 22 if not defined $anvil->data->{hosts}{$target}{port}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "hosts::${target}::port" => $anvil->data->{hosts}{$target}{port} }}); if ($anvil->data->{hosts}{$target}{port} =~ /^\d+$/) { @@ -686,9 +693,9 @@ sub call ### but it's here just in case. # If the output of the shell call doesn't end in a newline, the return_code:X # could be appended. This catches those cases and removes it. - $return_code = $1; - $line =~ s/return_code:\d+$//; - $output .= $line."\n"; + $return_code = $1; + $line =~ s/return_code:\d+$//; + $clean_output .= $line."\n"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line, output => $output, @@ -702,6 +709,7 @@ sub call } $clean_output =~ s/\n$//; $output = $clean_output; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { output => $output }}); # Have we been asked to close the connection? if ($close) @@ -1019,10 +1027,16 @@ sub _call_ssh_keyscan }}); # Log what we're doing + my $say_user = $user; + if (($say_user =~ /^\d+$/) && (getpwuid($user))) + { + $say_user = getpwuid($user); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { say_user => $say_user }}); + } $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "log_0159", variables => { target => $target, port => $port, - user => $user, + user => $say_user, }}); # Redirect STDERR to STDOUT and grep off the comments. diff --git a/Anvil/Tools/Striker.pm b/Anvil/Tools/Striker.pm index 96d85337..a355b898 100644 --- a/Anvil/Tools/Striker.pm +++ b/Anvil/Tools/Striker.pm @@ -136,8 +136,8 @@ sub generate_manifest if (($network eq "bcn") && ($i eq "1")) { # Get the IP. - my $ipmi_ip_key = $machine."_ipmi_ip"; - $machines->{$machine}{ipmi_ip} = defined $anvil->data->{cgi}{$ipmi_ip_key}{value} ? $anvil->data->{cgi}{$ipmi_ip_key}{value} : ""; + my $ipmi_ip_key = $machine."_ipmi_ip"; + $machines->{$machine}{ipmi_ip} = defined $anvil->data->{cgi}{$ipmi_ip_key}{value} ? $anvil->data->{cgi}{$ipmi_ip_key}{value} : ""; # Find the UPSes. foreach my $ups_name (sort {$a cmp $b} keys %{$anvil->data->{upses}{ups_name}}) diff --git a/cgi-bin/striker b/cgi-bin/striker index fbdb2259..905dbf06 100755 --- a/cgi-bin/striker +++ b/cgi-bin/striker @@ -7839,21 +7839,21 @@ sub sanity_check_step2 }}); foreach my $count (1..$network_count) { - my $this_network = $network.$count; - my $this_ip_key = $this_network."_ip"; + my $this_network = $network.$count; + my $this_ip_key = $this_network."_ip"; my $this_subnet_mask_key = $this_network."_subnet_mask"; - my $this_iface1_key = $this_network."_link1_mac_to_set"; - my $this_iface2_key = $this_network."_link2_mac_to_set"; + my $this_iface1_key = $this_network."_link1_mac_to_set"; + my $this_iface2_key = $this_network."_link2_mac_to_set"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - count => $count, - this_ip_key => $this_ip_key, + count => $count, + this_ip_key => $this_ip_key, this_subnet_mask_key => $this_subnet_mask_key, - this_iface1_key => $this_iface1_key, - this_iface2_key => $this_iface2_key, - "cgi::${this_ip_key}::value" => $anvil->data->{cgi}{$this_ip_key}{value}, + this_iface1_key => $this_iface1_key, + this_iface2_key => $this_iface2_key, + "cgi::${this_ip_key}::value" => $anvil->data->{cgi}{$this_ip_key}{value}, "cgi::${this_subnet_mask_key}::value" => $anvil->data->{cgi}{$this_subnet_mask_key}{value}, - "cgi::${this_iface1_key}::value" => $anvil->data->{cgi}{$this_iface1_key}{value}, - "cgi::${this_iface2_key}::value" => $anvil->data->{cgi}{$this_iface2_key}{value}, + "cgi::${this_iface1_key}::value" => $anvil->data->{cgi}{$this_iface1_key}{value}, + "cgi::${this_iface2_key}::value" => $anvil->data->{cgi}{$this_iface2_key}{value}, }}); # This will be used to tell the user which interface has a problem, if one exists. diff --git a/notes b/notes index 59071379..c1c35931 100644 --- a/notes +++ b/notes @@ -331,6 +331,10 @@ drbdsetup show all --show-defaults drbdsetup net-options srv01-c7_0 2 --_name=m3-a02n01.alteeve.com --csums-alg=md5 --data-integrity-alg=md5 --after-sb-0pri=discard-zero-changes --after-sb-1pri=discard-secondary --after-sb-2pri=disconnect --protocol=C --fencing=resource-and-stonith --allow-two-primaries=yes drbdsetup net-options srv01-c7_0 2 --_name=m3-a02n01.alteeve.com --csums-alg=md5 --data-integrity-alg=md5 --after-sb-0pri=discard-zero-changes --after-sb-1pri=discard-secondary --after-sb-2pri=disconnect --protocol=C --fencing=resource-and-stonith --allow-two-primaries=yes + +# Adding a second volume to a running resource; +- I wonder if you'd have the same results if you could get vol1 into an UpToDate/UpToDate state using the drbdsetup equivalent of drbdadm new-current-uuid --clear-bitmap + # Migrate: virsh -c qemu+ssh://root@m3-a02n02.alteeve.com/system list diff --git a/share/words.xml b/share/words.xml index c88ae052..06c30f08 100644 --- a/share/words.xml +++ b/share/words.xml @@ -332,6 +332,15 @@ Output (if any): - shell_call: [#!variable!shell_call!#] ]]> Usage: [#!variable!program!# --config /path/to/config]. + The file: [#!variable!file!#] doesn't appear to be valid. + Failed to find a matching entry in the file: [#!variable!file!#]. Please make sure the MAC addresses in the config are accurate for these systems. + Missing variable: [#!variable!variable!#] from config file: [#!data!switches::config!#]. + The length of the prefix: [#!variable!prefix!#] is: [#!variable!length!#]. The prefix needs to be not more than 5. + The DNS IP: [#!variable!ip!#] is invalid. + The gateway IP: [#!variable!ip!#] is invalid. + The variable: [#!variable!variable!#] is invalid: [#!variable!value!#]. + Failed to add the UPS: [#!variable!ups_name!#] at: [#!variable!aups_ip_address!#] using the agent: [#!variable!ups_agent!#]! + Failed to add the fence device: [#!variable!fence_name!#] using the agent: [#!variable!fence_agent!#]! @@ -674,6 +683,45 @@ It should be provisioned in the next minute or two. Preparing to delete the server: [#!variable!server_name!#]. Using virsh to destroy (force off) the server: [#!variable!server_name!#], if it is still running. Enabled the HA repository for CentOS Stream. + Initialize Stage-1 installed systems into a full Anvil!. + This program is designed the automation of turning a set of stage-1 (bare OS + anvil-repo) systems and turn them into a fully functioning Anvil! system. + We need to setup pairing with Striker: [#!variable!number!#]. We will wait for it to come up. Be sure that you're run 'striker-auto-initialize-all' on it. + Successfully connected to Striker: [#!variable!number!#] using the IP: [#!variable!ip!#]! + No connection to Striker: [#!variable!number!#] via the IP: [#!variable!ip!#]. + Failed to connect Striker: [#!variable!number!#] over any IPs. Sleeping a bit and then trying again. + Waiting now for the peer Striker: [#!variable!number!#] with host UUID: [#!variable!peer_host_uuid!#] to show up in our database. + The peer Striker: [#!variable!number!#] with host name: [#!variable!peer_host_name!#] has successfully peered with us! + The peer Striker: [#!variable!number!#] with host UUID: [#!variable!peer_host_uuid!#] has not yet started using our database. Waiting a bit before checking again... + Peering Striker dashbaords + Striker peers now working with us! + Adding UPSes now. + Successfully added/updated the UPS: [#!variable!ups_name!#] at: [#!variable!ups_ip_address!#] using the agent: [#!variable!ups_agent!#]. It's UPS UUID is: [#!variable!ups_uuid!#]. + Failed to assemble the Anvil!, aborting. + All UPSes added/updated. + Adding fence devices now. + Successfully added/updated the fence device: [#!variable!fence_name!#] using the agent: [#!variable!fence_agent!#]. It's fence UUID is: [#!variable!fence_uuid!#]. + All fence devices added/updated. + Creating Install Manifest(s). + Created the manifest: [#!variable!manifest_name!#] with the UUID: [#!variable!manifest_uuid!#]. + Install Manifest(s) created. + Initializing nodes and, if applicable, DR host(s). + The machine: [#!variable!machine!#] is already initialized and has the host UUID: [#!variable!host_uuid!#]. No need to initialize. + Trying to connect to: [#!variable!machine!#] using IP: [#!variable!ip!#] with the initial password. + Trying to connect to: [#!variable!machine!#] using IP: [#!variable!ip!#] with the desired password. + Connected! We will initialize using the IP: [#!variable!ip!#] + Failed to connect to: [#!variable!machine!#] using any IP address. We'll sleep and then try again shortly. + Created the job to initialize: [#!variable!host_name!#] via the IP address: [#!variable!ip!#] with job UUID: [#!variable!job_uuid!#]. + All machines should now be initializing. Waiting now for all machines to register in the database. + The machine: [#!variable!machine!#] hasn't connected to the database yet. + One (or more) machines have not yet initialized. Waiting a few seconds, then checking again. + All machines have been initialized! + Ready to create jobs to assemble Anvil! systems. + Created (or updated) the Anvil! [#!variable!anvil_name!#] with the UUID: [#!variable!anvil_uuid!#]. + Created the job for: [#!variable!machine_name!#] with host UUID: [#!variable!host_uuid!#] to the Anvil!: [#!variable!anvil_name!#] with the job UUID: [#!variable!job_uuid!#]. + Add machines have been asked to joing their Anvil! system(s). We'll now wait for all jobs to complete. + The job UUID: [#!variable!job_uuid!#] is at: [#!variable!progress!#%]. + Not all jobs are done yet, will check again in a bit. + All jobs are complete! Baring problems, the Anvil! system(s) should now be ready to use. Starting: [#!variable!program!#]. @@ -1360,6 +1408,7 @@ The file: [#!variable!file!#] needs to be updated. The difference is: Wiping the metadata from the DRBD resource: [#!variable!resource!#]. Wiping any file system signatures and then deleting the logical volume: [#!variable!device_path!#]. The resource name: [#!variable!resource_name!#] was found, returning the first TCP port and minor number. + The job: [#!variable!command!#] with UUID: [#!variable!job_uuid!#] is a start-time job, not running it now. The host name: [#!variable!target!#] does not resolve to an IP address. @@ -1676,6 +1725,7 @@ Are you sure that you want to delete the server: [#!variable!server_name!#]? [Ty Preparing to migrate a server (or all servers). - #!variable!server_name!# (Current state: [#!variable!server_state!#]) - * #!variable!server_name!# (Deleted, name can be reused) + We're Striker: [#!variable!striker!#], and we're now configured, so we're done. Striker 1 will finish configuration. Saved the mail server information successfully! diff --git a/tools/anvil-daemon b/tools/anvil-daemon index c3682e56..c00dc9f3 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -717,9 +717,9 @@ FROM WHERE variable_source_table = 'hosts' AND - variable_source_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." + variable_source_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." AND - variable_name = 'reboot::needed' + variable_name = 'reboot::needed' ;"; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0124", variables => { query => $query }}); my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); @@ -774,6 +774,9 @@ AND } } + # Now look for jobs that have a job status of 'scancore_startup' + run_jobs($anvil, 1); + # Check the firewall needs to be updated. check_firewall($anvil); @@ -856,7 +859,7 @@ sub keep_running } # Run any pending jobs by calling 'anvil-jobs' with the 'job_uuid' as a background process. - run_jobs($anvil) if not $anvil->data->{sys}{mapping_network}; + run_jobs($anvil, 0) if not $anvil->data->{sys}{mapping_network}; return(0); } @@ -866,7 +869,8 @@ sub keep_running # invoked to handle it. sub run_jobs { - my ($anvil) = @_; + my ($anvil, $startup) = @_; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { startup => $startup }}); # This will be set to 1 if any jobs are not complete, preventing a restart of the daemon if it's # changed on disk. @@ -876,11 +880,13 @@ sub run_jobs my $jobs_file = "{\"jobs\":[\n"; # Get a list of pending or incomplete jobs. - my $return = $anvil->Database->get_jobs({debug => 3, ended_within => 300}); - my $count = @{$return}; + my $ended_within = $startup ? 1 : 300; + my $return = $anvil->Database->get_jobs({debug => 3, ended_within => $ended_within}); + my $count = @{$return}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - 'return' => $return, - count => $count, + ended_within => $ended_within, + 'return' => $return, + count => $count, }}); foreach my $hash_ref (@{$return}) { @@ -1023,6 +1029,17 @@ sub run_jobs # If the job is done, move on. next if $job_progress eq "100"; + # If 'startup' is set, we only care if 'job_status' is 'scancore_startup' + if ((not $startup) && ($say_status eq "scancore_startup")) + { + # Skip this, it will run next time anvil-daemon restarts. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0593", variables => { + command => $job_command, + job_uuid => $job_uuid, + }}); + next; + } + # If the job is not running, start it. if ((not $job_picked_up_by) && ($job_progress ne "100") && (not $anvil->data->{switches}{'no-start'})) { diff --git a/tools/striker-auto-initialize-all b/tools/striker-auto-initialize-all index 967064eb..5810e33c 100755 --- a/tools/striker-auto-initialize-all +++ b/tools/striker-auto-initialize-all @@ -10,6 +10,7 @@ use strict; use warnings; use Anvil::Tools; use Data::Dumper; +use NetAddr::IP; $| = 1; @@ -20,76 +21,6 @@ if (($running_directory =~ /^\./) && ($ENV{PWD})) $running_directory =~ s/^\./$ENV{PWD}/; } -=cut - -Striker initialization; - -# Figure out if we're striker '1' or '2' by matching found MAC addresses against configured MAC addresses. -# Striker 1 will, after configuring itself, reboot and wait for access to Striker 2. Then it will bond the two and begin configuring nodes (and DR, if defined) - data source | variable_name | variable_value | variable_default | variable_description | variable_section | variable_source_uuid | variable_source_table | modified_date -------------------------------------------+--------------------------------------------------+-------------------------+------------------+----------------------+------------------+--------------------------------------+-----------------------+------------------------------- -base::organization_name | form::config_step1::organization::value | Alteeve | | striker_0004 | config_step1 | a64c477b-b0a1-4985-9968-f4b46d75fb0c | hosts | 2021-02-16 20:26:22.938934-05 -base::prefix | form::config_step1::prefix::value | di | | striker_0006 | config_step1 | a64c477b-b0a1-4985-9968-f4b46d75fb0c | hosts | 2021-02-16 20:26:22.938934-05 -base::domain | form::config_step1::domain::value | digimer.ca | | striker_0008 | config_step1 | a64c477b-b0a1-4985-9968-f4b46d75fb0c | hosts | 2021-02-16 20:26:22.938934-05 -keys %{striker}{1}{network}{ifn} | form::config_step1::ifn_count::value | 1 | | striker_0012 | config_step1 | a64c477b-b0a1-4985-9968-f4b46d75fb0c | hosts | 2021-02-16 20:26:22.938934-05 -# Match MAC for Striker sequence | form::config_step1::sequence::value | 2 | | striker_0010 | config_step1 | a64c477b-b0a1-4985-9968-f4b46d75fb0c | hosts | 2021-02-16 20:27:39.491016-05 --striker0. | form::config_step2::host_name::value | di-striker02.digimer.ca | | striker_0017 | config_step2 | a64c477b-b0a1-4985-9968-f4b46d75fb0c | hosts | 2021-02-16 20:29:59.317812-05 -# Hard code to 'admin' | form::config_step2::striker_user::value | admin | | striker_0032 | config_step2 | a64c477b-b0a1-4985-9968-f4b46d75fb0c | hosts | 2021-02-16 20:29:59.317812-05 -base::password::desired | form::config_step2::striker_password::value | super secret password | | striker_0034 | config_step2 | a64c477b-b0a1-4985-9968-f4b46d75fb0c | hosts | 2021-02-16 20:29:59.317812-05 -base::dns | form::config_step2::dns::value | 8.8.8.8, 8.8.4.4 | | striker_0038 | config_step2 | a64c477b-b0a1-4985-9968-f4b46d75fb0c | hosts | 2021-02-16 20:29:59.317812-05 -base::gateway | form::config_step2::gateway::value | 192.168.122.1 | | striker_0036 | config_step2 | a64c477b-b0a1-4985-9968-f4b46d75fb0c | hosts | 2021-02-16 20:30:16.688974-05 -base::interface | form::config_step2::gateway_interface::value | ifn1 | | | config_step2 | a64c477b-b0a1-4985-9968-f4b46d75fb0c | hosts | 2021-02-16 20:30:16.688974-05 -striker::1::network::bcn::1::ip | form::config_step2::bcn1_ip::value | 10.201.4.2 | | striker_0024 | config_step2 | a64c477b-b0a1-4985-9968-f4b46d75fb0c | hosts | 2021-02-16 20:29:59.317812-05 -striker::1::network::bcn::1::subnet_mask | form::config_step2::bcn1_subnet_mask::value | 255.255.0.0 | | striker_0025 | config_step2 | a64c477b-b0a1-4985-9968-f4b46d75fb0c | hosts | 2021-02-16 20:29:59.317812-05 -striker::1::network::bcn::1::link::1::mac | form::config_step2::bcn1_link1_mac_to_set::value | 52:54:00:8b:d6:82 | | striker_0029 | config_step2 | a64c477b-b0a1-4985-9968-f4b46d75fb0c | hosts | 2021-02-16 20:29:59.317812-05 -striker::1::network::ifn::1::subnet_mask | form::config_step2::ifn1_subnet_mask::value | 255.255.255.0 | | striker_0025 | config_step2 | a64c477b-b0a1-4985-9968-f4b46d75fb0c | hosts | 2021-02-16 20:29:59.317812-05 -striker::1::network::ifn::1::link::1::mac | form::config_step2::ifn1_link1_mac_to_set::value | 52:54:00:c0:f2:7c | | striker_0029 | config_step2 | a64c477b-b0a1-4985-9968-f4b46d75fb0c | hosts | 2021-02-16 20:29:59.317812-05 -striker::1::network::ifn::1::ip | form::config_step2::ifn1_ip::value | 192.168.122.12 | | striker_0024 | config_step2 | a64c477b-b0a1-4985-9968-f4b46d75fb0c | hosts | 2021-02-16 20:30:16.688974-05 - - -anvil=# SELECT * FROM jobs WHERE job_uuid = '158e8384-eac7-4289-8f70-bc43eaf8b017'; - job_uuid | job_host_uuid | job_command | job_data | job_picked_up_by | job_picked_up_at | job_updated | job_name | job_progress | job_title | job_description | job_status | modified_date ---------------------------------------+--------------------------------------+--------------------------------+--------------------+------------------+------------------+-------------+--------------------+--------------+-----------+-----------------+------------+------------------------------- - 158e8384-eac7-4289-8f70-bc43eaf8b017 | a64c477b-b0a1-4985-9968-f4b46d75fb0c | /usr/sbin/anvil-configure-host | form::config_step2 | 0 | 0 | 1613525509 | configure::network | 0 | job_0001 | job_0002 | | 2021-02-16 20:31:49.108908-05 - - -# At this point, the Striker should be coming up at the IP. Once both/all Strikers are up, update their anvil.conf to add each other's UUID database entry. -# FROM ONE STRIKER; - job_uuid | job_host_uuid | job_command | job_data | job_picked_up_by | job_picked_up_at | job_updated | job_name | job_progress | job_title | job_description | job_status | modified_date ---------------------------------------+--------------------------------------+------------------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+------------------+------------------+-------------+-------------------+--------------+-----------+-----------------+------------+------------------------------- - 6ca30d0b-c03c-43f9-bd7c-c40a79ca52a8 | 46c00674-fea2-44af-981d-2833d5c8270a | /usr/sbin/striker-manage-peers --add --host-uuid a64c477b-b0a1-4985-9968-f4b46d75fb0c --host 10.201.4.2 --port 5432 --ping 1 | password=super secret password +| 0 | 0 | 1613699163 | striker-peer::add | 0 | job_0011 | job_0012 | | 2021-02-18 20:46:03.305568-05 - | | | peer_job_command=/usr/sbin/striker-manage-peers --add --host-uuid 46c00674-fea2-44af-981d-2833d5c8270a --host 10.201.4.1 --port 5432 --ping 1 | | | | | | | | | -(1 row) - -# Initialize nodes / dr hosts (may need to call striker-get-peer-data) -anvil=# SELECT * FROM jobs ; - job_uuid | job_host_uuid | job_command | job_data | job_picked_up_by | job_picked_up_at | job_updated | job_name | job_progress | job_title | job_description | job_status | modified_date ---------------------------------------+--------------------------------------+-----------------------------------+---------------------------------+------------------+------------------+-------------+-----------------------------------+--------------+-----------+-----------------+------------+------------------------------ - a5c3381c-c581-4020-baa0-72e136c75a68 | 46c00674-fea2-44af-981d-2833d5c8270a | /usr/sbin/striker-initialize-host | password=Initial1 +| 0 | 0 | 1613957250 | initialize::node::192.168.122.207 | 0 | job_0020 | job_0022 | | 2021-02-21 20:27:30.73576-05 - | | | rh_password= +| | | | | | | | | - | | | rh_user= +| | | | | | | | | - | | | host_ip_address=192.168.122.207+| | | | | | | | | - | | | ssh_port=22 +| | | | | | | | | - | | | type=node +| | | | | | | | | - | | | host_name=di-a02n01.alteeve.com+| | | | | | | | | - | | | | | | | | | | | | -(1 row) -anvil=# SELECT * FROM jobs WHERE job_progress != 100; - job_uuid | job_host_uuid | job_command | job_data | job_picked_up_by | job_picked_up_at | job_updated | job_name | job_progress | job_title | job_description | job_status | modified_date ---------------------------------------+--------------------------------------+-----------------------------------+----------------------------------+------------------+------------------+-------------+---------------------------------+--------------+-----------+-----------------+------------+------------------------------- - 6c21d7ca-1c86-4389-9821-0ae945529754 | 46c00674-fea2-44af-981d-2833d5c8270a | /usr/sbin/striker-initialize-host | password=Initial1 +| 0 | 0 | 1614047831 | initialize::dr::192.168.122.141 | 0 | job_0021 | job_0022 | | 2021-02-22 21:37:11.082112-05 - | | | rh_password= +| | | | | | | | | - | | | rh_user= +| | | | | | | | | - | | | host_ip_address=192.168.122.141 +| | | | | | | | | - | | | ssh_port=22 +| | | | | | | | | - | | | type=dr +| | | | | | | | | - | | | host_name=di-a02dr01.alteeve.com+| | | | | | | | | - | | | | | | | | | | | | -(1 row) - -=cut - - my $anvil = Anvil::Tools->new(); @@ -101,6 +32,8 @@ if (not $anvil->data->{sys}{database}{connections}) $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, priority => "err", key => "error_0003"}); $anvil->nice_exit({exit_code => 1}); } +$anvil->data->{switches}{config} = ""; +$anvil->data->{switches}{'job-uuid'} = ""; $anvil->Get->switches; # Read in the config file @@ -114,8 +47,1421 @@ if ((not $anvil->data->{switches}{config}) or (not -f $anvil->data->{switches}{c # Load the config. $anvil->Storage->read_config({file => $anvil->data->{switches}{config}}); -print Dumper $anvil->data->{base}; -print Dumper $anvil->data->{striker}; +# Check that 'prefix' is now set as a rough test that the file we read was useful. +if ((not exists $anvil->data->{base}{prefix}) or ($anvil->data->{base}{prefix} eq "")) +{ + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0241", variables => { file => $anvil->data->{switches}{config} }}); + $anvil->nice_exit({exit_code => 1}); +} + +# Find myself +find_myself($anvil); +if (not $anvil->data->{i_am}{striker}) +{ + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0242", variables => { file => $anvil->data->{switches}{config} }}); + $anvil->nice_exit({exit_code => 1}); +} +# If I am not configured, configure myself now. +my $configured = $anvil->System->check_if_configured; +$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { configured => $configured }}); +if ($configured) +{ + # If I am not Striker 1, I am done. + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "i_am::striker" => $anvil->data->{i_am}{striker} }}); + if ($anvil->data->{i_am}{striker} ne "1") + { + # We're done. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "message_0221", variables => { striker => $anvil->data->{i_am}{striker} }}); + $anvil->nice_exit({exit_code => 0}); + } + striker_stage2($anvil); +} +else +{ + # Do the initial setup of ourselves. + striker_stage1($anvil); +} $anvil->nice_exit({exit_code => 0}); + + + +############################################################################################################# +# Functions # +############################################################################################################# + +# This does the rest of the setup. +sub striker_stage2 +{ + my ($anvil) = @_; + + # Merge my peer Striker. + merge_peer_striker($anvil); + + # Add UPSes. + add_upses($anvil); + + # Add fence devices + add_fences($anvil); + + # Create manifest. + create_manifest($anvil); + + # Initialize nodes and DR. + initialize_machines($anvil); + + # Run the manifest(s). + run_manifests($anvil); + + return(0); +} + +# By this point, all machines should be initialized and online. +sub run_manifests +{ + my ($anvil) = @_; + + update_progress($anvil, 70, "job_0257"); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0257"}); + + # All machines are up! + my $job_uuids = []; + foreach my $anvil_number (sort {$a cmp $b} keys %{$anvil->data->{anvil}}) + { + my $anvil_name = $anvil->data->{process}{anvil}{$anvil_number}{name}; + my $manifest_uuid = $anvil->data->{process}{anvil}{$anvil_number}{manifest_uuid}; + my $manifest_name = $anvil->data->{process}{anvil}{$anvil_number}{manifest_name}; + my $node1_host_uuid = $anvil->data->{process}{anvil}{$anvil_number}{node1}{host_uuid}; + my $node2_host_uuid = $anvil->data->{process}{anvil}{$anvil_number}{node2}{host_uuid}; + my $dr1_host_uuid = exists $anvil->data->{process}{anvil}{$anvil_number}{dr1}{host_uuid} ? $anvil->data->{process}{anvil}{$anvil_number}{dr1}{host_uuid} : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:anvil_name' => $anvil_name, + 's2:manifest_name' => $manifest_name, + 's3:manifest_uuid' => $manifest_uuid, + 's4:node1_host_uuid' => $node1_host_uuid, + 's5:node2_host_uuid' => $node2_host_uuid, + 's6:dr1_host_uuid' => $dr1_host_uuid, + }}); + + my ($anvil_uuid) = $anvil->Database->insert_or_update_anvils({ + debug => 2, + anvil_description => $anvil->data->{anvil}{$anvil_number}{description}, + anvil_name => $anvil_name, + anvil_password => $anvil->data->{base}{password}{desired}, + anvil_node1_host_uuid => $node1_host_uuid, + anvil_node2_host_uuid => $node2_host_uuid, + anvil_dr1_host_uuid => $dr1_host_uuid, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { anvil_uuid => $anvil_uuid }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0258", variables => { + anvil_name => $anvil_name, + anvil_uuid => $anvil_uuid, + }}); + + # Tell node 1 to join. + my ($node1_job_uuid) = $anvil->Database->insert_or_update_jobs({ + job_host_uuid => $node1_host_uuid, + job_command => $anvil->data->{path}{exe}{'anvil-join-anvil'}, + job_data => "as_machine=node1,manifest_uuid=".$manifest_uuid.",anvil_uuid=".$anvil_uuid, + job_name => "join_anvil::node1", + job_title => "job_0072", + job_description => "job_0073", + job_progress => 0, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { node1_job_uuid => $node1_job_uuid }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0259", variables => { + machine_name => "node1", + anvil_name => $anvil_name, + host_uuid => $node1_host_uuid, + job_uuid => $node1_job_uuid, + }}); + push @{$job_uuids}, $node1_job_uuid; + + my ($node2_job_uuid) = $anvil->Database->insert_or_update_jobs({ + job_host_uuid => $node2_host_uuid, + job_command => $anvil->data->{path}{exe}{'anvil-join-anvil'}, + job_data => "as_machine=node2,manifest_uuid=".$manifest_uuid.",anvil_uuid=".$anvil_uuid, + job_name => "join_anvil::node2", + job_title => "job_0072", + job_description => "job_0073", + job_progress => 0, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { node2_job_uuid => $node2_job_uuid }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0259", variables => { + machine_name => "node2", + anvil_name => $anvil_name, + host_uuid => $node2_host_uuid, + job_uuid => $node2_job_uuid, + }}); + push @{$job_uuids}, $node2_job_uuid; + + if ($anvil->data->{cgi}{dr1_host}{value}) + { + my ($dr1_job_uuid) = $anvil->Database->insert_or_update_jobs({ + job_host_uuid => $dr1_host_uuid, + job_command => $anvil->data->{path}{exe}{'anvil-join-anvil'}, + job_data => "as_machine=dr1,manifest_uuid=".$manifest_uuid.",anvil_uuid=".$anvil_uuid, + job_name => "join_anvil::dr1", + job_title => "job_0072", + job_description => "job_0073", + job_progress => 0, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { dr1_job_uuid => $dr1_job_uuid }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0259", variables => { + machine_name => "dr1", + anvil_name => $anvil_name, + host_uuid => $dr1_host_uuid, + job_uuid => $dr1_job_uuid, + }}); + push @{$job_uuids}, $dr1_job_uuid; + } + } + + update_progress($anvil, 80, "job_0257"); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0257"}); + + # Wait for jobs to complete. + my $waiting = 1; + while ($waiting) + { + $waiting = 0; + foreach my $job_uuid (@{$job_uuids}) + { + my $return = $anvil->Database->get_job_details({job_uuid => $job_uuid}); + my $job_progress = $return->{job_progress}; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0259", variables => { + job_uuid => $job_uuid, + progress => $job_progress, + }}); + + if ($job_progress != 100) + { + # Still waiting + $waiting = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { waiting => $waiting }}); + } + } + + if ($waiting) + { + # Wait a bit and check again. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0262"}); + sleep 10; + } + else + { + # We're done. + update_progress($anvil, 100, "job_0263"); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0263"}); + } + } + + return(0); +} + +# This initializes nodes and DR hosts. This also sets the 'cgi::::value' hashes that will be needed +# later to create the install manifest. +sub initialize_machines +{ + my ($anvil) = @_; + + update_progress($anvil, 60, "job_0246"); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0245"}); + + foreach my $anvil_number (sort {$a cmp $b} keys %{$anvil->data->{anvil}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { anvil_number => $anvil_number }}); + foreach my $machine_type ("node", "dr") + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { machine_type => $machine_type }}); + foreach my $machine_number (sort {$a cmp $b} keys %{$anvil->data->{anvil}{$anvil_number}{$machine_type}}) + { + my $startup_ip = $anvil->data->{anvil}{$anvil_number}{$machine_type}{start_ip}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + machine_number => $machine_number, + startup_ip => $startup_ip, + }}); + + # Find the IP we can access the machine with and the machine's host_uuid. + my $machine_host_uuid = ""; + my $machine_ips = []; + push @{$machine_ips}, $startup_ip; + + foreach my $network (sort {$a cmp $b} keys %{$anvil->data->{anvil}{$anvil_number}{$machine_type}{network}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network => $network }}); + foreach my $network_number (sort {$a cmp $b} keys %{$anvil->data->{anvil}{$anvil_number}{$machine_type}{network}{$network}}) + { + my $ip_address = $anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{network}{$network}{$network_number}{ip}; + my $subnet_mask = $anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{network}{$network}{$network_number}{subnet_mask}; + my $link1_mac = $anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{network}{$network}{$network_number}{'link'}{1}{mac}; + my $link2_mac = $anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{network}{$network}{$network_number}{'link'}{1}{mac}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:ip_address' => $ip_address, + 's2:subnet_mask' => $subnet_mask, + 's3:link1_mac' => $link1_mac, + 's4:link2_mac' => $link2_mac, + }}); + + # No sense pushing SN IPs + if ($network != /^sn/) + { + push @{$machine_ips}, $ip_address; + } + + if (not $machine_host_uuid) + { + $machine_host_uuid = get_host_uuid_from_mac($anvil, $link1_mac); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { machine_host_uuid => $machine_host_uuid }}); + } + if (not $machine_host_uuid) + { + $machine_host_uuid = get_host_uuid_from_mac($anvil, $link2_mac); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { machine_host_uuid => $machine_host_uuid }}); + } + } + } + + # If I don't have a machine host uuid, initialize the machine. + if ($machine_host_uuid) + { + # Already initialized + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0247", variables => { + machine => $machine_type.$machine_number, + host_uuid => $machine_host_uuid, + }}); + } + else + { + # Which IP should be use to initialize? + my $use_ip = ""; + my $use_password = $anvil->data->{base}{password}{current}; + until ($use_ip) + { + foreach my $ip_address (@{$machine_ips}) + { + next if $use_ip; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ip_address => $ip_address }}); + + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0248", variables => { + machine => $machine_type.$machine_number, + ip => $ip_address, + }}); + my $access = $anvil->Remote->test_access({ + target => $ip_address, + password => $use_password, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { access => $access }}); + if ($access) + { + $use_ip = $ip_address; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { use_ip => $use_ip }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0250", variables => { ip => $use_ip }}); + } + else + { + # Failed to log in, try again with the + # desired password, the machine might already + # be updated. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0249", variables => { + machine => $machine_type.$machine_number, + ip => $ip_address, + }}); + $access = $anvil->Remote->test_access({ + target => $ip_address, + password => $anvil->data->{base}{password}{desired}, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { access => $access }}); + if ($access) + { + # The new password worked. + $use_password = $anvil->data->{base}{password}{desired}; + $use_ip = $ip_address; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { use_ip => $use_ip }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0250", variables => { ip => $use_ip }}); + } + } + } + if (not $use_ip) + { + # Sleep and try again. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0251", variables => { machine => $machine_type.$machine_number }}); + sleep 10; + } + } + + # Now register a job to initialize the target. + my $padded_sequence = $anvil_number; + if (length($padded_sequence) == 1) + { + $padded_sequence = sprintf("%02d", $padded_sequence); + } + my $machine_suffix = $machine_type eq "node" ? "n".sprintf("%02d", $machine_number) : "dr".sprintf("%02d", $machine_number); + my $name_prefix = "a".$padded_sequence; + my $say_host_name = $anvil->data->{base}{prefix}."-".$name_prefix.$machine_suffix.".".$anvil->data->{base}{domain}; + + # Store the peer's password as the job data + my $job_data = "password=".$anvil->data->{base}{password}{desired}."\n"; + $job_data .= "rh_password=".$anvil->data->{base}{rhn}{password}."\n"; + $job_data .= "rh_user=".$anvil->data->{base}{rhn}{user}."\n"; + $job_data .= "host_ip_address=".$use_ip."\n"; + $job_data .= "ssh_port=22\n"; + $job_data .= "type=".$machine_type."\n"; + $job_data .= "host_name=".$say_host_name; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 1, list => { job_data => $job_data }}); + + # Store the job + my ($job_uuid) = $anvil->Database->insert_or_update_jobs({ + debug => 2, + file => $THIS_FILE, + line => __LINE__, + job_command => $anvil->data->{path}{exe}{'striker-initialize-host'}, + job_data => $job_data, + job_name => "initialize::".$machine_type."::".$use_ip, + job_title => $machine_type eq "dr" ? "job_0021" : "job_0020", + job_description => "job_0022", + job_progress => 0, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }}); + + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0246", variables => { + host_name => $say_host_name, + ip => $use_ip, + job_uuid => $job_uuid, + }}); + } + } + } + } + + update_progress($anvil, 65, "job_0253"); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0253"}); + + # Now wait until all machines are in the database. + my $waiting = 1; + my $node1_host_uuid = ""; + my $node2_host_uuid = ""; + my $dr1_host_uuid = ""; + while($waiting) + { + $waiting = 0; + foreach my $anvil_number (sort {$a cmp $b} keys %{$anvil->data->{anvil}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { anvil_number => $anvil_number }}); + foreach my $machine_type ("node", "dr") + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { machine_type => $machine_type }}); + foreach my $machine_number (sort {$a cmp $b} keys %{$anvil->data->{anvil}{$anvil_number}{$machine_type}}) + { + my $machine_host_uuid = ""; + foreach my $network (sort {$a cmp $b} keys %{$anvil->data->{anvil}{$anvil_number}{$machine_type}{network}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network => $network }}); + foreach my $network_number (sort {$a cmp $b} keys %{$anvil->data->{anvil}{$anvil_number}{$machine_type}{network}{$network}}) + { + next if $machine_host_uuid; + my $link1_mac = $anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{network}{$network}{$network_number}{'link'}{1}{mac}; + my $link2_mac = $anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{network}{$network}{$network_number}{'link'}{1}{mac}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:link1_mac' => $link1_mac, + 's2:link2_mac' => $link2_mac, + }}); + + # No sense pushing SN IPs + if (not $machine_host_uuid) + { + $machine_host_uuid = get_host_uuid_from_mac($anvil, $link1_mac); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { machine_host_uuid => $machine_host_uuid }}); + } + if (not $machine_host_uuid) + { + $machine_host_uuid = get_host_uuid_from_mac($anvil, $link2_mac); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { machine_host_uuid => $machine_host_uuid }}); + } + } + } + if ($machine_host_uuid) + { + # Ready + my $key = $machine_type.$machine_number; + $anvil->data->{process}{anvil}{$anvil_number}{$key}{host_uuid} = $machine_host_uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "process::anvil::${anvil_number}::${key}::host_uuid" => $anvil->data->{process}{anvil}{$anvil_number}{$key}{host_uuid}, + }}); + } + else + { + # At least one machine isn't up yet. + $waiting = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { waiting => $waiting }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0254", variables => { machine => $machine_type.$machine_number }}); + } + } + } + } + if ($waiting) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0255"}); + sleep 10; + } + } + + update_progress($anvil, 65, "job_0256"); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0256"}); + + return(0); +} + +# This creates the manifests +sub create_manifest +{ + my ($anvil) = @_; + + # By here, the peer(s) are joined. + update_progress($anvil, 50, "job_0243"); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0243"}); + + $anvil->Database->get_upses({debug => 2}); + $anvil->Database->get_fences({debug => 2}); + + # This is common for all Anvil! systems we might be building + $anvil->data->{cgi}{prefix}{value} = $anvil->data->{base}{prefix}; + $anvil->data->{cgi}{domain}{value} = $anvil->data->{base}{domain}; + $anvil->data->{cgi}{mtu}{value} = $anvil->data->{base}{mtu}; + $anvil->data->{cgi}{dns}{value} = $anvil->data->{base}{dns}; + $anvil->data->{cgi}{ntp}{value} = $anvil->data->{base}{ntp}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "cgi::prefix::value" => $anvil->data->{cgi}{prefix}{value}, + "cgi::domain::value" => $anvil->data->{cgi}{domain}{value}, + "cgi::mtu::value" => $anvil->data->{cgi}{mtu}{value}, + "cgi::dns::value" => $anvil->data->{cgi}{dns}{value}, + "cgi::ntp::value" => $anvil->data->{cgi}{ntp}{value}, + }}); + + foreach my $anvil_number (sort {$a cmp $b} keys %{$anvil->data->{anvil}}) + { + $anvil->data->{cgi}{sequence}{value} = $anvil_number; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "cgi::sequence::value" => $anvil->data->{cgi}{sequence}{value}, + }}); + + my $padded_sequence = $anvil_number; + if (length($padded_sequence) == 1) + { + $padded_sequence = sprintf("%02d", $padded_sequence); + } + my $anvil_name = $anvil->data->{cgi}{prefix}{value}."-anvil-".$padded_sequence; + my $query = "SELECT manifest_uuid FROM manifests WHERE manifest_name = ".$anvil->Database->quote($anvil_name).";"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + + $anvil->data->{process}{anvil}{$anvil_number}{name} = $anvil_name; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "process::anvil::${anvil_number}::name" => $anvil->data->{process}{anvil}{$anvil_number}{name}, + }}); + + my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); + my $count = @{$results}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + results => $results, + count => $count, + }}); + if ($count) + { + $anvil->data->{cgi}{manifest_uuid}{value} = $results->[0]->[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "cgi::manifest_uuid::value" => $anvil->data->{cgi}{manifest_uuid}{value}, + }}); + } + else + { + $anvil->data->{cgi}{manifest_uuid}{value} = "new"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "cgi::manifest_uuid::value" => $anvil->data->{cgi}{manifest_uuid}{value}, + }}); + } + + foreach my $machine_type ("node", "dr") + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { machine_type => $machine_type }}); + foreach my $machine_number (sort {$a cmp $b} keys %{$anvil->data->{anvil}{$anvil_number}{$machine_type}}) + { + my $machine = $machine_type.$machine_number; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + machine => $machine, + machine_number => $machine_number, + }}); + + $anvil->data->{cgi}{bcn_count}{value} = keys %{$anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{network}{bcn}}; + $anvil->data->{cgi}{sn_count}{value} = keys %{$anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{network}{sn}}; + $anvil->data->{cgi}{ifn_count}{value} = keys %{$anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{network}{ifn}}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "cgi::bcn_count::value" => $anvil->data->{cgi}{bcn_count}{value}, + "cgi::sn_count::value" => $anvil->data->{cgi}{sn_count}{value}, + "cgi::ifn_count::value" => $anvil->data->{cgi}{ifn_count}{value}, + }}); + + # The machine might already be initialized, so we'll look in our database for + # any entries ith the same MAC addresses. If none are found, we'll wait to + # ping it on the startup IP and then initialize it. + my $machine_host_uuid = ""; + my $machine_ips = []; + my $startup_ip = $anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{startup_ip}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { startup_ip => $startup_ip }}); + + foreach my $network (sort {$a cmp $b} keys %{$anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{network}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network => $network }}); + foreach my $network_number (sort {$a cmp $b} keys %{$anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{network}{$network}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_number => $network_number }}); + + my $ip_address = $anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{network}{$network}{$network_number}{ip}; + my $subnet_mask = $anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{network}{$network}{$network_number}{subnet_mask}; + my $link1_mac = $anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{network}{$network}{$network_number}{'link'}{1}{mac}; + my $link2_mac = $anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{network}{$network}{$network_number}{'link'}{1}{mac}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:ip_address' => $ip_address, + 's2:subnet_mask' => $subnet_mask, + 's3:link1_mac' => $link1_mac, + 's4:link2_mac' => $link2_mac, + }}); + push @{$machine_ips}, $ip_address."/".$subnet_mask; + + if (not $machine_host_uuid) + { + $machine_host_uuid = get_host_uuid_from_mac($anvil, $link1_mac); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { machine_host_uuid => $machine_host_uuid }}); + } + if (not $machine_host_uuid) + { + $machine_host_uuid = get_host_uuid_from_mac($anvil, $link2_mac); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { machine_host_uuid => $machine_host_uuid }}); + } + + my $network_name = $network.$network_number; + my $network_key = $network_name."_network"; + my $subnet_key = $network_name."_subnet"; + my $gateway_key = $network_name."_gateway"; + my $ip_key = $machine."_".$network_name."_ip"; + $anvil->data->{cgi}{$network_key}{value} = $anvil->Network->get_network({ip => $ip_address, subnet_mask => $subnet_mask}); + $anvil->data->{cgi}{$subnet_key}{value} = $subnet_mask; + $anvil->data->{cgi}{$gateway_key}{value} = $anvil->data->{base}{gateway_network} eq $network_name ? $anvil->data->{base}{gateway_network} : ""; + $anvil->data->{cgi}{$ip_key}{value} = $ip_address; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "cgi::${network_key}::value" => $anvil->data->{cgi}{$network_key}{value}, + "cgi::${subnet_key}::value" => $anvil->data->{cgi}{$subnet_key}{value}, + "cgi::${gateway_key}::value" => $anvil->data->{cgi}{$gateway_key}{value}, + "cgi::${ip_key}::value" => $anvil->data->{cgi}{$ip_key}{value}, + }}); + + if ($network_name eq "bcn1") + { + my $ipmi_ip_key = $machine."_ipmi_ip"; + $anvil->data->{cgi}{$ipmi_ip_key}{value} = $anvil->data->{$machine_type}{$machine_number}{network}{$network}{$network_number}{ipmi_ip}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "cgi::${ipmi_ip_key}::value" => $anvil->data->{cgi}{$ipmi_ip_key}{value}, + }}); + + ### Find the UPSes. + # Preset all known UPSes to not used + foreach my $ups_name (sort {$a cmp $b} keys %{$anvil->data->{upses}{ups_name}}) + { + my $ups_key = $machine."_ups_".$ups_name; + $anvil->data->{cgi}{$ups_key}{value} = ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "cgi::${ups_key}::value" => $anvil->data->{cgi}{$ups_key}{value}, + }}); + } + # Now flip on the ones configured for use + foreach my $ups_number (sort {$a cmp $b} keys %{$anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{ups}}) + { + my $ups_name = $anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{ups}{$ups_number}{name}; + my $ups_key = $machine."_ups_".$ups_name; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + ups_number => $ups_number, + ups_name => $ups_name, + }}); + + $anvil->data->{cgi}{$ups_key}{value} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "cgi::${ups_key}::value" => $anvil->data->{cgi}{$ups_key}{value}, + }}); + } + + ### Find the Fence devices. + # Preset all known fence devices to have no port. + foreach my $fence_name (sort {$a cmp $b} keys %{$anvil->data->{fences}{fence_name}}) + { + my $fence_key = $machine."_fence_".$fence_name; + $anvil->data->{cgi}{$fence_key}{value} = "" if not defined $anvil->data->{cgi}{$fence_key}{value}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "cgi::${fence_key}::value" => $anvil->data->{cgi}{$fence_key}{value}, + }}); + } + foreach my $fence_number (sort {$a cmp $b} keys %{$anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{fence}}) + { + my $fence_name = $anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{fence}{$fence_number}{name}; + my $fence_port = $anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{fence}{$fence_number}{port}; + my $fence_key = $machine."_fence_".$fence_name; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + fence_number => $fence_number, + fence_name => $fence_name, + fence_port => $fence_port, + }}); + + $anvil->data->{cgi}{$fence_key}{value} = $fence_port; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "cgi::${fence_key}::value" => $anvil->data->{cgi}{$fence_key}{value}, + }}); + } + } + } + } + } + } + # Now generate the manifest. + my ($manifest_uuid, $manifest_name) = $anvil->Striker->generate_manifest({debug => 2}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + manifest_uuid => $manifest_uuid, + manifest_name => $manifest_name, + }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0244", variables => { + manifest_name => $manifest_name, + manifest_uuid => $manifest_uuid, + }}); + + $anvil->data->{process}{anvil}{$anvil_number}{manifest_uuid} = $manifest_uuid; + $anvil->data->{process}{anvil}{$anvil_number}{manifest_name} = $manifest_name; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "process::anvil::${anvil_number}::manifest_name" => $anvil->data->{process}{anvil}{$anvil_number}{manifest_name}, + "process::anvil::${anvil_number}::manifest_uuid" => $anvil->data->{process}{anvil}{$anvil_number}{manifest_uuid}, + }}); + } + update_progress($anvil, 55, "job_0245"); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0245"}); + + return(0); +} + +sub add_fences +{ + my ($anvil) = @_; + + # By here, the peer(s) are joined. + update_progress($anvil, 40, "job_0240"); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0240"}); + + foreach my $fence_number (sort {$a cmp $b} keys %{$anvil->data->{fence}}) + { + my $fence_name = $anvil->data->{fence}{$fence_number}{name}; + my $fence_agent = $anvil->data->{fence}{$fence_number}{agent}; + my $fence_arguments = $anvil->data->{fence}{$fence_number}{arguments}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:fence_number' => $fence_number, + 's2:fence_name' => $fence_name, + 's3:fence_agent' => $fence_agent, + 's4:fence_arguments' => $fence_arguments, + }}); + + my ($fence_uuid) = $anvil->Database->insert_or_update_fences({ + fence_agent => $fence_agent, + fence_arguments => $fence_arguments, + fence_name => $fence_name, + }); + if (($fence_uuid) && ($anvil->Validate->uuid({uuid => $fence_uuid}))) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0241", variables => { + fence_name => $fence_name, + fence_agent => $fence_agent, + fence_uuid => $fence_uuid, + }}); + } + else + { + # WTF? + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0249", variables => { + fence_name => $fence_name, + fence_arguments => $fence_arguments, + fence_agent => $fence_agent, + }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "job_0238"}); + update_progress($anvil, 100, "job_0238"); + $anvil->nice_exit({exit_code => 1}); + } + } + + update_progress($anvil, 45, "job_0242"); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0242"}); + + return(0); +} + +sub add_upses +{ + my ($anvil) = @_; + + # By here, the peer(s) are joined. + update_progress($anvil, 30, "job_0236"); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0236"}); + + foreach my $ups_number (sort {$a cmp $b} keys %{$anvil->data->{ups}}) + { + my $ups_name = $anvil->data->{ups}{$ups_number}{name}; + my $ups_agent = $anvil->data->{ups}{$ups_number}{agent}; + my $ups_ip_address = $anvil->data->{ups}{$ups_number}{ip_address}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:ups_number' => $ups_number, + 's2:ups_name' => $ups_name, + 's3:ups_agent' => $ups_agent, + 's4:ups_ip_address' => $ups_ip_address, + }}); + + my ($ups_uuid) = $anvil->Database->insert_or_update_upses({ + ups_agent => $ups_agent, + ups_ip_address => $ups_ip_address, + ups_name => $ups_name, + }); + if (($ups_uuid) && ( $anvil->Validate->uuid({uuid => $ups_uuid}))) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0237", variables => { + ups_name => $ups_name, + ups_ip_address => $ups_ip_address, + ups_agent => $ups_agent, + ups_uuid => $ups_uuid, + }}); + } + else + { + # WTF? + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0248", variables => { + ups_name => $ups_name, + ups_ip_address => $ups_ip_address, + ups_agent => $ups_agent, + }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "job_0238"}); + update_progress($anvil, 100, "job_0238"); + $anvil->nice_exit({exit_code => 1}); + } + } + + update_progress($anvil, 35, "job_0239"); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0239"}); + + return(0); +} + +# This takes a MAC address and returns the host_uuid, if found. +sub get_host_uuid_from_mac +{ + my ($anvil, $mac_address) = @_; + + my $host_uuid = ""; + my $query = " +SELECT + network_interface_host_uuid +FROM + network_interfaces +WHERE + network_interface_operational != 'DELETED' +AND + network_interface_mac_address = ".$anvil->Database->quote($mac_address)." +;"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, 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 => 2, list => { + results => $results, + count => $count, + }}); + if ($count) + { + $host_uuid = $results->[0]->[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_uuid => $host_uuid }}); + } + + return($host_uuid); +} + +# Merge my peer Striker. +sub merge_peer_striker +{ + my ($anvil) = @_; + + # For each peer, see if we're already connected to it. + update_progress($anvil, 0, "clear"); + update_progress($anvil, 10, "job_0234"); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0234"}); + foreach my $striker_number (sort {$a cmp $b} keys %{$anvil->data->{striker}}) + { + next if $striker_number !~ /^\d+$/; + next if $striker_number == $anvil->data->{i_am}{striker}; + next if not exists $anvil->data->{striker}{$striker_number}{network}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { striker_number => $striker_number }}); + + # Use the MAC address(es) to look for a host UUID. If we don't find one, we need to peer it. + my $peer_host_uuid = ""; + my $peer_ips = []; + foreach my $network (sort {$a cmp $b} keys %{$anvil->data->{striker}{$striker_number}{network}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network => $network }}); + foreach my $network_number (sort {$a cmp $b} keys %{$anvil->data->{striker}{$striker_number}{network}{$network}}) + { + my $ip = $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{ip}; + my $subnet_mask = $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{subnet_mask}; + push @{$peer_ips}, $ip."/".$subnet_mask; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + network_number => $network_number, + ip => $ip, + subnet_mask => $subnet_mask, + }}); + foreach my $link_number (sort {$a cmp $b} keys %{$anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{'link'}}) + { + next if $peer_host_uuid; + my $mac_address = lc($anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{'link'}{$link_number}{mac}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + link_number => $link_number, + mac_address => $mac_address, + }}); + $peer_host_uuid = get_host_uuid_from_mac($anvil, $mac_address); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peer_host_uuid => $peer_host_uuid }}); + } + } + } + + if (not $peer_host_uuid) + { + ### Add the peer. + # First, wait for access. + my $waiting = 1; + my $joining = 0; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0227", variables => { number => $striker_number }}); + + while ($waiting) + { + foreach my $network (@{$peer_ips}) + { + next if not $waiting; + my ($ip, $subnet_mask) = ($network =~ /^(.*?)\/(.*)$/); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + ip => $ip, + subnet_mask => $subnet_mask, + }}); + + # Try to read the host uuid. + my $file = $anvil->data->{path}{data}{host_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file => $file }}); + my $shell_call = " +if [ -e ".$file." ]; +then + cat ".$file."; +else + echo 0; +fi; +"; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0166", variables => { + shell_call => $shell_call, + target => $ip, + remote_user => "root", + }}); + my ($host_uuid, $error, $return_code) = $anvil->Remote->call({ + shell_call => $shell_call, + target => $ip, + password => $anvil->data->{base}{password}{desired}, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + host_uuid => $host_uuid, + error => $error, + return_code => $return_code, + }}); + if (($host_uuid) && ($anvil->Validate->uuid({uuid => $host_uuid}))) + { + # Success! + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0228", variables => { + number => $striker_number, + ip => $ip, + }}); + + $peer_host_uuid = $host_uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peer_host_uuid => $peer_host_uuid }}); + + # Find the IP we used to reach the peer. + my $our_ip = ""; + $anvil->Network->load_ips({ + host => "local", + host_uuid => $anvil->Get->host_uuid(), + }); + foreach my $interface_name (sort {$a cmp $b} keys %{$anvil->data->{network}{'local'}{interface}}) + { + my $local_ip = $anvil->data->{network}{'local'}{interface}{$interface_name}{ip}; + my $local_subnet_mask = $anvil->data->{network}{'local'}{interface}{$interface_name}{subnet_mask}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + interface_name => $interface_name, + local_ip => $local_ip, + local_subnet_mask => $local_subnet_mask, + }}); + next if $local_subnet_mask ne $subnet_mask; + + # See if this IP is in the same subnet. + my $first = NetAddr::IP->new($local_ip."/".$local_subnet_mask); + my $second = NetAddr::IP->new($ip."/".$subnet_mask); + if ($second->within($first)) + { + # Found the IP to tell the peer to use + $our_ip = $local_ip; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { our_ip => $our_ip }}); + last; + } + } + + if (not $our_ip) + { + # wtf; + die; + } + + # Register a job and then wait for it to show up in our database. + my $job_data = "password=".$anvil->data->{base}{password}{desired}."\n"; + $job_data .= "peer_job_command=".$anvil->data->{path}{exe}{'striker-manage-peers'}." --add --host-uuid ".$anvil->Get->host_uuid." --host ".$our_ip." --port 5432 --ping 1"; + my $job_command = $anvil->data->{path}{exe}{'striker-manage-peers'}." --add --host-uuid ".$host_uuid." --host ".$ip." --port 5432 --ping 1"; + $waiting = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + job_command => $job_command, + job_data => $anvil->Log->is_secure($job_data), + waiting => $waiting, + }}); + my ($job_uuid) = $anvil->Database->insert_or_update_jobs({ + job_command => $job_command, + job_data => $job_data, + job_name => "striker-peer::remove", + job_title => "job_0013", + job_description => "job_0014", + job_progress => 0, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }}); + } + else + { + # No access + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0229", variables => { + number => $striker_number, + ip => $ip, + }}); + } + } + if ($waiting) + { + # Wait 30 seconds and try again + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0230", variables => { number => $striker_number }}); + sleep 30; + } + } + } + + # Now wait until the peer is in our database. + my $peer_host_name = ""; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0231", variables => { + number => $striker_number, + peer_host_uuid => $peer_host_uuid, + }}); + until ($peer_host_name) + { + my $query = "SELECT host_name FROM hosts WHERE host_uuid = ".$anvil->Database->quote($peer_host_uuid).";"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, 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 => 2, list => { + results => $results, + count => $count, + }}); + if ($count) + { + $peer_host_name = $results->[0]->[0]; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0232", variables => { + number => $striker_number, + peer_host_name => $peer_host_name, + }}); + } + else + { + # Sleep for a bit. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0233", variables => { + number => $striker_number, + peer_host_uuid => $peer_host_uuid, + }}); + sleep 5; + } + } + } + + # By here, the peer(s) are joined. + update_progress($anvil, 20, "job_0235"); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0235"}); + + return(0); +} + +# This preps and requests the initial configuration job. +sub striker_stage1 +{ + my ($anvil) = @_; + + ### TODO: Validate all steps up front before starting anything. + if ((not defined $anvil->data->{base}{organization_name}) or (not $anvil->data->{base}{organization_name})) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0243", variables => { variable => 'base::organization_name' }}); + $anvil->nice_exit({exit_code => 1}); + } + if ((not defined $anvil->data->{base}{prefix}) or (not $anvil->data->{base}{prefix})) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0243", variables => { variable => 'base::prefix' }}); + $anvil->nice_exit({exit_code => 1}); + } + elsif (length($anvil->data->{base}{prefix}) > 5) + { + # Prefix is too long + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0244", variables => { + prefix => $anvil->data->{base}{prefix}, + 'length' => length($anvil->data->{base}{prefix}), + }}); + $anvil->nice_exit({exit_code => 1}); + } + if ((not defined $anvil->data->{base}{domain}) or (not $anvil->data->{base}{domain})) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0243", variables => { variable => 'base::domain' }}); + $anvil->nice_exit({exit_code => 1}); + } + elsif (not $anvil->Validate->domain_name({name => $anvil->data->{base}{domain}})) + { + # Domain is not valid + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0117", variables => { name => $anvil->data->{base}{domain} }}); + $anvil->nice_exit({exit_code => 1}); + } + if ((not defined $anvil->data->{base}{password}{desired}) or (not $anvil->data->{base}{password}{desired})) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0243", variables => { variable => 'base::password::desired' }}); + $anvil->nice_exit({exit_code => 1}); + } + if ((not defined $anvil->data->{base}{dns}) or (not $anvil->data->{base}{dns})) + { + $anvil->data->{base}{dns} = "8.8.8.8,8.8.4.4"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "base::dns" => $anvil->data->{base}{dns} }}); + } + else + { + # Make sure any/all DNS are valid. + foreach my $ip (split/,/, $anvil->data->{base}{dns}) + { + if (not $anvil->Validate->ipv4({ip => $ip})) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0245", variables => { ip => $ip }}); + $anvil->nice_exit({exit_code => 1}); + } + } + } + if ((defined $anvil->data->{base}{gateway}) && ($anvil->data->{base}{gateway})) + { + if (not $anvil->Validate->ipv4({ip => $anvil->data->{base}{gateway}})) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0246", variables => { ip => $anvil->data->{base}{gateway} }}); + $anvil->nice_exit({exit_code => 1}); + } + } + + my $striker_number = $anvil->data->{i_am}{striker}; + my $organization_name = $anvil->data->{base}{organization_name}; + my $prefix = $anvil->data->{base}{prefix}; + my $domain = $anvil->data->{base}{domain}; + my $ifn_count = keys %{$anvil->data->{striker}{$striker_number}{network}{ifn}}; + my $host_name = $prefix."-striker0".$striker_number.".".$domain; + my $new_password = $anvil->data->{base}{password}{desired}; + my $dns = $anvil->data->{base}{dns}; + my $gateway = $anvil->data->{base}{gateway}; + my $gateway_network = defined $anvil->data->{base}{gateway_network} ? $anvil->data->{base}{gateway_network} : "ifn1"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + striker_number => $striker_number, + organization_name => $organization_name, + prefix => $prefix, + domain => $domain, + ifn_count => $ifn_count, + host_name => $host_name, + new_password => $anvil->Log->is_secure($new_password), + dns => $dns, + gateway => $gateway, + gateway_network => $gateway_network, + }}); + + # Load the variables. + $anvil->data->{striker}{stage1}{variables}{'form::config_step1::organization::value'}{variable_value} = $organization_name; + $anvil->data->{striker}{stage1}{variables}{'form::config_step1::organization::value'}{variable_description} = "striker_0004"; + $anvil->data->{striker}{stage1}{variables}{'form::config_step1::organization::value'}{variable_section} = "config_step1"; + $anvil->data->{striker}{stage1}{variables}{'form::config_step1::prefix::value'}{variable_value} = $prefix; + $anvil->data->{striker}{stage1}{variables}{'form::config_step1::prefix::value'}{variable_description} = "striker_0006"; + $anvil->data->{striker}{stage1}{variables}{'form::config_step1::prefix::value'}{variable_section} = "config_step1"; + $anvil->data->{striker}{stage1}{variables}{'form::config_step1::domain::value'}{variable_value} = $domain; + $anvil->data->{striker}{stage1}{variables}{'form::config_step1::domain::value'}{variable_description} = "striker_0008"; + $anvil->data->{striker}{stage1}{variables}{'form::config_step1::domain::value'}{variable_section} = "config_step1"; + $anvil->data->{striker}{stage1}{variables}{'form::config_step1::ifn_count::value'}{variable_value} = $ifn_count; + $anvil->data->{striker}{stage1}{variables}{'form::config_step1::ifn_count::value'}{variable_description} = "striker_0012"; + $anvil->data->{striker}{stage1}{variables}{'form::config_step1::ifn_count::value'}{variable_section} = "config_step1"; + $anvil->data->{striker}{stage1}{variables}{'form::config_step1::sequence::value'}{variable_value} = $striker_number; + $anvil->data->{striker}{stage1}{variables}{'form::config_step1::sequence::value'}{variable_description} = "striker_0010"; + $anvil->data->{striker}{stage1}{variables}{'form::config_step1::sequence::value'}{variable_section} = "config_step1"; + $anvil->data->{striker}{stage1}{variables}{'form::config_step2::host_name::value'}{variable_value} = $host_name; + $anvil->data->{striker}{stage1}{variables}{'form::config_step2::host_name::value'}{variable_description} = "striker_0017"; + $anvil->data->{striker}{stage1}{variables}{'form::config_step2::host_name::value'}{variable_section} = "config_step2"; + $anvil->data->{striker}{stage1}{variables}{'form::config_step2::striker_user::value'}{variable_value} = "admin"; + $anvil->data->{striker}{stage1}{variables}{'form::config_step2::striker_user::value'}{variable_description} = "striker_0032"; + $anvil->data->{striker}{stage1}{variables}{'form::config_step2::striker_user::value'}{variable_section} = "config_step2"; + $anvil->data->{striker}{stage1}{variables}{'form::config_step2::striker_password::value'}{variable_value} = $new_password; + $anvil->data->{striker}{stage1}{variables}{'form::config_step2::striker_password::value'}{variable_description} = "striker_0034"; + $anvil->data->{striker}{stage1}{variables}{'form::config_step2::striker_password::value'}{variable_section} = "config_step2"; + $anvil->data->{striker}{stage1}{variables}{'form::config_step2::dns::value'}{variable_value} = $dns; + $anvil->data->{striker}{stage1}{variables}{'form::config_step2::dns::value'}{variable_description} = "striker_0038"; + $anvil->data->{striker}{stage1}{variables}{'form::config_step2::dns::value'}{variable_section} = "config_step2"; + $anvil->data->{striker}{stage1}{variables}{'form::config_step2::gateway::value'}{variable_value} = $gateway; + $anvil->data->{striker}{stage1}{variables}{'form::config_step2::gateway::value'}{variable_description} = "striker_0036"; + $anvil->data->{striker}{stage1}{variables}{'form::config_step2::gateway::value'}{variable_section} = "config_step2"; + $anvil->data->{striker}{stage1}{variables}{'form::config_step2::gateway_interface::value'}{variable_value} = $gateway_network; + $anvil->data->{striker}{stage1}{variables}{'form::config_step2::gateway_interface::value'}{variable_description} = ""; + $anvil->data->{striker}{stage1}{variables}{'form::config_step2::gateway_interface::value'}{variable_section} = "config_step2"; + foreach my $network (sort {$a cmp $b} keys %{$anvil->data->{striker}{$striker_number}{network}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network => $network }}); + foreach my $network_number (sort {$a cmp $b} keys %{$anvil->data->{striker}{$striker_number}{network}{$network}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_number => $network_number }}); + if ((not defined $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{ip}) or (not $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{ip})) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0243", variables => { + variable => "striker::${striker_number}::network::${network}::${network_number}::ip", + }}); + $anvil->nice_exit({exit_code => 1}); + } + elsif (not $anvil->Validate->ipv4({ip => $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{ip}})) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0247", variables => { + variable => "striker::${striker_number}::network::${network}::${network_number}::ip", + value => $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{ip}, + }}); + $anvil->nice_exit({exit_code => 1}); + } + if ((not defined $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{subnet_mask}) or (not $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{subnet_mask})) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0243", variables => { + variable => "striker::${striker_number}::network::${network}::${network_number}::subnet_mask", + }}); + $anvil->nice_exit({exit_code => 1}); + } + elsif (not $anvil->Validate->ipv4({ip => $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{subnet_mask}})) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0247", variables => { + variable => "striker::${striker_number}::network::${network}::${network_number}::subnet_mask", + value => $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{subnet_mask}, + }}); + $anvil->nice_exit({exit_code => 1}); + } + if ((not defined $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{'link'}{1}{mac}) or (not $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{'link'}{1}{mac})) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0243", variables => { + variable => "striker::${striker_number}::network::${network}::${network_number}::link::1::mac", + }}); + $anvil->nice_exit({exit_code => 1}); + } + + my $ip_key = "form::config_step2::".$network.$network_number."_ip::value"; + my $ip = $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{ip}; + my $subnet_mask_key = "form::config_step2::".$network.$network_number."_subnet_mask::value"; + my $subnet_mask = $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{subnet_mask}; + my $link1_mac_key = "form::config_step2::".$network.$network_number."_link1_mac_to_set::value"; + my $link1_mac = $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{'link'}{1}{mac}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:ip_key' => $ip_key, + 's2:ip' => $ip, + 's3:subnet_mask_key' => $subnet_mask_key, + 's4:subnet_mask' => $subnet_mask, + 's4:link1_mac_key' => $link1_mac_key, + 's5:link1_mac' => $link1_mac, + }}); + + $anvil->data->{striker}{stage1}{variables}{$ip_key}{variable_value} = $ip; + $anvil->data->{striker}{stage1}{variables}{$ip_key}{variable_description} = "striker_0024"; + $anvil->data->{striker}{stage1}{variables}{$ip_key}{variable_section} = "config_step2"; + $anvil->data->{striker}{stage1}{variables}{$subnet_mask_key}{variable_value} = $subnet_mask; + $anvil->data->{striker}{stage1}{variables}{$subnet_mask_key}{variable_description} = "striker_0025"; + $anvil->data->{striker}{stage1}{variables}{$subnet_mask_key}{variable_section} = "config_step2"; + $anvil->data->{striker}{stage1}{variables}{$link1_mac_key}{variable_value} = $link1_mac; + $anvil->data->{striker}{stage1}{variables}{$link1_mac_key}{variable_description} = "striker_0029"; + $anvil->data->{striker}{stage1}{variables}{$link1_mac_key}{variable_section} = "config_step2"; + + if (exists $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{'link'}{2}) + { + if ((not defined $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{'link'}{2}{mac}) or (not $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{'link'}{2}{mac})) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0243", variables => { + variable => "striker::${striker_number}::network::${network}::${network_number}::link::2::mac", + }}); + $anvil->nice_exit({exit_code => 1}); + } + my $link2_mac_key = "form::config_step2::".$network.$network_number."_link2_mac_to_set::value"; + my $link2_mac = $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{'link'}{2}{mac}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:link2_mac_key' => $link2_mac_key, + 's2:link2_mac' => $link2_mac, + }}); + $anvil->data->{striker}{stage1}{variables}{$link2_mac_key}{variable_value} = $link2_mac; + $anvil->data->{striker}{stage1}{variables}{$link2_mac_key}{variable_description} = "striker_0029"; + $anvil->data->{striker}{stage1}{variables}{$link2_mac_key}{variable_section} = "config_step2"; + } + } + } + + # Now, for each variable, record it to the database. + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{striker}{stage1}{variables}}) + { + my $value = $anvil->data->{striker}{stage1}{variables}{$variable}{variable_value}; + my $description = $anvil->data->{striker}{stage1}{variables}{$variable}{variable_description}; + my $section = $anvil->data->{striker}{stage1}{variables}{$variable}{variable_section}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:variable' => $variable, + 's2:value' => $value, + 's3:description' => $description, + 's4:section' => $section, + }}); + + my ($variable_uuid) = $anvil->Database->insert_or_update_variables({ + variable_name => $variable, + variable_value => $value, + variable_default => "", + variable_description => $description, + variable_section => $section, + variable_source_uuid => $anvil->Get->host_uuid, + variable_source_table => "hosts", + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }}); + + } + + # Call anvil-configure-host now. + my ($job_uuid) = $anvil->Database->insert_or_update_jobs({ + debug => 2, + job_host_uuid => $anvil->data->{cgi}{host_uuid}{value}, + job_command => $anvil->data->{path}{exe}{'anvil-configure-host'}, + job_data => "form::config_step2", + job_name => "configure::network", + job_title => "job_0001", + job_description => "job_0071", + job_progress => 0, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }}); + + # If we're striker 1, add a job to restart ourselves when ScanCore starts (after the reboot) + if ($striker_number eq "1") + { + my ($job_uuid) = $anvil->Database->insert_or_update_jobs({ + debug => 2, + job_host_uuid => $anvil->data->{cgi}{host_uuid}{value}, + job_command => $anvil->data->{path}{exe}{'striker-auto-initialize-all'}." --config ".$anvil->data->{switches}{config}, + job_data => "", + job_name => "configure::auto_initialize", + job_title => "job_0225", + job_description => "job_0226", + job_status => "scancore_startup", + job_progress => 0, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }}); + } + + return(0); +} + +# This looks to see if we can map a 'striker::X::' to this machine. +sub find_myself +{ + my ($anvil) = @_; + + # Find my MAC addresses. + my $short_host_name = $anvil->Get->short_host_name(); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { short_host_name => $short_host_name }}); + + $anvil->Network->get_ips({debug => 3}); + + $anvil->data->{i_am}{striker} = 0; + foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{$short_host_name}{interface}}) + { + my $ip_address = $anvil->data->{network}{$short_host_name}{interface}{$interface}{ip}; + my $subnet_mask = $anvil->data->{network}{$short_host_name}{interface}{$interface}{subnet_mask}; + my $mac_address = $anvil->data->{network}{$short_host_name}{interface}{$interface}{mac_address}; + my $mtu = $anvil->data->{network}{$short_host_name}{interface}{$interface}{mtu}; + my $default_gateway = $anvil->data->{network}{$short_host_name}{interface}{$interface}{default_gateway}; + my $gateway = $anvil->data->{network}{$short_host_name}{interface}{$interface}{gateway}; + my $dns = $anvil->data->{network}{$short_host_name}{interface}{$interface}{dns}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + interface => $interface, + ip_address => $ip_address, + subnet_mask => $subnet_mask, + mac_address => $mac_address, + mtu => $mtu, + default_gateway => $default_gateway, + gateway => $gateway, + dns => $dns, + }}); + + foreach my $striker_number (sort {$a cmp $b} keys %{$anvil->data->{striker}}) + { + next if $striker_number !~ /^\d+$/; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { striker_number => $striker_number }}); + foreach my $network (sort {$a cmp $b} keys %{$anvil->data->{striker}{$striker_number}{network}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network => $network }}); + foreach my $network_number (sort {$a cmp $b} keys %{$anvil->data->{striker}{$striker_number}{network}{$network}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_number => $network_number }}); + foreach my $link_number (sort {$a cmp $b} keys %{$anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{'link'}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { link_number => $link_number }}); + + my $this_mac_address = lc($anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{'link'}{$link_number}{mac}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + mac_address => $mac_address, + this_mac_address => $this_mac_address, + }}); + if ((not $anvil->data->{i_am}{striker}) && ($this_mac_address eq $mac_address)) + { + # This is us. + $anvil->data->{i_am}{striker} = $striker_number; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "i_am::striker" => $anvil->data->{i_am}{striker} }}); + return($anvil->data->{i_am}{striker}); + } + } + } + } + } + } + + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { i_am_striker => $anvil->data->{i_am}{striker} }}); + return($anvil->data->{i_am}{striker}); +} + + +# If this is being called as a job, this will allow the progress to be updated. +sub update_progress +{ + my ($anvil, $progress, $message) = @_; + + $progress = 95 if $progress > 100; + if (not $anvil->data->{switches}{'job-uuid'}) + { + return(0); + } + + $anvil->Job->update_progress({ + progress => $progress, + message => $message, + job_uuid => $anvil->data->{switches}{'job-uuid'}, + }); + + return(0); +} diff --git a/tools/striker-auto-initialize-all.example b/tools/striker-auto-initialize-all.example index 7e92e2dd..a997faae 100644 --- a/tools/striker-auto-initialize-all.example +++ b/tools/striker-auto-initialize-all.example @@ -1,20 +1,160 @@ # This is an example script to feed to 'striker-auto-initialize-all'. # -base::password::current = Initial1 -base::password::desired = super secret password +############################################################################################################# +# Common values # +############################################################################################################# +# This is the listed owner, department or organization who this Anvil! serves. base::organization_name = Alteeve's Niche! + +# The prefix for the Anvil! system. The can be up to five characters long. base::prefix = an + +# This is the domain to use for the Anvil! and member machine host names. base::domain = alteeve.com + +# These are the DNS server to use when configuring networks, comma separated. base::dns = 8.8.8.8,8.8.4.4 + +# If you have specific NTP servers to use, specify them here +base::ntp = + +# If you want to set a specific MTU, set it here. +base::mtu = + +# When generating the Anvil! install manifest, what will the Anvil! sequence be? +base::anvil::sequence = 1 + +# This is the default gateway for the IFN base::gateway = 192.168.122.1 -base::interface = ifn1 -# Startup IP is used for peers to find us -striker::1::network::startup_ip = 192.168.122.145 -striker::1::network::ifn::1::ip = 192.168.122.11 +# This is the IFN network on which the gateway will be configured. +base::gateway_network = ifn1 + +# This is the startup password for newly built nodes and DR hosts we'll be integrating. +base::password::current = Initial1 + +# This is the password to set for all systems. +base::password::desired = super secret password + +# If registering with RH, here is where you can set your credentials. +base::rhn::user = +base::rhn::password = + + +############################################################################################################# +# Striker configurations # +############################################################################################################# + +### NOTE: 'striker::1::' is the Striker that will merge the dashboards, initialize nodes / DR, create the +### install manifest (and fence devices / upses), and assemble the nodes. As such, 'striker::1::' is +### required! +striker::1::network::ifn::1::ip = 192.168.122.251 striker::1::network::ifn::1::subnet_mask = 255.255.255.0 -striker::1::network::ifn::1::link::1::mac = aa:bb:cc:dd:ee:ff -striker::1::network::bcn::1::ip = 192.168.122.11 -striker::1::network::bcn::1::subnet_mask = 255.255.255.0 -striker::1::network::bcn::1::link::1::mac = aa:bb:cc:dd:ff:00 +striker::1::network::ifn::1::link::1::mac = 52:54:00:df:03:e +striker::1::network::ifn::1::link::2::mac = 52:54:00:45:6e:5d +striker::1::network::bcn::1::ip = 10.201.4.1 +striker::1::network::bcn::1::subnet_mask = 255.255.0.0 +striker::1::network::bcn::1::link::1::mac = 52:54:00:d9:24:52 +striker::1::network::bcn::1::link::2::mac = 52:54:00:aa:4d:e0 + +striker::2::network::ifn::1::ip = 192.168.122.252 +striker::2::network::ifn::1::subnet_mask = 255.255.255.0 +striker::2::network::ifn::1::link::1::mac = 52:54:00:41:1f:7d +striker::2::network::ifn::1::link::2::mac = 52:54:00:33:f7:de +striker::2::network::bcn::1::ip = 10.201.4.2 +striker::2::network::bcn::1::subnet_mask = 255.255.0.0 +striker::2::network::bcn::1::link::1::mac = 52:54:00:b8:34:a7 +striker::2::network::bcn::1::link::2::mac = 52:54:00:30:f9:db + + +############################################################################################################# +# Node and DR configuration # +############################################################################################################# + +### UPSes - Optional +# Note: The 'ups_agent' is the ScanCore agent that will be used to monitor to state/health of the UPSes. +ups::1::name = an-ups01 +ups::1::agent = scan-apc-ups +ups::1::ip_address = 10.201.3.1 +ups::2::name = an-ups01 +ups::2::agent = scan-apc-ups +ups::2::ip_address = 10.201.3.1 + +### Fence device(s) +# NOTE: Do NOT specify fence_ipmilan! It is detected / configured automatically. +# The fence_arguments only needs to contain variable="value" pairs that don't have a useful default. +fence::1::name = gravitar +fence::1::agent = virsh +fence::1::arguments = action="reboot" ip="192.168.122.1" password_script="/root/gravitar_password" username="root" + +# Example PDUs +#fence::2::name = an-pdu01 +#fence::2::agent = apc_snmp +#fence::2::arguments = action="reboot" ip="10.201.2.1" +#fence::3::name = an-pdu02 +#fence::3::agent = apc_snmp +#fence::3::arguments = action="reboot" ip="10.201.2.2" + +# Anvil description +anvil::1::description = "Test Anvil! running on gravitar" + +### Nodes +anvil::1::node::1::start_ip = 192.168.122.235 +anvil::1::node::1::network::ifn::1::ip = 192.168.122.11 +anvil::1::node::1::network::ifn::1::subnet_mask = 255.255.255.0 +anvil::1::node::1::network::ifn::1::link::1::mac = 52:54:00:17:d6:0b +anvil::1::node::1::network::ifn::1::link::2::mac = 52:54:00:c4:87:b6 +anvil::1::node::1::network::bcn::1::ip = 10.201.10.1 +anvil::1::node::1::network::bcn::1::ipmi_ip = 10.201.11.1 +anvil::1::node::1::network::bcn::1::subnet_mask = 255.255.0.0 +anvil::1::node::1::network::bcn::1::link::1::mac = 52:54:00:d2:6b:0b +anvil::1::node::1::network::bcn::1::link::2::mac = 52:54:00:01:11:0e +anvil::1::node::1::network::sn::1::ip = 10.101.4.1 +anvil::1::node::1::network::sn::1::subnet_mask = 255.255.0.0 +anvil::1::node::1::network::sn::1::link::1::mac = 52:54:00:7e:b8:9e +anvil::1::node::1::network::sn::1::link::2::mac = 52:54:00:23:e8:46 +# Fence (IPMI configured automatically), same fence types grouped automatically +anvil::1::node::1::fence::1::name = gravitar +anvil::1::node::1::fence::1::port = an-a01n01 +#anvil::1::node::1::fence::2::name = an-pdu01 +#anvil::1::node::1::fence::2::port = 1 +#anvil::1::node::1::fence::3::name = an-pdu02 +#anvil::1::node::1::fence::3::port = 1 +# Set for UPSes powering the node, if any +#anvil::1::node::1::ups::1::name = an-ups01 +#anvil::1::node::1::ups::2::name = an-ups02 + +anvil::1::node::2::start_ip = 192.168.122.185 +anvil::1::node::2::network::ifn::1::ip = 192.168.122.12 +anvil::1::node::2::network::ifn::1::subnet_mask = 255.255.255.0 +anvil::1::node::2::network::ifn::1::link::1::mac = 52:54:00:09:b7:90 +anvil::1::node::2::network::ifn::1::link::2::mac = 52:54:00:78:a3:41 +anvil::1::node::2::network::bcn::1::ip = 10.201.10.2 +anvil::1::node::2::network::bcn::1::ipmi_ip = 10.201.11.2 +anvil::1::node::2::network::bcn::1::subnet_mask = 255.255.0.0 +anvil::1::node::2::network::bcn::1::link::1::mac = 52:54:00:06:2e:2d +anvil::1::node::2::network::bcn::1::link::2::mac = 52:54:00:14:16:98 +anvil::1::node::2::network::sn::1::ip = 10.101.4.2 +anvil::1::node::2::network::sn::1::subnet_mask = 255.255.0.0 +anvil::1::node::2::network::sn::1::link::1::mac = 52:54:00:79:1c:ce +anvil::1::node::2::network::sn::1::link::2::mac = 52:54:00:5d:d3:6d +# Set for UPSes powering the node, if any +anvil::1::node::2::ups::1::name = an-ups01 +anvil::1::node::2::ups::2::name = an-ups02 + +### DR host (optional) +anvil::1::dr::1::start_ip = 192.168.122.153 +anvil::1::dr::1::network::ifn::1::ip = 192.168.122.10 +anvil::1::dr::1::network::ifn::1::subnet_mask = 255.255.255.0 +anvil::1::dr::1::network::ifn::1::link::1::mac = 52:54:00:6d:05:5e +anvil::1::dr::1::network::ifn::1::link::2::mac = 52:54:00:7e:87:ec +anvil::1::dr::1::network::bcn::1::ip = 10.201.10.3 +anvil::1::dr::1::network::bcn::1::ipmi_ip = 10.201.11.3 +anvil::1::dr::1::network::bcn::1::subnet_mask = 255.255.0.0 +anvil::1::dr::1::network::bcn::1::link::1::mac = 52:54:00:6a:88:c2 +anvil::1::dr::1::network::bcn::1::link::2::mac = 52:54:00:4b:58:fe +anvil::1::dr::1::network::sn::1::ip = 10.101.4.3 +anvil::1::dr::1::network::sn::1::subnet_mask = 255.255.0.0 +anvil::1::dr::1::network::sn::1::link::1::mac = 52:54:00:d6:f8:8d +anvil::1::dr::1::network::sn::1::link::2::mac = 52:54:00:51:7b:b6