贡献web根据负载弹性添加到loadblance的python脚本一份,适用于aws(亚马逊)书写并调试、优化差不多2天时间,写代码真TM累。此脚本需要在每台web上安装snmp协议,大家做运维的估计在服务器上都安装了,cacti的时候会用到。

 

#!/usr/bin/env python
#coding=utf-8
import boto
from  boto.ec2.elb import ELBConnection
import commands
import random
import logging
import time


ACCESS_KEY_ID = 'xxxx'
SECRET_ACCESS_KEY = 'xxxx'

conn = ELBConnection(ACCESS_KEY_ID, SECRET_ACCESS_KEY)
ec2_connection = boto.connect_ec2(ACCESS_KEY_ID, SECRET_ACCESS_KEY)

 

elastic_cloud_configs = {
    'testload': {         #loadbalancer name
        'filters': 'web', #machine nme filter 就是需要添加到负载均衡里面的机器名前缀
        'maxload': 0.02, #达到这个负载开始加机器
        'minload': 0.1, #达到这个负载开始关闭机器
        'keeps': ['web11', 'web10'] #长期开的机器,永远不关闭除非手动关闭
    },

}


def show_elb_instance(name):
    """
    show elb all instance
    """
    loadlist = str(conn.get_all_load_balancers()).strip('[]').replace('LoadBalancer', '').replace(',', '').split(':')
    loadlist = loadlist[1:]
    for line in loadlist:
        if line.strip() == name:
            load_balancer = conn.get_all_load_balancers(load_balancer_names=[name])[0]
            single_load_instances = [instance for instance in load_balancer.instances]
            return single_load_instances


def show_elb_running_instance(name):
    """
    show elb running instance
    """
    single_load_instances = show_elb_instance(name)
    reservations = ec2_connection.get_all_instances([i.id for i in single_load_instances])
    instance_running = [r.tags['Name'] for r in reservations for r in r.instances]
    return instance_running


def show_all_instance():
    """
    show all instance
    """
    ec2_reservations = ec2_connection.get_all_instances()
    all_instance = []
    for instance in ec2_reservations:
        for inst in instance.instances:
            all_instance.append(inst)
    return all_instance


def show_machine_load(single_load_instances):
    sum_minute_load = 0
    sum_fiveminute_load = 0
    numlist = []
    reservations = ec2_connection.get_all_instances([i.id for i in single_load_instances])
    instance_addresses = [r.public_dns_name for r in reservations for r in r.instances]
    for ip in instance_addresses:
        single_machine_load = commands.getoutput(
            "snmpwalk  -v 2c %s -c public  .1.3.6.1.4.1.2021.10.1.3.1|awk '{print $4}'" % ip)
        five_minute_load = commands.getoutput(
            "snmpwalk  -v 2c %s -c public  .1.3.6.1.4.1.2021.10.1.3.2|awk '{print $4}'" % ip)
        numlist.append(ip)
        sum_minute_load += float(single_machine_load)
        sum_fiveminute_load += float(five_minute_load)
    return sum_minute_load / len(numlist), sum_fiveminute_load / len(numlist)


def add_machine_instance(key, pre_start_instancelist):
    if len(pre_start_instancelist) == 1:
        start_instance = pre_start_instancelist[0]
    else:
        start_instance = pre_start_instancelist[random.randint(0, len(pre_start_instancelist) - 1)]
    print  start_instance.tags['Name']
    print "Pre start instance status is %s" % start_instance.state
    print "Start instance id is %s:" % start_instance.id
    start_instance.start()
    print start_instance.state
    i = 0
    while True:
        if str(start_instance.state) == 'running':
            conn.register_instances(key, start_instance.id.split())
            print "New machine has been add !"
            break
        else:
            i += 1
            time.sleep(5)
            start_instance.update()
            print start_instance.state
            print str(start_instance.state)
            if i > 30:
                # logging
                break


def del_machine_instance(key, pre_stop_instancelist):
    for num in pre_stop_instancelist:
        print num.tags['Name']
        print "Pre stop instance status is %s" % num.state
        print "Stop instance id is %s:" % num.id
        num.stop()
        k = 0
        while True:
            if str(num.state) == 'stopped':
                conn.deregister_instances(key, num.id.split())
                print "New machine has been delete !"
                break
            else:
                k += 1
                time.sleep(5)
                num.update()
                print num.state
                if k > 30:
                    #logging
                    break


def main():
    pre_start_instancelist = []
    pre_stop_instancelist = []
    running_instance_id = []
    keeps_instance_id = []
    all_instance = show_all_instance()
    for key, value in elastic_cloud_configs.items():
        single_elb_instance = show_elb_instance(key)
        for inst2 in single_elb_instance:
            running_instance_id.append(inst2.id)
        single_load_instances = show_elb_instance(key)
        avg_minute_load, avg_fiveminute_load = show_machine_load(single_load_instances)
        for inst in all_instance:
            if str(inst.tags['Name']).startswith(value['filters']) and str(inst.state) == 'stopped':
                pre_start_instancelist.append(inst)
            for n in value['keeps']:
                if str(inst.tags['Name']) == n:
                    keeps_instance_id.append(inst.id)
            pre_stop_instanceidlist = [i for i in running_instance_id if
                                       i not in keeps_instance_id] #stop instance which not in keeps instance
            for line in pre_stop_instanceidlist:
                if line == inst.id:
                    pre_stop_instancelist.append(inst)
        print avg_minute_load, avg_fiveminute_load
        if avg_minute_load > float(value['maxload']) * 2 or avg_fiveminute_load > float(value['maxload']):
            add_machine_instance(key, pre_start_instancelist)
            instance_running = show_elb_running_instance(key)
            print instance_running
        if avg_minute_load < float(value['minload']):
            del_machine_instance(key, pre_stop_instancelist)
            instance_running = show_elb_running_instance(key)
            print instance_running


if __name__ == '__main__':
    main()