diff --git a/Anvil/Tools/Server.pm b/Anvil/Tools/Server.pm index 41e3166f..3ffa42b1 100755 --- a/Anvil/Tools/Server.pm +++ b/Anvil/Tools/Server.pm @@ -281,6 +281,7 @@ sub _parse_definition $anvil->data->{server}{$server}{$source}{parsed} = $server_xml; #print Dumper $server_xml; + #die; # Pull out some basic server info. $anvil->data->{server}{$server}{$source}{info}{uuid} = $server_xml->{uuid}->[0]; @@ -691,5 +692,33 @@ sub _parse_definition } } + # Pull out console data + foreach my $hash_ref (@{$server_xml->{devices}->[0]->{interface}}) + { + #print Dumper $hash_ref; + my $mac = $hash_ref->{mac}->[0]->{address}; + + $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{bridge} = $hash_ref->{source}->[0]->{bridge}; + $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{alias} = $hash_ref->{alias}->[0]->{name}; + $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{target} = $hash_ref->{target}->[0]->{dev}; + $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{model} = $hash_ref->{model}->[0]->{type}; + $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{address}{bus} = $hash_ref->{address}->[0]->{bus}; + $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{address}{domain} = $hash_ref->{address}->[0]->{domain}; + $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{address}{type} = $hash_ref->{address}->[0]->{type}; + $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{address}{slot} = $hash_ref->{address}->[0]->{slot}; + $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{address}{function} = $hash_ref->{address}->[0]->{function}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "server::${server}::${source}::device::interface::${mac}::bridge" => $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{bridge}, + "server::${server}::${source}::device::interface::${mac}::alias" => $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{alias}, + "server::${server}::${source}::device::interface::${mac}::target" => $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{target}, + "server::${server}::${source}::device::interface::${mac}::model" => $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{model}, + "server::${server}::${source}::device::interface::${mac}::address::bus" => $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{address}{bus}, + "server::${server}::${source}::device::interface::${mac}::address::domain" => $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{address}{domain}, + "server::${server}::${source}::device::interface::${mac}::address::type" => $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{address}{type}, + "server::${server}::${source}::device::interface::${mac}::address::slot" => $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{address}{slot}, + "server::${server}::${source}::device::interface::${mac}::address::function" => $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{address}{function}, + }}); + } + return(0); } diff --git a/Anvil/Tools/System.pm b/Anvil/Tools/System.pm index d7156a96..832064ab 100644 --- a/Anvil/Tools/System.pm +++ b/Anvil/Tools/System.pm @@ -20,6 +20,8 @@ my $THIS_FILE = "System.pm"; # check_daemon # check_if_configured # check_memory +# get_bridges +# get_free_memory # get_host_type # enable_daemon # find_matching_ip @@ -541,6 +543,139 @@ sub check_memory return($used_ram); } +=hed2 get_bridges + +This finds a list of bridges on the host. Bridges that are found are stored is ' + +=cut +sub get_bridges +{ + my $self = shift; + my $parameter = shift; + my $anvil = $self->parent; + my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "System->get_bridges()" }}); + + my ($output, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{bridge}." -json -details link show"}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + output => $output, + return_code => $return_code, + }}); + + # Delete any previously known data + if (exists $anvil->data->{'local'}{network}{bridges}) + { + delete $anvil->data->{'local'}{network}{bridges}; + }; + + my $json = JSON->new->allow_nonref; + my $bridge_data = $json->decode($output); + #print Dumper $bridge_data; + foreach my $hash_ref (@{$bridge_data}) + { + # If the ifname and master are the same, it's a bridge. + my $type = "interface"; + my $interface_name = $hash_ref->{ifname}; + my $master_bridge = $hash_ref->{master}; + if ($interface_name eq $master_bridge) + { + $type = "bridge"; + $anvil->data->{'local'}{network}{bridges}{bridge}{$interface_name}{found} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "local::network::bridges::bridge::${interface_name}::found" => $anvil->data->{'local'}{network}{bridges}{bridge}{$interface_name}{found}, + }}); + } + else + { + # Store this interface under the bridge. + $anvil->data->{'local'}{network}{bridges}{bridge}{$master_bridge}{connected_interface}{$interface_name} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "local::network::bridges::bridge::${master_bridge}::connected_interface::${interface_name}" => $anvil->data->{'local'}{network}{bridges}{bridge}{$master_bridge}{connected_interface}{$interface_name}, + }}); + } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + interface_name => $interface_name, + 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_name}{$key} = []; + foreach my $value (sort {$a cmp $b} @{$hash_ref->{$key}}) + { + push @{$anvil->data->{'local'}{network}{bridges}{$type}{$interface_name}{$key}}, $value; + } + for (my $i = 0; $i < @{$anvil->data->{'local'}{network}{bridges}{$type}{$interface_name}{$key}}; $i++) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "local::network::bridges::${type}::${interface_name}::${key}->[$i]" => $anvil->data->{'local'}{network}{bridges}{$type}{$interface_name}{$key}->[$i], + }}); + } + } + else + { + $anvil->data->{'local'}{network}{bridges}{$type}{$interface_name}{$key} = $hash_ref->{$key}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "local::network::bridges::${type}::${interface_name}::${key}" => $anvil->data->{'local'}{network}{bridges}{$type}{$interface_name}{$key}, + }}); + } + } + } + + # Summary of found bridges. + foreach my $interface_name (sort {$a cmp $b} keys %{$anvil->data->{'local'}{network}{bridges}{bridge}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "local::network::bridges::bridge::${interface_name}::found" => $anvil->data->{'local'}{network}{bridges}{bridge}{$interface_name}{found}, + }}); + } + + return(0); +} + +=head2 get_free_memory + +This returns, in bytes, host much free memory is available on the local system. + +=cut +### TODO: Make this work on remote systems. +sub get_free_memory +{ + my $self = shift; + my $parameter = shift; + my $anvil = $self->parent; + my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "System->get_free_memory()" }}); + + my $available = 0; + my ($free_output, $free_rc) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{free}." --bytes"}); + foreach my $line (split/\n/, $free_output) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { line => $line }}); + if ($line =~ /Mem:\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)$/) + { + my $total = $1; + my $used = $2; + my $free = $3; + my $shared = $4; + my $cache = $5; + $available = $6; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + total => $total." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $total})."})", + used => $used." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $used})."})", + free => $free." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $free})."})", + shared => $shared." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $shared})."})", + cache => $cache." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $cache})."})", + available => $available." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $available})."})", + }}); + } + } + + return($available); +} + =head2 get_host_type This method tries to determine the host type and returns a value suitable for use is the C<< hosts >> table. diff --git a/ocf/alteeve/server b/ocf/alteeve/server index fb275e14..d60cde39 100755 --- a/ocf/alteeve/server +++ b/ocf/alteeve/server @@ -399,6 +399,16 @@ sub validate_all # Make sure the emulator it wants is the one we have. validate_emulator($anvil); + # These tests are only needed if we're about to boot the server + if (($anvil->data->{switches}{start}) or ($anvil->data->{switches}{migrate_from})) + { + # Check that we have enough RAM. + validate_ram($anvil); + } + + # Validate bridges + validate_bridges($anvil); + # Which DRBD resources do I need? @@ -410,6 +420,40 @@ sub validate_bridges { my ($anvil) = @_; + # Get my bridge list + $anvil->System->get_bridges({debug => 2}); + + # Find the Optical drives and DRBD devices. + my $server = $anvil->data->{environment}{OCF_RESKEY_name}; + foreach my $mac (sort {$a cmp $b} keys %{$anvil->data->{server}{$server}{from_disk}{device}{interface}}) + { + # See if we have this bridge + my $found = 0; + my $bridge = $anvil->data->{server}{$server}{from_disk}{device}{interface}{$mac}{bridge}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge => $bridge }}); + foreach my $interface_name (sort {$a cmp $b} keys %{$anvil->data->{'local'}{network}{bridges}{bridge}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { interface_name => $interface_name }}); + if ((exists $anvil->data->{'local'}{network}{bridges}{bridge}{$interface_name}) && ($anvil->data->{'local'}{network}{bridges}{bridge}{$interface_name}{found})) + { + $found = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { found => $found }}); + last; + } + } + + if ($found) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 3, key => "log_0368", variables => { bridge => $bridge }}); + } + else + { + # Missing bridge. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "log_0369", variables => { bridge => $bridge }}); + $anvil->nice_exit({exit_code => 5}); + } + } + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "log_0366"}); return(0); } @@ -516,7 +560,27 @@ sub validate_ram { my ($anvil) = @_; - + # How mcuh RAM does the server need and how much do we have free? + my $server = $anvil->data->{environment}{OCF_RESKEY_name}; + my $server_ram_bytes = $anvil->data->{server}{$server}{from_disk}{memory}; + my $available = $anvil->System->get_free_memory({debug => 2}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + server_ram_bytes => $anvil->Convert->add_commas({number => $server_ram_bytes})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $server_ram_bytes}).")", + available => $anvil->Convert->add_commas({number => $available})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $available}).")", + }}); + if ($server_ram_bytes > $available) + { + # Not enough free memory. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "log_0404", variables => { + name => $server, + ram => $anvil->Convert->bytes_to_human_readable({'bytes' => $server_ram_bytes}), + ram_bytes => $anvil->Convert->add_commas({number => $server_ram_bytes}), + available_ram => $anvil->Convert->bytes_to_human_readable({'bytes' => $server_ram_bytes}), + available_ram_bytes => $anvil->Convert->add_commas({number => $available}), + }}); + $anvil->nice_exit({exit_code => 1}); + } + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "log_0365"}); return(0); }