mirror of
https://github.com/usual2970/certimate.git
synced 2025-06-08 13:39:53 +00:00
add deploy info
This commit is contained in:
parent
bae35536b8
commit
fb40caa25c
@ -19,6 +19,7 @@ import (
|
||||
type aliyun struct {
|
||||
client *cas20200407.Client
|
||||
option *DeployerOption
|
||||
infos []string
|
||||
}
|
||||
|
||||
func NewAliyun(option *DeployerOption) (Deployer, error) {
|
||||
@ -26,6 +27,7 @@ func NewAliyun(option *DeployerOption) (Deployer, error) {
|
||||
json.Unmarshal([]byte(option.Access), access)
|
||||
a := &aliyun{
|
||||
option: option,
|
||||
infos: make([]string, 0),
|
||||
}
|
||||
client, err := a.createClient(access.AccessKeyId, access.AccessKeySecret)
|
||||
if err != nil {
|
||||
@ -36,6 +38,10 @@ func NewAliyun(option *DeployerOption) (Deployer, error) {
|
||||
|
||||
}
|
||||
|
||||
func (a *aliyun) GetInfo() []string {
|
||||
return a.infos
|
||||
}
|
||||
|
||||
func (a *aliyun) Deploy(ctx context.Context) error {
|
||||
|
||||
// 查询有没有对应的资源
|
||||
@ -44,24 +50,32 @@ func (a *aliyun) Deploy(ctx context.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
a.infos = append(a.infos, toStr("查询对应的资源", resource))
|
||||
|
||||
// 查询有没有对应的联系人
|
||||
contacts, err := a.contacts()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.infos = append(a.infos, toStr("查询联系人", contacts))
|
||||
|
||||
// 上传证书
|
||||
certId, err := a.uploadCert(&a.option.Certificate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.infos = append(a.infos, toStr("上传证书", certId))
|
||||
|
||||
// 部署证书
|
||||
jobId, err := a.deploy(resource, certId, contacts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.infos = append(a.infos, toStr("创建部署证书任务", jobId))
|
||||
|
||||
// 等待部署成功
|
||||
err = a.updateDeployStatus(*jobId)
|
||||
if err != nil {
|
||||
@ -80,10 +94,11 @@ func (a *aliyun) updateDeployStatus(jobId int64) error {
|
||||
JobId: tea.Int64(jobId),
|
||||
}
|
||||
|
||||
_, err := a.client.UpdateDeploymentJobStatus(req)
|
||||
resp, err := a.client.UpdateDeploymentJobStatus(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.infos = append(a.infos, toStr("查询对应的资源", resp))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
type AliyunCdn struct {
|
||||
client *cdn20180510.Client
|
||||
option *DeployerOption
|
||||
infos []string
|
||||
}
|
||||
|
||||
func NewAliyunCdn(option *DeployerOption) (*AliyunCdn, error) {
|
||||
@ -31,9 +32,14 @@ func NewAliyunCdn(option *DeployerOption) (*AliyunCdn, error) {
|
||||
return &AliyunCdn{
|
||||
client: client,
|
||||
option: option,
|
||||
infos: make([]string, 0),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (a *AliyunCdn) GetInfo() []string {
|
||||
return a.infos
|
||||
}
|
||||
|
||||
func (a *AliyunCdn) Deploy(ctx context.Context) error {
|
||||
|
||||
certName := fmt.Sprintf("%s-%s", a.option.Domain, a.option.DomainId)
|
||||
@ -49,11 +55,13 @@ func (a *AliyunCdn) Deploy(ctx context.Context) error {
|
||||
|
||||
runtime := &util.RuntimeOptions{}
|
||||
|
||||
_, err := a.client.SetCdnDomainSSLCertificateWithOptions(setCdnDomainSSLCertificateRequest, runtime)
|
||||
resp, err := a.client.SetCdnDomainSSLCertificateWithOptions(setCdnDomainSSLCertificateRequest, runtime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.infos = append(a.infos, toStr("cdn设置证书", resp))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ package deployer
|
||||
import (
|
||||
"certimate/internal/applicant"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
@ -31,6 +32,7 @@ type DeployerOption struct {
|
||||
|
||||
type Deployer interface {
|
||||
Deploy(ctx context.Context) error
|
||||
GetInfo() []string
|
||||
}
|
||||
|
||||
func Get(record *models.Record, cert *applicant.Certificate) (Deployer, error) {
|
||||
@ -73,3 +75,11 @@ func getProduct(record *models.Record) string {
|
||||
}
|
||||
return rs[1]
|
||||
}
|
||||
|
||||
func toStr(tag string, data any) string {
|
||||
if data == nil {
|
||||
return tag
|
||||
}
|
||||
byts, _ := json.Marshal(data)
|
||||
return tag + ":" + string(byts)
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
|
||||
type ssh struct {
|
||||
option *DeployerOption
|
||||
infos []string
|
||||
}
|
||||
|
||||
type sshAccess struct {
|
||||
@ -30,9 +31,14 @@ type sshAccess struct {
|
||||
func NewSSH(option *DeployerOption) (Deployer, error) {
|
||||
return &ssh{
|
||||
option: option,
|
||||
infos: make([]string, 0),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *ssh) GetInfo() []string {
|
||||
return s.infos
|
||||
}
|
||||
|
||||
func (s *ssh) Deploy(ctx context.Context) error {
|
||||
access := &sshAccess{}
|
||||
if err := json.Unmarshal([]byte(s.option.Access), access); err != nil {
|
||||
@ -45,6 +51,8 @@ func (s *ssh) Deploy(ctx context.Context) error {
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
s.infos = append(s.infos, toStr("ssh连接成功", nil))
|
||||
|
||||
// 上传
|
||||
session, err := client.NewSession()
|
||||
if err != nil {
|
||||
@ -52,16 +60,22 @@ func (s *ssh) Deploy(ctx context.Context) error {
|
||||
}
|
||||
defer session.Close()
|
||||
|
||||
s.infos = append(s.infos, toStr("ssh创建session成功", nil))
|
||||
|
||||
// 上传证书
|
||||
if err := s.upload(client, s.option.Certificate.Certificate, access.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 {
|
||||
return fmt.Errorf("failed to upload private key: %w", err)
|
||||
}
|
||||
|
||||
s.infos = append(s.infos, toStr("ssh上传私钥成功", nil))
|
||||
|
||||
// 执行命令
|
||||
var stdoutBuf bytes.Buffer
|
||||
session.Stdout = &stdoutBuf
|
||||
@ -72,6 +86,8 @@ func (s *ssh) Deploy(ctx context.Context) error {
|
||||
return fmt.Errorf("failed to run command: %w, stdout: %s, stderr: %s", err, stdoutBuf.String(), stderrBuf.String())
|
||||
}
|
||||
|
||||
s.infos = append(s.infos, toStr("ssh执行命令成功", []string{stdoutBuf.String()}))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@ import (
|
||||
type tencentCdn struct {
|
||||
option *DeployerOption
|
||||
credential *common.Credential
|
||||
infos []string
|
||||
}
|
||||
|
||||
func NewTencentCdn(option *DeployerOption) (Deployer, error) {
|
||||
@ -34,9 +35,14 @@ func NewTencentCdn(option *DeployerOption) (Deployer, error) {
|
||||
return &tencentCdn{
|
||||
option: option,
|
||||
credential: credential,
|
||||
infos: make([]string, 0),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (t *tencentCdn) GetInfo() []string {
|
||||
return t.infos
|
||||
}
|
||||
|
||||
func (t *tencentCdn) Deploy(ctx context.Context) error {
|
||||
|
||||
// 查询有没有对应的资源
|
||||
@ -45,11 +51,14 @@ func (t *tencentCdn) Deploy(ctx context.Context) error {
|
||||
return fmt.Errorf("failed to get resource: %w", err)
|
||||
}
|
||||
|
||||
t.infos = append(t.infos, toStr("查询对应的资源", resource))
|
||||
|
||||
// 上传证书
|
||||
certId, err := t.uploadCert()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to upload certificate: %w", err)
|
||||
}
|
||||
t.infos = append(t.infos, toStr("上传证书", certId))
|
||||
|
||||
if err := t.deploy(resource, certId); err != nil {
|
||||
return fmt.Errorf("failed to deploy: %w", err)
|
||||
@ -100,11 +109,12 @@ func (t *tencentCdn) deploy(resource *tag.ResourceTagMapping, certId string) err
|
||||
request.Status = common.Int64Ptr(1)
|
||||
|
||||
// 返回的resp是一个DeployCertificateInstanceResponse的实例,与请求对象对应
|
||||
_, err = client.DeployCertificateInstance(request)
|
||||
resp, err := client.DeployCertificateInstance(request)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to deploy certificate: %w", err)
|
||||
}
|
||||
t.infos = append(t.infos, toStr("部署证书", resp.Response))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -21,15 +21,21 @@ type hookData struct {
|
||||
|
||||
type webhook struct {
|
||||
option *DeployerOption
|
||||
infos []string
|
||||
}
|
||||
|
||||
func NewWebhook(option *DeployerOption) (Deployer, error) {
|
||||
|
||||
return &webhook{
|
||||
option: option,
|
||||
infos: make([]string, 0),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (w *webhook) GetInfo() []string {
|
||||
return w.infos
|
||||
}
|
||||
|
||||
func (w *webhook) Deploy(ctx context.Context) error {
|
||||
access := &webhookAccess{}
|
||||
if err := json.Unmarshal([]byte(w.option.Access), access); err != nil {
|
||||
@ -44,12 +50,14 @@ func (w *webhook) Deploy(ctx context.Context) error {
|
||||
|
||||
body, _ := json.Marshal(data)
|
||||
|
||||
_, err := xhttp.Req(access.Url, http.MethodPost, bytes.NewReader(body), map[string]string{
|
||||
resp, err := xhttp.Req(access.Url, http.MethodPost, bytes.NewReader(body), map[string]string{
|
||||
"Content-Type": "application/json",
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to send hook request: %w", err)
|
||||
}
|
||||
|
||||
w.infos = append(w.infos, toStr("webhook response", string(resp)))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -27,16 +27,17 @@ func deploy(ctx context.Context, record *models.Record) error {
|
||||
}
|
||||
}()
|
||||
var certificate *applicant.Certificate
|
||||
currRecord, err := app.GetApp().Dao().FindRecordById("domains", record.Id)
|
||||
|
||||
history := NewHistory(record)
|
||||
defer history.commit()
|
||||
|
||||
// ############1.检查域名配置
|
||||
history.record(checkPhase, "开始检查", nil)
|
||||
|
||||
currRecord, err := app.GetApp().Dao().FindRecordById("domains", record.Id)
|
||||
if err != nil {
|
||||
app.GetApp().Logger().Error("获取记录失败", "err", err)
|
||||
history.record(checkPhase, "获取域名配置失败", err)
|
||||
history.record(checkPhase, "获取域名配置失败", &RecordInfo{Err: err})
|
||||
return err
|
||||
}
|
||||
history.record(checkPhase, "获取记录成功", nil)
|
||||
@ -48,7 +49,7 @@ func deploy(ctx context.Context, record *models.Record) error {
|
||||
}
|
||||
err = errors.Join(errList...)
|
||||
app.GetApp().Logger().Error("展开记录失败", "err", err)
|
||||
history.record(checkPhase, "获取授权信息失败", err)
|
||||
history.record(checkPhase, "获取授权信息失败", &RecordInfo{Err: err})
|
||||
return err
|
||||
}
|
||||
history.record(checkPhase, "获取授权信息成功", nil)
|
||||
@ -56,9 +57,11 @@ func deploy(ctx context.Context, record *models.Record) error {
|
||||
cert := currRecord.GetString("certificate")
|
||||
expiredAt := currRecord.GetDateTime("expiredAt").Time()
|
||||
|
||||
if cert != "" && time.Until(expiredAt) > time.Hour*24 && currRecord.GetBool("deployed") {
|
||||
if cert != "" && time.Until(expiredAt) > time.Hour*24*10 && currRecord.GetBool("deployed") {
|
||||
app.GetApp().Logger().Info("证书在有效期内")
|
||||
history.record(checkPhase, "证书在有效期内且已部署,跳过", nil, true)
|
||||
history.record(checkPhase, "证书在有效期内且已部署,跳过", &RecordInfo{
|
||||
Info: []string{fmt.Sprintf("证书有效期至 %s", expiredAt.Format("2006-01-02"))},
|
||||
}, true)
|
||||
return err
|
||||
}
|
||||
history.record(checkPhase, "检查通过", nil, true)
|
||||
@ -67,21 +70,25 @@ func deploy(ctx context.Context, record *models.Record) error {
|
||||
history.record(applyPhase, "开始申请", nil)
|
||||
|
||||
if cert != "" && time.Until(expiredAt) > time.Hour*24 {
|
||||
history.record(applyPhase, "证书在有效期内,跳过", nil)
|
||||
history.record(applyPhase, "证书在有效期内,跳过", &RecordInfo{
|
||||
Info: []string{fmt.Sprintf("证书有效期至 %s", expiredAt.Format("2006-01-02"))},
|
||||
})
|
||||
} else {
|
||||
applicant, err := applicant.Get(currRecord)
|
||||
if err != nil {
|
||||
history.record(applyPhase, "获取applicant失败", err)
|
||||
history.record(applyPhase, "获取applicant失败", &RecordInfo{Err: err})
|
||||
app.GetApp().Logger().Error("获取applicant失败", "err", err)
|
||||
return err
|
||||
}
|
||||
certificate, err = applicant.Apply()
|
||||
if err != nil {
|
||||
history.record(applyPhase, "申请证书失败", err)
|
||||
history.record(applyPhase, "申请证书失败", &RecordInfo{Err: err})
|
||||
app.GetApp().Logger().Error("申请证书失败", "err", err)
|
||||
return err
|
||||
}
|
||||
history.record(applyPhase, "申请证书成功", nil)
|
||||
history.record(applyPhase, "申请证书成功", &RecordInfo{
|
||||
Info: []string{fmt.Sprintf("证书地址: %s", certificate.CertUrl)},
|
||||
})
|
||||
history.setCert(certificate)
|
||||
}
|
||||
|
||||
@ -91,7 +98,7 @@ func deploy(ctx context.Context, record *models.Record) error {
|
||||
history.record(deployPhase, "开始部署", nil, false)
|
||||
deployer, err := deployer.Get(currRecord, certificate)
|
||||
if err != nil {
|
||||
history.record(deployPhase, "获取deployer失败", err)
|
||||
history.record(deployPhase, "获取deployer失败", &RecordInfo{Err: err})
|
||||
app.GetApp().Logger().Error("获取deployer失败", "err", err)
|
||||
return err
|
||||
}
|
||||
@ -99,12 +106,14 @@ func deploy(ctx context.Context, record *models.Record) error {
|
||||
if err = deployer.Deploy(ctx); err != nil {
|
||||
|
||||
app.GetApp().Logger().Error("部署失败", "err", err)
|
||||
history.record(deployPhase, "部署失败", err)
|
||||
history.record(deployPhase, "部署失败", &RecordInfo{Err: err, Info: deployer.GetInfo()})
|
||||
return err
|
||||
}
|
||||
|
||||
app.GetApp().Logger().Info("部署成功")
|
||||
history.record(deployPhase, "部署成功", nil, true)
|
||||
history.record(deployPhase, "部署成功", &RecordInfo{
|
||||
Info: deployer.GetInfo(),
|
||||
}, true)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -10,9 +10,15 @@ import (
|
||||
)
|
||||
|
||||
type historyItem struct {
|
||||
Time string `json:"time"`
|
||||
Message string `json:"message"`
|
||||
Error string `json:"error"`
|
||||
Time string `json:"time"`
|
||||
Message string `json:"message"`
|
||||
Error string `json:"error"`
|
||||
Info []string `json:"info"`
|
||||
}
|
||||
|
||||
type RecordInfo struct {
|
||||
Err error `json:"err"`
|
||||
Info []string `json:"info"`
|
||||
}
|
||||
|
||||
type history struct {
|
||||
@ -34,21 +40,25 @@ func NewHistory(record *models.Record) *history {
|
||||
}
|
||||
}
|
||||
|
||||
func (a *history) record(phase Phase, msg string, err error, pass ...bool) {
|
||||
func (a *history) record(phase Phase, msg string, info *RecordInfo, pass ...bool) {
|
||||
if info == nil {
|
||||
info = &RecordInfo{}
|
||||
}
|
||||
a.Phase = phase
|
||||
if len(pass) > 0 {
|
||||
a.PhaseSuccess = pass[0]
|
||||
}
|
||||
|
||||
errMsg := ""
|
||||
if err != nil {
|
||||
errMsg = err.Error()
|
||||
if info.Err != nil {
|
||||
errMsg = info.Err.Error()
|
||||
a.PhaseSuccess = false
|
||||
}
|
||||
|
||||
a.Log[phase] = append(a.Log[phase], historyItem{
|
||||
Message: msg,
|
||||
Error: errMsg,
|
||||
Info: info.Info,
|
||||
Time: xtime.BeijingTimeStr(),
|
||||
})
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
2
ui/dist/index.html
vendored
2
ui/dist/index.html
vendored
@ -5,7 +5,7 @@
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Certimate - Your Trusted SSL Automation Partner</title>
|
||||
<script type="module" crossorigin src="/assets/index-B6xIlnQB.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-D3t3IJ9L.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-VYJgHfoP.css">
|
||||
</head>
|
||||
<body class="bg-background">
|
||||
|
@ -24,6 +24,7 @@ export type Log = {
|
||||
time: string;
|
||||
message: string;
|
||||
error: string;
|
||||
info?: string[];
|
||||
};
|
||||
|
||||
export type DeploymentListReq = {
|
||||
|
@ -187,7 +187,7 @@ export default function Dashboard() {
|
||||
href="https://github.com/usual2970/certimate/releases"
|
||||
target="_blank"
|
||||
>
|
||||
Certimate v0.0.7
|
||||
Certimate v0.0.8
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -147,6 +147,14 @@ const History = () => {
|
||||
<div>[{item.time}]</div>
|
||||
<div className="ml-2">{item.message}</div>
|
||||
</div>
|
||||
{item.info &&
|
||||
item.info.map((info: string) => {
|
||||
return (
|
||||
<div className="mt-1 text-green-600">
|
||||
{info}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{item.error && (
|
||||
<div className="mt-1 text-red-600">
|
||||
{item.error}
|
||||
|
Loading…
x
Reference in New Issue
Block a user