# #!/usr/bin/env python
# #coding=utf-8

import json
import logging
import time
import requests
import sys
from aliyunsdkcore import client
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.acs_exception.exceptions import ClientException
from aliyunsdkcore.acs_exception.exceptions import ServerException
from aliyunsdkecs.request.v20140526.CreateInstanceRequest import CreateInstanceRequest
from aliyunsdkecs.request.v20140526.StartInstanceRequest import StartInstanceRequest
from aliyunsdkecs.request.v20140526.DescribeInstancesRequest import DescribeInstancesRequest
from aliyunsdkecs.request.v20140526.RunInstancesRequest import RunInstancesRequest
from aliyunsdkecs.request.v20140526.DescribeNetworkInterfacesRequest import DescribeNetworkInterfacesRequest
from aliyunsdkslb.request.v20140515.AddBackendServersRequest import AddBackendServersRequest
from aliyunsdkecs.request.v20140526.RunCommandRequest import RunCommandRequest

logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                    datefmt='%a, %d %b %Y %H:%M:%S')
# ##### 购买服务器权限
# access key Id
ak_id = "LTAI4GBWbFvvXoXsSVBe1o9f"
# access key secret
ak_secret = "kRAikWitb4kDxaAyBqNrmLmllMEDO3"
# 设置地域
region_id = "cn-hangzhou"
clt = client.AcsClient(ak_id, ak_secret, region_id)

# 获取批量创建ECS实例的数量, 取值范围：1-100, 默认值：1
amount = int(sys.argv[1])
# 使用的镜像信息
image_id = "m-bp1dnxi0r8zn5s0gpuwm"

# 设置实例规格
instance_type = "ecs.ic5.large"
# 选择的交换机
vswitch_id = "vsw-bp19lpjwtc6j0p0m9mdc2"
# 当前VPC类型的安全组
security_group_id = "sg-bp1irhrkr4vfj272hk4y"
# 硬盘的大小，单位：G
disk_size = "200"
# 服务器命名
instance_name = "ESS-rov-server-[1,2]"
# 服务器所在区域
zone_id = "cn-hangzhou-h"
# 磁盘类型：云盘
disk_category = "cloud_efficiency"
# 密钥
key_pair_name = "stuuudy"
# 负载均衡ID
slb_id_2 = "lb-bp1werfophtsjzfr76njm"

# ##### 修改负载均衡权限
AccessKey = 'LTAIuPbTPL3LDDKN'
AccessSecret = 'ORcNedKwWuwVtcq4IRFtUDZgS0b1le'
RegionId = 'cn-hangzhou'
client = AcsClient(AccessKey, AccessSecret, RegionId)


def build_request():
    """购买服务器参数配置"""
    request = RunInstancesRequest()
    request.set_ImageId(image_id)
    request.set_VSwitchId(vswitch_id)
    request.set_SecurityGroupId(security_group_id)
    request.set_ZoneId(zone_id)
    request.set_InstanceType(instance_type)
    # request.set_UserData(init_data)
    request.set_InstanceName(instance_name)
    request.set_SystemDiskSize(disk_size)
    request.set_SystemDiskCategory(disk_category)
    request.set_KeyPairName(key_pair_name)
    request.set_Tags([
      {
        "Key": "app",
        "Value": "rov-server"
      }
    ])
    return request


def _send_request(request):
    """发送API请求"""
    request.set_accept_format('json')
    try:
        response_str = clt.do_action_with_exception(request)
        logging.info(response_str)
        response_detail = json.loads(response_str)
        return response_detail
    except Exception as e:
        logging.error(e)


def check_instance_running(instance_ids):
    """检查服务器运行状态"""
    request = DescribeInstancesRequest()
    request.set_InstanceIds(json.dumps(instance_ids))
    response = _send_request(request)
    if response.get('Code') is None:
        instances_list = response.get('Instances').get('Instance')
        running_count = 0
        for instance_detail in instances_list:
            if instance_detail.get('Status') == "Running":
                running_count += 1
        return running_count


def runCommand(instance_ids):
    """批量执行shell脚本：启动服务"""
    request = RunCommandRequest()
    request.set_accept_format('json')
    request.set_Type("RunShellScript")
    request.set_CommandContent("sh  /home/sh/rov-server-start.sh")
    request.set_InstanceIds(instance_ids)
    response = clt.do_action_with_exception(request)
    logging.info(response)


def healthCheck(instance_id):
    """服务健康检查 & 服务器挂载到负载均衡"""
    ipaddr = getIpaddr(instance_id)
    while True:
        health_url = 'http://%s:5001/healthcheck' %(ipaddr)
        try:
            http_code = requests.get(health_url).status_code
        except:
            logging.info("images is downloading")
            http_code = 0

        if http_code == 200:
            break
        else:
            time.sleep(20)

    # 服务预热60s, 服务刚启动时CPU很高
    time.sleep(60)
    # 挂载到负载均衡
    addBackendServers(slb_id_2, instance_id)


def addBackendServers(slb_id, instance_id):
    """服务器挂载到负载均衡"""
    request = AddBackendServersRequest()
    request.set_accept_format('json')
    ipaddr = getIpaddr(instance_id)
    request.set_LoadBalancerId(slb_id)

    request.set_BackendServers([{"ServerId": instance_id, "Weight": "100", "Type": "ecs", "ServerIp": ipaddr}])
    response = client.do_action_with_exception(request)
    logging.info(response)


def getIpaddr(instance_id):
    """根据 instance_id 获取实例IP地址"""
    request = DescribeNetworkInterfacesRequest()
    request.set_accept_format('json')
    request.set_InstanceId(instance_id)
    response = clt.do_action_with_exception(request)
    request_content = json.loads(response)
    ipaddr = request_content['NetworkInterfaceSets']['NetworkInterfaceSet'][0]['PrivateIpAddress']
    return ipaddr


def _execute_request(request):
    response = _send_request(request)
    if response.get('Code') is None:
        instance_ids = response.get('InstanceIdSets').get('InstanceIdSet')
        running_amount = 0
        while running_amount < amount:
            time.sleep(10)
            running_amount = check_instance_running(instance_ids)

        logging.info(f"{instance_ids} is running")
        time.sleep(60)
        runCommand(instance_ids)

        for instance_id in instance_ids:
            healthCheck(instance_id)


def create_multiple_instances():
    """创建ECS实例并启动"""
    request = build_request()
    request.set_Amount(amount)
    _execute_request(request)


if __name__ == '__main__':
    logging.info("Start Create Instances")
    # 创建ECS实例并启动
    create_multiple_instances()
