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