The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Net::FullAuto - Fully Automate ANY Workload with *Persistent* SSH/SFTP from One Host

NOTE TO USERS

Please contact me or my team at the following email addresses -

  • Brian.Kelly@fullauto.com or team@fullauto.com

and let us know of any and all bugs, issues, problems, questions as well as suggestions for improvements to both the documentation and module itself. We will make every effort to get back to you quickly.

Update the module from CPAN *often* - as we anticipate adding documentation and fixing bugs and making improvements often.

Brian Kelly, March 9, 2016

SHELL SYNOPSIS - simple "Hello World"

  •    use Net::FullAuto;
       $localhost=connect_shell();
       ($stdout,$stderr,$exitcode)=$localhost->cmd("echo 'Hello World'");
       print $stdout;

SSH & SFTP COMBINED SYNOPSIS

  •    use Net::FullAuto;
    
       my $ip_or_hostname = $ARGV[0] || 'localhost';
       my $username       = $ARGV[1] || getlogin || getpwuid($<);
       my $identity_file  = $ARGV[2] || ''; # required unless password or
                                            # or key-based login
       my $password       = $ARGV[3] || ''; # required unless identity file
                                            # or key-based login
       my $remote_host_block={
    
          Label => 'Remote Host',
          Hostname => $ip_or_hostname,
          Login => $username,
          IdentityFile => $identity_file,  # can leave out if password or
                                           # or key-based login
          Password => $password,        # can leave out if identity file
                                        # or key-based login
                                     # password is CLEAR TEXT, which
                                     # is poor security. Consider
                                     # IdentityFile or key-based login
          #log => 1,
          #debug => 1,
          #quiet => 1,
    
       };
    
       my ($remote_host_handle,$error)=('','');   # Define and scope variables
    
       ($remote_host_handle,$error)=connect_secure($remote_host_block);
       die "Connect_SSH ERROR!: $error\n" if $error;
    
       my ($stdout,$stderr,$exitcode)=('','',''); # Define and scope variables
    
       ($stdout,$stderr,$exitcode)=
          $remote_host_handle->cmd('hostname'); # Run 'hostname' command in
       die $stderr if $stderr;                  # remote command line environment
    
       print "REMOTE HOSTNAME IS: $stdout\n";
    
       ($stdout,$stderr,$exitcode)=
          $remote_host_handle->cwd('/'); # Change working directory to the
       die $stderr if $stderr;           # root of the remote host
    
       ($stdout,$stderr,$exitcode)=$remote_host_handle->cmd('pwd');
       die $stderr if $stderr;
    
       print "REMOTE HOST CURRENT DIRECTORY VIA SSH IS: $stdout\n";
    
       ($stdout,$stderr,$exitcode)=$remote_host_handle->cwd('/');
       die $stderr if $stderr;
    
       my @stdout=$remote_host_handle->sftp('pwd');
       print "REMOTE HOST CURRENT DIRECTORY VIA SFTP IS: $stdout[1]<==\n";
    
       $remote_host_handle->lcd('~');
    
       @stdout=$remote_host_handle->sftp('!pwd');
    
       print "LOCAL HOST CURRENT DIRECTORY VIA SFTP IS: $stdout[1]<==\n";
    
       #$remote_host_handle->close(); # Use this -OR- cleanup method
       cleanup; # Use this routine for faster cleanup

SSH SYNOPSIS

  •    use Net::FullAuto;
    
       my $ip_or_hostname = $ARGV[0] || 'localhost';
       my $username       = $ARGV[1] || getlogin || getpwuid($<);
       my $identity_file  = $ARGV[2] || ''; # required unless password or
                                            # or key-based login
       my $password       = $ARGV[3] || ''; # required unless identity file
                                            # or key-based login
    
       my $remote_host_block={
    
          Label => 'Remote Host',
          Hostname => $ip_or_hostname,
          Login => $username,
          IdentityFile => $identity_file,  # can leave out if password or
                                           # or key-based login
          Password => $password,        # can leave out if identity file
                                        # or key-based login
                                     # password is CLEAR TEXT, which
                                     # is poor security. Consider
                                     # IdentityFile or key-based login
          #log => 1,
          #debug => 1,
          #quiet => 1,
    
       };
    
       my ($remote_host_handle,$error)=('','');   # Define and scope variables
    
       ($remote_host_handle,$error)=connect_ssh($remote_host_block);
       die "Connect_SSH ERROR!: $error\n" if $error;
    
       my ($stdout,$stderr,$exitcode)=('','',''); # Define and scope variables
    
       ($stdout,$stderr,$exitcode)=
          $remote_host_handle->cmd('hostname'); # Run 'hostname' command in
       die $stderr if $stderr;                  # remote command line environment
    
       print "REMOTE HOSTNAME IS: $stdout\n";
    
       ($stdout,$stderr,$exitcode)=
          $remote_host_handle->cwd('/'); # Change working directory to the
       die $stderr if $stderr;           # root of the remote host
    
       ($stdout,$stderr,$exitcode)=$remote_host_handle->cmd('pwd');
       die $stderr if $stderr;
    
       print "CURRENT DIRECTORY IS: $stdout\n";
    
       #$remote_host_handle->close(); # Use this -OR- cleanup method
       cleanup; # Use this routine for faster cleanup

SFTP SYNOPSIS

  •    use Net::FullAuto;
    
       my $ip_or_hostname = $ARGV[0] || 'localhost';
       my $username       = $ARGV[1] || getlogin || getpwuid($<);
       my $identity_file  = $ARGV[2] || ''; # required unless password or
                                            # or key-based login
       my $password       = $ARGV[3] || ''; # required unless identity file
                                            # or key-based login
    
       my $remote_host_block={
    
          Label => 'Remote Host',
          HostName => $ip_or_hostname,
          LoginID => $username,
          IdentityFile => $identity_file, # can leave out if password or
                                          # or key-based login
          Password => $password,       # can leave out if identity file
                                       # or key-based login
                                    # password is CLEAR TEXT, which
                                    # is poor security. Consider
                                    # IdentityFile or key-based login
          #log => 1,
          #debug => 1,
          #quiet => 1,
    
       };
    
       my ($remote_host_handle,$error)=connect_sftp($remote_host_block);
       die "Connect_SFTP ERROR!: $error\n" if $error;
    
       my ($stdout,$stderr)=('','',''); # Define and scope variables
    
       my @stdout=$remote_host_handle->cmd('pwd');
    
       print "REMOTE DIRECTORY IS: @stdout\n";
    
       ($stdout,$stderr)=$remote_host_handle->cwd('/');
       die $stderr if $stderr;
    
       @stdout=$remote_host_handle->cmd('pwd');
    
       print "CURRENT DIRECTORY IS: @stdout\n";
    
       #$remote_host_handle->close(); # Use this -OR- cleanup method
       cleanup; # Use this routine for faster cleanup

