zoukankan      html  css  js  c++  java
  • linux服务器集群重复批量操作脚本实现

    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() { if [ -n \$${1} ]; then eval echo \$${1} else echo "" fi }" >> ${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}

  • 相关阅读:
    EXTJS 4.2 资料 控件之checkboxgroup的用法(静态数据)
    EXTJS 4.2 资料 控件之Window窗体相关属性的用法
    EXTJS 4.2 资料 控件之textfield文本框加事件的用法
    Entity Framework 学习笔记(一)之数据模型 数据库
    EXTJS 4.2 资料 控件之checkboxgroup的用法(动态数据)
    EXTJS 4.2 资料 控件之Grid 列鼠标悬停提示
    Entity Framework 学习笔记(二)之数据模型 Model 使用过程
    EXTJS 4.2 资料 控件之radiogroup 的用法
    EXTJS API
    vue移动端弹框组件,vue-layer-mobile
  • 原文地址:https://www.cnblogs.com/fvsfvs123/p/4126850.html
Copyright © 2011-2022 走看看