Skip to content

Commit

Permalink
feat: handle remediation strategy and concerning branch commit compar…
Browse files Browse the repository at this point in the history
…ison (#41)

* feat: implement remediation strategy check

* chore: compare strategy to auto apply instead of dry

* feat: add comparison to concerning commit for webhook

* chore: update manifests

* chore: change condition status type
  • Loading branch information
spoukke authored Feb 10, 2023
1 parent 6097d33 commit d52b467
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 53 deletions.
13 changes: 7 additions & 6 deletions api/v1alpha1/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ type OverrideRunnerSpec struct {
ServiceAccountName string `json:"serviceAccountName,omitempty"`
}

type RemediationStrategy struct {
PlanOnDrift bool `json:"planOnDrift,omitempty"`
ApplyOnDrift bool `json:"applyOnDrift,omitempty"`
PlanOnPush bool `json:"planOnPush,omitempty"`
ApplyOnPush bool `json:"applyOnPush,omitempty"`
}
// +kubebuilder:validation:Enum=dry;autoApply
type RemediationStrategy string

const (
DryRemediationStrategy RemediationStrategy = "dry"
AutoApplyRemediationStrategy RemediationStrategy = "autoApply"
)
19 changes: 1 addition & 18 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,10 @@ spec:
planOnPullRequest:
type: boolean
remediationStrategy:
properties:
applyOnDrift:
type: boolean
applyOnPush:
type: boolean
planOnDrift:
type: boolean
type: object
enum:
- dry
- autoApply
type: string
repository:
properties:
kind:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ spec:
type: object
type: array
type: object
remediationStrategy:
enum:
- dry
- autoApply
type: string
repository:
properties:
secretName:
Expand Down
6 changes: 4 additions & 2 deletions internal/annotations/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ const (
Failure string = "runner.terraform.padok.cloud/failure"
Lock string = "runner.terraform.padok.cloud/lock"

LastBranchCommit string = "webhook.terraform.padok.cloud/branch-commit"
ForceApply string = "notifications.terraform.padok.cloud/force-apply"
LastBranchCommit string = "webhook.terraform.padok.cloud/branch-commit"
LastConcerningCommit string = "webhook.terraform.padok.cloud/concerning-commit"

ForceApply string = "notifications.terraform.padok.cloud/force-apply"
)

func Add(ctx context.Context, c client.Client, obj configv1alpha1.TerraformLayer, annotations map[string]string) error {
Expand Down
29 changes: 21 additions & 8 deletions internal/controllers/terraformlayer/conditions.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ func (r *Reconciler) IsPlanArtifactUpToDate(t *configv1alpha1.TerraformLayer) (m
return condition, false
}

func (r *Reconciler) IsLastCommitPlanned(t *configv1alpha1.TerraformLayer) (metav1.Condition, bool) {
func (r *Reconciler) IsLastConcernginCommitPlanned(t *configv1alpha1.TerraformLayer) (metav1.Condition, bool) {
condition := metav1.Condition{
Type: "IsLastCommitPlanned",
Type: "IsLastConcerningCommitPlanned",
ObservedGeneration: t.GetObjectMeta().GetGeneration(),
Status: metav1.ConditionUnknown,
LastTransitionTime: metav1.NewTime(time.Now()),
Expand All @@ -72,16 +72,29 @@ func (r *Reconciler) IsLastCommitPlanned(t *configv1alpha1.TerraformLayer) (meta
condition.Status = metav1.ConditionTrue
return condition, true
}
lastConcerningCommit, ok := t.Annotations[annotations.LastConcerningCommit]
if !ok {
condition.Reason = "NoCommitReceived"
condition.Message = "No commit has been received from webhook"
condition.Status = metav1.ConditionTrue
return condition, true
}
if lastBranchCommit != lastConcerningCommit {
condition.Reason = "CommitAlreadyHadnled"
condition.Message = "The last concerning commit should already have been planned"
condition.Status = metav1.ConditionTrue
return condition, true
}
if lastPlannedCommit == lastBranchCommit {
condition.Reason = "LastCommitPlanned"
condition.Message = "The last commit has already been planned"
condition.Reason = "LastConcerningCommitPlanned"
condition.Message = "The last concerngin commit has already been planned"
condition.Status = metav1.ConditionTrue
return condition, false
return condition, true
}
condition.Reason = "LastCommitNotPlanned"
condition.Message = "The last received commit has not been planned yet"
condition.Reason = "LastConcerningCommitNotPlanned"
condition.Message = "The last received concerning commit has not been planned yet"
condition.Status = metav1.ConditionFalse
return condition, true
return condition, false
}

func (r *Reconciler) IsApplyUpToDate(t *configv1alpha1.TerraformLayer) (metav1.Condition, bool) {
Expand Down
31 changes: 26 additions & 5 deletions internal/controllers/terraformlayer/states.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,19 @@ func (r *Reconciler) GetState(ctx context.Context, l *configv1alpha1.TerraformLa
log := log.FromContext(ctx)
c1, isPlanArtifactUpToDate := r.IsPlanArtifactUpToDate(l)
c2, isApplyUpToDate := r.IsApplyUpToDate(l)
c3, isLastCommitPlanned := r.IsLastCommitPlanned(l)
c3, isLastConcerningCommitPlanned := r.IsLastConcernginCommitPlanned(l)
// c3, hasFailed := HasFailed(r)
conditions := []metav1.Condition{c1, c2, c3}
switch {
case isPlanArtifactUpToDate && isApplyUpToDate:
log.Info("Layer is up to date, waiting for a new drift detection cycle")
return &IdleState{}, conditions
case isPlanArtifactUpToDate && !isApplyUpToDate && !isLastCommitPlanned:
log.Info("Layer needs to be applied, acquiring lock and creating a new runner")
return &ApplyNeededState{}, conditions
case !isPlanArtifactUpToDate || !isLastCommitPlanned:
case !isPlanArtifactUpToDate || !isLastConcerningCommitPlanned:
log.Info("Layer needs to be planned, acquiring lock and creating a new runner")
return &PlanNeededState{}, conditions
case isPlanArtifactUpToDate && !isApplyUpToDate:
log.Info("Layer needs to be applied, acquiring lock and creating a new runner")
return &ApplyNeededState{}, conditions
default:
log.Info("Layer is in an unknown state, defaulting to idle. If this happens please file an issue, this is an intended behavior.")
return &IdleState{}, conditions
Expand Down Expand Up @@ -88,6 +88,16 @@ type ApplyNeededState struct{}
func (s *ApplyNeededState) getHandler() func(ctx context.Context, t *Reconciler, r *configv1alpha1.TerraformLayer, repository *configv1alpha1.TerraformRepository) ctrl.Result {
return func(ctx context.Context, t *Reconciler, r *configv1alpha1.TerraformLayer, repository *configv1alpha1.TerraformRepository) ctrl.Result {
log := log.FromContext(ctx)
deltaDriftDetection, err := time.ParseDuration(t.Config.Controller.Timers.DriftDetection)
if err != nil {
log.Error(err, "could not parse timer drift detection period")
return ctrl.Result{}
}
remediationStrategy := getRemediationStrategy(repository, r)
if remediationStrategy != configv1alpha1.AutoApplyRemediationStrategy {
log.Info("layer is in dry mode, no action taken")
return ctrl.Result{RequeueAfter: deltaDriftDetection}
}
deltaOnError, err := time.ParseDuration(t.Config.Controller.Timers.OnError)
if err != nil {
log.Error(err, "could not parse timer on error period")
Expand All @@ -113,3 +123,14 @@ func (s *ApplyNeededState) getHandler() func(ctx context.Context, t *Reconciler,
return ctrl.Result{RequeueAfter: delta}
}
}

func getRemediationStrategy(repo *configv1alpha1.TerraformRepository, layer *configv1alpha1.TerraformLayer) configv1alpha1.RemediationStrategy {
result := configv1alpha1.DryRemediationStrategy
if len(repo.Spec.RemediationStrategy) > 0 {
result = repo.Spec.RemediationStrategy
}
if len(layer.Spec.RemediationStrategy) > 0 {
result = layer.Spec.RemediationStrategy
}
return result
}
13 changes: 7 additions & 6 deletions internal/webhook/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,17 +131,18 @@ func (w *Webhook) Handle(payload interface{}) {
log.Println("could not get layers")
}
for _, layer := range layers.Items {
ann := map[string]string{}
if layer.Spec.Branch != revision {
continue
}
ann[annotations.LastBranchCommit] = change.shaAfter
log.Printf("Evaluating %s", layer.Name)
if layerFilesHaveChanged(&layer, changedFiles) {
ann := map[string]string{}
ann[annotations.LastBranchCommit] = change.shaAfter
err = annotations.Add(context.TODO(), w.Client, layer, ann)
if err != nil {
log.Printf("Error adding annotation to layer %s", err)
}
ann[annotations.LastConcerningCommit] = change.shaAfter
}
err = annotations.Add(context.TODO(), w.Client, layer, ann)
if err != nil {
log.Printf("Error adding annotation to layer %s", err)
}
}
}
Expand Down

0 comments on commit d52b467

Please sign in to comment.