switch_lb.py 8.14 KB
#!/usr/bin/python
# -*- coding: UTF-8 -*-

""" 
修改腾讯云七层负载均衡器的权重

@see doc:  https://cloud.tencent.com/document/product/214/8978
  
"""

from qcloud.qcloud_api import QcloudApi
from yansible.inventory_reader import InventoryReader
import time, sys, os




"""
  作用:切换负载均衡器的流量
  依赖: inventory 文件
  
  demo:
  
  
lbswitch = LBSwitch(secretId="AKID6dwppIHPO5qPv5GK", secretKey="ACJkH9mg0DBsQaW",
                    az1_lb_id="lb-dyh6eucn", az2_lb_id="lb-capto5b5", az3_lb_id="lb-capto5b5", az1_innerlb_id="lb-c26tgo5r")

# 全部流量切换到AZ1
ret = lbswitch.all_to_az1()

# 全部流量切换到AZ2
ret = lbswitch.all_to_az2()
  
"""


class LBSwitch:
        def __init__(self, secretId, secretKey, az1_lb_id, az2_lb_id, az3_lb_id, az1_innerlb_id):
           self.SecretId = secretId
           self.SecretKey = secretKey
           self.az1_lb_id = az1_lb_id
           self.az2_lb_id = az2_lb_id
           self.az3_lb_id = az3_lb_id
           self.az1_innerlb_id = az1_innerlb_id

        def all_to_az1(self):
            """
            所有流量切换到az1
            :return: 
            """
            inventory_reader = InventoryReader()
            az1_nginxs = inventory_reader.get_inventory_ifo("az1", 'java-nginx')
            print "get all java nginx: %s for az: %s" % (az1_nginxs, "az1")

            az1_nginx_weight = {}
            for az1_nginx in az1_nginxs:
                az1_nginx_weight[az1_nginx] = 10

            # az2 公网流量切换到az1
            ret_az2 = self.modify_alb_weight(lb_id=self.az2_lb_id, domain="*.yoho.cn", ip_weight_dict=az1_nginx_weight)
            print("switch all incoming request from az2 to az1 result: %s" % ret_az2)

            # az1 公网流量、内部流量切换到az1
            ret_az1 = self.modify_clb_weight(lb_id=self.az1_lb_id, ip_weight_dict=az1_nginx_weight)
            ret_az1_inner = self.modify_alb_weight(lb_id=self.az1_innerlb_id, domain="*.yoho.yohoops.org",
                                                   ip_weight_dict=az1_nginx_weight)
            print("switch all incoming request from az1 to az1 result: %s inner result: %s" % (ret_az1, ret_az1_inner))

            return ret_az1 and ret_az1_inner and ret_az2



        def all_to_az2(self):
             """
             所有流量切换到AZ2
             :return: 
             """
             inventory_reader = InventoryReader()
             az2_nginx = inventory_reader.get_inventory_ifo("az2", 'java-nginx')
             az2_nginx_weight = {}
             for nginx in az2_nginx:
                 az2_nginx_weight[nginx] = 10

             # az2 公网流量切换到az2
             ret_az2 = self.modify_alb_weight(lb_id=self.az2_lb_id, domain="*.yoho.cn", ip_weight_dict=az2_nginx_weight)
             print("switch all incoming request from az2 to az2 result: %s" % ret_az2)

             # az1 公网流量、内部流量切换到az2
             ret_az1 = self.modify_clb_weight(lb_id=self.az1_lb_id, ip_weight_dict=az2_nginx_weight)
             ret_az1_inner = self.modify_alb_weight(lb_id=self.az1_innerlb_id, domain="*.yoho.yohoops.org", ip_weight_dict=az2_nginx_weight)
             print("switch all incoming request from az1 to az2 result: %s  inner lb:%s" % (ret_az1, ret_az1_inner))

             return ret_az1 and ret_az2 and ret_az1_inner



        def modify_clb_weight(self, lb_id, ip_weight_dict):
            """
            修改传统负载均衡器的权重
            @:param lb_id 负载均衡器的ID
            @:param ip_weight_dict 需要设置权重的后端IP-权重字典, 格式为 {'ip': weight }
            :return: True: 修改成功
            """
            # 1.获取传统型负载均衡器的后端列表
            # see details at: https://cloud.tencent.com/document/api/214/1259
            instance_weight = {}  # instance_id --> weight

            api = QcloudApi(secretId=self.SecretId, secretKey=self.SecretKey)
            lb_info = api.do_query(params={'Action': 'DescribeLoadBalancerBackends', 'loadBalancerId': lb_id}, req_url=QcloudApi.URLS_lb)
            for backend in lb_info['backendSet']:
                if backend['lanIp'] in ip_weight_dict.keys():
                    # setup the instance_id --> weight
                    instance_weight[backend['unInstanceId']] = ip_weight_dict[backend['lanIp']]
                else:
                    instance_weight[backend['unInstanceId']] = 0

            # 2.检查至少有一个weight不为0
            if len(filter(lambda w: w != 0, instance_weight.values())) == 0:
                sys.exit(" instance weight: %s is all zero. please check again!" % instance_weight)

            # 3.修改权重: https://cloud.tencent.com/document/api/214/1264
            modify_params = {'Action': 'ModifyLoadBalancerBackends', 'loadBalancerId': lb_id}
            i = 1
            for ins_id, ins_weight in instance_weight.iteritems():
                modify_params['backends.%i.instanceId' % i] = ins_id
                modify_params['backends.%i.weight' % i] = ins_weight
                i = i + 1
            api = QcloudApi(secretId=self.SecretId, secretKey=self.SecretKey)
            rsp = api.do_query(params=modify_params, req_url=QcloudApi.URLS_lb)
            return rsp['code'] == 0

        def modify_alb_weight(self, lb_id, domain, ip_weight_dict):
            """
              修改应用型负载均衡器上服务器的权重
              @:param lb_id: 应用型负载均衡器ID
              @:param domain: 应用型负载均衡器的domain
              @:param ip_weight_dict: 需要设置权重的dict, 格式为 {'ip': weight }
             @return list
            """

            # 查询ALB的监听器信息
            # see qcloud api details at: https://cloud.tencent.com/document/product/214/8987
            instance_weight = {}  # instance_id --> weight
            instance_port = {}   # instance_id --> port
            listener_ids = {}   # all linsters

            api = QcloudApi(secretId=self.SecretId, secretKey=self.SecretKey)
            lb_info = api.do_query(params={'Action': 'DescribeForwardLBBackends', 'loadBalancerId': lb_id}, req_url=QcloudApi.URLS_lb)

            # listener : [http , https]
            for listener in lb_info['data']:
                for rule in listener['rules']:
                    if rule['domain'] == domain:  # domain match
                        listener_ids[listener['listenerId']] = listener['protocolType']
                        for backend in rule['backends']:
                            instance_port[backend['unInstanceId']] = backend['port']
                            if backend['lanIp'] in ip_weight_dict.keys():
                                # setup the instance_id --> weight
                                instance_weight[backend['unInstanceId']] = ip_weight_dict[backend['lanIp']]
                            else:
                                instance_weight[backend['unInstanceId']] = 0

            # 检查至少有一个weight
            if len(filter(lambda w: w != 0, instance_weight.values())) == 0:
                sys.exit(" instance weight: %s is all zero. please check again!" % instance_weight)

            # 修改七层负载均衡器的权重
            # see details at: https://cloud.tencent.com/document/product/214/8978
            return_code = []
            for lis_id in listener_ids.keys():
                params = {'Action': 'ModifyForwardSeventhBackends', 'loadBalancerId': lb_id,
                          'listenerId': lis_id, 'domain': domain}
                i = 1
                for ins_id, ins_weight in instance_weight.iteritems():
                    params['backends.%i.instanceId' % i] = ins_id
                    params['backends.%i.weight' % i] = ins_weight
                    params['backends.%i.port' % i] = instance_port[ins_id]
                    i = i + 1

                rsp = api.do_query(params, req_url=QcloudApi.URLS_lb)
                print(u"response code: %s . success change domain: %s for listener : %s. wait for 10s" % (rsp['code'], domain, listener_ids[lis_id]))
                return_code.append(rsp['code'])
                time.sleep(10)
            return return_code.count(0) == len(return_code)