jenkins Job华为云EIP变更带宽

news2025/7/19 14:25:55

引言:

在数字化时代,云服务资源的弹性管理是企业降低运营成本、提高效率的关键手段。通过弹性公网IP(EIP)服务,企业可以实现按需计费,优化网络支出。然而,根据业务流量的不同阶段调整计费模式,则是提升成本效益的进阶策略。本人腾讯云快十年老用户乘机吐槽一下腾讯云(由于我在大有所为的某云上面已经简单实现了更改流程):
习惯了使用apiexplorer这样的工具生成代码进行修改,参考一下友商的:
image.png
然后我的腾讯云弹性公网IP ?EIP 对吧?
image.png
这是什么样的体验?完全搜索不到?关键词EIP **弹性公网 **完全搜索不到…
image.png
image.png
最后我在这里找到了:
绑定弹性公网IP
image.png
你可以归于私有网络?是不是应该好歹独立一下…
image.png
吐槽完毕,本文将详细介绍如何使用华为云Go SDK在流量高峰时自动调整EIP带宽设置,并在峰值过后恢复原计费模式。

业务背景:

考虑到一家在线互动应用提供商,主要架构是websockt 长链接,其流量在晚高峰时段飙升,观众涌入平台进行抢红包等互动活动。活动时常大概在一个小时。在流量高峰时,固定带宽的使用能保证用户的观看体验,且相对于按流量计费,成本更为可控。因此,我们面临一个机遇,通过智能化工具调整EIP的带宽计费模式,在需要时提供稳定的网络资源和更优的财务开支。

技术方案:

服务器场景搭建在华为云上,使用了cce kubernetes服务。绑定了应用型负载均衡(负载均衡有本身的EIP公网IP),为了实现这一目标,我们选择华为云的Elastic IP服务,它提供了一系列API,允许程序化管理EIP资源。通过Go语言编写的定时任务,我们可以精确控制带宽的调整时机和规模。在本方案中,使用华为云提供的SDK,我们将编写一个Go应用程序,当业务流量达到高峰时,自动将EIP的计费模式从按流量计费调整为按带宽计费,并固定带宽大小。一小时后,系统自动将设置恢复为按流量计费,以节省成本。

代码实现:

参照以下代码实例:UpdateBandwidth 更新带宽方法:
image.png

package main

import (
	"fmt"
	"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/basic"
    eip "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/eip/v2"
	"github.com/huaweicloud/huaweicloud-sdk-go-v3/services/eip/v2/model"
    region "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/eip/v2/region"
)

func main() {
    // The AK and SK used for authentication are hard-coded or stored in plaintext, which has great security risks. It is recommended that the AK and SK be stored in ciphertext in configuration files or environment variables and decrypted during use to ensure security.
    // In this example, AK and SK are stored in environment variables for authentication. Before running this example, set environment variables CLOUD_SDK_AK and CLOUD_SDK_SK in the local environment
    ak := os.Getenv("CLOUD_SDK_AK")
    sk := os.Getenv("CLOUD_SDK_SK")

    auth := basic.NewCredentialsBuilder().
        WithAk(ak).
        WithSk(sk).
        Build()

    client := eip.NewEipClient(
        eip.EipClientBuilder().
            WithRegion(region.ValueOf("cn-east-3")).
            WithCredential(auth).
            Build())

    request := &model.UpdatePublicipRequest{}
	request.Body = &model.UpdatePublicipsRequestBody{
	}
	response, err := client.UpdatePublicip(request)
	if err == nil {
        fmt.Printf("%+v\n", response)
    } else {
        fmt.Println(err)
    }
}

最终实现代码如下:

package main

import (
	"fmt"
	"time"

	"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/basic"
	"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/config"
	eip "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/eip/v2"
	"github.com/huaweicloud/huaweicloud-sdk-go-v3/services/eip/v2/model"
	region "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/eip/v2/region"
)

func main() {
	// Replace with your own AK/SK, Region, and Project ID.
	ak := "xxxxx"
	sk := "xxxxx"
	projectID := "xxxxx"

	// Authenticate using your Access Key and Secret Key.
	auth := basic.NewCredentialsBuilder().
		WithAk(ak).
		WithSk(sk).
		WithProjectId(projectID).
		Build()

	// Create EIP client configuration.
	eipClient := eip.NewEipClient(
		eip.EipClientBuilder().
			WithRegion(region.ValueOf("cn-east-3")).
			WithCredential(auth).
			WithHttpConfig(config.DefaultHttpConfig()).
			Build(),
	)

	// Replace the bandwidthId with your actual bandwidth ID.
	sizeBandwidth := int32(xxx)
	sizeTraefikBandwidth := int32(xxxx)

	// Update bandwidth to 10 Mbps and set to bandwidth billing mode.
	if err := updateBandwidth(eipClient, bandwidthId, "", sizeBandwidth, model.GetUpdateBandwidthOptionChargeModeEnum().BANDWIDTH); err != nil {
		fmt.Printf("Error updating bandwidth: %s\n", err)
		return
	}
	// Set a timer to switch back to traffic billing mode after 1 hour.
	time.AfterFunc(1*time.Hour, func() {
		if err := updateBandwidth(eipClient, bandwidthId, "", sizeTraefikBandwidth, model.GetUpdateBandwidthOptionChargeModeEnum().TRAFFIC); err != nil {
			fmt.Printf("Error reverting bandwidth: %s\n", err)
			return
		}
	})

	// Block the main goroutine to not exit immediately.
	select {}
}

