From 17b3d15b052c9cf647245b081264dd2fea099e85 Mon Sep 17 00:00:00 2001 From: Alan Date: Mon, 26 Dec 2022 18:08:48 +0100 Subject: [PATCH] feat(multiple): moving some cache keys to annotations base, add kubernetes client to runner --- Dockerfile | 3 +- cache/redis.go | 11 ++- controllers/conditions_test.go | 70 +++++++------- controllers/pod.go | 3 +- controllers/terraformlayer_controller.go | 113 +++++++++-------------- runner/runner.go | 13 ++- 6 files changed, 101 insertions(+), 112 deletions(-) diff --git a/Dockerfile b/Dockerfile index be3ca572..98912a85 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,7 +18,8 @@ COPY controllers/ controllers/ COPY burrito/ burrito/ COPY cmd/ cmd/ COPY runner/ runner/ -COPY cache/ cache +COPY cache/ cache/ +COPY annotations/ annotations/ # Build # the GOARCH has not a default value to allow the binary be built according to the host where the command diff --git a/cache/redis.go b/cache/redis.go index 3a484ff9..b496d78f 100644 --- a/cache/redis.go +++ b/cache/redis.go @@ -23,8 +23,17 @@ func NewRedisCache(addr string, password string, db int) *RedisCache { func (r *RedisCache) Get(key string) ([]byte, error) { val, err := r.Client.Get(context.TODO(), key).Result() + if err == redis.Nil { + return nil, &CacheError{ + Err: err, + Nil: true, + } + } if err != nil { - return nil, err + return nil, &CacheError{ + Err: err, + Nil: false, + } } return []byte(val), nil } diff --git a/controllers/conditions_test.go b/controllers/conditions_test.go index 00eb125c..3d0b3429 100644 --- a/controllers/conditions_test.go +++ b/controllers/conditions_test.go @@ -17,12 +17,14 @@ limitations under the License. package controllers import ( + "context" "strconv" "testing" "time" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "github.com/padok-team/burrito/annotations" configv1alpha1 "github.com/padok-team/burrito/api/v1alpha1" internal "github.com/padok-team/burrito/cache" @@ -64,6 +66,7 @@ var _ = Describe("TerraformLayer", func() { }, }, } + t.SetAnnotations(map[string]string{}) cache = internal.NewMemoryCache() }) @@ -96,13 +99,13 @@ var _ = Describe("TerraformLayer", func() { }) Context("with last timestamp in cache < 20min", func() { It("should return true", func() { - cache.Set(internal.GenerateKey(internal.LastPlanDate, t), []byte(strconv.Itoa(int((time.Now().Add(-5 * time.Minute)).Unix()))), 0) + t.Annotations[annotations.LastPlanDate] = strconv.Itoa(int(time.Now().Add(-time.Minute * 15).Unix())) Expect(condition.Evaluate(cache, t)).To(Equal(true)) }) }) Context("with last timestamp in cache > 20min", func() { It("should return false", func() { - cache.Set(internal.GenerateKey(internal.LastPlanDate, t), []byte(strconv.Itoa(int(time.Now().Add(-time.Minute*60).Unix()))), 0) + t.Annotations[annotations.LastPlanDate] = strconv.Itoa(int(time.Now().Add(-time.Minute * 60).Unix())) Expect(condition.Evaluate(cache, t)).To(Equal(false)) }) }) @@ -119,21 +122,21 @@ var _ = Describe("TerraformLayer", func() { }) Context("with plan in cache but no apply", func() { It("should return false", func() { - cache.Set(internal.GenerateKey(internal.LastPlannedArtifact, t), []byte("ThisIsAPlanArtifact"), 0) + t.Annotations[annotations.LastPlanSum] = "ThisIsAPlanArtifact" Expect(condition.Evaluate(cache, t)).To(Equal(false)) }) }) Context("with same plan and apply in cache", func() { It("should return true", func() { - cache.Set(internal.GenerateKey(internal.LastPlannedArtifact, t), []byte("ThisIsAPlanArtifact"), 0) - cache.Set(internal.GenerateKey(internal.LastAppliedArtifact, t), []byte("ThisIsAPlanArtifact"), 0) + t.Annotations[annotations.LastPlanSum] = "ThisIsAPlanArtifact" + t.Annotations[annotations.LastApplySum] = "ThisIsAPlanArtifact" Expect(condition.Evaluate(cache, t)).To(Equal(true)) }) }) Context("with different plan and apply in cache", func() { It("should return false", func() { - cache.Set(internal.GenerateKey(internal.LastPlannedArtifact, t), []byte("ThisIsAPlanArtifact"), 0) - cache.Set(internal.GenerateKey(internal.LastAppliedArtifact, t), []byte("ThisIsAnotherPlanArtifact"), 0) + t.Annotations[annotations.LastPlanSum] = "ThisIsAPlanArtifact" + t.Annotations[annotations.LastApplySum] = "ThisIsAnotherPlanArtifact" Expect(condition.Evaluate(cache, t)).To(Equal(false)) }) }) @@ -150,14 +153,7 @@ var _ = Describe("TerraformLayer", func() { }) Context("with terraform failure in cache", func() { It("should return true", func() { - cache.Set(internal.GenerateKey(internal.RunResult, t), []byte("1"), 0) - Expect(condition.Evaluate(cache, t)).To(Equal(true)) - }) - }) - Context("with terraform failure and message in cache", func() { - It("should return true", func() { - cache.Set(internal.GenerateKey(internal.RunResult, t), []byte("1"), 0) - cache.Set(internal.GenerateKey(internal.RunMessage, t), []byte("This is an error message."), 0) + t.Annotations[annotations.Failure] = "1" Expect(condition.Evaluate(cache, t)).To(Equal(true)) }) }) @@ -170,16 +166,16 @@ var _ = Describe("TerraformLayer", func() { Context("terraform is running", func() { It("", func() { cache.Set(internal.GenerateKey(internal.Lock, t), []byte{1}, 0) - _, out := conditions.Evaluate() + _, out := conditions.Evaluate(context.TODO()) Expect(out[0].Status).To(Equal(metav1.ConditionTrue)) }) }) Context("terraform not running and everything is up to date", func() { It("", func() { - cache.Set(internal.GenerateKey(internal.LastPlanDate, t), []byte(strconv.Itoa(int((time.Now().Add(-5 * time.Minute)).Unix()))), 0) - cache.Set(internal.GenerateKey(internal.LastPlannedArtifact, t), []byte("ThisIsAPlanArtifact"), 0) - cache.Set(internal.GenerateKey(internal.LastAppliedArtifact, t), []byte("ThisIsAPlanArtifact"), 0) - _, out := conditions.Evaluate() + t.Annotations[annotations.LastPlanDate] = strconv.Itoa(int(time.Now().Add(-time.Minute * 15).Unix())) + t.Annotations[annotations.LastPlanSum] = "ThisIsAPlanArtifact" + t.Annotations[annotations.LastApplySum] = "ThisIsAPlanArtifact" + _, out := conditions.Evaluate(context.TODO()) Expect(out[0].Status).To(Equal(metav1.ConditionFalse)) Expect(out[1].Status).To(Equal(metav1.ConditionTrue)) Expect(out[2].Status).To(Equal(metav1.ConditionTrue)) @@ -187,11 +183,11 @@ var _ = Describe("TerraformLayer", func() { }) Context("terraform not running, plan up to date, apply not up to date, terraform has failed", func() { It("", func() { - cache.Set(internal.GenerateKey(internal.LastPlanDate, t), []byte(strconv.Itoa(int((time.Now().Add(-5 * time.Minute)).Unix()))), 0) - cache.Set(internal.GenerateKey(internal.LastPlannedArtifact, t), []byte("ThisIsAPlanArtifact"), 0) - cache.Set(internal.GenerateKey(internal.LastAppliedArtifact, t), []byte("ThisIsAnotherPlanArtifact"), 0) - cache.Set(internal.GenerateKey(internal.RunResult, t), []byte("1"), 0) - _, out := conditions.Evaluate() + t.Annotations[annotations.LastPlanDate] = strconv.Itoa(int(time.Now().Add(-time.Minute * 15).Unix())) + t.Annotations[annotations.LastPlanSum] = "ThisIsAPlanArtifact" + t.Annotations[annotations.LastApplySum] = "ThisIsAnotherPlanArtifact" + t.Annotations[annotations.Failure] = "1" + _, out := conditions.Evaluate(context.TODO()) Expect(out[0].Status).To(Equal(metav1.ConditionFalse)) Expect(out[1].Status).To(Equal(metav1.ConditionTrue)) Expect(out[2].Status).To(Equal(metav1.ConditionFalse)) @@ -200,11 +196,11 @@ var _ = Describe("TerraformLayer", func() { }) Context("terraform not running, plan up to date, apply noy up to date, terraform has not failed", func() { It("", func() { - cache.Set(internal.GenerateKey(internal.LastPlanDate, t), []byte(strconv.Itoa(int((time.Now().Add(-5 * time.Minute)).Unix()))), 0) - cache.Set(internal.GenerateKey(internal.LastPlannedArtifact, t), []byte("ThisIsAPlanArtifact"), 0) - cache.Set(internal.GenerateKey(internal.LastAppliedArtifact, t), []byte("ThisIsAnotherPlanArtifact"), 0) - cache.Set(internal.GenerateKey(internal.RunResult, t), []byte("0"), 0) - _, out := conditions.Evaluate() + t.Annotations[annotations.LastPlanDate] = strconv.Itoa(int(time.Now().Add(-time.Minute * 15).Unix())) + t.Annotations[annotations.LastPlanSum] = "ThisIsAPlanArtifact" + t.Annotations[annotations.LastApplySum] = "ThisIsAnotherPlanArtifact" + t.Annotations[annotations.Failure] = "0" + _, out := conditions.Evaluate(context.TODO()) Expect(out[0].Status).To(Equal(metav1.ConditionFalse)) Expect(out[1].Status).To(Equal(metav1.ConditionTrue)) Expect(out[2].Status).To(Equal(metav1.ConditionFalse)) @@ -213,19 +209,19 @@ var _ = Describe("TerraformLayer", func() { }) Context("terraform not running, plan not up to date, terraform has failed", func() { It("", func() { - cache.Set(internal.GenerateKey(internal.LastPlanDate, t), []byte(strconv.Itoa(int(time.Now().Add(-time.Minute*60).Unix()))), 0) - cache.Set(internal.GenerateKey(internal.RunResult, t), []byte("1"), 0) - _, out := conditions.Evaluate() + t.Annotations[annotations.LastPlanDate] = strconv.Itoa(int(time.Now().Add(-time.Minute * 60).Unix())) + t.Annotations[annotations.Failure] = "1" + _, out := conditions.Evaluate(context.TODO()) Expect(out[0].Status).To(Equal(metav1.ConditionFalse)) Expect(out[1].Status).To(Equal(metav1.ConditionFalse)) Expect(out[3].Status).To(Equal(metav1.ConditionTrue)) }) }) - Context("terraform not running, plan not up to date, terraform has failed", func() { + Context("terraform not running, plan not up to date, terraform hasn't failed", func() { It("", func() { - cache.Set(internal.GenerateKey(internal.LastPlanDate, t), []byte(strconv.Itoa(int(time.Now().Add(-time.Minute*60).Unix()))), 0) - cache.Set(internal.GenerateKey(internal.RunResult, t), []byte("0"), 0) - _, out := conditions.Evaluate() + t.Annotations[annotations.LastPlanDate] = strconv.Itoa(int(time.Now().Add(-time.Minute * 60).Unix())) + t.Annotations[annotations.Failure] = "0" + _, out := conditions.Evaluate(context.TODO()) Expect(out[0].Status).To(Equal(metav1.ConditionFalse)) Expect(out[1].Status).To(Equal(metav1.ConditionFalse)) Expect(out[3].Status).To(Equal(metav1.ConditionFalse)) diff --git a/controllers/pod.go b/controllers/pod.go index 37ad8bda..7549cc74 100644 --- a/controllers/pod.go +++ b/controllers/pod.go @@ -43,7 +43,8 @@ func defaultPodSpec(layer *configv1alpha1.TerraformLayer, repository *configv1al VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}}, }, }, - RestartPolicy: corev1.RestartPolicyNever, + RestartPolicy: corev1.RestartPolicyNever, + ServiceAccountName: "burrito-runner", Containers: []corev1.Container{ { Name: "runner", diff --git a/controllers/terraformlayer_controller.go b/controllers/terraformlayer_controller.go index 9cc61091..0535d7eb 100644 --- a/controllers/terraformlayer_controller.go +++ b/controllers/terraformlayer_controller.go @@ -17,11 +17,11 @@ limitations under the License. package controllers import ( - "bytes" "context" "strconv" "time" + "github.com/padok-team/burrito/annotations" "github.com/padok-team/burrito/burrito/config" internal "github.com/padok-team/burrito/cache" "k8s.io/apimachinery/pkg/api/errors" @@ -57,35 +57,35 @@ type TerraformLayerReconciler struct { // For more details, check Reconcile and its Result here: // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.13.0/pkg/reconcile func (r *TerraformLayerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - _ = log.FromContext(ctx).WithValues("LayerController", req.NamespacedName) - log.Log.Info("Starting reconciliation") + log := log.FromContext(ctx) + log.Info("Starting reconciliation") layer := &configv1alpha1.TerraformLayer{} err := r.Client.Get(ctx, req.NamespacedName, layer) if errors.IsNotFound(err) { - log.Log.Info("Resource not found. Ignoring since object must be deleted.") + log.Info("Resource not found. Ignoring since object must be deleted.") return ctrl.Result{}, nil } if err != nil { - log.Log.Error(err, "Failed to get TerraformLayer") + log.Error(err, "Failed to get TerraformLayer") return ctrl.Result{}, err } repository := &configv1alpha1.TerraformRepository{} - log.Log.Info("Getting Linked TerraformRepository") + log.Info("Getting Linked TerraformRepository") err = r.Client.Get(ctx, types.NamespacedName{ Namespace: layer.Spec.Repository.Namespace, Name: layer.Spec.Repository.Name, }, repository) if errors.IsNotFound(err) { - log.Log.Info("TerraformRepository not found, ignoring layer until it's modified.") + log.Info("TerraformRepository not found, ignoring layer until it's modified.") return ctrl.Result{}, err } if err != nil { - log.Log.Error(err, "Failed to get TerraformRepository") + log.Error(err, "Failed to get TerraformRepository") return ctrl.Result{}, err } c := TerraformLayerConditions{Resource: layer, Cache: &r.Cache, Repository: repository, Config: r.Config} - evalFunc, conditions := c.Evaluate() - log.Log.Info("Finishing reconciliation for TerraformLayer") + evalFunc, conditions := c.Evaluate(ctx) + log.Info("Finishing reconciliation for TerraformLayer") layer.Status = configv1alpha1.TerraformLayerStatus{Conditions: conditions} r.Client.Status().Update(ctx, layer) return evalFunc(ctx, r.Client), nil @@ -117,31 +117,32 @@ type TerraformLayerConditions struct { Repository *configv1alpha1.TerraformRepository } -func (t *TerraformLayerConditions) Evaluate() (func(ctx context.Context, c client.Client) ctrl.Result, []metav1.Condition) { +func (t *TerraformLayerConditions) Evaluate(ctx context.Context) (func(ctx context.Context, c client.Client) ctrl.Result, []metav1.Condition) { + log := log.FromContext(ctx) isTerraformRunning, err := t.IsRunning.Evaluate(*t.Cache, t.Resource) if err != nil { - log.Log.Info("Something went wrong with conditions evaluation requeuing") + log.Error(err, "Something went wrong with conditions evaluation requeuing") return func(ctx context.Context, c client.Client) ctrl.Result { return ctrl.Result{RequeueAfter: time.Second * time.Duration(t.Config.Controller.Timers.OnError)} }, nil } isPlanArtifactUpToDate, err := t.IsPlanArtifactUpToDate.Evaluate(*t.Cache, t.Resource) if err != nil { - log.Log.Info("Something went wrong with conditions evaluation requeuing") + log.Error(err, "Something went wrong with conditions evaluation requeuing") return func(ctx context.Context, c client.Client) ctrl.Result { return ctrl.Result{RequeueAfter: time.Second * time.Duration(t.Config.Controller.Timers.OnError)} }, nil } isApplyUpToDate, err := t.IsApplyUpToDate.Evaluate(*t.Cache, t.Resource) if err != nil { - log.Log.Info("Something went wrong with conditions evaluation requeuing") + log.Error(err, "Something went wrong with conditions evaluation requeuing") return func(ctx context.Context, c client.Client) ctrl.Result { return ctrl.Result{RequeueAfter: time.Second * time.Duration(t.Config.Controller.Timers.OnError)} }, nil } hasTerraformFailed, err := t.HasFailed.Evaluate(*t.Cache, t.Resource) if err != nil { - log.Log.Info("Something went wrong with conditions evaluation requeuing") + log.Error(err, "Something went wrong with conditions evaluation requeuing") return func(ctx context.Context, c client.Client) ctrl.Result { return ctrl.Result{RequeueAfter: time.Second * time.Duration(t.Config.Controller.Timers.OnError)} }, nil @@ -150,83 +151,83 @@ func (t *TerraformLayerConditions) Evaluate() (func(ctx context.Context, c clien cache := *t.Cache switch { case isTerraformRunning: - log.Log.Info("Terraform is already running on this layer, skipping") + log.Info("Terraform is already running on this layer, skipping") return func(ctx context.Context, c client.Client) ctrl.Result { return ctrl.Result{RequeueAfter: time.Second * time.Duration(t.Config.Controller.Timers.WaitAction)} }, conditions case !isTerraformRunning && isPlanArtifactUpToDate && isApplyUpToDate: - log.Log.Info("Layer has not drifted") + log.Info("Layer has not drifted") return func(ctx context.Context, c client.Client) ctrl.Result { return ctrl.Result{RequeueAfter: time.Second * time.Duration(t.Config.Controller.Timers.DriftDetection)} }, conditions case !isTerraformRunning && isPlanArtifactUpToDate && !isApplyUpToDate && hasTerraformFailed: - log.Log.Info("Layer needs to be applied but previous apply failed, launching a new runner") + log.Info("Layer needs to be applied but previous apply failed, launching a new runner") return func(ctx context.Context, c client.Client) ctrl.Result { pod := getPod(t.Resource, t.Repository, "apply") err := cache.Set(internal.GenerateKey(internal.Lock, t.Resource), []byte("1"), 0) if err != nil { - log.Log.Error(err, "[TerraformApplyHasFailedPreviously] failed to create lock in cache, requeuing evaluation in %s", t.Config.Controller.Timers.OnError) + log.Error(err, "[TerraformApplyHasFailedPreviously] failed to create lock in cache, requeuing evaluation in %s", t.Config.Controller.Timers.OnError) return ctrl.Result{RequeueAfter: time.Second * time.Duration(t.Config.Controller.Timers.OnError)} } err = c.Create(ctx, &pod) if err != nil { - log.Log.Error(err, "[TerraformApplyHasFailedPreviously] Failed to create pod for Apply action, requeuing evaluation in %s", t.Config.Controller.Timers.OnError) + log.Error(err, "[TerraformApplyHasFailedPreviously] Failed to create pod for Apply action, requeuing evaluation in %s", t.Config.Controller.Timers.OnError) cache.Delete(internal.GenerateKey(internal.Lock, t.Resource)) return ctrl.Result{RequeueAfter: time.Second * time.Duration(t.Config.Controller.Timers.OnError)} } return ctrl.Result{RequeueAfter: time.Second * time.Duration(t.Config.Controller.Timers.WaitAction)} }, conditions case !isTerraformRunning && isPlanArtifactUpToDate && !isApplyUpToDate && !hasTerraformFailed: - log.Log.Info("Layer needs to be applied, launching a new runner") + log.Info("Layer needs to be applied, launching a new runner") return func(ctx context.Context, c client.Client) ctrl.Result { pod := getPod(t.Resource, t.Repository, "apply") err := cache.Set(internal.GenerateKey(internal.Lock, t.Resource), []byte("1"), 0) if err != nil { - log.Log.Error(err, "[TerraformApplyNeeded] failed to create lock in cache") + log.Error(err, "[TerraformApplyNeeded] failed to create lock in cache") return ctrl.Result{RequeueAfter: time.Second * time.Duration(t.Config.Controller.Timers.OnError)} } err = c.Create(ctx, &pod) if err != nil { - log.Log.Error(err, "[TerraformApplyNeeded] Failed to create pod for Apply action") + log.Error(err, "[TerraformApplyNeeded] Failed to create pod for Apply action") cache.Delete(internal.GenerateKey(internal.Lock, t.Resource)) } return ctrl.Result{RequeueAfter: time.Second * time.Duration(t.Config.Controller.Timers.WaitAction)} }, conditions case !isTerraformRunning && !isPlanArtifactUpToDate && hasTerraformFailed: - log.Log.Info("Layer needs to be planned but previous plan failed, launching a new runner") + log.Info("Layer needs to be planned but previous plan failed, launching a new runner") return func(ctx context.Context, c client.Client) ctrl.Result { pod := getPod(t.Resource, t.Repository, "plan") err := cache.Set(internal.GenerateKey(internal.Lock, t.Resource), []byte("1"), 0) if err != nil { - log.Log.Error(err, "[TerraformPlanHasFailedPreviously] failed to create lock in cache") + log.Error(err, "[TerraformPlanHasFailedPreviously] failed to create lock in cache") return ctrl.Result{RequeueAfter: time.Second * time.Duration(t.Config.Controller.Timers.OnError)} } err = c.Create(ctx, &pod) if err != nil { - log.Log.Error(err, "[TerraformPlanHasFailedPreviously] Failed to create pod for Plan action") + log.Error(err, "[TerraformPlanHasFailedPreviously] Failed to create pod for Plan action") cache.Delete(internal.GenerateKey(internal.Lock, t.Resource)) return ctrl.Result{RequeueAfter: time.Second * time.Duration(t.Config.Controller.Timers.OnError)} } return ctrl.Result{RequeueAfter: time.Second * time.Duration(t.Config.Controller.Timers.WaitAction)} }, conditions case !isTerraformRunning && !isPlanArtifactUpToDate && !hasTerraformFailed: - log.Log.Info("Layer needs to be planned, launching a new runner") + log.Info("Layer needs to be planned, launching a new runner") return func(ctx context.Context, c client.Client) ctrl.Result { pod := getPod(t.Resource, t.Repository, "plan") err := cache.Set(internal.GenerateKey(internal.Lock, t.Resource), []byte("1"), 0) if err != nil { - log.Log.Error(err, "[TerraformPlanNeeded] failed to create lock in cache") + log.Error(err, "[TerraformPlanNeeded] failed to create lock in cache") return ctrl.Result{RequeueAfter: time.Second * time.Duration(t.Config.Controller.Timers.OnError)} } err = c.Create(ctx, &pod) if err != nil { - log.Log.Error(err, "[TerraformPlanNeeded] Failed to create pod for Plan action") + log.Error(err, "[TerraformPlanNeeded] Failed to create pod for Plan action") cache.Delete(internal.GenerateKey(internal.Lock, t.Resource)) } return ctrl.Result{RequeueAfter: time.Second * time.Duration(t.Config.Controller.Timers.WaitAction)} }, conditions default: - log.Log.Info("This controller is drunk") + log.Info("This controller is drunk") return func(ctx context.Context, c client.Client) ctrl.Result { return ctrl.Result{} }, conditions @@ -270,18 +271,14 @@ func (c *TerraformPlanArtifactUpToDate) Evaluate(cache internal.Cache, t *config ObservedGeneration: t.GetObjectMeta().GetGeneration(), Status: metav1.ConditionUnknown, } - key := internal.GenerateKey(internal.LastPlanDate, t) - value, err := cache.Get(key) - if internal.NotFound(err) { - c.Condition.Reason = "NoTimestampInCache" - c.Condition.Message = "The last plan date is not in cache." + value, ok := t.Annotations[annotations.LastPlanDate] + if !ok { + c.Condition.Reason = "NoPlanHasRunYet" + c.Condition.Message = "No plan has run on this layer yet" c.Condition.Status = metav1.ConditionFalse return false, nil } - if err != nil { - return true, err - } - unixTimestamp, _ := strconv.ParseInt(string(value), 10, 64) + unixTimestamp, _ := strconv.ParseInt(value, 10, 64) lastPlanDate := time.Unix(unixTimestamp, 0) nextPlanDate := lastPlanDate.Add(20 * time.Minute) now := time.Now() @@ -307,29 +304,21 @@ func (c *TerraformApplyUpToDate) Evaluate(cache internal.Cache, t *configv1alpha ObservedGeneration: t.GetObjectMeta().GetGeneration(), Status: metav1.ConditionUnknown, } - key := internal.GenerateKey(internal.LastPlannedArtifact, t) - planHash, err := cache.Get(key) - if internal.NotFound(err) { - c.Condition.Reason = "NoPlanYet" - c.Condition.Message = "No plan has run yet, Layer might be new" + planHash, ok := t.Annotations[annotations.LastPlanSum] + if !ok { + c.Condition.Reason = "NoPlanHasRunYet" + c.Condition.Message = "No plan has run on this layer yet" c.Condition.Status = metav1.ConditionTrue return true, nil } - if err != nil { - return true, err - } - key = internal.GenerateKey(internal.LastAppliedArtifact, t) - applyHash, err := cache.Get(key) - if internal.NotFound(err) { + applyHash, ok := t.Annotations[annotations.LastApplySum] + if !ok { c.Condition.Reason = "NoApplyHasRan" c.Condition.Message = "Apply has not ran yet but a plan is available, launching apply" c.Condition.Status = metav1.ConditionFalse return false, nil } - if err != nil { - return true, err - } - if bytes.Compare(planHash, applyHash) != 0 { + if applyHash != planHash { c.Condition.Reason = "NewPlanAvailable" c.Condition.Message = "Apply will run." c.Condition.Status = metav1.ConditionFalse @@ -351,17 +340,13 @@ func (c *TerraformFailure) Evaluate(cache internal.Cache, t *configv1alpha1.Terr ObservedGeneration: t.GetObjectMeta().GetGeneration(), Status: metav1.ConditionUnknown, } - key := internal.GenerateKey(internal.RunResult, t) - result, err := cache.Get(key) - if internal.NotFound(err) { + result, ok := t.Annotations[annotations.Failure] + if !ok { c.Condition.Reason = "NoRunYet" c.Condition.Message = "Terraform has not ran yet" c.Condition.Status = metav1.ConditionFalse return false, nil } - if err != nil { - return true, err - } if string(result) == "0" { c.Condition.Reason = "RunExitedGracefully" c.Condition.Message = "Last run exited gracefully" @@ -369,13 +354,7 @@ func (c *TerraformFailure) Evaluate(cache internal.Cache, t *configv1alpha1.Terr return false, nil } c.Condition.Status = metav1.ConditionTrue - key = internal.GenerateKey(internal.RunMessage, t) - message, err := cache.Get(key) - if err != nil { - c.Condition.Reason = "UnexpectedRunnerFailure" - c.Condition.Message = "Terraform runner might have crashed before updating Redis" - } c.Condition.Reason = "TerraformRunFailure" - c.Condition.Message = string(message) + c.Condition.Message = "Terraform has failed, look at the runner logs" return true, nil } diff --git a/runner/runner.go b/runner/runner.go index fc943127..4c34a835 100644 --- a/runner/runner.go +++ b/runner/runner.go @@ -10,6 +10,8 @@ import ( "strconv" "time" + b64 "encoding/base64" + "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" "github.com/hashicorp/go-version" @@ -52,7 +54,7 @@ func (r *Runner) Exec() { log.Fatalf("error initializing runner: %s", err) } defer r.cache.Delete(cache.GenerateKey(cache.Lock, r.layer)) - var ann map[string]string + ann := map[string]string{} switch r.config.Runner.Action { case "plan": ann, err = r.plan() @@ -61,6 +63,7 @@ func (r *Runner) Exec() { default: err = errors.New("Unrecognized runner action, If this is happening there might be a version mismatch between the controller and runner") } + ann[annotations.Failure] = "0" if err != nil { log.Fatalf("Error during runner execution: %s", err) n, ok := r.layer.Annotations[annotations.Failure] @@ -175,8 +178,8 @@ func (r *Runner) plan() (map[string]string, error) { } planSumKey := cache.GenerateKey(cache.LastPlannedArtifact, r.layer) log.Printf("Setting plan binary checksum into cache at key %s", planSumKey) - err = r.cache.Set(planSumKey, sum[:], 3600) - ann[annotations.LastPlanSum] = string(sum[:]) + err = r.cache.Set(planSumKey, []byte(b64.StdEncoding.EncodeToString(sum[:])), 3600) + ann[annotations.LastPlanSum] = b64.StdEncoding.EncodeToString(sum[:]) if err != nil { log.Fatalf("Could not put plan checksum in cache: %s", err) } @@ -207,8 +210,8 @@ func (r *Runner) apply() (map[string]string, error) { log.Print("Terraform apply ran successfully") applySumKey := cache.GenerateKey(cache.LastAppliedArtifact, r.layer) log.Printf("Setting plan binary checksum into cache at key %s", applySumKey) - err = r.cache.Set(applySumKey, sum[:], 3600) - ann[annotations.LastPlanSum] = string(sum[:]) + err = r.cache.Set(applySumKey, []byte(b64.StdEncoding.EncodeToString(sum[:])), 3600) + ann[annotations.LastApplySum] = b64.StdEncoding.EncodeToString(sum[:]) if err != nil { log.Fatalf("Could not put apply checksum in cache: %s", err) return nil, err