FullAuto Framework SYNOPSIS

    The FullAuto Framework utilizes the fa command line utility. Using the fa command instead of including Net::FullAuto in your scripts is recommended for better security when using password authentication with remote hosts/devices. Note that in the SSH SYNOPSIS above, there is a password => 'clear_text_password' element. The FullAuto Framework offers the ability to store such passwords encrypted, and will decrypt them only when actually submitting them to the remote host/device. Such passwords remain encrypted even when stored in memory.

DESCRIPTION

Net::FullAuto (aka FullAuto) is a Perl module and workload automation framework that transforms Perl into a true multi-host scripting language. It accomplishes this with multiple *PERSISTENT* SSH and SFTP connections to multiple hosts simultaneously. With FullAuto entire hosts are encapsulated in a single filehandle. Think of each filehandle as an always available SSH client (like PuTTY) and SFTP client (like WinSCP) that is available progammatically to the script.

The importance of PERSISTENT connections when attempting to programmatically control remote hosts cannot be over stated. Essentially, it means that FullAuto can automate EVERYTHING.

To see FullAuto in action, please download and explore the "Self Service Demonstration" at http://sourceforge.net/projects/fullauto. The demo contains an embedded YouTube video (https://youtu.be/gRwa1QoOS7M) explaining and showing the entire automated process of setting up a complex multi-host infrastructure in the Amazon EC2 Cloud. After watching or while watching the video, you can run the demo and standup your own cloud infrastructure in just a few minutes. The Hadoop demo is particularly interesting and timely given the recent explosion of BIG DATA and the need to access it more powerfully.

Imagine a scripting language that can turn an entire network of hosts into a virtual single host? This is precisely what FullAuto does.

FullAuto utilizes ssh and sftp (can also use telnet and ftp, though for security reasons, this is NOT recommended) to bring the command enviroments of any number of remote computers (Operating System of remote computer does not matter), together in one convenient scripting space. With FullAuto, you write code once, on one computer, and have it execute on multiple computers simultaneously, in an interactive dynamic fashion, as if the many computers were truly one.

How is FullAuto different from programs like Chef (http://www.chef.io) and Puppet (http://www.puppetlabs.com) and Ansible (http://www.ansible.com) and Salt (http://www.saltstack.com)? All of which assert the same ability and functionality?

Chef and Puppet and Salt require the use of agents on remote hosts. FullAuto has no such dependency as it is agent-less. It works against any ssh server implementation on any operating system. Ansible claims to be "agent-less" but actually has a dependency on the Python scripting language being available on the remote host, as well as requiring that the OpenSSH daemon on remote nodes be configured to utilize the ControlPersist feature. FullAuto has no such dependency (FullAuto does not even require Perl on the remote nodes), and if any manual terminal program or utility can connect to a device via ssh or sftp or scp or even telnet or ftp, FullAuto can connect as well - persistently.

FullAuto goes beyond these frameworks in its unique ability to PROXY-CHAIN multiple hosts with the same persistent connection capability. This means, without agents or any special configuration, FullAuto can proxy connect through any number of hosts and navigate multiple network segments to get you to the host and data you need - in REAL time! Real time interactive command channels and data feeds are the next "big thing", but till now have been incredibly difficult to setup, maintain and keep secure (not to mention "expensive"). With FullAuto, it is now possible for a single ssh process to proxy out through a firewall to a box in the DMZ, from that host go any distance accross the internet to another ssh host in another organization's DMZ, proxy through that host and through the firewall, and continue navigating proxies until the process arrives at the host, functionality and data it needs. For even additional security, the destination organization can also use FullAuto to host a real time "ssh service api" (similar to "web services" which is all rage now) and allow a distant process controlled and precise access to hosts and data just as is provided with web services - without the headache of "certificates", "https", "tokens", etc. - and with much better performance! (due to the simplicity and direct connect capability of FullAuto's architecture). In spite of all the "hoopla", web services are still predominantly "stateless" due to the architecture of the http protocol. FullAuto is state-FULL, insuring the most direct access to remote host functionality and data imaginable - regardless of application. And because FullAuto proxy connections are so lightweight, proxy hosts in DMZ environments can do double duty as "honey pots" - which themselves can be stood up, fully configured and fully managed automatically by FullAuto. The capabilities are almost limitless. (See the 'proxy' configuration element - below).

FullAuto can be run by a user in a Menu driven, interactive mode (using the Term::Menus module - also written by Brian Kelly), or via UNIX or Linux cron or Windows Scheduler or Cygwin cron in a fully automated (and secure) fashion.

Example: A user needs to pull data from a database, put it in a text file, zip and encrypt it, and then transfer that file to another computer on the other side of the world via the internet - in one step, and in a secure fashion.

Assume FullAuto is installed on computer one, the database is on computer two, and the remote computer in China is computer three. When the user starts the script using Net::FullAuto, FullAuto will connect via ssh and sftp (simultaneously) to computer two, and via sftp to computer three. Using a sql command utility on computer two, data can be extracted and piped to a text file on computer two. Then, FullAuto will run the command for a zip utility over ssh on computer two to compress the file. Next (assume the encryption software is on computer one) FullAuto will transfer this file to computer one, where it can be encrypted with licensed encryption software, and then finally, the encrypted file can be transferred to computer three via sftp. Email and pager software can be used for automated notification as well.

Example: The same process above needs to run at 2:00am unattended.

A script using FullAuto can be run via cron (or any other scheduler) to perform the same actions above without user involvement.

