diff --git a/drivers/rainyun/model.go b/drivers/rainyun/model.go index 9e2ec5d..d5e43cf 100644 --- a/drivers/rainyun/model.go +++ b/drivers/rainyun/model.go @@ -15,3 +15,7 @@ type RainyunWorkOrderRule struct { type RainyunAccount struct { APIKey string `json:"api_key"` } + +type RainyunRunAwayRule struct { + IK string `json:"ik"` +} diff --git a/drivers/rainyun/rainyun.go b/drivers/rainyun/rainyun.go index 2215647..3bfc961 100644 --- a/drivers/rainyun/rainyun.go +++ b/drivers/rainyun/rainyun.go @@ -2,13 +2,17 @@ package rainyun import ( "context" + "fmt" + "github.com/ssdomei232/goodBaby/internal/retry" "github.com/ssdomei232/goodBaby/model" rain "github.com/ssdomei232/rainyun-go-sdk/v2/rainyun/common" + "github.com/ssdomei232/rainyun-go-sdk/v2/rainyun/rcs" + "github.com/ssdomei232/rainyun-go-sdk/v2/rainyun/rgs" "github.com/ssdomei232/rainyun-go-sdk/v2/rainyun/workorder" ) -func sendRainyunWorkorderMsg(ctx context.Context, rule *model.Rule) error { +func SendRainyunWorkorderMsg(ctx context.Context, rule *model.Rule) error { rainyunConfig, err := getRainyunConfigFromRule(rule) if err != nil { return err @@ -19,14 +23,26 @@ func sendRainyunWorkorderMsg(ctx context.Context, rule *model.Rule) error { return err } + err = retry.Do(ctx, func() error { + return sendRainyunWorkorderMsg(rainyunConfig, rainyunAccount) + }) + + if err != nil { + return err + } + + return nil +} + +func sendRainyunWorkorderMsg(rainyunRuleConfig *RainyunWorkOrderRule, rainyunAccount *RainyunAccount) error { client := rain.NewClient(rainyunAccount.APIKey) workorderClient := workorder.Client{Client: client} - _, err = workorderClient.CreateWorkOrder(&workorder.CreateWorkerorderRequest{ - Content: rainyunConfig.Msg, + _, err := workorderClient.CreateWorkOrder(&workorder.CreateWorkerorderRequest{ + Content: rainyunRuleConfig.Msg, IsAuthed: false, IsUrgent: 1, - Title: rainyunConfig.Title, + Title: rainyunRuleConfig.Title, Type: "reward", }) @@ -36,3 +52,70 @@ func sendRainyunWorkorderMsg(ctx context.Context, rule *model.Rule) error { return nil } + +func RainyunRunAway(ctx context.Context, rule *model.Rule) error { + rainyunAccount, err := getRainyunAccountFromRule(rule) + if err != nil { + return err + } + client := rain.NewClient(rainyunAccount.APIKey) + + var fails []string + total := 0 + + // 重装所有RCS + rcsClient := rcs.Client{Client: client} + options := rain.EncodingStandardQueryParameters(1, 20) + rcsList, err := rcsClient.GetRcsList(options) + if err != nil { + return err + } + if rcsList.Data.TotalRecords == 0 { + return nil + } else if rcsList.Data.TotalRecords > 20 { + rcsTotal := rcsList.Data.TotalRecords + options := rain.EncodingStandardQueryParameters(1, rcsTotal) + rcsList, err = rcsClient.GetRcsList(options) + if err != nil { + return err + } + } + for _, rcs := range rcsList.Data.Records { + total++ + err := retry.Do(context.Background(), func() error { + return reinstallOneRCS(rcs.ID, &rcsClient) + }) + if err != nil { + fails = append(fails, fmt.Sprintf("RCS %d: %v", rcs.ID, err)) + } + } + + // 重装所有RGS + rgsClient := rgs.Client{Client: client} + rgsOptions := rain.EncodingStandardQueryParameters(1, 20) + rgsList, err := rgsClient.GetRgsList(rgsOptions) + if err != nil { + return err + } + if rgsList.Data.TotalRecords == 0 { + return nil + } else if rgsList.Data.TotalRecords > 20 { + rgsTotal := rgsList.Data.TotalRecords + rgsOptions := rain.EncodingStandardQueryParameters(1, rgsTotal) + rgsList, err = rgsClient.GetRgsList(rgsOptions) + if err != nil { + return err + } + } + for _, rgs := range rgsList.Data.Records { + total++ + err := retry.Do(context.Background(), func() error { + return reinstallOneRGS(rgs.ID, &rgsClient) + }) + if err != nil { + fails = append(fails, fmt.Sprintf("RGS %d: %v", rgs.ID, err)) + } + } + + return nil +} diff --git a/drivers/rainyun/ruleConfigChecker.go b/drivers/rainyun/ruleConfigChecker.go index 4a86f80..c8eaa28 100644 --- a/drivers/rainyun/ruleConfigChecker.go +++ b/drivers/rainyun/ruleConfigChecker.go @@ -43,3 +43,34 @@ func (v *RainyunWorkorderRuleValidator) Meta() meta.RuleMeta { }, } } + +type RainyunRunAwayRuleValidator struct{} + +func (v *RainyunRunAwayRuleValidator) GetType() string { + return "rainyun-runaway" +} + +func (v *RainyunRunAwayRuleValidator) Validate(configJSON string) error { + var config RainyunRunAwayRule + if err := json.Unmarshal([]byte(configJSON), &config); err != nil { + return fmt.Errorf("解析雨云规则配置失败: %v", err) + } + + if config.IK != "我已知晓" { + return fmt.Errorf("请输入正确内容") + } + + return nil +} + +func (v *RainyunRunAwayRuleValidator) Meta() meta.RuleMeta { + return meta.RuleMeta{ + Type: "rainyun-runaway", + Label: "重置雨云账号中所有云服务器(一键跑路)", + Description: "触发时会重装雨云账号下所有云服务器来实现跑路", + AccountType: AccountType, + Fields: []meta.Field{ + {Key: "ik", Label: "该操作引发的损失及法律责任归属账号所有人,本软件一律不承担,请输入我已知晓", Type: meta.FieldTextarea, Required: true}, + }, + } +} diff --git a/drivers/rainyun/runner.go b/drivers/rainyun/runner.go index 9816d35..d5ed5eb 100644 --- a/drivers/rainyun/runner.go +++ b/drivers/rainyun/runner.go @@ -17,5 +17,5 @@ func (e *RainyunWorkorderExecutor) GetType() string { func (e *RainyunWorkorderExecutor) Execute(ctx context.Context, rule *model.Rule) error { log.Printf("执行雨云工单规则: %s", rule.Name) - return sendRainyunWorkorderMsg(ctx, rule) + return SendRainyunWorkorderMsg(ctx, rule) } diff --git a/drivers/rainyun/tool.go b/drivers/rainyun/tool.go index 7945504..587eb20 100644 --- a/drivers/rainyun/tool.go +++ b/drivers/rainyun/tool.go @@ -6,6 +6,9 @@ import ( "github.com/ssdomei232/goodBaby/handler/db" "github.com/ssdomei232/goodBaby/model" + "github.com/ssdomei232/rainyun-go-sdk/v2/rainyun/public" + "github.com/ssdomei232/rainyun-go-sdk/v2/rainyun/rcs" + "github.com/ssdomei232/rainyun-go-sdk/v2/rainyun/rgs" ) // 从 Rule 中获取 RainyunConfig @@ -25,3 +28,57 @@ func getRainyunAccountFromRule(rule *model.Rule) (*RainyunAccount, error) { } return &rainyunAccount, nil } + +func reinstallOneRCS(rcsID int, rcsClient *rcs.Client) error { + rcsDetail, err := rcsClient.GetRcsDetails(rcsID) + if err != nil { + return err + } + + rcsOSList, err := public.GetRcsOSList() + if err != nil { + return err + } + + for _, os := range rcsOSList.Data { + if os.Region == rcsDetail.Data.Data.Node.Region && os.OsType == "linux" { + rcsReinstallRequest := &rcs.ReinstallRcsRequest{ + OsID: os.ID, + ResetOsd: true, + } + _, err := rcsClient.ReinstallRcs(rcsID, rcsReinstallRequest) + if err != nil { + return err + } + break + } + } + return nil +} + +func reinstallOneRGS(rgsID int, rgsClient *rgs.Client) error { + rgsDetail, err := rgsClient.GetRgsDetails(rgsID) + if err != nil { + return err + } + + rgsOSList, err := public.GetRgsOSList() + if err != nil { + return err + } + + for _, os := range rgsOSList.Data { + if os.Region == rgsDetail.Data.Data.Node.Region && os.OsType == "linux" { + rgsReinstallRequest := &rcs.ReinstallRcsRequest{ + OsID: os.ID, + ResetOsd: true, + } + _, err := rgsClient.Reinstallgs(rgsID, rgsReinstallRequest) + if err != nil { + return err + } + break + } + } + return nil +} diff --git a/go.mod b/go.mod index 372e9b2..e3ed2de 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/google/go-github/v84 v84.0.0 github.com/robfig/cron/v3 v3.0.1 github.com/ssdomei232/napcat-http-go-sdk v1.0.0 - github.com/ssdomei232/rainyun-go-sdk/v2 v2.0.5 + github.com/ssdomei232/rainyun-go-sdk/v2 v2.0.6 github.com/wneessen/go-mail v0.7.2 golang.org/x/crypto v0.48.0 gorm.io/driver/postgres v1.6.0 diff --git a/go.sum b/go.sum index a0583af..5405674 100644 --- a/go.sum +++ b/go.sum @@ -123,8 +123,8 @@ github.com/spf13/cast v1.9.2 h1:SsGfm7M8QOFtEzumm7UZrZdLLquNdzFYfIbEXntcFbE= github.com/spf13/cast v1.9.2/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= github.com/ssdomei232/napcat-http-go-sdk v1.0.0 h1:BY3iqqlZw5letiCwTmfMrhyqsx0a96eL5LpDuinnOSE= github.com/ssdomei232/napcat-http-go-sdk v1.0.0/go.mod h1:yPsSaMs3OyKMVPXwIs5ZB5G532vRi1GvL/WiWUEwblU= -github.com/ssdomei232/rainyun-go-sdk/v2 v2.0.5 h1:T30N4npW+U10IlZeQ8SooJi9V42uM+f+lrFPRRftHeg= -github.com/ssdomei232/rainyun-go-sdk/v2 v2.0.5/go.mod h1:Wf9X0qEpKQ1/uD4iUGGoPLHydiCxULqCVk+JCoVqdIg= +github.com/ssdomei232/rainyun-go-sdk/v2 v2.0.6 h1:tjratVKpPk3lc2bw+oVnIzVZG79mFlvUBez+FbX86pQ= +github.com/ssdomei232/rainyun-go-sdk/v2 v2.0.6/go.mod h1:Wf9X0qEpKQ1/uD4iUGGoPLHydiCxULqCVk+JCoVqdIg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=