...

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

Documentation: github.com/chaos-mesh/chaos-mesh/pkg/dashboard/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  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    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  // NewStore returns a new ScheduleStore.
    31  func NewStore(db *gorm.DB) core.ScheduleStore {
    32  	db.AutoMigrate(&core.Schedule{})
    33  
    34  	return &ScheduleStore{db}
    35  }
    36  
    37  // DeleteIncompleteSchedules call core.ScheduleStore.DeleteIncompleteSchedules to deletes all incomplete schedules.
    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  // ListMeta implements the core.ScheduleStore.ListMeta method.
    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("archived = ?", archived).Find(&sches).Error; err != nil && !gorm.IsRecordNotFoundError(err) {
    55  		return nil, err
    56  	}
    57  
    58  	return sches, nil
    59  }
    60  
    61  // FindByUID implements the core.ScheduleStore.FindByUID method.
    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  // FindMetaByUID implements the core.ScheduleStore.FindMetaByUID method.
    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  // Set implements the core.ScheduleStore.Set method.
    85  func (e *ScheduleStore) Set(_ context.Context, schedule *core.Schedule) error {
    86  	return e.db.Model(core.Schedule{}).Save(schedule).Error
    87  }
    88  
    89  // Archive implements the core.ScheduleStore.Archive method.
    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  // Delete deletes the experiment from the datastore.
   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  // DeleteByFinishTime deletes schedules whose time difference is greater than the given time from FinishTime.
   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 == nil {
   116  			log.Error(nil, "finish time is nil when deleting archived schedule records, skip it", "schedule", sch)
   117  			continue
   118  		}
   119  		if sch.FinishTime.Add(ttl).Before(nowTime) {
   120  			if err := e.db.Table("schedules").Unscoped().Delete(*sch).Error; err != nil {
   121  				return err
   122  			}
   123  		}
   124  	}
   125  
   126  	return nil
   127  }
   128  
   129  // DeleteByUIDs deletes schedules by the uid list.
   130  func (e *ScheduleStore) DeleteByUIDs(_ context.Context, uids []string) error {
   131  	return e.db.Table("schedules").Where("uid IN (?)", uids).Unscoped().Delete(core.Schedule{}).Error
   132  }
   133  
   134  // DeleteIncompleteSchedules implements the core.ScheduleStore.DeleteIncompleteSchedules method.
   135  func (e *ScheduleStore) DeleteIncompleteSchedules(_ context.Context) error {
   136  	return e.db.Where("finish_time IS NULL").Unscoped().Delete(core.Schedule{}).Error
   137  }
   138  
   139  func constructQueryArgs(kind, ns, name, uid string) (string, []string) {
   140  	query := ""
   141  	args := make([]string, 0)
   142  
   143  	if kind != "" {
   144  		query += "kind = ?"
   145  		args = append(args, kind)
   146  	}
   147  
   148  	if ns != "" {
   149  		if len(args) > 0 {
   150  			query += " AND namespace = ?"
   151  		} else {
   152  			query += "namespace = ?"
   153  		}
   154  		args = append(args, ns)
   155  	}
   156  
   157  	if name != "" {
   158  		if len(args) > 0 {
   159  			query += " AND name = ?"
   160  		} else {
   161  			query += "name = ?"
   162  		}
   163  		args = append(args, name)
   164  	}
   165  
   166  	if uid != "" {
   167  		if len(args) > 0 {
   168  			query += " AND uid = ?"
   169  		} else {
   170  			query += "uid = ?"
   171  		}
   172  		args = append(args, uid)
   173  	}
   174  
   175  	return query, args
   176  }
   177