chaosblade
315 строк · 7.8 Кб
1/*
2* Copyright 1999-2020 Alibaba Group Holding Ltd.
3*
4* Licensed under the Apache License, Version 2.0 (the "License");
5* you may not use this file except in compliance with the License.
6* You may obtain a copy of the License at
7*
8* http://www.apache.org/licenses/LICENSE-2.0
9*
10* Unless required by applicable law or agreed to in writing, software
11* distributed under the License is distributed on an "AS IS" BASIS,
12* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13* See the License for the specific language governing permissions and
14* limitations under the License.
15*/
16
17package data
18
19import (
20"context"
21"database/sql"
22"fmt"
23"github.com/chaosblade-io/chaosblade-spec-go/log"
24"strings"
25"time"
26
27"github.com/chaosblade-io/chaosblade-spec-go/spec"
28)
29
30type ExperimentModel struct {
31Uid string
32Command string
33SubCommand string
34Flag string
35Status string
36Error string
37CreateTime string
38UpdateTime string
39}
40
41type ExperimentSource interface {
42// CheckAndInitExperimentTable, if experiment table not exists, then init it
43CheckAndInitExperimentTable()
44
45// ExperimentTableExists return true if experiment exists
46ExperimentTableExists() (bool, error)
47
48// InitExperimentTable for first executed
49InitExperimentTable() error
50
51// InsertExperimentModel for creating chaos experiment
52InsertExperimentModel(model *ExperimentModel) error
53
54// UpdateExperimentModelByUid
55UpdateExperimentModelByUid(uid, status, errMsg string) error
56
57// QueryExperimentModelByUid
58QueryExperimentModelByUid(uid string) (*ExperimentModel, error)
59
60// QueryExperimentModels
61QueryExperimentModels(target, action, flag, status, limit string, asc bool) ([]*ExperimentModel, error)
62
63// QueryExperimentModelsByCommand
64// flags value contains necessary parameters generally
65QueryExperimentModelsByCommand(command, subCommand string, flags map[string]string) ([]*ExperimentModel, error)
66
67// DeleteExperimentModelByUid
68DeleteExperimentModelByUid(uid string) error
69}
70
71const expTableDDL = `CREATE TABLE IF NOT EXISTS experiment (
72id INTEGER PRIMARY KEY AUTOINCREMENT,
73uid VARCHAR(32) UNIQUE,
74command VARCHAR NOT NULL,
75sub_command VARCHAR,
76flag VARCHAR,
77status VARCHAR,
78error VARCHAR,
79create_time VARCHAR,
80update_time VARCHAR
81)`
82
83var expIndexDDL = []string{
84`CREATE INDEX exp_uid_uidx ON experiment (uid)`,
85`CREATE INDEX exp_command_idx ON experiment (command)`,
86`CREATE INDEX exp_status_idx ON experiment (status)`,
87}
88
89var insertExpDML = `INSERT INTO
90experiment (uid, command, sub_command, flag, status, error, create_time, update_time)
91VALUES (?, ?, ?, ?, ?, ?, ?, ?)
92`
93
94func (s *Source) CheckAndInitExperimentTable() {
95exists, err := s.ExperimentTableExists()
96ctx := context.Background()
97if err != nil {
98log.Fatalf(ctx, err.Error())
99//log.Error(err, "ExperimentTableExists err")
100//os.Exit(1)
101}
102if !exists {
103err = s.InitExperimentTable()
104if err != nil {
105log.Fatalf(ctx, err.Error())
106//log.Error(err, "InitExperimentTable err")
107//os.Exit(1)
108}
109}
110}
111
112func (s *Source) ExperimentTableExists() (bool, error) {
113stmt, err := s.DB.Prepare(tableExistsDQL)
114if err != nil {
115return false, fmt.Errorf("select experiment table exists err when invoke db prepare, %s", err)
116}
117defer stmt.Close()
118rows, err := stmt.Query("experiment")
119if err != nil {
120return false, fmt.Errorf("select experiment table exists or not err, %s", err)
121}
122defer rows.Close()
123var c int
124if rows.Next() {
125rows.Scan(&c)
126}
127
128return c != 0, nil
129}
130
131func (s *Source) InitExperimentTable() error {
132_, err := s.DB.Exec(expTableDDL)
133if err != nil {
134return fmt.Errorf("create experiment table err, %s", err)
135}
136for _, sql := range expIndexDDL {
137s.DB.Exec(sql)
138}
139return nil
140}
141
142func (s *Source) InsertExperimentModel(model *ExperimentModel) error {
143stmt, err := s.DB.Prepare(insertExpDML)
144if err != nil {
145return err
146}
147defer stmt.Close()
148_, err = stmt.Exec(
149model.Uid,
150model.Command,
151model.SubCommand,
152model.Flag,
153model.Status,
154model.Error,
155model.CreateTime,
156model.UpdateTime,
157)
158if err != nil {
159return err
160}
161return nil
162}
163
164func (s *Source) UpdateExperimentModelByUid(uid, status, errMsg string) error {
165stmt, err := s.DB.Prepare(`UPDATE experiment
166SET status = ?, error = ?, update_time = ?
167WHERE uid = ?
168`)
169if err != nil {
170return err
171}
172defer stmt.Close()
173_, err = stmt.Exec(status, errMsg, time.Now().Format(time.RFC3339Nano), uid)
174if err != nil {
175return err
176}
177return nil
178}
179
180func (s *Source) QueryExperimentModelByUid(uid string) (*ExperimentModel, error) {
181stmt, err := s.DB.Prepare(`SELECT * FROM experiment WHERE uid = ?`)
182if err != nil {
183return nil, err
184}
185defer stmt.Close()
186rows, err := stmt.Query(uid)
187if err != nil {
188return nil, err
189}
190defer rows.Close()
191models, err := getExperimentModelsFrom(rows)
192if err != nil {
193return nil, err
194}
195if len(models) == 0 {
196return nil, nil
197}
198return models[0], nil
199}
200
201func (s *Source) QueryExperimentModels(target, action, flag, status, limit string, asc bool) ([]*ExperimentModel, error) {
202sql := `SELECT * FROM experiment where 1=1`
203parameters := make([]interface{}, 0)
204if target != "" {
205sql = fmt.Sprintf(`%s and command = ?`, sql)
206parameters = append(parameters, target)
207}
208if action != "" {
209sql = fmt.Sprintf(`%s and sub_command = ?`, sql)
210parameters = append(parameters, action)
211}
212if flag != "" {
213sql = fmt.Sprintf(`%s and flag like ?`, sql)
214parameters = append(parameters, "%"+flag+"%")
215}
216if status != "" {
217sql = fmt.Sprintf(`%s and status = ?`, sql)
218parameters = append(parameters, UpperFirst(status))
219}
220if asc {
221sql = fmt.Sprintf(`%s order by id asc`, sql)
222} else {
223sql = fmt.Sprintf(`%s order by id desc`, sql)
224}
225if limit != "" {
226values := strings.Split(limit, ",")
227offset := "0"
228count := "0"
229if len(values) > 1 {
230offset = values[0]
231count = values[1]
232} else {
233count = values[0]
234}
235sql = fmt.Sprintf(`%s limit ?,?`, sql)
236parameters = append(parameters, offset, count)
237}
238stmt, err := s.DB.Prepare(sql)
239if err != nil {
240return nil, err
241}
242defer stmt.Close()
243rows, err := stmt.Query(parameters...)
244if err != nil {
245return nil, err
246}
247defer rows.Close()
248return getExperimentModelsFrom(rows)
249}
250
251func (s *Source) QueryExperimentModelsByCommand(command, subCommand string, flags map[string]string) ([]*ExperimentModel, error) {
252models := make([]*ExperimentModel, 0)
253experimentModels, err := s.QueryExperimentModels(command, subCommand, "", "", "", true)
254if err != nil {
255return models, err
256}
257if flags == nil || len(flags) == 0 {
258return experimentModels, nil
259}
260for _, experimentModel := range experimentModels {
261recordModel := spec.ConvertCommandsToExpModel(subCommand, command, experimentModel.Flag)
262recordFlags := recordModel.ActionFlags
263isMatched := true
264for k, v := range flags {
265if v == "" {
266continue
267}
268if recordFlags[k] != v {
269isMatched = false
270break
271}
272}
273if isMatched {
274models = append(models, experimentModel)
275}
276}
277return models, nil
278}
279
280func getExperimentModelsFrom(rows *sql.Rows) ([]*ExperimentModel, error) {
281models := make([]*ExperimentModel, 0)
282for rows.Next() {
283var id int
284var uid, command, subCommand, flag, status, error, createTime, updateTime string
285err := rows.Scan(&id, &uid, &command, &subCommand, &flag, &status, &error, &createTime, &updateTime)
286if err != nil {
287return nil, err
288}
289model := &ExperimentModel{
290Uid: uid,
291Command: command,
292SubCommand: subCommand,
293Flag: flag,
294Status: status,
295Error: error,
296CreateTime: createTime,
297UpdateTime: updateTime,
298}
299models = append(models, model)
300}
301return models, nil
302}
303
304func (s *Source) DeleteExperimentModelByUid(uid string) error {
305stmt, err := s.DB.Prepare(`DELETE FROM experiment WHERE uid = ?`)
306if err != nil {
307return err
308}
309defer stmt.Close()
310_, err = stmt.Exec(uid)
311if err != nil {
312return err
313}
314return nil
315}
316