// Function to update the bandwidth of an EIP.
func updateBandwidth(client *eip.EipClient, bandwidthId, name string, size int32, chargeMode model.UpdateBandwidthOptionChargeMode) error {
	request := &model.UpdateBandwidthRequest{
		BandwidthId: bandwidthId,
		Body: &model.UpdateBandwidthRequestBody{
			Bandwidth: &model.UpdateBandwidthOption{
				Name:       &name,
				Size:       &size,
				ChargeMode: &chargeMode,
			},
		},
	}

	response, err := client.UpdateBandwidth(request)
	if err != nil {
		return err
	}
	fmt.Printf("Update response: %+v\n", response)
	return nil
}

初始化EIP客户端

首先,需设置客户端认证,这涉及到基础的Access Key(AK)和Secret Key(SK)配置:

ak := "REPLACE_WITH_YOUR_AK"
sk := "REPLACE_WITH_YOUR_SK"
projectID := "REPLACE_WITH_YOUR_PROJECT_ID"

    auth := basic.NewCredentialsBuilder().
        WithAk(ak).
        WithSk(sk).
        Build()

    client := eip.NewEipClient(
        eip.EipClientBuilder().
            WithRegion(region.ValueOf("cn-east-3")).
            WithCredential(auth).
            Build())
...

务必保障这些敏感信息在环境变量或加密存储中,避免硬编码在应用程序中。

更新带宽函数

updateBandwidth 函数对EIP带宽大小和计费模式进行修改。

func updateBandwidth(client *eip.EipClient, bandwidthId, name string, size int32, chargeMode model.UpdateBandwidthOptionChargeMode) error {
	request := &model.UpdateBandwidthRequest{
		BandwidthId: bandwidthId,
		Body: &model.UpdateBandwidthRequestBody{
			Bandwidth: &model.UpdateBandwidthOption{
				Name:       &name,
				Size:       &size,
				ChargeMode: &chargeMode,
			},
		},
	}

	response, err := client.UpdateBandwidth(request)
	if err != nil {
		return err
	}
	fmt.Printf("Update response: %+v\n", response)
	return nil
}

这个函数构造了更新带宽的API请求,并处理响应或可能出现的错误。

使用协程和定时器

Go的并发模型让我们能够用协程(goroutines)和定时器轻松实现这个需求。

	go func() {
		if err := updateBandwidth(eipClient, bandwidthId, "xxxxx", sizeBandwidth, model.GetUpdateBandwidthOptionChargeModeEnum().BANDWIDTH); err != nil {
			fmt.Printf("更新带宽时出错: %s\n", err)
			return
		}

		// 设置计时器在10分钟后切换回流量计费模式。
		timer := time.NewTimer(1 * time.Minute)
		<-timer.C

		if err := updateBandwidth(eipClient, bandwidthId, "xxxxxx", sizeTrafficBandwidth, model.GetUpdateBandwidthOptionChargeModeEnum().TRAFFIC); err != nil {
			fmt.Printf("恢复带宽时出错: %s\n", err)
			return
		}
	}()

	// 使用通道阻塞主 goroutine 无限期。避免在空的 select 语句中旋转,这是不必要的。
	done := make(chan struct{})
	<-done
}

第一版代码

完整代码如下:

package main

import (
	"fmt"
	"time"

	"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/basic"
	"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/config"
	eip "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/eip/v2"
	"github.com/huaweicloud/huaweicloud-sdk-go-v3/services/eip/v2/model"
	region "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/eip/v2/region"
)

func main() {
	// Replace with your own AK/SK, Region, and Project ID.
	ak := "xxxxxx"
	sk := "xxxxxx"
	projectID := "xxxxxx"

	// Authenticate using your Access Key and Secret Key.
	auth := basic.NewCredentialsBuilder().
		WithAk(ak).
		WithSk(sk).
		WithProjectId(projectID).
		Build()

	// Create EIP client configuration.
	eipClient := eip.NewEipClient(
		eip.EipClientBuilder().
			WithRegion(region.ValueOf("cn-east-3")).
			WithCredential(auth).
			WithHttpConfig(config.DefaultHttpConfig()).
			Build(),
	)

	// Replace the bandwidthId with your actual bandwidth ID.
	bandwidthId := "xxxx"
	sizeBandwidth := int32(xxx)
    sizeTrafficBandwidth := int32(xxx)

	// Update bandwidth to 10 Mbps and set to bandwidth billing mode.
	if err := updateBandwidth(eipClient, bandwidthId, "xxxx", sizeBandwidth, model.GetUpdateBandwidthOptionChargeModeEnum().BANDWIDTH); err != nil {
		fmt.Printf("Error updating bandwidth: %s\n", err)
		return
	}
	// Set a timer to switch back to traffic billing mode after 1 hour.
	time.AfterFunc(1*time.Hour, func() {
		if err := updateBandwidth(eipClient, bandwidthId, "xxxxx", sizeBandwidth, model.GetUpdateBandwidthOptionChargeModeEnum().TRAFFIC); err != nil {
			fmt.Printf("Error reverting bandwidth: %s\n", err)
			return
		}
	})

	// Block the main goroutine to not exit immediately.
	select {}
}