FullAuto is reliable and fault tolerant. Each individual command run on a remote computer returns to FullAuto STDOUT (output) and STDERR (error messages) and command exit codes. With these features, users and programmers can write code to essentially trap remote errors "locally" and respond with any number of error recovery approaches. Everything from sending an e-mail, to re-running the command, to switching remote computers and much more is available as error handling options. The only limits are the skills and ingenuity of the programmers and administrators using FullAuto. If FullAuto loses a connection to a remote host, automatic attempts will be made to re-connect seemlessly - with errors reported when the configured number of attempts fail.

Using FullAuto is easy. Connecting to a remote host is as easy as:

 my $remote_host_block={

      Label => 'Remote Host',
      Hostname => $ip_or_hostname,
      Login => $username,
      IdentityFile => $identity_file,  # can leave out if password or
                                       # or key-based login
      # Password => $password,         # can leave out if identity file
                                       # or key-based login
 };

 $computer_one=connect_ssh($remote_host_block);

Commands also are easy:

 ($stdout,$stderr,$exitcode)=$computer_one->cmd('ls -l');

And no cleanup is necessary - FullAuto handles this AUTOMATICALLY.

FullAuto is secure. It uses ssh and sftp for communication accross hosts and devices. FullAuto connections can be configured to use password-less key exchange. When FullAuto is used in "framework mode" with the fa executable, passwords can be stored encrypted in the Berkeley DB database.

For added security, and enhanced user functionality, FullAuto can be installed on UNIX and Linux based hosts to use setuid. (Windows/Cygwin does not support "setuid" - so this feature is not available on Windows computers. This is the only Windows FullAuto limitation.) With FullAuto setup to use setuid, users can be configured to run complex distributed processes in a secure fashion without the permissions actually needed by the remote (or even local) resources. This setup can allow users to run FullAuto processes without having access to the passwords controlling remote access, or for that matter, the code running those processes.

Reasons to Use this Module

You want to do everything you could do with other workload automation frameworks like Chef, Puppet, Anisble and Salt without the cost, overhead and resource requirements of those solutions. You want to go beyond those frameworks and set up real-time ssh proxy-chained interactive command channels and data feeds. You want to do managed file transfers via sftp or insecure ftp without having to impose requirements on owners of remote host servers. You want entire automated workloads encapsulated in a single "instruction set" that often is so tiny, you can easily attach it to an email. You want a solution that is as easy to install as install Net::FullAuto. You want the entire CPAN available for use in your "instruction sets". You want the true strengths of Perl and the Perl Community and features like Perl's unsurpassed regular expression functionality readily available. You want the flexibility of a serial scripting language, and the option to use modern OO programming with Moose. You want a solution that can work equally well on both UNIX/Linux and Windows operating syetems (FullAuto works on Windows within the Cygwin Linux layer for Windows evironment).

FullAuto is the SIMPLEST and most direct path to Full Automation (hence the name). That path is to make full use of trusted connectivity components already in widespread use on billions of devices the world over. SSH and SFTP are literally on every UNIX and Linux host in the world - and are both easily added to MS Windows. SSH and SFTP are used to connect to multiple network devices such as routers and switches. SSH and SFTP are a widely available means to connect to the Mainframe. All we EVER needed, was an automation solution that simply utilized this widespread access architecture already in place - AS IS, without requiring any special features or configuration. That solution is now a reality - and it's name is FullAuto.

And soon - there will be the FullAuto Web Service API that will enable anyone in any programming or scripting language to access and use the full power and functionality of FullAuto without having to know Perl at all.

CONNECT METHODS

%connection_info - hash to pass connection information to the following connect_<type> methods.

  •    %connection_info=(
    
          Label    => '<label_to_identify>',
          Hostname => '<hostname>', # Optional - need Hostname -or- IP Address
          IP       => '<ip address>',
          Login    => '<login id>',
          Use      => '<hostname or ip>, # When both Hostname and IP are listed,
                                         # use the specified first
          IdentityFile => '<path to file>', # Optional - RECOMMENDED (most secure)
          Password => '<password>', # Optional - *NOT* Recommended
          Log      => 1 | 0,     # Optional - Log output to FullAuto log
          Debug    => 1 | 0,     # Optional - Display debug info in output
          Quiet    => 1 | 0,     # Optional - Suppress output
          Timeout  => <seconds>, # Optional - Default is 90 seconds. Use to extend
                                 # time allowed to establish a connection
          Proxy    => <\%proxy_connection_info>, # Optional - use other host as a
                                                 # Proxy
     
       );

Label

  • Label => <label>,

    This element contains the label to identify the host.

Hostname

  • Hostname => <hostname>,

    This element contains the hostname of the host. It can also be encoded with an ip address as no validation is done.

IP

  • IP => <ip address>,

    This element contains the ip address of the host. It can also be encoded with a hostname as no validation is done.

Use

  • Use => <hostname|ip>,

    This element is used when both a hostname and ip address are included in %connection_info. It is used to indicate which to "use" first - hostname or ip address. FullAuto will use try the hostname first, if both hostname and ip address are configured, and Use is not used.

Password

  • Password => <password>,

    This element contains the password to use when logging in. You are stongly advised NOT to use this element, as clear text passwords are VERY insecure! Rather, use keys or identityfiles to authenticate against remote ssh/sftp servers.

IdentityFile

  • IdentityFile => <path to identityfile>,

    This element contains the path to the identityfile used to login to the remote host. If you are not already authenticating with this approach, you are STRONGLY encouraged to consider doing so. Clear text passwords are notoriously unsafe.

Log

  • Log => <1|0|path_to_logfile>,

    FullAuto has built in logging, but in order to use it, it must be explicitly turned on. It can be turned on and off in %connection_info using this element. A custom logfile and location can be indicated rather than a '1' which simply turns it on. The default location for FullAuto logs is /home/<user>/.fullauto/logs. FullAuto does NOT have one big log, but rather creates an entirely new log for each script/instruction set invocation. This is a typical example: FA9320d031716h14m13s19.log The naming convention of the file is as follows.

     FA        -> identifies this as a FullAuto log file
     9320      -> PID (Process ID) of the FullAuto process to which this log belongs
     d031716   -> Date of the log: March 17, 2016
     h14m13s19 -> h: hour 14 (2pm) m: 13 minutes s: 19 seconds

The Log element is used to dynamically turn on and off logging:

Turn on logging: Log => 1,

Turn off logging: Log => 0,

Turn on logging with custom name and path location: Log => <path_to_logfile>,

