Skip to content

Commit

Permalink
feat(runner): enhance runner with a kubernetes client to check layer …
Browse files Browse the repository at this point in the history
…resources

Also starting to set up annotations on TerraformLayer to replace redis
  • Loading branch information
Alan-pad committed Dec 26, 2022
1 parent bc7555e commit 3672cf7
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 48 deletions.
14 changes: 14 additions & 0 deletions annotations/annotations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package annotations

const (
LastApplySum string = "runner.terraform.padok.cloud/apply-sum"
LastApplyDate string = "runner.terraform.padok.cloud/apply-date"
LastApplyCommit string = "runner.terraform.padok.cloud/apply-commit"
LastPlanCommit string = "runner.terraform.padok.cloud/plan-commit"
LastPlanDate string = "runner.terraform.padok.cloud/plan-date"
LastPlanSum string = "runner.terraform.padok.cloud/plan-sum"
Failure string = "runner.terraform.padok.cloud/failure"

LastBranchCommit string = "notifications.terraform.padok.cloud/branch-commit"
ForceApply string = "notifications.terraform.padok.cloud/force-apply"
)
2 changes: 1 addition & 1 deletion api/v1alpha1/terraformlayer_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ type TerraformLayerRepository struct {

// TerraformLayerStatus defines the observed state of TerraformLayer
type TerraformLayerStatus struct {
Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,1,rep,name=conditions"`
Conditions []metav1.Condition `json:"conditions,omitempty"`
}

//+kubebuilder:object:root=true
Expand Down
11 changes: 4 additions & 7 deletions burrito/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,12 @@ type RunnerConfig struct {
Version string `yaml:"version"`
Action string `yaml:"action"`
Repository RepositoryConfig `yaml:"repository"`
Layer LayerConfig `yaml:"layer"`
Layer Layer `yaml:"layer"`
}

type LayerConfig struct {
Lock string `yaml:"lock"`
PlanSum string `yaml:"planSum"`
PlanBin string `yaml:"planBin"`
ApplySum string `yaml:"applySum"`
PlanDate string `yaml:"planDate"`
type Layer struct {
Name string `yaml:"name"`
Namespace string `yaml:"namespace"`
}

type Redis struct {
Expand Down
21 changes: 4 additions & 17 deletions controllers/pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"fmt"

configv1alpha1 "github.com/padok-team/burrito/api/v1alpha1"
"github.com/padok-team/burrito/cache"
corev1 "k8s.io/api/core/v1"
)

Expand Down Expand Up @@ -99,24 +98,12 @@ func defaultPodSpec(layer *configv1alpha1.TerraformLayer, repository *configv1al
Value: layer.Spec.TerraformVersion,
},
{
Name: "BURRITO_RUNNER_LAYER_LOCK",
Value: cache.GenerateKey(cache.Lock, layer),
Name: "BURRITO_RUNNER_LAYER_NAME",
Value: layer.GetObjectMeta().GetName(),
},
{
Name: "BURRITO_RUNNER_LAYER_PLANSUM",
Value: cache.GenerateKey(cache.LastPlannedArtifact, layer),
},
{
Name: "BURRITO_RUNNER_LAYER_PLANBIN",
Value: cache.GenerateKey(cache.LastPlannedArtifactBin, layer),
},
{
Name: "BURRITO_RUNNER_LAYER_APPLYSUM",
Value: cache.GenerateKey(cache.LastAppliedArtifact, layer),
},
{
Name: "BURRITO_RUNNER_LAYER_PLANDATE",
Value: cache.GenerateKey(cache.LastPlanDate, layer),
Name: "BURRITO_RUNNER_LAYER_NAMESPACE",
Value: layer.GetObjectMeta().GetNamespace(),
},
},
},
Expand Down
112 changes: 89 additions & 23 deletions runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package runner
import (
"context"
"crypto/sha256"
"errors"
"fmt"
"log"
"os"
Expand All @@ -15,8 +16,17 @@ import (
"github.com/hashicorp/hc-install/product"
"github.com/hashicorp/hc-install/releases"
"github.com/hashicorp/terraform-exec/tfexec"
"github.com/padok-team/burrito/annotations"
configv1alpha1 "github.com/padok-team/burrito/api/v1alpha1"
"github.com/padok-team/burrito/burrito/config"
"github.com/padok-team/burrito/cache"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"

utilruntime "k8s.io/apimachinery/pkg/util/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
"sigs.k8s.io/controller-runtime/pkg/client"
)

const PlanArtifact string = "plan.out"
Expand All @@ -26,6 +36,8 @@ type Runner struct {
config *config.Config
terraform *tfexec.Terraform
cache cache.Cache
client client.Client
layer *configv1alpha1.TerraformLayer
}

func New(c *config.Config) *Runner {
Expand All @@ -35,23 +47,63 @@ func New(c *config.Config) *Runner {
}

func (r *Runner) Exec() {
r.cache = cache.NewRedisCache(r.config.Redis.URL, r.config.Redis.Password, r.config.Redis.Database)
defer r.cache.Delete(r.config.Runner.Layer.Lock)
err := r.init()
if err != nil {
log.Fatalf("error initializing runner: %s", err)
}
defer r.cache.Delete(cache.GenerateKey(cache.Lock, r.layer))
var ann map[string]string
switch r.config.Runner.Action {
case "plan":
r.plan()
ann, err = r.plan()
case "apply":
r.apply()
ann, err = r.apply()
default:
log.Fatalf("Unrecognized runner Action")
err = errors.New("Unrecognized runner action, If this is happening there might be a version mismatch between the controller and runner")
}
if err != nil {
log.Fatalf("Error during runner execution: %s", err)
n, ok := r.layer.Annotations[annotations.Failure]
number := 0
if ok {
number, err = strconv.Atoi(n)
if err != nil {
number = 0
}
}
number++
ann[annotations.Failure] = strconv.Itoa(number)
}
for k, v := range ann {
r.layer.Annotations[k] = v
}
err = r.client.Update(context.TODO(), r.layer)
if err != nil {
log.Fatalf("Could not update annotations on Layer: %s", err)
}
}

func (r *Runner) init() error {
r.cache = cache.NewRedisCache(r.config.Redis.URL, r.config.Redis.Password, r.config.Redis.Database)
scheme := runtime.NewScheme()
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
utilruntime.Must(configv1alpha1.AddToScheme(scheme))
cl, err := client.New(ctrl.GetConfigOrDie(), client.Options{
Scheme: scheme,
})
if err != nil {
return err
}
r.client = cl
layer := &configv1alpha1.TerraformLayer{}
err = r.client.Get(context.TODO(), types.NamespacedName{
Namespace: r.config.Runner.Layer.Namespace,
Name: r.config.Runner.Layer.Name,
}, layer)
if err != nil {
return err
}
r.layer = layer
log.Printf("Using Terraform version: %s", r.config.Runner.Version)
terraformVersion, err := version.NewVersion(r.config.Runner.Version)
if err != nil {
Expand Down Expand Up @@ -88,64 +140,78 @@ func (r *Runner) init() error {
return nil
}

func (r *Runner) plan() {
func (r *Runner) plan() (map[string]string, error) {
ann := map[string]string{}
log.Print("Launching terraform plan")
diff, err := r.terraform.Plan(context.Background(), tfexec.Out(PlanArtifact))
if err != nil {
log.Printf("Terraform plan errored: %s", err)
return
return nil, err
}
log.Printf("Setting last plan date cache at key %s", r.config.Runner.Layer.PlanDate)
err = r.cache.Set(r.config.Runner.Layer.PlanDate, []byte(strconv.FormatInt(time.Now().Unix(), 10)), 3600)
planDateKey := cache.GenerateKey(cache.LastPlanDate, r.layer)
log.Printf("Setting last plan date cache at key %s", planDateKey)
err = r.cache.Set(planDateKey, []byte(strconv.FormatInt(time.Now().Unix(), 10)), 3600)
ann[annotations.LastPlanDate] = strconv.FormatInt(time.Now().Unix(), 10)
if err != nil {
log.Fatalf("Could not put plan date in cache: %s", err)
return nil, err
}
if !diff {
log.Printf("Terraform plan diff empty, no subsequent apply should be launched")
return
return nil, err
}
plan, err := os.ReadFile(fmt.Sprintf("%s/%s", r.terraform.WorkingDir(), PlanArtifact))
if err != nil {
log.Fatalf("Could not read plan output: %s", err)
return
return nil, err
}
log.Print("Terraform plan ran successfully")
sum := sha256.Sum256(plan)
log.Printf("Setting plan binary into cache at key %s", r.config.Runner.Layer.PlanBin)
err = r.cache.Set(r.config.Runner.Layer.PlanBin, plan, 3600)
planBinKey := cache.GenerateKey(cache.LastPlannedArtifactBin, r.layer)
log.Printf("Setting plan binary into cache at key %s", planBinKey)
err = r.cache.Set(planBinKey, plan, 3600)
if err != nil {
log.Fatalf("Could not put plan binary in cache: %s", err)
}
log.Printf("Setting plan binary checksum into cache at key %s", r.config.Runner.Layer.PlanSum)
err = r.cache.Set(r.config.Runner.Layer.PlanSum, sum[:], 3600)
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[:])
if err != nil {
log.Fatalf("Could not put plan checksum in cache: %s", err)
}
return ann, nil
}

func (r *Runner) apply() {
log.Printf("Getting plan binary in cache at key %s", r.config.Runner.Layer.PlanBin)
plan, err := r.cache.Get(r.config.Runner.Layer.PlanBin)
func (r *Runner) apply() (map[string]string, error) {
ann := map[string]string{}
planBinKey := cache.GenerateKey(cache.LastPlannedArtifactBin, r.layer)
log.Printf("Getting plan binary in cache at key %s", planBinKey)
plan, err := r.cache.Get(planBinKey)
if err != nil {
log.Printf("Could not get plan artifact: %s", err)
return
return nil, err
}
sum := sha256.Sum256(plan)
err = os.WriteFile(fmt.Sprintf("%s/%s", r.terraform.WorkingDir(), PlanArtifact), plan, 0644)
if err != nil {
log.Printf("Could not write plan artifact to disk: %s", err)
return
return nil, err
}
log.Print("Launching terraform apply")
err = r.terraform.Apply(context.Background(), tfexec.DirOrPlan(PlanArtifact))
if err != nil {
log.Fatalf("Terraform apply errored: %s", err)
return
return nil, err
}
log.Print("Terraform apply ran successfully")
log.Printf("Setting plan binary checksum into cache at key %s", r.config.Runner.Layer.ApplySum)
err = r.cache.Set(r.config.Runner.Layer.ApplySum, sum[:], 3600)
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[:])
if err != nil {
log.Fatalf("Could not put apply checksum in cache: %s", err)
return nil, err
}
return ann, nil
}

0 comments on commit 3672cf7

Please sign in to comment.