// Function to update the bandwidth of an EIP.
func updateBandwidth(client *eip.EipClient, bandwidthId, name string, size int32, chargeMode model.UpdateBandwidthOptionChargeMode) error {
	request := &model.UpdateBandwidthRequest{
		BandwidthId: bandwidthId,
		Body: &model.UpdateBandwidthRequestBody{
			Bandwidth: &model.UpdateBandwidthOption{
				Name:       &name,
				Size:       &size,
				ChargeMode: &chargeMode,
			},
		},
	}

	response, err := client.UpdateBandwidth(request)
	if err != nil {
		return err
	}
	fmt.Printf("Update response: %+v\n", response)
	return nil
}

运行main.go
xreUAjVvck.png
可以在控制台查看代码操作,控制台对应实例生效!

继续完善代码:

上面的代码是用户传入bandwidthId,这关键一般用户不知道bandwidthId 阿?控制台用户来说一般能知道的是公网IP
image.png
我这里想到的是使用ListPublicips-查询弹性公网IP列表获取bandwidth_name bandwidth_id。 创建两个函数:getBandwidthIdByPublicIP getBandwidthNameByPublicIP

// 这里假设有一个通过公网IP获取带宽ID的函数
func getBandwidthIdByPublicIP(client *eip.EipClient, publicIP string) (string, error) {
	// 首先构造查询请求
	request := &model.ListPublicipsRequest{
		// 根据需要设置查询参数
	}

	// 调用SDK方法查询EIP详情
	response, err := client.ListPublicips(request)
	if err != nil {
		return "", err
	}

	// 遍历响应中的公共IP地址
	for _, publicip := range *response.Publicips { // 假设返回的是指针指向的切片
		// 检查 PublicIpAddress 是否为nil,并解引用来比较值
		if publicip.PublicIpAddress != nil && *publicip.PublicIpAddress == publicIP {
			// 检查 BandwidthId 是否为nil,并解引用来返回值
			if publicip.BandwidthId != nil {
				return *publicip.BandwidthId, nil
			}
			break // 如果 BandwidthId 为nil,则结束循环
		}
	}

	// 如果没有找到匹配的公共IP地址或带宽ID是nil,则返回错误
	return "", errors.New("public IP not found or bandwidth ID is nil")
}
func getBandwidthNameByPublicIP(client *eip.EipClient, publicIP string) (string, error) {
	// 首先构造查询请求
	request := &model.ListPublicipsRequest{
		// 根据需要设置查询参数
	}

	// 调用SDK方法查询EIP详情
	response, err := client.ListPublicips(request)
	if err != nil {
		return "", err
	}

	// 遍历响应中的公共IP地址
	for _, publicip := range *response.Publicips { // 假设返回的是指针指向的切片
		// 检查 PublicIpAddress 是否为nil,并解引用来比较值
		if publicip.PublicIpAddress != nil && *publicip.PublicIpAddress == publicIP {
			// 检查 BandwidthId 是否为nil,并解引用来返回值
			if publicip.BandwidthName != nil {
				return *publicip.BandwidthName, nil
			}
			break // 如果 BandwidthId 为nil,则结束循环
		}
	}

	// 如果没有找到匹配的公共IP地址或带宽ID是nil,则返回错误
	return "", errors.New("public IP not found or bandwidth ID is nil")
}

继续完善一下,通过运行main.go传入公网IP,固定带宽恢复按量计费后的带宽大小,以及修改为固定带宽的持续时间 。

go run main.go publicIP  sizeBandwidth sizeTrafficBandwidth timerMinutes
package main

import (
	"errors"
	"fmt"
	"os"
	"strconv"
	"time"

	"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/basic"
	"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/config"
	eip "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/eip/v2"
	"github.com/huaweicloud/huaweicloud-sdk-go-v3/services/eip/v2/model"
	region "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/eip/v2/region"
)

