package Object::Remote::Connector::LocalSudo;
+use Object::Remote::Logging qw (:log :dlog);
use Symbol qw(gensym);
+use Module::Runtime qw(use_module);
use IPC::Open3;
use Moo;
extends 'Object::Remote::Connector::Local';
-has password_callback => (is => 'ro');
+has target_user => (is => 'ro', required => 1);
-sub _sudo_perl_command {
- my ($self, $target_user) = @_;
+has password_callback => (is => 'lazy');
+
+sub _build_password_callback {
+ my ($self) = @_;
+ my $pw_prompt = use_module('Object::Remote::Prompt')->can('prompt_pw');
+ my $user = $self->target_user;
+ return sub {
+ $pw_prompt->("sudo password for ${user}", undef, { cache => 1 })
+ }
+}
+
+has sudo_perl_command => (is => 'lazy');
+
+sub _build_sudo_perl_command {
+ my ($self) = @_;
return
- 'sudo', '-S', '-u', $target_user, '-p', "[sudo] password please\n",
+ 'sudo', '-S', '-u', $self->target_user, '-p', "[sudo] password please\n",
'perl', '-MPOSIX=dup2',
'-e', 'print STDERR "GO\n"; exec(@ARGV);',
- $self->_perl_command($target_user);
+ $self->perl_command;
}
sub _start_perl {
my $foreign_stdin,
my $foreign_stdout,
$sudo_stderr,
- $self->_sudo_perl_command(@_)
+ @{$self->sudo_perl_command}
) or die "open3 failed: $!";
chomp(my $line = <$sudo_stderr>);
if ($line eq "GO") {
->watch_io(
handle => $sudo_stderr,
on_read_ready => sub {
- if (sysread($sudo_stderr, my $buf, 1024) > 0) {
+ Dlog_debug { "LocalSudo: Preparing to read data from $_" } $sudo_stderr;
+ if (sysread($sudo_stderr, my $buf, 32768) > 0) {
+ log_trace { "LocalSudo: successfully read data, printing it to STDERR" };
print STDERR $buf;
+ log_trace { "LocalSudo: print() to STDERR is done" };
} else {
+ log_debug { "LocalSudo: received EOF or error on file handle, unwatching it" };
Object::Remote->current_loop
->unwatch_io(
handle => $sudo_stderr,
for ($_[0]) {
# username followed by @
if (defined and !ref and /^ ([^\@]*?) \@ $/x) {
- return __PACKAGE__->new->connect($1);
+ shift(@_);
+ return __PACKAGE__->new(@_, target_user => $1);
}
}
return;
};
1;
+
+=head1 NAME
+
+Object::Remote::Connector::LocalSudo - A connector for a local Perl process with
+sudo
+
+=head1 DESCRIPTION
+
+Used to create a connector that talks to a Perl process started on the local
+machine, via sudo as a specific user. Invoked by L<Object::Remote/connect> if
+the connection spec is a username followed by a @.
+
+=head1 ARGUMENTS
+
+Inherits arguments from L<Object::Remote::Connector::Local> and provides the
+following:
+
+=head2 target_user
+
+When invoked via L<Object::Remote/connect>, specified via the connection spec,
+and not overridable.
+
+The name of the user to run the process as.
+
+=head2 password_callback
+
+A function that returns the password to be passed on to sudo. Defaults to asking
+the operator via command line.
+
+=head2 sudo_perl_command
+
+An arrayref containing a list of strings to be passed to L<IPC::Open3> to open
+the perl process. Defaults to a specific sudo incantation.
+
+=cut