feat: add huaweicloud elb deployer

This commit is contained in:
Fu Diwei 2024-10-24 22:37:55 +08:00
parent af3e20709d
commit dc720a5d99
13 changed files with 673 additions and 37 deletions

View File

@ -21,6 +21,7 @@ const (
targetTencentCDN = "tencent-cdn"
targetTencentCOS = "tencent-cos"
targetHuaweiCloudCDN = "huaweicloud-cdn"
targetHuaweiCloudELB = "huaweicloud-elb"
targetQiniuCdn = "qiniu-cdn"
targetLocal = "local"
targetSSH = "ssh"
@ -110,6 +111,8 @@ func getWithDeployConfig(record *models.Record, cert *applicant.Certificate, dep
return NewTencentCOSDeployer(option)
case targetHuaweiCloudCDN:
return NewHuaweiCloudCDNDeployer(option)
case targetHuaweiCloudELB:
return NewHuaweiCloudELBDeployer(option)
case targetQiniuCdn:
return NewQiniuCDNDeployer(option)
case targetLocal:

View File

@ -31,9 +31,9 @@ func NewHuaweiCloudCDNDeployer(option *DeployerOption) (Deployer, error) {
}
client, err := (&HuaweiCloudCDNDeployer{}).createSdkClient(
option.DeployConfig.GetConfigAsString("region"),
access.AccessKeyId,
access.SecretAccessKey,
option.DeployConfig.GetConfigAsString("region"),
)
if err != nil {
return nil, err
@ -119,7 +119,7 @@ func (d *HuaweiCloudCDNDeployer) Deploy(ctx context.Context) error {
return nil
}
func (d *HuaweiCloudCDNDeployer) createSdkClient(region, accessKeyId, secretAccessKey string) (*hcCdn.CdnClient, error) {
func (d *HuaweiCloudCDNDeployer) createSdkClient(accessKeyId, secretAccessKey, region string) (*hcCdn.CdnClient, error) {
if region == "" {
region = "cn-north-1" // CDN 服务默认区域:华北一北京
}

View File

@ -0,0 +1,365 @@
package deployer
import (
"context"
"encoding/json"
"errors"
"fmt"
"sort"
"strings"
"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/basic"
"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/global"
hcElb "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/elb/v3"
hcElbModel "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/elb/v3/model"
hcElbRegion "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/elb/v3/region"
hcIam "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/iam/v3"
hcIamModel "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/iam/v3/model"
hcIamRegion "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/iam/v3/region"
"github.com/usual2970/certimate/internal/domain"
"github.com/usual2970/certimate/internal/pkg/core/uploader"
"github.com/usual2970/certimate/internal/pkg/utils/cast"
)
type HuaweiCloudELBDeployer struct {
option *DeployerOption
infos []string
sdkClient *hcElb.ElbClient
sslUploader uploader.Uploader
}
func NewHuaweiCloudELBDeployer(option *DeployerOption) (Deployer, error) {
access := &domain.HuaweiCloudAccess{}
if err := json.Unmarshal([]byte(option.Access), access); err != nil {
return nil, err
}
client, err := (&HuaweiCloudELBDeployer{}).createSdkClient(
access.AccessKeyId,
access.SecretAccessKey,
option.DeployConfig.GetConfigAsString("region"),
)
if err != nil {
return nil, err
}
uploader, err := uploader.NewHuaweiCloudELBUploader(&uploader.HuaweiCloudELBUploaderConfig{
Region: option.DeployConfig.GetConfigAsString("region"),
AccessKeyId: access.AccessKeyId,
SecretAccessKey: access.SecretAccessKey,
})
if err != nil {
return nil, err
}
return &HuaweiCloudELBDeployer{
option: option,
infos: make([]string, 0),
sdkClient: client,
sslUploader: uploader,
}, nil
}
func (d *HuaweiCloudELBDeployer) GetID() string {
return fmt.Sprintf("%s-%s", d.option.AccessRecord.GetString("name"), d.option.AccessRecord.Id)
}
func (d *HuaweiCloudELBDeployer) GetInfo() []string {
return d.infos
}
func (d *HuaweiCloudELBDeployer) Deploy(ctx context.Context) error {
switch d.option.DeployConfig.GetConfigAsString("resourceType") {
case "certificate":
if err := d.deployToCertificate(ctx); err != nil {
return err
}
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 *HuaweiCloudELBDeployer) createSdkClient(accessKeyId, secretAccessKey, region string) (*hcElb.ElbClient, error) {
if region == "" {
region = "cn-north-4" // ELB 服务默认区域:华北四北京
}
projectId, err := (&HuaweiCloudELBDeployer{}).getSdkProjectId(
accessKeyId,
secretAccessKey,
region,
)
if err != nil {
return nil, err
}
auth, err := basic.NewCredentialsBuilder().
WithAk(accessKeyId).
WithSk(secretAccessKey).
WithProjectId(projectId).
SafeBuild()
if err != nil {
return nil, err
}
hcRegion, err := hcElbRegion.SafeValueOf(region)
if err != nil {
return nil, err
}
hcClient, err := hcElb.ElbClientBuilder().
WithRegion(hcRegion).
WithCredential(auth).
SafeBuild()
if err != nil {
return nil, err
}
client := hcElb.NewElbClient(hcClient)
return client, nil
}
func (u *HuaweiCloudELBDeployer) getSdkProjectId(accessKeyId, secretAccessKey, region string) (string, error) {
if region == "" {
region = "cn-north-4" // IAM 服务默认区域:华北四北京
}
auth, err := global.NewCredentialsBuilder().
WithAk(accessKeyId).
WithSk(secretAccessKey).
SafeBuild()
if err != nil {
return "", err
}
hcRegion, err := hcIamRegion.SafeValueOf(region)
if err != nil {
return "", err
}
hcClient, err := hcIam.IamClientBuilder().
WithRegion(hcRegion).
WithCredential(auth).
SafeBuild()
if err != nil {
return "", err
}
client := hcIam.NewIamClient(hcClient)
if err != nil {
return "", err
}
request := &hcIamModel.KeystoneListProjectsRequest{
Name: &region,
}
response, err := client.KeystoneListProjects(request)
if err != nil {
return "", err
} else if response.Projects == nil || len(*response.Projects) == 0 {
return "", fmt.Errorf("no project found")
}
return (*response.Projects)[0].Id, nil
}
func (d *HuaweiCloudELBDeployer) deployToCertificate(ctx context.Context) error {
// 更新证书
// REF: https://support.huaweicloud.com/api-elb/UpdateCertificate.html
updateCertificateReq := &hcElbModel.UpdateCertificateRequest{
CertificateId: d.option.DeployConfig.GetConfigAsString("certificateId"),
Body: &hcElbModel.UpdateCertificateRequestBody{
Certificate: &hcElbModel.UpdateCertificateOption{
Certificate: cast.StringPtr(d.option.Certificate.Certificate),
PrivateKey: cast.StringPtr(d.option.Certificate.PrivateKey),
},
},
}
updateCertificateResp, err := d.sdkClient.UpdateCertificate(updateCertificateReq)
if err != nil {
return fmt.Errorf("failed to execute sdk request 'elb.UpdateCertificate': %w", err)
}
d.infos = append(d.infos, toStr("已更新 ELB 证书", updateCertificateResp))
return nil
}
func (d *HuaweiCloudELBDeployer) deployToLoadbalancer(ctx context.Context) error {
// 查询负载均衡器详情
// REF: https://support.huaweicloud.com/api-elb/ShowLoadBalancer.html
showLoadBalancerReq := &hcElbModel.ShowLoadBalancerRequest{
LoadbalancerId: d.option.DeployConfig.GetConfigAsString("loadbalancerId"),
}
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))
// 查询监听器列表
// REF: https://support.huaweicloud.com/api-elb/ListListeners.html
listenerIds := make([]string, 0)
listListenersLimit := int32(2000)
var listListenersMarker *string = nil
for {
listListenersReq := &hcElbModel.ListListenersRequest{
Limit: cast.Int32Ptr(listListenersLimit),
Marker: listListenersMarker,
Protocol: &[]string{"HTTPS", "TERMINATED_HTTPS"},
LoadbalancerId: &[]string{showLoadBalancerResp.Loadbalancer.Id},
}
listListenersResp, err := d.sdkClient.ListListeners(listListenersReq)
if err != nil {
return fmt.Errorf("failed to execute sdk request 'elb.ListListeners': %w", err)
}
if listListenersResp.Listeners != nil {
for _, listener := range *listListenersResp.Listeners {
listenerIds = append(listenerIds, listener.Id)
}
}
if listListenersResp.Listeners == nil || len(*listListenersResp.Listeners) < int(listListenersLimit) {
break
} else {
listListenersMarker = listListenersResp.PageInfo.NextMarker
}
}
d.infos = append(d.infos, toStr("已查询到到 ELB 负载均衡器下的监听器", listenerIds))
// 上传证书到 SCM
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 _, listenerId := range listenerIds {
if err := d.updateListenerCertificate(ctx, listenerId, uploadResult.CertId); err != nil {
errs = append(errs, err)
}
}
if len(errs) > 0 {
return errors.Join(errs...)
}
return nil
}
func (d *HuaweiCloudELBDeployer) deployToListener(ctx context.Context) error {
// 上传证书到 SCM
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, d.option.DeployConfig.GetConfigAsString("listenerId"), uploadResult.CertId); err != nil {
return err
}
return nil
}
func (d *HuaweiCloudELBDeployer) updateListenerCertificate(ctx context.Context, hcListenerId string, hcCertId string) error {
// 查询监听器详情
// REF: https://support.huaweicloud.com/api-elb/ShowListener.html
showListenerReq := &hcElbModel.ShowListenerRequest{
ListenerId: hcListenerId,
}
showListenerResp, err := d.sdkClient.ShowListener(showListenerReq)
if err != nil {
return fmt.Errorf("failed to execute sdk request 'elb.ShowListener': %w", err)
}
d.infos = append(d.infos, toStr("已查询到到 ELB 监听器", showListenerResp))
// 更新监听器
// REF: https://support.huaweicloud.com/api-elb/UpdateListener.html
updateListenerReq := &hcElbModel.UpdateListenerRequest{
ListenerId: hcListenerId,
Body: &hcElbModel.UpdateListenerRequestBody{
Listener: &hcElbModel.UpdateListenerOption{
DefaultTlsContainerRef: cast.StringPtr(hcCertId),
},
},
}
if showListenerResp.Listener.SniContainerRefs != nil {
if len(showListenerResp.Listener.SniContainerRefs) > 0 {
// 如果开启 SNI需替换同 SAN 的证书
sniCertIds := make([]string, 0)
sniCertIds = append(sniCertIds, hcCertId)
listOldCertificateReq := &hcElbModel.ListCertificatesRequest{
Id: &showListenerResp.Listener.SniContainerRefs,
}
listOldCertificateResp, err := d.sdkClient.ListCertificates(listOldCertificateReq)
if err != nil {
return fmt.Errorf("failed to execute sdk request 'elb.ListCertificates': %w", err)
}
showNewCertificateReq := &hcElbModel.ShowCertificateRequest{
CertificateId: hcCertId,
}
showNewCertificateResp, err := d.sdkClient.ShowCertificate(showNewCertificateReq)
if err != nil {
return fmt.Errorf("failed to execute sdk request 'elb.ShowCertificate': %w", err)
}
for _, certificate := range *listOldCertificateResp.Certificates {
oldCertificate := certificate
newCertificate := showNewCertificateResp.Certificate
if oldCertificate.SubjectAlternativeNames != nil && newCertificate.SubjectAlternativeNames != nil {
oldCertificateSans := oldCertificate.SubjectAlternativeNames
newCertificateSans := newCertificate.SubjectAlternativeNames
sort.Strings(*oldCertificateSans)
sort.Strings(*newCertificateSans)
if strings.Join(*oldCertificateSans, ";") == strings.Join(*newCertificateSans, ";") {
continue
}
} else {
if oldCertificate.Domain == newCertificate.Domain {
continue
}
}
sniCertIds = append(sniCertIds, certificate.Id)
}
updateListenerReq.Body.Listener.SniContainerRefs = &sniCertIds
}
if showListenerResp.Listener.SniMatchAlgo != "" {
updateListenerReq.Body.Listener.SniMatchAlgo = cast.StringPtr(showListenerResp.Listener.SniMatchAlgo)
}
}
updateListenerResp, err := d.sdkClient.UpdateListener(updateListenerReq)
if err != nil {
return fmt.Errorf("failed to execute sdk request 'elb.UpdateListener': %w", err)
}
d.infos = append(d.infos, toStr("已更新监听器", updateListenerResp))
return nil
}

View File

@ -6,19 +6,22 @@ import (
"time"
"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/basic"
"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/global"
hcElb "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/elb/v3"
hcElbModel "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/elb/v3/model"
hcElbRegion "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/elb/v3/region"
hcIam "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/iam/v3"
hcIamModel "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/iam/v3/model"
hcIamRegion "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/iam/v3/region"
"github.com/usual2970/certimate/internal/pkg/utils/cast"
"github.com/usual2970/certimate/internal/pkg/utils/x509"
)
type HuaweiCloudELBUploaderConfig struct {
Region string `json:"region"`
ProjectId string `json:"projectId"`
AccessKeyId string `json:"accessKeyId"`
SecretAccessKey string `json:"secretAccessKey"`
Region string `json:"region"`
}
type HuaweiCloudELBUploader struct {
@ -28,9 +31,9 @@ type HuaweiCloudELBUploader struct {
func NewHuaweiCloudELBUploader(config *HuaweiCloudELBUploaderConfig) (Uploader, error) {
client, err := (&HuaweiCloudELBUploader{}).createSdkClient(
config.Region,
config.AccessKeyId,
config.SecretAccessKey,
config.Region,
)
if err != nil {
return nil, fmt.Errorf("failed to create sdk client: %w", err)
@ -100,6 +103,13 @@ func (u *HuaweiCloudELBUploader) Upload(ctx context.Context, certPem string, pri
}
}
// 获取项目 ID
// REF: https://support.huaweicloud.com/api-iam/iam_06_0001.html
projectId, err := u.getSdkProjectId(u.config.Region, u.config.AccessKeyId, u.config.SecretAccessKey)
if err != nil {
return nil, fmt.Errorf("failed to get SDK project id: %w", err)
}
// 生成新证书名(需符合华为云命名规则)
var certId, certName string
certName = fmt.Sprintf("certimate-%d", time.Now().UnixMilli())
@ -109,7 +119,7 @@ func (u *HuaweiCloudELBUploader) Upload(ctx context.Context, certPem string, pri
createCertificateReq := &hcElbModel.CreateCertificateRequest{
Body: &hcElbModel.CreateCertificateRequestBody{
Certificate: &hcElbModel.CreateCertificateOption{
ProjectId: cast.StringPtr(u.config.ProjectId),
ProjectId: cast.StringPtr(projectId),
Name: cast.StringPtr(certName),
Certificate: cast.StringPtr(certPem),
PrivateKey: cast.StringPtr(privkeyPem),
@ -129,7 +139,7 @@ func (u *HuaweiCloudELBUploader) Upload(ctx context.Context, certPem string, pri
}, nil
}
func (u *HuaweiCloudELBUploader) createSdkClient(region, accessKeyId, secretAccessKey string) (*hcElb.ElbClient, error) {
func (u *HuaweiCloudELBUploader) createSdkClient(accessKeyId, secretAccessKey, region string) (*hcElb.ElbClient, error) {
if region == "" {
region = "cn-north-4" // ELB 服务默认区域:华北四北京
}
@ -158,3 +168,47 @@ func (u *HuaweiCloudELBUploader) createSdkClient(region, accessKeyId, secretAcce
client := hcElb.NewElbClient(hcClient)
return client, nil
}
func (u *HuaweiCloudELBUploader) getSdkProjectId(accessKeyId, secretAccessKey, region string) (string, error) {
if region == "" {
region = "cn-north-4" // IAM 服务默认区域:华北四北京
}
auth, err := global.NewCredentialsBuilder().
WithAk(accessKeyId).
WithSk(secretAccessKey).
SafeBuild()
if err != nil {
return "", err
}
hcRegion, err := hcIamRegion.SafeValueOf(region)
if err != nil {
return "", err
}
hcClient, err := hcIam.IamClientBuilder().
WithRegion(hcRegion).
WithCredential(auth).
SafeBuild()
if err != nil {
return "", err
}
client := hcIam.NewIamClient(hcClient)
if err != nil {
return "", err
}
request := &hcIamModel.KeystoneListProjectsRequest{
Name: &region,
}
response, err := client.KeystoneListProjects(request)
if err != nil {
return "", err
} else if response.Projects == nil || len(*response.Projects) == 0 {
return "", fmt.Errorf("no project found")
}
return (*response.Projects)[0].Id, nil
}

View File

@ -15,9 +15,9 @@ import (
)
type HuaweiCloudSCMUploaderConfig struct {
Region string `json:"region"`
AccessKeyId string `json:"accessKeyId"`
SecretAccessKey string `json:"secretAccessKey"`
Region string `json:"region"`
}
type HuaweiCloudSCMUploader struct {
@ -27,9 +27,9 @@ type HuaweiCloudSCMUploader struct {
func NewHuaweiCloudSCMUploader(config *HuaweiCloudSCMUploaderConfig) (Uploader, error) {
client, err := (&HuaweiCloudSCMUploader{}).createSdkClient(
config.Region,
config.AccessKeyId,
config.SecretAccessKey,
config.Region,
)
if err != nil {
return nil, fmt.Errorf("failed to create sdk client: %w", err)
@ -137,7 +137,7 @@ func (u *HuaweiCloudSCMUploader) Upload(ctx context.Context, certPem string, pri
}, nil
}
func (u *HuaweiCloudSCMUploader) createSdkClient(region, accessKeyId, secretAccessKey string) (*hcScm.ScmClient, error) {
func (u *HuaweiCloudSCMUploader) createSdkClient(accessKeyId, secretAccessKey, region string) (*hcScm.ScmClient, error) {
if region == "" {
region = "cn-north-4" // SCM 服务默认区域:华北四北京
}

View File

@ -14,6 +14,7 @@ import DeployToAliyunCDN from "./DeployToAliyunCDN";
import DeployToTencentCDN from "./DeployToTencentCDN";
import DeployToTencentCOS from "./DeployToTencentCOS";
import DeployToHuaweiCloudCDN from "./DeployToHuaweiCloudCDN";
import DeployToHuaweiCloudELB from "./DeployToHuaweiCloudELB";
import DeployToQiniuCDN from "./DeployToQiniuCDN";
import DeployToSSH from "./DeployToSSH";
import DeployToWebhook from "./DeployToWebhook";
@ -82,7 +83,7 @@ const DeployEditDialog = ({ trigger, deployConfig, onSave }: DeployEditDialogPro
return true;
}
return item.configType === locDeployConfig.type.split("-")[0];
return item.configType === deployTargetsMap.get(locDeployConfig.type)?.provider;
});
const handleSaveClick = () => {
@ -125,6 +126,9 @@ const DeployEditDialog = ({ trigger, deployConfig, onSave }: DeployEditDialogPro
case "huaweicloud-cdn":
childComponent = <DeployToHuaweiCloudCDN />;
break;
case "huaweicloud-elb":
childComponent = <DeployToHuaweiCloudELB />;
break;
case "qiniu-cdn":
childComponent = <DeployToQiniuCDN />;
break;

View File

@ -12,6 +12,18 @@ const DeployToHuaweiCloudCDN = () => {
const { deploy: data, setDeploy, error, setError } = useDeployEditContext();
useEffect(() => {
if (!data.id) {
setDeploy({
...data,
config: {
region: "cn-north-1",
domain: "",
},
});
}
}, []);
useEffect(() => {
setError({});
}, []);
@ -46,12 +58,12 @@ const DeployToHuaweiCloudCDN = () => {
onChange={(e) => {
const newData = produce(data, (draft) => {
draft.config ??= {};
draft.config.region = e.target.value;
draft.config.region = e.target.value?.trim();
});
setDeploy(newData);
}}
/>
<div className="text-red-600 text-sm mt-1">{error?.domain}</div>
<div className="text-red-600 text-sm mt-1">{error?.region}</div>
</div>
<div>
@ -61,26 +73,9 @@ const DeployToHuaweiCloudCDN = () => {
className="w-full mt-1"
value={data?.config?.domain}
onChange={(e) => {
const temp = e.target.value;
const resp = domainSchema.safeParse(temp);
if (!resp.success) {
setError({
...error,
domain: JSON.parse(resp.error.message)[0].message,
});
} else {
setError({
...error,
domain: "",
});
}
const newData = produce(data, (draft) => {
if (!draft.config) {
draft.config = {};
}
draft.config.domain = temp;
draft.config ??= {};
draft.config.domain = e.target.value?.trim();
});
setDeploy(newData);
}}

View File

@ -0,0 +1,190 @@
import { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { z } from "zod";
import { produce } from "immer";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { useDeployEditContext } from "./DeployEdit";
const DeployToHuaweiCloudCDN = () => {
const { t } = useTranslation();
const { deploy: data, setDeploy, error, setError } = useDeployEditContext();
useEffect(() => {
if (!data.id) {
setDeploy({
...data,
config: {
region: "cn-north-1",
resourceType: "",
certificateId: "",
loadbalancerId: "",
listenerId: "",
},
});
}
}, []);
useEffect(() => {
setError({});
}, []);
const formSchema = z
.object({
region: z.string().min(1, t("domain.deployment.form.huaweicloud_elb_region.placeholder")),
resourceType: z.string().min(1, t("domain.deployment.form.huaweicloud_elb_resource_type.placeholder")),
certificateId: z.string().optional(),
loadbalancerId: z.string().optional(),
listenerId: z.string().optional(),
})
.refine((data) => (data.resourceType === "certificate" ? !!data.certificateId?.trim() : true), {
message: t("domain.deployment.form.huaweicloud_elb_certificate_id.placeholder"),
path: ["certificateId"],
})
.refine((data) => (data.resourceType === "loadbalancer" ? !!data.certificateId?.trim() : true), {
message: t("domain.deployment.form.huaweicloud_elb_loadbalancer_id.placeholder"),
path: ["loadbalancerId"],
})
.refine((data) => (data.resourceType === "listener" ? !!data.listenerId?.trim() : true), {
message: t("domain.deployment.form.huaweicloud_elb_listener_id.placeholder"),
path: ["listenerId"],
});
useEffect(() => {
const res = formSchema.safeParse(data.config);
if (!res.success) {
setError({
...error,
region: res.error.errors.find((e) => e.path[0] === "region")?.message,
resourceType: res.error.errors.find((e) => e.path[0] === "resourceType")?.message,
certificateId: res.error.errors.find((e) => e.path[0] === "certificateId")?.message,
loadbalancerId: res.error.errors.find((e) => e.path[0] === "loadbalancerId")?.message,
listenerId: res.error.errors.find((e) => e.path[0] === "listenerId")?.message,
});
} else {
setError({
...error,
region: undefined,
resourceType: undefined,
certificateId: undefined,
loadbalancerId: undefined,
listenerId: undefined,
});
}
}, [data]);
return (
<div className="flex flex-col space-y-8">
<div>
<Label>{t("domain.deployment.form.huaweicloud_elb_region.label")}</Label>
<Input
placeholder={t("domain.deployment.form.huaweicloud_elb_region.placeholder")}
className="w-full mt-1"
value={data?.config?.region}
onChange={(e) => {
const newData = produce(data, (draft) => {
draft.config ??= {};
draft.config.region = e.target.value?.trim();
});
setDeploy(newData);
}}
/>
<div className="text-red-600 text-sm mt-1">{error?.region}</div>
</div>
<div>
<Label>{t("domain.deployment.form.huaweicloud_elb_resource_type.label")}</Label>
<Select
value={data?.config?.resourceType}
onValueChange={(value) => {
const newData = produce(data, (draft) => {
draft.config ??= {};
draft.config.resourceType = value?.trim();
});
setDeploy(newData);
}}
>
<SelectTrigger>
<SelectValue placeholder={t("domain.deployment.form.huaweicloud_elb_resource_type.placeholder")} />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="certificate">{t("domain.deployment.form.huaweicloud_elb_resource_type.option.certificate.label")}</SelectItem>
<SelectItem value="loadbalancer">{t("domain.deployment.form.huaweicloud_elb_resource_type.option.loadbalancer.label")}</SelectItem>
<SelectItem value="listener">{t("domain.deployment.form.huaweicloud_elb_resource_type.option.listener.label")}</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<div className="text-red-600 text-sm mt-1">{error?.resourceType}</div>
</div>
{data?.config?.resourceType === "certificate" ? (
<div>
<Label>{t("domain.deployment.form.huaweicloud_elb_certificate_id.label")}</Label>
<Input
placeholder={t("domain.deployment.form.huaweicloud_elb_certificate_id.placeholder")}
className="w-full mt-1"
value={data?.config?.certificateId}
onChange={(e) => {
const newData = produce(data, (draft) => {
draft.config ??= {};
draft.config.certificateId = e.target.value?.trim();
});
setDeploy(newData);
}}
/>
<div className="text-red-600 text-sm mt-1">{error?.certificateId}</div>
</div>
) : (
<></>
)}
{data?.config?.resourceType === "loadbalancer" ? (
<div>
<Label>{t("domain.deployment.form.huaweicloud_elb_loadbalancer_id.label")}</Label>
<Input
placeholder={t("domain.deployment.form.huaweicloud_elb_loadbalancer_id.placeholder")}
className="w-full mt-1"
value={data?.config?.loadbalancerId}
onChange={(e) => {
const newData = produce(data, (draft) => {
draft.config ??= {};
draft.config.loadbalancerId = e.target.value?.trim();
});
setDeploy(newData);
}}
/>
<div className="text-red-600 text-sm mt-1">{error?.loadbalancerId}</div>
</div>
) : (
<></>
)}
{data?.config?.resourceType === "listener" ? (
<div>
<Label>{t("domain.deployment.form.huaweicloud_elb_listener_id.label")}</Label>
<Input
placeholder={t("domain.deployment.form.huaweicloud_elb_listener_id.placeholder")}
className="w-full mt-1"
value={data?.config?.listenerId}
onChange={(e) => {
const newData = produce(data, (draft) => {
draft.config ??= {};
draft.config.listenerId = e.target.value?.trim();
});
setDeploy(newData);
}}
/>
<div className="text-red-600 text-sm mt-1">{error?.listenerId}</div>
</div>
) : (
<></>
)}
</div>
);
};
export default DeployToHuaweiCloudCDN;

View File

@ -65,6 +65,7 @@ export type Statistic = {
type DeployTarget = {
type: string;
provider: string;
name: string;
icon: string;
};
@ -77,10 +78,11 @@ export const deployTargetsMap: Map<DeployTarget["type"], DeployTarget> = new Map
["tencent-cdn", "common.provider.tencent.cdn", "/imgs/providers/tencent.svg"],
["tencent-cos", "common.provider.tencent.cos", "/imgs/providers/tencent.svg"],
["huaweicloud-cdn", "common.provider.huaweicloud.cdn", "/imgs/providers/huaweicloud.svg"],
["huaweicloud-elb", "common.provider.huaweicloud.elb", "/imgs/providers/huaweicloud.svg"],
["qiniu-cdn", "common.provider.qiniu.cdn", "/imgs/providers/qiniu.svg"],
["local", "common.provider.local", "/imgs/providers/local.svg"],
["ssh", "common.provider.ssh", "/imgs/providers/ssh.svg"],
["webhook", "common.provider.webhook", "/imgs/providers/webhook.svg"],
["k8s-secret", "common.provider.kubernetes.secret", "/imgs/providers/k8s.svg"],
].map(([type, name, icon]) => [type, { type, name, icon }])
].map(([type, name, icon]) => [type, { type, provider: type.split("-")[0], name, icon }])
);

View File

@ -61,6 +61,7 @@
"common.provider.tencent.cos": "Tencent - COS",
"common.provider.huaweicloud": "Huawei Cloud",
"common.provider.huaweicloud.cdn": "Huawei Cloud - CDN",
"common.provider.huaweicloud.elb": "Huawei Cloud - ELB",
"common.provider.qiniu": "Qiniu",
"common.provider.qiniu.cdn": "Qiniu - CDN",
"common.provider.aws": "AWS",

View File

@ -66,6 +66,17 @@
"domain.deployment.form.tencent_cos_bucket.placeholder": "Please enter bucket",
"domain.deployment.form.huaweicloud_elb_region.label": "Region",
"domain.deployment.form.huaweicloud_elb_region.placeholder": "Please enter region (e.g. cn-north-1)",
"domain.deployment.form.huaweicloud_elb_resource_type.label": "Resource Type",
"domain.deployment.form.huaweicloud_elb_resource_type.placeholder": "Please select ELB resource type",
"domain.deployment.form.huaweicloud_elb_resource_type.option.certificate.label": "ELB Certificate",
"domain.deployment.form.huaweicloud_elb_resource_type.option.loadbalancer.label": "ELB LoadBalancer",
"domain.deployment.form.huaweicloud_elb_resource_type.option.listener.label": "ELB Listener",
"domain.deployment.form.huaweicloud_elb_certificate_id.label": "Certificate ID",
"domain.deployment.form.huaweicloud_elb_certificate_id.placeholder": "Please enter ELB certificate ID",
"domain.deployment.form.huaweicloud_elb_loadbalancer_id.label": "LoadBalancer ID",
"domain.deployment.form.huaweicloud_elb_loadbalancer_id.placeholder": "Please enter ELB loadbalancer ID",
"domain.deployment.form.huaweicloud_elb_listener_id.label": "Listener ID",
"domain.deployment.form.huaweicloud_elb_listener_id.placeholder": "Please enter ELB listener ID",
"domain.deployment.form.ssh_key_path.label": "Private Key Save Path",
"domain.deployment.form.ssh_key_path.placeholder": "Please enter private key save path",
"domain.deployment.form.ssh_cert_path.label": "Certificate Save Path",

View File

@ -52,15 +52,16 @@
"common.errmsg.ip_invalid": "请输入正确的 IP 地址",
"common.errmsg.url_invalid": "请输入正确的 URL",
"common.provider.tencent": "腾讯云",
"common.provider.tencent.cdn": "腾讯云 - CDN",
"common.provider.tencent.cos": "腾讯云 - COS",
"common.provider.aliyun": "阿里云",
"common.provider.aliyun.oss": "阿里云 - OSS",
"common.provider.aliyun.cdn": "阿里云 - CDN",
"common.provider.aliyun.dcdn": "阿里云 - DCDN",
"common.provider.tencent": "腾讯云",
"common.provider.tencent.cdn": "腾讯云 - CDN",
"common.provider.tencent.cos": "腾讯云 - COS",
"common.provider.huaweicloud": "华为云",
"common.provider.huaweicloud.cdn": "华为云 - CDN",
"common.provider.huaweicloud.elb": "华为云 - ELB",
"common.provider.qiniu": "七牛云",
"common.provider.qiniu.cdn": "七牛云 - CDN",
"common.provider.aws": "AWS",
@ -78,4 +79,3 @@
"common.provider.telegram": "Telegram",
"common.provider.lark": "飞书"
}

View File

@ -66,6 +66,17 @@
"domain.deployment.form.tencent_cos_bucket.placeholder": "请输入存储桶名",
"domain.deployment.form.huaweicloud_elb_region.label": "地域",
"domain.deployment.form.huaweicloud_elb_region.placeholder": "请输入地域(如 cn-north-1",
"domain.deployment.form.huaweicloud_elb_resource_type.label": "资源类型替换方式",
"domain.deployment.form.huaweicloud_elb_resource_type.placeholder": "请选择资源类型替换方式",
"domain.deployment.form.huaweicloud_elb_resource_type.option.certificate.label": "按证书替换",
"domain.deployment.form.huaweicloud_elb_resource_type.option.loadbalancer.label": "按负载均衡器替换",
"domain.deployment.form.huaweicloud_elb_resource_type.option.listener.label": "按监听器替换",
"domain.deployment.form.huaweicloud_elb_certificate_id.label": "证书 ID",
"domain.deployment.form.huaweicloud_elb_certificate_id.placeholder": "请输入证书 ID可从华为云控制面板获取",
"domain.deployment.form.huaweicloud_elb_loadbalancer_id.label": "负载均衡器 ID",
"domain.deployment.form.huaweicloud_elb_loadbalancer_id.placeholder": "请输入负载均衡器 ID可从华为云控制面板获取",
"domain.deployment.form.huaweicloud_elb_listener_id.label": "监听器 ID",
"domain.deployment.form.huaweicloud_elb_listener_id.placeholder": "请输入监听器 ID可从华为云控制面板获取",
"domain.deployment.form.ssh_key_path.label": "私钥保存路径",
"domain.deployment.form.ssh_key_path.placeholder": "请输入私钥保存路径",
"domain.deployment.form.ssh_cert_path.label": "证书保存路径",