1
2
3
4
5
6
7
8
9
10
11
12
13
14 package schedule
15
16 import (
17 "context"
18 "time"
19
20 "github.com/jinzhu/gorm"
21 ctrl "sigs.k8s.io/controller-runtime"
22
23 "github.com/chaos-mesh/chaos-mesh/pkg/core"
24 "github.com/chaos-mesh/chaos-mesh/pkg/store/dbstore"
25 )
26
27 var log = ctrl.Log.WithName("store/schedule")
28
29
30 func NewStore(db *dbstore.DB) core.ScheduleStore {
31 db.AutoMigrate(&core.Schedule{})
32
33 return &ScheduleStore{db}
34 }
35
36
37 func DeleteIncompleteSchedules(es core.ScheduleStore, _ core.EventStore) {
38 if err := es.DeleteIncompleteSchedules(context.Background()); err != nil && !gorm.IsRecordNotFoundError(err) {
39 log.Error(err, "failed to delete all incomplete schedules")
40 }
41 }
42
43 type ScheduleStore struct {
44 db *dbstore.DB
45 }
46
47
48 func (e *ScheduleStore) ListMeta(_ context.Context, namespace, name string, archived bool) ([]*core.ScheduleMeta, error) {
49 db := e.db.Table("schedules")
50 sches := make([]*core.ScheduleMeta, 0)
51 query, args := constructQueryArgs("", namespace, name, "")
52
53 if err := db.Where(query, args).Where(query, args).Where("archived = ?", archived).Find(&sches).Error; err != nil && !gorm.IsRecordNotFoundError(err) {
54 return nil, err
55 }
56
57 return sches, nil
58 }
59
60
61 func (e *ScheduleStore) FindByUID(_ context.Context, uid string) (*core.Schedule, error) {
62 sch := new(core.Schedule)
63
64 if err := e.db.Where("uid = ?", uid).First(sch).Error; err != nil {
65 return nil, err
66 }
67
68 return sch, nil
69 }
70
71
72 func (e *ScheduleStore) FindMetaByUID(_ context.Context, uid string) (*core.ScheduleMeta, error) {
73 db := e.db.Table("schedules")
74 sch := new(core.ScheduleMeta)
75
76 if err := db.Where("uid = ?", uid).First(sch).Error; err != nil {
77 return nil, err
78 }
79
80 return sch, nil
81 }
82
83
84 func (e *ScheduleStore) Set(_ context.Context, schedule *core.Schedule) error {
85 return e.db.Model(core.Schedule{}).Save(schedule).Error
86 }
87
88
89 func (e *ScheduleStore) Archive(_ context.Context, ns, name string) error {
90 if err := e.db.Model(core.Schedule{}).
91 Where("namespace = ? AND name = ? AND archived = ?", ns, name, false).
92 Updates(map[string]interface{}{"archived": true, "finish_time": time.Now()}).Error; err != nil && !gorm.IsRecordNotFoundError(err) {
93 return err
94 }
95
96 return nil
97 }
98
99
100 func (e *ScheduleStore) Delete(_ context.Context, exp *core.Schedule) error {
101 err := e.db.Table("schedules").Unscoped().Delete(*exp).Error
102 return err
103 }
104
105
106 func (e *ScheduleStore) DeleteByFinishTime(_ context.Context, ttl time.Duration) error {
107 sches, err := e.ListMeta(context.Background(), "", "", true)
108 if err != nil {
109 return err
110 }
111
112 nowTime := time.Now()
113 for _, sch := range sches {
114 if sch.FinishTime.Add(ttl).Before(nowTime) {
115 if err := e.db.Table("schedules").Unscoped().Delete(*sch).Error; err != nil {
116 return err
117 }
118 }
119 }
120
121 return nil
122 }
123
124
125 func (e *ScheduleStore) DeleteByUIDs(_ context.Context, uids []string) error {
126 return e.db.Table("schedules").Where("uid IN (?)", uids).Unscoped().Delete(core.Schedule{}).Error
127 }
128
129
130 func (e *ScheduleStore) DeleteIncompleteSchedules(_ context.Context) error {
131 return e.db.Where("finish_time IS NULL").Unscoped().Delete(core.Schedule{}).Error
132 }
133
134 func constructQueryArgs(kind, ns, name, uid string) (string, []string) {
135 query := ""
136 args := make([]string, 0)
137
138 if kind != "" {
139 query += "kind = ?"
140 args = append(args, kind)
141 }
142
143 if ns != "" {
144 if len(args) > 0 {
145 query += " AND namespace = ?"
146 } else {
147 query += "namespace = ?"
148 }
149 args = append(args, ns)
150 }
151
152 if name != "" {
153 if len(args) > 0 {
154 query += " AND name = ?"
155 } else {
156 query += "name = ?"
157 }
158 args = append(args, name)
159 }
160
161 if uid != "" {
162 if len(args) > 0 {
163 query += " AND uid = ?"
164 } else {
165 query += "uid = ?"
166 }
167 args = append(args, uid)
168 }
169
170 return query, args
171 }
172