运行 EC2 上的 expect 脚本挂起,但手动调用时运行成功
Running expect script on EC2 hangs, but runs successfully when manually invoked
我正在编写 expect
脚本来启动 SSH 隧道。
它在实例启动时在 EC2 上获得 运行,作为从 .ebextensions
配置文件创建脚本的部署的一部分。
当脚本为运行时,总是卡在这个点:
Enter passphrase for key '/home/ec2-user/id_data_app_rsa':
如果我 运行 在服务器上手动执行相同的脚本它会成功并且我可以看到隧道进程 运行ning。
ps aux | grep ssh
root 19046 0.0 0.0 73660 1068 ? Ss 16:58 0:00 ssh -i /home/ec2-user/id_data_app_rsa -p222 -vfN -L 3306:X.X.X.X:3306 root@X.X.X.X
我可以通过将脚本打印到控制台来验证脚本是否正确读取 SSH_PASSPHRASE
。
set password $::env(SSH_PASSPHRASE)
send_user "retrieved env variable : $password "
这是我从 EC2 日志中得到的调试输出:
Enter passphrase for key '/home/ec2-user/id_data_app_rsa':
interact: received eof from spawn_id exp0
我很困惑为什么当 EC2 部署器 运行s 时它在这里没有进一步,但是当 运行 手动时它继续正常。
这是 .ebextensions
中的脚本,脚本本身从 #!/usr/bin/expect
:
开始
files:
"/scripts/createTunnel.sh" :
mode: "000755"
owner: root
group: root
content: |
#!/usr/bin/expect
exp_internal 1
set timeout 60
# set variables
set password $::env(SSH_PASSPHRASE)
send_user "retrieved env variable : $password "
spawn -ignore HUP ssh -i /home/ec2-user/id_data_app_rsa -p222 -vfN -L 3306:X.X.X.X:3306 root@X.X.X.X
expect {
"(yes/no)?" { send "yes\n" }
-re "(.*)assphrase" { sleep 1; send -- "$password\n" }
-re "(.*)data_app_rsa" { sleep 1; send -- "$password\n" }
-re "(.*)assword:" { sleep 1; send -- "$password\n" }
timeout { send_user "un-able to login: timeout\n"; return }
"denied" { send_user "\nFatal Error: denied \n"}
eof { send_user "Closed\n" ; return }
}
interact
您的问题在这里:
set password $::env(SSH_PASSPHRASE)
以及 shell 使用环境变量的方式。调用脚本时,您假定已设置环境变量。根据调用脚本的方式,$::env(SSH_PASSPHRASE) 可能未设置,导致变量为 null/blank。当 init 脚本(或 cloud-init)是 运行 时,它们不是 运行 登录环境 shell。因此,您不应假定已设置 .profile 或 /etc/profile 环境变量,而应显式获取或设置它们。
一个可能的解决方案可能是
. ~ec2-user/.profile /path/to/above.script
我们终于解决了这个问题。有两件事似乎有问题:
- 将最后的
interact
更改为 expect eof
。
- 修剪
expect
尽可能匹配模式。
我们在测试中注意到 expect 似乎在错误地匹配,发送密码,例如,当它应该在 'yes/no' 提示符上发送 'yes' 匹配时。
这是我们最终得到的最终脚本,以防它对其他人有用:
#!/usr/bin/expect
exp_internal 1
set timeout 60
# set variables
set password $::env(SSH_TUNNEL_PASSPHRASE)
spawn -ignore HUP ssh -i /home/ec2-user/id_data_rsa -p222 -vfN -L 3306:X.X.X.X:3306 root@X.X.X.X
expect {
"(yes/no)?" { send "yes\r" }
"Enter passphrase" { sleep 2; send -- "$password\r"; sleep 2; exit }
}
expect eof
我正在编写 expect
脚本来启动 SSH 隧道。
它在实例启动时在 EC2 上获得 运行,作为从 .ebextensions
配置文件创建脚本的部署的一部分。
当脚本为运行时,总是卡在这个点:
Enter passphrase for key '/home/ec2-user/id_data_app_rsa':
如果我 运行 在服务器上手动执行相同的脚本它会成功并且我可以看到隧道进程 运行ning。
ps aux | grep ssh
root 19046 0.0 0.0 73660 1068 ? Ss 16:58 0:00 ssh -i /home/ec2-user/id_data_app_rsa -p222 -vfN -L 3306:X.X.X.X:3306 root@X.X.X.X
我可以通过将脚本打印到控制台来验证脚本是否正确读取 SSH_PASSPHRASE
。
set password $::env(SSH_PASSPHRASE)
send_user "retrieved env variable : $password "
这是我从 EC2 日志中得到的调试输出:
Enter passphrase for key '/home/ec2-user/id_data_app_rsa':
interact: received eof from spawn_id exp0
我很困惑为什么当 EC2 部署器 运行s 时它在这里没有进一步,但是当 运行 手动时它继续正常。
这是 .ebextensions
中的脚本,脚本本身从 #!/usr/bin/expect
:
files:
"/scripts/createTunnel.sh" :
mode: "000755"
owner: root
group: root
content: |
#!/usr/bin/expect
exp_internal 1
set timeout 60
# set variables
set password $::env(SSH_PASSPHRASE)
send_user "retrieved env variable : $password "
spawn -ignore HUP ssh -i /home/ec2-user/id_data_app_rsa -p222 -vfN -L 3306:X.X.X.X:3306 root@X.X.X.X
expect {
"(yes/no)?" { send "yes\n" }
-re "(.*)assphrase" { sleep 1; send -- "$password\n" }
-re "(.*)data_app_rsa" { sleep 1; send -- "$password\n" }
-re "(.*)assword:" { sleep 1; send -- "$password\n" }
timeout { send_user "un-able to login: timeout\n"; return }
"denied" { send_user "\nFatal Error: denied \n"}
eof { send_user "Closed\n" ; return }
}
interact
您的问题在这里:
set password $::env(SSH_PASSPHRASE)
以及 shell 使用环境变量的方式。调用脚本时,您假定已设置环境变量。根据调用脚本的方式,$::env(SSH_PASSPHRASE) 可能未设置,导致变量为 null/blank。当 init 脚本(或 cloud-init)是 运行 时,它们不是 运行 登录环境 shell。因此,您不应假定已设置 .profile 或 /etc/profile 环境变量,而应显式获取或设置它们。
一个可能的解决方案可能是
. ~ec2-user/.profile /path/to/above.script
我们终于解决了这个问题。有两件事似乎有问题:
- 将最后的
interact
更改为expect eof
。 - 修剪
expect
尽可能匹配模式。
我们在测试中注意到 expect 似乎在错误地匹配,发送密码,例如,当它应该在 'yes/no' 提示符上发送 'yes' 匹配时。
这是我们最终得到的最终脚本,以防它对其他人有用:
#!/usr/bin/expect
exp_internal 1
set timeout 60
# set variables
set password $::env(SSH_TUNNEL_PASSPHRASE)
spawn -ignore HUP ssh -i /home/ec2-user/id_data_rsa -p222 -vfN -L 3306:X.X.X.X:3306 root@X.X.X.X
expect {
"(yes/no)?" { send "yes\r" }
"Enter passphrase" { sleep 2; send -- "$password\r"; sleep 2; exit }
}
expect eof