...

Source file src/github.com/chaos-mesh/chaos-mesh/pkg/store/schedule/schedule.go

Documentation: github.com/chaos-mesh/chaos-mesh/pkg/store/schedule

     1  // Copyright 2021 Chaos Mesh Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    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  // NewStore returns a new ScheduleStore.
    30  func NewStore(db *dbstore.DB) core.ScheduleStore {
    31  	db.AutoMigrate(&core.Schedule{})
    32  
    33  	return &ScheduleStore{db}
    34  }
    35  
    36  // DeleteIncompleteSchedules call core.ScheduleStore.DeleteIncompleteSchedules to deletes all incomplete schedules.
    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  // ListMeta implements the core.ScheduleStore.ListMeta method.
    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  // FindByUID implements the core.ScheduleStore.FindByUID method.
    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  // FindMetaByUID implements the core.ScheduleStore.FindMetaByUID method.
    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  // Set implements the core.ScheduleStore.Set method.
    84  func (e *ScheduleStore) Set(_ context.Context, schedule *core.Schedule) error {
    85  	return e.db.Model(core.Schedule{}).Save(schedule).Error
    86  }
    87  
    88  // Archive implements the core.ScheduleStore.Archive method.
    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  // Delete deletes the experiment from the datastore.
   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  // DeleteByFinishTime deletes schedules whose time difference is greater than the given time from FinishTime.
   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  // DeleteByUIDs deletes schedules by the uid list.
   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  // DeleteIncompleteSchedules implements the core.ScheduleStore.DeleteIncompleteSchedules method.
   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