LogCount

  • Log => <number>,

    This element indicates how many logs to store. When the number is reached, FullAuto will delete the oldest.

Debug

  • Debug => <1|0>,

    This element instructs FullAuto to print all debug output to the screen.

Quiet

  • Quiet => <1|0>,

    This element instructs FullAuto suppress all output except Fatal Errors.

Timeout

  • Timeout => <1|0>,

    This element changes the default timeout value for any command that has no output. As long as a command has output, there is no timeout. The default timeout value is 90 seconds. It is advised that a stream of continuous output be provided if possible. Examine the options of commands you will be using, and use verbose or debug options if output is ordinarily light. When calling custom scripts - make sure those scripts provide output that comes continuously, or at least within the 90 second timeout.

Proxy

  • Proxy => <\%proxy_connection_info>,

connect_secure() - connect to remote host via ssh and sftp

  • ($ssh_host_object,$error) = connect_secure(\%connection_info);

    $ssh_host_object = connect_secure(\%connection_info);

Any connection errors will result in complete termination of the process.

The $secure_host_object represents both ssh AND sftp connections together in ONE
object.

The important thing to understand, is that there is no other code needed to connect to remote
hosts. Net::FullAuto handles all connection details, such as dynamic remote-prompt discovery,
AUTOMATICALLY. No need to define or even know what the remote prompt is. This feature
'alone' is a major departure from most other scriptable remote command and file transfer utilities.

connect_ssh() - connect to remote host via ssh

  • ($ssh_host_object,$error) = connect_ssh(\%connection_info);

    $ssh_host_object = connect_ssh(\%connection_info);

This method returns an ssh connection only - any attempt to use file-transfer features with this object
will throw an error.

Use this method if you don't need file-transfer capability in your process.

connect_sftp() - connect to remote host via sftp

  • ($sftp_host_object,$error) = connect_sftp(\%connection_info);

    $sftp_host_object = connect_sftp(\%connection_info);

This method returns an sftp connection only - any attempt to use remote command-line features with this object
will throw an error.

Use this method if you don't need remote command-line capability in your process.

connect_insecure() - connect to remote host via telnet & ftp

  • ($insecure_host_object,$error) = connect_insecure(\%connection_info);

All Connect Methods return a host object if connection is successful, or error message(s)
in the error variable if the method is requested to return a list. Otherwise, if the method is
requested to only return a scalar:

  • $insecure_host_object = connect_insecure(\%connection_info);

Any connection errors will result in complete termination of the process.

The $insecure_host_object represents both telnet AND ftp connections together in ONE
object.

  • THIS METHOD IS *NOT* RECOMMENDED for CONNECTING - use connect_secure() whenever possible.

connect_telnet() - connect to remote host via telnet

  • ($ssh_host_object,$error) = connect_telnet(\%connection_info);

    $ssh_host_object = connect_telnet(\%connection_info);

This method returns a telnet connection only - any attempt to use file-transfer features with this object
will throw an error.

Use this method if you don't need file-transfer capability in your process.

  • THIS METHOD IS *NOT* RECOMMENDED for CONNECTING - use connect_ssh() whenever possible.

connect_ftp() - connect to remote host via ftp

  • ($ftp_host_object,$error) = connect_ftp(\%connection_info);

    $ftp_host_object = connect_ftp(\%connection_info);

This method returns an ftp connection only - any attempt to use remote command-line features with this object
will throw an error.

Use this method if you don't need remote command-line capability in your process.

  • THIS METHOD IS *NOT* RECOMMENDED for CONNECTING - use connect_sftp() whenever possible.

connect_shell() - connect to local shell

  • ($shell_localhost_object,$error) = connect_shell();

    ($shell_localhost_object,$error) = connect_shell(\%connection_info);

    $shell_localhost_object = connect_shell();

    $shell_localhost_object = connect_shell(\%connection_info);

This method returns a local shell handle. When this connect method is used, a separate process is forked in memory and a local shell (currently only BASH is supported) is spawned within it. In this way, you can have any number of local shell processes running that each emulate a command line environment precisely as if it were a remote host handle. This is an extremely useful feature and allows you to run a number of local processes in their own protected environments in parallel. The one difference of note between a local process and a remote one, is that the \%connection_info hash is optional. With connect_shell(\%connection_info) the only elements of \%connection_info that are available are debug, quiet, and log.

Host Object Elements

A Host Object is in fact an ordinary Perl object in that is contains both elements and methods. The elements contain both one or two process handles, and descriptive metadata about the handle(s).

_hostlabel

  • $connect_secure_object->{_hostlabel} = [ 'Label','' ];

The _hostlabel element contains the label you assigned in the \%connection_info hash passed to the connect_<type>() method. Each object must have a unique label. If FullAuto detects that you are attempting to create a new object with a label already in use by another object, it will terminate with an error. The _hostlabel element is an array, and you may assign more than one label to an object.

$connect_secure_object-E{_hostlabel} = [ 'Label','Label Two' ];.

You can access the primary label at anytime with the following syntax:

$connect_secure_object->{_hostlabel}->[0];

_cmd_handle

  • $connect_secure_object->{_cmd_handle} = Net::Telnet=GLOB(0x8006c330);

    $connect_ssh_object->{_cmd_handle} = Net::Telnet=GLOB(0x8006c330);

