linux伺服器叢集重複大量操作指令碼實現

來源:互聯網
上載者:User

標籤:blog   http   io   ar   os   使用   sp   for   strong   

http://blog.csdn.net/flyinmind/article/details/8074863      

   在伺服器叢集的維護中,經常會遇到同樣的操作重複執行很多遍的情況,“登入伺服器->做操作->退出”,繼續下一個伺服器。簡單枯燥、容易出錯、並且毫無成就感。

       我在做push產品的過程中,見到有同事在這個簡單重複的工作中,經常犯一些低級錯誤,心灰意冷。所以我花了一點時間將能自動化的過程全部自動化,操作人員只需做兩件事:

1、記錄所有伺服器的IP、SSH連接埠、使用者名稱、密碼、登入提示符、主路徑,記為:xx.srv檔案;

每行一個伺服器,以逗號分隔,比如:"192.168.9.1:22,opush,opush,>,/home/push/8080"

2、記錄每個伺服器上要做的重複操作,記為:yy.cmd檔案。

每行一個命令,[]括起的部分表示在本地執行的,<>括起的是最開始執行一次,{}括起的部分表示在所有伺服器都操作完之後,最後在本地執行一次的命令,比如:

 

[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/*}

 

       上面例子中,先拷貝tomcat的日誌到本地的rec目錄,然後登陸到伺服器上關閉tomcat、刪除日誌、啟動tomcat,所有伺服器都做一遍之後,退回到本機打包壓縮記錄檔。

       上面例子中出現了{USER}、{HOST},這個類似於“宏”,在執行時會被替換為相應值,看當前在叢集中的哪個伺服器上執行,比如在192.168.9.1上執行,使用者名稱是opush,則這裡就會被替換成他們,還有:{PORT}、{PASSWORD}、{PATH}、{NO}幾個宏,可以在命令中使用。

       還有一點需要注意,<>,[],{}只能括住一行,不能多行,如果有多個命令,比如多行,並且每行一對括弧。

      最後一點,這兩個檔案如果行首是"#",則表示注釋。

      

      本工具的目錄結構如下:

/--

   |--conf/

   |--exec

 

      做好後,將這個兩個檔案放到conf目錄下,xx.srv檔案可以只需一份,在不同的操作中重複使用;每一類操作記錄一個yy.cmd檔案(比如上面的操作可以命名為getlogs_reset.cmd),在以後操作時只需運行:

./exec xx.srv yy.cmd

OK,所有操作都自動完成。

 

      指令碼的基本原理是使用awk讀取設定檔,使用expect指令碼來完成自動的互動,所以在你的跳板機上(只需跳板機安裝就可以了)必須要有awk、expect;這個指令碼用的是bash,所以也需要它,如果沒有,可能要對exec做一點改動,比如適應ksh、csh等。如果你用的是suse,安裝包中已內建了expect,使用yast安裝就可以了,其他的linux也應該可以安裝。

     下面是指令碼的源碼,供參考,如果你做了什麼改進,或發現了問題,歡迎發給我,一起來改進它。本來想起一個開源項目,因為這個太小了,也沒有必要做的太通用,所以就放在這裡,供大家參考吧。希望能將你從重複枯草的鍵盤運動中解放出來:)

 

 

 

#!/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($0)
        pos = index(line, "#")

        if (pos != 1) {
            if (NF >= 3) {
                server = $1
                user = $2
                password = $3

                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 = $5
                }
                
                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
    }
    ‘ $1
}

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($0)
        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
    }
    ‘ $1
}

executeRemote() {
    HOST="$1"
    PORT="$2"
    USER="$3"
    PASSWORDD="$4"
    PROMPT="$5"
    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伺服器叢集重複大量操作指令碼實現

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.