NAME

App::FuguVM::Remote - the remote side of one running guest

SYNOPSIS

use App::FuguVM::Remote;

my $remote = App::FuguVM::Remote->new(
    host => $vm->connect_address,
    port => $ssh_port,
);

my $result = $remote->run('uname', '-m');

$remote->put('lib', '/root/lib', mode => 0644)
    or die "put failed\n";

$remote->get('/root/report.txt', 'report.txt')
    or die "get failed\n";

DESCRIPTION

The module holds the remote side of one running guest: the Fugu::SSH object, the argument quoting, the local walk, and the publish order. Thus App::FuguVM::CLI keeps thin command bodies, and one module holds the session timeout.

Three constants carry the numbers. SSH_TIMEOUT is 3600 seconds: Fugu::SSH bounds the connect and the channel read with one value, and the value must hold a guest build and a large transfer. MAX_TRANSFER_SIZE is 64 MiB for one file, because write_file and read_file each hold a file in memory. BATCH_PATHS is 100 paths for each batched remote command, so no command line grows too long.

new and run die on a missing argument, because each one is a programming error. Every other failure is a return value, and the module reports each reason through Fugu::Log->default.

METHODS

new

App::FuguVM::Remote->new(host => $host, port => $port)

Build the object. It opens nothing. host is the connect address of the guest, and the user is root. The method dies when the caller gives no host, and it dies when the caller gives no port.

quote_argv

App::FuguVM::Remote->quote_argv(@argv)

Return one remote command string. A class method. The method wraps each word in single quotes, and it replaces each single quote inside a word with the '\'' form. An empty word becomes ''. The words join with one space. So the remote shell splits the string at the word boundaries only: it expands nothing, and it globs nothing.

run

$remote->run(@argv)

Run one argument vector on the guest. The method returns the hash of Fugu::SSH->run_command: stdout, stderr and exit_code. It dies on an empty vector. A connect failure reads as exit code 1, with the reason in stderr.

interactive

$remote->interactive

Open an interactive session. The method returns the exit code of ssh(1).

put

$remote->put($local, $remote_path, mode => 0600)

Copy a local file or a local directory to $remote_path in the guest. The destination is never a container: the content of a directory arrives under $remote_path, with no component for the source directory name. mode sets the mode of each file that the method writes. Without it each file keeps its local permission bits, masked with 0777, so no setuid bit and no setgid bit arrives. A directory gets the mode that the remote umask allows.

The method walks the source first, and a symbolic link, a device node, a socket, a fifo, and a file above MAX_TRANSFER_SIZE each fail the whole call before one byte moves. It creates every remote directory with batched mkdir -p calls, writes each file to a temporary name beside its destination, and publishes every temporary file with batched mv -f calls. A failure removes every temporary file, so a failed run leaves no partial destination file. A directory copy is not atomic as a whole.

The method returns 1, or undef.

get

$remote->get($remote_path, $local)

Copy one regular guest file to $local on the host. The method reads the whole file, with MAX_TRANSFER_SIZE as the cap. It creates the parent directory of $local, and it writes the bytes atomically, mode 0644. So a failure leaves no partial local file. A $local that is an existing directory fails the call.

The method returns 1, or undef.

SEE ALSO

Fugu::SSH, Fugu::File, App::FuguVM::CLI, fuguvm(1)

AUTHOR

Dick Olsson <hi@senzilla.io>