package locking import ( "errors" "time" "github.com/runatlantis/atlantis/server/events/command" ) //go:generate pegomock generate -m --package mocks -o mocks/mock_apply_lock_checker.go ApplyLockChecker // ApplyLockChecker is an implementation of the global apply lock retrieval. // It returns an object that contains information about apply locks status. type ApplyLockChecker interface { CheckApplyLock() (ApplyCommandLock, error) } //go:generate pegomock generate -m --package mocks -o mocks/mock_apply_locker.go ApplyLocker // ApplyLocker interface that manages locks for apply command runner type ApplyLocker interface { // LockApply creates a lock for ApplyCommand if lock already exists it will // return existing lock without any changes LockApply() (ApplyCommandLock, error) // UnlockApply deletes apply lock created by LockApply if present, otherwise // it is a no-op UnlockApply() error ApplyLockChecker } // ApplyCommandLock contains information about apply command lock status. type ApplyCommandLock struct { // Locked is true is when apply commands are locked // Either by using DisableApply flag or creating a global ApplyCommandLock // DisableApply lock take precedence when set Locked bool Time time.Time Failure string } type ApplyClient struct { backend Backend disableApplyFlag bool } func NewApplyClient(backend Backend, disableApplyFlag bool) ApplyLocker { return &ApplyClient{ backend: backend, disableApplyFlag: disableApplyFlag, } } // LockApply acquires global apply lock. // DisableApplyFlag takes presedence to any existing locks, if it is set to true // this function returns an error func (c *ApplyClient) LockApply() (ApplyCommandLock, error) { response := ApplyCommandLock{} if c.disableApplyFlag { return response, errors.New("DisableApplyFlag is set; Apply commands are locked globally until flag is unset") } applyCmdLock, err := c.backend.LockCommand(command.Apply, time.Now()) if err != nil { return response, err } if applyCmdLock != nil { response.Locked = true response.Time = applyCmdLock.LockTime() } return response, nil } // UnlockApply releases a global apply lock. // DisableApplyFlag takes presedence to any existing locks, if it is set to true // this function returns an error func (c *ApplyClient) UnlockApply() error { if c.disableApplyFlag { return errors.New("apply commands are disabled until DisableApply flag is unset") } err := c.backend.UnlockCommand(command.Apply) if err != nil { return err } return nil } // CheckApplyLock retrieves an apply command lock if present. // If DisableApplyFlag is set it will always return a lock. func (c *ApplyClient) CheckApplyLock() (ApplyCommandLock, error) { response := ApplyCommandLock{} if c.disableApplyFlag { return ApplyCommandLock{ Locked: true, }, nil } applyCmdLock, err := c.backend.CheckCommandLock(command.Apply) if err != nil { return response, err } if applyCmdLock != nil { response.Locked = true response.Time = applyCmdLock.LockTime() } return response, nil }