Skip to content

Commit 833c77e

Browse files
authored
fix(layer): handle terraform errors in runner (#149)
* fix(layer): check plan sum in IsPlanArtifactUpToDate * fix(layer): change condition reason when plan failed * fix(layer): change condition IsApplyUpToDate when plan failed * fix(runner): do not put an empty plan checksum * fix(runner): put exit code to 1 on error * fix(runner): try to not use os.exit * fix(runner): make Exec func return with err * fix(runner): new Exec function with better error handling * revert: fix(runner): new Exec function with better error handling This reverts commit d17f524. * fix(runner): propagate error through cobra * fix(runner): error propagation * fix(mispell): some mispell in error messages * test(layer): adapt fail plan test case to new condition
1 parent 8f98413 commit 833c77e

File tree

9 files changed

+53
-24
lines changed

9 files changed

+53
-24
lines changed

cmd/runner/start.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@ func buildRunnerStartCmd(app *burrito.App) *cobra.Command {
1212
cmd := &cobra.Command{
1313
Use: "start",
1414
Short: "Start Burrito runner",
15+
// Do not display usage on program error
16+
SilenceUsage: true,
1517
RunE: func(cmd *cobra.Command, args []string) error {
16-
app.StartRunner()
17-
return nil
18+
return app.StartRunner()
1819
},
1920
}
2021

internal/burrito/burrito.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ type Server interface {
2626
}
2727

2828
type Runner interface {
29-
Exec()
29+
Exec() error
3030
}
3131

3232
type Controllers interface {

internal/burrito/runner.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
package burrito
22

3-
func (app *App) StartRunner() {
4-
app.Runner.Exec()
3+
func (app *App) StartRunner() error {
4+
return app.Runner.Exec()
55
}

internal/controllers/terraformlayer/conditions.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@ func (r *Reconciler) IsPlanArtifactUpToDate(t *configv1alpha1.TerraformLayer) (m
2626
condition.Status = metav1.ConditionFalse
2727
return condition, false
2828
}
29+
planHash, ok := t.Annotations[annotations.LastPlanSum]
30+
if !ok || planHash == "" {
31+
condition.Reason = "LastPlanFailed"
32+
condition.Message = "Last plan run has failed"
33+
condition.Status = metav1.ConditionFalse
34+
return condition, false
35+
}
2936
lastPlanDate, err := time.Parse(time.UnixDate, value)
3037
if err != nil {
3138
condition.Reason = "ParseError"
@@ -95,16 +102,16 @@ func (r *Reconciler) IsApplyUpToDate(t *configv1alpha1.TerraformLayer) (metav1.C
95102
LastTransitionTime: metav1.NewTime(time.Now()),
96103
}
97104
planHash, ok := t.Annotations[annotations.LastPlanSum]
98-
if !ok {
105+
if !ok || planHash == "" {
99106
condition.Reason = "NoPlanHasRunYet"
100107
condition.Message = "No plan has run on this layer yet"
101108
condition.Status = metav1.ConditionTrue
102109
return condition, true
103110
}
104111
applyHash, ok := t.Annotations[annotations.LastApplySum]
105112
if !ok {
106-
condition.Reason = "NoApplyHasRan"
107-
condition.Message = "Apply has not ran yet but a plan is available, launching apply"
113+
condition.Reason = "NoApplyHasRun"
114+
condition.Message = "Apply has not run yet but a plan is available, launching apply"
108115
condition.Status = metav1.ConditionFalse
109116
return condition, false
110117
}

internal/controllers/terraformlayer/controller_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,10 @@ var _ = Describe("Layer", func() {
367367
It("should end in PlanNeeded state", func() {
368368
Expect(layer.Status.State).To(Equal("PlanNeeded"))
369369
})
370+
It("should have the condition IsPlanArtifactUpToDate set to false", func() {
371+
Expect(layer.Status.Conditions[0].Reason).To(Equal("LastPlanFailed"))
372+
Expect(string(layer.Status.Conditions[0].Status)).To(Equal("False"))
373+
})
370374
It("should set RequeueAfter to WaitAction", func() {
371375
Expect(result.RequeueAfter).To(Equal(reconciler.Config.Controller.Timers.WaitAction))
372376
})

internal/controllers/terraformpullrequest/states.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ func (s *CommentNeeded) getHandler() func(ctx context.Context, r *Reconciler, re
111111
comment := comment.NewDefaultComment(layers, r.Storage)
112112
err = provider.Comment(repository, pr, comment)
113113
if err != nil {
114-
log.Errorf("an error occured while commenting pull request: %s", err)
114+
log.Errorf("an error occurred while commenting pull request: %s", err)
115115
return ctrl.Result{RequeueAfter: r.Config.Controller.Timers.OnError}
116116
}
117117
err = annotations.Add(ctx, r.Client, pr, map[string]string{annotations.LastCommentedCommit: pr.Annotations[annotations.LastDiscoveredCommit]})

internal/runner/runner.go

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -66,18 +66,24 @@ func (r *Runner) unlock() {
6666
if err != nil {
6767
log.Fatalf("could not remove lease lock for terraform layer %s: %s", r.layer.Name, err)
6868
}
69+
log.Infof("successfully removed lease lock for terraform layer %s", r.layer.Name)
6970
}
7071

71-
func (r *Runner) Exec() {
72+
func (r *Runner) Exec() error {
7273
defer r.unlock()
74+
7375
var sum string
74-
err := r.init()
76+
var commit string
7577
ann := map[string]string{}
78+
79+
err := r.init()
7680
if err != nil {
7781
log.Errorf("error initializing runner: %s", err)
7882
}
79-
ref, _ := r.gitRepository.Head()
80-
commit := ref.Hash().String()
83+
if r.gitRepository != nil {
84+
ref, _ := r.gitRepository.Head()
85+
commit = ref.Hash().String()
86+
}
8187

8288
switch r.config.Runner.Action {
8389
case "plan":
@@ -95,8 +101,9 @@ func (r *Runner) Exec() {
95101
ann[annotations.LastApplyCommit] = commit
96102
}
97103
default:
98-
err = errors.New("unrecognized runner action, If this is happening there might be a version mismatch between the controller and runner")
104+
err = errors.New("unrecognized runner action, if this is happening there might be a version mismatch between the controller and runner")
99105
}
106+
100107
if err != nil {
101108
log.Errorf("error during runner execution: %s", err)
102109
n, ok := r.layer.Annotations[annotations.Failure]
@@ -109,10 +116,14 @@ func (r *Runner) Exec() {
109116
} else {
110117
ann[annotations.Failure] = "0"
111118
}
112-
err = annotations.Add(context.TODO(), r.client, r.layer, ann)
113-
if err != nil {
119+
120+
annotErr := annotations.Add(context.TODO(), r.client, r.layer, ann)
121+
if annotErr != nil {
114122
log.Errorf("could not update terraform layer annotations: %s", err)
115123
}
124+
log.Infof("successfully updated terraform layer annotations")
125+
126+
return err
116127
}
117128

118129
func (r *Runner) getLayerAndRepository() error {
@@ -195,6 +206,8 @@ func (r *Runner) init() error {
195206
log.Infof("cloning repository %s %s branch", r.repository.Spec.Repository.Url, r.layer.Spec.Branch)
196207
r.gitRepository, err = clone(r.config.Runner.Repository, r.repository.Spec.Repository.Url, r.layer.Spec.Branch, r.layer.Spec.Path)
197208
if err != nil {
209+
r.gitRepository = nil // reset git repository for the caller
210+
log.Errorf("error cloning repository: %s", err)
198211
return err
199212
}
200213
log.Infof("repository cloned successfully")
@@ -211,14 +224,18 @@ func (r *Runner) init() error {
211224
log.Infof("Launching terraform init in %s", workingDir)
212225
err = r.exec.Init(workingDir)
213226
if err != nil {
214-
log.Errorf("")
227+
log.Errorf("error executing terraform init: %s", err)
215228
return err
216229
}
217230
return nil
218231
}
219232

220233
func (r *Runner) plan() (string, error) {
221234
log.Infof("starting terraform plan")
235+
if r.exec == nil {
236+
err := errors.New("terraform or terragrunt binary not installed")
237+
return "", err
238+
}
222239
err := r.exec.Plan()
223240
if err != nil {
224241
log.Errorf("error executing terraform plan: %s", err)
@@ -246,7 +263,7 @@ func (r *Runner) plan() (string, error) {
246263
log.Errorf("error parsing terraform json plan: %s", err)
247264
return "", err
248265
}
249-
diff, shortDiff := getDiff(plan)
266+
_, shortDiff := getDiff(plan)
250267
planJsonKey := storage.GenerateKey(storage.LastPlannedArtifactJson, r.layer)
251268
log.Infof("setting plan json into storage at key %s", planJsonKey)
252269
err = r.storage.Set(planJsonKey, planJsonBytes, 3600)
@@ -257,10 +274,6 @@ func (r *Runner) plan() (string, error) {
257274
if err != nil {
258275
log.Errorf("could not put short plan in cache: %s", err)
259276
}
260-
if !diff {
261-
log.Infof("terraform plan diff empty, no subsequent apply should be launched")
262-
return "", nil
263-
}
264277
planBin, err := os.ReadFile(PlanArtifact)
265278
if err != nil {
266279
log.Errorf("could not read plan output: %s", err)
@@ -280,6 +293,10 @@ func (r *Runner) plan() (string, error) {
280293

281294
func (r *Runner) apply() (string, error) {
282295
log.Infof("starting terraform apply")
296+
if r.exec == nil {
297+
err := errors.New("terraform or terragrunt binary not installed")
298+
return "", err
299+
}
283300
planBinKey := storage.GenerateKey(storage.LastPlannedArtifactBin, r.layer)
284301
log.Infof("getting plan binary in cache at key %s", planBinKey)
285302
plan, err := r.storage.Get(planBinKey)

internal/webhook/github/provider.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ func (g *Github) GetEvent(r *http.Request) (event.Event, error) {
3636
return nil, err
3737
}
3838
if err != nil {
39-
log.Errorf("an error occured during request parsing: %s", err)
39+
log.Errorf("an error occurred during request parsing: %s", err)
4040
return nil, err
4141
}
4242

internal/webhook/gitlab/provider.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ func (g *Gitlab) GetEvent(r *http.Request) (event.Event, error) {
3636
return nil, err
3737
}
3838
if err != nil {
39-
log.Errorf("an error occured during event parsing: %s", err)
39+
log.Errorf("an error occurred during event parsing: %s", err)
4040
return nil, err
4141
}
4242
switch payload := p.(type) {

0 commit comments

Comments
 (0)