I've been trying to write an expect script which has one method to open an ssh connection and this method can be called by other methods so that they can send additional commands for execution. What I already have is -
#!/usr/bin/expect
set timeout -1
#log_user 0
set username [lindex ${argv} 0]
set node_address [lindex ${argv} 1]
set password [lindex ${argv} 2]
set prompt ".*\[>#:$%\] \?\$"
set password_prompt ".*: \?\$"
set install_dir "/usr/share/elasticsearch"
set conf_dir "/etc/elasticsearch"
set plugin_manager "${install_dir}/bin/elasticsearch-plugin"
set es_config_file "${conf_dir}/elasticsearch.yml"
puts "Attempting login to ${node_address}"
spawn ssh ${username}@${node_address}
expect -re ${password_prompt} {send -- "${password}\n"}
expect -re ${prompt} {send -- "sudo su - kompuser\n"}
expect -re ${prompt}
puts "Logged in to the node ${node_address} successfully"}
expect -re ${prompt}
send -- "curl -XGET 'localhost:9200/_cat/nodes?v&h=ip,node.role'\n"
expect -re ${prompt}
send_user $expect_out(buffer)
I have other scripts which try to login to a host using the similar code and have lots of code duplication. I want to avoid the code duplication by writing a single method, let's call it login and invoke it before sending any command to the remote server, what I want is -
#!/usr/bin/expect
set timeout -1
#log_user 0
set username [lindex ${argv} 0]
set node_address [lindex ${argv} 1]
set password [lindex ${argv} 2]
set prompt ".*\[>#:$%\] \?\$"
set password_prompt ".*: \?\$"
set install_dir "/usr/share/elasticsearch"
set conf_dir "/etc/elasticsearch"
set plugin_manager "${install_dir}/bin/elasticsearch-plugin"
set es_config_file "${conf_dir}/elasticsearch.yml"
proc login {username node_address password prompt password_prompt} {
puts "Attempting login to ${node_address}"
spawn ssh ${username}@${node_address}
expect -re ${password_prompt} {send -- "${password}\n"}
expect -re ${prompt} {send -- "sudo su - kompuser\n"}
puts "Logged in to the node ${node_address} successfully"}
proc get_node_info {username node_address password prompt password_prompt} {
login ${username} ${node_address} ${password} ${prompt} ${password_prompt}
expect -re ${prompt}
send -- "curl -XGET 'localhost:9200/_cat/nodes?v&h=ip,node.role'\n"
expect -re ${prompt}}
proc restart_node {username node_address password prompt password_prompt} {
login ${username} ${node_address} ${password} ${prompt} ${password_prompt}
expect -re ${prompt} {send -- "sudo systemctl daemon-reload\n"}
expect -re ${prompt} {send -- "sudo systemctl start elasticsearch.service\n"}
expect -re ${prompt}
}
get_node_info ${username} ${node_address} ${password} ${prompt} ${password_prompt}
restart_node ${username} ${node_address} ${password} ${prompt} ${password_prompt}
The issue is that call to login logs in successfully but expecting for the prompt in the caller hangs - Following are the last few lines of the logs on enabling the debug logs -
send: sending "sudo su - kompuser\n" to { exp4 }
Logged in to the node 10.109.14.73 successfully
Gate keeper glob pattern for '.*[>#:$%] ?$' is ''. Not usable, disabling the performance booster.
expect: does "" (spawn_id exp0) match regular expression ".*[>#:$%] ?$"? (No Gate, RE only) gate=yes re=no
Any help will be much appreciated. Thanks
ssh-copy-idand just use ssh? Looks like you should interest yourself in some automation tools, like ansible.sshinto the destination user? AddNOPASSWDto ssh config?ansiblebecomemodule, that does just that - passes a password tosudoto "become" a user.