The _cmd_handle element contains the process handle GLOB. This is a Net::Telnet handle as the Net::Telnet module from CPAN is used to actually connect spawn a local shell (bash) process, that is then used to launch SSH and SFTP sessions. Don't let the name "Net::Telnet" confuse you - when connect_secure() and other FullAuto secure connect methods are used, the actual clear text and insecure 'telnet' protocal is *NOT* being used! SSH and SFTP are being used instead. Net::Telnet can be used as a lightweight "Expect" and that is precisely how it is used in the internals of Net::FullAuto. As such, all the features and methods of Net::Telnet are available within this handle. There are times when it is very useful to access some of Net::Telnet's methods directly and bypass FullAuto's input and output manipulations. When doing so, you will have to account for the output artifacts that FullAuto handles for you, but there are occasions where this is desirable - especially when front-ending and automating interactive command line programs that prompt the user. Examples of this are provided later in the documentation. So just what does FullAuto provide that Net::Telnet does not? For starters, Net::Telnet requires you to know the prompt of each remote host you want to connect and interact with. This sounds like a simple requirement, but in actual practice, this requirement is a MAJOR headache. The truth is, prompts are very dynamic artifacts that change from host to host, shell to shell, user to user, and can and do change without notice. Prompt changes are one of the most common reasons automated workloads break! FullAuto dynamically discovers the prompt for you on login, eliminating this requirement altogether - and making your job of automating processes significantly easier. FullAuto enables you to access correct output, error output from STDERR, and command exit codes with each command sent. Net::Telnet alone does not provide this kind of advanced functionality. FullAuto automatically handles echo'd prompts and other telnet protocol line noise, relieving the user of having to deal with any of it. Many many users over the years have attempted to use Net::Telnet the way they CAN use FullAuto, without understanding and appreciating Net::Telnet's limitations and the actual knowledge and skill needed to use Net::Telnet successfully. The goal of the FullAuto project was to essentially remove nearly all of Net::Telnet's limitations, and allow users to automate workloads as they would intuitively expect they should be able to - like they would do it manually in PuTTY for instance, but programmatically instead. A user can successfully use FullAuto without needing a deep dive into the documentation, and without a big learning curve - unlike when trying to use Net::Telnet alone. FullAuto also provides process locking - a necessary feature when automating large and complex workloads.

Net::Telnet methods can be accessed in the following manner:

$connect_secure_object->{_cmd_handle}->print();

  • $connect_sftp_object->{_cmd_handle} = Net::Telnet=GLOB(0x8006c330);

When connecting via the connect_sftp() method, the resulting _cmd_handle element contains the command environment of the local sftp program only. This environment is very limited, with the command set comprising ls, put, get, cd, lcd, etc. One important feature of note however, is the escape to local command line feature which is accomplished with the exclamation point or 'bang' character. This does work as expected with this handle. For example, to get the hostname of the local host, this will work as expected:

$connect_sftp_object->cmd('!hostname');

_ftp_handle

  • $connect_secure_object->{_ftp_handle} = Net::Telnet=GLOB(0x8006c330);

This element exists only when connecting via the connect_secure() and connect_insecure() methods. It's needed with these methods because the _cmd_handle element contains an ssh or telnet or shell command environment. Otherwise, for the connect_sftp() and connect_ftp() methods, the ftp handle is accessed through the _cmd_handle element. An example of usage is the following:

$connect_secure_object->{_ftp_handle}->cmd('!hostname');

Also available is a Host Object Method called ftpcmd(). It can be used instead:

$connect_secure_object->ftpcmd('!hostname');

_cmd_type

  • $connect_secure_object->{_cmd_type} = 'type';

This element indicates what type of command connection exists in the connect_object. The possible values are 'ssh', 'telnet' and 'shell'.

_ftp_type

  • $connect_secure_object->{_ftp_type} = 'sftp|ftp';

This element indicates what type of file transfer connection (or method) exists in the connect_object. The possible values are 'ftp' and 'sftp'.

_connect

  • $connect_secure_object->{_connect} = 'connect_<type>';

This element indicates which connect_<type>() method was used to create the host object.

_work_dirs

  • $connect_secure_object->{_work_dirs} = \%work_dirs;

This element is used heavily by the FullAuto cwd() method. It is listed here for informational purposes, but it is NOT recommended that anyone modify these values directly.

_work_dirs -> _cwd

  • $connect_secure_object->{_work_dirs}->{_cwd} = cwd (current working directory in Unix format)

This element stores the current working directory in Unix format.

_work_dirs -> _pre

  • $connect_secure_object->{_work_dirs}->{_pre} = (previous working directory in Unix format)

This element stores the previous working directory in Unix format.

_work_dirs -> _tmp

  • $connect_secure_object->{_work_dirs}->{_tmp} = /tmp directory

This element stores the /tmp directory in Unix format.

_work_dirs -> _cwd_mswin

  • $connect_secure_object->{_work_dirs}->{_cwd_mswin} = cwd - current working directory

This element stores the current working directory in MS Windows format.

_work_dirs -> _pre_mswin

  • $connect_secure_object->{_work_dirs}->{_pre_mswin} = previous working directory

This element stores the previous working directory in MS Windows format.

_work_dirs -> _tmp_mswin

  • $connect_secure_object->{_work_dirs}->{_tmp_mswin} = temp directory

This element stores the temp directory in MS Windows format.

_hostname

  • $connect_secure_object->{_hostname} = hostname

This element indicates hostname of the remote host encapsulated in the host object. When connect_shell() is used, the hostname is the local host.

_ip

  • $connect_secure_object->{_ip} = ip address

This element indicates the ip address of the remote host encapsulated in the host object. When connect_shell() is used, the ip address is the local host.

_uname

  • $connect_secure_object->{_uname} = uname of remote host

This element indicates uname of the remote host encapsulated in the host object. When connect_shell() is used, the uname is from the local host.

_luname

  • $connect_secure_object->{_luname} = uname of local host

This element indicates uname of the local host encapsulated in the host object. When connect_shell() is used, the luname is the same as uname.

_cmd_pid

  • $connect_secure_object->{_cmd_pid} = process id of forked ssh or telnet program

This element indicates the process id of the forked ssh or telnet program encasulated in the host object. When connect_shell() is used, the _cmd_pid is the same as _sh_pid.

_sh_pid

  • $connect_secure_object->{_sh_pid} = process id of the shell within the ssh or telnet connection

This element indicates the process id of the shell within the ssh or telnet connection encasulated in the host object. When connect_shell() is used, the _sh_pid is the same as _cmd_pid.

_shell

  • $connect_secure_object->{_shell} = remote shell

This element indicates which shell is being used within the ssh or telnet connection encasulated in the host object.

_homedir

  • $connect_secure_object->{_homedir} = home directory on remote host

This element indicates the home directory on the remote host.

_cygdrive

  • $connect_secure_object->{_cygdrive} = cygdrive value when remote environment is Cygwin

This element contains the cygdrive value when remote environment is Cygwin.

_cygdrive_regex

  • $connect_secure_object->{_cygdrive_regex} = regular expression to test for Cygwin paths

This element contains a regular expression to test output for Cygwin style path construction.

Host Object Methods

