diff --git a/Anvil/Tools.pm b/Anvil/Tools.pm index b56b44d7..b20248c9 100644 --- a/Anvil/Tools.pm +++ b/Anvil/Tools.pm @@ -243,7 +243,7 @@ sub new # I need to read the initial words early. $anvil->Words->read({debug => $debug}); - # If the local './tools.conf' file exists, read it in. + # If the local './anvil.conf' file exists, read it in. if (-r $anvil->data->{path}{configs}{'anvil.conf'}) { $anvil->Storage->read_config({debug => 3, file => $anvil->data->{path}{configs}{'anvil.conf'}}); @@ -955,6 +955,9 @@ sub _set_defaults hash_count => 500000, salt_length => 16, }, + privacy => { + strong => 0, + }, # On actual RHEL systems, this will be used to ensure that given repos are enabled on given # machines types. Obviously, this requires that the host has been subscribed. rhel => { diff --git a/Anvil/Tools/DRBD.pm b/Anvil/Tools/DRBD.pm index fcc1a1a6..a598a9e9 100755 --- a/Anvil/Tools/DRBD.pm +++ b/Anvil/Tools/DRBD.pm @@ -409,18 +409,22 @@ sub get_devices } foreach my $volume_href (@{$host_href->{volume}}) { - my $volume = $volume_href->{vnr}; - my $drbd_path = $volume_href->{device}->[0]->{content}; - my $lv_path = $volume_href->{disk}->[0]; - $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{volume}{$volume}{drbd_path} = $drbd_path; - $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{volume}{$volume}{drbd_minor} = $volume_href->{device}->[0]->{minor}; - $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{volume}{$volume}{'meta-disk'} = $volume_href->{'meta-disk'}->[0]; - $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{volume}{$volume}{backing_lv} = $lv_path; + my $volume = $volume_href->{vnr}; + my $drbd_path = $volume_href->{device}->[0]->{content}; + my $lv_path = $volume_href->{disk}->[0]; + my $by_res = "/dev/drbd/by-res/".$this_resource."/".$volume; + my $minor = $volume_href->{device}->[0]->{minor}; + $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{volume}{$volume}{drbd_path} = "/dev/drbd".$minor; + $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{volume}{$volume}{drbd_path_by_res} = $by_res; + $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{volume}{$volume}{drbd_minor} = $minor; + $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{volume}{$volume}{'meta-disk'} = $volume_href->{'meta-disk'}->[0]; + $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{volume}{$volume}{backing_lv} = $lv_path; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "drbd::config::${host}::resource::${this_resource}::volume::${volume}::drbd_path" => $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{volume}{$volume}{drbd_path}, - "drbd::config::${host}::resource::${this_resource}::volume::${volume}::drbd_minor" => $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{volume}{$volume}{drbd_minor}, - "drbd::config::${host}::resource::${this_resource}::volume::${volume}::meta-disk" => $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{volume}{$volume}{'meta-disk'}, - "drbd::config::${host}::resource::${this_resource}::volume::${volume}::backing_lv" => $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{volume}{$volume}{backing_lv}, + "drbd::config::${host}::resource::${this_resource}::volume::${volume}::drbd_path" => $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{volume}{$volume}{drbd_path}, + "drbd::config::${host}::resource::${this_resource}::volume::${volume}::drbd_path_by_res" => $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{volume}{$volume}{drbd_path_by_res}, + "drbd::config::${host}::resource::${this_resource}::volume::${volume}::drbd_minor" => $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{volume}{$volume}{drbd_minor}, + "drbd::config::${host}::resource::${this_resource}::volume::${volume}::meta-disk" => $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{volume}{$volume}{'meta-disk'}, + "drbd::config::${host}::resource::${this_resource}::volume::${volume}::backing_lv" => $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{volume}{$volume}{backing_lv}, }}); if (($anvil->data->{drbd}{config}{$host}{host}) && ($anvil->data->{drbd}{config}{$host}{host} eq $this_host)) { @@ -433,6 +437,18 @@ sub get_devices "drbd::config::${host}::lv_path::${lv_path}::under" => $anvil->data->{drbd}{config}{$host}{lv_path}{$lv_path}{under}, }}); } + + # If this is ourself, store the resource name and backing LV in the 'by-res' + # hash. + if ($anvil->Network->is_local({host => $this_host})) + { + $anvil->data->{drbd}{config}{$host}{'by-res'}{$by_res}{resource} = $this_resource; + $anvil->data->{drbd}{config}{$host}{'by-res'}{$by_res}{backing_lv} = $lv_path; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "drbd::config::${host}::by-res::${by_res}::resource" => $anvil->data->{drbd}{config}{$host}{'by-res'}{$by_res}{resource}, + "drbd::config::${host}::by-res::${by_res}::backing_lv" => $anvil->data->{drbd}{config}{$host}{'by-res'}{$by_res}{backing_lv}, + }}); + } } } diff --git a/Anvil/Tools/Get.pm b/Anvil/Tools/Get.pm index e55cb611..49852455 100644 --- a/Anvil/Tools/Get.pm +++ b/Anvil/Tools/Get.pm @@ -271,59 +271,167 @@ sub bridges delete $anvil->data->{'local'}{network}{bridges}; }; + my $bridge_data = ""; my $json = JSON->new->allow_nonref; - my $bridge_data = $json->decode($output); - #print Dumper $bridge_data; - foreach my $hash_ref (@{$bridge_data}) + eval { $bridge_data = $json->decode($output); }; + if ($@) { - # If the ifname and master are the same, it's a bridge. - my $type = "interface"; - my $interface = $hash_ref->{ifname}; - my $master_bridge = $hash_ref->{master}; - if ($interface eq $master_bridge) - { - $type = "bridge"; - $anvil->data->{'local'}{network}{bridges}{bridge}{$interface}{found} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "local::network::bridges::bridge::${interface}::found" => $anvil->data->{'local'}{network}{bridges}{bridge}{$interface}{found}, - }}); - } - else - { - # Store this interface under the bridge. - $anvil->data->{'local'}{network}{bridges}{bridge}{$master_bridge}{connected_interface}{$interface} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "local::network::bridges::bridge::${master_bridge}::connected_interface::${interface}" => $anvil->data->{'local'}{network}{bridges}{bridge}{$master_bridge}{connected_interface}{$interface}, - }}); - } + # JSON parse failed. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, key => "error_0140", variables => { + json => $output, + error => $@, + }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0519"}); + + # NOTE: This is not design to be normally used. It was created as a stop-gap while waiting + # for resolution on: https://bugzilla.redhat.com/show_bug.cgi?id=1868467 + my ($output, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{bridge}." -details link show"}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - interface => $interface, - master_bridge => $master_bridge, - type => $type, + output => $output, + return_code => $return_code, }}); - foreach my $key (sort {$a cmp $b} keys %{$hash_ref}) + my $interface = ""; + my $type = ""; + foreach my $line (split/\n/, $output) { - if (ref($hash_ref->{$key}) eq "ARRAY") + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }}); + if ($line =~ /^\d+:\s+(.*?):/) + { + $interface = $1; + $type = ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + interface => $interface, + type => $type, + }}); + + $anvil->data->{'local'}{network}{bridges}{bridge}{$interface}{found} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "local::network::bridges::bridge::${interface}::found" => $anvil->data->{'local'}{network}{bridges}{bridge}{$interface}{found}, + }}); + } + if ($interface) { - $anvil->data->{'local'}{network}{bridges}{$type}{$interface}{$key} = []; - foreach my $value (sort {$a cmp $b} @{$hash_ref->{$key}}) + if (($line =~ /master (.*?) /) or ($line =~ /master (.*?)$/)) { - push @{$anvil->data->{'local'}{network}{bridges}{$type}{$interface}{$key}}, $value; + my $master_bridge = $1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { master_bridge => $master_bridge }}); + + if ($master_bridge eq $interface) + { + # This is the bridge + $type = "bridge"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { type => $type }}); + } + else + { + # It's an interface, store it under the bridge. + $type = "interface"; + $anvil->data->{'local'}{network}{bridges}{bridge}{$master_bridge}{connected_interface}{$interface} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + type => $type, + "local::network::bridges::bridge::${master_bridge}::connected_interface::${interface}" => $anvil->data->{'local'}{network}{bridges}{bridge}{$master_bridge}{connected_interface}{$interface}, + }}); + } } - for (my $i = 0; $i < @{$anvil->data->{'local'}{network}{bridges}{$type}{$interface}{$key}}; $i++) + } + + if (($interface) && ($type)) + { + if ($line =~ /<(.*?)>/) { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "local::network::bridges::${type}::${interface}::${key}->[$i]" => $anvil->data->{'local'}{network}{bridges}{$type}{$interface}{$key}->[$i], - }}); + my $flags = $1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { flags => $flags }}); + + my $i = 0; + foreach my $flag (split/,/, $flags) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { flag => $flag }}); + push @{$anvil->data->{'local'}{network}{bridges}{$type}{$interface}{flags}}, $flag; + } } } + if ($line =~ /^\s+(.*?)$interface/) + { + # Break out settings. + my $values = $1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'values' => $values }}); + + my $variable = ""; + foreach my $word (split/ /, $values) + { + if (($variable) && (($word eq "on") or ($word eq "off"))) + { + my $value = $word; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { value => $value }}); + + $anvil->data->{'local'}{network}{bridges}{$type}{$interface}{$variable} = $value eq "on" ? "true" : "false"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "local::network::bridges::${type}::${interface}::${variable}" => $anvil->data->{'local'}{network}{bridges}{$type}{$interface}{$variable}, + }}); + $variable = ""; + } + else + { + $variable = $word; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { variable => $variable }}); + } + } + } + } + } + else + { + foreach my $hash_ref (@{$bridge_data}) + { + # If the ifname and master are the same, it's a bridge. + my $type = "interface"; + my $interface = $hash_ref->{ifname}; + my $master_bridge = $hash_ref->{master}; + if ($interface eq $master_bridge) + { + $type = "bridge"; + $anvil->data->{'local'}{network}{bridges}{bridge}{$interface}{found} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "local::network::bridges::bridge::${interface}::found" => $anvil->data->{'local'}{network}{bridges}{bridge}{$interface}{found}, + }}); + } else { - $anvil->data->{'local'}{network}{bridges}{$type}{$interface}{$key} = $hash_ref->{$key}; + # Store this interface under the bridge. + $anvil->data->{'local'}{network}{bridges}{bridge}{$master_bridge}{connected_interface}{$interface} = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "local::network::bridges::${type}::${interface}::${key}" => $anvil->data->{'local'}{network}{bridges}{$type}{$interface}{$key}, + "local::network::bridges::bridge::${master_bridge}::connected_interface::${interface}" => $anvil->data->{'local'}{network}{bridges}{bridge}{$master_bridge}{connected_interface}{$interface}, }}); } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + interface => $interface, + master_bridge => $master_bridge, + type => $type, + }}); + foreach my $key (sort {$a cmp $b} keys %{$hash_ref}) + { + if (ref($hash_ref->{$key}) eq "ARRAY") + { + $anvil->data->{'local'}{network}{bridges}{$type}{$interface}{$key} = []; + foreach my $value (sort {$a cmp $b} @{$hash_ref->{$key}}) + { + push @{$anvil->data->{'local'}{network}{bridges}{$type}{$interface}{$key}}, $value; + } + for (my $i = 0; $i < @{$anvil->data->{'local'}{network}{bridges}{$type}{$interface}{$key}}; $i++) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "local::network::bridges::${type}::${interface}::${key}->[$i]" => $anvil->data->{'local'}{network}{bridges}{$type}{$interface}{$key}->[$i], + }}); + } + } + else + { + $anvil->data->{'local'}{network}{bridges}{$type}{$interface}{$key} = $hash_ref->{$key}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "local::network::bridges::${type}::${interface}::${key}" => $anvil->data->{'local'}{network}{bridges}{$type}{$interface}{$key}, + }}); + } + } } } diff --git a/Anvil/Tools/Server.pm b/Anvil/Tools/Server.pm index a318a6b0..531e5882 100755 --- a/Anvil/Tools/Server.pm +++ b/Anvil/Tools/Server.pm @@ -559,6 +559,37 @@ sub map_network return(0); } +=head2 provision + +This method creates a new (virtual) server on an Anvil! system. + +Parameters; + +=cut +sub provision +{ + my $self = shift; + my $parameter = shift; + my $anvil = $self->parent; + my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; + +=cut +Provision order: + +1. Create LVs and register the storage. + - NOTE: If the LV is already in the DB (from a past install) and the peer is not available and the local + DRBD resource doesn't show Consistent, abort. If the peer is alive but we can't contact it, it's + possible the peer is UpToDate. +2. Create the DRBD resource. If "Inconsistent" on both nodes, force up to date +3. Wait for install media/image to be ready +4. Provision VM and add to Pacemaker. + +=cut + + + return(0); +} + =head2 migrate This will migrate (push or pull) a server from one node to another. If the migration was successful, C<< 1 >> is returned. Otherwise, C<< 0 >> is returned with a (hopefully) useful error being logged. @@ -1319,6 +1350,20 @@ sub _parse_definition my $on_lv = defined $anvil->data->{drbd}{config}{$host}{drbd_path}{$device_path}{on} ? $anvil->data->{drbd}{config}{$host}{drbd_path}{$device_path}{on} : ""; my $resource = defined $anvil->data->{drbd}{config}{$host}{drbd_path}{$device_path}{resource} ? $anvil->data->{drbd}{config}{$host}{drbd_path}{$device_path}{resource} : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + on_lv => $on_lv, + resource => $resource, + }}); + if ((not $resource) && ($anvil->data->{drbd}{config}{$host}{'by-res'}{$device_path}{resource})) + { + $resource = $anvil->data->{drbd}{config}{$host}{'by-res'}{$device_path}{resource}; + $on_lv = $anvil->data->{drbd}{config}{$host}{'by-res'}{$device_path}{backing_lv}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + on_lv => $on_lv, + resource => $resource, + }}); + } + $anvil->data->{server}{$target}{$server}{device}{$device_path}{on_lv} = $on_lv; $anvil->data->{server}{$target}{$server}{device}{$device_path}{resource} = $resource; $anvil->data->{server}{$target}{$server}{device}{$device_path}{target} = $device_target; @@ -1332,7 +1377,7 @@ sub _parse_definition }}); # Keep a list of DRBD resources used by this server. - my $drbd_resource = $anvil->data->{server}{$target}{$server}{device}{$device_path}{resource}; + my $drbd_resource = $anvil->data->{server}{$target}{$server}{device}{$device_path}{resource}; $anvil->data->{server}{$target}{$server}{drbd}{resource}{$drbd_resource} = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "server::${target}::${server}::drbd::resource::${drbd_resource}" => $anvil->data->{server}{$target}{$server}{drbd}{resource}{$drbd_resource}, diff --git a/Anvil/Tools/Storage.pm b/Anvil/Tools/Storage.pm index d1ee4492..c374001e 100644 --- a/Anvil/Tools/Storage.pm +++ b/Anvil/Tools/Storage.pm @@ -1243,6 +1243,15 @@ fi"; return(0); } +=head2 create_lv + +This creates a logical volume on the local host. + +=cut +sub create_lv +{ +} + =head2 find This searches for the given file on the system. It will search in the directories returned by C<< $anvil->Storage->search_directories() >>. diff --git a/anvil.conf b/anvil.conf index ff0b2d2e..6b1a8435 100644 --- a/anvil.conf +++ b/anvil.conf @@ -1,5 +1,9 @@ ### This is the main Anvil! configuration file. +# To help understand how the Anvil! is used, some features will "call home" to record anonymous information +# about a machine participating in an Anvil! system. If you wish to not have this happen, set this to '1'. +sys::privacy::strong = 0 + ### Database # Database connections; # diff --git a/notes b/notes index d16d9a91..09f57944 100644 --- a/notes +++ b/notes @@ -293,9 +293,9 @@ pcs resource clone hypervisor clone-max=2 notify="false" pcs resource create drbd systemd:drbd op monitor interval=60 pcs resource clone drbd clone-max=2 notify="false" -pcs resource create test_server ocf:alteeve:server name="test_server" meta allow-migrate="true" op monitor interval="60" +pcs resource create srv01-sql ocf:alteeve:server name="srv01-sql" meta allow-migrate="true" op monitor interval="60" on-fail="block" - or - -pcs resource update test_server ocf:alteeve:server name="test_server" meta allow-migrate="true" op monitor interval="60" +pcs resource update srv01-sql ocf:alteeve:server name="srv01-sql" meta allow-migrate="true" op monitor interval="60" on-fail="block" # Test stonith_admin --fence el8-a01n02 --verbose; crm_error $? @@ -911,13 +911,13 @@ virt-install --connect qemu:///system \ # Migration; -pcs resource move test_server +pcs resource move srv01-sql # (then remove the constraint); pcs constraint show --full -pcs constraint remove cli-ban-test_server-on-el8-a01n01 +pcs constraint remove cli-ban-srv01-sql-on-el8-a01n01 -pcs constraint remove $(pcs constraint show --full | grep ban-test_server | perl -pe 's/^.*?id:(.*?)\)/$1/') +pcs constraint remove $(pcs constraint show --full | grep ban-srv01-sql | perl -pe 's/^.*?id:(.*?)\)/$1/') DRBD 9 - Check; diff --git a/ocf/alteeve/server b/ocf/alteeve/server index 087dc97d..a12f6e70 100755 --- a/ocf/alteeve/server +++ b/ocf/alteeve/server @@ -100,9 +100,9 @@ $anvil->Log->secure({set => 1}); ### Read or Set the environment variables # This is the name of the server we're managing. # Example values: -$anvil->data->{environment}{OCF_RESKEY_name} = defined $ENV{OCF_RESKEY_name} ? $ENV{OCF_RESKEY_name} : ""; # srv01-c7 +$anvil->data->{environment}{OCF_RESKEY_name} = defined $ENV{OCF_RESKEY_name} ? $ENV{OCF_RESKEY_name} : ""; # srv01-sql # This is our node name -$anvil->data->{environment}{OCF_RESKEY_CRM_meta_on_node} = defined $ENV{OCF_RESKEY_CRM_meta_on_node} ? $ENV{OCF_RESKEY_CRM_meta_on_node} : ""; # el8-a01n01.digimer.ca +$anvil->data->{environment}{OCF_RESKEY_CRM_meta_on_node} = defined $ENV{OCF_RESKEY_CRM_meta_on_node} ? $ENV{OCF_RESKEY_CRM_meta_on_node} : ""; # mk-a02n01.digimer.ca # This says "UUID", but it's the node ID. $anvil->data->{environment}{OCF_RESKEY_CRM_meta_on_node_uuid} = defined $ENV{OCF_RESKEY_CRM_meta_on_node_uuid} ? $ENV{OCF_RESKEY_CRM_meta_on_node_uuid} : ""; # 1 # This is the timeout for the called action in millisecond. @@ -119,8 +119,8 @@ $anvil->data->{environment}{OCF_RESOURCE_PROVIDER} = defined $ENV{O $anvil->data->{environment}{OCF_RESOURCE_TYPE} = defined $ENV{OCF_RESOURCE_TYPE} ? $ENV{OCF_RESOURCE_TYPE} : ""; # server $anvil->data->{environment}{OCF_ROOT} = defined $ENV{OCF_ROOT} ? $ENV{OCF_ROOT} : ""; # /usr/lib/ocf # These are set during a migration -$anvil->data->{environment}{OCF_RESKEY_CRM_meta_migrate_source} = defined $ENV{OCF_RESKEY_CRM_meta_migrate_source} ? $ENV{OCF_RESKEY_CRM_meta_migrate_source} : ""; # el8-a01n01.digimer.ca -$anvil->data->{environment}{OCF_RESKEY_CRM_meta_migrate_target} = defined $ENV{OCF_RESKEY_CRM_meta_migrate_target} ? $ENV{OCF_RESKEY_CRM_meta_migrate_target} : ""; # el8-a01n02.digimer.ca +$anvil->data->{environment}{OCF_RESKEY_CRM_meta_migrate_source} = defined $ENV{OCF_RESKEY_CRM_meta_migrate_source} ? $ENV{OCF_RESKEY_CRM_meta_migrate_source} : ""; # mk-a02n01.digimer.ca +$anvil->data->{environment}{OCF_RESKEY_CRM_meta_migrate_target} = defined $ENV{OCF_RESKEY_CRM_meta_migrate_target} ? $ENV{OCF_RESKEY_CRM_meta_migrate_target} : ""; # mk-a02n02.digimer.ca $anvil->data->{environment}{OCF_RESKEY_CRM_meta_record_pending} = defined $ENV{OCF_RESKEY_CRM_meta_record_pending} ? $ENV{OCF_RESKEY_CRM_meta_record_pending} : ""; # true # If pacemaker is in debug, so are we, @@ -149,27 +149,27 @@ $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 0, level ### TEST: to be removed later if ($anvil->data->{switches}{test1}) { - $anvil->data->{environment}{OCF_RESKEY_name} = "test_server"; + $anvil->data->{environment}{OCF_RESKEY_name} = "srv01-sql"; $anvil->data->{environment}{OCF_RESKEY_CRM_meta_timeout} = 20000; - $anvil->data->{environment}{OCF_RESKEY_CRM_meta_on_node} = "el8-a01n01.digimer.ca"; - $anvil->data->{environment}{OCF_RESKEY_CRM_meta_migrate_source} = "el8-a01n01.digimer.ca"; - $anvil->data->{environment}{OCF_RESKEY_CRM_meta_migrate_target} = "el8-a01n02.digimer.ca"; - #print "Running test 1; Migrate: [".$anvil->data->{environment}{OCF_RESKEY_name}."] from: [".$anvil->data->{environment}{OCF_RESKEY_CRM_meta_migrate_source}."] to: [".$anvil->data->{environment}{OCF_RESKEY_CRM_meta_migrate_target}."]\n"; + $anvil->data->{environment}{OCF_RESKEY_CRM_meta_on_node} = "mk-a02n01.digimer.ca"; + $anvil->data->{environment}{OCF_RESKEY_CRM_meta_migrate_source} = "mk-a02n01.digimer.ca"; + $anvil->data->{environment}{OCF_RESKEY_CRM_meta_migrate_target} = "mk-a02n02.digimer.ca"; + print "Running test 1; Migrate: [".$anvil->data->{environment}{OCF_RESKEY_name}."] from: [".$anvil->data->{environment}{OCF_RESKEY_CRM_meta_migrate_source}."] to: [".$anvil->data->{environment}{OCF_RESKEY_CRM_meta_migrate_target}."]\n"; } if ($anvil->data->{switches}{test2}) { - $anvil->data->{environment}{OCF_RESKEY_name} = "test_server"; + $anvil->data->{environment}{OCF_RESKEY_name} = "srv01-sql"; $anvil->data->{environment}{OCF_RESKEY_CRM_meta_timeout} = 20000; - $anvil->data->{environment}{OCF_RESKEY_CRM_meta_on_node} = "el8-a01n02.digimer.ca"; - $anvil->data->{environment}{OCF_RESKEY_CRM_meta_migrate_source} = "el8-a01n02.digimer.ca"; - $anvil->data->{environment}{OCF_RESKEY_CRM_meta_migrate_target} = "el8-a01n01.digimer.ca"; - #print "Running test 2; Migrate: [".$anvil->data->{environment}{OCF_RESKEY_name}."] from: [".$anvil->data->{environment}{OCF_RESKEY_CRM_meta_migrate_source}."] to: [".$anvil->data->{environment}{OCF_RESKEY_CRM_meta_migrate_target}."]\n"; + $anvil->data->{environment}{OCF_RESKEY_CRM_meta_on_node} = "mk-a02n02.digimer.ca"; + $anvil->data->{environment}{OCF_RESKEY_CRM_meta_migrate_source} = "mk-a02n02.digimer.ca"; + $anvil->data->{environment}{OCF_RESKEY_CRM_meta_migrate_target} = "mk-a02n01.digimer.ca"; + print "Running test 2; Migrate: [".$anvil->data->{environment}{OCF_RESKEY_name}."] from: [".$anvil->data->{environment}{OCF_RESKEY_CRM_meta_migrate_source}."] to: [".$anvil->data->{environment}{OCF_RESKEY_CRM_meta_migrate_target}."]\n"; } if ($anvil->data->{switches}{test3}) { - $anvil->data->{environment}{OCF_RESKEY_name} = "test_server"; - $anvil->data->{environment}{OCF_RESKEY_CRM_meta_on_node} = "el8-a01n01.digimer.ca"; - #print "Running test 3; Boot or shutdown of: [".$anvil->data->{environment}{OCF_RESKEY_name}."].\n"; + $anvil->data->{environment}{OCF_RESKEY_name} = "srv01-sql"; + $anvil->data->{environment}{OCF_RESKEY_CRM_meta_on_node} = "mk-a02n01.digimer.ca"; + print "Running test 3; Boot or shutdown of: [".$anvil->data->{environment}{OCF_RESKEY_name}."].\n"; } # This is for debugging. @@ -275,6 +275,7 @@ sub check_daemons { my ($anvil, $task) = @_; + print "Parsing CIB\n"; my $problem = $anvil->Cluster->parse_cib(); if ($problem) { @@ -285,7 +286,7 @@ sub check_daemons } # Is the peer running? We'll use this to know whether to try and start daemons on the peer. - my $peer_name = $anvil->Cluster->get_peers(); + my $peer_name = $anvil->data->{cib}{parsed}{peer}{name}; my $peer_ready = $anvil->data->{cib}{parsed}{peer}{ready}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peer_name => $peer_name, @@ -294,7 +295,8 @@ sub check_daemons if ($task eq "start") { - foreach my $daemon ("libvirtd.service", "drbd.service") + #foreach my $daemon ("libvirtd.service", "drbd.service") + foreach my $daemon ("libvirtd.service") { my $running_local = 0; my $running_peer = 0; @@ -353,7 +355,6 @@ sub check_daemons $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0485", variables => { daemon => $daemon }}); } - ### TODO: Left off here. if ($peer_ready) { my ($output, $error, $return_code) = $anvil->Remote->call({ @@ -441,8 +442,10 @@ sub check_daemons } } } +=cut # It's simpler (and thus safer) to not stop daemons. if ($task eq "stop") { + print "Stopping daemons\n"; my $stop = 0; # Check both nodes if a server is running on either node. @@ -580,6 +583,7 @@ sub check_daemons $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0496"}); } } +=cut return(0); } @@ -1313,7 +1317,7 @@ sub validate_storage { my ($anvil) = @_; - ### TODO: When checking on a running server, use 'from_memory'. + # When checking on a running server, use 'from_memory'. my $server = $anvil->data->{environment}{OCF_RESKEY_name}; my $source = "from_disk"; if ($anvil->data->{server}{'local'}{$server}{from_memory}{host}) @@ -1380,7 +1384,7 @@ sub validate_storage_drbd foreach my $device_path (sort {$a cmp $b} keys %{$anvil->data->{server}{'local'}{$server}{device}}) { next if not $device_path; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "server::local::${server}::device::${device_path}::resource" => $anvil->data->{server}{'local'}{$server}{device}{$device_path}{resource}, }}); if (not $anvil->data->{server}{'local'}{$server}{device}{$device_path}{resource}) @@ -1392,15 +1396,25 @@ sub validate_storage_drbd foreach my $device_target (sort {$a cmp $b} keys %{$anvil->data->{server}{'local'}{$server}{$source}{device}{disk}{target}}) { - my $drbd_device = $anvil->data->{server}{'local'}{$server}{$source}{device}{disk}{target}{$device_target}{path}; - my $drbd_resource = $anvil->data->{drbd}{config}{$host}{drbd_path}{$drbd_device}{resource}; - my $on_lv = $anvil->data->{drbd}{config}{$host}{drbd_path}{$drbd_device}{on}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { + my $drbd_device = $anvil->data->{server}{'local'}{$server}{$source}{device}{disk}{target}{$device_target}{path}; + my $drbd_resource = defined $anvil->data->{drbd}{config}{$host}{drbd_path}{$drbd_device}{resource} ? $anvil->data->{drbd}{config}{$host}{drbd_path}{$drbd_device}{resource} : ""; + my $on_lv = defined $anvil->data->{drbd}{config}{$host}{drbd_path}{$drbd_device}{on} ? $anvil->data->{drbd}{config}{$host}{drbd_path}{$drbd_device}{on} : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host => $host, drbd_device => $drbd_device, drbd_resource => $drbd_resource, on_lv => $on_lv, }}); + if (not $drbd_resource) + { + # See if we can find the resource in the 'by-res' hash. + $drbd_resource = defined $anvil->data->{drbd}{config}{$host}{'by-res'}{$drbd_device}{resource} ? $anvil->data->{drbd}{config}{$host}{'by-res'}{$drbd_device}{resource} : ""; + $on_lv = defined $anvil->data->{drbd}{config}{$host}{'by-res'}{$drbd_device}{backing_lv} ? $anvil->data->{drbd}{config}{$host}{'by-res'}{$drbd_device}{backing_lv} : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + drbd_resource => $drbd_resource, + on_lv => $on_lv, + }}); + } # If the logical volume here here and active? if ((not $on_lv) or (not exists $anvil->data->{lvm}{'local'}{lv}{$on_lv})) diff --git a/share/words.xml b/share/words.xml index 4742084a..714dbe48 100644 --- a/share/words.xml +++ b/share/words.xml @@ -199,6 +199,16 @@ The error was: All attempts to change the IPMI user: [#!variable!user_name!#] (number: [#!variable!user_number!#] failed. The last try's output (if any) was: [#!variable!output!#] (return code: [#!variable!return code!#]). The system call: [#!variable!shell_call!#] failed. The output (if any) was: [#!variable!output!#] (return code: [#!variable!return code!#]). The DRBD global common config file: [#!data!path::configs::global-common.conf!#] doesn't exist, unable to update it. + +Failed to parse the JSON string: +=========================================================== +#!variable!json!# +=========================================================== +The error was: +=========================================================== +#!variable!error!# +=========================================================== + Current Network Interfaces and States @@ -372,6 +382,10 @@ Failure! The return code: [#!variable!return_code!#] was received ('0' was expec Adding a fence delay agent to provide time for the IPMI BMC to boot before trying it again. Configuring the cluster to loop fence attempts indefinitely. Enabling fencing! + Checking to see if: [#!data!path::configs::global-common.conf!#] needs to be configured or updated. + Update completed successfully. + Update not required, nothing changed. + Completed joining the #!string!brand_0002!#. Starting: [#!variable!program!#]. @@ -981,6 +995,7 @@ The file: [#!variable!file!#] needs to be updated. The difference is: ==== Appending the file: [#!variable!file!#] with the line: [#!variable!line!#]. + Attempting to parse bridge information using standard output after failing to parse JSON status information. The host name: [#!variable!target!#] does not resolve to an IP address. diff --git a/tools/anvil-join-anvil b/tools/anvil-join-anvil index 9fddca1b..b63dccff 100755 --- a/tools/anvil-join-anvil +++ b/tools/anvil-join-anvil @@ -66,6 +66,8 @@ configure_pacemaker($anvil); # Configure DRBD configure_drbd($anvil); +update_progress($anvil, 100, "job_0128"); +$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0128"}); $anvil->nice_exit({exit_code => 0}); ############################################################################################################# @@ -78,7 +80,22 @@ sub configure_drbd my ($anvil) = @_; ### TODO: See if there is a hardware RAID controller and, if so, auto-enable - # Read in the global_common.conf + update_progress($anvil, ($anvil->data->{job}{progress} += 1), "job_0126"); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0126"}); + my $updated = $anvil->DRBD->update_global_common({ + usage_count => $anvil->data->{sys}{privacy}{strong} ? 0 : 1, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { updated => $updated }}); + if ($updated) + { + update_progress($anvil, ($anvil->data->{job}{progress} += 1), "job_0127"); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0127"}); + } + else + { + update_progress($anvil, ($anvil->data->{job}{progress} += 1), "job_0128"); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0128"}); + } return(0); } @@ -166,28 +183,35 @@ sub configure_pacemaker } ### Run on both nodes. - # Enable pcsd and start the pcsd daemons. - my ($return_code) = $anvil->System->enable_daemon({daemon => "pcsd"}); + # Enable pcsd and start the pcsd daemon. + my ($return_code) = $anvil->System->enable_daemon({daemon => "pcsd.service"}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { return_code => $return_code }}); + $return_code = undef; + ($return_code) = $anvil->System->start_daemon({daemon => "pcsd.service"}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { return_code => $return_code }}); + $return_code = undef; + update_progress($anvil, ($anvil->data->{job}{progress} += 2), "job_0094,!!daemon!pcsd.service!!"); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0094", variables => { daemon => "pcsd.service" }}); + + # Enable libvirtd and start the libvirtd daemon. + ($return_code) = $anvil->System->enable_daemon({daemon => "libvirtd.service"}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { return_code => $return_code }}); $return_code = undef; - ($return_code) = $anvil->System->start_daemon({daemon => "pcsd"}); + ($return_code) = $anvil->System->start_daemon({daemon => "libvirtd.service"}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { return_code => $return_code }}); $return_code = undef; - update_progress($anvil, ($anvil->data->{job}{progress} += 2), "job_0094,!!daemon!pcsd!!"); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0094", variables => { daemon => "pcsd" }}); + update_progress($anvil, ($anvil->data->{job}{progress} += 2), "job_0094,!!daemon!libvirtd.service!!"); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0094", variables => { daemon => "libvirtd.service" }}); # Disabled and stop the libvirtd daemon. - foreach my $daemon ("libvirtd.service", "drbd.service") - { - my ($return_code) = $anvil->System->disable_daemon({daemon => $daemon}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { return_code => $return_code }}); - $return_code = undef; - ($return_code) = $anvil->System->stop_daemon({daemon => $daemon}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { return_code => $return_code }}); - $return_code = undef; - update_progress($anvil, ($anvil->data->{job}{progress} += 2), "job_0095,!!daemon!".$daemon."!!"); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0095", variables => { daemon => $daemon }}); - } + ($return_code) = $anvil->System->disable_daemon({daemon => "drbd.service"}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { return_code => $return_code }}); + $return_code = undef; + ($return_code) = $anvil->System->stop_daemon({daemon => "drbd.service"}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { return_code => $return_code }}); + $return_code = undef; + update_progress($anvil, ($anvil->data->{job}{progress} += 2), "job_0095,!!daemon!drbd.service!!"); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0095", variables => { daemon => "drbd.service" }}); # If there is no corosync.conf, see if the peer has it. If so, copy it. If not, we'll initialize the # cluster shortly. @@ -1900,11 +1924,8 @@ sub update_progress 's1:progress' => $progress, 's2:message' => $message, }}); - - # Disabled for the moment - return(0); - $progress = 95 if $progress > 100; + $progress = 98 if $progress > 100; if (not $anvil->data->{switches}{'job-uuid'}) { return(0); diff --git a/tools/scancore b/tools/scancore index f0559fa6..da1b4ac8 100755 --- a/tools/scancore +++ b/tools/scancore @@ -145,9 +145,8 @@ sub call_agents } # Now call the agent. - my $start_time = time; - my $return_code = 9999; - my $timeout = $default_timeout; + my $start_time = time; + my $timeout = $default_timeout; if ((exists $anvil->data->{scancore}{agent}{$agent_name}{agent_runtime}) && ($anvil->data->{scancore}{agent}{$agent_name}{agent_runtime} =~ /^\d+$/)) { $timeout = $anvil->data->{scancore}{agent}{$agent_name}{agent_runtime}; @@ -155,7 +154,7 @@ sub call_agents my $shell_call = $anvil->data->{path}{exe}{timeout}." ".$timeout." ".$agent_path; if ($anvil->data->{sys}{'log'}{level}) { - $shell_call .= ." ".$anvil->data->{sys}{'log'}{level}; + $shell_call .= " ".$anvil->data->{sys}{'log'}{level}; } $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); diff --git a/tools/test.pl b/tools/test.pl index 28ad510a..7d552cf1 100755 --- a/tools/test.pl +++ b/tools/test.pl @@ -29,7 +29,9 @@ $anvil->Database->connect(); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, secure => 0, key => "log_0132"}); $anvil->Get->switches; -my $updated = $anvil->DRBD->update_global_common({ - debug => 2, +#$anvil->DRBD->get_devices({ debug => 2 }); die; +$anvil->Server->get_status({ + debug => 2, + server => "srv01-sql", }); -print "DRBD global common updated? [".$updated."]\n"; +