From 155b186978122e978bf947780cc8deae9e40f604 Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Thu, 4 Jun 2026 01:08:23 +0800 Subject: [PATCH] feat(provider): new deployment provider: byteplus alb --- .../certmgmt/deployers/sp_byteplus_alb.go | 31 ++ internal/domain/provider.go | 1 + .../providers/byteplus-alb/byteplus_alb.go | 279 ++++++++++++++++++ .../byteplus-alb/byteplus_alb_test.go | 58 ++++ .../deployer/providers/byteplus-alb/consts.go | 8 + .../providers/byteplus-tos/byteplus_tos.go | 2 +- .../byteplus-tos/byteplus_tos_test.go | 2 +- .../alb/api_describe_listener_attributes.go | 39 +++ .../service/alb/api_describe_listeners.go | 42 +++ .../api_describe_load_balancer_attributes.go | 42 +++ .../alb/api_modify_listener_attributes.go | 44 +++ .../service/alb/service_alb.go | 60 ++++ .../BizDeployNodeConfigFieldsProvider.tsx | 2 + ...loyNodeConfigFieldsProviderBytePlusALB.tsx | 155 ++++++++++ ui/src/domain/provider.ts | 2 + ui/src/i18n/resources/en/nls.provider.json | 1 + .../i18n/resources/en/nls.workflow.nodes.json | 34 ++- ui/src/i18n/resources/zh/nls.provider.json | 1 + .../i18n/resources/zh/nls.workflow.nodes.json | 34 ++- 19 files changed, 831 insertions(+), 6 deletions(-) create mode 100644 internal/certmgmt/deployers/sp_byteplus_alb.go create mode 100644 pkg/core/deployer/providers/byteplus-alb/byteplus_alb.go create mode 100644 pkg/core/deployer/providers/byteplus-alb/byteplus_alb_test.go create mode 100644 pkg/core/deployer/providers/byteplus-alb/consts.go create mode 100644 pkg/sdk3rd-trimmed/github.com/byteplus-sdk/byteplus-go-sdk-v2/service/alb/api_describe_listener_attributes.go create mode 100644 pkg/sdk3rd-trimmed/github.com/byteplus-sdk/byteplus-go-sdk-v2/service/alb/api_describe_listeners.go create mode 100644 pkg/sdk3rd-trimmed/github.com/byteplus-sdk/byteplus-go-sdk-v2/service/alb/api_describe_load_balancer_attributes.go create mode 100644 pkg/sdk3rd-trimmed/github.com/byteplus-sdk/byteplus-go-sdk-v2/service/alb/api_modify_listener_attributes.go create mode 100644 pkg/sdk3rd-trimmed/github.com/byteplus-sdk/byteplus-go-sdk-v2/service/alb/service_alb.go create mode 100644 ui/src/components/workflow/designer/forms/BizDeployNodeConfigFieldsProviderBytePlusALB.tsx diff --git a/internal/certmgmt/deployers/sp_byteplus_alb.go b/internal/certmgmt/deployers/sp_byteplus_alb.go new file mode 100644 index 000000000..af4f32fb3 --- /dev/null +++ b/internal/certmgmt/deployers/sp_byteplus_alb.go @@ -0,0 +1,31 @@ +package deployers + +import ( + "fmt" + + "github.com/certimate-go/certimate/internal/domain" + "github.com/certimate-go/certimate/pkg/core" + dplyimpl "github.com/certimate-go/certimate/pkg/core/deployer/providers/byteplus-alb" + xmaps "github.com/certimate-go/certimate/pkg/utils/maps" +) + +func init() { + Registries.MustRegister(domain.DeploymentProviderTypeBytePlusALB, func(options *ProviderFactoryOptions) (core.Deployer, error) { + credentials := domain.AccessConfigForBytePlus{} + if err := xmaps.Populate(options.ProviderAccessConfig, &credentials); err != nil { + return nil, fmt.Errorf("failed to populate provider access config: %w", err) + } + + provider, err := dplyimpl.NewDeployer(&dplyimpl.DeployerConfig{ + AccessKeyId: credentials.AccessKeyId, + SecretAccessKey: credentials.SecretAccessKey, + ProjectName: credentials.ProjectName, + Region: xmaps.GetString(options.ProviderExtendedConfig, "region"), + DeployTarget: xmaps.GetString(options.ProviderExtendedConfig, "deployTarget"), + LoadbalancerId: xmaps.GetString(options.ProviderExtendedConfig, "loadbalancerId"), + ListenerId: xmaps.GetString(options.ProviderExtendedConfig, "listenerId"), + Domain: xmaps.GetString(options.ProviderExtendedConfig, "domain"), + }) + return provider, err + }) +} diff --git a/internal/domain/provider.go b/internal/domain/provider.go index 83ccfad0d..58743796f 100644 --- a/internal/domain/provider.go +++ b/internal/domain/provider.go @@ -338,6 +338,7 @@ const ( DeploymentProviderTypeBaotaWAF = DeploymentProviderType(AccessProviderTypeBaotaWAF) DeploymentProviderTypeBaotaWAFConsole = DeploymentProviderType(AccessProviderTypeBaotaWAF + "-console") DeploymentProviderTypeBunnyCDN = DeploymentProviderType(AccessProviderTypeBunny + "-cdn") + DeploymentProviderTypeBytePlusALB = DeploymentProviderType(AccessProviderTypeBytePlus + "-alb") DeploymentProviderTypeBytePlusCDN = DeploymentProviderType(AccessProviderTypeBytePlus + "-cdn") DeploymentProviderTypeBytePlusCertCenter = DeploymentProviderType(AccessProviderTypeBytePlus + "-certcenter") DeploymentProviderTypeBytePlusMediaLive = DeploymentProviderType(AccessProviderTypeBytePlus + "-medialive") diff --git a/pkg/core/deployer/providers/byteplus-alb/byteplus_alb.go b/pkg/core/deployer/providers/byteplus-alb/byteplus_alb.go new file mode 100644 index 000000000..091880aab --- /dev/null +++ b/pkg/core/deployer/providers/byteplus-alb/byteplus_alb.go @@ -0,0 +1,279 @@ +package byteplusalb + +import ( + "context" + "errors" + "fmt" + "log/slog" + + bp "github.com/byteplus-sdk/byteplus-go-sdk-v2/byteplus" + bpsession "github.com/byteplus-sdk/byteplus-go-sdk-v2/byteplus/session" + "github.com/samber/lo" + + bpalb "github.com/certimate-go/certimate/pkg/sdk3rd-trimmed/github.com/byteplus-sdk/byteplus-go-sdk-v2/service/alb" + + "github.com/certimate-go/certimate/pkg/core" + cmgrimpl "github.com/certimate-go/certimate/pkg/core/certmgr/providers/byteplus-certcenter" +) + +type ( + Provider = core.Deployer + DeployResult = core.DeployerDeployResult +) + +type DeployerConfig struct { + // BytePlus AccessKeyId。 + AccessKeyId string `json:"accessKeyId"` + // BytePlus SecretAccessKey。 + SecretAccessKey string `json:"secretAccessKey"` + // BytePlus 项目名称。 + ProjectName string `json:"projectName,omitempty"` + // BytePlus 地域。 + Region string `json:"region"` + // 部署目标。 + DeployTarget string `json:"deployTarget"` + // 负载均衡实例 ID。 + // 部署目标为 [DEPLOY_TARGET_LOADBALANCER] 时必填。 + LoadbalancerId string `json:"loadbalancerId,omitempty"` + // 负载均衡监听器 ID。 + // 部署目标为 [DEPLOY_TARGET_LISTENER] 时必填。 + ListenerId string `json:"listenerId,omitempty"` + // SNI 域名(支持泛域名)。 + // 部署目标为 [DEPLOY_TARGET_LOADBALANCER]、[DEPLOY_TARGET_LISTENER] 时选填。 + Domain string `json:"domain,omitempty"` +} + +type Deployer struct { + config *DeployerConfig + logger *slog.Logger + sdkClient *bpalb.ALB + sdkCertmgr core.Certmgr +} + +var _ Provider = (*Deployer)(nil) + +func NewDeployer(config *DeployerConfig) (*Deployer, error) { + if config == nil { + return nil, fmt.Errorf("the configuration of the deployer provider is nil") + } + + client, err := createSDKClient(config.AccessKeyId, config.SecretAccessKey, config.Region) + if err != nil { + return nil, fmt.Errorf("could not create client: %w", err) + } + + pcertmgr, err := cmgrimpl.NewCertmgr(&cmgrimpl.CertmgrConfig{ + AccessKeyId: config.AccessKeyId, + SecretAccessKey: config.SecretAccessKey, + ProjectName: config.ProjectName, + Region: "ap-singapore-1", + }) + if err != nil { + return nil, fmt.Errorf("could not create certmgr: %w", err) + } + + return &Deployer{ + config: config, + logger: slog.Default(), + sdkClient: client, + sdkCertmgr: pcertmgr, + }, nil +} + +func (d *Deployer) SetLogger(logger *slog.Logger) { + if logger == nil { + d.logger = slog.New(slog.DiscardHandler) + } else { + d.logger = logger + } + + d.sdkCertmgr.SetLogger(logger) +} + +func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*DeployResult, error) { + // 上传证书 + upres, err := d.sdkCertmgr.Upload(ctx, certPEM, privkeyPEM) + if err != nil { + return nil, fmt.Errorf("failed to upload certificate file: %w", err) + } else { + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) + } + + // 根据部署目标决定业务流程 + switch d.config.DeployTarget { + case DEPLOY_TARGET_LOADBALANCER: + if err := d.deployToLoadbalancer(ctx, upres.CertId); err != nil { + return nil, err + } + + case DEPLOY_TARGET_LISTENER: + if err := d.deployToListener(ctx, upres.CertId); err != nil { + return nil, err + } + + default: + return nil, fmt.Errorf("unsupported deploy target '%s'", d.config.DeployTarget) + } + + return &DeployResult{}, nil +} + +func (d *Deployer) deployToLoadbalancer(ctx context.Context, cloudCertId string) error { + if d.config.LoadbalancerId == "" { + return fmt.Errorf("config `loadbalancerId` is required") + } + + // 查询 ALB 实例的详细信息 + describeLoadBalancerAttributesReq := &bpalb.DescribeLoadBalancerAttributesInput{ + LoadBalancerId: bp.String(d.config.LoadbalancerId), + } + describeLoadBalancerAttributesResp, err := d.sdkClient.DescribeLoadBalancerAttributes(describeLoadBalancerAttributesReq) + d.logger.Debug("sdk request 'alb.DescribeLoadBalancerAttributes'", slog.Any("request", describeLoadBalancerAttributesReq), slog.Any("response", describeLoadBalancerAttributesResp)) + if err != nil { + return fmt.Errorf("failed to execute sdk request 'alb.DescribeLoadBalancerAttributes': %w", err) + } + + // 查询 HTTPS 监听器列表 + listenerIds := make([]string, 0) + describeListenersPageSize := 100 + describeListenersPageNumber := 1 + for { + select { + case <-ctx.Done(): + return ctx.Err() + default: + } + + describeListenersReq := &bpalb.DescribeListenersInput{ + ProjectName: lo.EmptyableToPtr(d.config.ProjectName), + LoadBalancerId: bp.String(d.config.LoadbalancerId), + Protocol: bp.String("HTTPS"), + PageNumber: bp.Int64(int64(describeListenersPageNumber)), + PageSize: bp.Int64(int64(describeListenersPageSize)), + } + describeListenersResp, err := d.sdkClient.DescribeListeners(describeListenersReq) + d.logger.Debug("sdk request 'alb.DescribeListeners'", slog.Any("request", describeListenersReq), slog.Any("response", describeListenersResp)) + if err != nil { + return fmt.Errorf("failed to execute sdk request 'alb.DescribeListeners': %w", err) + } + + for _, listener := range describeListenersResp.Listeners { + listenerIds = append(listenerIds, *listener.ListenerId) + } + + if len(describeListenersResp.Listeners) < describeListenersPageSize { + break + } + + describeListenersPageNumber++ + } + + // 遍历更新监听证书 + if len(listenerIds) == 0 { + d.logger.Info("no alb listeners to deploy") + } else { + d.logger.Info("found https listeners to deploy", slog.Any("listenerIds", listenerIds)) + var errs []error + + for _, listenerId := range listenerIds { + select { + case <-ctx.Done(): + return ctx.Err() + default: + if err := d.updateListenerCertificate(ctx, listenerId, cloudCertId); err != nil { + errs = append(errs, err) + } + } + } + + if len(errs) > 0 { + return errors.Join(errs...) + } + } + + return nil +} + +func (d *Deployer) deployToListener(ctx context.Context, cloudCertId string) error { + if d.config.ListenerId == "" { + return fmt.Errorf("config `listenerId` is required") + } + + if err := d.updateListenerCertificate(ctx, d.config.ListenerId, cloudCertId); err != nil { + return err + } + + return nil +} + +func (d *Deployer) updateListenerCertificate(ctx context.Context, cloudListenerId string, cloudCertId string) error { + // 查询指定监听器的详细信息 + describeListenerAttributesReq := &bpalb.DescribeListenerAttributesInput{ + ListenerId: bp.String(cloudListenerId), + } + describeListenerAttributesResp, err := d.sdkClient.DescribeListenerAttributesWithContext(ctx, describeListenerAttributesReq) + d.logger.Debug("sdk request 'alb.DescribeListenerAttributes'", slog.Any("request", describeListenerAttributesReq), slog.Any("response", describeListenerAttributesResp)) + if err != nil { + return fmt.Errorf("failed to execute sdk request 'alb.DescribeListenerAttributes': %w", err) + } + + if d.config.Domain == "" { + // 未指定 SNI,只需部署到监听器 + + // 修改指定监听器 + modifyListenerAttributesReq := &bpalb.ModifyListenerAttributesInput{ + ListenerId: bp.String(cloudListenerId), + CertificateSource: bp.String("cert_center"), + CertCenterCertificateId: bp.String(cloudCertId), + } + modifyListenerAttributesResp, err := d.sdkClient.ModifyListenerAttributesWithContext(ctx, modifyListenerAttributesReq) + d.logger.Debug("sdk request 'alb.ModifyListenerAttributes'", slog.Any("request", modifyListenerAttributesReq), slog.Any("response", modifyListenerAttributesResp)) + if err != nil { + return fmt.Errorf("failed to execute sdk request 'alb.ModifyListenerAttributes': %w", err) + } + } else { + // 指定 SNI,需部署到扩展域名 + + // 修改指定监听器 + modifyListenerAttributesReq := &bpalb.ModifyListenerAttributesInput{ + ListenerId: bp.String(cloudListenerId), + DomainExtensions: lo.Map( + lo.Filter( + describeListenerAttributesResp.DomainExtensions, + func(domain *bpalb.DomainExtensionForDescribeListenerAttributesOutput, _ int) bool { + return *domain.Domain == d.config.Domain + }, + ), + func(domain *bpalb.DomainExtensionForDescribeListenerAttributesOutput, _ int) *bpalb.DomainExtensionForModifyListenerAttributesInput { + return &bpalb.DomainExtensionForModifyListenerAttributesInput{ + DomainExtensionId: domain.DomainExtensionId, + Domain: domain.Domain, + CertificateSource: bp.String("cert_center"), + CertCenterCertificateId: bp.String(cloudCertId), + Action: bp.String("modify"), + } + }), + } + modifyListenerAttributesResp, err := d.sdkClient.ModifyListenerAttributesWithContext(ctx, modifyListenerAttributesReq) + d.logger.Debug("sdk request 'alb.ModifyListenerAttributes'", slog.Any("request", modifyListenerAttributesReq), slog.Any("response", modifyListenerAttributesResp)) + if err != nil { + return fmt.Errorf("failed to execute sdk request 'alb.ModifyListenerAttributes': %w", err) + } + } + + return nil +} + +func createSDKClient(accessKeyId, secretAccessKey, region string) (*bpalb.ALB, error) { + config := bp.NewConfig(). + WithAkSk(accessKeyId, secretAccessKey). + WithRegion(region) + + session, err := bpsession.NewSession(config) + if err != nil { + return nil, err + } + + client := bpalb.New(session) + return client, nil +} diff --git a/pkg/core/deployer/providers/byteplus-alb/byteplus_alb_test.go b/pkg/core/deployer/providers/byteplus-alb/byteplus_alb_test.go new file mode 100644 index 000000000..c76c66a05 --- /dev/null +++ b/pkg/core/deployer/providers/byteplus-alb/byteplus_alb_test.go @@ -0,0 +1,58 @@ +package byteplusalb_test + +import ( + "testing" + + "github.com/certimate-go/certimate/pkg/core/deployer/internal/tester" + impl "github.com/certimate-go/certimate/pkg/core/deployer/providers/byteplus-alb" +) + +var ( + fp = tester.Args("BYTEPLUSALB_") + fTestCertPath string + fTestKeyPath string + fAccessKeyId string + fSecretAccessKey string + fRegion string + fListenerId string +) + +func init() { + fp.DefineString(&fTestCertPath, "TESTCERTPATH") + fp.DefineString(&fTestKeyPath, "TESTKEYPATH") + fp.DefineString(&fAccessKeyId, "ACCESSKEYID") + fp.DefineString(&fSecretAccessKey, "SECRETACCESSKEY") + fp.DefineString(&fRegion, "REGION") + fp.DefineString(&fListenerId, "LISTENERID") +} + +/* +Shell command to run this test: + + go test -v ./byteplus_alb_test.go -args \ + --BYTEPLUSALB_TESTCERTPATH="/path/to/your-test-cert.pem" \ + --BYTEPLUSALB_TESTKEYPATH="/path/to/your-test-key.pem" \ + --BYTEPLUSALB_ACCESSKEYID="your-access-key-id" \ + --BYTEPLUSALB_SECRETACCESSKEY="your-secret-access-key" \ + --BYTEPLUSALB_REGION="ap-southeast-1" \ + --BYTEPLUSALB_LISTENERID="your-listener-id" +*/ +func TestProvider(t *testing.T) { + fp.Parse() + + t.Run("Deploy_ToListener", func(t *testing.T) { + provider, err := impl.NewDeployer(&impl.DeployerConfig{ + AccessKeyId: fAccessKeyId, + SecretAccessKey: fSecretAccessKey, + Region: fRegion, + DeployTarget: impl.DEPLOY_TARGET_LISTENER, + ListenerId: fListenerId, + }) + if err != nil { + t.Errorf("err: %+v", err) + return + } + + tester.TestDeploy(t, provider, tester.TestDeployArgs{CertPath: fTestCertPath, KeyPath: fTestKeyPath}) + }) +} diff --git a/pkg/core/deployer/providers/byteplus-alb/consts.go b/pkg/core/deployer/providers/byteplus-alb/consts.go new file mode 100644 index 000000000..33f9a73f7 --- /dev/null +++ b/pkg/core/deployer/providers/byteplus-alb/consts.go @@ -0,0 +1,8 @@ +package byteplusalb + +const ( + // 部署目标:部署到指定负载均衡器。 + DEPLOY_TARGET_LOADBALANCER = "loadbalancer" + // 部署目标:部署到指定监听器。 + DEPLOY_TARGET_LISTENER = "listener" +) diff --git a/pkg/core/deployer/providers/byteplus-tos/byteplus_tos.go b/pkg/core/deployer/providers/byteplus-tos/byteplus_tos.go index 0bb7bc0d7..790170dba 100644 --- a/pkg/core/deployer/providers/byteplus-tos/byteplus_tos.go +++ b/pkg/core/deployer/providers/byteplus-tos/byteplus_tos.go @@ -54,7 +54,7 @@ func NewDeployer(config *DeployerConfig) (*Deployer, error) { AccessKeyId: config.AccessKeyId, SecretAccessKey: config.SecretAccessKey, ProjectName: config.ProjectName, - Region: config.Region, + Region: "ap-singapore-1", }) if err != nil { return nil, fmt.Errorf("could not create certmgr: %w", err) diff --git a/pkg/core/deployer/providers/byteplus-tos/byteplus_tos_test.go b/pkg/core/deployer/providers/byteplus-tos/byteplus_tos_test.go index 7319be6ae..6242b1784 100644 --- a/pkg/core/deployer/providers/byteplus-tos/byteplus_tos_test.go +++ b/pkg/core/deployer/providers/byteplus-tos/byteplus_tos_test.go @@ -36,7 +36,7 @@ Shell command to run this test: --BYTEPLUSTOS_TESTKEYPATH="/path/to/your-test-key.pem" \ --BYTEPLUSTOS_ACCESSKEYID="your-access-key-id" \ --BYTEPLUSTOS_SECRETACCESSKEY="your-secret-access-key" \ - --BYTEPLUSTOS_REGION="cn-beijing" \ + --BYTEPLUSTOS_REGION="ap-southeast-1" \ --BYTEPLUSTOS_BUCKET="your-tos-bucket" \ --BYTEPLUSTOS_DOMAIN="example.com" */ diff --git a/pkg/sdk3rd-trimmed/github.com/byteplus-sdk/byteplus-go-sdk-v2/service/alb/api_describe_listener_attributes.go b/pkg/sdk3rd-trimmed/github.com/byteplus-sdk/byteplus-go-sdk-v2/service/alb/api_describe_listener_attributes.go new file mode 100644 index 000000000..5045a0a50 --- /dev/null +++ b/pkg/sdk3rd-trimmed/github.com/byteplus-sdk/byteplus-go-sdk-v2/service/alb/api_describe_listener_attributes.go @@ -0,0 +1,39 @@ +package alb + +import ( + "github.com/byteplus-sdk/byteplus-go-sdk-v2/byteplus" + "github.com/byteplus-sdk/byteplus-go-sdk-v2/byteplus/request" + "github.com/byteplus-sdk/byteplus-go-sdk-v2/service/alb" +) + +const opDescribeListenerAttributes = "DescribeListenerAttributes" + +func (c *ALB) DescribeListenerAttributesRequest(input *DescribeListenerAttributesInput) (req *request.Request, output *DescribeListenerAttributesOutput) { + op := &request.Operation{ + Name: opDescribeListenerAttributes, + HTTPMethod: "GET", + HTTPPath: "/", + } + + if input == nil { + input = &DescribeListenerAttributesInput{} + } + + output = &DescribeListenerAttributesOutput{} + req = c.newRequest(op, input, output) + + return +} + +func (c *ALB) DescribeListenerAttributesWithContext(ctx byteplus.Context, input *DescribeListenerAttributesInput, opts ...request.Option) (*DescribeListenerAttributesOutput, error) { + req, out := c.DescribeListenerAttributesRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type DescribeListenerAttributesInput = alb.DescribeListenerAttributesInput + +type DescribeListenerAttributesOutput = alb.DescribeListenerAttributesOutput + +type DomainExtensionForDescribeListenerAttributesOutput = alb.DomainExtensionForDescribeListenerAttributesOutput diff --git a/pkg/sdk3rd-trimmed/github.com/byteplus-sdk/byteplus-go-sdk-v2/service/alb/api_describe_listeners.go b/pkg/sdk3rd-trimmed/github.com/byteplus-sdk/byteplus-go-sdk-v2/service/alb/api_describe_listeners.go new file mode 100644 index 000000000..be071b31b --- /dev/null +++ b/pkg/sdk3rd-trimmed/github.com/byteplus-sdk/byteplus-go-sdk-v2/service/alb/api_describe_listeners.go @@ -0,0 +1,42 @@ +package alb + +import ( + "github.com/byteplus-sdk/byteplus-go-sdk-v2/byteplus" + "github.com/byteplus-sdk/byteplus-go-sdk-v2/byteplus/request" + "github.com/byteplus-sdk/byteplus-go-sdk-v2/service/alb" +) + +const opDescribeListeners = "DescribeListeners" + +func (c *ALB) DescribeListenersRequest(input *DescribeListenersInput) (req *request.Request, output *DescribeListenersOutput) { + op := &request.Operation{ + Name: opDescribeListeners, + HTTPMethod: "GET", + HTTPPath: "/", + } + + if input == nil { + input = &DescribeListenersInput{} + } + + output = &DescribeListenersOutput{} + req = c.newRequest(op, input, output) + + return +} + +func (c *ALB) DescribeListeners(input *DescribeListenersInput) (*DescribeListenersOutput, error) { + req, out := c.DescribeListenersRequest(input) + return out, req.Send() +} + +func (c *ALB) DescribeListenersWithContext(ctx byteplus.Context, input *DescribeListenersInput, opts ...request.Option) (*DescribeListenersOutput, error) { + req, out := c.DescribeListenersRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type DescribeListenersInput = alb.DescribeListenersInput + +type DescribeListenersOutput = alb.DescribeListenersOutput diff --git a/pkg/sdk3rd-trimmed/github.com/byteplus-sdk/byteplus-go-sdk-v2/service/alb/api_describe_load_balancer_attributes.go b/pkg/sdk3rd-trimmed/github.com/byteplus-sdk/byteplus-go-sdk-v2/service/alb/api_describe_load_balancer_attributes.go new file mode 100644 index 000000000..8f93668f0 --- /dev/null +++ b/pkg/sdk3rd-trimmed/github.com/byteplus-sdk/byteplus-go-sdk-v2/service/alb/api_describe_load_balancer_attributes.go @@ -0,0 +1,42 @@ +package alb + +import ( + "github.com/byteplus-sdk/byteplus-go-sdk-v2/byteplus" + "github.com/byteplus-sdk/byteplus-go-sdk-v2/byteplus/request" + "github.com/byteplus-sdk/byteplus-go-sdk-v2/service/alb" +) + +const opDescribeLoadBalancerAttributes = "DescribeLoadBalancerAttributes" + +func (c *ALB) DescribeLoadBalancerAttributesRequest(input *DescribeLoadBalancerAttributesInput) (req *request.Request, output *DescribeLoadBalancerAttributesOutput) { + op := &request.Operation{ + Name: opDescribeLoadBalancerAttributes, + HTTPMethod: "GET", + HTTPPath: "/", + } + + if input == nil { + input = &DescribeLoadBalancerAttributesInput{} + } + + output = &DescribeLoadBalancerAttributesOutput{} + req = c.newRequest(op, input, output) + + return +} + +func (c *ALB) DescribeLoadBalancerAttributes(input *DescribeLoadBalancerAttributesInput) (*DescribeLoadBalancerAttributesOutput, error) { + req, out := c.DescribeLoadBalancerAttributesRequest(input) + return out, req.Send() +} + +func (c *ALB) DescribeLoadBalancerAttributesWithContext(ctx byteplus.Context, input *DescribeLoadBalancerAttributesInput, opts ...request.Option) (*DescribeLoadBalancerAttributesOutput, error) { + req, out := c.DescribeLoadBalancerAttributesRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type DescribeLoadBalancerAttributesInput = alb.DescribeLoadBalancerAttributesInput + +type DescribeLoadBalancerAttributesOutput = alb.DescribeLoadBalancerAttributesOutput diff --git a/pkg/sdk3rd-trimmed/github.com/byteplus-sdk/byteplus-go-sdk-v2/service/alb/api_modify_listener_attributes.go b/pkg/sdk3rd-trimmed/github.com/byteplus-sdk/byteplus-go-sdk-v2/service/alb/api_modify_listener_attributes.go new file mode 100644 index 000000000..a755c1710 --- /dev/null +++ b/pkg/sdk3rd-trimmed/github.com/byteplus-sdk/byteplus-go-sdk-v2/service/alb/api_modify_listener_attributes.go @@ -0,0 +1,44 @@ +package alb + +import ( + "github.com/byteplus-sdk/byteplus-go-sdk-v2/byteplus" + "github.com/byteplus-sdk/byteplus-go-sdk-v2/byteplus/request" + "github.com/byteplus-sdk/byteplus-go-sdk-v2/service/alb" +) + +const opModifyListenerAttributes = "ModifyListenerAttributes" + +func (c *ALB) ModifyListenerAttributesRequest(input *ModifyListenerAttributesInput) (req *request.Request, output *ModifyListenerAttributesOutput) { + op := &request.Operation{ + Name: opModifyListenerAttributes, + HTTPMethod: "GET", + HTTPPath: "/", + } + + if input == nil { + input = &ModifyListenerAttributesInput{} + } + + output = &ModifyListenerAttributesOutput{} + req = c.newRequest(op, input, output) + + return +} + +func (c *ALB) ModifyListenerAttributes(input *ModifyListenerAttributesInput) (*ModifyListenerAttributesOutput, error) { + req, out := c.ModifyListenerAttributesRequest(input) + return out, req.Send() +} + +func (c *ALB) ModifyListenerAttributesWithContext(ctx byteplus.Context, input *ModifyListenerAttributesInput, opts ...request.Option) (*ModifyListenerAttributesOutput, error) { + req, out := c.ModifyListenerAttributesRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type ModifyListenerAttributesInput = alb.ModifyListenerAttributesInput + +type ModifyListenerAttributesOutput = alb.ModifyListenerAttributesOutput + +type DomainExtensionForModifyListenerAttributesInput = alb.DomainExtensionForModifyListenerAttributesInput diff --git a/pkg/sdk3rd-trimmed/github.com/byteplus-sdk/byteplus-go-sdk-v2/service/alb/service_alb.go b/pkg/sdk3rd-trimmed/github.com/byteplus-sdk/byteplus-go-sdk-v2/service/alb/service_alb.go new file mode 100644 index 000000000..4e7ced9fe --- /dev/null +++ b/pkg/sdk3rd-trimmed/github.com/byteplus-sdk/byteplus-go-sdk-v2/service/alb/service_alb.go @@ -0,0 +1,60 @@ +package alb + +import ( + "github.com/byteplus-sdk/byteplus-go-sdk-v2/byteplus" + "github.com/byteplus-sdk/byteplus-go-sdk-v2/byteplus/byteplusquery" + "github.com/byteplus-sdk/byteplus-go-sdk-v2/byteplus/client" + "github.com/byteplus-sdk/byteplus-go-sdk-v2/byteplus/client/metadata" + "github.com/byteplus-sdk/byteplus-go-sdk-v2/byteplus/corehandlers" + "github.com/byteplus-sdk/byteplus-go-sdk-v2/byteplus/request" + "github.com/byteplus-sdk/byteplus-go-sdk-v2/byteplus/signer/byteplussign" + "github.com/byteplus-sdk/byteplus-go-sdk-v2/service/alb" +) + +type ALB struct { + *client.Client +} + +const ( + ServiceName = alb.ServiceName + EndpointsID = alb.EndpointsID + ServiceID = alb.ServiceID +) + +func New(p client.ConfigProvider, cfgs ...*byteplus.Config) *ALB { + c := p.ClientConfig(EndpointsID, cfgs...) + return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +func newClient(cfg byteplus.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *ALB { + svc := &ALB{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: ServiceName, + ServiceID: ServiceID, + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "2020-04-01", + }, + handlers, + ), + } + + svc.Handlers.Build.PushBackNamed(corehandlers.SDKVersionUserAgentHandler) + svc.Handlers.Build.PushBackNamed(corehandlers.AddHostExecEnvUserAgentHandler) + svc.Handlers.Sign.PushBackNamed(byteplussign.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(byteplusquery.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(byteplusquery.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(byteplusquery.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(byteplusquery.UnmarshalErrorHandler) + + return svc +} + +func (c *ALB) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} diff --git a/ui/src/components/workflow/designer/forms/BizDeployNodeConfigFieldsProvider.tsx b/ui/src/components/workflow/designer/forms/BizDeployNodeConfigFieldsProvider.tsx index 16b9cdea8..525b951f1 100644 --- a/ui/src/components/workflow/designer/forms/BizDeployNodeConfigFieldsProvider.tsx +++ b/ui/src/components/workflow/designer/forms/BizDeployNodeConfigFieldsProvider.tsx @@ -37,6 +37,7 @@ import BizDeployNodeConfigFieldsProviderBaotaPanelGoConsole from "./BizDeployNod import BizDeployNodeConfigFieldsProviderBaotaWAF from "./BizDeployNodeConfigFieldsProviderBaotaWAF"; import BizDeployNodeConfigFieldsProviderBaotaWAFConsole from "./BizDeployNodeConfigFieldsProviderBaotaWAFConsole"; import BizDeployNodeConfigFieldsProviderBunnyCDN from "./BizDeployNodeConfigFieldsProviderBunnyCDN"; +import BizDeployNodeConfigFieldsProviderBytePlusALB from "./BizDeployNodeConfigFieldsProviderBytePlusALB"; import BizDeployNodeConfigFieldsProviderBytePlusCDN from "./BizDeployNodeConfigFieldsProviderBytePlusCDN"; import BizDeployNodeConfigFieldsProviderBytePlusCertCenter from "./BizDeployNodeConfigFieldsProviderBytePlusCertCenter"; import BizDeployNodeConfigFieldsProviderBytePlusMediaLive from "./BizDeployNodeConfigFieldsProviderBytePlusMediaLive"; @@ -167,6 +168,7 @@ const providerComponentMap: Partial { + const { i18n, t } = useTranslation(); + + const { parentNamePath } = useFormNestedFieldsContext(); + const formSchema = z.object({ + [parentNamePath]: getSchema({ i18n }), + }); + const formRule = createSchemaFieldRule(formSchema); + const formInst = Form.useFormInstance(); + const initialValues = getInitialValues(); + + const fieldResourceType = Form.useWatch([parentNamePath, "deployTarget"], formInst); + + return ( + <> + } + > + + + + + + + + + + } + > + + + + + + + + + + + ); +}; + +const getInitialValues = (): Nullish>> => { + return { + region: "", + deployTarget: DEPLOY_TARGET_LISTENER, + }; +}; + +const getSchema = ({ i18n = getI18n() }: { i18n?: ReturnType }) => { + const { t } = i18n; + + return z + .object({ + region: z.string().nonempty(), + deployTarget: z.enum([DEPLOY_TARGET_LOADBALANCER, DEPLOY_TARGET_LISTENER]), + loadbalancerId: z.string().nullish(), + listenerId: z.string().nullish(), + domain: z + .string() + .nullish() + .refine((v) => { + if (!v) return true; + return isDomain(v, { allowWildcard: true }); + }, t("common.errmsg.domain_invalid")), + }) + .superRefine((values, ctx) => { + switch (values.deployTarget) { + case DEPLOY_TARGET_LOADBALANCER: + { + const scLoadbalancerId = z.string().nonempty(); + const spLoadbalancerId = scLoadbalancerId.safeParse(values.loadbalancerId); + if (!spLoadbalancerId.success) { + ctx.addIssue({ + code: "custom", + message: z.treeifyError(spLoadbalancerId.error).errors.join(), + path: ["loadbalancerId"], + }); + } + } + break; + + case DEPLOY_TARGET_LISTENER: + { + const scListenerId = z.string().nonempty(); + const spListenerId = scListenerId.safeParse(values.listenerId); + if (!spListenerId.success) { + ctx.addIssue({ + code: "custom", + message: z.treeifyError(spListenerId.error).errors.join(), + path: ["listenerId"], + }); + } + } + break; + } + }); +}; + +const _default = Object.assign(BizDeployNodeConfigFieldsProviderBytePlusALB, { + getInitialValues, + getSchema, +}); + +export default _default; diff --git a/ui/src/domain/provider.ts b/ui/src/domain/provider.ts index 7f9592281..4a17367a4 100644 --- a/ui/src/domain/provider.ts +++ b/ui/src/domain/provider.ts @@ -621,6 +621,7 @@ export const DEPLOYMENT_PROVIDERS = Object.freeze({ BAOTAWAF: `${ACCESS_PROVIDERS.BAOTAWAF}`, BAOTAWAF_CONSOLE: `${ACCESS_PROVIDERS.BAOTAWAF}-console`, BUNNY_CDN: `${ACCESS_PROVIDERS.BUNNY}-cdn`, + BYTEPLUS_ALB: `${ACCESS_PROVIDERS.BYTEPLUS}-alb`, BYTEPLUS_CDN: `${ACCESS_PROVIDERS.BYTEPLUS}-cdn`, BYTEPLUS_CERTCENTER: `${ACCESS_PROVIDERS.BYTEPLUS}-certcenter`, BYTEPLUS_MEDIALIVE: `${ACCESS_PROVIDERS.BYTEPLUS}-medialive`, @@ -829,6 +830,7 @@ export const deploymentProvidersMap: Maphttps://dash.bunny.net/cdn" }, + "byteplus_alb_region": { + "label": "BytePlus region", + "placeholder": "Please enter BytePlus ALB region (e.g. ap-southeast-1)", + "tooltip": "For more information, see https://docs.byteplus.com/en/docs/clb/Regions-and-Availability-Zones" + }, + "byteplus_alb_deploy_target": { + "option": { + "loadbalancer": { + "label": "ALB load balancer" + }, + "listener": { + "label": "ALB listener" + } + } + }, + "byteplus_alb_loadbalancer_id": { + "label": "BytePlus ALB load balancer ID", + "placeholder": "Please enter BytePlus ALB load balancer ID", + "tooltip": "For more information, see https://console.byteplus.com/alb" + }, + "byteplus_alb_listener_id": { + "label": "BytePlus ALB listener ID", + "placeholder": "Please enter BytePlus ALB listener ID", + "tooltip": "For more information, see https://console.byteplus.com/alb" + }, + "byteplus_alb_snidomain": { + "label": "BytePlus ALB SNI domain (Optional)", + "placeholder": "Please enter BytePlus ALB SNI domain name", + "help": "Notes: Leave it blank to set the default certificate; otherwise, to set the extension one for SNI." + }, "byteplus_cdn_domain": { "label": "BytePlus CDN domain", "placeholder": "Please enter BytePlus CDN domain name" @@ -1223,8 +1253,8 @@ }, "byteplus_tos_region": { "label": "BytePlus region", - "placeholder": "Please enter BytePlus TOS region (e.g. ap-singapore-1)", - "tooltip": "For more information, see https://www.volcengine.com/docs/6349/107356" + "placeholder": "Please enter BytePlus TOS region (e.g. ap-southeast-1)", + "tooltip": "For more information, see https://docs.byteplus.com/en/docs/tos/docs-region-and-endpoint" }, "byteplus_tos_bucket": { "label": "BytePlus TOS bucket", diff --git a/ui/src/i18n/resources/zh/nls.provider.json b/ui/src/i18n/resources/zh/nls.provider.json index 944ba08ff..7da7f255b 100644 --- a/ui/src/i18n/resources/zh/nls.provider.json +++ b/ui/src/i18n/resources/zh/nls.provider.json @@ -89,6 +89,7 @@ "bunny": "Bunny", "bunny_cdn": "Bunny - 内容分发网络 CDN", "byteplus": "BytePlus", + "byteplus_alb": "BytePlus - 应用型负载均衡 ALB", "byteplus_cdn": "BytePlus - 内容分发网络 CDN", "byteplus_certcenter_upload": "BytePlus - 上传到证书中心", "byteplus_dns": "BytePlus - DNS Suite", diff --git a/ui/src/i18n/resources/zh/nls.workflow.nodes.json b/ui/src/i18n/resources/zh/nls.workflow.nodes.json index aed2f7832..2343e81d5 100644 --- a/ui/src/i18n/resources/zh/nls.workflow.nodes.json +++ b/ui/src/i18n/resources/zh/nls.workflow.nodes.json @@ -1208,6 +1208,36 @@ "placeholder": "请输入 Bunny CDN 主机名", "tooltip": "这是什么?请参阅 https://dash.bunny.net/cdn" }, + "byteplus_alb_deploy_target": { + "option": { + "loadbalancer": { + "label": "部署到指定负载均衡器下的全部 HTTPS 监听" + }, + "listener": { + "label": "部署到指定 HTTPS 监听器" + } + } + }, + "byteplus_alb_region": { + "label": "BytePlus 服务地域", + "placeholder": "请输入 BytePlus ALB 服务地域(例如:cn-beijing)", + "tooltip": "这是什么?请参阅 https://docs.byteplus.com/en/docs/clb/Regions-and-Availability-Zones" + }, + "byteplus_alb_loadbalancer_id": { + "label": "BytePlus ALB 负载均衡器 ID", + "placeholder": "请输入 BytePlus ALB 负载均衡器 ID", + "tooltip": "这是什么?请参阅 https://console.byteplus.com/alb" + }, + "byteplus_alb_listener_id": { + "label": "BytePlus ALB 监听器 ID", + "placeholder": "请输入 BytePlus ALB 监听器 ID", + "tooltip": "这是什么?请参阅 https://console.byteplus.com/alb" + }, + "byteplus_alb_snidomain": { + "label": "BytePlus ALB 扩展域名(可选)", + "placeholder": "请输入 BytePlus ALB 扩展域名", + "help": "提示:不填写时,将替换监听器的默认证书;否则,将替换扩展域名证书。" + }, "byteplus_cdn_domain": { "label": "BytePlus CDN 域名", "placeholder": "请输入 BytePlus CDN 域名" @@ -1222,8 +1252,8 @@ }, "byteplus_tos_region": { "label": "BytePlus 服务地域", - "placeholder": "请输入 BytePlus TOS 服务地域(例如:ap-singapore-1)", - "tooltip": "这是什么?请参阅 https://www.volcengine.com/docs/6349/107356" + "placeholder": "请输入 BytePlus TOS 服务地域(例如:ap-southeast-1)", + "tooltip": "这是什么?请参阅 https://docs.byteplus.com/en/docs/tos/docs-region-and-endpoint" }, "byteplus_tos_bucket": { "label": "BytePlus TOS 存储桶名",