Tuesday, 23 April 2013

When to use Expect scripting and when to avoid it

If you are not familiar with "expect", it is a script/programming language that is designed to automate interactive processes.

For example, suppose you need to install a piece of software on many UNIX/Linux servers. The installation program runs from the command line, but must be run interactively. When run, it interactively asks the user for several pieces of information, and then installs.

With expect, you could write a script to automate this task so that when the installation program prompts for information expect supplies the information, essentially simulating a user and automating the task.

Expect allows you to turn a normally interactive-only process in to a completely non-interactive, automated task.

The author of the expect language, Don Libes, wrote the definitive book on expect.   The book is called "Exploring Expect" by O'Reilly.   I would highly recommend the book to anyone wanting to learn expect.


In this posting I will cover when you should use expect and when you should avoid it.

When approaching a problem, my first rule of thumb when it comes to expect is to avoid using expect unless it is the only solution.

Why?  Expect is an amazing tool, but can be complicated to use and very fragile.  The basic premise of expect is to set it up to look for certain strings of text ("expect"ing them), and when it sees certain text, respond in a certain way.

For example, you could write a script that expects the text "Specify directory to install application to:  " and when it sees this, type back in "/opt/software/".However, if in the next version of the software the text of the installer changes slightly (i.e. "Specify directory location to install application to: ") , your expect program will no longer see what it is looking for and will fail to work.   If there is a different way to get something done other than using an expect script then it is usually a better option in my experience.

It would be possible to write an expect program to automate opening vi, editing the file, and then saving and exiting vi.   But it would be much easier and more reliable to use a tool such as sed, awk, perl, etc.  to edit the file.   Make sure you are using the right tool for the job.

My second rule of thumb is to not  use expect to automate tasks that deal with passwords.  When you look around for expect information and examples, a lot of them deal with automating things like SSH, SFTP, SCP, etc.   For example, the Wikipedia page on Expect lists 4 example scripts for using expect.   They all deal with automating logging in to a service with password authentication (telnet, ftp, sftp, and ssh).

I would not recommend using expect to automate anything like this.  There is a very good reason why tools like SFTP and SSH don't allow you to script using a password without a tool like expect:   It is a very bad idea!   The first problem is you generally need to include the clear text password in your expect script.  If anyone gets access to the script, they have access to the password as well.

The second big problem when using expect with passwords is the risk that expect will "type" in the password at the wrong time.  For example, if you have a expect script setup to expect certain things, and then send the password, and something goes wrong, the script might send the password too early or too late.

The password might then end up somewhere inappropriate or visible to other users or in a shell history file.   The bottom line is, if you need to automate running remote commands or copying files around, use SSH keys.   SSH keys are so much safer than passwords for a variety of reasons, and there are several things you can do to make them a good option for automated tasks.

If you MUST use expect to automate a password related task, one method to help the situation would be to have the expect  script prompt you for the password when beginning the task and have the user type it in each time.  This way the password is not stored in the script file.

Another password related example of what NOT to do with expect:  automate changing passwords.   Expect even includes an example script with it named "passmass" that will change your password on multiple servers.   From a security perspective I think this is a really, really bad idea for the reasons I specified in the previous paragraph.

The right tool for this kind of job is the "chpasswd" command.  The chpasswd utility even allows you to specify a password hash ("encrypted" password) when setting a users password to make it more secure to script.

chpasswd isn't perfect, but in my opinion it is a much better option than expect when it comes to automating changing passwords.

So when should you consider using expect?   

You should think about expect anytime you have a manual task that needs to be repeated and that only provides a interactive interface to the user.

We already covered the example of a interactive software installation program.

Another example is any propriety software that forces you to go through a text based menu to do something.   Using expect, you could write a script to navigate the menu and automate the task.

Another extremely good way to use expect is when you need to automate an appliance or other closed system that doesn't have the ability to be scripted.

To do this, you use expect on a Linux/UNIX machine to connect to the appliance or closed system, and then complete a task.

For example, you could write an expect script that would connect to a Cisco switch and run a series of commands on the switch.

Expect is also a good option when creating test cases.   If you need to routinely test software functionality then expect might make your life easier.

You can also use expect to not fully automate tasks, but just assist with manual tasks.   This is because expect allows you to partially automate tasks while still allowing parts to be manual completed by a real person.

An example of this is the AIX command "mkdvd" which burns mksysb images on to a DVD.

When you run this command it writes the first DVD, and then if needed it will prompt you to insert additional DVD's.

With expect, you could write a script that would email you or page you whenever it was time to put in the next DVD or when the mkdvd command was completed.  This script needs to be customized with 2 command lines to email you/page you.
#!/usr/bin/expect --

#Notify you when mkdvd needs another DVD inserted and when completed.
#Specify mkdvd command line as argument to this script.
#For example, ./mkdvdnotify mkdvd -d /dev/cd0 -m /mksysb .....
set timeout -1
puts "Running command:  $argv"
eval spawn $argv

while true {
    expect {
        "The backup will require an additional CD or DVD" {
            exec ##Put command line here to email you/page you that we need another DVD
            puts "Need to insert additional CD/DVD"
            interact "\r" return
            send "\r"
        }
        eof {
            exec ##Put command line here to email you/page you that mksysb is done
            puts "mksysb command completed"
            break
        }
    }
}
This mkdvd expect script helps with a manual process and this is not something you could do without a tool like expect.

Please post comments with some creative examples of when you have used expect, or horror stories of other people using expect when they shouldn't have :)

0 blogger-disqus:

Post a comment