Authored by root

初始化负载均衡权重切换模块

  1 +#!/usr/bin/python
  2 +# -*- coding: UTF-8 -*-
  3 +
  4 +"""
  5 +修改腾讯云七层负载均衡器的权重
  6 +
  7 +@see doc: https://cloud.tencent.com/document/product/214/8978
  8 +
  9 +"""
  10 +
  11 +from qcloud.qcloud_api import QcloudApi
  12 +import time, sys, os
  13 +import json
  14 +
  15 +
  16 +
  17 +"""
  18 + 作用:切换负载均衡器的权重
  19 +"""
  20 +
  21 +def modify_clb_weight(SecretId, SecretKey, lb_id, ip_weight_dict={}, hostname_weight_dict={}, default_weight=0):
  22 + """
  23 + 修改传统负载均衡器的权重
  24 + @:param lb_id 负载均衡器的ID
  25 + @:param ip_weight_dict 需要设置权重的后端IP-权重字典, 格式为 {'ip': weight }
  26 + :return: True: 修改成功
  27 + """
  28 + # 1.获取传统型负载均衡器的后端列表
  29 + # see details at: https://cloud.tencent.com/document/api/214/1259
  30 + instance_weight = {} # instance_id --> weight
  31 +
  32 + api = QcloudApi(secretId=SecretId, secretKey=SecretKey)
  33 + lb_info = api.do_query(params={'Action': 'DescribeLoadBalancerBackends', 'loadBalancerId': lb_id}, req_url=QcloudApi.URLS_lb)
  34 + for backend in lb_info['backendSet']:
  35 + if ip_weight_dict:
  36 + if backend['lanIp'] in ip_weight_dict.keys():
  37 + # setup the instance_id --> weight
  38 + instance_weight[backend['unInstanceId']] = ip_weight_dict[backend['lanIp']]
  39 + else:
  40 + instance_weight[backend['unInstanceId']] = default_weight
  41 + elif hostname_weight_dict:
  42 + if backend['instanceName'] in hostname_weight_dict.keys():
  43 + # setup the instance_id --> weight
  44 + instance_weight[backend['unInstanceId']] = hostname_weight_dict[backend['unInstanceId']]
  45 + else:
  46 + instance_weight[backend['unInstanceId']] = default_weight
  47 + else:
  48 + break
  49 +
  50 + # 2.检查至少有一个weight不为0
  51 + if len(filter(lambda w: w != 0, instance_weight.values())) == 0:
  52 + sys.exit(" instance weight: %s is all zero. please check again!" % instance_weight)
  53 +
  54 + # 3.修改权重: https://cloud.tencent.com/document/api/214/1264
  55 + modify_params = {'Action': 'ModifyLoadBalancerBackends', 'loadBalancerId': lb_id}
  56 + i = 1
  57 + for ins_id, ins_weight in instance_weight.iteritems():
  58 + modify_params['backends.%i.instanceId' % i] = ins_id
  59 + modify_params['backends.%i.weight' % i] = ins_weight
  60 + i = i + 1
  61 + api = QcloudApi(secretId=SecretId, secretKey=SecretKey)
  62 + rsp = api.do_query(params=modify_params, req_url=QcloudApi.URLS_lb)
  63 + return rsp['code'] == 0
  64 +
  65 +
  66 +def modify_alb_weight(SecretId, SecretKey, lb_id, domain, ip_weight_dict={}, hostname_weight_dict={},default_weight=0):
  67 + """
  68 + 修改应用型负载均衡器上服务器的权重
  69 + @:param lb_id: 应用型负载均衡器ID
  70 + @:param domain: 应用型负载均衡器的domain
  71 + @:param ip_weight_dict: 需要设置权重的dict, 格式为 {'ip': weight }
  72 + @return list
  73 + """
  74 +
  75 + # 查询ALB的监听器信息
  76 + # see qcloud api details at: https://cloud.tencent.com/document/product/214/8987
  77 + instance_weight = {} # instance_id --> weight
  78 + instance_port = {} # instance_id --> port
  79 + listener_ids = {} # all linsters
  80 + hostname_ip_map = {} # instance_name --> ip
  81 +
  82 +
  83 + api = QcloudApi(secretId=SecretId, secretKey=SecretKey)
  84 + lb_info = api.do_query(params={'Action': 'DescribeForwardLBBackends', 'loadBalancerId': lb_id}, req_url=QcloudApi.URLS_lb)
  85 +
  86 + # listener : [http , https]
  87 + for listener in lb_info['data']:
  88 + for rule in listener['rules']:
  89 + if rule['domain'] == domain: # domain match
  90 + listener_ids[listener['listenerId']] = listener['protocolType']
  91 + for backend in rule['backends']:
  92 + instance_port[backend['unInstanceId']] = backend['port']
  93 + if ip_weight_dict:
  94 + if backend['lanIp'] in ip_weight_dict.keys():
  95 + # setup the instance_id --> weight
  96 + instance_weight[backend['unInstanceId']] = ip_weight_dict[backend['lanIp']]
  97 + if hostname_ip_map.has_key(backend['instanceName']):
  98 + hostname_ip_map[backend['instanceName']].append(backend['lanIp'])
  99 + else:
  100 + hostname_ip_map[backend['instanceName']] = [backend['lanIp']]
  101 + else:
  102 + instance_weight[backend['unInstanceId']] = default_weight
  103 + elif hostname_weight_dict:
  104 + if backend['instanceName'] in hostname_weight_dict.keys():
  105 + # setup the instance_id --> weight
  106 + instance_weight[backend['unInstanceId']] = hostname_weight_dict[backend['instanceName']]
  107 + else:
  108 + instance_weight[backend['unInstanceId']] = default_weight
  109 + else:
  110 + break
  111 +
  112 + # 检查至少有一个weight
  113 + if len(filter(lambda w: w != 0, instance_weight.values())) == 0:
  114 + sys.exit(" instance weight: %s is all zero. please check again!" % instance_weight)
  115 +
  116 + # 修改七层负载均衡器的权重
  117 + # see details at: https://cloud.tencent.com/document/product/214/8978
  118 + return_code = []
  119 + for lis_id in listener_ids.keys():
  120 + params = {'Action': 'ModifyForwardSeventhBackends', 'loadBalancerId': lb_id,
  121 + 'listenerId': lis_id, 'domain': domain}
  122 + i = 1
  123 + for ins_id, ins_weight in instance_weight.iteritems():
  124 + params['backends.%i.instanceId' % i] = ins_id
  125 + params['backends.%i.weight' % i] = ins_weight
  126 + params['backends.%i.port' % i] = instance_port[ins_id]
  127 + i = i + 1
  128 +
  129 + rsp = api.do_query(params, req_url=QcloudApi.URLS_lb)
  130 + print(u"response code: %s . success change domain: %s for listener : %s. wait for 10s" % (rsp['code'], domain, listener_ids[lis_id]))
  131 + return_code.append(rsp['code'])
  132 + time.sleep(10)
  133 + return return_code.count(0) == len(return_code)
  134 +
  135 +
  136 +def describe_lbs(SecretId, SecretKey):
  137 + api = QcloudApi(secretId=SecretId, secretKey=SecretKey)
  138 + lb_info = api.do_query(params={'Action': 'DescribeLoadBalancers', 'forward': -1, 'limit':100, 'withRs':1}, req_url=QcloudApi.URLS_lb)
  139 + return lb_info['loadBalancerSet']
