期望脚本:创建使用 ssh 登录远程服务器的方法,并在方法返回后发送命令

问题描述

我一直在尝试编写一个 expect 脚本,该脚本具有打开 ssh 连接的一种方法,并且该方法可以由其他方法调用,以便它们可以发送额外的执行命令。我已经拥有的是 -

#!/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)

我有其他脚本尝试使用类似的代码登录主机,并且有很多代码重复。我想通过编写单个方法来避免代码重复,让我们称之为 login 并在向远程服务器发送任何命令之前调用它,我想要的是 -

#!/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}

问题是调用 login 成功登录但期望调用者中的提示挂起 - 以下是启用调试日志的最后几行日志 -

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

任何帮助将不胜感激。 谢谢

解决方法

当您在 proc 内运行 spawn 时,变量 spawn_id 在当前堆栈帧中创建,使其成为局部变量,除非采取特殊措施。

有了这些知识,解决方案很简单:在运行 spawn_id 命令之前将 spawn 声明为全局:

proc login {username node_address password prompt password_prompt} {
    global spawn_id
    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"
}

我相信你不需要在其他过程中这样做。但为了一致性,我会。