func main() {
	// Replace with your own AK/SK, Region, and Project ID.
	ak := "xxxxxx"
	sk := "xxxxxx"
	projectID := "xxxxxx"
	if len(os.Args) != 5 {
		fmt.Println("Usage: go run main.go <publicIP> <sizeBandwidth> <sizeTrafficBandwidth> <timerMinutes>")
		return
	}

	publicIP := os.Args[1]
	sizeBandwidth, err := strconv.Atoi(os.Args[2])
	if err != nil {
		fmt.Println("Invalid sizeBandwidth:", err)
		return
	}
	sizeTrafficBandwidth, err := strconv.Atoi(os.Args[3])
	if err != nil {
		fmt.Println("Invalid sizeTrafficBandwidth:", err)
		return
	}
	timerMinutes, err := strconv.Atoi(os.Args[4])
	if err != nil {
		fmt.Println("Invalid timerMinutes:", err)
		return
	}
	// Authenticate using your Access Key and Secret Key.
	auth := basic.NewCredentialsBuilder().
		WithAk(ak).
		WithSk(sk).
		WithProjectId(projectID).
		Build()

	// Create EIP client configuration.
	eipClient := eip.NewEipClient(
		eip.EipClientBuilder().
			WithRegion(region.ValueOf("cn-east-3")).
			WithCredential(auth).
			WithHttpConfig(config.DefaultHttpConfig()).
			Build(),
	)

	bandwidthId, err := getBandwidthIdByPublicIP(eipClient, publicIP)
	if err != nil {
		fmt.Println(err)
		return
	}
	bandwidthName, err := getBandwidthNameByPublicIP(eipClient, publicIP)
	if err != nil {
		fmt.Println(err)
		return
	}
	go func() {
		if err := updateBandwidth(eipClient, bandwidthId, bandwidthName, int32(sizeBandwidth), model.GetUpdateBandwidthOptionChargeModeEnum().BANDWIDTH); err != nil {
			fmt.Printf("更新带宽时出错: %s\n", err)
			return
		}

		// 设置计时器在10分钟后切换回流量计费模式。
		timer := time.NewTimer(time.Duration(timerMinutes) * time.Minute)
		<-timer.C

		if err := updateBandwidth(eipClient, bandwidthId, bandwidthName, int32(sizeTrafficBandwidth), model.GetUpdateBandwidthOptionChargeModeEnum().TRAFFIC); err != nil {
			fmt.Printf("恢复带宽时出错: %s\n", err)
			return
		}
	}()

	// 使用通道阻塞主 goroutine 无限期。避免在空的 select 语句中旋转,这是不必要的。
	done := make(chan struct{})
	<-done
}

// 这里假设有一个通过公网IP获取带宽ID的函数
func getBandwidthIdByPublicIP(client *eip.EipClient, publicIP string) (string, error) {
	// 首先构造查询请求
	request := &model.ListPublicipsRequest{
		// 根据需要设置查询参数
	}

	// 调用SDK方法查询EIP详情
	response, err := client.ListPublicips(request)
	if err != nil {
		return "", err
	}

	// 遍历响应中的公共IP地址
	for _, publicip := range *response.Publicips { // 假设返回的是指针指向的切片
		// 检查 PublicIpAddress 是否为nil,并解引用来比较值
		if publicip.PublicIpAddress != nil && *publicip.PublicIpAddress == publicIP {
			// 检查 BandwidthId 是否为nil,并解引用来返回值
			if publicip.BandwidthId != nil {
				return *publicip.BandwidthId, nil
			}
			break // 如果 BandwidthId 为nil,则结束循环
		}
	}

	// 如果没有找到匹配的公共IP地址或带宽ID是nil,则返回错误
	return "", errors.New("public IP not found or bandwidth ID is nil")
}
func getBandwidthNameByPublicIP(client *eip.EipClient, publicIP string) (string, error) {
	// 首先构造查询请求
	request := &model.ListPublicipsRequest{
		// 根据需要设置查询参数
	}

	// 调用SDK方法查询EIP详情
	response, err := client.ListPublicips(request)
	if err != nil {
		return "", err
	}

	// 遍历响应中的公共IP地址
	for _, publicip := range *response.Publicips { // 假设返回的是指针指向的切片
		// 检查 PublicIpAddress 是否为nil,并解引用来比较值
		if publicip.PublicIpAddress != nil && *publicip.PublicIpAddress == publicIP {
			// 检查 BandwidthId 是否为nil,并解引用来返回值
			if publicip.BandwidthName != nil {
				return *publicip.BandwidthName, nil
			}
			break // 如果 BandwidthId 为nil,则结束循环
		}
	}

	// 如果没有找到匹配的公共IP地址或带宽ID是nil,则返回错误
	return "", errors.New("public IP not found or bandwidth ID is nil")
}

// Function to update the bandwidth of an EIP.
func updateBandwidth(client *eip.EipClient, bandwidthId, name string, size int32, chargeMode model.UpdateBandwidthOptionChargeMode) error {
	request := &model.UpdateBandwidthRequest{
		BandwidthId: bandwidthId,
		Body: &model.UpdateBandwidthRequestBody{
			Bandwidth: &model.UpdateBandwidthOption{
				Name:       &name,
				Size:       &size,
				ChargeMode: &chargeMode,
			},
		},
	}

	response, err := client.UpdateBandwidth(request)
	if err != nil {
		return err
	}
	fmt.Printf("Update response: %+v\n", response)
	return nil
}

jenkins运行以上代码实例

最终我需要在jenkins中运行这个更改流量的任务,我将引用ak,sk引用jenkins凭据的方式:
参照之前刷新cdn时候引用凭据的方式:
image.png
最终代码如下:

package main

import (
	"errors"
	"fmt"
	"os"
	"strconv"
	"time"

	"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/basic"
	"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/config"
	eip "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/eip/v2"
	"github.com/huaweicloud/huaweicloud-sdk-go-v3/services/eip/v2/model"
	region "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/eip/v2/region"
)