No preview for this file type
  1 +#!/usr/bin/python
  2 +# -*- coding: UTF-8 -*-
  3 +
  4 +"""
  5 +修改腾讯云七层负载均衡器的权重
  6 +
  7 +demo: python lb_switch.py --secretid=AKID6**************dwpKK --secretkey=ACJk9**************sQaW --lb_name=ytx-switch-test --domain=search.yohoops.org --hostname=search-service-az2 --weight=10
  8 +
  9 +@see doc: https://cloud.tencent.com/document/product/214/8978
  10 +
  11 +"""
  12 +
  13 +import time, sys, os
  14 +import argparse
  15 +from lb_action import modify_clb_weight,modify_alb_weight,describe_lbs
  16 +
  17 +
  18 +if __name__ == "__main__":
  19 + parser = argparse.ArgumentParser()
  20 + parser.add_argument('--secretid',type=str,help='腾讯云 SecretId')
  21 + parser.add_argument('--secretkey',type=str,help='腾讯云 SecretKey')
  22 + parser.add_argument('--lb_name',type=str,help='负载均衡器名称')
  23 + parser.add_argument('--domain',type=str,default='',help='应用型负载均衡器的域名')
  24 + parser.add_argument('--hostname',type=str,help='负载均衡器后端绑定的主机名称')
  25 + parser.add_argument('--weight',type=int,help='需要调整的主机权重')
  26 + parser.add_argument('--default_weight',type=int,default=0,help='同域名/负载均衡器下其他主机默认权重')
  27 + args = parser.parse_args()
  28 + lbs = describe_lbs(args.secretid,args.secretkey)
  29 + lb_id = ''
  30 + for lb in lbs:
  31 + if lb['loadBalancerName'].encode('utf-8') == args.lb_name:
  32 + lb_id = lb['loadBalancerId']
  33 + break
  34 +
  35 + if not lb_id:
  36 + print '未找到负载均衡器{0}'.format(args.lb_name)
  37 + sys.exit(1)
  38 + else:
  39 +
  40 + hostname_weight_dict = {
  41 + args.hostname: args.weight
  42 + }
  43 +
  44 + if args.domain:
  45 + modify_alb_weight(args.secretid, args.secretkey, lb_id, args.domain, hostname_weight_dict=hostname_weight_dict, default_weight=args.default_weight)
  46 + else:
  47 + modify_clb_weight(args.secretid, args.secretkey, lb_id, hostname_weight_dict=hostname_weight_dict, default_weight=args.default_weight)
  1 +{
  2 + "lb-8gm6tsyr": {
  3 + "domain":"search.yohoops.org",
  4 + "mappings": {
  5 + "10.66.104.14": 10,
  6 + "10.66.104.4": 10,
  7 + "10.66.104.9": 10
  8 + }
  9 + }
  10 +}
