chaosblade

Форк
0
/
experiment.go 
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

17
package data
18

19
import (
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

30
type ExperimentModel struct {
31
	Uid        string
32
	Command    string
33
	SubCommand string
34
	Flag       string
35
	Status     string
36
	Error      string
37
	CreateTime string
38
	UpdateTime string
39
}
40

41
type ExperimentSource interface {
42
	// CheckAndInitExperimentTable, if experiment table not exists, then init it
43
	CheckAndInitExperimentTable()
44

45
	// ExperimentTableExists return true if experiment exists
46
	ExperimentTableExists() (bool, error)
47

48
	// InitExperimentTable for first executed
49
	InitExperimentTable() error
50

51
	// InsertExperimentModel for creating chaos experiment
52
	InsertExperimentModel(model *ExperimentModel) error
53

54
	// UpdateExperimentModelByUid
55
	UpdateExperimentModelByUid(uid, status, errMsg string) error
56

57
	// QueryExperimentModelByUid
58
	QueryExperimentModelByUid(uid string) (*ExperimentModel, error)
59

60
	// QueryExperimentModels
61
	QueryExperimentModels(target, action, flag, status, limit string, asc bool) ([]*ExperimentModel, error)
62

63
	// QueryExperimentModelsByCommand
64
	// flags value contains necessary parameters generally
65
	QueryExperimentModelsByCommand(command, subCommand string, flags map[string]string) ([]*ExperimentModel, error)
66

67
	// DeleteExperimentModelByUid
68
	DeleteExperimentModelByUid(uid string) error
69
}
70

71
const expTableDDL = `CREATE TABLE IF NOT EXISTS experiment (
72
	id INTEGER PRIMARY KEY AUTOINCREMENT,
73
	uid VARCHAR(32) UNIQUE,
74
	command VARCHAR NOT NULL,
75
	sub_command VARCHAR,
76
	flag VARCHAR,
77
	status VARCHAR,
78
	error VARCHAR,
79
	create_time VARCHAR,
80
	update_time VARCHAR
81
)`
82

83
var 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

89
var insertExpDML = `INSERT INTO
90
	experiment (uid, command, sub_command, flag, status, error, create_time, update_time)
91
	VALUES (?, ?, ?, ?, ?, ?, ?, ?)
92
`
93

94
func (s *Source) CheckAndInitExperimentTable() {
95
	exists, err := s.ExperimentTableExists()
96
	ctx := context.Background()
97
	if err != nil {
98
		log.Fatalf(ctx, err.Error())
99
		//log.Error(err, "ExperimentTableExists err")
100
		//os.Exit(1)
101
	}
102
	if !exists {
103
		err = s.InitExperimentTable()
104
		if err != nil {
105
			log.Fatalf(ctx, err.Error())
106
			//log.Error(err, "InitExperimentTable err")
107
			//os.Exit(1)
108
		}
109
	}
110
}
111

112
func (s *Source) ExperimentTableExists() (bool, error) {
113
	stmt, err := s.DB.Prepare(tableExistsDQL)
114
	if err != nil {
115
		return false, fmt.Errorf("select experiment table exists err when invoke db prepare, %s", err)
116
	}
117
	defer stmt.Close()
118
	rows, err := stmt.Query("experiment")
119
	if err != nil {
120
		return false, fmt.Errorf("select experiment table exists or not err, %s", err)
121
	}
122
	defer rows.Close()
123
	var c int
124
	if rows.Next() {
125
		rows.Scan(&c)
126
	}
127

128
	return c != 0, nil
129
}
130

131
func (s *Source) InitExperimentTable() error {
132
	_, err := s.DB.Exec(expTableDDL)
133
	if err != nil {
134
		return fmt.Errorf("create experiment table err, %s", err)
135
	}
136
	for _, sql := range expIndexDDL {
137
		s.DB.Exec(sql)
138
	}
139
	return nil
140
}
141

142
func (s *Source) InsertExperimentModel(model *ExperimentModel) error {
143
	stmt, err := s.DB.Prepare(insertExpDML)
144
	if err != nil {
145
		return err
146
	}
147
	defer stmt.Close()
148
	_, err = stmt.Exec(
149
		model.Uid,
150
		model.Command,
151
		model.SubCommand,
152
		model.Flag,
153
		model.Status,
154
		model.Error,
155
		model.CreateTime,
156
		model.UpdateTime,
157
	)
158
	if err != nil {
159
		return err
160
	}
161
	return nil
162
}
163

164
func (s *Source) UpdateExperimentModelByUid(uid, status, errMsg string) error {
165
	stmt, err := s.DB.Prepare(`UPDATE experiment
166
	SET status = ?, error = ?, update_time = ?
167
	WHERE uid = ?
168
`)
169
	if err != nil {
170
		return err
171
	}
172
	defer stmt.Close()
173
	_, err = stmt.Exec(status, errMsg, time.Now().Format(time.RFC3339Nano), uid)
174
	if err != nil {
175
		return err
176
	}
177
	return nil
178
}
179

180
func (s *Source) QueryExperimentModelByUid(uid string) (*ExperimentModel, error) {
181
	stmt, err := s.DB.Prepare(`SELECT * FROM experiment WHERE uid = ?`)
182
	if err != nil {
183
		return nil, err
184
	}
185
	defer stmt.Close()
186
	rows, err := stmt.Query(uid)
187
	if err != nil {
188
		return nil, err
189
	}
190
	defer rows.Close()
191
	models, err := getExperimentModelsFrom(rows)
192
	if err != nil {
193
		return nil, err
194
	}
195
	if len(models) == 0 {
196
		return nil, nil
197
	}
198
	return models[0], nil
199
}
200

201
func (s *Source) QueryExperimentModels(target, action, flag, status, limit string, asc bool) ([]*ExperimentModel, error) {
202
	sql := `SELECT * FROM experiment where 1=1`
203
	parameters := make([]interface{}, 0)
204
	if target != "" {
205
		sql = fmt.Sprintf(`%s and command = ?`, sql)
206
		parameters = append(parameters, target)
207
	}
208
	if action != "" {
209
		sql = fmt.Sprintf(`%s and sub_command = ?`, sql)
210
		parameters = append(parameters, action)
211
	}
212
	if flag != "" {
213
		sql = fmt.Sprintf(`%s and flag like ?`, sql)
214
		parameters = append(parameters, "%"+flag+"%")
215
	}
216
	if status != "" {
217
		sql = fmt.Sprintf(`%s and status = ?`, sql)
218
		parameters = append(parameters, UpperFirst(status))
219
	}
220
	if asc {
221
		sql = fmt.Sprintf(`%s order by id asc`, sql)
222
	} else {
223
		sql = fmt.Sprintf(`%s order by id desc`, sql)
224
	}
225
	if limit != "" {
226
		values := strings.Split(limit, ",")
227
		offset := "0"
228
		count := "0"
229
		if len(values) > 1 {
230
			offset = values[0]
231
			count = values[1]
232
		} else {
233
			count = values[0]
234
		}
235
		sql = fmt.Sprintf(`%s limit ?,?`, sql)
236
		parameters = append(parameters, offset, count)
237
	}
238
	stmt, err := s.DB.Prepare(sql)
239
	if err != nil {
240
		return nil, err
241
	}
242
	defer stmt.Close()
243
	rows, err := stmt.Query(parameters...)
244
	if err != nil {
245
		return nil, err
246
	}
247
	defer rows.Close()
248
	return getExperimentModelsFrom(rows)
249
}
250

251
func (s *Source) QueryExperimentModelsByCommand(command, subCommand string, flags map[string]string) ([]*ExperimentModel, error) {
252
	models := make([]*ExperimentModel, 0)
253
	experimentModels, err := s.QueryExperimentModels(command, subCommand, "", "", "", true)
254
	if err != nil {
255
		return models, err
256
	}
257
	if flags == nil || len(flags) == 0 {
258
		return experimentModels, nil
259
	}
260
	for _, experimentModel := range experimentModels {
261
		recordModel := spec.ConvertCommandsToExpModel(subCommand, command, experimentModel.Flag)
262
		recordFlags := recordModel.ActionFlags
263
		isMatched := true
264
		for k, v := range flags {
265
			if v == "" {
266
				continue
267
			}
268
			if recordFlags[k] != v {
269
				isMatched = false
270
				break
271
			}
272
		}
273
		if isMatched {
274
			models = append(models, experimentModel)
275
		}
276
	}
277
	return models, nil
278
}
279

280
func getExperimentModelsFrom(rows *sql.Rows) ([]*ExperimentModel, error) {
281
	models := make([]*ExperimentModel, 0)
282
	for rows.Next() {
283
		var id int
284
		var uid, command, subCommand, flag, status, error, createTime, updateTime string
285
		err := rows.Scan(&id, &uid, &command, &subCommand, &flag, &status, &error, &createTime, &updateTime)
286
		if err != nil {
287
			return nil, err
288
		}
289
		model := &ExperimentModel{
290
			Uid:        uid,
291
			Command:    command,
292
			SubCommand: subCommand,
293
			Flag:       flag,
294
			Status:     status,
295
			Error:      error,
296
			CreateTime: createTime,
297
			UpdateTime: updateTime,
298
		}
299
		models = append(models, model)
300
	}
301
	return models, nil
302
}
303

304
func (s *Source) DeleteExperimentModelByUid(uid string) error {
305
	stmt, err := s.DB.Prepare(`DELETE FROM experiment WHERE uid = ?`)
306
	if err != nil {
307
		return err
308
	}
309
	defer stmt.Close()
310
	_, err = stmt.Exec(uid)
311
	if err != nil {
312
		return err
313
	}
314
	return nil
315
}
316

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.