package provision import ( "context" "errors" "fmt" "sub2api-cn-relay-manager/internal/host/sub2api" "sub2api-cn-relay-manager/internal/pack" ) type rollbackHost interface { ListManagedResources(ctx context.Context, req sub2api.ListManagedResourcesRequest) (sub2api.ManagedResourceSnapshot, error) DeleteAccount(ctx context.Context, accountID string) error DeletePlan(ctx context.Context, planID string) error DeleteChannel(ctx context.Context, channelID string) error DeleteGroup(ctx context.Context, groupID string) error } type RollbackRequest struct { Provider pack.ProviderManifest } type RollbackReport struct { AccountsDeleted int PlansDeleted int ChannelsDeleted int GroupsDeleted int } type RollbackService struct { host rollbackHost } func NewRollbackService(host rollbackHost) *RollbackService { return &RollbackService{host: host} } func (s *RollbackService) Rollback(ctx context.Context, req RollbackRequest) (RollbackReport, error) { if s.host == nil { return RollbackReport{}, fmt.Errorf("rollback host is required") } names := SuggestResourceNames(req.Provider) snapshot, err := s.host.ListManagedResources(ctx, sub2api.ListManagedResourcesRequest{ GroupName: names.Group, ChannelName: names.Channel, PlanName: names.Plan, AccountNamePrefix: SuggestAccountNamePrefix(req.Provider), }) if err != nil { return RollbackReport{}, fmt.Errorf("list managed resources: %w", err) } var report RollbackReport var errs []error for index := len(snapshot.Accounts) - 1; index >= 0; index-- { if err := s.host.DeleteAccount(ctx, snapshot.Accounts[index].ID); err != nil { errs = append(errs, fmt.Errorf("delete account %s: %w", snapshot.Accounts[index].ID, err)) continue } report.AccountsDeleted++ } for index := len(snapshot.Plans) - 1; index >= 0; index-- { if err := s.host.DeletePlan(ctx, snapshot.Plans[index].ID); err != nil { errs = append(errs, fmt.Errorf("delete plan %s: %w", snapshot.Plans[index].ID, err)) continue } report.PlansDeleted++ } for index := len(snapshot.Channels) - 1; index >= 0; index-- { if err := s.host.DeleteChannel(ctx, snapshot.Channels[index].ID); err != nil { errs = append(errs, fmt.Errorf("delete channel %s: %w", snapshot.Channels[index].ID, err)) continue } report.ChannelsDeleted++ } for index := len(snapshot.Groups) - 1; index >= 0; index-- { if err := s.host.DeleteGroup(ctx, snapshot.Groups[index].ID); err != nil { errs = append(errs, fmt.Errorf("delete group %s: %w", snapshot.Groups[index].ID, err)) continue } report.GroupsDeleted++ } if len(errs) > 0 { return report, errors.Join(errs...) } return report, nil }