func main() {
	// Replace with your own AK/SK, Region, and Project ID.
	// 尝试从环境变量中获取ak和sk
	creds := os.Getenv("huaweiyun-hn-cdn")
	if creds == "" {
		fmt.Fprintln(os.Stderr, "Error: Credentials environment variable is not set.")
		os.Exit(1)
	}

	parts := strings.SplitN(creds, ":", 2)
	if len(parts) != 2 {
		fmt.Fprintln(os.Stderr, "Error: Invalid credential format. Expected 'AK:SK'.")
		os.Exit(1)
	}

	ak, sk := parts[0], parts[1]
	projectID := "xxxxxx"
	if len(os.Args) != 5 {
		fmt.Println("Usage: go run main.go <publicIP> <sizeBandwidth> <sizeTrafficBandwidth> <timerMinutes>")
		return
	}

	publicIP := os.Args[1]
	sizeBandwidth, err := strconv.Atoi(os.Args[2])
	if err != nil {
		fmt.Println("Invalid sizeBandwidth:", err)
		return
	}
	sizeTrafficBandwidth, err := strconv.Atoi(os.Args[3])
	if err != nil {
		fmt.Println("Invalid sizeTrafficBandwidth:", err)
		return
	}
	timerMinutes, err := strconv.Atoi(os.Args[4])
	if err != nil {
		fmt.Println("Invalid timerMinutes:", err)
		return
	}
	// Authenticate using your Access Key and Secret Key.
	auth := basic.NewCredentialsBuilder().
		WithAk(ak).
		WithSk(sk).
		WithProjectId(projectID).
		Build()

	// Create EIP client configuration.
	eipClient := eip.NewEipClient(
		eip.EipClientBuilder().
			WithRegion(region.ValueOf("cn-east-3")).
			WithCredential(auth).
			WithHttpConfig(config.DefaultHttpConfig()).
			Build(),
	)

	bandwidthId, err := getBandwidthIdByPublicIP(eipClient, publicIP)
	if err != nil {
		fmt.Println(err)
		return
	}
	bandwidthName, err := getBandwidthNameByPublicIP(eipClient, publicIP)
	if err != nil {
		fmt.Println(err)
		return
	}
	go func() {
		if err := updateBandwidth(eipClient, bandwidthId, bandwidthName, int32(sizeBandwidth), model.GetUpdateBandwidthOptionChargeModeEnum().BANDWIDTH); err != nil {
			fmt.Printf("更新带宽时出错: %s\n", err)
			return
		}

		// 设置计时器在10分钟后切换回流量计费模式。
		timer := time.NewTimer(time.Duration(timerMinutes) * time.Minute)
		<-timer.C

		if err := updateBandwidth(eipClient, bandwidthId, bandwidthName, int32(sizeTrafficBandwidth), model.GetUpdateBandwidthOptionChargeModeEnum().TRAFFIC); err != nil {
			fmt.Printf("恢复带宽时出错: %s\n", err)
			return
		}
	}()

	// 使用通道阻塞主 goroutine 无限期。避免在空的 select 语句中旋转,这是不必要的。
	done := make(chan struct{})
	<-done
}

// 这里假设有一个通过公网IP获取带宽ID的函数
func getBandwidthIdByPublicIP(client *eip.EipClient, publicIP string) (string, error) {
	// 首先构造查询请求
	request := &model.ListPublicipsRequest{
		// 根据需要设置查询参数
	}

	// 调用SDK方法查询EIP详情
	response, err := client.ListPublicips(request)
	if err != nil {
		return "", err
	}

	// 遍历响应中的公共IP地址
	for _, publicip := range *response.Publicips { // 假设返回的是指针指向的切片
		// 检查 PublicIpAddress 是否为nil,并解引用来比较值
		if publicip.PublicIpAddress != nil && *publicip.PublicIpAddress == publicIP {
			// 检查 BandwidthId 是否为nil,并解引用来返回值
			if publicip.BandwidthId != nil {
				return *publicip.BandwidthId, nil
			}
			break // 如果 BandwidthId 为nil,则结束循环
		}
	}

	// 如果没有找到匹配的公共IP地址或带宽ID是nil,则返回错误
	return "", errors.New("public IP not found or bandwidth ID is nil")
}
func getBandwidthNameByPublicIP(client *eip.EipClient, publicIP string) (string, error) {
	// 首先构造查询请求
	request := &model.ListPublicipsRequest{
		// 根据需要设置查询参数
	}

	// 调用SDK方法查询EIP详情
	response, err := client.ListPublicips(request)
	if err != nil {
		return "", err
	}

	// 遍历响应中的公共IP地址
	for _, publicip := range *response.Publicips { // 假设返回的是指针指向的切片
		// 检查 PublicIpAddress 是否为nil,并解引用来比较值
		if publicip.PublicIpAddress != nil && *publicip.PublicIpAddress == publicIP {
			// 检查 BandwidthId 是否为nil,并解引用来返回值
			if publicip.BandwidthName != nil {
				return *publicip.BandwidthName, nil
			}
			break // 如果 BandwidthId 为nil,则结束循环
		}
	}

	// 如果没有找到匹配的公共IP地址或带宽ID是nil,则返回错误
	return "", errors.New("public IP not found or bandwidth ID is nil")
}

