From Code to Community: Sponsoring The Perl and Raku Conference 2025 Learn more

#
# (c) Jan Gehring <jan.gehring@gmail.com>
#
use v5.12.5;
our $VERSION = '1.16.0'; # VERSION
use Symbol;
use List::Util 1.45 qw(uniq);
'eq' => sub { shift->is_eq(@_); },
'ne' => sub { shift->is_ne(@_); },
'""' => sub { shift->to_s(@_); },
'cmp' => sub { shift->compare(@_); };
sub function {
my ( $class, $name, $code ) = @_;
my $ref_to_function = qualify_to_ref( $name, $class );
*{$ref_to_function} = $code;
}
sub new {
my $that = shift;
my $proto = ref($that) || $that;
my $self = {@_};
bless( $self, $proto );
# be save check if name is already a server ref
if ( ref $self->{name} eq __PACKAGE__ ) {
return $self->{name};
}
# rewrite auth info
if ( $self->{user} ) {
$self->{auth}->{user} = $self->{user};
delete $self->{user};
}
if ( $self->{password} ) {
$self->{auth}->{password} = $self->{password};
delete $self->{password};
}
if ( $self->{port} ) {
$self->{auth}->{port} = $self->{port};
delete $self->{port};
}
if ( $self->{public_key} ) {
$self->{auth}->{public_key} = $self->{public_key};
delete $self->{public_key};
}
if ( $self->{private_key} ) {
$self->{auth}->{private_key} = $self->{private_key};
delete $self->{private_key};
}
if ( $self->{sudo} ) {
$self->{auth}->{sudo} = $self->{sudo};
delete $self->{sudo};
}
if ( $self->{sudo_password} ) {
$self->{auth}->{sudo_password} = $self->{sudo_password};
delete $self->{sudo_password};
}
if ( $self->{auth_type} ) {
$self->{auth}->{auth_type} = $self->{auth_type};
delete $self->{auth_type};
}
if ( !ref $self->{__group__} ) {
$self->{__group__} = [];
}
return $self;
}
sub get_servers {
my ($self) = @_;
return uniq map {
if ( ref $_ && $_->isa("Rex::Group::Entry::Server") ) {
$_;
}
else {
Rex::Group::Entry::Server->new( name => $_, auth => $self->{auth} );
}
} $self->evaluate_hostname;
}
sub to_s {
my ($self) = @_;
return $self->{name};
}
sub is_eq {
my ( $self, $comp ) = @_;
if ( $comp eq $self->to_s ) {
return 1;
}
}
sub is_ne {
my ( $self, $comp ) = @_;
if ( $comp ne $self->to_s ) {
return 1;
}
}
sub compare {
my ( $self, $comp ) = @_;
return ncmp( $self->to_s, $comp->to_s );
}
sub has_auth {
my ($self) = @_;
return exists $self->{auth};
}
sub set_auth {
my ( $self, %auth ) = @_;
$self->{auth} = \%auth;
}
sub get_auth {
my ($self) = @_;
return $self->{auth};
}
sub get_user {
my ($self) = @_;
if ( exists $self->{auth}->{user} ) {
return $self->{auth}->{user};
}
if (!Rex::Config->has_user
&& Rex::Config->get_ssh_config_username( server => $self->to_s ) )
{
Rex::Logger::debug("Checking for a user in .ssh/config");
return Rex::Config->get_ssh_config_username( server => $self->to_s );
}
return Rex::Config->get_user;
}
sub get_password {
my ($self) = @_;
if ( exists $self->{auth}->{password} ) {
return $self->{auth}->{password};
}
return Rex::Config->get_password;
}
sub get_port {
my ($self) = @_;
if ( exists $self->{auth}->{port} ) {
return $self->{auth}->{port};
}
return Rex::Config->get_port;
}
sub get_public_key {
my ($self) = @_;
if ( exists $self->{auth}->{public_key} && -f $self->{auth}->{public_key} ) {
Rex::Logger::debug(
"Rex::Group::Entry::Server (public_key): returning $self->{auth}->{public_key}"
);
return $self->{auth}->{public_key};
}
if (!Rex::Config->has_public_key
&& Rex::Config->get_ssh_config_public_key( server => $self->to_s ) )
{
Rex::Logger::debug("Checking for a public key in .ssh/config");
my $key = Rex::Config->get_ssh_config_public_key( server => $self->to_s );
Rex::Logger::debug(
"Rex::Group::Entry::Server (public_key): returning $key");
return $key;
}
Rex::Logger::debug( "Rex::Group::Entry::Server (public_key): returning "
. ( Rex::Config->get_public_key || "" ) );
return Rex::Config->get_public_key;
}
sub get_private_key {
my ($self) = @_;
if ( exists $self->{auth}->{private_key} && -f $self->{auth}->{private_key} )
{
Rex::Logger::debug( "Rex::Group::Entry::Server (private_key): returning "
. $self->{auth}->{private_key} );
return $self->{auth}->{private_key};
}
if (!Rex::Config->has_private_key
&& Rex::Config->get_ssh_config_private_key( server => $self->to_s ) )
{
Rex::Logger::debug("Checking for a private key in .ssh/config");
my $key = Rex::Config->get_ssh_config_private_key( server => $self->to_s );
Rex::Logger::debug(
"Rex::Group::Entry::Server (private_key): returning " . $key );
return $key;
}
Rex::Logger::debug( "Rex::Group::Entry::Server (private_key): returning "
. ( Rex::Config->get_private_key || "" ) );
return Rex::Config->get_private_key;
}
sub get_auth_type {
my ($self) = @_;
if ( exists $self->{auth}->{auth_type} && $self->{auth}->{auth_type} ) {
return $self->{auth}->{auth_type};
}
if ( exists $self->{auth}->{public_key}
&& -f $self->{auth}->{public_key}
&& exists $self->{auth}->{private_key}
&& -f $self->{auth}->{private_key} )
{
return "try";
}
elsif ( exists $self->{auth}->{user}
&& $self->{auth}->{user}
&& exists $self->{auth}->{password}
&& $self->{auth}->{password} ne "" )
{
return "try";
}
elsif ( Rex::Config->get_krb5_auth ) {
return "krb5";
}
elsif ( Rex::Config->get_password_auth ) {
return "pass";
}
elsif ( Rex::Config->get_key_auth ) {
return "key";
}
return "try";
}
sub get_sudo {
my ($self) = @_;
if ( exists $self->{auth}->{sudo} ) {
return $self->{auth}->{sudo};
}
return 0;
}
sub get_sudo_password {
my ($self) = @_;
if ( exists $self->{auth}->{sudo_password} ) {
return $self->{auth}->{sudo_password};
}
Rex::Config->get_sudo_password;
}
sub merge_auth {
my ( $self, $other_auth ) = @_;
my %new_auth;
my @keys =
qw/user password port private_key public_key auth_type sudo sudo_password/;
for my $key (@keys) {
my $call = "get_$key";
if ( ref($self)->can($call) ) {
$new_auth{$key} = $self->$call();
}
else {
$new_auth{$key} = $other_auth->{$key};
}
# other_auth has presedence
if ( exists $other_auth->{$key}
&& defined $other_auth->{$key}
&& Rex::Config->get_use_server_auth() == 0 )
{
$new_auth{$key} = $other_auth->{$key};
}
}
return %new_auth;
}
sub append_to_group {
my ( $self, $group ) = @_;
push @{ $self->{__group__} }, $group;
}
sub group {
my ($self) = @_;
return $self->groups;
}
sub groups {
my ($self) = @_;
return @{ $self->{__group__} };
}
sub option {
my ( $self, $option ) = @_;
if ( exists $self->{$option} ) {
return $self->{$option};
}
}
sub gather_information {
my ($self) = @_;
my %info = Rex::Helper::System::info();
$self->{__hardware_info__} = \%info;
}
sub AUTOLOAD {
use vars qw($AUTOLOAD);
my $self = shift;
return $self if ( $AUTOLOAD =~ m/DESTROY/ );
my ($wanted_data) = ( $AUTOLOAD =~ m/::([a-z0-9A-Z_]+)$/ );
if ( scalar( keys %{ $self->{__hardware_info__} } ) == 0 ) {
$self->gather_information;
}
if ( exists $self->{__hardware_info__}->{$wanted_data} ) {
return $self->{__hardware_info__}->{$wanted_data};
}
if ( exists $self->{$wanted_data} ) {
return $self->{$wanted_data};
}
return;
}
sub evaluate_hostname {
my ($self) = @_;
my @servers = Rex::Commands::evaluate_hostname( $self->to_s );
my @multiple_me;
for (@servers) {
push @multiple_me, ref($self)->new( %{$self} );
$multiple_me[-1]->{name} = $_;
}
return @multiple_me;
}
sub test_perl {
my ($self) = @_;
my $exec = Rex::Interface::Exec->create;
return $exec->can_run( ["perl"] ); # use a new anon ref, so that we don't have drawbacks if some lower layers will manipulate things.
}
1;