cmd() - run ssh, telnet or local shell command line commands on the targeted (remote or local) host

  • ($cmd_output,$error,$exitcode) = $connect_secure_object->cmd('<command>');

There is a cmd method available with every connect_object. For all objects that contain both remote command-line and file-transfer connections, the cmd method gives access ONLY to the remote command-line feature. To access the ftp cmd options, use the following syntax:

  • ($ftp_cmd_output,$error) = $connect_secure_object->{_ftp_handle}->cmd('<ftp command>');

For all objects that contain only an sftp or ftp connection, the cmd method gives access ONLY to the sftp and ftp command-line feature

($sftp_cmd_output,$error,$exitcode) = $connect_sftp_object->cmd('<ftp command>').

  • =================================================================

The cmd() method is truly the "centerpiece" of FullAuto. This is the one method you will use at least 80% of the time, or more. It is as close to a full "command environment" encapsulated in one handle as could be imagined. Literally, just about anything you could do manually with a shell terminal or program like PuTTY, you can do just as easily with this method. The most important attribute of this method, and of FullAuto itself, is its use of a *PERSISTENT* connection to the remote host. Because of the successful implementation of this approach, STATE is persisted among invocations of this method throughout the life cycle of the "instruction set". In simpler terms, if you change a directory IT STAYS CHANGED. If you add or modify an environment variable, IT STAYS MODIFIED for the next call of the cmd() method. If you do a su or sudo su, the session will remain persistent until you exit. (One caveat - su usage is the one time you will have to account for the prompt and set it yourself). It is this single attribute (persistent connection) that suddenly makes workload automation EASY.

NOTE: While this does work:

($ssh_cmd_output,$error,$exitcode) = $connect_secure_object->cmd('cd /etc')

It is better to use the FullAuto cwd() method for all file system navigation. This is because it will keep track of history for both command and (s)ftp environments, and keep both environments synchronized.

($ssh_cmd_output,$error,$exitcode) = $connect_secure_object->cwd('/etc')

The cmd() method has two other optional arguments

timeout

The default timeout value for the cmd() method is 90 seconds. You can change this by specifiying a timeout value parameter in seconds:

The timeout setting is important only with long running commands that do not produce output. As long as a command produces output, the timeout value will not come into play. The command can run literally forever - as long as there is continuous output. It is advised that if you have any control over the output of the command, to enable a sufficient amount of output to avoid having to use the timeout argument. If the command has a "verbose" option, consider activating it. The tradeoff is that supplying output rather than a timeout value increases reliability, and allows the cmd('<command>') to end whenever it needs to - regardless of how long it takes. However, output is "expensive" and to get the quickest return time, using a timeout might produce faster results. But know that you are intentionally choosing speed over reliability, and speed always carries an increased risk.

($cmd_output,$error,$exitcode) = $connect_secure_object->cmd('<command>',<seconds>)

__display__

This parameter turns on sending all STDOUT to the screen in real time as the <command> runs. Without setting this, all STDOUT is sent only to the $cmd_output variable (when set). '__display__' is not position dependent after the <command> parameter (which needs to be the first parameter.) It can appear before any timeout value, or after. '__display__' is a very useful feature for debugging, as well as for processes that human eyes will be anxiously watching closely. Output is "comforting", heals "blank screen anxiety" and allows stakeholders to relax and know that things are working. However, printing output to the screen has costs and slows down processing - significantly. So unless you really need to see output, it's best not to set this.

($cmd_output,$error,$exitcode) = $connect_secure_object->cmd('<command>','__display__')

print() - convenience method for invoking Net::Telnet's print() method.

  • $connect_secure_object->print('<command>');

Used in combination with the fetch() method (see fetch() below), it becomes easy to automate interactive command utilities. print() simply sends commands staight to the socket unmodified and unverified via the Net::Telnet handle that FullAuto uses internally. It is a convenience method that saves from having to invoke it like this instead:

$connect_secure_object->{_cmd_handle}->print(<command>);

cmd_raw() - run ssh or telnet or local shell command without input validation and output parsing.

  • $cmd_output = cmd_raw($connect_secure_object,'<command>');

There are occasions where a command simply has too many special symbols, quotes, escapes, etc, that no amount of manipulation can get it through FullAuto's input validation correctly. In these cases, sending it through the method and bypassing all of FullAuto's special handling logic, can occasionally produce the desired result. Usually this will work when there is no output, or the output can be discarded. For the most relaible and robust processing, always try to use cmd() as much as possible, savng as a method of last resort. Example of actual command that only works through cmd_raw():

cmd_raw($connect_secure_object,"sed -i 's/\\(^Session$\\\)/ \\1/' $file_to_modify");

sftpcmd() - run sftp commands on the targeted (remote or local) host

This method is useful when Host Object contains both a ssh (or telnet) and (s)ftp connection.

($sftp_cmd_output,$error) = $connect_secure_object->sftpcmd('<sftp command>')

Uses same timeout and __display__ parameters as the cmd() method.

sftp() - run sftp commands on the targeted (remote or local) host

Same as sftpcmd above, but a little shorter (and less descriptive) method name.

($sftp_cmd_output,$error) = $connect_secure_object->sftp('<sftp command>')

Uses same timeout and __display__ parameters as the cmd() method.

ftpcmd() - run ftp commands on the targeted (remote or local) host

Same as sftpcmd above, but for ftp.

($ftp_cmd_output,$error) = $connect_secure_object->ftpcmd('<ftp command>')

Uses same timeout and __display__ parameters as the cmd() method.

ftp() - run ftp commands on the targeted (remote or local) host

Same as ftpcmd above, but a little shorter (and less descriptive) method name.

($ftp_cmd_output,$error) = $connect_secure_object->ftp('<ftp command>')

Uses same timeout and __display__ parameters as the cmd() method.

cwd() - change working directory for both command (ssh or telnet) and (s)ftp connections simultaneously

  • ($sftp_cmd_output,$error) = $connect_secure_object->cwd('<path>');

    ($sftp_cmd_output,$error) = $connect_secure_object->cwd('-');

    ($sftp_cmd_output,$error) = $connect_secure_object->cwd('~');

    ($sftp_cmd_output,$error) = $connect_secure_object->cwd('../..');