// Function to update the bandwidth of an EIP.
func updateBandwidth(client *eip.EipClient, bandwidthId, name string, size int32, chargeMode model.UpdateBandwidthOptionChargeMode) error {
	request := &model.UpdateBandwidthRequest{
		BandwidthId: bandwidthId,
		Body: &model.UpdateBandwidthRequestBody{
			Bandwidth: &model.UpdateBandwidthOption{
				Name:       &name,
				Size:       &size,
				ChargeMode: &chargeMode,
			},
		},
	}

	response, err := client.UpdateBandwidth(request)
	if err != nil {
		return err
	}
	fmt.Printf("Update response: %+v\n", response)
	return nil
}

go build main.go,编译为可执行程序!将可执行程序放在工作节点上,jenkins 做了一个demo
参数化构建,字符参数
image.png
绑定密钥文件:
image.png
Build Steps 执行shell

cd /home/eip-hw&&./main $publicIP $sizeBandwidth $sizeTrafficBandwidth $timerMinutes

image.png
输入publicIP运行程序:
image.png
程序运行生效,但是进程没有退出:

image.png

最终go相关代码:

继续完善一下代码,当程序运行完成后,退出程序。输出Bandwidth update successful, exiting:

package main

import (
	"errors"
	"fmt"
	"os"
	"strconv"
	"time"
        "strings"
	"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/basic"
	"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/config"
	eip "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/eip/v2"
	"github.com/huaweicloud/huaweicloud-sdk-go-v3/services/eip/v2/model"
	region "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/eip/v2/region"
)

func main() {
	// Replace with your own AK/SK, Region, and Project ID.
	// 尝试从环境变量中获取ak和sk
	creds := os.Getenv("xxxxxx")
	if creds == "" {
		fmt.Fprintln(os.Stderr, "Error: Credentials environment variable is not set.")
		os.Exit(1)
	}

	parts := strings.SplitN(creds, ":", 2)
	if len(parts) != 2 {
		fmt.Fprintln(os.Stderr, "Error: Invalid credential format. Expected 'AK:SK'.")
		os.Exit(1)
	}

	ak, sk := parts[0], parts[1]
	projectID := "xxxxxx"
	if len(os.Args) != 5 {
		fmt.Println("Usage: go run main.go <publicIP> <sizeBandwidth> <sizeTrafficBandwidth> <timerMinutes>")
		return
	}

	publicIP := os.Args[1]
	sizeBandwidth, err := strconv.Atoi(os.Args[2])
	if err != nil {
		fmt.Println("Invalid sizeBandwidth:", err)
		return
	}
	sizeTrafficBandwidth, err := strconv.Atoi(os.Args[3])
	if err != nil {
		fmt.Println("Invalid sizeTrafficBandwidth:", err)
		return
	}
	timerMinutes, err := strconv.Atoi(os.Args[4])
	if err != nil {
		fmt.Println("Invalid timerMinutes:", err)
		return
	}
	// Authenticate using your Access Key and Secret Key.
	auth := basic.NewCredentialsBuilder().
		WithAk(ak).
		WithSk(sk).
		WithProjectId(projectID).
		Build()

	// Create EIP client configuration.
	eipClient := eip.NewEipClient(
		eip.EipClientBuilder().
			WithRegion(region.ValueOf("cn-east-3")).
			WithCredential(auth).
			WithHttpConfig(config.DefaultHttpConfig()).
			Build(),
	)

	bandwidthId, err := getBandwidthIdByPublicIP(eipClient, publicIP)
	if err != nil {
		fmt.Println(err)
		return
	}
	bandwidthName, err := getBandwidthNameByPublicIP(eipClient, publicIP)
	if err != nil {
		fmt.Println(err)
		return
	}
	go func() {
		if err := updateBandwidth(eipClient, bandwidthId, bandwidthName, int32(sizeBandwidth), model.GetUpdateBandwidthOptionChargeModeEnum().BANDWIDTH); err != nil {
			fmt.Printf("更新带宽时出错: %s\n", err)
			 os.Exit(1)
			return
		}

		// 设置计时器在10分钟后切换回流量计费模式。
		timer := time.NewTimer(time.Duration(timerMinutes) * time.Minute)
		<-timer.C

		if err := updateBandwidth(eipClient, bandwidthId, bandwidthName, int32(sizeTrafficBandwidth), model.GetUpdateBandwidthOptionChargeModeEnum().TRAFFIC); err != nil {
			fmt.Printf("恢复带宽时出错: %s\n", err)
			os.Exit(1)
			return
		}
		fmt.Println("Bandwidth update successful, exiting.") // Log success message
                os.Exit(0) // Exit the process after success
	}()

	// 使用通道阻塞主 goroutine 无限期。避免在空的 select 语句中旋转,这是不必要的。
	done := make(chan struct{})
	<-done
}

