This commit is contained in:
yoan
2024-08-21 12:19:12 +08:00
commit 50fa238d88
89 changed files with 11835 additions and 0 deletions

191
internal/deployer/aliyun.go Normal file
View File

@@ -0,0 +1,191 @@
package deployer
import (
"certimate/internal/applicant"
"certimate/internal/utils/rand"
"context"
"encoding/json"
"errors"
"fmt"
"strings"
cas20200407 "github.com/alibabacloud-go/cas-20200407/v2/client"
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
util "github.com/alibabacloud-go/tea-utils/v2/service"
"github.com/alibabacloud-go/tea/tea"
)
type aliyunAccess struct {
AccessKeyId string `json:"accessKeyId"`
AccessKeySecret string `json:"accessKeySecret"`
}
type aliyun struct {
client *cas20200407.Client
option *DeployerOption
}
func NewAliyun(option *DeployerOption) (Deployer, error) {
access := &aliyunAccess{}
json.Unmarshal([]byte(option.Access), access)
a := &aliyun{
option: option,
}
client, err := a.createClient(access.AccessKeyId, access.AccessKeySecret)
if err != nil {
return nil, err
}
a.client = client
return a, nil
}
func (a *aliyun) Deploy(ctx context.Context) error {
// 查询有没有对应的资源
resource, err := a.resource()
if err != nil {
return err
}
// 查询有没有对应的联系人
contacts, err := a.contacts()
if err != nil {
return err
}
// 上传证书
certId, err := a.uploadCert(&a.option.Certificate)
if err != nil {
return err
}
// 部署证书
jobId, err := a.deploy(resource, certId, contacts)
if err != nil {
return err
}
// 等待部署成功
err = a.updateDeployStatus(*jobId)
if err != nil {
return err
}
// 部署成功后删除旧的证书
a.deleteCert(resource)
return nil
}
func (a *aliyun) updateDeployStatus(jobId int64) error {
// 查询部署状态
req := &cas20200407.UpdateDeploymentJobStatusRequest{
JobId: tea.Int64(jobId),
}
_, err := a.client.UpdateDeploymentJobStatus(req)
if err != nil {
return err
}
return nil
}
func (a *aliyun) deleteCert(resource *cas20200407.ListCloudResourcesResponseBodyData) error {
// 查询有没有对应的资源
if resource.CertId == nil {
return nil
}
// 删除证书
_, err := a.client.DeleteUserCertificate(&cas20200407.DeleteUserCertificateRequest{
CertId: resource.CertId,
})
if err != nil {
return err
}
return nil
}
func (a *aliyun) contacts() ([]*cas20200407.ListContactResponseBodyContactList, error) {
listContactRequest := &cas20200407.ListContactRequest{}
runtime := &util.RuntimeOptions{}
resp, err := a.client.ListContactWithOptions(listContactRequest, runtime)
if err != nil {
return nil, err
}
if resp.Body.TotalCount == nil {
return nil, errors.New("no contact found")
}
return resp.Body.ContactList, nil
}
func (a *aliyun) deploy(resource *cas20200407.ListCloudResourcesResponseBodyData, certId int64, contacts []*cas20200407.ListContactResponseBodyContactList) (*int64, error) {
contactIds := make([]string, 0, len(contacts))
for _, contact := range contacts {
contactIds = append(contactIds, fmt.Sprintf("%d", *contact.ContactId))
}
// 部署证书
createCloudResourceRequest := &cas20200407.CreateDeploymentJobRequest{
CertIds: tea.String(fmt.Sprintf("%d", certId)),
Name: tea.String(a.option.Domain + rand.RandStr(6)),
JobType: tea.String("user"),
ResourceIds: tea.String(fmt.Sprintf("%d", *resource.Id)),
ContactIds: tea.String(strings.Join(contactIds, ",")),
}
runtime := &util.RuntimeOptions{}
resp, err := a.client.CreateDeploymentJobWithOptions(createCloudResourceRequest, runtime)
if err != nil {
return nil, err
}
return resp.Body.JobId, nil
}
func (a *aliyun) uploadCert(cert *applicant.Certificate) (int64, error) {
uploadUserCertificateRequest := &cas20200407.UploadUserCertificateRequest{
Cert: &cert.Certificate,
Key: &cert.PrivateKey,
Name: tea.String(a.option.Domain + rand.RandStr(6)),
}
runtime := &util.RuntimeOptions{}
resp, err := a.client.UploadUserCertificateWithOptions(uploadUserCertificateRequest, runtime)
if err != nil {
return 0, err
}
return *resp.Body.CertId, nil
}
func (a *aliyun) createClient(accessKeyId, accessKeySecret string) (_result *cas20200407.Client, _err error) {
config := &openapi.Config{
AccessKeyId: tea.String(accessKeyId),
AccessKeySecret: tea.String(accessKeySecret),
}
config.Endpoint = tea.String("cas.aliyuncs.com")
_result = &cas20200407.Client{}
_result, _err = cas20200407.NewClient(config)
return _result, _err
}
func (a *aliyun) resource() (*cas20200407.ListCloudResourcesResponseBodyData, error) {
listCloudResourcesRequest := &cas20200407.ListCloudResourcesRequest{
CloudProduct: tea.String(a.option.Product),
Keyword: tea.String(a.option.Domain),
}
resp, err := a.client.ListCloudResources(listCloudResourcesRequest)
if err != nil {
return nil, err
}
if *resp.Body.Total == 0 {
return nil, errors.New("no resource found")
}
return resp.Body.Data[0], nil
}

View File

@@ -0,0 +1,49 @@
package deployer
import (
"certimate/internal/applicant"
"context"
"errors"
"strings"
"github.com/pocketbase/pocketbase/models"
)
const (
configTypeAliyun = "aliyun"
)
type DeployerOption struct {
Domain string `json:"domain"`
Product string `json:"product"`
Access string `json:"access"`
Certificate applicant.Certificate `json:"certificate"`
}
type Deployer interface {
Deploy(ctx context.Context) error
}
func Get(record *models.Record) (Deployer, error) {
access := record.ExpandedOne("targetAccess")
switch access.GetString("configType") {
case configTypeAliyun:
option := &DeployerOption{
Domain: record.GetString("domain"),
Product: getProduct(record),
Access: access.GetString("config"),
Certificate: applicant.Certificate{
Certificate: record.GetString("certificate"),
PrivateKey: record.GetString("privateKey"),
},
}
return NewAliyun(option)
}
return nil, errors.New("not implemented")
}
func getProduct(record *models.Record) string {
targetType := record.GetString("targetType")
rs := strings.Split(targetType, "-")
return rs[1]
}