Skip to content

Commit

Permalink
feat(controllers): Implement the TerraformRun controller (#167)
Browse files Browse the repository at this point in the history
* chore: wip

* feat(tfrun): bootstrap tfrun controller and CRD

* test(tfrun): wip writing tests

* feat(layer): refactored remediationStrategy

* fix(layer): fix test data with remediationStrategy

* feat(tfrun): wip: conditions and state handlers

* feat(tfrun): minimal working controller

* feat(tfrun): add RBAC for tfrun on burrito-controllers

* fix(tfrun): initialize controller clock

* fix(tfrun): add RBAC for tfrun to plain manifests

* feat(tfrun): wip: layer controller creates tfruns

* feat(tfrun): layer controller creates tfruns

* fix(tfrun): drop tfrun when in terminal state

* fix(tfrun): rework condition for last retry

* fix(tfrun): make maxRetries an int ptr for merging repo/layer

* feat(tfrun): remove from runner failure annotation

* test(layer): remove old commented tests

* test(tfrun): first tests on nominal case

* test(tfrun): tests on error cases

* feat(tfrun): define maxRetries in config

* feat(tfrun): make Retries column integer

* chore(docs): update documentation for tfrun

* style: changing logrus -> log

---------

Co-authored-by: Alan <alanl@padok.fr>
  • Loading branch information
corrieriluca and Alan-pad authored Oct 12, 2023
1 parent 006165a commit 93a6cd3
Show file tree
Hide file tree
Showing 55 changed files with 2,387 additions and 597 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/docs.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Documentation
name: Documentation
on:
push:
branches:
Expand All @@ -9,7 +9,7 @@ jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
with:
python-version: 3.x
Expand All @@ -19,5 +19,5 @@ jobs:
path: .cache
restore-keys: |
mkdocs-material-
- run: pip install mkdocs-material
- run: pip install mkdocs-material
- run: mkdocs gh-deploy --force
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,9 @@ Dockerfile.cross
*.swp
*.swo
*~

# Python virtual environment (for mkdocs)
.env
.venv
env/
venv/
13 changes: 7 additions & 6 deletions api/v1alpha1/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,14 @@ type MetadataOverride struct {
Labels map[string]string `json:"labels,omitempty"`
}

// +kubebuilder:validation:Enum=dry;autoApply
type RemediationStrategy string
type RemediationStrategy struct {
AutoApply bool `json:"autoApply,omitempty"`
OnError OnErrorRemediationStrategy `json:"onError,omitempty"`
}

const (
DryRemediationStrategy RemediationStrategy = "dry"
AutoApplyRemediationStrategy RemediationStrategy = "autoApply"
)
type OnErrorRemediationStrategy struct {
MaxRetries *int `json:"maxRetries,omitempty"`
}

type TerraformConfig struct {
Version string `json:"version,omitempty"`
Expand Down
21 changes: 20 additions & 1 deletion api/v1alpha1/terraformlayer_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ type TerraformLayerStatus struct {
// +kubebuilder:printcolumn:name="Repository",type=string,JSONPath=`.spec.repository.name`
// +kubebuilder:printcolumn:name="Branch",type=string,JSONPath=`.spec.branch`
// +kubebuilder:printcolumn:name="Path",type=string,JSONPath=`.spec.path`
// +kubebuilder:printcolumn:name="LastResult",type=string,JSONPath=`.status.lastResult`
// +kubebuilder:printcolumn:name="Last Result",type=string,JSONPath=`.status.lastResult`
// TerraformLayer is the Schema for the terraformlayers API
type TerraformLayer struct {
metav1.TypeMeta `json:",inline"`
Expand All @@ -77,3 +77,22 @@ type TerraformLayerList struct {
func init() {
SchemeBuilder.Register(&TerraformLayer{}, &TerraformLayerList{})
}

// Associated functions

// Workaround needed for envtest which does not populate the TypeMeta structure
// See https://github.com/kubernetes-sigs/controller-runtime/issues/1870
func (layer *TerraformLayer) GetAPIVersion() string {
if layer.APIVersion == "" {
return "config.terraform.padok.cloud/v1alpha1"
}
return layer.APIVersion
}

// Same as above
func (layer *TerraformLayer) GetKind() string {
if layer.Kind == "" {
return "TerraformLayer"
}
return layer.Kind
}
92 changes: 92 additions & 0 deletions api/v1alpha1/terraformrun_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
Copyright 2022.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1alpha1

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.

// TerraformRunSpec defines the desired state of TerraformRun
type TerraformRunSpec struct {
Action string `json:"action,omitempty"`
Layer TerraformRunLayer `json:"layer,omitempty"`
}

type TerraformRunLayer struct {
Name string `json:"name,omitempty"`
Namespace string `json:"namespace,omitempty"`
}

// TerraformRunStatus defines the observed state of TerraformRun
type TerraformRunStatus struct {
Conditions []metav1.Condition `json:"conditions,omitempty"`
State string `json:"state,omitempty"`
Retries int `json:"retries"`
LastRun string `json:"lastRun,omitempty"`
RunnerPod string `json:"runnerPod,omitempty"`
}

// +kubebuilder:object:root=true
// +kubebuilder:resource:shortName=runs;run;tfruns;tfrun;
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="State",type=string,JSONPath=`.status.state`
// +kubebuilder:printcolumn:name="Retries",type=integer,JSONPath=`.status.retries`
// +kubebuilder:printcolumn:name="Created On",type=string,JSONPath=`.metadata.creationTimestamp`
// +kubebuilder:printcolumn:name="Runner Pod",type=string,JSONPath=`.status.runnerPod`
// TerraformRun is the Schema for the terraformRuns API
type TerraformRun struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

Spec TerraformRunSpec `json:"spec,omitempty"`
Status TerraformRunStatus `json:"status,omitempty"`
}

//+kubebuilder:object:root=true

// TerraformRunList contains a list of TerraformRun
type TerraformRunList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []TerraformRun `json:"items"`
}

func init() {
SchemeBuilder.Register(&TerraformRun{}, &TerraformRunList{})
}

// Associated functions

// Workaround needed for envtest which does not populate the TypeMeta structure
// See https://github.com/kubernetes-sigs/controller-runtime/issues/1870
func (run *TerraformRun) GetAPIVersion() string {
if run.APIVersion == "" {
return "config.terraform.padok.cloud/v1alpha1"
}
return run.APIVersion
}

// Same as above
func (run *TerraformRun) GetKind() string {
if run.Kind == "" {
return "TerraformRun"
}
return run.Kind
}
150 changes: 150 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

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

3 changes: 2 additions & 1 deletion cmd/controllers/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,12 @@ func buildControllersStartCmd(app *burrito.App) *cobra.Command {
defaultFailureGracePeriod, _ := time.ParseDuration("15s")

cmd.Flags().StringSliceVar(&app.Config.Controller.Namespaces, "namespaces", []string{"burrito-system"}, "list of namespaces to watch")
cmd.Flags().StringSliceVar(&app.Config.Controller.Types, "types", []string{"layer", "repository", "pullrequest"}, "list of controllers to start")
cmd.Flags().StringSliceVar(&app.Config.Controller.Types, "types", []string{"layer", "repository", "run", "pullrequest"}, "list of controllers to start")
cmd.Flags().DurationVar(&app.Config.Controller.Timers.DriftDetection, "drift-detection-period", defaultDriftDetectionTimer, "period between two plans. Must end with s, m or h.")
cmd.Flags().DurationVar(&app.Config.Controller.Timers.OnError, "on-error-period", defaultOnErrorTimer, "period between two runners launch when an error occurred in the controllers. Must end with s, m or h.")
cmd.Flags().DurationVar(&app.Config.Controller.Timers.WaitAction, "wait-action-period", defaultWaitActionTimer, "period between two runners when a layer is locked. Must end with s, m or h.")
cmd.Flags().DurationVar(&app.Config.Controller.Timers.FailureGracePeriod, "failure-grace-period", defaultFailureGracePeriod, "initial time before retry, goes exponential function of number failure. Must end with s, m or h.")
cmd.Flags().IntVar(&app.Config.Controller.TerraformMaxRetries, "terraform-max-retries", 5, "default number of retries for terraform actions (can be overriden in CRDs)")
cmd.Flags().BoolVar(&app.Config.Controller.LeaderElection.Enabled, "leader-election", true, "whether leader election is enabled or not, default to true")
cmd.Flags().StringVar(&app.Config.Controller.LeaderElection.ID, "leader-election-id", "6d185457.terraform.padok.cloud", "lease id used for leader election")
cmd.Flags().StringVar(&app.Config.Controller.HealthProbeBindAddress, "health-probe-bind-address", ":8081", "address to bind the metrics server embedded in the controllers")
Expand Down
Loading

0 comments on commit 93a6cd3

Please sign in to comment.