http://blog.csdn.net/flyinmind/article/details/8074863
In the maintenance of the server cluster, often encounter the same operation repeated many times, "Log on server, do operations, exit", continue to the next server. Simple and boring, error-prone, and no sense of accomplishment.
I was in the process of making push products, I saw colleagues in this simple repetition of the work, often make some low-level mistakes, discouraged. So it took me a little time to automate all the processes, and the operators only had to do two things:
1, record all the server IP, SSH port, user name, password, login prompt, the main path, recorded as: Xx.srv file;
One server per line, separated by commas, for example:"192.168.9.1:22,opush,opush,>,/home/push/8080"
2. Record the repeated operations on each server as follows: Yy.cmd file.
One command per line, [] enclosed part means that the locally executed,<> is the first to execute, and the {} section represents the last command to execute locally once all the servers have finished operation, such as:
[SCP {user}@{host}:/home/opush/logs/*./rec]
PS Aux|grep {user}|grep catalina|grep startup|awk ' {print \\\$2} ' | Xargs kill-9
Cd/home/{user}
Rm-rf./logs/*
./bin/startup.sh
{tar Cfz logs.tar.gz./rec/*}
In the example above, copy the Tomcat log to the local rec directory, then log on to the server to close Tomcat, delete the log, start Tomcat, and after all the servers are done again, return to the native packaged compressed log file.
In the example above, {user}, {HOST}, which is similar to "macro", will be replaced with the corresponding value at execution, to see which server is currently executing on the cluster, such as executing on 192.168.9.1, the user name is Opush, then this will be replaced with the following: {PORT} , {PASSWORD}, {PATH}, {NO} several macros, which can be used in commands.
It is also important to note that <>,[],{} can only enclose one row, not multiple rows, if there are multiple commands, such as multiple lines, and a pair of parentheses per line.
Finally, these two files indicate a comment if the line is "#" at the beginning of the line.
The directory structure of this tool is as follows:
/--
|--conf/
|--exec
When done, put this two files into the Conf directory, the Xx.srv file can be used in a single copy, repeated use in different operations; each type of operation records a Yy.cmd file (for example, the above operation can be named Getlogs_reset.cmd) and only needs to be run at a later time:
./exec Xx.srv Yy.cmd
OK, all operations are done automatically.
The rationale of the script is to use awk to read the configuration file and use the expect script to complete the automatic interaction, so on your springboard (just install the springboard) you have to have awk, expect; This script uses bash, so it needs it, if not, You may want to make a little change to exec, such as adapting to Ksh, CSH, etc. If you are using SuSE, the installation package has its own expect, installed with YaST, and other Linux should be installed.
Below is the script source code, for reference, if you did any improvement, or found the problem, welcome to send me, together to improve it. Originally thought of an open source project, because this is too small, there is no need to do too general, so put here, for everyone to reference it. Hope to liberate you from the keyboard movement of repeated grasses:)
#!/bin/bash
Translateservers () {
awk '
BEGIN {
Fs= ","
Servernum = 0
}
function Trim (str) {
Gsub (/^\s*/, "", str)
Gsub (/\s*$/, "", str)
Return str
}
{
prompt = ">"
Port = 22
Host = ""
user = ""
Password = ""
Path = ""
Line = Trim ($)
pos = index (line, "#")
if (pos! = 1) {
if (NF >= 3) {
Server = $
User = $
Password = $ $
POS = index (server, ":")
if (pos > 1) {
Split (server, arr, ":")
Host = Arr[1]
Port = arr[2]
} else {
Host = Server
}
if (NF > 3) {
prompt = $4
}
if (NF > 4) {
Path = $
}
Print "Host_" NR "=\" "host" \ "" "
Print "Port_" NR "=" Port
Print "User_" NR "=\" "User" \ "" "
Print "Password_" NR "=\" "Password" \ "" "
Print "Prompt_" NR "=\" "Prompt" \ "" "
Print "Path_" NR "=\" "Path" \ "" "
Servernum = servernum + 1
}
}
}
END {
Print "server_num=" Servernum
}
' $
}
Translatecommands () {
awk '
BEGIN {
Commandnum = 0
Remote_commands = ""
Foretype = 0
Fs= ","
}
function Trim (str) {
Gsub (/^\s*/, "", str);
Gsub (/\s*$/, "", str);
Return str
}
function Print_remote () {
if (remote_commands! = "" "&& Foretype = = 0) {
Print "Cmd_type" commandnum "= 0"
Print "Cmd_line" Commandnum "=\" "Remote_commands" \ ""
}
Remote_commands = ""
}
function print_local (line, end, type) {
Print_remote ()
Commandnum = commandnum + 1
Len = Length (line)
Last = substr (line, Len, 1)
if (last = = end) {
Command = substr (line, 2, len-2)
} else {
Command = substr (line, 2)
}
Print "Cmd_type" commandnum "=" type
Print "Cmd_line" Commandnum "=\" "command" \ ""
}
{
Type = 0
Gsub (/\ "/," \\\\\\\ "")
#gsub (/\$/, "\\\\\\\$")
Line = Trim ($)
Header = substr (line, 1, 1)
if (header! = "#" && Length (line) > 1) {
if (header = = "[") {
Type = 1
Print_local (line, "]", type)
} else if (header = = "{") {
Type = 2
Print_local (line, "}", type)
} else if (header = = "<") {
Type = 3
Print_local (line, ">", type)
} else {
if (Remote_commands = = "") {
Commandnum = commandnum + 1
}
Type = 0
Remote_commands = remote_commands "\\r" line
}
Foretype = Type
}
}
END {
Print_remote ()
Print "command_num=" Commandnum
}
' $
}
Executeremote () {
Host= "$"
Port= "$"
User= "$"
Passwordd= "$4"
Prompt= "$"
Cmds= "$6"
Remote_commands= "
Puts \ "Login server, wait ${prompt}...\\n\";
Spawn Ssh-p ${port} ${user}@${host};
Set timeout 15;
Set Doitagain 1;
While {\${doitagain}} {
Expect {
\ "*continue connecting*\" {
Send \ "Yes\\r\";
}
\ "*assword*\" {
Send \ "${password}\\r\";
}
\ "*${user}*${prompt}\" {
Puts \ "Login ${host} successfully:) \";
Set Doitagain 0;
}
\"*#\" {
Puts \ "Login ${host} successfully:) \";
Set Doitagain 0;
}
Timeout break;
}
}
if {\ $doItAgain = = 0} {
Set CMDS [Split \ "${cmds}\" \ "\\r\"];
foreach CMD \${cmds} {
Send \ "\${cmd}\\r\";
Expect \ "*${user}*${prompt}\";
}
Send \ "Exit\\r\";
Expect EOF;
} else {
Puts \ "fail to login\";
}
"
Expect-c "$remote _commands"
}
Scpfile () {
Scpcmd=$1
Password=$2
Scp_commands= "
Puts \ "Spawn ${scpcmd}\\n\";
Spawn ${scpcmd};
Set Doitagain 1;
While {\ $doItAgain} {
Expect {
\ "*continue connecting*\" {
Send \ "Yes\\r\";
}
\ "*assword:*\" {
Send \ "${password}\\r\";
}
EOF {
Set Doitagain 0;
}
}
}
"
Expect-c "$SCP _commands"
}
RunCommand () {
N=$1
host=$ (Getcfgitem "Host_${n}")
port=$ (Getcfgitem "Port_${n}")
user=$ (Getcfgitem "User_${n}")
password=$ (Getcfgitem "Password_${n}")
pmpt=$ (Getcfgitem "Prompt_${n}")
mainpath=$ (Getcfgitem "Path_${n}")
for (k = 1; k <= command_num; k++)); Do
type=$ (Getcfgitem "Cmd_type${k}")
cmd=$ (Getcfgitem "Cmd_line${k}")
cmd=${cmd//\{host\}/$HOST}
cmd=${cmd//\{port\}/$PORT}
cmd=${cmd//\{user\}/$USER}
cmd=${cmd//\{path\}/$MAINPATH}
cmd=${cmd//\{password\}/$PASSWORD}
cmd=${cmd//\{no\}/$N}
if [$TYPE = 1]; Then
echo "Execute \" ${cmd}\ ""
if [[$CMD =~ "^scp.*$"]]; Then
Scpfile "${cmd}" "${password}"
Else
Eval "${cmd}"
Fi
elif [$TYPE = 0]; Then
Executeremote "$HOST" "$PORT" "$USER" "$PASSWORD" "$PMPT" "$CMD"
Fi
Done
}
# # only local command, and run at the end
Runcommandonce () {
Expected_type=$1
for ((i = 1; I <= command_num; i++)); Do
type=$ (Getcfgitem "Cmd_type${i}")
If ["$TYPE"-eq "$EXPECTED _type"]; Then
echo "Execute \" ${cmd}\ ""
cmd=$ (Getcfgitem "Cmd_line${i}")
Eval "${cmd}"
Fi
Done
}
If [$#-lt 1]; Then
echo "Usage:exec server_list_file command_list_file"
Exit
Fi
Server_file= "./conf/$1"
Command_file= "./conf/$2"
Temp_file= "./$2.cmd"
Dos2unix ${server_file}
Dos2unix ${command_file}
Translateservers ${server_file} > ${temp_file}
Translatecommands ${command_file} >> ${temp_file}
Echo-e "Getcfgitem () {\nif [-n \\$\${1}]; then\n eval echo \\$\${1}\nelse\n echo \ "\" \nfi\n} ">> ${temp_file}
SOURCE ${temp_file}
Runcommandonce 3
echo "Start to execute command on all ${server_num} servers"
for ((i = 1; I <= server_num; i++)); Do
RunCommand $i
Done
Runcommandonce 2
echo "Execute commands End"
RM ${temp_file}
Linux server cluster Repeat batch operation script implementation