Unlike any other workload automation framework the author of FullAuto is aware of, this one feature is truly unique to FullAuto. One of the biggest problems there is when a connection is not persistent, is maintaining "state" between commands. When the connection is not persistent, the environment must be updated along with each command sent. This is huge burden on developers, is resource intensive, and makes workload automation extraordinarly complex and fragile. This is precisely why most workload automation software like 'Chef', 'Puppet', 'Salt' and others are Client-Server architecture - requiring agents on all remote hosts/nodes. 'Ansible' is dependent on the "ControlPersist" feature of OpenSSH. The problem with that, is not all SSH servers are OpenSSH, or a recent version of OpenSSH. FullAuto has NO such dependency and will work with ANY SSH server or version of SSH server known to the author. Also, (s)ftp servers cwd and lcd commands do not support common Unix/Linux shell navigation syntax such as '~' for one button access to the user's home directory. But when using the cwd() method supplied with FullAuto, this syntax is fully supported for both the command and (s)ftp environments. The importance of this becomes apparent when you start coding up large and complex instruction sets. The ability to use one single method to change the path location in both environments simultaneously, and to navigate PRECISELY as you would as if you were using a manual terminal like PuTTY, or within any Unix/Linux shell environment, makes it easy for ANYONE who works with these tools regularly to use FullAuto successfully without needing advanced programming language skills or any significant learning curve.

($cmd_output,$error,$exitcode) = $connect_secure_object->cwd('src')
($cmd_output,$error,$exitcode) = $connect_secure_object->cmd('make install','__display__')
($cmd_output,$error,$exitcode) = $connect_secure_object->cwd('-')

lcd()

  • $connect_secure_object->lcd('<path>');

The lcd() method is a convenience method to perform local change directory on the (s)ftp handle without having to do this:

($cmd_output,$error) = $connect_secure_object->{_ftp_handle}->cmd('lcd path')

Also, it supports Unix navigation syntax like '~' for navigating to the home directory, etc.

put()

  • $connect_secure_object->put('<file>');

The put() method is a convenience method to perform (s)ftp put on the (s)ftp handle without having to do this:

($cmd_output,$error) = $connect_secure_object->{_ftp_handle}->cmd('put file')

get()

  • $connect_secure_object->get('<file>');

The get() method is a convenience method to perform (s)ftp get on the (s)ftp handle without having to do this:

($cmd_output,$error) = $connect_secure_object->{_ftp_handle}->cmd('get file')

prompt() - convenience method for invoking Net::Telnet's prompt() method.

  • $connect_secure_object->prompt();

This is convenience method for accessing the Net::Telnet prompt() method. It saves from having to invoke it like this instead:

$connect_secure_object->{_cmd_handle}->prompt();

FullAuto Methods

fetch()

  • $output = fetch($connect_secure_object);;

The fetch() method is used to retrieve raw output straight from the socket when a command is sent via Net::Telnet's print() method.

The following is typical usage of fetch(). In this example, responses to installation options are sent automatically to an interactive MySQL command line utility used to perform a secure install of a MySQL database:

  •    $connect_secure_object->print('sudo mysql_secure_installation');
             # Using Net::Telnet's print() method
       my $prompt=substr($connect_secure_object->prompt(),1,-1);
             # Using Net::Telnet's prompt() method to retrieve shell prompt
       while (1==1) {
          my $output=fetch($connect_secure_object);
          last if $output=~/$prompt/;
          print $output;
          if (-1<index $output,'root (enter for none):') {
             $connect_secure_object->print();
             next;
          } elsif (-1<index $output,'Set root password? [Y/n]') {
             $connect_secure_object->print('n');
             next;
          } elsif (-1<index $output,'Remove anonymous users? [Y/n]') {
             $connect_secure_object->print('Y');
             next;
          } elsif (-1<index $output,'Disallow root login remotely? [Y/n]') {
             $connect_secure_object->print('Y');
             next;
          } elsif (-1<index $output,
                'Remove test database and access to it? [Y/n]') {
             $connect_secure_object->print('Y');
             next;
          } elsif (-1<index $output,'Reload privilege tables now? [Y/n]') {
             $connect_secure_object->print('Y');
             next;
          }
       }

log()

  • log('<1|0|path_to_logfile>');

    FullAuto has built in logging, but in order to use it, it must be explicitly turned on. It can be turned on and off anywhere in the script/instruction set using this method. A custom logfile and location can be indicated rather than a '1' which simply turns it on. The default location for FullAuto logs is /home/<user>/.fullauto/logs. FullAuto does NOT have one big log, but rather creates an entirely new log for each script/instruction set invocation. This is a typical example: FA9320d031716h14m13s19.log The naming convention of the file is as follows.

     FA        -> identifies this as a FullAuto log file
     9320      -> PID (Process ID) of the FullAuto process for which this log belongs
     d031716   -> Date of the log: March 17, 2016
     h14m13s19 -> h: hour 14 (2pm) m: 13 minutes s: 19 seconds

The log() method is used to dynamically turn on and off logging:

Turn on logging: log(1);

Turn off logging: log(0);

Turn on logging with custom name and path location: log(<path_to_logfile>);

ls_parse()

  • ($size,$timestamp,$file_or_dir)=ls_parse($line);;

The ls_parse() method was created because of the frequent need to derive size, timestand and file and directory names from ls -l output from remote hosts.

The following is typical output from the ls -l command; followed by an example of how ls_parse() can be used:

  •  ($stdout,$stderr)=$connect_secure_object->cmd('ls -l')
    
     ---------------------------------------------------------------------------
     total 166
     drwxrwxrwx+ 1 KB06606       Domain Users     0 Mar 10 10:26 FullAuto
     -rw-r--r--  1 KB06606-admin Domain Users 53383 Mar 14 08:35 FullAuto.html
     -rwxr-xr-x  1 KB06606       Domain Users 47560 Mar 13 18:47 FullAuto.pm
     -rwxr-xr-x  1 KB06606-admin Domain Users 46742 Mar 13 12:22 FullAuto.pm.bak
     -rw-r--r--  1 KB06606-admin Domain Users     3 Mar 22  2015 pod2htmd.tmp
     -rw-r--r--  1 KB06606-admin Domain Users     3 Mar 22  2015 pod2htmi.tmp
     -rw-r--r--  1 KB06606-admin Domain Users  1784 Jun 14  2015 test.pl
     -rwxrwxrwx  1 KB06606-admin Domain Users  1327 Jul 18  2015 tsftp.pl
     ---------------------------------------------------------------------------
    
     my ($size,$timestamp,$file_or_dir)=('','','');
     foreach my $line (split /\n/, $stdout) {
    
        ($size,$timestamp,$file_or_dir)=ls_parse($line);
    
     }

