阿里云Open API自动化脚本—ECS公网IP转化弹性公网IP

1、OpenAPI Explorer

  记录一下使用阿里云 Open API 自动化/脚本化 “ECS 公网 IP 转化弹性公网 IP”的实现 全过程。原博客地址:https://www.markeditor.com/file/get/e156893757a36a62d761e2d79950d0da?t=1564731800

   开始编码之前,我们要有一个良好的调试环境,来验证程序是否运行良好。阿里云提供了 OpenAPI Explorer,提供了运行 demo,UI 运行器,Cloud Shell(一个带完整运行环境的 shell)等功能,帮助我们调试。并且使用 OpenAPI Explorer 会自动获取当前用户的身份,从而生成临时 secret 用于调用鉴权,更加方便安全。事实上整个调试运行过程(包括最终一键转换 150+ 实例),都是使用 OpenAPI Explorer 的 UI 运行器和 Cloud Shell 来做的。打开地址:https://api.aliyun.com/?spm=a2c4g.11186623.2.9.ad1712fduNHxC3#/?product=Cms 

  阿里云 Open API 的 sdk 支持非常丰富的语言类型,这里使用了 golang。

  产品选择云服务器,DescribeInstances,选择必填项 RegionId,其余过滤条件暂时不选,然后发起调用。使用 Cloud Shell 方式进行同样的操作。Cloud Shell 与 UI 运行器不同,是个完整的 shell 环境,依赖 SDK 来执行,两种方式最终执行结果都是一样。

   第一种结果是json 格式,获取到了当前所有的实例,以及完整的实例信息

  第二种使用使用 Cloud Shell 方式进行同样的操作,发现获取的结果一致。

2、完整源码

  想了解更详细,请参考 https://www.markeditor.com/file/get/e156893757a36a62d761e2d79950d0da?t=1564731800

  这里直接贴出最终源码:

package main

import (
    "fmt"
    "github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
    "github.com/aliyun/alibaba-cloud-sdk-go/services/ecs"
    "os"
    "time"
)
// 第一步:获取所有需要转换的实例,详见 describeAllInstances getInstancesNum函数
// 第二步:转化公网IP为按量付费,详见 reduceNetwork 函数
// 第三步:将按量公网IP转化为弹性IP,详见 convertToEIP 函数
// 第四步:主函数调用,详见 main 函数

// 选取运行状态为Running 的实例
var STATUS = "Running"
// 设置实例列表接口分页查询每页 50 个
var PAGE_SIZE = "50"
// 灰度处理,仅对指定数量的实例进行转化
var TOTAL_SIZE = 2

// 网络付费类型为按量付费
var NETWORK_CHARGE_TYPE = "PayByTraffic"

func main() {
    // 生成 ecs 的操作工具,临时 access token 会在 Cloud Shell 中自动生成,可通过环境变量获取
    client, err := ecs.NewClientWithAccessKey("cn-beijing", os.Getenv("ACCESS_KEY_ID"), os.Getenv("ACCESS_KEY_SECRET"))
    if err != nil {
        fmt.Print(err.Error())
    }
    var instances []MyInstance
    // 取出所有需要转化的实例
    instances = describeAllInstances(client)
    // 手动设置一个实例进行转换
    //instances = append(instances, MyInstance{"iZ2ze9j5p0uyrr0iz3aq2nZ", 1})
    fmt.Printf("Number of instances processed : %d\n", len(instances))
    cutInstances := instances
    // 灰度处理,仅对指定数量的实例进行转化
    if TOTAL_SIZE > 0 && TOTAL_SIZE < len(instances){
        cutInstances = instances[:TOTAL_SIZE]
    }
    fmt.Printf("Number of instances actually processed : %d\n", len(cutInstances))
    reduceNetwork(client, cutInstances)
    time.Sleep(time.Duration(1)*time.Second)
    convertToEIP(client, cutInstances)
}

