github.com/siglens/siglens@v0.0.0-20240328180423-f7ce9ae441ed/pkg/alerts/alertsqlite/alerts_sqlite.go (about)

     1  /*
     2  Copyright 2023.
     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 alertsqlite
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"fmt"
    23  	"strings"
    24  	"time"
    25  
    26  	"github.com/google/uuid"
    27  	"gorm.io/driver/sqlite"
    28  	_ "gorm.io/driver/sqlite"
    29  	"gorm.io/gorm"
    30  
    31  	"github.com/siglens/siglens/pkg/alerts/alertutils"
    32  	"github.com/sirupsen/logrus"
    33  	log "github.com/sirupsen/logrus"
    34  )
    35  
    36  type Sqlite struct {
    37  	db  *gorm.DB
    38  	ctx context.Context
    39  }
    40  
    41  func (p *Sqlite) SetDB(dbConnection *gorm.DB) {
    42  	p.db = dbConnection
    43  }
    44  
    45  func (p *Sqlite) CloseDb() {
    46  	sqlDB, err := p.db.DB()
    47  	if err != nil {
    48  		log.Errorf("Error occurred while closing a DB connection")
    49  	}
    50  	defer sqlDB.Close()
    51  }
    52  
    53  func (p *Sqlite) Connect() error {
    54  	dbname := "siglens.db"
    55  	logger := logrus.New()
    56  	dbConnection, err := gorm.Open(sqlite.Open(dbname), &gorm.Config{
    57  		Logger: alertutils.NewGormLogrusLogger(logger.WithField("component", "gorm"), 100*time.Millisecond),
    58  	})
    59  	if err != nil {
    60  		log.Errorf("connectAlertDB: error in opening sqlite connection, err: %+v", err)
    61  		return err
    62  	}
    63  
    64  	p.SetDB(dbConnection)
    65  
    66  	err = dbConnection.AutoMigrate(&alertutils.AlertDetails{})
    67  	if err != nil {
    68  		return err
    69  	}
    70  	err = dbConnection.AutoMigrate(&alertutils.AlertLabel{})
    71  	if err != nil {
    72  		return err
    73  	}
    74  	err = dbConnection.AutoMigrate(&alertutils.AlertHistoryDetails{})
    75  	if err != nil {
    76  		return err
    77  	}
    78  	err = dbConnection.AutoMigrate(&alertutils.Notification{})
    79  	if err != nil {
    80  		return err
    81  	}
    82  	err = dbConnection.AutoMigrate(&alertutils.Contact{})
    83  	if err != nil {
    84  		return err
    85  	}
    86  	err = dbConnection.AutoMigrate(&alertutils.SlackTokenConfig{})
    87  	if err != nil {
    88  		return err
    89  	}
    90  	err = dbConnection.AutoMigrate(&alertutils.MinionSearch{})
    91  	if err != nil {
    92  		return err
    93  	}
    94  	p.ctx = context.Background()
    95  	return nil
    96  }
    97  
    98  func isValid(str string) bool {
    99  	return str != "" && str != "*"
   100  }
   101  
   102  // checks whether the alert name exists
   103  func (p Sqlite) isNewAlertName(alertName string) (bool, error) {
   104  	if !isValid(alertName) {
   105  		log.Errorf("isNewAlertName: data validation check failed")
   106  		return false, errors.New("isNewAlertName: data validation check failed")
   107  	}
   108  	if err := p.db.Where("alert_name = ?", alertName).First(&alertutils.AlertDetails{}).Error; err != nil {
   109  		if err == gorm.ErrRecordNotFound {
   110  			return true, nil
   111  		} else {
   112  			return false, err
   113  		}
   114  	}
   115  	return true, nil
   116  }
   117  
   118  // checks based on alert_id, returns true and alert_name if alert exists
   119  func (p Sqlite) verifyAlertExists(alert_id string) (bool, string, error) {
   120  	if !isValid(alert_id) {
   121  		log.Errorf("verifyAlertExists: data validation check failed %v", alert_id)
   122  		return false, "", errors.New("verifyAlertExists: data validation check failed")
   123  	}
   124  	var alert alertutils.AlertDetails
   125  
   126  	if err := p.db.Where("alert_id = ?", alert_id).Find(&alert).First(&alertutils.AlertDetails{}).Error; err != nil {
   127  		if err == gorm.ErrRecordNotFound {
   128  			return true, alert.AlertName, nil
   129  		} else {
   130  			return false, "", err
   131  		}
   132  	}
   133  
   134  	return true, "", nil
   135  }
   136  
   137  func (p Sqlite) verifyContactExists(contact_id string) (bool, error) {
   138  	if !isValid(contact_id) {
   139  		log.Errorf("verifyContactExists: data validation check failed")
   140  		return false, errors.New("verifyContactExists: data validation check failed")
   141  	}
   142  	var contact alertutils.Contact
   143  	if err := p.db.Where("contact_id = ?", contact_id).Find(&contact).First(&alertutils.Contact{}).Error; err != nil {
   144  		if err == gorm.ErrRecordNotFound {
   145  			return true, nil
   146  		} else {
   147  			return false, err
   148  		}
   149  	}
   150  	return true, nil
   151  }
   152  
   153  // Generates uniq uuid for alert, contact point
   154  func CreateUniqId() string {
   155  	newAlertId := uuid.New().String()
   156  	return newAlertId
   157  }
   158  
   159  // Creates a new record in all_alerts table and notification_details table
   160  // In notification_details table, cooldown period will be set as 0 for now
   161  // Starts a new cron job for the alert
   162  func (p Sqlite) CreateAlert(alertDetails *alertutils.AlertDetails) (alertutils.AlertDetails, error) {
   163  	if !isValid(alertDetails.AlertName) {
   164  		log.Errorf("createAlert: data validation check failed")
   165  		return alertutils.AlertDetails{}, errors.New("createAlert: data validation check failed")
   166  	}
   167  	isNewAlertName, _ := p.isNewAlertName(alertDetails.AlertName)
   168  
   169  	if !isNewAlertName {
   170  		log.Errorf("createAlert: alert name already exists")
   171  		return alertutils.AlertDetails{}, errors.New("alert name already exists")
   172  	}
   173  	alert_id := CreateUniqId()
   174  	state := alertutils.Inactive
   175  	alertDetails.State = state
   176  	alertDetails.AlertId = alert_id
   177  	result := p.db.Create(alertDetails)
   178  	if result.Error != nil && result.RowsAffected != 1 {
   179  		log.Errorf("createAlert: unable to create alert:%v", result.Error)
   180  		return alertutils.AlertDetails{}, result.Error
   181  	}
   182  
   183  	var notification alertutils.Notification
   184  	notification.CooldownPeriod = 0
   185  	notification.AlertId = alert_id
   186  	notification.NotificationId = CreateUniqId()
   187  	result = p.db.Create(&notification)
   188  	if result.Error != nil && result.RowsAffected != 1 {
   189  		log.Errorf("createAlert: unable to update notification details:%v", result.Error)
   190  		return alertutils.AlertDetails{}, result.Error
   191  	}
   192  	return *alertDetails, nil
   193  }
   194  
   195  func (p Sqlite) GetAlert(alert_id string) (*alertutils.AlertDetails, error) {
   196  	if !isValid(alert_id) {
   197  		log.Errorf("getAlert: data validation check failed")
   198  		return nil, errors.New("getAlert: data validation check failed")
   199  	}
   200  	var alert alertutils.AlertDetails
   201  	if err := p.db.Preload("Labels").Where(&alertutils.AlertDetails{AlertId: alert_id}).Find(&alert).Error; err != nil {
   202  		return nil, err
   203  	}
   204  	return &alert, nil
   205  
   206  }
   207  
   208  func (p Sqlite) GetAllAlerts(orgId uint64) ([]alertutils.AlertDetails, error) {
   209  	alerts := make([]alertutils.AlertDetails, 0)
   210  	err := p.db.Model(&alerts).Preload("Labels").Where("org_id = ?", orgId).Find(&alerts).Error
   211  	return alerts, err
   212  }
   213  
   214  func (p Sqlite) UpdateSilenceMinutes(updatedSilenceMinutes *alertutils.AlertDetails) error {
   215  	if !isValid(updatedSilenceMinutes.AlertName) || !isValid(updatedSilenceMinutes.QueryParams.QueryText) {
   216  		log.Errorf("updateSilenceMinutes: data validation check failed")
   217  		return errors.New("updateSilenceMinutesupdateSilenceMinutes: data validation check failed")
   218  	}
   219  	alertExists, _, err := p.verifyAlertExists(updatedSilenceMinutes.AlertId)
   220  	if err != nil {
   221  		log.Errorf("updateSilenceMinutes: unable to verify if alert exists, err: %+v", err)
   222  		return err
   223  	}
   224  	if !alertExists {
   225  		log.Errorf("updateSilenceMinutes: alert does not exist")
   226  		return errors.New("alert does not exist")
   227  	}
   228  	result := p.db.Save(&updatedSilenceMinutes)
   229  	if result.Error != nil && result.RowsAffected != 1 {
   230  		log.Errorf("UpdateSilenceMinutes: unable to update silence minutes details:%v", result.Error)
   231  		return result.Error
   232  	}
   233  
   234  	return nil
   235  }
   236  
   237  // Deletes cron job associated with the alert
   238  // Updates the db
   239  // Starts a new cron job with a new cron job id
   240  // updates alert details except state & cron_job_id
   241  func (p Sqlite) UpdateAlert(editedAlert *alertutils.AlertDetails) error {
   242  	// update alert can update alert name -> still id will remain same
   243  	// todo: check if contact_id exists
   244  	if !isValid(editedAlert.AlertName) || !isValid(editedAlert.QueryParams.QueryText) {
   245  		log.Errorf("updateAlert: data validation check failed")
   246  		return errors.New("updateAlert: data validation check failed")
   247  	}
   248  	alertExists, alertName, err := p.verifyAlertExists(editedAlert.AlertId)
   249  	if err != nil {
   250  		log.Errorf("updateAlert: unable to verify if alert exists, err: %+v", err)
   251  		return err
   252  	}
   253  	// new alert means id in request body is incorrect
   254  	if !alertExists {
   255  		log.Errorf("updateAlert: alert does not exist")
   256  		return errors.New("alert does not exist")
   257  	}
   258  	// if alert name in request body is same as that present in db, allow update
   259  	if alertName != editedAlert.AlertName {
   260  		isNewAlertName, err := p.isNewAlertName(editedAlert.AlertName)
   261  		if err != nil {
   262  			log.Errorf("updateAlert: unable to verify if alert name is new, err: %+v", err)
   263  			return err
   264  		}
   265  		if !isNewAlertName {
   266  			log.Errorf("updateAlert: alert name already exists")
   267  			return errors.New("alert name already exists")
   268  		}
   269  	}
   270  	result := p.db.Set("gorm:association_autoupdate", true).Save(&editedAlert)
   271  	if result.Error != nil && result.RowsAffected != 1 {
   272  		log.Errorf("UpdateAlert: unable to update alert details:%v", result.Error)
   273  		return result.Error
   274  	}
   275  	return nil
   276  }
   277  
   278  func (p Sqlite) DeleteAlert(alert_id string) error {
   279  	if !isValid(alert_id) {
   280  		log.Errorf("deleteAlert: data validation check failed")
   281  		return errors.New("deleteAlert: data validation check failed")
   282  	}
   283  	var alert alertutils.AlertDetails
   284  	result := p.db.First(&alert, "alert_id = ?", alert_id)
   285  	if result.Error != nil {
   286  		log.Errorf("deleteAlert: error deleting alert %v", result.Error)
   287  		if errors.Is(result.Error, gorm.ErrRecordNotFound) {
   288  			log.Errorf("deleteAlert: alert does not exist")
   289  			return result.Error
   290  		} else {
   291  			return result.Error
   292  		}
   293  	}
   294  	err := p.db.Model(&alert).Association("Labels").Clear()
   295  	if err != nil {
   296  		log.Errorf("deleteAlert: unable to delete alert :%v", err)
   297  		return err
   298  	}
   299  
   300  	result = p.db.Delete(&alert)
   301  	if result.Error != nil && result.RowsAffected != 1 {
   302  		log.Errorf("deleteAlert: unable to delete alert :%v", result.Error)
   303  		return result.Error
   304  	}
   305  
   306  	return nil
   307  }
   308  
   309  func (p Sqlite) CreateContact(newContact *alertutils.Contact) error {
   310  	var contact alertutils.Contact
   311  	result := p.db.First(&contact, "contact_name = ?", newContact.ContactName)
   312  	if result.Error != nil {
   313  		if !errors.Is(result.Error, gorm.ErrRecordNotFound) {
   314  			log.Errorf("CreateContact: contact name already exist")
   315  			return result.Error
   316  		} else {
   317  			contact_id := CreateUniqId()
   318  			newContact.ContactId = contact_id
   319  			result = p.db.Create(&newContact)
   320  			if result.Error != nil && result.RowsAffected != 1 {
   321  				log.Errorf("CreateContact: unable to create contact:%v", result.Error)
   322  				return result.Error
   323  			}
   324  		}
   325  	}
   326  	return nil
   327  }
   328  
   329  func (p Sqlite) GetAllContactPoints(org_id uint64) ([]alertutils.Contact, error) {
   330  	contacts := make([]alertutils.Contact, 0)
   331  	if err := p.db.Preload("Slack").Where("org_id = ?", org_id).Find(&contacts).Error; err != nil {
   332  		return nil, err
   333  	}
   334  
   335  	return contacts, nil
   336  }
   337  
   338  func (p Sqlite) UpdateContactPoint(contact *alertutils.Contact) error {
   339  	if !isValid(contact.ContactId) {
   340  		log.Errorf("updateContactPoint: invalid contact id")
   341  		return errors.New("invalid contact id")
   342  	}
   343  
   344  	contactExists, err := p.verifyContactExists(contact.ContactId)
   345  	if err != nil {
   346  		log.Errorf("updateContactPoint: unable to verify if contact exists, err: %+v", err)
   347  		return err
   348  	}
   349  	// contact does not exist, that means id in request body is incorrect
   350  	if !contactExists {
   351  		log.Errorf("updateContactPoint: contact does not exist")
   352  		return errors.New("contact does not exist")
   353  	}
   354  
   355  	if len(contact.Slack) != 0 {
   356  		err := p.db.Model(&alertutils.Contact{ContactId: contact.ContactId}).Association("Slack").Clear()
   357  		if err != nil {
   358  			log.Errorf("updateContactPoint: unable to update contact : %v, err: %+v", contact.ContactName, err)
   359  			return err
   360  		}
   361  	}
   362  	if len(contact.Webhook) != 0 {
   363  		err := p.db.Model(&alertutils.Contact{ContactId: contact.ContactId}).Association("Webhook").Clear()
   364  		if err != nil {
   365  			log.Errorf("updateContactPoint: unable to update contact : %v, err: %+v", contact.ContactName, err)
   366  			return err
   367  		}
   368  	}
   369  	result := p.db.Session(&gorm.Session{FullSaveAssociations: true}).Save(&contact)
   370  	if result.Error != nil && result.RowsAffected != 1 {
   371  		log.Errorf("updateContactPoint: unable to update contact : %v, err: %+v", contact.ContactName, err)
   372  		return result.Error
   373  	}
   374  	return nil
   375  
   376  }
   377  
   378  // get contact_id and message from all_alerts table using alert_id
   379  func (p Sqlite) GetContactDetails(alert_id string) (string, string, string, error) {
   380  
   381  	var alert alertutils.AlertDetails
   382  	if err := p.db.First(&alert).Where("alert_id = ?", alert_id).Error; err != nil {
   383  		return "", "", "", err
   384  	}
   385  	alert_name := alert.AlertName
   386  	contact_id := alert.ContactID
   387  	message := alert.Message
   388  	condition := alert.Condition
   389  	value := alert.Value
   390  
   391  	newMessage := strings.ReplaceAll(message, "{{alert_rule_name}}", alert_name)
   392  	newMessage = strings.ReplaceAll(newMessage, "{{query_string}}", alert.QueryParams.QueryLanguage)
   393  	if condition == 0 {
   394  		val := "above " + fmt.Sprintf("%1.0f", value)
   395  		newMessage = strings.ReplaceAll(newMessage, "{{condition}}", val)
   396  	} else if condition == 1 {
   397  		val := "below " + fmt.Sprintf("%1.0f", value)
   398  		newMessage = strings.ReplaceAll(newMessage, "{{condition}}", val)
   399  	} else if condition == 2 {
   400  		val := "is equal to " + fmt.Sprintf("%1.0f", value)
   401  		newMessage = strings.ReplaceAll(newMessage, "{{condition}}", val)
   402  	} else if condition == 3 {
   403  		val := "is not equal to " + fmt.Sprintf("%1.0f", value)
   404  		newMessage = strings.ReplaceAll(newMessage, "{{condition}}", val)
   405  	} else if condition == 4 {
   406  		newMessage = strings.ReplaceAll(newMessage, "{{condition}}", "has no value")
   407  	}
   408  	newMessage = strings.ReplaceAll(newMessage, "{{queryLanguage}}", alert.QueryParams.QueryLanguage)
   409  	return contact_id, newMessage, alert_name, nil
   410  }
   411  
   412  func (p Sqlite) GetCoolDownDetails(alert_id string) (uint64, time.Time, error) {
   413  	var notification alertutils.Notification
   414  	if err := p.db.First(&notification).Where("alert_id = ?", alert_id).Error; err != nil {
   415  		return 0, time.Time{}, err
   416  	}
   417  	cooldown_period := notification.CooldownPeriod
   418  	last_sent_time := notification.LastSentTime
   419  
   420  	return cooldown_period, last_sent_time, nil
   421  }
   422  
   423  func (p Sqlite) DeleteContactPoint(contact_id string) error {
   424  	if !isValid(contact_id) {
   425  		log.Errorf("deleteContactPoint: data validation check failed")
   426  		return errors.New("deleteContactPoint: data validation check failed")
   427  	}
   428  
   429  	contactExists, err := p.verifyContactExists(contact_id)
   430  	if err != nil {
   431  		log.Errorf("deleteContactPoint: unable to verify if contact exists, err: %+v", err)
   432  		return err
   433  	}
   434  	// contact does not exist, that means id in request body is incorrect
   435  	if !contactExists {
   436  		log.Errorf("deleteContactPoint: contact does not exist")
   437  		return errors.New("contact does not exist")
   438  	}
   439  
   440  	var contact alertutils.Contact
   441  
   442  	result := p.db.First(&contact, "contact_id = ?", contact_id)
   443  	if result.Error != nil {
   444  		log.Errorf("deleteContactPoint: error deleting contact %v", result.Error)
   445  		if errors.Is(result.Error, gorm.ErrRecordNotFound) {
   446  			log.Errorf("deleteContactPoint: contact does not exist")
   447  			return result.Error
   448  		} else {
   449  			return result.Error
   450  		}
   451  	}
   452  	err = p.db.Model(&contact).Association("Slack").Clear()
   453  	if err != nil {
   454  		log.Errorf("deleteContactPoint: unable to delete contact :%v", err)
   455  		return err
   456  	}
   457  
   458  	result = p.db.Delete(&contact)
   459  	if result.Error != nil && result.RowsAffected != 1 {
   460  		log.Errorf("deleteContactPoint: unable to delete contact :%v", result.Error)
   461  		return result.Error
   462  	}
   463  
   464  	return nil
   465  }
   466  
   467  // update last_sent_time in notification_details table
   468  func (p Sqlite) UpdateLastSentTime(alert_id string) error {
   469  	currentTime := time.Now().UTC()
   470  	if err := p.db.Model(&alertutils.Notification{}).Where("alert_id = ?", alert_id).Update("last_sent_time", currentTime).Error; err != nil {
   471  		log.Errorf("updateLastSentTime: unable to UpdateLastSentTime, err: %+v", err)
   472  		return err
   473  	}
   474  	return nil
   475  }
   476  
   477  func (p Sqlite) UpdateAlertStateByAlertID(alert_id string, alertState alertutils.AlertState) error {
   478  	if !isValid(alert_id) {
   479  		log.Errorf("UpdateAlertStateByAlertID: data validation check failed")
   480  		return errors.New("UpdateAlertStateByAlertID: data validation check failed")
   481  	}
   482  	alertExists, _, err := p.verifyAlertExists(alert_id)
   483  	if err != nil {
   484  		log.Errorf("UpdateAlertStateByAlertID: unable to verify if alert name exists, err: %+v", err)
   485  		return err
   486  	}
   487  	if !alertExists {
   488  		log.Errorf("UpdateAlertStateByAlertID: alert does not exist")
   489  		return errors.New("alert does not exist")
   490  	}
   491  
   492  	if err := p.db.Model(&alertutils.AlertDetails{}).Where("alert_id = ?", alert_id).Update("state", alertState).Error; err != nil {
   493  		log.Errorf("UpdateAlertStateByAlertID: unable to update alert state, with alert id: %v, err: %+v", alert_id, err)
   494  		return err
   495  	}
   496  	return nil
   497  }
   498  
   499  func (p Sqlite) GetEmailAndChannelID(contact_id string) ([]string, []alertutils.SlackTokenConfig, []string, error) {
   500  
   501  	var contact = &alertutils.Contact{}
   502  	if err := p.db.Preload("Slack").First(&contact).Where("contact_id = ?", contact_id).Error; err != nil {
   503  		log.Errorf("GetEmailAndChannelID: unable to update contact, err: %+v", err)
   504  		return nil, nil, nil, err
   505  	}
   506  	emailArray := contact.Email
   507  	slackArray := contact.Slack
   508  	webhookArray := contact.Webhook
   509  
   510  	return emailArray, slackArray, webhookArray, nil
   511  }
   512  
   513  func (p Sqlite) GetAllMinionSearches(orgId uint64) ([]alertutils.MinionSearch, error) {
   514  
   515  	alerts := make([]alertutils.MinionSearch, 0)
   516  	err := p.db.Model(&alerts).Where("org_id = ?", orgId).Find(&alertutils.MinionSearch{}).Error
   517  	return alerts, err
   518  }
   519  
   520  // Creates a new record in all_alerts table
   521  func (p Sqlite) CreateMinionSearch(minionSearchDetails *alertutils.MinionSearch) (alertutils.MinionSearch, error) {
   522  	if !isValid(minionSearchDetails.AlertName) {
   523  		log.Errorf("CreateMinionSearch: data validation check failed")
   524  		return alertutils.MinionSearch{}, errors.New("CreateMinionSearch: data validation check failed")
   525  	}
   526  	isNewAlertName, _ := p.isNewAlertName(minionSearchDetails.AlertName)
   527  
   528  	if !isNewAlertName {
   529  		log.Errorf("CreateMinionSearch: alert name already exists")
   530  		return alertutils.MinionSearch{}, errors.New("alert name already exists")
   531  	}
   532  	minionSearchDetails.CreateTimestamp = time.Now()
   533  	minionSearchDetails.State = alertutils.Inactive
   534  
   535  	result := p.db.Create(minionSearchDetails)
   536  	if result.Error != nil && result.RowsAffected != 1 {
   537  		log.Errorf("createAlert: unable to create alert:%v", result.Error)
   538  		return alertutils.MinionSearch{}, result.Error
   539  	}
   540  
   541  	return *minionSearchDetails, nil
   542  }
   543  
   544  func (p Sqlite) GetMinionSearch(alert_id string) (*alertutils.MinionSearch, error) {
   545  	if !isValid(alert_id) {
   546  		log.Errorf("GetMinionSearch: data validation check failed")
   547  		return nil, errors.New("GetMinionSearch: data validation check failed")
   548  	}
   549  
   550  	var alert alertutils.MinionSearch
   551  	if err := p.db.Preload("Labels").Where(&alertutils.AlertDetails{AlertId: alert_id}).Find(&alert).Error; err != nil {
   552  		return nil, err
   553  	}
   554  	return &alert, nil
   555  
   556  }
   557  
   558  func (p Sqlite) UpdateMinionSearchStateByAlertID(alertId string, alertState alertutils.AlertState) error {
   559  	if !isValid(alertId) {
   560  		log.Errorf("UpdateMinionSearchStateByAlertID: data validation check failed")
   561  		return errors.New("UpdateMinionSearchStateByAlertID: data validation check failed")
   562  	}
   563  	searchExists, _, err := p.verifyMinionSearchExists(alertId)
   564  	if err != nil {
   565  		log.Errorf("UpdateMinionSearchStateByAlertID: unable to verify if alert name exists, err: %+v", err)
   566  		return err
   567  	}
   568  	if !searchExists {
   569  		log.Errorf("UpdateMinionSearchStateByAlertID: alert does not exist")
   570  		return errors.New("MinionSearch does not exist")
   571  	}
   572  	if err := p.db.Model(&alertutils.MinionSearch{}).Where("alert_id = ?", alertId).Update("state", alertState).Error; err != nil {
   573  		log.Errorf("UpdateAlertStateByAlertID: unable to update alert state, with alert id: %v, err: %+v", alertId, err)
   574  		return err
   575  	}
   576  	return nil
   577  }
   578  
   579  func (p Sqlite) verifyMinionSearchExists(alert_id string) (bool, string, error) {
   580  	if !isValid(alert_id) {
   581  		log.Errorf("verifyMinionSearchExists: data validation check failed %v", alert_id)
   582  		return false, "", errors.New("verifyMinionSearchExists: data validation check failed")
   583  	}
   584  	var alert alertutils.MinionSearch
   585  
   586  	if err := p.db.Where("alert_id = ?", alert_id).Find(&alert).First(&alertutils.AlertDetails{}).Error; err != nil {
   587  		if err == gorm.ErrRecordNotFound {
   588  			return true, alert.AlertName, nil
   589  		} else {
   590  			return false, "", err
   591  		}
   592  	}
   593  	return true, "", nil
   594  }
   595  
   596  func (p Sqlite) CreateAlertHistory(alertHistoryDetails *alertutils.AlertHistoryDetails) (*alertutils.AlertHistoryDetails, error) {
   597  	if !isValid(alertHistoryDetails.AlertId) || !isValid(alertHistoryDetails.EventDescription) || !isValid(alertHistoryDetails.UserName) {
   598  		log.Errorf("CreateAlertHistory: data validation check failed")
   599  		return nil, errors.New("CreateAlertHistory: data validation check failed")
   600  	}
   601  
   602  	result := p.db.Create(alertHistoryDetails)
   603  	if result.Error != nil && result.RowsAffected != 1 {
   604  		log.Errorf("createAlert: unable to create alert:%v", result.Error)
   605  		return &alertutils.AlertHistoryDetails{}, result.Error
   606  	}
   607  	return alertHistoryDetails, nil
   608  }
   609  
   610  func (p Sqlite) GetAlertHistory(alertId string) ([]*alertutils.AlertHistoryDetails, error) {
   611  	if !isValid(alertId) {
   612  		log.Errorf("GetAlertHistory: data validation check failed")
   613  		return nil, errors.New("GetAlertHistory: data validation check failed")
   614  	}
   615  
   616  	alertExists, _, err := p.verifyAlertExists(alertId)
   617  	if err != nil {
   618  		log.Errorf("GetAlertHistory: unable to verify if alert exists, err: %+v", err)
   619  		return nil, err
   620  	}
   621  
   622  	if !alertExists {
   623  		log.Errorf("GetAlertHistory: alert does not exist")
   624  		return nil, errors.New("alert does not exist")
   625  	}
   626  
   627  	alertHistory := make([]*alertutils.AlertHistoryDetails, 0)
   628  
   629  	err = p.db.First(&alertHistory).Where("alert_id = ?", alertId).Error
   630  	return alertHistory, err
   631  
   632  }