feat: add aliyun clb deployer
This commit is contained in:
281
internal/deployer/aliyun_clb.go
Normal file
281
internal/deployer/aliyun_clb.go
Normal file
@@ -0,0 +1,281 @@
|
||||
package deployer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
|
||||
slb20140515 "github.com/alibabacloud-go/slb-20140515/v4/client"
|
||||
"github.com/alibabacloud-go/tea/tea"
|
||||
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||
)
|
||||
|
||||
type AliyunCLBDeployer struct {
|
||||
option *DeployerOption
|
||||
infos []string
|
||||
|
||||
sdkClient *slb20140515.Client
|
||||
sslUploader uploader.Uploader
|
||||
}
|
||||
|
||||
func NewAliyunCLBDeployer(option *DeployerOption) (Deployer, error) {
|
||||
access := &domain.AliyunAccess{}
|
||||
json.Unmarshal([]byte(option.Access), access)
|
||||
|
||||
client, err := (&AliyunCLBDeployer{}).createSdkClient(
|
||||
access.AccessKeyId,
|
||||
access.AccessKeySecret,
|
||||
option.DeployConfig.GetConfigAsString("region"),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
uploader, err := uploader.NewAliyunSLBUploader(&uploader.AliyunSLBUploaderConfig{
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
AccessKeySecret: access.AccessKeySecret,
|
||||
Region: option.DeployConfig.GetConfigAsString("region"),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &AliyunCLBDeployer{
|
||||
option: option,
|
||||
infos: make([]string, 0),
|
||||
sdkClient: client,
|
||||
sslUploader: uploader,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *AliyunCLBDeployer) GetID() string {
|
||||
return fmt.Sprintf("%s-%s", d.option.AccessRecord.GetString("name"), d.option.AccessRecord.Id)
|
||||
}
|
||||
|
||||
func (d *AliyunCLBDeployer) GetInfo() []string {
|
||||
return d.infos
|
||||
}
|
||||
|
||||
func (d *AliyunCLBDeployer) Deploy(ctx context.Context) error {
|
||||
switch d.option.DeployConfig.GetConfigAsString("resourceType") {
|
||||
case "loadbalancer":
|
||||
if err := d.deployToLoadbalancer(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
case "listener":
|
||||
if err := d.deployToListener(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return errors.New("unsupported resource type")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *AliyunCLBDeployer) createSdkClient(accessKeyId, accessKeySecret, region string) (*slb20140515.Client, error) {
|
||||
if region == "" {
|
||||
region = "cn-hangzhou" // CLB(SLB) 服务默认区域:华东一杭州
|
||||
}
|
||||
|
||||
aConfig := &openapi.Config{
|
||||
AccessKeyId: tea.String(accessKeyId),
|
||||
AccessKeySecret: tea.String(accessKeySecret),
|
||||
}
|
||||
|
||||
var endpoint string
|
||||
switch region {
|
||||
case "cn-hangzhou":
|
||||
case "cn-hangzhou-finance":
|
||||
case "cn-shanghai-finance-1":
|
||||
case "cn-shenzhen-finance-1":
|
||||
endpoint = "slb.aliyuncs.com"
|
||||
default:
|
||||
endpoint = fmt.Sprintf("slb.%s.aliyuncs.com", region)
|
||||
}
|
||||
aConfig.Endpoint = tea.String(endpoint)
|
||||
|
||||
client, err := slb20140515.NewClient(aConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func (d *AliyunCLBDeployer) deployToLoadbalancer(ctx context.Context) error {
|
||||
aliLoadbalancerId := d.option.DeployConfig.GetConfigAsString("loadbalancerId")
|
||||
if aliLoadbalancerId == "" {
|
||||
return errors.New("`loadbalancerId` is required")
|
||||
}
|
||||
|
||||
// 查询负载均衡器实例的详细信息
|
||||
// REF: https://help.aliyun.com/zh/slb/classic-load-balancer/developer-reference/api-slb-2014-05-15-describeloadbalancerattribute
|
||||
describeLoadBalancerAttributeReq := &slb20140515.DescribeLoadBalancerAttributeRequest{
|
||||
RegionId: tea.String(d.option.DeployConfig.GetConfigAsString("region")),
|
||||
LoadBalancerId: tea.String(aliLoadbalancerId),
|
||||
}
|
||||
describeLoadBalancerAttributeResp, err := d.sdkClient.DescribeLoadBalancerAttribute(describeLoadBalancerAttributeReq)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute sdk request 'slb.DescribeLoadBalancerAttribute': %w", err)
|
||||
}
|
||||
|
||||
d.infos = append(d.infos, toStr("已查询到 CLB 负载均衡器实例", describeLoadBalancerAttributeResp))
|
||||
|
||||
// 查询监听列表
|
||||
// REF: https://help.aliyun.com/zh/slb/classic-load-balancer/developer-reference/api-slb-2014-05-15-describeloadbalancerlisteners
|
||||
aliListenerPorts := make([]int32, 0)
|
||||
listListenersPage := 1
|
||||
listListenersLimit := int32(100)
|
||||
var listListenersToken *string = nil
|
||||
for {
|
||||
describeLoadBalancerListenersReq := &slb20140515.DescribeLoadBalancerListenersRequest{
|
||||
RegionId: tea.String(d.option.DeployConfig.GetConfigAsString("region")),
|
||||
MaxResults: tea.Int32(listListenersLimit),
|
||||
NextToken: listListenersToken,
|
||||
LoadBalancerId: []*string{tea.String(aliLoadbalancerId)},
|
||||
ListenerProtocol: tea.String("https"),
|
||||
}
|
||||
describeLoadBalancerListenersResp, err := d.sdkClient.DescribeLoadBalancerListeners(describeLoadBalancerListenersReq)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute sdk request 'slb.DescribeLoadBalancerListeners': %w", err)
|
||||
}
|
||||
|
||||
if describeLoadBalancerListenersResp.Body.Listeners != nil {
|
||||
for _, listener := range describeLoadBalancerListenersResp.Body.Listeners {
|
||||
aliListenerPorts = append(aliListenerPorts, *listener.ListenerPort)
|
||||
}
|
||||
}
|
||||
|
||||
if describeLoadBalancerListenersResp.Body.NextToken == nil {
|
||||
break
|
||||
} else {
|
||||
listListenersToken = describeLoadBalancerListenersResp.Body.NextToken
|
||||
listListenersPage += 1
|
||||
}
|
||||
}
|
||||
|
||||
d.infos = append(d.infos, toStr("已查询到 ELB 负载均衡器下的监听器", aliListenerPorts))
|
||||
|
||||
// 上传证书到 SLB
|
||||
uploadResult, err := d.sslUploader.Upload(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.infos = append(d.infos, toStr("已上传证书", uploadResult))
|
||||
|
||||
// 批量更新监听证书
|
||||
var errs []error
|
||||
for _, aliListenerPort := range aliListenerPorts {
|
||||
if err := d.updateListenerCertificate(ctx, aliLoadbalancerId, aliListenerPort, uploadResult.CertId); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *AliyunCLBDeployer) deployToListener(ctx context.Context) error {
|
||||
aliLoadbalancerId := d.option.DeployConfig.GetConfigAsString("loadbalancerId")
|
||||
if aliLoadbalancerId == "" {
|
||||
return errors.New("`loadbalancerId` is required")
|
||||
}
|
||||
|
||||
aliListenerPort := d.option.DeployConfig.GetConfigAsInt32("listenerPort")
|
||||
if aliListenerPort == 0 {
|
||||
return errors.New("`listenerPort` is required")
|
||||
}
|
||||
|
||||
// 上传证书到 SLB
|
||||
uploadResult, err := d.sslUploader.Upload(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.infos = append(d.infos, toStr("已上传证书", uploadResult))
|
||||
|
||||
// 更新监听
|
||||
if err := d.updateListenerCertificate(ctx, aliLoadbalancerId, aliListenerPort, uploadResult.CertId); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *AliyunCLBDeployer) updateListenerCertificate(ctx context.Context, aliLoadbalancerId string, aliListenerPort int32, aliCertId string) error {
|
||||
// 查询监听配置
|
||||
// REF: https://help.aliyun.com/zh/slb/classic-load-balancer/developer-reference/api-slb-2014-05-15-describeloadbalancerhttpslistenerattribute
|
||||
describeLoadBalancerHTTPSListenerAttributeReq := &slb20140515.DescribeLoadBalancerHTTPSListenerAttributeRequest{
|
||||
LoadBalancerId: tea.String(aliLoadbalancerId),
|
||||
ListenerPort: tea.Int32(aliListenerPort),
|
||||
}
|
||||
describeLoadBalancerHTTPSListenerAttributeResp, err := d.sdkClient.DescribeLoadBalancerHTTPSListenerAttribute(describeLoadBalancerHTTPSListenerAttributeReq)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute sdk request 'slb.DescribeLoadBalancerHTTPSListenerAttribute': %w", err)
|
||||
}
|
||||
|
||||
d.infos = append(d.infos, toStr("已查询到 CLB HTTPS 监听配置", describeLoadBalancerHTTPSListenerAttributeResp))
|
||||
|
||||
// 查询扩展域名
|
||||
// REF: https://help.aliyun.com/zh/slb/classic-load-balancer/developer-reference/api-slb-2014-05-15-describedomainextensions
|
||||
describeDomainExtensionsReq := &slb20140515.DescribeDomainExtensionsRequest{
|
||||
RegionId: tea.String(d.option.DeployConfig.GetConfigAsString("region")),
|
||||
LoadBalancerId: tea.String(aliLoadbalancerId),
|
||||
ListenerPort: tea.Int32(aliListenerPort),
|
||||
}
|
||||
describeDomainExtensionsResp, err := d.sdkClient.DescribeDomainExtensions(describeDomainExtensionsReq)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute sdk request 'slb.DescribeDomainExtensions': %w", err)
|
||||
}
|
||||
|
||||
d.infos = append(d.infos, toStr("已查询到 CLB 扩展域名", describeDomainExtensionsResp))
|
||||
|
||||
// 遍历修改扩展域名
|
||||
// REF: https://help.aliyun.com/zh/slb/classic-load-balancer/developer-reference/api-slb-2014-05-15-setdomainextensionattribute
|
||||
//
|
||||
// 这里仅修改跟被替换证书一致的扩展域名
|
||||
if describeDomainExtensionsResp.Body.DomainExtensions == nil && describeDomainExtensionsResp.Body.DomainExtensions.DomainExtension == nil {
|
||||
for _, domainExtension := range describeDomainExtensionsResp.Body.DomainExtensions.DomainExtension {
|
||||
if *domainExtension.ServerCertificateId == *describeLoadBalancerHTTPSListenerAttributeResp.Body.ServerCertificateId {
|
||||
break
|
||||
}
|
||||
|
||||
setDomainExtensionAttributeReq := &slb20140515.SetDomainExtensionAttributeRequest{
|
||||
RegionId: tea.String(d.option.DeployConfig.GetConfigAsString("region")),
|
||||
DomainExtensionId: tea.String(*domainExtension.DomainExtensionId),
|
||||
ServerCertificateId: tea.String(aliCertId),
|
||||
}
|
||||
_, err := d.sdkClient.SetDomainExtensionAttribute(setDomainExtensionAttributeReq)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute sdk request 'slb.SetDomainExtensionAttribute': %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 修改监听配置
|
||||
// REF: https://help.aliyun.com/zh/slb/classic-load-balancer/developer-reference/api-slb-2014-05-15-setloadbalancerhttpslistenerattribute
|
||||
//
|
||||
// 注意修改监听配置要放在修改扩展域名之后
|
||||
setLoadBalancerHTTPSListenerAttributeReq := &slb20140515.SetLoadBalancerHTTPSListenerAttributeRequest{
|
||||
RegionId: tea.String(d.option.DeployConfig.GetConfigAsString("region")),
|
||||
LoadBalancerId: tea.String(aliLoadbalancerId),
|
||||
ListenerPort: tea.Int32(aliListenerPort),
|
||||
ServerCertificateId: tea.String(aliCertId),
|
||||
}
|
||||
setLoadBalancerHTTPSListenerAttributeResp, err := d.sdkClient.SetLoadBalancerHTTPSListenerAttribute(setLoadBalancerHTTPSListenerAttributeReq)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute sdk request 'slb.SetLoadBalancerHTTPSListenerAttribute': %w", err)
|
||||
}
|
||||
|
||||
d.infos = append(d.infos, toStr("已更新 CLB HTTPS 监听配置", setLoadBalancerHTTPSListenerAttributeResp))
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -18,6 +18,7 @@ const (
|
||||
targetAliyunOSS = "aliyun-oss"
|
||||
targetAliyunCDN = "aliyun-cdn"
|
||||
targetAliyunESA = "aliyun-dcdn"
|
||||
targetAliyunCLB = "aliyun-clb"
|
||||
targetTencentCDN = "tencent-cdn"
|
||||
targetTencentCLB = "tencent-clb"
|
||||
targetTencentCOS = "tencent-cos"
|
||||
@@ -106,6 +107,8 @@ func getWithDeployConfig(record *models.Record, cert *applicant.Certificate, dep
|
||||
return NewAliyunCDNDeployer(option)
|
||||
case targetAliyunESA:
|
||||
return NewAliyunESADeployer(option)
|
||||
case targetAliyunCLB:
|
||||
return NewAliyunCLBDeployer(option)
|
||||
case targetTencentCDN:
|
||||
return NewTencentCDNDeployer(option)
|
||||
case targetTencentCLB:
|
||||
|
||||
@@ -41,9 +41,9 @@ func NewHuaweiCloudCDNDeployer(option *DeployerOption) (Deployer, error) {
|
||||
|
||||
// TODO: SCM 服务与 DNS 服务所支持的区域可能不一致,这里暂时不传而是使用默认值,仅支持华为云国内版
|
||||
uploader, err := uploader.NewHuaweiCloudSCMUploader(&uploader.HuaweiCloudSCMUploaderConfig{
|
||||
Region: "",
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
SecretAccessKey: access.SecretAccessKey,
|
||||
Region: "",
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -46,9 +46,9 @@ func NewHuaweiCloudELBDeployer(option *DeployerOption) (Deployer, error) {
|
||||
}
|
||||
|
||||
uploader, err := uploader.NewHuaweiCloudELBUploader(&uploader.HuaweiCloudELBUploaderConfig{
|
||||
Region: option.DeployConfig.GetConfigAsString("region"),
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
SecretAccessKey: access.SecretAccessKey,
|
||||
Region: option.DeployConfig.GetConfigAsString("region"),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -176,10 +176,15 @@ func (u *HuaweiCloudELBDeployer) getSdkProjectId(accessKeyId, secretAccessKey, r
|
||||
}
|
||||
|
||||
func (d *HuaweiCloudELBDeployer) deployToCertificate(ctx context.Context) error {
|
||||
hcCertId := d.option.DeployConfig.GetConfigAsString("certificateId")
|
||||
if hcCertId == "" {
|
||||
return errors.New("`certificateId` is required")
|
||||
}
|
||||
|
||||
// 更新证书
|
||||
// REF: https://support.huaweicloud.com/api-elb/UpdateCertificate.html
|
||||
updateCertificateReq := &hcElbModel.UpdateCertificateRequest{
|
||||
CertificateId: d.option.DeployConfig.GetConfigAsString("certificateId"),
|
||||
CertificateId: hcCertId,
|
||||
Body: &hcElbModel.UpdateCertificateRequestBody{
|
||||
Certificate: &hcElbModel.UpdateCertificateOption{
|
||||
Certificate: cast.StringPtr(d.option.Certificate.Certificate),
|
||||
@@ -198,21 +203,26 @@ func (d *HuaweiCloudELBDeployer) deployToCertificate(ctx context.Context) error
|
||||
}
|
||||
|
||||
func (d *HuaweiCloudELBDeployer) deployToLoadbalancer(ctx context.Context) error {
|
||||
hcLoadbalancerId := d.option.DeployConfig.GetConfigAsString("loadbalancerId")
|
||||
if hcLoadbalancerId == "" {
|
||||
return errors.New("`loadbalancerId` is required")
|
||||
}
|
||||
|
||||
// 查询负载均衡器详情
|
||||
// REF: https://support.huaweicloud.com/api-elb/ShowLoadBalancer.html
|
||||
showLoadBalancerReq := &hcElbModel.ShowLoadBalancerRequest{
|
||||
LoadbalancerId: d.option.DeployConfig.GetConfigAsString("loadbalancerId"),
|
||||
LoadbalancerId: hcLoadbalancerId,
|
||||
}
|
||||
showLoadBalancerResp, err := d.sdkClient.ShowLoadBalancer(showLoadBalancerReq)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute sdk request 'elb.ShowLoadBalancer': %w", err)
|
||||
}
|
||||
|
||||
d.infos = append(d.infos, toStr("已查询到到 ELB 负载均衡器", showLoadBalancerResp))
|
||||
d.infos = append(d.infos, toStr("已查询到 ELB 负载均衡器", showLoadBalancerResp))
|
||||
|
||||
// 查询监听器列表
|
||||
// REF: https://support.huaweicloud.com/api-elb/ListListeners.html
|
||||
listenerIds := make([]string, 0)
|
||||
hcListenerIds := make([]string, 0)
|
||||
listListenersLimit := int32(2000)
|
||||
var listListenersMarker *string = nil
|
||||
for {
|
||||
@@ -229,7 +239,7 @@ func (d *HuaweiCloudELBDeployer) deployToLoadbalancer(ctx context.Context) error
|
||||
|
||||
if listListenersResp.Listeners != nil {
|
||||
for _, listener := range *listListenersResp.Listeners {
|
||||
listenerIds = append(listenerIds, listener.Id)
|
||||
hcListenerIds = append(hcListenerIds, listener.Id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,7 +250,7 @@ func (d *HuaweiCloudELBDeployer) deployToLoadbalancer(ctx context.Context) error
|
||||
}
|
||||
}
|
||||
|
||||
d.infos = append(d.infos, toStr("已查询到到 ELB 负载均衡器下的监听器", listenerIds))
|
||||
d.infos = append(d.infos, toStr("已查询到 ELB 负载均衡器下的监听器", hcListenerIds))
|
||||
|
||||
// 上传证书到 SCM
|
||||
uploadResult, err := d.sslUploader.Upload(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey)
|
||||
@@ -252,8 +262,8 @@ func (d *HuaweiCloudELBDeployer) deployToLoadbalancer(ctx context.Context) error
|
||||
|
||||
// 批量更新监听器证书
|
||||
var errs []error
|
||||
for _, listenerId := range listenerIds {
|
||||
if err := d.updateListenerCertificate(ctx, listenerId, uploadResult.CertId); err != nil {
|
||||
for _, hcListenerId := range hcListenerIds {
|
||||
if err := d.updateListenerCertificate(ctx, hcListenerId, uploadResult.CertId); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
@@ -265,6 +275,11 @@ func (d *HuaweiCloudELBDeployer) deployToLoadbalancer(ctx context.Context) error
|
||||
}
|
||||
|
||||
func (d *HuaweiCloudELBDeployer) deployToListener(ctx context.Context) error {
|
||||
hcListenerId := d.option.DeployConfig.GetConfigAsString("listenerId")
|
||||
if hcListenerId == "" {
|
||||
return errors.New("`listenerId` is required")
|
||||
}
|
||||
|
||||
// 上传证书到 SCM
|
||||
uploadResult, err := d.sslUploader.Upload(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey)
|
||||
if err != nil {
|
||||
@@ -274,7 +289,7 @@ func (d *HuaweiCloudELBDeployer) deployToListener(ctx context.Context) error {
|
||||
d.infos = append(d.infos, toStr("已上传证书", uploadResult))
|
||||
|
||||
// 更新监听器证书
|
||||
if err := d.updateListenerCertificate(ctx, d.option.DeployConfig.GetConfigAsString("listenerId"), uploadResult.CertId); err != nil {
|
||||
if err := d.updateListenerCertificate(ctx, hcListenerId, uploadResult.CertId); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -292,7 +307,7 @@ func (d *HuaweiCloudELBDeployer) updateListenerCertificate(ctx context.Context,
|
||||
return fmt.Errorf("failed to execute sdk request 'elb.ShowListener': %w", err)
|
||||
}
|
||||
|
||||
d.infos = append(d.infos, toStr("已查询到到 ELB 监听器", showListenerResp))
|
||||
d.infos = append(d.infos, toStr("已查询到 ELB 监听器", showListenerResp))
|
||||
|
||||
// 更新监听器
|
||||
// REF: https://support.huaweicloud.com/api-elb/UpdateListener.html
|
||||
@@ -359,7 +374,7 @@ func (d *HuaweiCloudELBDeployer) updateListenerCertificate(ctx context.Context,
|
||||
return fmt.Errorf("failed to execute sdk request 'elb.UpdateListener': %w", err)
|
||||
}
|
||||
|
||||
d.infos = append(d.infos, toStr("已更新监听器", updateListenerResp))
|
||||
d.infos = append(d.infos, toStr("已更新 ELB 监听器", updateListenerResp))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user