// 接受实例列表,将指定实例的公网IP转为弹性 IP
func convertToEIP(client *ecs.Client, instances []MyInstance) {
    for _, instance := range instances {
        request := ecs.CreateConvertNatPublicIpToEipRequest()
        request.Scheme = "https"
        request.InstanceId = instance.id
        response, err := client.ConvertNatPublicIpToEip(request)
        if err != nil {
            // 失败重试
            response, err = client.ConvertNatPublicIpToEip(request)
            if err != nil {
                fmt.Println(err.Error())
                // 再重试 
                time.Sleep(time.Duration(1)*time.Second)
                response, err = client.ConvertNatPublicIpToEip(request)
            }
        }
        fmt.Printf("The result status of converting to eip is %v, the instance's id is [%s]\n", response.IsSuccess(), instance.id)
    }
}
// 接受实例列表,将实例转为指定网络付费类型,与指定带宽值(对于按量,是带宽峰值)
func reduceNetwork(client *ecs.Client, instances []MyInstance) {
    for _, instance := range instances {
        request := ecs.CreateModifyInstanceNetworkSpecRequest()
        request.Scheme = "https"
        // 设置公网出口带宽
        request.InternetMaxBandwidthOut = requests.NewInteger(instance.bandWidth)
        // 设置要修改的实例id,每次只能修改一个
        request.InstanceId = instance.id
        // 设置公网付费类型
        request.NetworkChargeType = NETWORK_CHARGE_TYPE
        // 发起请求
        response, err := client.ModifyInstanceNetworkSpec(request)
        if err != nil {
            // 失败重试
            response, err = client.ModifyInstanceNetworkSpec(request)
            if err != nil {
                fmt.Print(err.Error())
                time.Sleep(time.Duration(1)*time.Second)
                // 再重试
                response, err = client.ModifyInstanceNetworkSpec(request)
            }
        }
        fmt.Printf("The result status of reducing instance's bandwidth is %v, the instance's id is [%s]\n", response.IsSuccess(), instance.id)
    }
}

// 根据固定好的条件查询所有相应实例,返回其实例 id 与公网带宽出口值
func describeAllInstances(client *ecs.Client) []MyInstance{
    num := getInstancesNum(client)
    fmt.Printf("total instance count: %d\n", num)
    // 存放所需的所有实例的id与带宽信息
    var shouldConvertInstance []MyInstance
    // 用于记录分页查询到了第几页
    var pageCount int
    // 分页查询所有实例
    for true {
        pageCount++
        
        request := ecs.CreateDescribeInstancesRequest()
        // 设置过滤条件
        request.Status = STATUS
        // 设置分页查询信息
        request.PageNumber = requests.NewInteger(pageCount)
        request.PageSize = requests.Integer(PAGE_SIZE)
        request.Scheme = "https"
        // 执行查询
        response, err := client.DescribeInstances(request)
        if err != nil {
            fmt.Print(err.Error())
        }
        // 取出实例列表
        instances := response.Instances.Instance

        if len(instances) == 0 {
            break
        }
        // 从本分页过滤并取出所需实例信息
        for _, instance := range instances {
            if len(instance.PublicIpAddress.IpAddress) == 0 {
                continue
            }
            shouldConvertInstance = append(shouldConvertInstance, MyInstance{instance.InstanceId, instance.InternetMaxBandwidthOut})
        }
        time.Sleep(time.Duration(2)*time.Second)
    }
    return shouldConvertInstance
}
// 获取实例正在运行的总数量
func getInstancesNum(client *ecs.Client) int {
    request := ecs.CreateDescribeInstancesRequest()
    request.Status = STATUS
    request.PageNumber = "1"
    request.PageSize = "1"
    request.Scheme = "https"
    response, err := client.DescribeInstances(request)
    if err != nil {
        fmt.Print(err.Error())
    }
    time.Sleep(time.Duration(2)*time.Second)
    return response.TotalCount
}

type MyInstance struct{
    id string
    bandWidth int
}
View Code

  将整个运行脚本复制到 Cloud Shell 中,比如叫demo.go,然后运行go run demo.go

    

  好了,此时我们已经完成所有实例的 EIP 转化。转换完成后,再重试一次,确定已经没有实例需要处理了。

  

  执行完成之后,所有的ecs实例都自动将外网ip转换成EIP了,接下来就可以将EIP加入到共享带宽了。为什么将公网ip转换成EIP请参考:https://www.markeditor.com/file/get/e156893757a36a62d761e2d79950d0da?t=1564731800 感谢这位技术大牛提供的源码,为运维解决了烦恼,接下来就是去学习阿里的open api和oos运维编排服务了。

posted @ 2019-08-03 19:17  淺景尘  阅读(1002)  评论(0编辑  收藏  举报
TOP