Delay between two expect in TCL - tcl

I am writing a script to automate the ambari server installation.
I have created on tcl script to automate ambari-server setup. My issue is at one place it downloads and installs jdk and that step takes a little time and meanwhile the other sends under other expects starts popping up on screen and screws up all the installation.
My Script:
#!/usr/bin/expect
spawn sudo ambari-server setup
expect "OK to continue"
send "y\r"
expect "Customize user account for ambari-server daemon"
send "y\r"
expect "Enter user account for ambari-server daemon (root):"
send "root\r"
expect "Enter choice (1):"
send "1\r"
expect "Do you accept the Oracle Binary Code License Agreement"
send "y\r"
expect"Enter advanced database configuration"
send "y\r"
expect "Enter choice (1):"
send "3\r"
expect "Hostname (localhost):"
send "localhost\r"
expect "Port (3306):"
send "3306\r"
expect "Database name (ambari):"
send "ambari\r"
expect "Username (ambari):"
send "ambari\r"
expect "Enter Database Password (bigdata):"
send "password\r"
expect "Proceed with configuring remote database connection properties"
send "y\r"
after accepting Oracle Binary Code License Agreement it downloads and installs jdk and in that duration it starts taking send of next excepts.
Can someone suggest me how to stop the execution of an except while the previous one is still running.
i did try to use after and sleep to try something but it did not work.
Thanks

altering the timeout is the right way to do it. I'd write:
expect "Do you accept the Oracle Binary Code License Agreement"
set old_timeout $timeout ;# remember the previous value
set timeout -1 ;# disable the timeout
send "y\r"
expect"Enter advanced database configuration"
set timeout $old_timeout ;# restore the timeout
send "y\r"

Your code is missing handlers for what to do if an expected string is not received. It would be good style to add those. Otherwise the script will just continue if the string was not received within the allotted time (10 seconds by default), as you have seen.
To use a different timeout for one expect command, you can simply use the -timeout option. For example to allow 10 minutes for the jdk to install:
expect -timeout 600 "Enter advanced database configuration"
send "y\r"
And with an added handler in case of failure:
expect {
-timeout 600
"Enter advanced database configuration" {
send "y\r"
}
default {
error "jdk failed to install in time"
}
}

Related

expect garbage before prompt

I try to connect to my router using ssh in order to automatically extract some logs from it.
I developed this code below :
#!/usr/bin/expect -f
spawn ssh root#192.168.1.1
expect "Are you sure you want to"
send -- "yes\r"
expect "password"
send -- "root\r"
expect "\#"
send -- "ls\r"
expect "\#"
the problem is I expected a garbage before the prompt in the output log.
spawn ssh root#192.168.1.1
The authenticity of host '192.168.1.1 (192.168.1.1)' can't be established.
RSA key fingerprint is SHA256:6aeE74qXMeQzg0SGJBZMIa0HFQ5HJrNqE5f3XZ6Irds.
Are you sure you want to continue connecting (yes/no)? yes
Failed to add the host to the list of known hosts (/home/amin/.ssh/known_hosts).
root#192.168.1.1's password:
BusyBox v1.30.1 () built-in shell (ash)
OpenWrt Version: ALPHA
OpenWrt base: 19.07
------------------------------------
]0;root#openwrt: ~root#openwrt:~# ls
[0;0mnetwork[m
]0;root#openwrt: ~root#openwrt:~#
what's the main cause of this issue? How I can fix it?
The problem is that there are terminal escape sequences being issued, probably to control what colour the terminal uses. The easiest fix is to set the terminal type (an environment variable) to something that doesn't support colour before doing the spawn. Perhaps this will do the trick:
set env(TERM) "dumb"
If that doesn't work (it depends on exactly what is in someone's .bashrc) then you can just override the PS1 environment variable on the remote side with your first command after logging in.
# etc for logging in
expect "# "
send "PS1='# '\r"
expect "# "
# Everything should be right from here on

Expect script: Need a means to validate an SSH connection does not need a password

