v0.2
This commit is contained in:
@@ -190,7 +190,7 @@ func (a *aliyun) resource() (*cas20200407.ListCloudResourcesResponseBodyData, er
|
||||
|
||||
listCloudResourcesRequest := &cas20200407.ListCloudResourcesRequest{
|
||||
CloudProduct: tea.String(a.option.Product),
|
||||
Keyword: tea.String(a.option.Domain),
|
||||
Keyword: tea.String(getDeployString(a.option.DeployConfig, "domain")),
|
||||
}
|
||||
|
||||
resp, err := a.client.ListCloudResources(listCloudResourcesRequest)
|
||||
|
||||
@@ -2,6 +2,7 @@ package deployer
|
||||
|
||||
import (
|
||||
"certimate/internal/domain"
|
||||
"certimate/internal/utils/rand"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
@@ -46,9 +47,9 @@ func (a *AliyunCdn) GetInfo() []string {
|
||||
|
||||
func (a *AliyunCdn) Deploy(ctx context.Context) error {
|
||||
|
||||
certName := fmt.Sprintf("%s-%s", a.option.Domain, a.option.DomainId)
|
||||
certName := fmt.Sprintf("%s-%s-%s", a.option.Domain, a.option.DomainId, rand.RandStr(6))
|
||||
setCdnDomainSSLCertificateRequest := &cdn20180510.SetCdnDomainSSLCertificateRequest{
|
||||
DomainName: tea.String(a.option.Domain),
|
||||
DomainName: tea.String(getDeployString(a.option.DeployConfig, "domain")),
|
||||
CertName: tea.String(certName),
|
||||
CertType: tea.String("upload"),
|
||||
SSLProtocol: tea.String("on"),
|
||||
|
||||
@@ -7,6 +7,7 @@ package deployer
|
||||
|
||||
import (
|
||||
"certimate/internal/domain"
|
||||
"certimate/internal/utils/rand"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
@@ -51,9 +52,9 @@ func (a *AliyunEsa) GetInfo() []string {
|
||||
|
||||
func (a *AliyunEsa) Deploy(ctx context.Context) error {
|
||||
|
||||
certName := fmt.Sprintf("%s-%s", a.option.Domain, a.option.DomainId)
|
||||
certName := fmt.Sprintf("%s-%s-%s", a.option.Domain, a.option.DomainId, rand.RandStr(6))
|
||||
setDcdnDomainSSLCertificateRequest := &dcdn20180115.SetDcdnDomainSSLCertificateRequest{
|
||||
DomainName: tea.String(a.option.Domain),
|
||||
DomainName: tea.String(getDeployString(a.option.DeployConfig, "domain")),
|
||||
CertName: tea.String(certName),
|
||||
CertType: tea.String("upload"),
|
||||
SSLProtocol: tea.String("on"),
|
||||
|
||||
@@ -2,8 +2,8 @@ package deployer
|
||||
|
||||
import (
|
||||
"certimate/internal/applicant"
|
||||
"certimate/internal/domain"
|
||||
"certimate/internal/utils/app"
|
||||
"certimate/internal/utils/variables"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
@@ -30,6 +30,7 @@ type DeployerOption struct {
|
||||
Product string `json:"product"`
|
||||
Access string `json:"access"`
|
||||
AceessRecord *models.Record `json:"-"`
|
||||
DeployConfig domain.DeployConfig `json:"deployConfig"`
|
||||
Certificate applicant.Certificate `json:"certificate"`
|
||||
Variables map[string]string `json:"variables"`
|
||||
}
|
||||
@@ -42,52 +43,29 @@ type Deployer interface {
|
||||
|
||||
func Gets(record *models.Record, cert *applicant.Certificate) ([]Deployer, error) {
|
||||
rs := make([]Deployer, 0)
|
||||
|
||||
if record.GetString("targetAccess") != "" {
|
||||
singleDeployer, err := Get(record, cert)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rs = append(rs, singleDeployer)
|
||||
if record.GetString("deployConfig") == "" {
|
||||
return rs, nil
|
||||
}
|
||||
|
||||
if record.GetString("group") != "" {
|
||||
group := record.ExpandedOne("group")
|
||||
|
||||
if errs := app.GetApp().Dao().ExpandRecord(group, []string{"access"}, nil); len(errs) > 0 {
|
||||
|
||||
errList := make([]error, 0)
|
||||
for name, err := range errs {
|
||||
errList = append(errList, fmt.Errorf("展开记录失败,%s: %w", name, err))
|
||||
}
|
||||
err := errors.Join(errList...)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
records := group.ExpandedAll("access")
|
||||
|
||||
deployers, err := getByGroup(record, cert, records...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rs = append(rs, deployers...)
|
||||
deployConfigs := make([]domain.DeployConfig, 0)
|
||||
|
||||
err := record.UnmarshalJSONField("deployConfig", &deployConfigs)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("解析部署配置失败: %w", err)
|
||||
}
|
||||
|
||||
return rs, nil
|
||||
if len(deployConfigs) == 0 {
|
||||
return rs, nil
|
||||
}
|
||||
|
||||
}
|
||||
for _, deployConfig := range deployConfigs {
|
||||
|
||||
func getByGroup(record *models.Record, cert *applicant.Certificate, accesses ...*models.Record) ([]Deployer, error) {
|
||||
deployer, err := getWithDeployConfig(record, cert, deployConfig)
|
||||
|
||||
rs := make([]Deployer, 0)
|
||||
|
||||
for _, access := range accesses {
|
||||
deployer, err := getWithAccess(record, cert, access)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rs = append(rs, deployer)
|
||||
}
|
||||
|
||||
@@ -95,15 +73,21 @@ func getByGroup(record *models.Record, cert *applicant.Certificate, accesses ...
|
||||
|
||||
}
|
||||
|
||||
func getWithAccess(record *models.Record, cert *applicant.Certificate, access *models.Record) (Deployer, error) {
|
||||
func getWithDeployConfig(record *models.Record, cert *applicant.Certificate, deployConfig domain.DeployConfig) (Deployer, error) {
|
||||
|
||||
access, err := app.GetApp().Dao().FindRecordById("access", deployConfig.Access)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("access record not found: %w", err)
|
||||
}
|
||||
|
||||
option := &DeployerOption{
|
||||
DomainId: record.Id,
|
||||
Domain: record.GetString("domain"),
|
||||
Product: getProduct(record),
|
||||
Product: getProduct(deployConfig.Type),
|
||||
Access: access.GetString("config"),
|
||||
AceessRecord: access,
|
||||
Variables: variables.Parse2Map(record.GetString("variables")),
|
||||
DeployConfig: deployConfig,
|
||||
}
|
||||
if cert != nil {
|
||||
option.Certificate = *cert
|
||||
@@ -114,7 +98,7 @@ func getWithAccess(record *models.Record, cert *applicant.Certificate, access *m
|
||||
}
|
||||
}
|
||||
|
||||
switch record.GetString("targetType") {
|
||||
switch deployConfig.Type {
|
||||
case targetAliyunOss:
|
||||
return NewAliyun(option)
|
||||
case targetAliyunCdn:
|
||||
@@ -136,16 +120,8 @@ func getWithAccess(record *models.Record, cert *applicant.Certificate, access *m
|
||||
return nil, errors.New("not implemented")
|
||||
}
|
||||
|
||||
func Get(record *models.Record, cert *applicant.Certificate) (Deployer, error) {
|
||||
|
||||
access := record.ExpandedOne("targetAccess")
|
||||
|
||||
return getWithAccess(record, cert, access)
|
||||
}
|
||||
|
||||
func getProduct(record *models.Record) string {
|
||||
targetType := record.GetString("targetType")
|
||||
rs := strings.Split(targetType, "-")
|
||||
func getProduct(t string) string {
|
||||
rs := strings.Split(t, "-")
|
||||
if len(rs) < 2 {
|
||||
return ""
|
||||
}
|
||||
@@ -159,3 +135,39 @@ func toStr(tag string, data any) string {
|
||||
byts, _ := json.Marshal(data)
|
||||
return tag + ":" + string(byts)
|
||||
}
|
||||
|
||||
func getDeployString(conf domain.DeployConfig, key string) string {
|
||||
if _, ok := conf.Config[key]; !ok {
|
||||
return ""
|
||||
}
|
||||
|
||||
val, ok := conf.Config[key].(string)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
|
||||
return val
|
||||
}
|
||||
|
||||
func getDeployVariables(conf domain.DeployConfig) map[string]string {
|
||||
rs := make(map[string]string)
|
||||
data, ok := conf.Config["variables"]
|
||||
if !ok {
|
||||
return rs
|
||||
}
|
||||
|
||||
bts, _ := json.Marshal(data)
|
||||
|
||||
kvData := make([]domain.KV, 0)
|
||||
|
||||
if err := json.Unmarshal(bts, &kvData); err != nil {
|
||||
return rs
|
||||
}
|
||||
|
||||
for _, kv := range kvData {
|
||||
rs[kv.Key] = kv.Value
|
||||
}
|
||||
|
||||
return rs
|
||||
|
||||
}
|
||||
|
||||
@@ -11,9 +11,6 @@ import (
|
||||
)
|
||||
|
||||
type localAccess struct {
|
||||
Command string `json:"command"`
|
||||
CertPath string `json:"certPath"`
|
||||
KeyPath string `json:"keyPath"`
|
||||
}
|
||||
|
||||
type local struct {
|
||||
@@ -41,18 +38,27 @@ func (l *local) Deploy(ctx context.Context) error {
|
||||
if err := json.Unmarshal([]byte(l.option.Access), access); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
preCommand := getDeployString(l.option.DeployConfig, "preCommand")
|
||||
|
||||
if preCommand != "" {
|
||||
if err := execCmd(preCommand); err != nil {
|
||||
return fmt.Errorf("执行前置命令失败: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 复制文件
|
||||
if err := copyFile(l.option.Certificate.Certificate, access.CertPath); err != nil {
|
||||
if err := copyFile(l.option.Certificate.Certificate, getDeployString(l.option.DeployConfig, "certPath")); err != nil {
|
||||
return fmt.Errorf("复制证书失败: %w", err)
|
||||
}
|
||||
|
||||
if err := copyFile(l.option.Certificate.PrivateKey, access.KeyPath); err != nil {
|
||||
if err := copyFile(l.option.Certificate.PrivateKey, getDeployString(l.option.DeployConfig, "keyPath")); err != nil {
|
||||
return fmt.Errorf("复制私钥失败: %w", err)
|
||||
}
|
||||
|
||||
// 执行命令
|
||||
|
||||
if err := execCmd(access.Command); err != nil {
|
||||
if err := execCmd(getDeployString(l.option.DeployConfig, "command")); err != nil {
|
||||
return fmt.Errorf("执行命令失败: %w", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ func (q *qiuniu) Deploy(ctx context.Context) error {
|
||||
}
|
||||
|
||||
func (q *qiuniu) enableHttps(certId string) error {
|
||||
path := fmt.Sprintf("/domain/%s/sslize", q.option.Domain)
|
||||
path := fmt.Sprintf("/domain/%s/sslize", getDeployString(q.option.DeployConfig, "domain"))
|
||||
|
||||
body := &modifyDomainCertReq{
|
||||
CertID: certId,
|
||||
@@ -104,7 +104,7 @@ type domainInfo struct {
|
||||
}
|
||||
|
||||
func (q *qiuniu) getDomainInfo() (*domainInfo, error) {
|
||||
path := fmt.Sprintf("/domain/%s", q.option.Domain)
|
||||
path := fmt.Sprintf("/domain/%s", getDeployString(q.option.DeployConfig, "domain"))
|
||||
|
||||
res, err := q.req(qiniuGateway+path, http.MethodGet, nil)
|
||||
if err != nil {
|
||||
@@ -135,8 +135,8 @@ func (q *qiuniu) uploadCert() (string, error) {
|
||||
path := "/sslcert"
|
||||
|
||||
body := &uploadCertReq{
|
||||
Name: q.option.Domain,
|
||||
CommonName: q.option.Domain,
|
||||
Name: getDeployString(q.option.DeployConfig, "domain"),
|
||||
CommonName: getDeployString(q.option.DeployConfig, "domain"),
|
||||
Pri: q.option.Certificate.PrivateKey,
|
||||
Ca: q.option.Certificate.Certificate,
|
||||
}
|
||||
@@ -166,7 +166,7 @@ type modifyDomainCertReq struct {
|
||||
}
|
||||
|
||||
func (q *qiuniu) modifyDomainCert(certId string) error {
|
||||
path := fmt.Sprintf("/domain/%s/httpsconf", q.option.Domain)
|
||||
path := fmt.Sprintf("/domain/%s/httpsconf", getDeployString(q.option.DeployConfig, "domain"))
|
||||
|
||||
body := &modifyDomainCertReq{
|
||||
CertID: certId,
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
xpath "path"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/sftp"
|
||||
sshPkg "golang.org/x/crypto/ssh"
|
||||
@@ -19,15 +18,11 @@ type ssh struct {
|
||||
}
|
||||
|
||||
type sshAccess struct {
|
||||
Host string `json:"host"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Key string `json:"key"`
|
||||
Port string `json:"port"`
|
||||
PreCommand string `json:"preCommand"`
|
||||
Command string `json:"command"`
|
||||
CertPath string `json:"certPath"`
|
||||
KeyPath string `json:"keyPath"`
|
||||
Host string `json:"host"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Key string `json:"key"`
|
||||
Port string `json:"port"`
|
||||
}
|
||||
|
||||
func NewSSH(option *DeployerOption) (Deployer, error) {
|
||||
@@ -50,16 +45,6 @@ func (s *ssh) Deploy(ctx context.Context) error {
|
||||
if err := json.Unmarshal([]byte(s.option.Access), access); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 将证书路径和命令中的变量替换为实际值
|
||||
for k, v := range s.option.Variables {
|
||||
key := fmt.Sprintf("${%s}", k)
|
||||
access.CertPath = strings.ReplaceAll(access.CertPath, key, v)
|
||||
access.KeyPath = strings.ReplaceAll(access.KeyPath, key, v)
|
||||
access.Command = strings.ReplaceAll(access.Command, key, v)
|
||||
access.PreCommand = strings.ReplaceAll(access.PreCommand, key, v)
|
||||
}
|
||||
|
||||
// 连接
|
||||
client, err := s.getClient(access)
|
||||
if err != nil {
|
||||
@@ -70,29 +55,30 @@ func (s *ssh) Deploy(ctx context.Context) error {
|
||||
s.infos = append(s.infos, toStr("ssh连接成功", nil))
|
||||
|
||||
// 执行前置命令
|
||||
if access.PreCommand != "" {
|
||||
err, stdout, stderr := s.sshExecCommand(client, access.PreCommand)
|
||||
preCommand := getDeployString(s.option.DeployConfig, "preCommand")
|
||||
if preCommand != "" {
|
||||
err, stdout, stderr := s.sshExecCommand(client, preCommand)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to run pre-command: %w, stdout: %s, stderr: %s", err, stdout, stderr)
|
||||
}
|
||||
}
|
||||
|
||||
// 上传证书
|
||||
if err := s.upload(client, s.option.Certificate.Certificate, access.CertPath); err != nil {
|
||||
if err := s.upload(client, s.option.Certificate.Certificate, getDeployString(s.option.DeployConfig, "certPath")); err != nil {
|
||||
return fmt.Errorf("failed to upload certificate: %w", err)
|
||||
}
|
||||
|
||||
s.infos = append(s.infos, toStr("ssh上传证书成功", nil))
|
||||
|
||||
// 上传私钥
|
||||
if err := s.upload(client, s.option.Certificate.PrivateKey, access.KeyPath); err != nil {
|
||||
if err := s.upload(client, s.option.Certificate.PrivateKey, getDeployString(s.option.DeployConfig, "keyPath")); err != nil {
|
||||
return fmt.Errorf("failed to upload private key: %w", err)
|
||||
}
|
||||
|
||||
s.infos = append(s.infos, toStr("ssh上传私钥成功", nil))
|
||||
|
||||
// 执行命令
|
||||
err, stdout, stderr := s.sshExecCommand(client, access.Command)
|
||||
err, stdout, stderr := s.sshExecCommand(client, getDeployString(s.option.DeployConfig, "command"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to run command: %w, stdout: %s, stderr: %s", err, stdout, stderr)
|
||||
}
|
||||
|
||||
@@ -14,9 +14,10 @@ type webhookAccess struct {
|
||||
}
|
||||
|
||||
type hookData struct {
|
||||
Domain string `json:"domain"`
|
||||
Certificate string `json:"certificate"`
|
||||
PrivateKey string `json:"privateKey"`
|
||||
Domain string `json:"domain"`
|
||||
Certificate string `json:"certificate"`
|
||||
PrivateKey string `json:"privateKey"`
|
||||
Variables map[string]string `json:"variables"`
|
||||
}
|
||||
|
||||
type webhook struct {
|
||||
@@ -50,6 +51,7 @@ func (w *webhook) Deploy(ctx context.Context) error {
|
||||
Domain: w.option.Domain,
|
||||
Certificate: w.option.Certificate.Certificate,
|
||||
PrivateKey: w.option.Certificate.PrivateKey,
|
||||
Variables: getDeployVariables(w.option.DeployConfig),
|
||||
}
|
||||
|
||||
body, _ := json.Marshal(data)
|
||||
|
||||
Reference in New Issue
Block a user