No preview for this file type
  1 +#!/usr/bin/python
  2 +# -*- coding: UTF-8 -*-
  3 +
  4 +import smtplib
  5 +from email.mime.text import MIMEText
  6 +from email.header import Header
  7 +import time
  8 +
  9 +
  10 +class mailman(object):
  11 + def __init__(self):
  12 + self.sender = 'robot@yohoops.cn'
  13 + self.smtpObj = smtplib.SMTP('localhost')
  14 +
  15 + def mail(self,receivers=[],Content='Test Mail',From ='Robot',To='YOHOOPS',Title='Test Mail'):
  16 + message = MIMEText(Content, 'plain', 'utf-8')
  17 + message['From'] = Header(From, 'utf-8')
  18 + message['To'] = Header(To, 'utf-8')
  19 + message['Subject'] = Header(Title, 'utf-8')
  20 +
  21 + retry = 5
  22 + while retry>0:
  23 + try:
  24 + self.smtpObj.sendmail(self.sender, receivers, message.as_string())
  25 + print "邮件发送成功"
  26 + return True
  27 + except Exception as e:
  28 + retry-=1
  29 + print e
  30 + print "Error: 无法发送邮件"
  31 + print "重新发送邮件...还剩{0}次".format(retry)
  32 + time.sleep(10)
  33 + return False
  34 +
  35 +if __name__ == '__main__':
  36 + demo = mailman()
  37 + demo.mail(['tiexin.yang@yoho.cn'])
