1
2
3
4
5
6
7
8
9
10
11
12
13
14 package experiment
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/experiment")
28
29
30 func NewStore(db *dbstore.DB) core.ExperimentStore {
31 db.AutoMigrate(&core.Experiment{})
32
33 return &experimentStore{db}
34 }
35
36
37 func DeleteIncompleteExperiments(es core.ExperimentStore, _ core.EventStore) {
38 if err := es.DeleteIncompleteExperiments(context.Background()); err != nil && !gorm.IsRecordNotFoundError(err) {
39 log.Error(err, "failed to delete all incomplete experiments")
40 }
41 }
42
43 type experimentStore struct {
44 db *dbstore.DB
45 }
46
47
48 func (e *experimentStore) ListMeta(_ context.Context, kind, namespace, name string, archived bool) ([]*core.ExperimentMeta, error) {
49 db := e.db.Table("experiments")
50 experiments := make([]*core.ExperimentMeta, 0)
51 query, args := constructQueryArgs(kind, namespace, name, "")
52
53 if err := db.Where(query, args).Where(query, args).Where("archived = ?", archived).Find(&experiments).Error; err != nil && !gorm.IsRecordNotFoundError(err) {
54 return nil, err
55 }
56
57 return experiments, nil
58 }
59
60
61 func (e *experimentStore) FindByUID(_ context.Context, uid string) (*core.Experiment, error) {
62 experiment := new(core.Experiment)
63
64 if err := e.db.Where("uid = ?", uid).First(experiment).Error; err != nil {
65 return nil, err
66 }
67
68 return experiment, nil
69 }
70
71
72 func (e *experimentStore) FindMetaByUID(_ context.Context, uid string) (*core.ExperimentMeta, error) {
73 db := e.db.Table("experiments")
74 experiment := new(core.ExperimentMeta)
75
76 if err := db.Where("uid = ?", uid).First(experiment).Error; err != nil {
77 return nil, err
78 }
79
80 return experiment, nil
81 }
82
83
84 func (e *experimentStore) Set(_ context.Context, experiment *core.Experiment) error {
85 return e.db.Model(core.Experiment{}).Save(experiment).Error
86 }
87
88
89 func (e *experimentStore) Archive(_ context.Context, ns, name string) error {
90 if err := e.db.Model(core.Experiment{}).
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 *experimentStore) Delete(_ context.Context, exp *core.Experiment) error {
101 err := e.db.Table("experiments").Unscoped().Delete(*exp).Error
102 return err
103 }
104
105
106 func (e *experimentStore) DeleteByFinishTime(_ context.Context, ttl time.Duration) error {
107 experiments, err := e.ListMeta(context.Background(), "", "", "", true)
108 if err != nil {
109 return err
110 }
111
112 nowTime := time.Now()
113 for _, exp := range experiments {
114 if exp.FinishTime.Add(ttl).Before(nowTime) {
115 if err := e.db.Table("experiments").Unscoped().Delete(*exp).Error; err != nil {
116 return err
117 }
118 }
119 }
120
121 return nil
122 }
123
124
125 func (e *experimentStore) DeleteByUIDs(_ context.Context, uids []string) error {
126 return e.db.Table("experiments").Where("uid IN (?)", uids).Unscoped().Delete(core.Experiment{}).Error
127 }
128
129
130 func (e *experimentStore) DeleteIncompleteExperiments(_ context.Context) error {
131 return e.db.Where("finish_time IS NULL").Unscoped().Delete(core.Experiment{}).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