Skip to content

Commit

Permalink
Merge branch 'main' into upgrade_yaml_v3
Browse files Browse the repository at this point in the history
  • Loading branch information
jamengual authored Jan 24, 2024
2 parents bfce614 + fe32f86 commit c1ea4b7
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 28 deletions.
4 changes: 4 additions & 0 deletions cmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ const (
DisableAutoplanLabelFlag = "disable-autoplan-label"
DisableMarkdownFoldingFlag = "disable-markdown-folding"
DisableRepoLockingFlag = "disable-repo-locking"
DisableGlobalApplyLockFlag = "disable-global-apply-lock"
DisableUnlockLabelFlag = "disable-unlock-label"
DiscardApprovalOnPlanFlag = "discard-approval-on-plan"
EmojiReaction = "emoji-reaction"
Expand Down Expand Up @@ -437,6 +438,9 @@ var boolFlags = map[string]boolFlag{
DisableRepoLockingFlag: {
description: "Disable atlantis locking repos",
},
DisableGlobalApplyLockFlag: {
description: "Disable atlantis global apply lock in UI",
},
DiscardApprovalOnPlanFlag: {
description: "Enables the discarding of approval if a new plan has been executed. Currently only Github is supported",
defaultValue: false,
Expand Down
3 changes: 2 additions & 1 deletion server/controllers/events/events_controller_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1295,6 +1295,7 @@ func setupE2E(t *testing.T, repoDir string, opt setupOption) (events_controllers
allowCommands = opt.allowCommands
}
disableApply := true
disableGlobalApplyLock := false
for _, allowCommand := range allowCommands {
if allowCommand == command.Apply {
disableApply = false
Expand All @@ -1314,7 +1315,7 @@ func setupE2E(t *testing.T, repoDir string, opt setupOption) (events_controllers
backend := boltdb
lockingClient := locking.NewClient(boltdb)
noOpLocker := locking.NewNoOpLocker()
applyLocker = locking.NewApplyClient(boltdb, disableApply)
applyLocker = locking.NewApplyClient(boltdb, disableApply, disableGlobalApplyLock)
projectLocker := &events.DefaultProjectLocker{
Locker: lockingClient,
NoOpLocker: noOpLocker,
Expand Down
9 changes: 6 additions & 3 deletions server/controllers/templates/web_templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,10 @@ type LockIndexData struct {

// ApplyLockData holds the fields to display in the index view
type ApplyLockData struct {
Locked bool
Time time.Time
TimeFormatted string
Locked bool
GlobalApplyLockEnabled bool
Time time.Time
TimeFormatted string
}

// IndexData holds the data for rendering the index page
Expand Down Expand Up @@ -98,6 +99,7 @@ var IndexTemplate = template.Must(template.New("index.html.tmpl").Parse(`
<p class="js-discard-success"><strong>Plan discarded and unlocked!</strong></p>
</section>
<section>
{{ if .ApplyLock.GlobalApplyLockEnabled }}
{{ if .ApplyLock.Locked }}
<div class="twelve center columns">
<h6><strong>Apply commands are disabled globally</strong></h6>
Expand All @@ -111,6 +113,7 @@ var IndexTemplate = template.Must(template.New("index.html.tmpl").Parse(`
<a class="button button-primary" id="applyLockPrompt">Disable Apply Commands</a>
</div>
{{ end }}
{{ end }}
</section>
<br>
<br>
Expand Down
26 changes: 17 additions & 9 deletions server/core/locking/apply_locking.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,23 @@ type ApplyCommandLock struct {
// Locked is true is when apply commands are locked
// Either by using omitting apply from AllowCommands or creating a global ApplyCommandLock
// DisableApply lock take precedence when set
Locked bool
Time time.Time
Failure string
Locked bool
GlobalApplyLockEnabled bool
Time time.Time
Failure string
}

type ApplyClient struct {
backend Backend
disableApply bool
backend Backend
disableApply bool
disableGlobalApplyLock bool
}

func NewApplyClient(backend Backend, disableApply bool) ApplyLocker {
func NewApplyClient(backend Backend, disableApply bool, disableGlobalApplyLock bool) ApplyLocker {
return &ApplyClient{
backend: backend,
disableApply: disableApply,
backend: backend,
disableApply: disableApply,
disableGlobalApplyLock: disableGlobalApplyLock,
}
}

Expand Down Expand Up @@ -91,7 +94,9 @@ func (c *ApplyClient) UnlockApply() error {
// CheckApplyLock retrieves an apply command lock if present.
// If DisableApply is set it will always return a lock.
func (c *ApplyClient) CheckApplyLock() (ApplyCommandLock, error) {
response := ApplyCommandLock{}
response := ApplyCommandLock{
GlobalApplyLockEnabled: true,
}

if c.disableApply {
return ApplyCommandLock{
Expand All @@ -108,6 +113,9 @@ func (c *ApplyClient) CheckApplyLock() (ApplyCommandLock, error) {
response.Locked = true
response.Time = applyCmdLock.LockTime()
}
if c.disableGlobalApplyLock {
response.GlobalApplyLockEnabled = false
}

return response, nil
}
18 changes: 9 additions & 9 deletions server/core/locking/locking_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ func TestApplyLocker(t *testing.T) {
backend := mocks.NewMockBackend()

When(backend.LockCommand(Any[command.Name](), Any[time.Time]())).ThenReturn(nil, errExpected)
l := locking.NewApplyClient(backend, false)
l := locking.NewApplyClient(backend, false, false)
lock, err := l.LockApply()
Equals(t, errExpected, err)
Assert(t, !lock.Locked, "exp false")
Expand All @@ -205,7 +205,7 @@ func TestApplyLocker(t *testing.T) {
t.Run("can't lock if apply is omitted from userConfig.AllowCommands", func(t *testing.T) {
backend := mocks.NewMockBackend()

l := locking.NewApplyClient(backend, true)
l := locking.NewApplyClient(backend, true, false)
_, err := l.LockApply()
ErrEquals(t, "apply is omitted from AllowCommands; Apply commands are locked globally until flag is updated", err)

Expand All @@ -216,7 +216,7 @@ func TestApplyLocker(t *testing.T) {
backend := mocks.NewMockBackend()

When(backend.LockCommand(Any[command.Name](), Any[time.Time]())).ThenReturn(applyLock, nil)
l := locking.NewApplyClient(backend, false)
l := locking.NewApplyClient(backend, false, false)
lock, _ := l.LockApply()
Assert(t, lock.Locked, "exp lock present")
})
Expand All @@ -227,15 +227,15 @@ func TestApplyLocker(t *testing.T) {
backend := mocks.NewMockBackend()

When(backend.UnlockCommand(Any[command.Name]())).ThenReturn(errExpected)
l := locking.NewApplyClient(backend, false)
l := locking.NewApplyClient(backend, false, false)
err := l.UnlockApply()
Equals(t, errExpected, err)
})

t.Run("can't lock if apply is omitted from userConfig.AllowCommands", func(t *testing.T) {
backend := mocks.NewMockBackend()

l := locking.NewApplyClient(backend, true)
l := locking.NewApplyClient(backend, true, false)
err := l.UnlockApply()
ErrEquals(t, "apply commands are disabled until AllowCommands flag is updated", err)

Expand All @@ -246,7 +246,7 @@ func TestApplyLocker(t *testing.T) {
backend := mocks.NewMockBackend()

When(backend.UnlockCommand(Any[command.Name]())).ThenReturn(nil)
l := locking.NewApplyClient(backend, false)
l := locking.NewApplyClient(backend, false, false)
err := l.UnlockApply()
Equals(t, nil, err)
})
Expand All @@ -258,7 +258,7 @@ func TestApplyLocker(t *testing.T) {
backend := mocks.NewMockBackend()

When(backend.CheckCommandLock(Any[command.Name]())).ThenReturn(nil, errExpected)
l := locking.NewApplyClient(backend, false)
l := locking.NewApplyClient(backend, false, false)
lock, err := l.CheckApplyLock()
Equals(t, errExpected, err)
Equals(t, lock.Locked, false)
Expand All @@ -267,7 +267,7 @@ func TestApplyLocker(t *testing.T) {
t.Run("when apply is not in AllowCommands always return a lock", func(t *testing.T) {
backend := mocks.NewMockBackend()

l := locking.NewApplyClient(backend, true)
l := locking.NewApplyClient(backend, true, false)
lock, err := l.CheckApplyLock()
Ok(t, err)
Equals(t, lock.Locked, true)
Expand All @@ -278,7 +278,7 @@ func TestApplyLocker(t *testing.T) {
backend := mocks.NewMockBackend()

When(backend.CheckCommandLock(Any[command.Name]())).ThenReturn(applyLock, nil)
l := locking.NewApplyClient(backend, false)
l := locking.NewApplyClient(backend, false, false)
lock, err := l.CheckApplyLock()
Equals(t, nil, err)
Assert(t, lock.Locked, "exp lock present")
Expand Down
21 changes: 15 additions & 6 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ type Server struct {
WebPassword string
ProjectCmdOutputHandler jobs.ProjectCommandOutputHandler
ScheduledExecutorService *scheduled.ExecutorService
DisableGlobalApplyLock bool
}

// Config holds config for server that isn't passed in by the user.
Expand Down Expand Up @@ -455,8 +456,12 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) {
} else {
lockingClient = locking.NewClient(backend)
}
disableGlobalApplyLock := false
if userConfig.DisableGlobalApplyLock {
disableGlobalApplyLock = true
}

applyLockingClient = locking.NewApplyClient(backend, disableApply)
applyLockingClient = locking.NewApplyClient(backend, disableApply, disableGlobalApplyLock)
workingDirLocker := events.NewDefaultWorkingDirLocker()

var workingDir events.WorkingDir = &events.FileWorkspace{
Expand Down Expand Up @@ -919,6 +924,7 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) {
ProjectJobsErrorTemplate: templates.ProjectJobsErrorTemplate,
SSLKeyFile: userConfig.SSLKeyFile,
SSLCertFile: userConfig.SSLCertFile,
DisableGlobalApplyLock: userConfig.DisableGlobalApplyLock,
Drainer: drainer,
ProjectCmdOutputHandler: projectCmdOutputHandler,
WebAuthentication: userConfig.WebBasicAuth,
Expand All @@ -941,8 +947,6 @@ func (s *Server) Start() error {
s.Router.HandleFunc("/api/apply", s.APIController.Apply).Methods("POST")
s.Router.HandleFunc("/github-app/exchange-code", s.GithubAppController.ExchangeCode).Methods("GET")
s.Router.HandleFunc("/github-app/setup", s.GithubAppController.New).Methods("GET")
s.Router.HandleFunc("/apply/lock", s.LocksController.LockApply).Methods("POST").Queries()
s.Router.HandleFunc("/apply/unlock", s.LocksController.UnlockApply).Methods("DELETE").Queries()
s.Router.HandleFunc("/locks", s.LocksController.DeleteLock).Methods("DELETE").Queries("id", "{id:.*}")
s.Router.HandleFunc("/lock", s.LocksController.GetLock).Methods("GET").
Queries(LockViewRouteIDQueryParam, fmt.Sprintf("{%s}", LockViewRouteIDQueryParam)).Name(LockViewRouteName)
Expand All @@ -953,6 +957,10 @@ func (s *Server) Start() error {
if ok {
s.Router.Handle(s.CommandRunner.GlobalCfg.Metrics.Prometheus.Endpoint, r.HTTPHandler())
}
if !s.DisableGlobalApplyLock {
s.Router.HandleFunc("/apply/lock", s.LocksController.LockApply).Methods("POST").Queries()
s.Router.HandleFunc("/apply/unlock", s.LocksController.UnlockApply).Methods("DELETE").Queries()
}

n := negroni.New(&negroni.Recovery{
Logger: log.New(os.Stdout, "", log.LstdFlags),
Expand Down Expand Up @@ -1064,9 +1072,10 @@ func (s *Server) Index(w http.ResponseWriter, _ *http.Request) {
}

applyLockData := templates.ApplyLockData{
Time: applyCmdLock.Time,
Locked: applyCmdLock.Locked,
TimeFormatted: applyCmdLock.Time.Format("02-01-2006 15:04:05"),
Time: applyCmdLock.Time,
Locked: applyCmdLock.Locked,
GlobalApplyLockEnabled: applyCmdLock.GlobalApplyLockEnabled,
TimeFormatted: applyCmdLock.Time.Format("02-01-2006 15:04:05"),
}
//Sort by date - newest to oldest.
sort.SliceStable(lockResults, func(i, j int) bool { return lockResults[i].Time.After(lockResults[j].Time) })
Expand Down
1 change: 1 addition & 0 deletions server/user_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type UserConfig struct {
DisableAutoplanLabel string `mapstructure:"disable-autoplan-label"`
DisableMarkdownFolding bool `mapstructure:"disable-markdown-folding"`
DisableRepoLocking bool `mapstructure:"disable-repo-locking"`
DisableGlobalApplyLock bool `mapstructure:"disable-global-apply-lock"`
DisableUnlockLabel string `mapstructure:"disable-unlock-label"`
DiscardApprovalOnPlanFlag bool `mapstructure:"discard-approval-on-plan"`
EmojiReaction string `mapstructure:"emoji-reaction"`
Expand Down

0 comments on commit c1ea4b7

Please sign in to comment.