I am attempting to write a script that will run system updates on about 30 linux servers (mixed distributions). For now I am focusing on debian to keep things simple. The script is composed of three parts: A bash script that reads a file containing the list of servers and executes an expect script located on each server. I have a decent grasp of bash and am very new to expect with little no knowledge of how bash and expect behave together.
The list of servers is written in a hosts file:
all_hosts
Code:
? List of servers to update
? Preceeding question mark is a commented line
?
? port separated by percent then hostname
? port%server
22%server1
8912%server2
189%server3
The main bash script reads this file and loops through. This part of the script works. I have been using this for some time now to move files between all my servers. Here is the main bash script:
update_all
Code:
1 #!/bin/bash
2
3 # update_all
4
5 # There are three variables accepted via commandline
6 # $1 = first parameter (/source_path/source_filename)
7 # $2 = second parameter (/target_directory/)
8 # $3 = third paramter (file that contains list of hosts)
9
10 HOSTFILE=$1
11 PASS=$2
12
13 if [ $# -ne 2 ]; then
14 echo "usage: $0 [hostsfile] [password]"
15 exit 1
16 elif [ -f $HOSTFILE ]; then
17 printf "Begining update process ...\n"
18 while read line; do
19 COMMENT=`expr index "$line" ?`
20 if [ $COMMENT -lt 1 ]; then
21 SEPER=`expr index "$line" %`
22 SERVER=${line:SEPER}
23 let SEPER-=1
24 PORT=${line:0:SEPER}
25 echo "$SERVER: "
26 ssh -p $PORT $SERVER '/home/user/update $2'
27 fi
28 done < $HOSTFILE
29 else
30 printf "File \"$HOSTFILE\" not found\n"
31 exit 0
32 fi
33 exit 0
You can see on line 26 in update_all, the update process is executed via SSH. So on each server there is an expect script called
update which is an expect script that looks like:
Code:
1 #!/usr/bin/expect
2
3 set timeout 10
4
5 set pass [lindex $argv 0]
6
7 spawn sudo apt-get clean
8 expect "*?assword*"
9 send "$pass\r";
10 interact
11
12 spawn sudo apt-get update
13 expect "*?assword*"
14 send "$pass\r";
15 interact
16
17 spawn sudo apt-get -yq upgrade
18 expect "*?assword*"
19 send "$pass\r";
20 interact
Now this expect script works when executed locally on each server. So the command looks like:
Code:
$ ./update "mypassword"
Back on my central server if I put it all together:
Code:
$ ./update_all all_hosts "mypassword"
Begining update process ...
server1:
spawn sudo apt-get clean
[sudo] password for user: interact: spawn id exp0 not open
while executing
"interact"
(file "/home/user/update" line 15)
I have scoured google around this error but I believe the problem is a fundamental misunderstanding on my part. All the information I have found points to using different methods alltogether, for example:
stackoverflow.com/how-can-i-make-an-expect-script-prompt-for-a-password. My questions are thus:
- Does my approach seem reasonable? As in, using bash and expect in this manner.
- Does this approach have any security risks?
- What does the above error mean and how can I mitigate it?
Thanks.