views:

2889

answers:

5

I made a Bash script which uses an expect script to automate ssh logins.The script connects to multiple servers and runs some commands. The bash script prompts for login credentials once.

I want to incorporate a feature wherein the script terminates if the login fails for the first server to avoid the script checking for next servers resulting in the user account getting locked. The account lockout happens for 3 consecutive login failures and the number of server the script tries to connect is more than 3.

This is the snippet in the bash script which calls the expect script.

countu=0
for servername in $(cat $linux_host_list)
do
./script.expect $LUSERNAME $LPASS $servername Linux >> linux_log_file.txt & < /dev/null
let countl=countl+1
done

and here is the expect script (script.expect) snippet

#!/usr/bin/expect -f
set timeout 30
set username [lindex $argv 0]
set SPASS [lindex $argv 1]
set servername [lindex $argv 2]
set case [lindex $argv 3]
set prompt "(%|#|\\$|%\]) $"
switch $case {
    Linux {
        log_user 0
        spawn ssh -o StrictHostKeyChecking=no $username@$servername
        expect  {
            "assword:" {
                send "$SPASS\r"
                expect -re "$prompt"
            }
            expect -re "$prompt"
        }
        send "sudo su -\r"
        expect {
            "assword:" { send "$SPASS\r" }
        }
        expect -re "$prompt"
        log_user 1
        send "opcagt -status ; opctemplate -l ; cat watch.cf 2> /dev/null\r"
        expect -re "$prompt"
        log_user 0
        send "exit\r"
        expect -re "$prompt"
        log_user 1
    }

I tried grabbing the bash command output ($?) assuming that the bash command would return a non zero value if login fails for incorrect password in the expect script but that did not work out. Any suggestions would be much appreciated.

A: 

You should seriously take a look at Fabric.

iElectric
Honestly, I'd be hesitant to move to anything over Expect. Expect has been, for many years, one of the premier tools to automate system tasks that don't expect to be automated. It does a number of things that other such tools really can't compare to (such as it's ability to simulate a tty/user nearly perfectly). That's not to say Fabric isn't great, as I don't know anything about it... Just that Expect has some very big shoes to fill.
RHSeeger
I was suggesting this only because Fabric is just made for such tasks. No harm!
iElectric
Fabric looks cool, thanks for sharing.
pyrony
A: 

Hi

I am not much into scripting and all, thus I cannot write the exact steps or script to prove what I got in mind - kindly excuse

I just hope my suggestion helps

Well, I read that bash provides for a thing called as exit status

An exit status is a status of 0 for true and 1 or anything else for false

You can see this by executing a command and then checking its exit status by typing "echo $?"

What I suggest is when you try to ssh into one server and authentication fails, there shall be an exit status of something other than 0

Getting an if-then-else loop here and checking the status for 0 for execution of script and any other value to exit the script totally with a suitable error message

I sincerely hope that this helps

Regards

amRit

If you read my question,I said that I have already tried that ($?) but that didn't work out.
Sharjeel Sayed
+1  A: 

For error checking in an expect script, there's a decent example at http://systeminetwork.com/article/handle-errors-expect-scripts

What you should do is something like this:

proc do_exit {msg} {
    puts stderr $msg
    exit 1
}

switch -exact -- $case {
    Linux {
        spawn ssh ...
        expect {
            -re {assword: $} {
                send -- "$SPASS\r"
                exp_continue 
                # remain in this expect block and look for the next matching pattern
            }
            "some message about incorrect password" {
                do_exit "incorrect password"
            }
            timeout {do_exit "timed out waiting for prompt"}
            default {do_exit "something else happened"}
            -re $prompt
        }
        # ... rest of your script
    }
}

I assume you don't need to know about the exit status of the "opcagt ..." series of commands (you just want to see the contents of the watch.cf file. If you do care, you'll need to get the shell to tell you:

send -- "opcagt -status 2>&1 || echo "non-zero return from opcagt: $?"
expect {
    "non-zero return" { handle error and exit? }
    -re $prompt
}
# ... continue
glenn jackman
A: 

You're running the expect scripts in the background (&), so you can't have the results of the first one before continuing.

The way your expect script is written, it'll get a 30 second timeout at the second password prompt if the first password fails. Instead, you could do an expect alternative, to see if you get another assword prompt, and exit immediately.

Then change the shell script to not put the expect calls in the background, instead capture the output with $? and test it.

Douglas Leeder
A: 

The section:

    expect  {
        "assword:" {
            send "$SPASS\r"
            expect -re "$prompt"
        }
        expect -re "$prompt"
    }

Looks highly suspicious to me. In particular, I really would expect that to cause things to become confused. A more idiomatic way of writing that would be:

    expect  {
        "assword:" {
            send "$SPASS\r"
            exp_continue
        }
        -re "$prompt"
    }
Donal Fellows