No preview for this file type
  1 +#!/usr/bin/python
  2 +# -*- coding: UTF-8 -*-
  3 +# author chunhua.zhang@yoho.cn
  4 +import random
  5 +import hmac
  6 +import base64
  7 +import hashlib
  8 +import time
  9 +import requests
  10 +import json
  11 +
  12 +
  13 +class QcloudApi:
  14 + """腾讯云API接口"""
  15 +
  16 + 'pre-defined url'
  17 + 'load balance'
  18 + URLS_lb = 'lb.api.qcloud.com/v2/index.php'
  19 + URLS_DNS = 'cns.api.qcloud.com/v2/index.php'
  20 +
  21 + 'public request params'
  22 + Region = 'ap-beijing'
  23 + Version = 'YOHO-QCLOUD-V1.0'
  24 +
  25 + 'see doc: https://www.qcloud.com/document/api/377/4153'
  26 + 'init. must provide SecretId and SecretKey'
  27 + def __init__(self, secretId, secretKey):
  28 + self.secretId = secretId
  29 + self.secretKey = secretKey
  30 +
  31 + def do_query(self, params, req_url=URLS_lb, api_version=2):
  32 + """
  33 + Do Query Qcloud api
  34 + :param params: 查询参数,dict类型,必须包含 Action
  35 + :param req_url: 查询的地址,参考:qcloud_api.URLS_lb --> lb.api.qcloud.com/v2/index.php
  36 + :return: dict类型,腾讯云返回的消息体
  37 + """
  38 + if 'Action' not in params:
  39 + print("must provide [Action] params !")
  40 + raise ValueError(params)
  41 +
  42 + if api_version == 2:
  43 + public_params = {'RequestClient': QcloudApi.Version, 'limit': 100, 'Region': QcloudApi.Region, 'Timestamp': int(time.time()), 'Nonce': QcloudApi.generate_nonce(), 'SecretId': self.secretId}
  44 + # merge params
  45 + params = dict(params, **public_params)
  46 + # signature
  47 + sign = self.signature(params, req_url)
  48 + params['Signature'] = sign
  49 + response_dict = requests.post("https://" + req_url, data=params).json()
  50 + elif api_version == 3:
  51 + public_params = {'Region': QcloudApi.Region, 'Timestamp': int(time.time()), 'Nonce': int(QcloudApi.generate_nonce()), 'Version': '2017-03-12', 'SecretId': self.secretId, 'SignatureMethod':'HmacSHA1'}
  52 + # merge params
  53 + params = dict(params, **public_params)
  54 + # signature
  55 + req_url = req_url.rstrip('/')+'/'
  56 + sign = self.signature(params, req_url)
  57 + params['Signature'] = sign
  58 + response_dict = requests.post("https://" + req_url, data=params).json()
  59 +
  60 + #print("call qcloud api success. params:\n %s \n" % (params))
  61 + #print json.dumps(response_dict, indent=4, sort_keys=True)
  62 + return response_dict
  63 +
  64 + @staticmethod
  65 + def generate_nonce(length=8):
  66 + """Generate pseudorandom number."""
  67 + return ''.join([str(random.randint(0, 9)) for i in range(length)])
  68 +
  69 + def signature(self, request_params, url):
  70 + """
  71 + 对消息进行签名 see https://www.qcloud.com/document/api/377/4214
  72 + @param request_params
  73 + @param url, 请求地址,例如:lb.api.qcloud.com/v2/index.php
  74 + """
  75 + # sort dict by key
  76 + kv_pairs = []
  77 + for key in sorted(request_params):
  78 + kv_pairs.append('%s=%s' % (key, request_params[key]))
  79 + str_req = '&'.join(kv_pairs)
  80 + str_full = 'POST%s?%s' % (url, str_req)
  81 + hmac_sign = hmac.new(bytes(self.secretKey), bytes(str_full), hashlib.sha1).digest()
  82 + return base64.b64encode(hmac_sign).decode()
  83 +
  84 +
  85 +
  86 +
  87 +
  88 +
  89 +
  90 +
No preview for this file type