// 这里假设有一个通过公网IP获取带宽ID的函数
func getBandwidthIdByPublicIP(client *eip.EipClient, publicIP string) (string, error) {
	// 首先构造查询请求
	request := &model.ListPublicipsRequest{
		// 根据需要设置查询参数
	}

	// 调用SDK方法查询EIP详情
	response, err := client.ListPublicips(request)
	if err != nil {
		return "", err
	}

	// 遍历响应中的公共IP地址
	for _, publicip := range *response.Publicips { // 假设返回的是指针指向的切片
		// 检查 PublicIpAddress 是否为nil,并解引用来比较值
		if publicip.PublicIpAddress != nil && *publicip.PublicIpAddress == publicIP {
			// 检查 BandwidthId 是否为nil,并解引用来返回值
			if publicip.BandwidthId != nil {
				return *publicip.BandwidthId, nil
			}
			break // 如果 BandwidthId 为nil,则结束循环
		}
	}

	// 如果没有找到匹配的公共IP地址或带宽ID是nil,则返回错误
	return "", errors.New("public IP not found or bandwidth ID is nil")
}
func getBandwidthNameByPublicIP(client *eip.EipClient, publicIP string) (string, error) {
	// 首先构造查询请求
	request := &model.ListPublicipsRequest{
		// 根据需要设置查询参数
	}

	// 调用SDK方法查询EIP详情
	response, err := client.ListPublicips(request)
	if err != nil {
		return "", err
	}

	// 遍历响应中的公共IP地址
	for _, publicip := range *response.Publicips { // 假设返回的是指针指向的切片
		// 检查 PublicIpAddress 是否为nil,并解引用来比较值
		if publicip.PublicIpAddress != nil && *publicip.PublicIpAddress == publicIP {
			// 检查 BandwidthId 是否为nil,并解引用来返回值
			if publicip.BandwidthName != nil {
				return *publicip.BandwidthName, nil
			}
			break // 如果 BandwidthId 为nil,则结束循环
		}
	}

	// 如果没有找到匹配的公共IP地址或带宽ID是nil,则返回错误
	return "", errors.New("public IP not found or bandwidth ID is nil")
}

// Function to update the bandwidth of an EIP.
func updateBandwidth(client *eip.EipClient, bandwidthId, name string, size int32, chargeMode model.UpdateBandwidthOptionChargeMode) error {
	request := &model.UpdateBandwidthRequest{
		BandwidthId: bandwidthId,
		Body: &model.UpdateBandwidthRequestBody{
			Bandwidth: &model.UpdateBandwidthOption{
				Name:       &name,
				Size:       &size,
				ChargeMode: &chargeMode,
			},
		},
	}

	response, err := client.UpdateBandwidth(request)
	if err != nil {
		return err
	}
	fmt.Printf("Update response: %+v\n", response)
	return nil
}

image.png
ok这样就简单实现了!
注:以上代码chatgpt生成,个人进行了更改整理.

其他想到的

  1. 修改一下程序,检测流量计费,当带宽到xxx的时候自动切换带宽?
  2. 支持一下更多类型的切换方式?比如固定带宽的直接10变更 5 20,不恢复流量计费?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1334787.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【数据结构】什么是二叉树?

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:数据结构 ⚙️操作环境:Visual Studio 2022 目录 &#x1f4cc;二叉树的定义 &#x1f4cc;二叉树的特点 &#x1f4cc;特殊二叉树 &#x1f4cc;二叉树的性质 &#x1f4cc;二叉树的存储结构 &#x1f4cc;二叉树…

路径规划最全综述+代码+可视化绘图(Dijkstra算法+A*算法+RRT算法等)

路径规划综述 1. 背景介绍 路径规划是指在给定的环境中找到从起点到终点的最佳路径的过程。它在现实生活中有着广泛的应用&#xff0c;包括无人驾驶、物流配送、机器人导航等领域。随着人工智能和计算机技术的发展&#xff0c;路径规划技术也在不断地得到改进和应用。 路径规划…

宠物智能喂养系统App重新定义养宠体验

​ 在科技蓬勃发展的当今世界&#xff0c;宠物照顾和护理的更多可能性也随之扩大。宠物智能喂养系统App正改变着我们对宠物看护的传统理解。 一、对宠物用品店的影响 作为一款集成了先进的摄像头、传感器和自动投喂功能的设备&#xff0c;智能喂养系统App使得宠物用品店可以…

龙迅LT8713SX适用于一路Type-C/DP1.4转三路Type-C/DP1.4/HDMI2.0应用方案,分辨率高达4K60HZ,支持SST/MST模式!

1. 概述 LT8713SX是一款高性能Type-C/DP1.4转Type-C/DP1.4/HDMI2.0转换器&#xff0c;具有三个可配置的DP1.4/HDMI2.0/DP输出接口和音频输出接口。LT8713SX支持 DisplayPort™ 单流传输 &#xff08;SST&#xff09; 模式和多流传输 &#xff08;MST&#xff09; 模式。当接收…

【SpringBoot】之Security进阶使用(登陆授权)

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是君易--鑨&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的博客专栏《SpringBoot开发之Security系列》。&#x1f3af…

C# Onnx yolov8 pokemon detection

目录 效果 模型信息 项目 代码 下载 C# Onnx yolov8 pokemon detectio 效果 模型信息 Model Properties ------------------------- date&#xff1a;2023-12-25T17:55:44.583431 author&#xff1a;Ultralytics task&#xff1a;detect license&#xff1a;AGPL-3.0 h…

4.9【共享源】流的多生产者和消费者

