726a4374d1
* Updated 'variables' -> 'variable_source_uuid' to type 'uuid' and removed the 'not null' constraint. * Updated Database->insert_or_update_variables() to check/update 'variables_source_table' and 'variables_source_uuid'. * Created the 'trusts' database table which will, when done, tell anvil-daemon which users@machines to trust (setup passwordkess SSH). * Created (but not finished) System->manage_authorized_keys() and moved the logic over to it from anvil-daemon. * Changed the host types "dashboard" to "striker". * Moved the following methods from 'System' to 'Get'; ** System->get_host_type to Get->host_type ** System->get_bridges to Get->bridges ** System->get_free_memory to Get->free_memory ** System->get_os_type to Get->os_type ** System->get_uptime to Get->uptime * Updated striker to include the host_uuid for the 'node1', 'node2' and (if chosen) 'dr1' when running a job manifest. Signed-off-by: Digimer <digimer@alteeve.ca>
1316 lines
45 KiB
Perl
1316 lines
45 KiB
Perl
package Anvil::Tools::Get;
|
|
#
|
|
# This module contains methods used to handle access to frequently used data.
|
|
#
|
|
|
|
use strict;
|
|
use warnings;
|
|
use Scalar::Util qw(weaken isweak);
|
|
use Data::Dumper;
|
|
use Encode;
|
|
use UUID::Tiny qw(:std);
|
|
use Net::Netmask;
|
|
|
|
our $VERSION = "3.0.0";
|
|
my $THIS_FILE = "Get.pm";
|
|
|
|
### Methods;
|
|
# anvil_version
|
|
# bridges
|
|
# cgi
|
|
# date_and_time
|
|
# free_memory
|
|
# host_type
|
|
# host_uuid
|
|
# md5sum
|
|
# os_type
|
|
# switches
|
|
# uptime
|
|
# users_home
|
|
# uuid
|
|
# _salt
|
|
# _wrap_to
|
|
|
|
=pod
|
|
|
|
=encoding utf8
|
|
|
|
=head1 NAME
|
|
|
|
Anvil::Tools::Get
|
|
|
|
Provides all methods related to getting access to frequently used data.
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
use Anvil::Tools;
|
|
|
|
# Get a common object handle on all Anvil::Tools modules.
|
|
my $anvil = Anvil::Tools->new();
|
|
|
|
# Access to methods using '$anvil->Get->X'.
|
|
#
|
|
# Example using 'date_and_time()';
|
|
my $date = $anvil->Get->date_and_time({...});
|
|
|
|
=head1 METHODS
|
|
|
|
Methods in this module;
|
|
|
|
=cut
|
|
sub new
|
|
{
|
|
my $class = shift;
|
|
my $self = {
|
|
HOST => {
|
|
UUID => "",
|
|
},
|
|
};
|
|
|
|
bless $self, $class;
|
|
|
|
return ($self);
|
|
}
|
|
|
|
# Get a handle on the Anvil::Tools object. I know that technically that is a sibling module, but it makes more
|
|
# sense in this case to think of it as a parent.
|
|
sub parent
|
|
{
|
|
my $self = shift;
|
|
my $parent = shift;
|
|
|
|
$self->{HANDLE}{TOOLS} = $parent if $parent;
|
|
|
|
# Defend against memory leads. See Scalar::Util'.
|
|
if (not isweak($self->{HANDLE}{TOOLS}))
|
|
{
|
|
weaken($self->{HANDLE}{TOOLS});
|
|
}
|
|
|
|
return ($self->{HANDLE}{TOOLS});
|
|
}
|
|
|
|
|
|
#############################################################################################################
|
|
# Public methods #
|
|
#############################################################################################################
|
|
|
|
=head2 anvil_version
|
|
|
|
This reads to C<< VERSION >> file of a local or remote machine. If the version file isn't found, C<< 0 >> is returned.
|
|
|
|
Parameters;
|
|
|
|
=head3 password (optional)
|
|
|
|
This is the password to use when connecting to a remote machine. If not set, but C<< target >> is, an attempt to connect without a password will be made.
|
|
|
|
=head3 port (optional)
|
|
|
|
This is the TCP port to use when connecting to a remote machine. If not set, but C<< target >> is, C<< 22 >> will be used.
|
|
|
|
=head3 remote_user (optional, default root)
|
|
|
|
If C<< target >> is set, this will be the user we connect to the remote machine as.
|
|
|
|
=head3 target (optional)
|
|
|
|
This is the IP or host name of the machine to read the version of. If this is not set, the local system's version is checked.
|
|
|
|
=cut
|
|
# NOTE: the version is set in anvil.spec by sed'ing the release and arch onto anvil.version in anvil-core's %post
|
|
sub anvil_version
|
|
{
|
|
my $self = shift;
|
|
my $parameter = shift;
|
|
my $anvil = $self->parent;
|
|
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
|
|
|
|
my $password = defined $parameter->{password} ? $parameter->{password} : "";
|
|
my $port = defined $parameter->{port} ? $parameter->{port} : "";
|
|
my $remote_user = defined $parameter->{remote_user} ? $parameter->{remote_user} : "root";
|
|
my $target = defined $parameter->{target} ? $parameter->{target} : "";
|
|
my $version = 0;
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
|
|
password => $anvil->Log->is_secure($password),
|
|
port => $port,
|
|
remote_user => $remote_user,
|
|
target => $target,
|
|
}});
|
|
|
|
# Is this a local call or a remote call?
|
|
if ($anvil->Network->is_local({host => $target}))
|
|
{
|
|
# Local.
|
|
$version = $anvil->Storage->read_file({file => $anvil->data->{path}{configs}{'anvil.version'}});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { version => $version }});
|
|
|
|
# Did we actually read a version?
|
|
if ($version eq "!!error!!")
|
|
{
|
|
$version = 0;
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { version => $version }});
|
|
}
|
|
}
|
|
else
|
|
{
|
|
# Remote call. If we're running as the apache user, we need to read the cached version for
|
|
# the peer. otherwise, after we read the version, will write the cached version.
|
|
my $user = getpwuid($<);
|
|
my $cache_file = $anvil->data->{path}{directories}{anvil}."/anvil.".$target.".version";
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
|
|
cache_file => $cache_file,
|
|
user => $user,
|
|
}});
|
|
if ($user eq "apache")
|
|
{
|
|
# Try to read the local cached version.
|
|
if (-e $cache_file)
|
|
{
|
|
# Read it in.
|
|
$version = $anvil->Storage->read_file({file => $cache_file});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { version => $version }});
|
|
}
|
|
}
|
|
else
|
|
{
|
|
my $shell_call = "
|
|
if [ -e ".$anvil->data->{path}{configs}{'anvil.version'}." ];
|
|
then
|
|
cat ".$anvil->data->{path}{configs}{'anvil.version'}.";
|
|
else
|
|
echo 0;
|
|
fi;
|
|
";
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0166", variables => { shell_call => $shell_call, target => $target, remote_user => $remote_user }});
|
|
my ($output, $error, $return_code) = $anvil->Remote->call({
|
|
debug => $debug,
|
|
shell_call => $shell_call,
|
|
target => $target,
|
|
port => $port,
|
|
password => $password,
|
|
remote_user => $remote_user,
|
|
});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
|
|
error => $error,
|
|
output => $output,
|
|
}});
|
|
|
|
$version = defined $output ? $output : "";
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { version => $version }});
|
|
|
|
# Create/Update the cache file.
|
|
if ($version)
|
|
{
|
|
my $update_cache = 1;
|
|
my $old_version = "";
|
|
if (-e $cache_file)
|
|
{
|
|
$old_version = $anvil->Storage->read_file({file => $cache_file});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { old_version => $old_version }});
|
|
if ($old_version eq $version)
|
|
{
|
|
# No need to update
|
|
$update_cache = 0;
|
|
}
|
|
else
|
|
{
|
|
|
|
}
|
|
}
|
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { update_cache => $update_cache }});
|
|
if ($update_cache)
|
|
{
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0437", variables => {
|
|
target => $target,
|
|
file => $cache_file,
|
|
}});
|
|
$anvil->Storage->write_file({
|
|
debug => $debug,
|
|
file => $cache_file,
|
|
body => $version,
|
|
mode => "0666",
|
|
overwrite => 1,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Clear off any newline.
|
|
$version =~ s/\n//gs;
|
|
|
|
return($version);
|
|
}
|
|
|
|
=head2 bridges
|
|
|
|
This finds a list of bridges on the host. Bridges that are found are stored is '
|
|
|
|
=cut
|
|
sub 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 => "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 = $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},
|
|
}});
|
|
}
|
|
$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},
|
|
}});
|
|
}
|
|
}
|
|
}
|
|
|
|
# Summary of found bridges.
|
|
foreach my $interface (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}::found" => $anvil->data->{'local'}{network}{bridges}{bridge}{$interface}{found},
|
|
}});
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
=head2 cgi
|
|
|
|
This reads in the CGI variables passed in by a form or URL.
|
|
|
|
This method takes no parameters.
|
|
|
|
=cut
|
|
sub cgi
|
|
{
|
|
my $self = shift;
|
|
my $parameter = shift;
|
|
my $anvil = $self->parent;
|
|
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
|
|
|
|
# This will store all of the CGI variables.
|
|
$anvil->data->{sys}{cgi_string} = "?";
|
|
|
|
# Needed to read in passed CGI variables
|
|
my $cgi = CGI->new();
|
|
|
|
my $cgis = [];
|
|
my $cgi_count = 0;
|
|
# Get the list of parameters coming in, if possible,
|
|
if (exists $cgi->{param})
|
|
{
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'cgi->{param}' => $cgi->{param} }});
|
|
foreach my $variable (sort {$a cmp $b} keys %{$cgi->{param}})
|
|
{
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { variable => $variable }});
|
|
push @{$cgis}, $variable;
|
|
}
|
|
}
|
|
|
|
$cgi_count = @{$cgis};
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { cgi_count => $cgi_count }});
|
|
|
|
# If we don't have at least one variable, we're done.
|
|
if ($cgi_count < 1)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
# NOTE: Later, we will have another array for handling file uploads.
|
|
# Now read in the variables.
|
|
foreach my $variable (sort {$a cmp $b} @{$cgis})
|
|
{
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { variable => $variable }});
|
|
|
|
$anvil->data->{cgi}{$variable}{value} = "";
|
|
$anvil->data->{cgi}{$variable}{mime_type} = "string";
|
|
$anvil->data->{cgi}{$variable}{file_handle} = "";
|
|
$anvil->data->{cgi}{$variable}{file_name} = "";
|
|
$anvil->data->{cgi}{$variable}{alert} = 0; # This is set if a sanity check fails
|
|
|
|
# This is a special CGI key for download files (upload from the user's perspective)
|
|
if ($variable eq "upload_file")
|
|
{
|
|
if (not $cgi->upload('upload_file'))
|
|
{
|
|
# Empty file passed, looks like the user forgot to select a file to upload.
|
|
$anvil->Log->entry({log_level => 2, message_key => "log_0242", file => $THIS_FILE, line => __LINE__});
|
|
}
|
|
else
|
|
{
|
|
$anvil->data->{cgi}{upload_file}{file_handle} = $cgi->upload('upload_file');
|
|
my $file = $anvil->data->{cgi}{upload_file}{file_handle};
|
|
$anvil->data->{cgi}{upload_file}{file_name} = $file;
|
|
$anvil->data->{cgi}{upload_file}{mime_type} = $cgi->uploadInfo($file)->{'Content-Type'};
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
|
|
variable => 'upload_file',
|
|
"cgi::${variable}::file_handle" => $anvil->data->{cgi}{upload_file}{file_handle},
|
|
"cgi::${variable}::file_handle->handle" => $anvil->data->{cgi}{upload_file}{file_handle}->handle,
|
|
"cgi::${variable}::file_name" => $anvil->data->{cgi}{upload_file}{file_name},
|
|
"cgi::${variable}::mime_type" => $anvil->data->{cgi}{upload_file}{mime_type},
|
|
"cgi->upload('upload_file')" => $cgi->upload('upload_file'),
|
|
"cgi->upload('upload_file')->handle" => $cgi->upload('upload_file')->handle,
|
|
}});
|
|
}
|
|
}
|
|
|
|
if (defined $cgi->param($variable))
|
|
{
|
|
# Make this UTF8 if it isn't already.
|
|
if (Encode::is_utf8($cgi->param($variable)))
|
|
{
|
|
$anvil->data->{cgi}{$variable}{value} = $cgi->param($variable);
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "cgi::${variable}::value" => $anvil->data->{cgi}{$variable}{value} }});
|
|
}
|
|
else
|
|
{
|
|
$anvil->data->{cgi}{$variable}{value} = Encode::decode_utf8($cgi->param($variable));
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "cgi::${variable}::value" => $anvil->data->{cgi}{$variable}{value} }});
|
|
}
|
|
|
|
# Append to 'sys::cgi_string', so long as the variable doesn't have 'passwd' or 'password' in it.
|
|
if (($variable !~ /password/) && ($variable !~ /passwd/))
|
|
{
|
|
$anvil->data->{sys}{cgi_string} .= "$variable=".$anvil->data->{cgi}{$variable}{value}."&";
|
|
}
|
|
}
|
|
}
|
|
|
|
# This is a pretty way of displaying the passed-in CGI variables. It loops through all we've got and
|
|
# sorts out the longest variable name. Then it loops again, appending '.' to shorter ones so that
|
|
# everything is lined up in the logs. This almost always prints, save for log level 0.
|
|
if ($anvil->Log->level >= 1)
|
|
{
|
|
my $longest_variable = 0;
|
|
foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{cgi}})
|
|
{
|
|
next if $anvil->data->{cgi}{$variable} eq "";
|
|
if (length($variable) > $longest_variable)
|
|
{
|
|
$longest_variable = length($variable);
|
|
}
|
|
}
|
|
|
|
# Now loop again.
|
|
foreach my $variable (@{$cgis})
|
|
{
|
|
next if $anvil->data->{cgi}{$variable} eq "";
|
|
my $difference = $longest_variable - length($variable);
|
|
my $say_value = "value";
|
|
if ($difference == 0)
|
|
{
|
|
# Do nothing
|
|
}
|
|
elsif ($difference == 1)
|
|
{
|
|
$say_value .= " ";
|
|
}
|
|
elsif ($difference == 2)
|
|
{
|
|
$say_value .= " ";
|
|
}
|
|
else
|
|
{
|
|
my $dots = $difference - 2;
|
|
$say_value .= " ";
|
|
for (1 .. $dots)
|
|
{
|
|
$say_value .= ".";
|
|
}
|
|
$say_value .= " ";
|
|
}
|
|
# This is always '1' as the passed-in variables are what we want to see.
|
|
my $censored_value = $anvil->data->{cgi}{$variable}{value};
|
|
if ((($variable =~ /passwd/) or ($variable =~ /password/)) && (not $anvil->Log->secure))
|
|
{
|
|
# 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 => {
|
|
"cgi::${variable}::$say_value" => $censored_value,
|
|
}});
|
|
}
|
|
}
|
|
|
|
# Clear the last &
|
|
$anvil->data->{sys}{cgi_string} =~ s/&$//;
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::cgi_string" => $anvil->data->{sys}{cgi_string} }});
|
|
|
|
return(0);
|
|
}
|
|
|
|
=head2 date_and_time
|
|
|
|
This method returns the date and/or time using either the current time, or a specified unix time.
|
|
|
|
NOTE: This only returns times in 24-hour notation.
|
|
|
|
=head2 Parameters;
|
|
|
|
=head3 date_only (optional)
|
|
|
|
If set, only the date will be returned (in C<< yyyy/mm/dd >> format).
|
|
|
|
=head3 file_name (optional)
|
|
|
|
When set, the date and/or time returned in a string more useful in file names. Specifically, it will replace spaces with 'C<< _ >>' and 'C<< : >>' and 'C<< / >>' for 'C<< - >>'. This will result in a string in the format like 'C<< yyyy-mm-dd_hh-mm-ss >>'.
|
|
|
|
=head3 offset (optional)
|
|
|
|
If set to a signed number, it will add or subtract the number of seconds from the 'C<< use_time >>' before processing.
|
|
|
|
=head3 use_time (optional)
|
|
|
|
This can be set to a unix timestamp. If it is not set, the current time is used.
|
|
|
|
=head3 time_only (optional)
|
|
|
|
If set, only the time will be returned (in C<< hh:mm:ss >> format).
|
|
|
|
=head3 use_utc (optional)
|
|
|
|
If set, C<< gmtime >> is used instead of C<< localtime >>. The effect of this is that GMTime (greenwhich mean time, UTC-0) is used instead of the local system's time zone.
|
|
|
|
=cut
|
|
sub date_and_time
|
|
{
|
|
my $self = shift;
|
|
my $parameter = shift;
|
|
my $anvil = $self->parent;
|
|
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
|
|
|
|
my $offset = defined $parameter->{offset} ? $parameter->{offset} : 0;
|
|
my $use_time = defined $parameter->{use_time} ? $parameter->{use_time} : time;
|
|
my $use_utc = defined $parameter->{use_utc} ? $parameter->{use_utc} : 0;
|
|
my $file_name = defined $parameter->{file_name} ? $parameter->{file_name} : 0;
|
|
my $time_only = defined $parameter->{time_only} ? $parameter->{time_only} : 0;
|
|
my $date_only = defined $parameter->{date_only} ? $parameter->{date_only} : 0;
|
|
|
|
### NOTE: This is used too early for normal error handling.
|
|
# Are things sane?
|
|
if ($use_time =~ /D/)
|
|
{
|
|
die "Get->date_and_time() was called with 'use_time' set to: [$use_time]. Only a unix timestamp is allowed.\n";
|
|
}
|
|
if ($offset =~ /D/)
|
|
{
|
|
die "Get->date_and_time() was called with 'offset' set to: [$offset]. Only real number is allowed.\n";
|
|
}
|
|
|
|
# Do my initial calculation.
|
|
my $return_string = "";
|
|
my $time = {};
|
|
my $adjusted_time = $use_time + $offset;
|
|
#print $THIS_FILE." ".__LINE__."; [ Debug ] - adjusted_time: [$adjusted_time]\n";
|
|
|
|
# Get the date and time pieces
|
|
if ($use_utc)
|
|
{
|
|
($time->{sec}, $time->{min}, $time->{hour}, $time->{mday}, $time->{mon}, $time->{year}, $time->{wday}, $time->{yday}, $time->{isdst}) = gmtime($adjusted_time);
|
|
#print $THIS_FILE." ".__LINE__."; [ Debug ] - time->{sec}: [".$time->{sec}."], time->{min}: [".$time->{min}."], time->{hour}: [".$time->{hour}."], time->{mday}: [".$time->{mday}."], time->{mon}: [".$time->{mon}."], time->{year}: [".$time->{year}."], time->{wday}: [".$time->{wday}."], time->{yday}: [".$time->{yday}."], time->{isdst}: [".$time->{isdst}."]\n";
|
|
}
|
|
else
|
|
{
|
|
($time->{sec}, $time->{min}, $time->{hour}, $time->{mday}, $time->{mon}, $time->{year}, $time->{wday}, $time->{yday}, $time->{isdst}) = localtime($adjusted_time);
|
|
#print $THIS_FILE." ".__LINE__."; [ Debug ] - time->{sec}: [".$time->{sec}."], time->{min}: [".$time->{min}."], time->{hour}: [".$time->{hour}."], time->{mday}: [".$time->{mday}."], time->{mon}: [".$time->{mon}."], time->{year}: [".$time->{year}."], time->{wday}: [".$time->{wday}."], time->{yday}: [".$time->{yday}."], time->{isdst}: [".$time->{isdst}."]\n";
|
|
}
|
|
|
|
# Process the raw data
|
|
$time->{pad_hour} = sprintf("%02d", $time->{hour});
|
|
$time->{mon}++;
|
|
$time->{pad_min} = sprintf("%02d", $time->{min});
|
|
$time->{pad_sec} = sprintf("%02d", $time->{sec});
|
|
$time->{year} = ($time->{year} + 1900);
|
|
$time->{pad_mon} = sprintf("%02d", $time->{mon});
|
|
$time->{pad_mday} = sprintf("%02d", $time->{mday});
|
|
#print $THIS_FILE." ".__LINE__."; [ Debug ] - time->{pad_hour}: [".$time->{pad_hour}."], time->{pad_min}: [".$time->{pad_min}."], time->{pad_sec}: [".$time->{pad_sec}."], time->{year}: [".$time->{year}."], time->{pad_mon}: [".$time->{pad_mon}."], time->{pad_mday}: [".$time->{pad_mday}."], time->{mon}: [".$time->{mon}."]\n";
|
|
|
|
# Now, the date and time separator depends on if 'file_name' is set.
|
|
my $date_separator = $file_name ? "-" : "/";
|
|
my $time_separator = $file_name ? "-" : ":";
|
|
my $space_separator = $file_name ? "_" : " ";
|
|
if ($time_only)
|
|
{
|
|
$return_string = $time->{pad_hour}.$time_separator.$time->{pad_min}.$time_separator.$time->{pad_sec};
|
|
#print $THIS_FILE." ".__LINE__."; [ Debug ] - return_string: [$return_string]\n";
|
|
}
|
|
elsif ($date_only)
|
|
{
|
|
$return_string = $time->{year}.$date_separator.$time->{pad_mon}.$date_separator.$time->{pad_mday};
|
|
#print $THIS_FILE." ".__LINE__."; [ Debug ] - return_string: [$return_string]\n";
|
|
}
|
|
else
|
|
{
|
|
$return_string = $time->{year}.$date_separator.$time->{pad_mon}.$date_separator.$time->{pad_mday}.$space_separator.$time->{pad_hour}.$time_separator.$time->{pad_min}.$time_separator.$time->{pad_sec};
|
|
#print $THIS_FILE." ".__LINE__."; [ Debug ] - return_string: [$return_string]\n";
|
|
}
|
|
|
|
return($return_string);
|
|
}
|
|
|
|
=head2 host_name
|
|
|
|
This takes a host UUID and returns the host name (as recorded in the C<< hosts >> table). If the entry is not found, an empty string is returned.
|
|
|
|
Parameters;
|
|
|
|
=head3 host_uuid (required)
|
|
|
|
This is the C<< host_uuid >> to translate into a host name.
|
|
|
|
=cut
|
|
sub host_name
|
|
{
|
|
my $self = shift;
|
|
my $parameter = shift;
|
|
my $anvil = $self->parent;
|
|
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
|
|
|
|
my $host_name = "";
|
|
my $host_uuid = defined $parameter->{host_uuid} ? $parameter->{host_uuid} : "";
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_uuid => $host_uuid }});
|
|
|
|
my $query = "
|
|
SELECT
|
|
host_name
|
|
FROM
|
|
hosts
|
|
WHERE
|
|
host_uuid = ".$anvil->Database->quote($host_uuid).";
|
|
";
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
|
|
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
|
|
my $count = @{$results};
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
|
|
results => $results,
|
|
count => $count,
|
|
}});
|
|
if ($count == 1)
|
|
{
|
|
# Found it
|
|
$host_name = defined $results->[0]->[0] ? $results->[0]->[0] : "";
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_name => $host_name }});
|
|
}
|
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_name => $host_name }});
|
|
return($host_name);
|
|
}
|
|
|
|
=head2 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 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 => "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 host_type
|
|
|
|
This method tries to determine the host type and returns a value suitable for use is the C<< hosts >> table.
|
|
|
|
my $type = $anvil->System->host_type();
|
|
|
|
First, it looks to see if C<< sys::host_type >> is set and, if so, uses that string as it is.
|
|
|
|
If that isn't set, it then looks to see if the file C<< /etc/anvil/type.X >> exists, where C<< X >> is C<< node >>, C<< striker >> or C<< dr >>. If found, the appropriate type is returned.
|
|
|
|
If that file doesn't exist, then it then checks to see which C<< anvil-<type> >> rpm is installed. In order, it looks for C<< anvil-striker >>, then C<< anvil-node >> and finally C<< anvil-dr >>. If one of them is found, the appropriate C<< /etc/anvil/type.X >> is created.
|
|
|
|
=cut
|
|
sub host_type
|
|
{
|
|
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 => "Get->host_type()" }});
|
|
|
|
my $host_type = "";
|
|
my $host_name = $anvil->_short_host_name;
|
|
$host_type = "unknown";
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
|
|
host_type => $host_type,
|
|
host_name => $host_name,
|
|
"sys::host_type" => $anvil->data->{sys}{host_type},
|
|
}});
|
|
|
|
if ($anvil->data->{sys}{host_type})
|
|
{
|
|
$host_type = $anvil->data->{sys}{host_type};
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_type => $host_type }});
|
|
}
|
|
else
|
|
{
|
|
# Can I determine it by seeing a file?
|
|
if (-e $anvil->data->{path}{configs}{'type.node'})
|
|
{
|
|
$host_type = "node";
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_type => $host_type }});
|
|
}
|
|
elsif (-e $anvil->data->{path}{configs}{'type.striker'})
|
|
{
|
|
$host_type = "striker";
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_type => $host_type }});
|
|
}
|
|
elsif (-e $anvil->data->{path}{configs}{'type.dr'})
|
|
{
|
|
$host_type = "dr";
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_type => $host_type }});
|
|
}
|
|
else
|
|
{
|
|
# Last gasp here is to use 'rpm' to see which RPMs are installed. If we find one,
|
|
# we'll touch 'type.X' file
|
|
foreach my $rpm ("anvil-striker", "anvil-node", "anvil-dr")
|
|
{
|
|
my ($output, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{rpm}." -q ".$rpm});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { output => $output, return_code => $return_code }});
|
|
if ($return_code eq "0")
|
|
{
|
|
# Found out what we are.
|
|
if ($rpm eq "anvil-striker")
|
|
{
|
|
$host_type = "striker";
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_type => $host_type }});
|
|
}
|
|
|
|
my $key = "type.".$host_type;
|
|
my $file = $anvil->data->{path}{configs}{$key};
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
|
|
key => $key,
|
|
file => $file,
|
|
}});
|
|
# If we have a file and we're root, touch to the file.
|
|
if (($file) && (($< == 0) or ($> == 0)))
|
|
{
|
|
my $error = $anvil->Storage->write_file({
|
|
debug => $debug,
|
|
body => "",
|
|
file => $file,
|
|
});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 0, list => { error => $error }});
|
|
}
|
|
last;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return($host_type);
|
|
}
|
|
|
|
=head2 host_uuid
|
|
|
|
This returns the local host's system UUID (as reported by 'dmidecode'). If the host UUID isn't available, and the program is not running with root priviledges, C<< #!error!# >> is returned.
|
|
|
|
print "This host's UUID: [".$anvil->Get->host_uuid."]\n";
|
|
|
|
It is possible to override the local UUID, though it is not recommended.
|
|
|
|
$anvil->Get->host_uuid({set => "720a0509-533d-406b-8fc1-03aca3e75fa7"})
|
|
|
|
=cut
|
|
sub host_uuid
|
|
{
|
|
my $self = shift;
|
|
my $parameter = shift;
|
|
my $anvil = $self->parent;
|
|
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
|
|
|
|
my $set = defined $parameter->{set} ? $parameter->{set} : "";
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
|
|
set => $set,
|
|
'HOST::UUID' => $anvil->{HOST}{UUID},
|
|
}});
|
|
|
|
if ($set)
|
|
{
|
|
$anvil->{HOST}{UUID} = $set;
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "HOST::UUID" => $anvil->{HOST}{UUID} }});
|
|
}
|
|
elsif (not $anvil->{HOST}{UUID})
|
|
{
|
|
# Read /etc/anvil/host.uuid if it exists. If not, and if we're root, we'll create that file
|
|
# using the UUID from dmidecode.
|
|
my $uuid = "";
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
|
|
'$<' => $<,
|
|
'$>' => $>,
|
|
'path::data::host_uuid' => $anvil->data->{path}{data}{host_uuid},
|
|
}});
|
|
if (-e $anvil->data->{path}{data}{host_uuid})
|
|
{
|
|
# Read the UUID in
|
|
$uuid = $anvil->Storage->read_file({debug => $debug, file => $anvil->data->{path}{data}{host_uuid}});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uuid => $uuid }});
|
|
}
|
|
elsif (($< == 0) or ($> == 0))
|
|
{
|
|
# Create the UUID file.
|
|
($uuid, my $return_code) = $anvil->System->call({debug => $debug, shell_call => $anvil->data->{path}{exe}{dmidecode}." --string system-uuid"});
|
|
$uuid = lc($uuid);
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
|
|
uuid => $uuid,
|
|
return_code => $return_code,
|
|
}});
|
|
}
|
|
else
|
|
{
|
|
# Host UUID file doesn't exist and I'm Not running as root, I'm done.
|
|
# We're done.
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0187"});
|
|
return("#!error!#");
|
|
}
|
|
|
|
if ($anvil->Validate->is_uuid({uuid => $uuid}))
|
|
{
|
|
$anvil->{HOST}{UUID} = $uuid;
|
|
if (not -e $anvil->data->{path}{data}{host_uuid})
|
|
{
|
|
### TODO: This will need to set the proper SELinux context.
|
|
# Apache run scripts can't call the system UUID, so we'll write it to a text
|
|
# file.
|
|
$anvil->Storage->write_file({
|
|
debug => $debug,
|
|
file => $anvil->data->{path}{data}{host_uuid},
|
|
body => $uuid,
|
|
user => "apache",
|
|
group => "apache",
|
|
mode => "0666",
|
|
overwrite => 0,
|
|
});
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "message_0011", variables => { file => $anvil->data->{path}{configs}{'postgresql.conf'} }});
|
|
}
|
|
}
|
|
else
|
|
{
|
|
# Bad UUID.
|
|
$anvil->{HOST}{UUID} = "";
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "HOST::UUID" => $anvil->{HOST}{UUID} }});
|
|
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0134", variables => { uuid => $uuid }});
|
|
return("#!error!#");
|
|
}
|
|
}
|
|
|
|
# We'll also store the host UUID in a variable.
|
|
if ((not $anvil->data->{sys}{host_uuid}) && ($anvil->{HOST}{UUID}))
|
|
{
|
|
$anvil->data->{sys}{host_uuid} = $anvil->{HOST}{UUID};
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::host_uuid" => $anvil->data->{sys}{host_uuid} }});
|
|
}
|
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "HOST::UUID" => $anvil->{HOST}{UUID} }});
|
|
return($anvil->{HOST}{UUID});
|
|
}
|
|
|
|
=head2 md5sum
|
|
|
|
This returns the C<< md5sum >> of a given file.
|
|
|
|
Parameters;
|
|
|
|
=head3 file
|
|
|
|
This is the full or relative path to the file. If the file doesn't exist, an empty string is returned.
|
|
|
|
=cut
|
|
sub md5sum
|
|
{
|
|
my $self = shift;
|
|
my $parameter = shift;
|
|
my $anvil = $self->parent;
|
|
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
|
|
|
|
my $sum = "";
|
|
my $file = defined $parameter->{file} ? $parameter->{file} : "";
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { file => $file }});
|
|
|
|
if (-e $file)
|
|
{
|
|
my $shell_call = $anvil->data->{path}{exe}{md5sum}." ".$file;
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }});
|
|
|
|
my ($return, $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'return' => $return, return_code => $return_code }});
|
|
|
|
# split the sum off.
|
|
$sum = ($return =~ /^(.*?)\s+$file$/)[0];
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { sum => $sum }});
|
|
}
|
|
|
|
return($sum);
|
|
}
|
|
|
|
=head2 os_type
|
|
|
|
This returns the operating system type and the system architecture as two separate string variables.
|
|
|
|
# Run on RHEL 8, on a 64-bit system
|
|
my ($os_type, $os_arch) = $anvil->Get->os_type();
|
|
|
|
# '$os_type' holds 'rhel8' ('rhel' or 'centos' + release version)
|
|
# '$os_arch' holds 'x86_64' (specifically, 'uname --hardware-platform')
|
|
|
|
If either can not be determined, C<< unknown >> will be returned.
|
|
|
|
This method takes no parameters.
|
|
|
|
=cut
|
|
sub get_os_type
|
|
{
|
|
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 => "Get->os_type()" }});
|
|
|
|
my $os_type = "unknown";
|
|
my $os_arch = "unknown";
|
|
|
|
### NOTE: Examples;
|
|
# Red Hat Enterprise Linux release 8.0 Beta (Ootpa)
|
|
# Red Hat Enterprise Linux Server release 7.5 (Maipo)
|
|
# CentOS Linux release 7.5.1804 (Core)
|
|
|
|
# Read in the /etc/redhat-release file
|
|
my $release = $anvil->Storage->read_file({file => $anvil->data->{path}{data}{'redhat-release'}});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { release => $release }});
|
|
if ($release =~ /Red Hat Enterprise Linux .* (\d+)\./)
|
|
{
|
|
# RHEL, with the major version number appended
|
|
$os_type = "rhel".$1;
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { os_type => $os_type }});
|
|
}
|
|
elsif ($release =~ /CentOS .*? (\d+)\./)
|
|
{
|
|
# CentOS, with the major version number appended
|
|
$os_type = "centos".$1;
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { os_type => $os_type }});
|
|
}
|
|
|
|
my ($output, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{uname}." --hardware-platform"});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { output => $output, return_code => $return_code }});
|
|
if ($output)
|
|
{
|
|
$os_arch = $output;
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { os_arch => $os_arch }});
|
|
}
|
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
|
|
os_type => $os_type,
|
|
os_arch => $os_arch,
|
|
}});
|
|
return($os_type, $os_arch);
|
|
}
|
|
|
|
=head2 switches
|
|
|
|
This reads in the command line switches used to invoke the parent program.
|
|
|
|
It takes no arguments, and data is stored in 'C<< $anvil->data->{switches}{x} >>', where 'x' is the switch used.
|
|
|
|
Switches in the form 'C<< -x >>' and 'C<< --x >>' are treated the same and the corresponding 'C<< $anvil->data->{switches}{x} >>' will contain '#!set!#'.
|
|
|
|
Switches in the form 'C<< -x foo >>', 'C<< --x foo >>', 'C<< -x=foo >>' and 'C<< --x=foo >>' are treated the same and the corresponding 'C<< $anvil->data->{switches}{x} >>' will contain 'foo'.
|
|
|
|
The switches 'C<< -v >>', 'C<< -vv >>', 'C<< -vvv >>' and 'C<< -vvvv >>' will cause the active log level to automatically change to 1, 2, 3 or 4 respectively. Passing 'C<< -V >>' will set the log level to '0'.
|
|
|
|
Anything after 'C<< -- >>' is treated as a raw string and is not processed.
|
|
|
|
=cut
|
|
sub switches
|
|
{
|
|
my $self = shift;
|
|
my $parameter = shift;
|
|
my $anvil = $self->parent;
|
|
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
|
|
|
|
my $last_argument = "";
|
|
foreach my $argument (@ARGV)
|
|
{
|
|
if ($last_argument eq "raw")
|
|
{
|
|
# Don't process anything.
|
|
$anvil->data->{switches}{raw} .= " $argument";
|
|
}
|
|
elsif ($argument =~ /^-/)
|
|
{
|
|
# If the argument is just '--', appeand everything after it to 'raw'.
|
|
if ($argument eq "--")
|
|
{
|
|
$last_argument = "raw";
|
|
$anvil->data->{switches}{raw} = "";
|
|
}
|
|
else
|
|
{
|
|
($last_argument) = ($argument =~ /^-{1,2}(.*)/)[0];
|
|
if ($last_argument =~ /=/)
|
|
{
|
|
# Break up the variable/value.
|
|
($last_argument, my $value) = (split /=/, $last_argument, 2);
|
|
$anvil->data->{switches}{$last_argument} = $value;
|
|
}
|
|
else
|
|
{
|
|
$anvil->data->{switches}{$last_argument} = "#!SET!#";
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ($last_argument)
|
|
{
|
|
$anvil->data->{switches}{$last_argument} = $argument;
|
|
$last_argument = "";
|
|
}
|
|
else
|
|
{
|
|
# Got a value without an argument, so just record it as '#!SET!#'.
|
|
$anvil->data->{switches}{$argument} = "#!SET!#";
|
|
}
|
|
}
|
|
}
|
|
|
|
# Clean up the initial space added to 'raw'.
|
|
if ($anvil->data->{switches}{raw})
|
|
{
|
|
$anvil->data->{switches}{raw} =~ s/^ //;
|
|
}
|
|
|
|
# Adjust the log level if requested.
|
|
$anvil->Log->_adjust_log_level();
|
|
|
|
return(0);
|
|
}
|
|
|
|
=head2 uptime
|
|
|
|
This returns, in seconds, how long the host has been up and running for.
|
|
|
|
This method takes no parameters.
|
|
|
|
=cut
|
|
### TODO: Make this work on remote hosts
|
|
sub uptime
|
|
{
|
|
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 => "Get->uptime()" }});
|
|
|
|
my $uptime = $anvil->Storage->read_file({
|
|
force_read => 1,
|
|
cache => 0,
|
|
file => $anvil->data->{path}{proc}{uptime},
|
|
});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uptime => $uptime }});
|
|
|
|
# Clean it up. We'll have gotten two numbers, the uptime in seconds (to two decimal places) and the
|
|
# total idle time. We only care about the int number.
|
|
$uptime =~ s/^(\d+)\..*$/$1/;
|
|
$uptime =~ s/\n//gs;
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uptime => $uptime }});
|
|
|
|
return($uptime);
|
|
}
|
|
|
|
=head2 users_home
|
|
|
|
This method takes a user's name and returns the user's home directory. If the home directory isn't found, C<< 0 >> is returned.
|
|
|
|
Parameters;
|
|
|
|
=head3 user (optional, default is the user name of the real UID (as stored in '$<'))
|
|
|
|
This is the user whose home directory you are looking for.
|
|
|
|
=cut
|
|
sub users_home
|
|
{
|
|
my $self = shift;
|
|
my $parameter = shift;
|
|
my $anvil = $self->parent;
|
|
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
|
|
|
|
my $home_directory = 0;
|
|
|
|
my $user = defined $parameter->{user} ? $parameter->{user} : getpwuid($<);
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { user => $user }});
|
|
|
|
# Make sure the user is only one digit. Sometimes $< (and others) will return multiple IDs.
|
|
if ($user =~ /^\d+ \d$/)
|
|
{
|
|
$user =~ s/^(\d+)\s.*$/$1/;
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { user => $user }});
|
|
}
|
|
|
|
# If the user is numerical, convert it to a name.
|
|
if ($user =~ /^\d+$/)
|
|
{
|
|
$user = getpwuid($user);
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { user => $user }});
|
|
}
|
|
|
|
# Still don't have a name? fail...
|
|
if ($user eq "")
|
|
{
|
|
# No user? No bueno...
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Get->users_home()", parameter => "user" }});
|
|
return($home_directory);
|
|
}
|
|
|
|
my $body = $anvil->Storage->read_file({file => $anvil->data->{path}{data}{passwd}});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { body => $body }});
|
|
foreach my $line (split /\n/, $body)
|
|
{
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }});
|
|
if ($line =~ /^$user:/)
|
|
{
|
|
$home_directory = (split/:/, $line)[5];
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { home_directory => $home_directory }});
|
|
last;
|
|
}
|
|
}
|
|
|
|
# Do I have the a user's $HOME now?
|
|
if (not $home_directory)
|
|
{
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0061", variables => { user => $user }});
|
|
}
|
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { home_directory => $home_directory }});
|
|
return($home_directory);
|
|
}
|
|
|
|
=head2 uuid
|
|
|
|
This method returns a new v4 UUID (using 'UUID::Tiny').
|
|
|
|
Parameters;
|
|
|
|
=head3 short (optional, default '0')
|
|
|
|
This returns just the first 8 bytes of the uuid. For example, if the generated UUID is C<< 9e4b3f7c-5a98-40b6-9c34-84fdb24ddd30 >>, only C<< 9e4b3f7c >> is returned.
|
|
|
|
=cut
|
|
sub uuid
|
|
{
|
|
my $self = shift;
|
|
my $parameter = shift;
|
|
my $anvil = $self->parent;
|
|
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
|
|
|
|
my $short = defined $parameter->{short} ? $parameter->{short} : 0;
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
|
|
short => $short,
|
|
}});
|
|
|
|
my $uuid = create_uuid_as_string(UUID_RANDOM);
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uuid => $uuid }});
|
|
|
|
if ($short)
|
|
{
|
|
$uuid =~ s/^(\w+?)-.*$/$1/;
|
|
}
|
|
|
|
return($uuid);
|
|
}
|
|
|
|
# =head3
|
|
#
|
|
# Private Functions;
|
|
#
|
|
# =cut
|
|
|
|
#############################################################################################################
|
|
# Private functions #
|
|
#############################################################################################################
|
|
|
|
=head2 _salt
|
|
|
|
This generates a random salt string for use with internal Striker passwords.
|
|
|
|
=cut
|
|
sub _salt
|
|
{
|
|
my $self = shift;
|
|
my $parameter = shift;
|
|
my $anvil = $self->parent;
|
|
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
|
|
|
|
my $salt = "";
|
|
my $salt_length = $anvil->data->{sys}{password}{salt_length} =~ /^\d+$/ ? $anvil->data->{sys}{password}{salt_length} : 16;
|
|
my @seed = (" ", "~", "`", "!", "#", "^", "&", "*", "(", ")", "-", "_", "+", "=", "{", "[", "}", "]", "|", ":", ";", "'", ",", "<", ".", ">", "/");
|
|
my @alpha = ("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z");
|
|
my $seed_count = @seed;
|
|
my $alpha_count = @alpha;
|
|
|
|
my $skip_count = 0;
|
|
for (1..$salt_length)
|
|
{
|
|
# We want to have a little randomness in the salt length, but not skip tooooo many times.
|
|
if ((int(rand(20)) == 2) && ($skip_count <= 3))
|
|
{
|
|
$skip_count++;
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { skip_count => $skip_count }});
|
|
next;
|
|
}
|
|
|
|
# What character will this string be?
|
|
my $this_integer = int(rand(3));
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { this_integer => $this_integer }});
|
|
if ($this_integer == 0)
|
|
{
|
|
# Inject a random digit
|
|
$salt .= int(rand(10));
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { salt => $salt }});
|
|
}
|
|
elsif ($this_integer == 1)
|
|
{
|
|
# Inject a random letter
|
|
$salt .= $alpha[int(rand($alpha_count))];
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { salt => $salt }});
|
|
}
|
|
else
|
|
{
|
|
# Inject a random character
|
|
$salt .= $seed[int(rand($seed_count))];
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { salt => $salt }});
|
|
}
|
|
}
|
|
|
|
return($salt);
|
|
}
|
|
|
|
|
|
=head2 _wrap_to
|
|
|
|
This determines how wide the user's terminal currently is and returns that width, as well as store it in C<< sys::terminal::columns >>.
|
|
|
|
This takes no parameters. If there is a problem reading the column width, C<< 0 >> will be returned.
|
|
|
|
=cut
|
|
sub _wrap_to
|
|
{
|
|
my $self = shift;
|
|
my $parameter = shift;
|
|
my $anvil = $self->parent;
|
|
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
|
|
|
|
# Get the column width
|
|
my ($columns, $return_code) = $anvil->System->call({debug => $debug, redirect_stderr => 0, shell_call => $anvil->data->{path}{exe}{tput}." cols" });
|
|
if ((not defined $columns) or ($columns !~ /^\d+$/))
|
|
{
|
|
# Set 0.
|
|
$columns = 0;
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { columns => $columns }});
|
|
}
|
|
else
|
|
{
|
|
# Got a good value
|
|
$anvil->data->{sys}{terminal}{columns} = $columns;
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'sys::terminal::columns' => $anvil->data->{sys}{terminal}{columns} }});
|
|
}
|
|
|
|
return($columns);
|
|
}
|
|
|
|
1;
|