acquire_fa_lock() - acquire a FullAuto lock.

  • acquire_fa_lock(\%lock_config);

Workload automation of any complexity will quickly introduce the need for a powerful locking mechanism. FullAuto uses locking internally, and provides that same mechanism for customized use in scripts and "instruction sets". Here is a short list of occasions when a locking mechanism is needed:

* You have a script using FullAuto that runs on a scheduler. Occasionally a new instance starts before the old instance has completed.

* You have an "instruction set" that is written to run in parallel, but you have a need to limit the number of FullAuto processes running in memory at any one time.

* You want to do Managed File Transfers, and have a number of FullAuto worker processes emptying an outbound folder of files on a remote SFTP host. You want only one process working on any particular file.

* You need multiple processes to append to a file on a remote server, and because it's remote, local file locking mechanisms are not available.

* You want to insure only one FullAuto process connects to a particular remote host at any given time.

* Other scenarios too numerous to list.

FullAuto uses Oracle BerkeleyDB as it's internal locking store, because of it's speed, portablility, and maturity. BerkeleyDB has very robust deadlock protection that is critically important for workload automation of any complexity and sensitivity.

A workload of any complexity will likely require more than one kind of lock. Within a single workload there may be a need for 3, 4 or more different kinds of locks for different needs. In the EXAMPLES section is a sample Managed File Transfer workload that uses 3 different types of locks.

%lock_config - hash to pass config information to acquire_fa_lock();

  •  my %lock_config = (
    
         # Optional User Defined
    
         FullAuto_Lock_ID => "$filename",
         Lock_Description => "File Lock",
         MaxNumberAllowed => 1,
         KillAfterSeconds => 1600,
         Enable_This_Lock => 1,
         Wait_For_NewLock => 0,
         PollingMilliSecs => 500,
         Return_If_Locked => 1,
    
         # AUTO POPULATED
    
         UserName         => 'username',
         Logfile          => 'logfile if activated',
         FullAuto_Proc_ID => 'fullauto process id',
         FA_Proc_Launched => [time fullauto launched],
         TimeLockAcquired => 'time this lock was acquired',
    
     );

FullAuto_Lock_ID

  • FullAuto_Lock_ID => '<id>',

This is the name of a FullAuto lock. The FullAuto_Lock_ID is how FullAuto identifies a lock, and uses this name to lookup the lock in the BerkeleyDB database.

Lock_Description

  • Lock_Description => '<description>',

This is an element where an optional lock description would be placed.

MaxNumberAllowed

  • MaxNumberAllowed => '<number>',

This element defines the maximum number of locks that can be created by all FullAuto processes configured to use locks sharing the same FullAuto_Lock_ID.

KillAfterSeconds

  • KillAfterSeconds => '<seconds>',

In a perfect world, this feature would not be needed. But in this world, "hangs" happen. For long-running workloads that are spawned by a scheduler or recurrent event of some sort, hung or orphaned processes can built up in memory, and eventually impair the performance of the host. To insure this doesn't happen, the KillAfterSeconds element can be used. It is recommended that the number of seconds be something in the order of 10 times the expected duration of a successfully completed workload. The notion being that a workload that is 10 times older than expected is "dead" and needs to terminated. This element instructs FullAuto to both delete the lock, and kill the process group associated with it. Use this feature with caution.

Enable_This_Lock

  • Enable_This_Lock => '0|1',

This element is a simple binary that tells FullAuto whether the lock is enabled or not. This is useful for temporarily disabling a particular lock with only a simple toggle. '1' is enabled, and '0' is not.

Wait_For_NewLock

  • Wait_For_NewLock => '<seconds>', '0' means do not wait at all. The default is '60' seconds.

This element defines how long a FullAuto process that encounters a lock, and cannot get a new one because no locks are available (defined with MaxNumberAllowed), should wait to get a new one, before it terminates. This is important for long-running processes because of potentially long and resource intensive startup and initialization. Performance is improved if a process that takes 2 minutes to start and initialize, can instead wait up to the 2 minutes to get a lock from a process that no longer needs it, rather than start from scratch. '0' instructs FullAuto not to wait at all. The default is '60' seconds.

PollingMilliSecs

  • PollingMilliSecs => '<milliseconds<gt',>

When a FullAuto process encounters a lock, it polls the BerkeleyDB database for the availability of a particular lock at a configured interval. The default interval is '500' milliseconds.

Return_If_Locked

  • Return_If_Locked => '<0|1>',

This element instructs FullAuto to either terminate when it encounters a lock, or return to the script or "instruction set". '1' means return, '0' means terminate. The default is to terminate any FullAuto processes that encounter the lock, and exceed the Wait_For_Newlock setting - if any. This is particularly useful when locking files that will be removed by other processes upon completion of a transfer or other operation. In these cases, when a FullAuto process encounters a lock on a file, it can return from the acquire_fa_lock() method and loop and attempt to work with another file that is not locked by another FullAuto process.

AUTO POPULATED

  •  UserName         => 'username',
     Logfile          => 'logfile if activated',
     FullAuto_Proc_ID => 'fullauto process id',
     FA_Proc_Launched => [time fullauto launched],
     TimeLockAcquired => 'time this lock was acquired',

The elements above are "auto populated" - meaning FullAuto adds them automatically to the lock_config. These are listed for informational purposes, and should NOT be defined by the user.

release_fa_lock() - release a FullAuto lock.

  • release_fa_lock('<FullAuto_Lock_ID>');

EXAMPLES

AUTHOR

Brian M. Kelly <Brian.Kelly@fullauto.com>

DISCLAIMER

 Beware that this software is provided "as is", and comes with no warranty
 of any kind, either express or implied. If you use the contents of this
 distribution, you do so at your own risk, and you agree to free the
 author(s) of any consequences arising from such use, either intended or
 otherwise.

COPYRIGHT

Copyright (C) 2000-2016

by Brian M. Kelly.

This program is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License. (http://www.gnu.org/licenses/agpl.html).