I am a system tester and I have a particular set of DUTs which can run either on a pre-release version of the firmware or a release candidate. On the pre-release I can access the Linux core OS of the DUT by logging in with a particular user account. The release candidate does not allow this.
The whole basis of the script I'm writing is to be able to remotely execute a script which resides on the DUT. I would like to check if I have access to the Linux core OS with need of a password or not. If I do have access then continue else exit the script.
I have tried many things and each has failed when testing against the release candidate as a password is expected. Here is the latest attempt:
set status [catch {exec ssh $user#$host ls} result]
if { [regexp "Password:" $result]} then {
# A password was asked for. Fail
puts "This is a Release Candidate Version\nAccess to the Linux OS is denied"
exit
} else {
# no password needed. Success
puts "This is a Pre-Release version"
}
When executed against a pre-release version this code works. But when a password is required it does not as the SSH session prompts for a password and waits for input.
Would anyone have a workaround that would break out of the required password scenario?
Thank you
If you have a case where the connection to the remote system may ask for a password, but isn't always going to, you're best of doing the connection from within expect. This is because the expect command can be told to wait for several different things at once.
set timeout 20; # 20 seconds; if things don't respond within that, we've got problems
# 'echo OK' because it is quick and produces known output
spawn ssh $user#$host echo OK
# Wait for the possibilities we know about; note the extra cases!
expect {
"Password:" {
# Password was asked for
puts "This is a Release Candidate Version\nAccess to the Linux OS is denied"
close
exit
}
"OK" {
# Password not asked for
puts "This is a Pre-Release version"
}
timeout {
puts "There was a network problem? Cannot continue test"
close
exit 1
}
eof {
puts "Inferior ssh exited early? Cannot continue test"
close
exit 1
}
}
close
# ... now you've checked the connection ...

print expect output to the terminal on the fly

I want to run some script on other machine, by doing ssh there. This script might take longer time and it would be better for me if I am able to display what is going on right now in execution step.
But, when I pass to spawn ssh with script, task is completed and it comes out silently. Is there a way that we can print the output from the other machine. I can take a log also, but it can be accessed when job is completed. Can I do it on the fly?
package require Expect
spawn ssh machine
expect -regexp {
"bash" {
send "perl script.pl\r"
}
timeout {
exit
}
eof {
exit
}
interact
}
puts "Done"
I have used, puts $expect_out(buffer); which is giving me no variable error.
Thanks in advance.

TCL program to login to a remote server and excute command

I need to write a TCL program through which I shall be able to login to the remote server and then execute commands on the remote server; also I need to get the output from the remote server.
EDIT:
Thanks Kostix for the reply. My requirement says that the TCL script should be able to login to the remote server. I am planning to send the password thru the expect mechanism, and after that I am planning to send the commands. My sample code goes like this:
set prompt "(%|>|\#|\\\$) #"
spawn /usr/bin/ssh $username#$server
expect {
-re "Are you sure you want to continue connecting (yes/no)?" {
exp_send "yes\r"
exp_continue
#continue to match statements within this expect {}
}
-nocase "password: " {
exp_send "$password\r"
interact
}
}
I am able to login with this but dont know how to extend this code to send commands. I've tried few methods, but didn't work out.
Since you're about to use SSH, you might not need neither Tcl nor Expect to carry out this task at all: since SSH stands for "Secure SHell", all you need to do to execute commands remotely is to tell SSH what program to spawn on the remote side after logging in (if you do not do this, SSH spawns the so-called "login shell" of the logged in user) and then SSH feeds that program what you pass the SSH client on its standard input and channels back what the remote program writes to its standard output streams.
To automate logging via SSH, several ways exist:
Authentication using public keys: if the private (client's) key is not protected by a password, this method requires no scripting at all — you just tell the SSH client what key to use.
"Keyboard interactive" authentication (password-based). This is what most people think SSH is all about (which is wrong). Scripting this is somewhat hard as SSH insists on getting the password from a "real terminal". It can be tricked to beleive so either through using Expect or simply by wrapping a call to the SSH client using the sshpass program.
Both the SSH client and the server might also support Kerberos-based or GSSAPI-based authentication. Using it might not require any scripting as it derives the authentication credentials from the system (the local user's session).
So the next steps to carry out would be to narrow your requirements:
What kind of authentication has to be supported?
What program should perform the commands you intend to send from the client? Will that be a Unix shell? A Tcl shell? Something else?
Should that remote command be scripted using some degree of interactivity (we send something to it then wait for reply and decide what to send next based on it) or batch-style script would be okay?
Before these questions are answered, the inital question has little sense as it's too broad and hence does not meet stackoverflow format.
Commands on the server can be executed either using exec command like this,
set a [exec ls -lrta]
puts $a
[OR] The expect and execute loop can be continued as above;
I am making a proc using which linux commands can easily be run;
package require Expect
proc ExecCommand {username server password cmd } {
spawn /usr/bin/ssh $username#$server
expect {
".*(yes/no)? " {exp_send "yes\r" ; exp_continue}
".*password: " {exp_send "$password\r";exp_continue}
".*$ " {exp_send -i $spawn_id "$cmd \r";
expect {
".*$ " { return 1; close }
}
}
}
}
set result [ExecCommand "admin" "0" "qwerty" "ls"]
if {$result > 0 } {
puts "Command succesfully executed\n"
} else {
puts "Failed to execute\n"
}

Expect/TCL: pass commands to specific proc/spawn IDs

I am trying to write an expect script that will do the following..
open up 13 terminal windows (gnome-terminal, xterm etc)
each window connects to a terminal server via ssh (ssh InReach#10.1.6.254)
and is provided the password via expect.
i can get this to work fine in a single window. the problem i am having though is getting the input passed over to each window.
for instance...
i can do
set timeout -1
spawn gnome-terminal -x ssh InReach#10.1.6.254
inside of a while loop and get my 13 windows. but i would like each one to be logged in automatically via expect.
You can try a slightly different approach. Instead of opening the terminal windows in the expect script, open them in a basic shell script, and have each terminal run an expect script to start a single SSH session.
So the expect script could be as simple as this:
#!/usr/bin/expect -f
spawn ssh InReach#10.1.6.254
# ... provide password ...
interact
And the shell script:
#!/bin/sh
for a in `seq 1 13`; do
gnome-terminal -x ./expect_script
done
When you spawn, you need to cache the $spawn_id value which is set by the attempt.
e.g.
if [catch "spawn ssh -l mtc $ub1_ip_address" ub1_pid] {
Log $ERROR "Unable to spawn ssh to Xubuntu.\n$ub1_pid\n"
return 0
}
set stored_id $spawn_id
To send a command to one terminal session in particular, do
send -i $stored_id "command"
Then, before you contact each, you must first do
expect {
-i $stored_id
[ ... your regexes, globs, etc. ... ]
}
You can find some add'l info http://wiki.tcl.tk/11583
I would also suggest making use of gnome-terminal's ability to specify multiple tabs, including an indication of which is the currently-active one, and a command to be executed. gnome-terminal --help-all is helpful (no pun intended).