当一个系统中存在多个生产者和消费者时&#xff0c;情况可能会变得复杂。 了解生产者和消费者流之间支持的基数非常重要。 本质上&#xff0c;一个生产者流可以与多个消费者流连接&#xff0c;但一个消费者流只能连接到一个生产者流。请注意&#xff0c;基数关系仅限于单个流&…

竞赛保研 基于RSSI的室内wifi定位系统

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; wifi室内定位系统 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;…

asp.net mvc 重定向问题的解决方式

前端ajax发起请求&#xff0c;在后端接口中重定向&#xff0c;结果报错&#xff0c;无法跳转 Ajax实际上是通过XMLHttpRequest来向服务器发送异步请求的&#xff0c;从服务器获取数据&#xff0c;然后使用JS来更新页面&#xff0c;这也就是常说的局部刷新实现方式&#xff0c;所…

Linux部署MeterSphere结合内网穿透实现远程访问服务管理界面

文章目录 前言1. 安装MeterSphere2. 本地访问MeterSphere3. 安装 cpolar内网穿透软件4. 配置MeterSphere公网访问地址5. 公网远程访问MeterSphere6. 固定MeterSphere公网地址 前言 MeterSphere 是一站式开源持续测试平台, 涵盖测试跟踪、接口测试、UI 测试和性能测试等功能&am…

华为数通方向HCIP-DataCom H12-831题库(多选题:241-249)

第241题 (NEW) 以下哪些操作可能会影响客户网络的正常运行? A、从设备上下载日志 B、软件升级 C、路由协议配置变更 D、debug核心交换机上转发的所有IP报文 答案:ABCD 解析: 第242题 对于防火墙的默认安全区 Trust 和 Untrust 的说法,正确的有 A、从 Trust 区域访问 Untr…

安卓开发--RecyclerView快速上手【上】

效果图展示: 下面三个kml文件名即动态从服务器获取并列表加载。 RecyclerView简称 RV, 是作为 ListView 和 GridView 的加强版出现的,目的是在有限的屏幕之上展示大量的内容,因此 RecyclerView 的复用机制的实现是它的一个核心部分。 一般在动态获取服务器数据进行…

K8S理论

kubernetes&#xff1a;8个字母省略&#xff0c;就是k8s 自动部署自动扩展和管理容器化部署的应用程序的一个开源系统 k8s是负责自动化运维管理多个容器化程序的集群&#xff0c;是一个功能强大的容器编排工具 分布式和集群化的方式进行容器化管理 版本有1.15 .1.18 .1.20 …

ES5语法数组遍历、字符串、对象新增方法

ES5数组遍历forEach\filter\some\every\map、字符串trim、对象keys\defineProperty新增方法   Elasticsearch 是一个分布式、RESTful 风格的搜索和数据分析引擎&#xff0c;能够解决不断涌现出的各种用例。作为 Elastic Stack 的核心&#xff0c;它集中存储您的数据&#xff…

ssh工具 向指定的ssh服务器配置公钥

此文分享一个python脚本,用于向指定的ssh服务器配置公钥,以达到免密登录ssh服务器的目的。 效果演示 🔥完整演示效果 👇第一步,显然,我们需要选择功能 👇第二步,确认 or 选择ssh服务器 👇第三步,输入ssh登录密码,以完成公钥配置 👇验证,我们通过ssh登录…

PHP+MySQL组合开发:万能在线预约小程序源码系统 附带完整的搭建教程

近年来&#xff0c;线上服务逐渐成为市场主流。特别是在预约服务领域&#xff0c;用户越来越倾向于选择方便快捷的线上预约方式。传统的预约方式如电话预约和到店预约不仅效率低下&#xff0c;而且在信息传达上存在很大的误差。这使得用户常常需要反复确认&#xff0c;浪费了大…

java实现矩阵谱峰搜索算法

矩阵谱峰搜索算法&#xff0c;也称为矩阵谱峰查找算法&#xff0c;是一种用于搜索二维矩阵中谱峰的方法。谱峰是指在矩阵中的一个元素&#xff0c;它比其上下左右四个相邻元素都大或相等。 该算法的基本思想是从矩阵的中间列开始&#xff0c;找到该列中的最大元素&#xff0c;…

使用ImageJ将Raw格式图片批量转换为JPG

自动方法&#xff1a; 1&#xff0c;创建一个txt文本文档&#xff0c;然后将下面的代码复制粘贴进去。 2&#xff0c;将代码的第一行path修改为你的raw图片所在的路径, 3&#xff0c;第二行out修改为转换后jpg图片存储路径。 4&#xff0c;完成前2步后&#xff0c;如果你是win…

最新ChatGPT商业运营网站程序源码,支持Midjourney绘画,GPT语音对话+DALL-E3文生图+文档对话总结

一、前言 SparkAi创作系统是基于ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI创作Ch…

华为云Windows Server服务器下,Node使用pm2-logrotate分割pm2日志,解决pm2日志内存占用过高的问题。

一、简介 PM2 是一个守护进程管理器&#xff0c;它将帮助您管理和保持您的应用程序在线。PM2 入门很简单&#xff0c;它以简单直观的 CLI 形式提供&#xff0c;可通过 NPM 安装。官网地址&#xff1a;https://pm2.keymetrics.io/ 二、问题&#xff1a;pm2日志内存占用过高&am…