From afbe55ec69770dfba808edfa64555441b1c6d709 Mon Sep 17 00:00:00 2001 From: Alan Date: Thu, 24 Nov 2022 17:07:08 +0100 Subject: [PATCH 01/42] chore(wip): wip --- api/v1alpha1/terraformlayer_types.go | 25 ++++- controllers/cache.go | 36 +++++++ controllers/terraformlayer_controller.go | 124 ++++++++++++++++++++++- 3 files changed, 177 insertions(+), 8 deletions(-) create mode 100644 controllers/cache.go diff --git a/api/v1alpha1/terraformlayer_types.go b/api/v1alpha1/terraformlayer_types.go index ac96baa8..a866a3bf 100644 --- a/api/v1alpha1/terraformlayer_types.go +++ b/api/v1alpha1/terraformlayer_types.go @@ -17,6 +17,7 @@ limitations under the License. package v1alpha1 import ( + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -28,14 +29,30 @@ type TerraformLayerSpec struct { // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster // Important: Run "make" to regenerate code after modifying this file - // Foo is an example field of TerraformLayer. Edit terraformlayer_types.go to remove/update - Foo string `json:"foo,omitempty"` + Path string `json:"path,omitempty"` + Branch string `json:"branch,omitempty"` + TerraformVersion string `json:"terraformVersion,omitempty"` + Repository TerraformLayerRepository `json:"repository,omitempty"` + RemediationStrategy TerraformLayerRemediationStrategy `json:"remediationStrategy,omitempty"` + PlanOnPullRequest bool `json:"planOnPullRequest,omitempty"` + RunnerPodTemplate corev1.PodTemplateSpec `json:"template,omitempty"` +} + +type TerraformLayerRemediationStrategy struct { + PlanOnDrift bool `json:"planOnDrift,omitempty"` + ApplyOnDrift bool `json:"applyOnDrift,omitempty"` + ApplyOnPush bool `json:"applyOnPush,omitempty"` +} + +type TerraformLayerRepository struct { + Kind string `json:"kind,omitempty"` + Name string `json:"name,omitempty"` + Namespace string `json:"namespace,omitempty"` } // TerraformLayerStatus defines the observed state of TerraformLayer type TerraformLayerStatus struct { - // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - // Important: Run "make" to regenerate code after modifying this file + Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,1,rep,name=conditions"` } //+kubebuilder:object:root=true diff --git a/controllers/cache.go b/controllers/cache.go new file mode 100644 index 00000000..590829d0 --- /dev/null +++ b/controllers/cache.go @@ -0,0 +1,36 @@ +package controllers + +import "errors" + +type Cache interface { + Get(key string) ([]byte, error) + Set(key string, value []byte, ttl int) error + Delete(key string) error +} + +type MemoryCache struct { + data map[string][]byte +} + +func newMemoryCache() *MemoryCache { + return &MemoryCache{ + data: map[string][]byte{}, + } +} + +func (m *MemoryCache) Get(key string) ([]byte, error) { + if _, ok := m.data[key]; !ok { + return nil, errors.New("key not found") + } + return m.data[key], nil +} + +func (m *MemoryCache) Set(key string, value []byte, ttl int) error { + m.data[key] = value + return nil +} + +func (m *MemoryCache) Delete(key string) error { + delete(m.data, key) + return nil +} diff --git a/controllers/terraformlayer_controller.go b/controllers/terraformlayer_controller.go index 2a706845..8ec177d9 100644 --- a/controllers/terraformlayer_controller.go +++ b/controllers/terraformlayer_controller.go @@ -18,7 +18,10 @@ package controllers import ( "context" + "time" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -31,6 +34,7 @@ import ( type TerraformLayerReconciler struct { client.Client Scheme *runtime.Scheme + Cache Cache } //+kubebuilder:rbac:groups=config.terraform.padok.cloud,resources=terraformlayers,verbs=get;list;watch;create;update;patch;delete @@ -48,15 +52,127 @@ type TerraformLayerReconciler struct { // - 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) - - // TODO(user): your logic here - - return ctrl.Result{}, nil + layer := &configv1alpha1.TerraformLayer{} + err := r.Client.Get(context.TODO(), req.NamespacedName, layer) + if errors.IsNotFound(err) { + log.Log.Info("TerraformLayer resource not found. Ignoring since object must be deleted.") + return ctrl.Result{}, nil + } + if err != nil { + log.Log.Error(err, "Failed to get TerraformLayer.") + return ctrl.Result{}, err + } + c := TerraformLayerConditions{Resource: layer, Cache: &r.Cache} + evalFunc, conditions := c.Evaluate() + layer.Status = configv1alpha1.TerraformLayerStatus{Conditions: conditions} + r.Client.Status().Update(context.TODO(), layer) + return evalFunc(), nil } // SetupWithManager sets up the controller with the Manager. func (r *TerraformLayerReconciler) SetupWithManager(mgr ctrl.Manager) error { + r.Cache = newMemoryCache() return ctrl.NewControllerManagedBy(mgr). For(&configv1alpha1.TerraformLayer{}). Complete(r) } + +const ( + RunningCondition = "IsTerraformRunning" + PlanArtifact = "IsPlanArtifactUpToDate" + ApplyUpToDate = "IsApplyUpToDate" + TerraformFailure = "HasTerraformFailed" +) + +type TerraformLayerConditions struct { + RunningCondition TerraformRunningCondition + PlanArtifact TerraformPlanArtifactCondition + ApplyUpToDate TerraformApplyUpToDateCondition + TerraformFailure TerraformFailureCondition + Cache *Cache + Resource *configv1alpha1.TerraformLayer +} + +func (t *TerraformLayerConditions) Evaluate() (func() ctrl.Result, []metav1.Condition) { + isTerraformRunning := t.RunningCondition.Evaluate(t.Cache) + isPlanArtifactUpToDate := t.PlanArtifact.Evaluate(t.Cache) + isApplyUpToDate := t.ApplyUpToDate.Evaluate(t.Cache) + hasTerraformFailed := t.TerraformFailure.Evaluate(t.Cache) + conditions := []metav1.Condition{t.RunningCondition.Status, t.PlanArtifact.Status, t.ApplyUpToDate.Status, t.TerraformFailure.Status} + switch { + case isTerraformRunning: + return func() ctrl.Result { + return ctrl.Result{RequeueAfter: time.Minute * time.Duration(2)} + }, conditions + case !isTerraformRunning && isPlanArtifactUpToDate && isApplyUpToDate: + return func() ctrl.Result { + return ctrl.Result{RequeueAfter: time.Minute * time.Duration(20)} + }, conditions + case !isTerraformRunning && isPlanArtifactUpToDate && !isApplyUpToDate && hasTerraformFailed: + return func() ctrl.Result { + //TODO: Launch Apply + //TODO: Implement Exponential backoff + return ctrl.Result{} + }, conditions + case !isTerraformRunning && isPlanArtifactUpToDate && !isApplyUpToDate && !hasTerraformFailed: + return func() ctrl.Result { + //TODO: Launch Apply + return ctrl.Result{RequeueAfter: time.Minute * time.Duration(20)} + }, conditions + case !isTerraformRunning && !isPlanArtifactUpToDate && hasTerraformFailed: + return func() ctrl.Result { + //TODO: Launch Plan + //TODO: Implement Exponential backoff + return ctrl.Result{} + }, conditions + case !isTerraformRunning && !isPlanArtifactUpToDate && !hasTerraformFailed: + return func() ctrl.Result { + //TODO: Launch Plan + return ctrl.Result{RequeueAfter: time.Minute * time.Duration(20)} + }, conditions + default: + return func() ctrl.Result { + //TODO: Add Log -> This should not have happened + return ctrl.Result{} + }, conditions + } +} + +type TerraformRunningCondition struct { + Status metav1.Condition +} + +func (c *TerraformRunningCondition) Evaluate(cache *Cache) bool { + //TODO: Compute key : Path + Repository + return true +} + +type TerraformPlanArtifactCondition struct { + Status metav1.Condition +} + +func (c *TerraformPlanArtifactCondition) Evaluate(cache *Cache) bool { + //TODO: Compute key : Path + Repository + Branch / Value: Hash Artifact + Timestamp for Last plan date + return true + +} + +type TerraformApplyUpToDateCondition struct { + Status metav1.Condition +} + +func (c *TerraformApplyUpToDateCondition) Evaluate(cache *Cache) bool { + //TODO: Compute key : Path + Repository / Value: Hash Artifact + //TODO: Compare hash artifact values (Plan vs Apply) + return true + +} + +type TerraformFailureCondition struct { + Status metav1.Condition +} + +func (c *TerraformFailureCondition) Evaluate(cache *Cache) bool { + //TODO: Compute key: Path + Repository + Branch / Value: bool + return true +} From 15f13a8e5229c2ba27955a2a3436de60862e536e Mon Sep 17 00:00:00 2001 From: Alan Date: Thu, 24 Nov 2022 17:12:29 +0100 Subject: [PATCH 02/42] chore(evaluate): change function signature --- controllers/terraformlayer_controller.go | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/controllers/terraformlayer_controller.go b/controllers/terraformlayer_controller.go index 8ec177d9..45df43d5 100644 --- a/controllers/terraformlayer_controller.go +++ b/controllers/terraformlayer_controller.go @@ -94,10 +94,10 @@ type TerraformLayerConditions struct { } func (t *TerraformLayerConditions) Evaluate() (func() ctrl.Result, []metav1.Condition) { - isTerraformRunning := t.RunningCondition.Evaluate(t.Cache) - isPlanArtifactUpToDate := t.PlanArtifact.Evaluate(t.Cache) - isApplyUpToDate := t.ApplyUpToDate.Evaluate(t.Cache) - hasTerraformFailed := t.TerraformFailure.Evaluate(t.Cache) + isTerraformRunning := t.RunningCondition.Evaluate(t.Cache, t.Resource) + isPlanArtifactUpToDate := t.PlanArtifact.Evaluate(t.Cache, t.Resource) + isApplyUpToDate := t.ApplyUpToDate.Evaluate(t.Cache, t.Resource) + hasTerraformFailed := t.TerraformFailure.Evaluate(t.Cache, t.Resource) conditions := []metav1.Condition{t.RunningCondition.Status, t.PlanArtifact.Status, t.ApplyUpToDate.Status, t.TerraformFailure.Status} switch { case isTerraformRunning: @@ -142,7 +142,7 @@ type TerraformRunningCondition struct { Status metav1.Condition } -func (c *TerraformRunningCondition) Evaluate(cache *Cache) bool { +func (c *TerraformRunningCondition) Evaluate(cache *Cache, t *configv1alpha1.TerraformLayer) bool { //TODO: Compute key : Path + Repository return true } @@ -151,17 +151,16 @@ type TerraformPlanArtifactCondition struct { Status metav1.Condition } -func (c *TerraformPlanArtifactCondition) Evaluate(cache *Cache) bool { +func (c *TerraformPlanArtifactCondition) Evaluate(cache *Cache, t *configv1alpha1.TerraformLayer) bool { //TODO: Compute key : Path + Repository + Branch / Value: Hash Artifact + Timestamp for Last plan date return true - } type TerraformApplyUpToDateCondition struct { Status metav1.Condition } -func (c *TerraformApplyUpToDateCondition) Evaluate(cache *Cache) bool { +func (c *TerraformApplyUpToDateCondition) Evaluate(cache *Cache, t *configv1alpha1.TerraformLayer) bool { //TODO: Compute key : Path + Repository / Value: Hash Artifact //TODO: Compare hash artifact values (Plan vs Apply) return true @@ -172,7 +171,7 @@ type TerraformFailureCondition struct { Status metav1.Condition } -func (c *TerraformFailureCondition) Evaluate(cache *Cache) bool { +func (c *TerraformFailureCondition) Evaluate(cache *Cache, t *configv1alpha1.TerraformLayer) bool { //TODO: Compute key: Path + Repository + Branch / Value: bool return true } From 87c3d6dc9350b86e71aff9e82b3a9227c0bf04c5 Mon Sep 17 00:00:00 2001 From: spoukke Date: Thu, 24 Nov 2022 17:19:01 +0100 Subject: [PATCH 03/42] feat: add compute hash func --- controllers/terraformlayer_controller.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/controllers/terraformlayer_controller.go b/controllers/terraformlayer_controller.go index 45df43d5..6f5264d1 100644 --- a/controllers/terraformlayer_controller.go +++ b/controllers/terraformlayer_controller.go @@ -18,6 +18,9 @@ package controllers import ( "context" + "fmt" + "hash/fnv" + "strings" "time" "k8s.io/apimachinery/pkg/api/errors" @@ -138,6 +141,14 @@ func (t *TerraformLayerConditions) Evaluate() (func() ctrl.Result, []metav1.Cond } } +func computeHash(s ...string) string { + beforeHash := "" + strings.Join(s, beforeHash) + h := fnv.New32a() + h.Write([]byte(beforeHash)) + return fmt.Sprint(h.Sum32()) +} + type TerraformRunningCondition struct { Status metav1.Condition } From 5ceba86f4496b4ddd86be474a61968bf654f0071 Mon Sep 17 00:00:00 2001 From: Alan Date: Thu, 24 Nov 2022 17:23:35 +0100 Subject: [PATCH 04/42] chore(signature): again changing function signature --- controllers/terraformlayer_controller.go | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/controllers/terraformlayer_controller.go b/controllers/terraformlayer_controller.go index 6f5264d1..3a9e1adc 100644 --- a/controllers/terraformlayer_controller.go +++ b/controllers/terraformlayer_controller.go @@ -97,10 +97,10 @@ type TerraformLayerConditions struct { } func (t *TerraformLayerConditions) Evaluate() (func() ctrl.Result, []metav1.Condition) { - isTerraformRunning := t.RunningCondition.Evaluate(t.Cache, t.Resource) - isPlanArtifactUpToDate := t.PlanArtifact.Evaluate(t.Cache, t.Resource) - isApplyUpToDate := t.ApplyUpToDate.Evaluate(t.Cache, t.Resource) - hasTerraformFailed := t.TerraformFailure.Evaluate(t.Cache, t.Resource) + isTerraformRunning := t.RunningCondition.Evaluate(*t.Cache, t.Resource) + isPlanArtifactUpToDate := t.PlanArtifact.Evaluate(*t.Cache, t.Resource) + isApplyUpToDate := t.ApplyUpToDate.Evaluate(*t.Cache, t.Resource) + hasTerraformFailed := t.TerraformFailure.Evaluate(*t.Cache, t.Resource) conditions := []metav1.Condition{t.RunningCondition.Status, t.PlanArtifact.Status, t.ApplyUpToDate.Status, t.TerraformFailure.Status} switch { case isTerraformRunning: @@ -153,7 +153,7 @@ type TerraformRunningCondition struct { Status metav1.Condition } -func (c *TerraformRunningCondition) Evaluate(cache *Cache, t *configv1alpha1.TerraformLayer) bool { +func (c *TerraformRunningCondition) Evaluate(cache Cache, t *configv1alpha1.TerraformLayer) bool { //TODO: Compute key : Path + Repository return true } @@ -162,7 +162,7 @@ type TerraformPlanArtifactCondition struct { Status metav1.Condition } -func (c *TerraformPlanArtifactCondition) Evaluate(cache *Cache, t *configv1alpha1.TerraformLayer) bool { +func (c *TerraformPlanArtifactCondition) Evaluate(cache Cache, t *configv1alpha1.TerraformLayer) bool { //TODO: Compute key : Path + Repository + Branch / Value: Hash Artifact + Timestamp for Last plan date return true } @@ -171,7 +171,7 @@ type TerraformApplyUpToDateCondition struct { Status metav1.Condition } -func (c *TerraformApplyUpToDateCondition) Evaluate(cache *Cache, t *configv1alpha1.TerraformLayer) bool { +func (c *TerraformApplyUpToDateCondition) Evaluate(cache Cache, t *configv1alpha1.TerraformLayer) bool { //TODO: Compute key : Path + Repository / Value: Hash Artifact //TODO: Compare hash artifact values (Plan vs Apply) return true @@ -182,7 +182,9 @@ type TerraformFailureCondition struct { Status metav1.Condition } -func (c *TerraformFailureCondition) Evaluate(cache *Cache, t *configv1alpha1.TerraformLayer) bool { +func (c *TerraformFailureCondition) Evaluate(cache Cache, t *configv1alpha1.TerraformLayer) bool { + key := "run-result-" + computeHash(t.Spec.Path, t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Branch) + value, err := cache.Get(key) //TODO: Compute key: Path + Repository + Branch / Value: bool return true } From 30d2d169182f6b68fb1a61c617aeb468b9ee4751 Mon Sep 17 00:00:00 2001 From: spoukke Date: Thu, 24 Nov 2022 17:53:10 +0100 Subject: [PATCH 05/42] feat: add evaluate for isTerraformRunning and isPlanArtifactUpToDDate --- controllers/terraformlayer_controller.go | 51 +++++++++++++++++++++--- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/controllers/terraformlayer_controller.go b/controllers/terraformlayer_controller.go index 3a9e1adc..a5c494cf 100644 --- a/controllers/terraformlayer_controller.go +++ b/controllers/terraformlayer_controller.go @@ -18,6 +18,7 @@ package controllers import ( "context" + "encoding/binary" "fmt" "hash/fnv" "strings" @@ -105,11 +106,11 @@ func (t *TerraformLayerConditions) Evaluate() (func() ctrl.Result, []metav1.Cond switch { case isTerraformRunning: return func() ctrl.Result { - return ctrl.Result{RequeueAfter: time.Minute * time.Duration(2)} + return ctrl.Result{RequeueAfter: time.Minute * 2} }, conditions case !isTerraformRunning && isPlanArtifactUpToDate && isApplyUpToDate: return func() ctrl.Result { - return ctrl.Result{RequeueAfter: time.Minute * time.Duration(20)} + return ctrl.Result{RequeueAfter: time.Minute * 20} }, conditions case !isTerraformRunning && isPlanArtifactUpToDate && !isApplyUpToDate && hasTerraformFailed: return func() ctrl.Result { @@ -120,7 +121,7 @@ func (t *TerraformLayerConditions) Evaluate() (func() ctrl.Result, []metav1.Cond case !isTerraformRunning && isPlanArtifactUpToDate && !isApplyUpToDate && !hasTerraformFailed: return func() ctrl.Result { //TODO: Launch Apply - return ctrl.Result{RequeueAfter: time.Minute * time.Duration(20)} + return ctrl.Result{RequeueAfter: time.Minute * 20} }, conditions case !isTerraformRunning && !isPlanArtifactUpToDate && hasTerraformFailed: return func() ctrl.Result { @@ -131,7 +132,7 @@ func (t *TerraformLayerConditions) Evaluate() (func() ctrl.Result, []metav1.Cond case !isTerraformRunning && !isPlanArtifactUpToDate && !hasTerraformFailed: return func() ctrl.Result { //TODO: Launch Plan - return ctrl.Result{RequeueAfter: time.Minute * time.Duration(20)} + return ctrl.Result{RequeueAfter: time.Minute * 20} }, conditions default: return func() ctrl.Result { @@ -154,7 +155,21 @@ type TerraformRunningCondition struct { } func (c *TerraformRunningCondition) Evaluate(cache Cache, t *configv1alpha1.TerraformLayer) bool { - //TODO: Compute key : Path + Repository + c.Status = metav1.Condition{ + Type: TerraformFailure, + ObservedGeneration: t.GetObjectMeta().GetGeneration(), + } + key := "lock-" + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path) + _, err := cache.Get(key) + if err != nil { + c.Status.Reason = "NoLockInCache" + c.Status.Message = "No lock has been found in Cache. Terraform is not running on this layer." + c.Status.Status = metav1.ConditionFalse + return false + } + c.Status.Reason = "LockInCache" + c.Status.Message = "Lock has been found in Cache. Terraform is already running on this layer." + c.Status.Status = metav1.ConditionTrue return true } @@ -163,7 +178,31 @@ type TerraformPlanArtifactCondition struct { } func (c *TerraformPlanArtifactCondition) Evaluate(cache Cache, t *configv1alpha1.TerraformLayer) bool { - //TODO: Compute key : Path + Repository + Branch / Value: Hash Artifact + Timestamp for Last plan date + c.Status = metav1.Condition{ + Type: TerraformFailure, + ObservedGeneration: t.GetObjectMeta().GetGeneration(), + } + key := "lastPlanDate-" + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch) + value, err := cache.Get(key) + if err != nil { + c.Status.Reason = "NoTimestampInCache" + c.Status.Message = "The last plan date is not in cache." + c.Status.Status = metav1.ConditionFalse + return false + } + unixTimestamp := int64(binary.BigEndian.Uint64(value)) + lastPlanDate := time.Unix(unixTimestamp, 0) + nextPlanDate := lastPlanDate.Add(20 * time.Minute) + now := time.Now() + if nextPlanDate.After(now) { + c.Status.Reason = "PlanIsRecent" + c.Status.Message = "The plan has been made less than 20 minutes ago." + c.Status.Status = metav1.ConditionFalse + return false + } + c.Status.Reason = "PlanIsTooOld" + c.Status.Message = "The plan has been made more than 20 minutes ago." + c.Status.Status = metav1.ConditionTrue return true } From 8645fe2d47518915fc66cca40e50f4e9a14c65ea Mon Sep 17 00:00:00 2001 From: Alan Date: Thu, 24 Nov 2022 17:56:08 +0100 Subject: [PATCH 06/42] feat(conditions): terraformFailure TerraformApplyUpToDate --- controllers/terraformlayer_controller.go | 61 ++++++++++++++++++++---- 1 file changed, 53 insertions(+), 8 deletions(-) diff --git a/controllers/terraformlayer_controller.go b/controllers/terraformlayer_controller.go index a5c494cf..2a385f47 100644 --- a/controllers/terraformlayer_controller.go +++ b/controllers/terraformlayer_controller.go @@ -17,6 +17,7 @@ limitations under the License. package controllers import ( + "bytes" "context" "encoding/binary" "fmt" @@ -211,10 +212,32 @@ type TerraformApplyUpToDateCondition struct { } func (c *TerraformApplyUpToDateCondition) Evaluate(cache Cache, t *configv1alpha1.TerraformLayer) bool { - //TODO: Compute key : Path + Repository / Value: Hash Artifact - //TODO: Compare hash artifact values (Plan vs Apply) - return true - + c.Status = metav1.Condition{ + Type: ApplyUpToDate, + ObservedGeneration: t.GetObjectMeta().GetGeneration(), + Status: metav1.ConditionTrue, + } + status := true + planKey := "last-planned-artifact-" + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch) + applyKey := "last-applied-artifact-" + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path) + planHash, err := cache.Get(planKey) + if err != nil { + c.Status.Reason = "NoPlanYet" + c.Status.Message = "No plan has run yet, Layer might be new" + return status + } + applyHash, err := cache.Get(applyKey) + if err != nil { + c.Status.Reason = "NoApplyHasRan" + c.Status.Message = "Apply has not ran yet but a plan is available, launching apply" + status = false + } + if bytes.Compare(planHash, applyHash) != 0 { + c.Status.Reason = "NewPlanAvailable" + c.Status.Message = "Apply will run." + status = false + } + return status } type TerraformFailureCondition struct { @@ -222,8 +245,30 @@ type TerraformFailureCondition struct { } func (c *TerraformFailureCondition) Evaluate(cache Cache, t *configv1alpha1.TerraformLayer) bool { - key := "run-result-" + computeHash(t.Spec.Path, t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Branch) - value, err := cache.Get(key) - //TODO: Compute key: Path + Repository + Branch / Value: bool - return true + c.Status = metav1.Condition{ + Type: TerraformFailure, + ObservedGeneration: t.GetObjectMeta().GetGeneration(), + Status: metav1.ConditionFalse, + } + status := false + hashKey := computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch) + resultKey := "run-result-" + hashKey + messageKey := "run-message-" + hashKey + result, err := cache.Get(resultKey) + if err != nil { + c.Status.Reason = "NoRunYet" + c.Status.Message = "Terraform has not ran yet" + return status + } + if string(result) == "1" { + c.Status.Status = metav1.ConditionTrue + status = true + } + message, err := cache.Get(messageKey) + if err != nil { + c.Status.Reason = "UnexpectedRunnerFailure" + c.Status.Message = "Terraform runner might have crashed before updating Redis" + } + c.Status.Message = string(message) + return status } From b6852fc70abca283916ccd8aa1f4974b26f9cfcf Mon Sep 17 00:00:00 2001 From: spoukke Date: Thu, 24 Nov 2022 18:01:15 +0100 Subject: [PATCH 07/42] feat: use const prefixes for cahce keys --- controllers/terraformlayer_controller.go | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/controllers/terraformlayer_controller.go b/controllers/terraformlayer_controller.go index 2a385f47..04a4031c 100644 --- a/controllers/terraformlayer_controller.go +++ b/controllers/terraformlayer_controller.go @@ -87,6 +87,13 @@ const ( PlanArtifact = "IsPlanArtifactUpToDate" ApplyUpToDate = "IsApplyUpToDate" TerraformFailure = "HasTerraformFailed" + + PrefixLock = "lock-" + PrefixLastPlanDate = "lastPlandate" + PrefixLastPlannedArtifact = "lastPlannedArtifact-" + PrefixLastAppliedArtifact = "lastApplyArtifact-" + PrefixRunResult = "runResult-" + PrefixRunMessage = "runMessage-" ) type TerraformLayerConditions struct { @@ -160,7 +167,7 @@ func (c *TerraformRunningCondition) Evaluate(cache Cache, t *configv1alpha1.Terr Type: TerraformFailure, ObservedGeneration: t.GetObjectMeta().GetGeneration(), } - key := "lock-" + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path) + key := PrefixLock + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path) _, err := cache.Get(key) if err != nil { c.Status.Reason = "NoLockInCache" @@ -183,7 +190,7 @@ func (c *TerraformPlanArtifactCondition) Evaluate(cache Cache, t *configv1alpha1 Type: TerraformFailure, ObservedGeneration: t.GetObjectMeta().GetGeneration(), } - key := "lastPlanDate-" + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch) + key := PrefixLastPlanDate + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch) value, err := cache.Get(key) if err != nil { c.Status.Reason = "NoTimestampInCache" @@ -218,8 +225,8 @@ func (c *TerraformApplyUpToDateCondition) Evaluate(cache Cache, t *configv1alpha Status: metav1.ConditionTrue, } status := true - planKey := "last-planned-artifact-" + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch) - applyKey := "last-applied-artifact-" + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path) + planKey := PrefixLastPlannedArtifact + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch) + applyKey := PrefixLastAppliedArtifact + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path) planHash, err := cache.Get(planKey) if err != nil { c.Status.Reason = "NoPlanYet" @@ -252,8 +259,8 @@ func (c *TerraformFailureCondition) Evaluate(cache Cache, t *configv1alpha1.Terr } status := false hashKey := computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch) - resultKey := "run-result-" + hashKey - messageKey := "run-message-" + hashKey + resultKey := PrefixRunResult + hashKey + messageKey := PrefixRunMessage + hashKey result, err := cache.Get(resultKey) if err != nil { c.Status.Reason = "NoRunYet" From 026bdaf65b51c18208a0c4f642c9679affbcc184 Mon Sep 17 00:00:00 2001 From: Alan Date: Mon, 5 Dec 2022 10:57:55 +0100 Subject: [PATCH 08/42] chore(tests): add some units tests for conditions --- controllers/conditions_test.go | 143 +++++++++++++++++++++++++++++++++ controllers/suite_test.go | 118 +++++++++++++-------------- go.mod | 20 +++-- go.sum | 41 ++++++++++ 4 files changed, 256 insertions(+), 66 deletions(-) create mode 100644 controllers/conditions_test.go diff --git a/controllers/conditions_test.go b/controllers/conditions_test.go new file mode 100644 index 00000000..c0e602e1 --- /dev/null +++ b/controllers/conditions_test.go @@ -0,0 +1,143 @@ +/* +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 controllers + +import ( + "strconv" + "testing" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + configv1alpha1 "github.com/padok-team/burrito/api/v1alpha1" + + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + //+kubebuilder:scaffold:imports +) + +// These tests use Ginkgo (BDD-style Go testing framework). Refer to +// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. + +func TestConditions(t *testing.T) { + RegisterFailHandler(Fail) + + RunSpecs(t, "Conditions Suite") +} + +var _ = BeforeSuite(func() { + logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) +}) + +var _ = AfterSuite(func() { +}) + +var _ = Describe("TerraformLayer", func() { + var t *configv1alpha1.TerraformLayer + var cache Cache + + BeforeEach(func() { + t = &configv1alpha1.TerraformLayer{ + Spec: configv1alpha1.TerraformLayerSpec{ + Path: "/test", + Branch: "main", + Repository: configv1alpha1.TerraformLayerRepository{ + Name: "test-repository", + Namespace: "default", + }, + }, + } + cache = newMemoryCache() + }) + + Describe("TerraformRunningCondition", func() { + var condition TerraformRunningCondition + BeforeEach(func() { + condition = TerraformRunningCondition{} + }) + Context("with lock in cache", func() { + It("should return true", func() { + cache.Set(PrefixLock+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path), []byte{1}, 0) + Expect(condition.Evaluate(cache, t)).To(Equal(true)) + }) + }) + Context("with lock not in cache", func() { + It("should return false", func() { + Expect(condition.Evaluate(cache, t)).To(Equal(false)) + }) + }) + }) + Describe("TerraformPlanArtifactCondition", func() { + var condition TerraformPlanArtifactCondition + BeforeEach(func() { + condition = TerraformPlanArtifactCondition{} + }) + Context("with no last timestamp in cache", func() { + It("should return false", func() { + Expect(condition.Evaluate(cache, t)).To(Equal(false)) + }) + }) + Context("with last timestamp in cache < 20min", func() { + It("should return true", func() { + cache.Set(PrefixLastPlanDate+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), + []byte(strconv.Itoa(int((time.Now().Add(-5 * time.Minute)).Unix()))), 0) + Expect(condition.Evaluate(cache, t)).To(Equal(true)) + }) + }) + Context("with last timestamp in cache > 20min", func() { + It("should return false", func() { + cache.Set(PrefixLastPlanDate+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), + []byte(strconv.Itoa(int(time.Now().Add(-25*time.Minute).Unix()))), 0) + Expect(condition.Evaluate(cache, t)).To(Equal(false)) + }) + }) + }) + // Describe("TerraformPlanArtifactCondition", func() { + // var runningCondition TerraformRunningCondition + // BeforeEach(func() { + // runningCondition = TerraformRunningCondition{} + // }) + // Context("with lock in cache", func() { + // It("should return true", func() { + // cache.Set(PrefixLock+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path), []byte{1}, 0) + // Expect(runningCondition.Evaluate(cache, t)).To(Equal(true)) + // }) + // }) + // Context("with lock not in cache", func() { + // It("should return false", func() { + // Expect(runningCondition.Evaluate(cache, t)).To(Equal(false)) + // }) + // }) + // }) + // Describe("TerraformPlanArtifactCondition", func() { + // var runningCondition TerraformRunningCondition + // BeforeEach(func() { + // runningCondition = TerraformRunningCondition{} + // }) + // Context("with lock in cache", func() { + // It("should return true", func() { + // cache.Set(PrefixLock+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path), []byte{1}, 0) + // Expect(runningCondition.Evaluate(cache, t)).To(Equal(true)) + // }) + // }) + // Context("with lock not in cache", func() { + // It("should return false", func() { + // Expect(runningCondition.Evaluate(cache, t)).To(Equal(false)) + // }) + // }) + // }) +}) diff --git a/controllers/suite_test.go b/controllers/suite_test.go index e6141da2..9639edf5 100644 --- a/controllers/suite_test.go +++ b/controllers/suite_test.go @@ -1,80 +1,80 @@ -/* -Copyright 2022. +// /* +// 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 +// 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 +// 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. -*/ +// 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 controllers -import ( - "path/filepath" - "testing" +// import ( +// "path/filepath" +// "testing" - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" +// . "github.com/onsi/ginkgo/v2" +// . "github.com/onsi/gomega" - "k8s.io/client-go/kubernetes/scheme" - "k8s.io/client-go/rest" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/envtest" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/log/zap" +// "k8s.io/client-go/kubernetes/scheme" +// "k8s.io/client-go/rest" +// "sigs.k8s.io/controller-runtime/pkg/client" +// "sigs.k8s.io/controller-runtime/pkg/envtest" +// logf "sigs.k8s.io/controller-runtime/pkg/log" +// "sigs.k8s.io/controller-runtime/pkg/log/zap" - configv1alpha1 "github.com/padok-team/burrito/api/v1alpha1" - //+kubebuilder:scaffold:imports -) +// configv1alpha1 "github.com/padok-team/burrito/api/v1alpha1" +// //+kubebuilder:scaffold:imports +// ) -// These tests use Ginkgo (BDD-style Go testing framework). Refer to -// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. +// // These tests use Ginkgo (BDD-style Go testing framework). Refer to +// // http://onsi.github.io/ginkgo/ to learn more about Ginkgo. -var cfg *rest.Config -var k8sClient client.Client -var testEnv *envtest.Environment +// var cfg *rest.Config +// var k8sClient client.Client +// var testEnv *envtest.Environment -func TestAPIs(t *testing.T) { - RegisterFailHandler(Fail) +// func TestAPIs(t *testing.T) { +// RegisterFailHandler(Fail) - RunSpecs(t, "Controller Suite") -} +// RunSpecs(t, "Controller Suite") +// } -var _ = BeforeSuite(func() { - logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) +// var _ = BeforeSuite(func() { +// logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) - By("bootstrapping test environment") - testEnv = &envtest.Environment{ - CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")}, - ErrorIfCRDPathMissing: true, - } +// By("bootstrapping test environment") +// testEnv = &envtest.Environment{ +// CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")}, +// ErrorIfCRDPathMissing: true, +// } - var err error - // cfg is defined in this file globally. - cfg, err = testEnv.Start() - Expect(err).NotTo(HaveOccurred()) - Expect(cfg).NotTo(BeNil()) +// var err error +// // cfg is defined in this file globally. +// cfg, err = testEnv.Start() +// Expect(err).NotTo(HaveOccurred()) +// Expect(cfg).NotTo(BeNil()) - err = configv1alpha1.AddToScheme(scheme.Scheme) - Expect(err).NotTo(HaveOccurred()) +// err = configv1alpha1.AddToScheme(scheme.Scheme) +// Expect(err).NotTo(HaveOccurred()) - //+kubebuilder:scaffold:scheme +// //+kubebuilder:scaffold:scheme - k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) - Expect(err).NotTo(HaveOccurred()) - Expect(k8sClient).NotTo(BeNil()) +// k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) +// Expect(err).NotTo(HaveOccurred()) +// Expect(k8sClient).NotTo(BeNil()) -}) +// }) -var _ = AfterSuite(func() { - By("tearing down the test environment") - err := testEnv.Stop() - Expect(err).NotTo(HaveOccurred()) -}) +// var _ = AfterSuite(func() { +// By("tearing down the test environment") +// err := testEnv.Stop() +// Expect(err).NotTo(HaveOccurred()) +// }) diff --git a/go.mod b/go.mod index 30fc449d..d705fd78 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module github.com/padok-team/burrito go 1.19 require ( - github.com/onsi/ginkgo/v2 v2.1.4 - github.com/onsi/gomega v1.19.0 + github.com/onsi/ginkgo/v2 v2.5.0 + github.com/onsi/gomega v1.24.1 k8s.io/apimachinery v0.25.0 k8s.io/client-go v0.25.0 sigs.k8s.io/controller-runtime v0.13.0 @@ -31,13 +31,15 @@ require ( github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/jsonreference v0.19.5 // indirect github.com/go-openapi/swag v0.19.14 // indirect + github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.2.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/google/gnostic v0.5.7-v3refs // indirect - github.com/google/go-cmp v0.5.8 // indirect + github.com/google/go-cmp v0.5.9 // indirect github.com/google/gofuzz v1.1.0 // indirect + github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect github.com/google/uuid v1.1.2 // indirect github.com/imdario/mergo v0.3.12 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -47,6 +49,8 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/nxadm/tail v1.4.8 // indirect + github.com/onsi/ginkgo v1.16.5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.12.2 // indirect github.com/prometheus/client_model v0.2.0 // indirect @@ -57,16 +61,18 @@ require ( go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.21.0 // indirect golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd // indirect - golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect + golang.org/x/net v0.2.0 // indirect golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect - golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect - golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect - golang.org/x/text v0.3.7 // indirect + golang.org/x/sys v0.2.0 // indirect + golang.org/x/term v0.2.0 // indirect + golang.org/x/text v0.4.0 // indirect golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect + golang.org/x/tools v0.2.0 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.28.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/api v0.25.0 // indirect diff --git a/go.sum b/go.sum index d51d4677..145e5d04 100644 --- a/go.sum +++ b/go.sum @@ -111,6 +111,8 @@ github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMi github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -139,6 +141,8 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= @@ -197,6 +201,8 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -217,6 +223,7 @@ github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= @@ -227,6 +234,7 @@ github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pf github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= @@ -275,12 +283,23 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY= github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= +github.com/onsi/ginkgo/v2 v2.5.0 h1:TRtrvv2vdQqzkwrQ1ke6vtXf7IK34RBUJafIy1wMwls= +github.com/onsi/ginkgo/v2 v2.5.0/go.mod h1:Luc4sArBICYCS8THh8v3i3i5CuSZO+RaQRaJoeNwomw= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= +github.com/onsi/gomega v1.24.1 h1:KORJXNNTzJXzu4ScJWssJfJMnJ+2QJqhoQSRwNlze9E= +github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -398,6 +417,7 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -421,6 +441,7 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= @@ -438,6 +459,8 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -468,6 +491,7 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -478,7 +502,10 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -502,6 +529,7 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -524,9 +552,13 @@ golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -537,6 +569,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -588,6 +622,7 @@ golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82u golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= @@ -596,6 +631,10 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -742,9 +781,11 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= From f19aaf494989b5b0c1d0038e3369c926d7b5083a Mon Sep 17 00:00:00 2001 From: spoukke Date: Mon, 5 Dec 2022 12:13:06 +0100 Subject: [PATCH 09/42] build: generate deepcopy and manifests --- api/v1alpha1/zz_generated.deepcopy.go | 45 +- ...terraform.padok.cloud_terraformlayers.yaml | 7321 +++++++++++++++++ ...orm.padok.cloud_terraformrepositories.yaml | 51 + config/rbac/role.yaml | 59 + 4 files changed, 7474 insertions(+), 2 deletions(-) create mode 100644 config/crd/bases/config.terraform.padok.cloud_terraformlayers.yaml create mode 100644 config/crd/bases/config.terraform.padok.cloud_terraformrepositories.yaml create mode 100644 config/rbac/role.yaml diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 2afb8bfb..83254a73 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -22,6 +22,7 @@ limitations under the License. package v1alpha1 import ( + "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -30,8 +31,8 @@ func (in *TerraformLayer) DeepCopyInto(out *TerraformLayer) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec - out.Status = in.Status + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TerraformLayer. @@ -84,9 +85,42 @@ func (in *TerraformLayerList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TerraformLayerRemediationStrategy) DeepCopyInto(out *TerraformLayerRemediationStrategy) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TerraformLayerRemediationStrategy. +func (in *TerraformLayerRemediationStrategy) DeepCopy() *TerraformLayerRemediationStrategy { + if in == nil { + return nil + } + out := new(TerraformLayerRemediationStrategy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TerraformLayerRepository) DeepCopyInto(out *TerraformLayerRepository) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TerraformLayerRepository. +func (in *TerraformLayerRepository) DeepCopy() *TerraformLayerRepository { + if in == nil { + return nil + } + out := new(TerraformLayerRepository) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TerraformLayerSpec) DeepCopyInto(out *TerraformLayerSpec) { *out = *in + out.Repository = in.Repository + out.RemediationStrategy = in.RemediationStrategy + in.RunnerPodTemplate.DeepCopyInto(&out.RunnerPodTemplate) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TerraformLayerSpec. @@ -102,6 +136,13 @@ func (in *TerraformLayerSpec) DeepCopy() *TerraformLayerSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TerraformLayerStatus) DeepCopyInto(out *TerraformLayerStatus) { *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TerraformLayerStatus. diff --git a/config/crd/bases/config.terraform.padok.cloud_terraformlayers.yaml b/config/crd/bases/config.terraform.padok.cloud_terraformlayers.yaml new file mode 100644 index 00000000..d5403a2b --- /dev/null +++ b/config/crd/bases/config.terraform.padok.cloud_terraformlayers.yaml @@ -0,0 +1,7321 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.10.0 + creationTimestamp: null + name: terraformlayers.config.terraform.padok.cloud +spec: + group: config.terraform.padok.cloud + names: + kind: TerraformLayer + listKind: TerraformLayerList + plural: terraformlayers + singular: terraformlayer + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: TerraformLayer is the Schema for the terraformlayers API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: TerraformLayerSpec defines the desired state of TerraformLayer + properties: + branch: + type: string + path: + type: string + planOnPullRequest: + type: boolean + remediationStrategy: + properties: + applyOnDrift: + type: boolean + applyOnPush: + type: boolean + planOnDrift: + type: boolean + type: object + repository: + properties: + kind: + type: string + name: + type: string + namespace: + type: string + type: object + template: + description: PodTemplateSpec describes the data a pod should have + when created from a template + properties: + metadata: + description: 'Standard object''s metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata' + type: object + spec: + description: 'Specification of the desired behavior of the pod. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status' + properties: + activeDeadlineSeconds: + description: Optional duration in seconds the pod may be active + on the node relative to StartTime before the system will + actively try to mark it failed and kill associated containers. + Value must be a positive integer. + format: int64 + type: integer + affinity: + description: If specified, the pod's scheduling constraints + properties: + nodeAffinity: + description: Describes node affinity scheduling rules + for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule + pods to nodes that satisfy the affinity expressions + specified by this field, but it may choose a node + that violates one or more of the expressions. The + node that is most preferred is the one with the + greatest sum of weights, i.e. for each node that + meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, + etc.), compute a sum by iterating through the elements + of this field and adding "weight" to the sum if + the node matches the corresponding matchExpressions; + the node(s) with the highest sum are the most preferred. + items: + description: An empty preferred scheduling term + matches all objects with implicit weight 0 (i.e. + it's a no-op). A null preferred scheduling term + matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated + with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: A node selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: Represents a key's relationship + to a set of values. Valid operators + are In, NotIn, Exists, DoesNotExist. + Gt, and Lt. + type: string + values: + description: An array of string values. + If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. + If the operator is Gt or Lt, the + values array must have a single + element, which will be interpreted + as an integer. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: A node selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: Represents a key's relationship + to a set of values. Valid operators + are In, NotIn, Exists, DoesNotExist. + Gt, and Lt. + type: string + values: + description: An array of string values. + If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. + If the operator is Gt or Lt, the + values array must have a single + element, which will be interpreted + as an integer. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching + the corresponding nodeSelectorTerm, in the + range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified + by this field are not met at scheduling time, the + pod will not be scheduled onto the node. If the + affinity requirements specified by this field cease + to be met at some point during pod execution (e.g. + due to an update), the system may or may not try + to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector + terms. The terms are ORed. + items: + description: A null or empty node selector term + matches no objects. The requirements of them + are ANDed. The TopologySelectorTerm type implements + a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: A node selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: Represents a key's relationship + to a set of values. Valid operators + are In, NotIn, Exists, DoesNotExist. + Gt, and Lt. + type: string + values: + description: An array of string values. + If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. + If the operator is Gt or Lt, the + values array must have a single + element, which will be interpreted + as an integer. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: A node selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: Represents a key's relationship + to a set of values. Valid operators + are In, NotIn, Exists, DoesNotExist. + Gt, and Lt. + type: string + values: + description: An array of string values. + If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. + If the operator is Gt or Lt, the + values array must have a single + element, which will be interpreted + as an integer. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + x-kubernetes-map-type: atomic + type: array + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. + co-locate this pod in the same node, zone, etc. as some + other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule + pods to nodes that satisfy the affinity expressions + specified by this field, but it may choose a node + that violates one or more of the expressions. The + node that is most preferred is the one with the + greatest sum of weights, i.e. for each node that + meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, + etc.), compute a sum by iterating through the elements + of this field and adding "weight" to the sum if + the node has pods which matches the corresponding + podAffinityTerm; the node(s) with the highest sum + are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. + properties: + labelSelector: + description: A label query over a set of + resources, in this case pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: operator represents + a key's relationship to a set + of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array + of string values. If the operator + is In or NotIn, the values array + must be non-empty. If the operator + is Exists or DoesNotExist, the + values array must be empty. + This array is replaced during + a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of + {key,value} pairs. A single {key,value} + in the matchLabels map is equivalent + to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are + ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaceSelector: + description: A label query over the set + of namespaces that the term applies to. + The term is applied to the union of the + namespaces selected by this field and + the ones listed in the namespaces field. + null selector and null or empty namespaces + list means "this pod's namespace". An + empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: operator represents + a key's relationship to a set + of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array + of string values. If the operator + is In or NotIn, the values array + must be non-empty. If the operator + is Exists or DoesNotExist, the + values array must be empty. + This array is replaced during + a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of + {key,value} pairs. A single {key,value} + in the matchLabels map is equivalent + to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are + ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies a static + list of namespace names that the term + applies to. The term is applied to the + union of the namespaces listed in this + field and the ones selected by namespaceSelector. + null or empty namespaces list and null + namespaceSelector means "this pod's namespace". + items: + type: string + type: array + topologyKey: + description: This pod should be co-located + (affinity) or not co-located (anti-affinity) + with the pods matching the labelSelector + in the specified namespaces, where co-located + is defined as running on a node whose + value of the label with key topologyKey + matches that of any node on which any + of the selected pods is running. Empty + topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: weight associated with matching + the corresponding podAffinityTerm, in the + range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified + by this field are not met at scheduling time, the + pod will not be scheduled onto the node. If the + affinity requirements specified by this field cease + to be met at some point during pod execution (e.g. + due to a pod label update), the system may or may + not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes + corresponding to each podAffinityTerm are intersected, + i.e. all terms must be satisfied. + items: + description: Defines a set of pods (namely those + matching the labelSelector relative to the given + namespace(s)) that this pod should be co-located + (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node + whose value of the label with key + matches that of any node on which a pod of the + set of pods is running + properties: + labelSelector: + description: A label query over a set of resources, + in this case pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaceSelector: + description: A label query over the set of namespaces + that the term applies to. The term is applied + to the union of the namespaces selected by + this field and the ones listed in the namespaces + field. null selector and null or empty namespaces + list means "this pod's namespace". An empty + selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies a static list + of namespace names that the term applies to. + The term is applied to the union of the namespaces + listed in this field and the ones selected + by namespaceSelector. null or empty namespaces + list and null namespaceSelector means "this + pod's namespace". + items: + type: string + type: array + topologyKey: + description: This pod should be co-located (affinity) + or not co-located (anti-affinity) with the + pods matching the labelSelector in the specified + namespaces, where co-located is defined as + running on a node whose value of the label + with key topologyKey matches that of any node + on which any of the selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules + (e.g. avoid putting this pod in the same node, zone, + etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule + pods to nodes that satisfy the anti-affinity expressions + specified by this field, but it may choose a node + that violates one or more of the expressions. The + node that is most preferred is the one with the + greatest sum of weights, i.e. for each node that + meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity + expressions, etc.), compute a sum by iterating through + the elements of this field and adding "weight" to + the sum if the node has pods which matches the corresponding + podAffinityTerm; the node(s) with the highest sum + are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. + properties: + labelSelector: + description: A label query over a set of + resources, in this case pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: operator represents + a key's relationship to a set + of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array + of string values. If the operator + is In or NotIn, the values array + must be non-empty. If the operator + is Exists or DoesNotExist, the + values array must be empty. + This array is replaced during + a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of + {key,value} pairs. A single {key,value} + in the matchLabels map is equivalent + to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are + ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaceSelector: + description: A label query over the set + of namespaces that the term applies to. + The term is applied to the union of the + namespaces selected by this field and + the ones listed in the namespaces field. + null selector and null or empty namespaces + list means "this pod's namespace". An + empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: operator represents + a key's relationship to a set + of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array + of string values. If the operator + is In or NotIn, the values array + must be non-empty. If the operator + is Exists or DoesNotExist, the + values array must be empty. + This array is replaced during + a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of + {key,value} pairs. A single {key,value} + in the matchLabels map is equivalent + to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are + ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies a static + list of namespace names that the term + applies to. The term is applied to the + union of the namespaces listed in this + field and the ones selected by namespaceSelector. + null or empty namespaces list and null + namespaceSelector means "this pod's namespace". + items: + type: string + type: array + topologyKey: + description: This pod should be co-located + (affinity) or not co-located (anti-affinity) + with the pods matching the labelSelector + in the specified namespaces, where co-located + is defined as running on a node whose + value of the label with key topologyKey + matches that of any node on which any + of the selected pods is running. Empty + topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: weight associated with matching + the corresponding podAffinityTerm, in the + range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the anti-affinity requirements specified + by this field are not met at scheduling time, the + pod will not be scheduled onto the node. If the + anti-affinity requirements specified by this field + cease to be met at some point during pod execution + (e.g. due to a pod label update), the system may + or may not try to eventually evict the pod from + its node. When there are multiple elements, the + lists of nodes corresponding to each podAffinityTerm + are intersected, i.e. all terms must be satisfied. + items: + description: Defines a set of pods (namely those + matching the labelSelector relative to the given + namespace(s)) that this pod should be co-located + (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node + whose value of the label with key + matches that of any node on which a pod of the + set of pods is running + properties: + labelSelector: + description: A label query over a set of resources, + in this case pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaceSelector: + description: A label query over the set of namespaces + that the term applies to. The term is applied + to the union of the namespaces selected by + this field and the ones listed in the namespaces + field. null selector and null or empty namespaces + list means "this pod's namespace". An empty + selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies a static list + of namespace names that the term applies to. + The term is applied to the union of the namespaces + listed in this field and the ones selected + by namespaceSelector. null or empty namespaces + list and null namespaceSelector means "this + pod's namespace". + items: + type: string + type: array + topologyKey: + description: This pod should be co-located (affinity) + or not co-located (anti-affinity) with the + pods matching the labelSelector in the specified + namespaces, where co-located is defined as + running on a node whose value of the label + with key topologyKey matches that of any node + on which any of the selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + type: object + type: object + automountServiceAccountToken: + description: AutomountServiceAccountToken indicates whether + a service account token should be automatically mounted. + type: boolean + containers: + description: List of containers belonging to the pod. Containers + cannot currently be added or removed. There must be at least + one container in a Pod. Cannot be updated. + items: + description: A single application container that you want + to run within a pod. + properties: + args: + description: 'Arguments to the entrypoint. The container + image''s CMD is used if this is not provided. Variable + references $(VAR_NAME) are expanded using the container''s + environment. If a variable cannot be resolved, the + reference in the input string will be unchanged. Double + $$ are reduced to a single $, which allows for escaping + the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce + the string literal "$(VAR_NAME)". Escaped references + will never be expanded, regardless of whether the + variable exists or not. Cannot be updated. More info: + https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + command: + description: 'Entrypoint array. Not executed within + a shell. The container image''s ENTRYPOINT is used + if this is not provided. Variable references $(VAR_NAME) + are expanded using the container''s environment. If + a variable cannot be resolved, the reference in the + input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) + syntax: i.e. "$$(VAR_NAME)" will produce the string + literal "$(VAR_NAME)". Escaped references will never + be expanded, regardless of whether the variable exists + or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + env: + description: List of environment variables to set in + the container. Cannot be updated. + items: + description: EnvVar represents an environment variable + present in a Container. + properties: + name: + description: Name of the environment variable. + Must be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) + are expanded using the previously defined environment + variables in the container and any service environment + variables. If a variable cannot be resolved, + the reference in the input string will be unchanged. + Double $$ are reduced to a single $, which allows + for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" + will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless + of whether the variable exists or not. Defaults + to "".' + type: string + valueFrom: + description: Source for the environment variable's + value. Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Selects a field of the pod: + supports metadata.name, metadata.namespace, + `metadata.labels['''']`, `metadata.annotations['''']`, + spec.nodeName, spec.serviceAccountName, + status.hostIP, status.podIP, status.podIPs.' + properties: + apiVersion: + description: Version of the schema the + FieldPath is written in terms of, defaults + to "v1". + type: string + fieldPath: + description: Path of the field to select + in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of the container: + only resources limits and requests (limits.cpu, + limits.memory, limits.ephemeral-storage, + requests.cpu, requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: required + for volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format + of the exposed resources, defaults to + "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in + the pod's namespace + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + description: List of sources to populate environment + variables in the container. The keys defined within + a source must be a C_IDENTIFIER. All invalid keys + will be reported as an event when the container is + starting. When a key exists in multiple sources, the + value associated with the last source will take precedence. + Values defined by an Env with a duplicate key will + take precedence. Cannot be updated. + items: + description: EnvFromSource represents the source of + a set of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to prepend + to each key in the ConfigMap. Must be a C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + image: + description: 'Container image name. More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config + management to default or override container images + in workload controllers like Deployments and StatefulSets.' + type: string + imagePullPolicy: + description: 'Image pull policy. One of Always, Never, + IfNotPresent. Defaults to Always if :latest tag is + specified, or IfNotPresent otherwise. Cannot be updated. + More info: https://kubernetes.io/docs/concepts/containers/images#updating-images' + type: string + lifecycle: + description: Actions that the management system should + take in response to container lifecycle events. Cannot + be updated. + properties: + postStart: + description: 'PostStart is called immediately after + a container is created. If the handler fails, + the container is terminated and restarted according + to its restart policy. Other management of the + container blocks until the hook completes. More + info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line + to execute inside the container, the working + directory for the command is root ('/') + in the container's filesystem. The command + is simply exec'd, it is not run inside + a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, + you need to explicitly call out to that + shell. Exit status of 0 is treated as + live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT supported + as a LifecycleHandler and kept for the backward + compatibility. There are no validation of + this field and lifecycle hooks will fail in + runtime when tcp handler is specified. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + description: 'PreStop is called immediately before + a container is terminated due to an API request + or management event such as liveness/startup probe + failure, preemption, resource contention, etc. + The handler is not called if the container crashes + or exits. The Pod''s termination grace period + countdown begins before the PreStop hook is executed. + Regardless of the outcome of the handler, the + container will eventually terminate within the + Pod''s termination grace period (unless delayed + by finalizers). Other management of the container + blocks until the hook completes or until the termination + grace period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line + to execute inside the container, the working + directory for the command is root ('/') + in the container's filesystem. The command + is simply exec'd, it is not run inside + a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, + you need to explicitly call out to that + shell. Exit status of 0 is treated as + live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT supported + as a LifecycleHandler and kept for the backward + compatibility. There are no validation of + this field and lifecycle hooks will fail in + runtime when tcp handler is specified. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + description: 'Periodic probe of container liveness. + Container will be restarted if the probe fails. Cannot + be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to + execute inside the container, the working + directory for the command is root ('/') in + the container's filesystem. The command is + simply exec'd, it is not run inside a shell, + so traditional shell instructions ('|', etc) + won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is + treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the + probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. This is a beta field and requires + enabling GRPCContainerProbe feature gate. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service + to place in the gRPC HealthCheckRequest (see + https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set "Host" + in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to + the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the + probe. Default to 10 seconds. Minimum value is + 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the + probe to be considered successful after having + failed. Defaults to 1. Must be 1 for liveness + and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod + needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after + the processes running in the pod are sent a termination + signal and the time when the processes are forcibly + halted with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value must + be non-negative integer. The value zero indicates + stop immediately via the kill signal (no opportunity + to shut down). This is a beta field and requires + enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the + probe times out. Defaults to 1 second. Minimum + value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + name: + description: Name of the container specified as a DNS_LABEL. + Each container in a pod must have a unique name (DNS_LABEL). + Cannot be updated. + type: string + ports: + description: List of ports to expose from the container. + Not specifying a port here DOES NOT prevent that port + from being exposed. Any port which is listening on + the default "0.0.0.0" address inside a container will + be accessible from the network. Modifying this array + with strategic merge patch may corrupt the data. For + more information See https://github.com/kubernetes/kubernetes/issues/108255. + Cannot be updated. + items: + description: ContainerPort represents a network port + in a single container. + properties: + containerPort: + description: Number of port to expose on the pod's + IP address. This must be a valid port number, + 0 < x < 65536. + format: int32 + type: integer + hostIP: + description: What host IP to bind the external + port to. + type: string + hostPort: + description: Number of port to expose on the host. + If specified, this must be a valid port number, + 0 < x < 65536. If HostNetwork is specified, + this must match ContainerPort. Most containers + do not need this. + format: int32 + type: integer + name: + description: If specified, this must be an IANA_SVC_NAME + and unique within the pod. Each named port in + a pod must have a unique name. Name for the + port that can be referred to by services. + type: string + protocol: + default: TCP + description: Protocol for port. Must be UDP, TCP, + or SCTP. Defaults to "TCP". + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: 'Periodic probe of container service readiness. + Container will be removed from service endpoints if + the probe fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to + execute inside the container, the working + directory for the command is root ('/') in + the container's filesystem. The command is + simply exec'd, it is not run inside a shell, + so traditional shell instructions ('|', etc) + won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is + treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the + probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. This is a beta field and requires + enabling GRPCContainerProbe feature gate. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service + to place in the gRPC HealthCheckRequest (see + https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set "Host" + in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to + the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the + probe. Default to 10 seconds. Minimum value is + 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the + probe to be considered successful after having + failed. Defaults to 1. Must be 1 for liveness + and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod + needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after + the processes running in the pod are sent a termination + signal and the time when the processes are forcibly + halted with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value must + be non-negative integer. The value zero indicates + stop immediately via the kill signal (no opportunity + to shut down). This is a beta field and requires + enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the + probe times out. Defaults to 1 second. Minimum + value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + resources: + description: 'Compute Resources required by this container. + Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount + of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount + of compute resources required. If Requests is + omitted for a container, it defaults to Limits + if that is explicitly specified, otherwise to + an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + securityContext: + description: 'SecurityContext defines the security options + the container should be run with. If set, the fields + of SecurityContext override the equivalent fields + of PodSecurityContext. More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/' + properties: + allowPrivilegeEscalation: + description: 'AllowPrivilegeEscalation controls + whether a process can gain more privileges than + its parent process. This bool directly controls + if the no_new_privs flag will be set on the container + process. AllowPrivilegeEscalation is true always + when the container is: 1) run as Privileged 2) + has CAP_SYS_ADMIN Note that this field cannot + be set when spec.os.name is windows.' + type: boolean + capabilities: + description: The capabilities to add/drop when running + containers. Defaults to the default set of capabilities + granted by the container runtime. Note that this + field cannot be set when spec.os.name is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + type: object + privileged: + description: Run container in privileged mode. Processes + in privileged containers are essentially equivalent + to root on the host. Defaults to false. Note that + this field cannot be set when spec.os.name is + windows. + type: boolean + procMount: + description: procMount denotes the type of proc + mount to use for the containers. The default is + DefaultProcMount which uses the container runtime + defaults for readonly paths and masked paths. + This requires the ProcMountType feature flag to + be enabled. Note that this field cannot be set + when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: Whether this container has a read-only + root filesystem. Default is false. Note that this + field cannot be set when spec.os.name is windows. + type: boolean + runAsGroup: + description: The GID to run the entrypoint of the + container process. Uses runtime default if unset. + May also be set in PodSecurityContext. If set + in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name + is windows. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container must run + as a non-root user. If true, the Kubelet will + validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start + the container if it does. If unset or false, no + such validation will be performed. May also be + set in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in + SecurityContext takes precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of the + container process. Defaults to user specified + in image metadata if unspecified. May also be + set in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in + SecurityContext takes precedence. Note that this + field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied to + the container. If unspecified, the container runtime + will allocate a random SELinux context for each + container. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name + is windows. + properties: + level: + description: Level is SELinux level label that + applies to the container. + type: string + role: + description: Role is a SELinux role label that + applies to the container. + type: string + type: + description: Type is a SELinux type label that + applies to the container. + type: string + user: + description: User is a SELinux user label that + applies to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by this + container. If seccomp options are provided at + both the pod & container level, the container + options override the pod options. Note that this + field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: localhostProfile indicates a profile + defined in a file on the node should be used. + The profile must be preconfigured on the node + to work. Must be a descending path, relative + to the kubelet's configured seccomp profile + location. Must only be set if type is "Localhost". + type: string + type: + description: "type indicates which kind of seccomp + profile will be applied. Valid options are: + \n Localhost - a profile defined in a file + on the node should be used. RuntimeDefault + - the container runtime default profile should + be used. Unconfined - no profile should be + applied." + type: string + required: + - type + type: object + windowsOptions: + description: The Windows specific settings applied + to all containers. If unspecified, the options + from the PodSecurityContext will be used. If set + in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name + is linux. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where the + GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential + spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name + of the GMSA credential spec to use. + type: string + hostProcess: + description: HostProcess determines if a container + should be run as a 'Host Process' container. + This field is alpha-level and will only be + honored by components that enable the WindowsHostProcessContainers + feature flag. Setting this field without the + feature flag will result in errors when validating + the Pod. All of a Pod's containers must have + the same effective HostProcess value (it is + not allowed to have a mix of HostProcess containers + and non-HostProcess containers). In addition, + if HostProcess is true then HostNetwork must + also be set to true. + type: boolean + runAsUserName: + description: The UserName in Windows to run + the entrypoint of the container process. Defaults + to the user specified in image metadata if + unspecified. May also be set in PodSecurityContext. + If set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. + type: string + type: object + type: object + startupProbe: + description: 'StartupProbe indicates that the Pod has + successfully initialized. If specified, no other probes + are executed until this completes successfully. If + this probe fails, the Pod will be restarted, just + as if the livenessProbe failed. This can be used to + provide different probe parameters at the beginning + of a Pod''s lifecycle, when it might take a long time + to load data or warm a cache, than during steady-state + operation. This cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to + execute inside the container, the working + directory for the command is root ('/') in + the container's filesystem. The command is + simply exec'd, it is not run inside a shell, + so traditional shell instructions ('|', etc) + won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is + treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the + probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. This is a beta field and requires + enabling GRPCContainerProbe feature gate. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service + to place in the gRPC HealthCheckRequest (see + https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set "Host" + in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to + the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the + probe. Default to 10 seconds. Minimum value is + 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the + probe to be considered successful after having + failed. Defaults to 1. Must be 1 for liveness + and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod + needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after + the processes running in the pod are sent a termination + signal and the time when the processes are forcibly + halted with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value must + be non-negative integer. The value zero indicates + stop immediately via the kill signal (no opportunity + to shut down). This is a beta field and requires + enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the + probe times out. Defaults to 1 second. Minimum + value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + stdin: + description: Whether this container should allocate + a buffer for stdin in the container runtime. If this + is not set, reads from stdin in the container will + always result in EOF. Default is false. + type: boolean + stdinOnce: + description: Whether the container runtime should close + the stdin channel after it has been opened by a single + attach. When stdin is true the stdin stream will remain + open across multiple attach sessions. If stdinOnce + is set to true, stdin is opened on container start, + is empty until the first client attaches to stdin, + and then remains open and accepts data until the client + disconnects, at which time stdin is closed and remains + closed until the container is restarted. If this flag + is false, a container processes that reads from stdin + will never receive an EOF. Default is false + type: boolean + terminationMessagePath: + description: 'Optional: Path at which the file to which + the container''s termination message will be written + is mounted into the container''s filesystem. Message + written is intended to be brief final status, such + as an assertion failure message. Will be truncated + by the node if greater than 4096 bytes. The total + message length across all containers will be limited + to 12kb. Defaults to /dev/termination-log. Cannot + be updated.' + type: string + terminationMessagePolicy: + description: Indicate how the termination message should + be populated. File will use the contents of terminationMessagePath + to populate the container status message on both success + and failure. FallbackToLogsOnError will use the last + chunk of container log output if the termination message + file is empty and the container exited with an error. + The log output is limited to 2048 bytes or 80 lines, + whichever is smaller. Defaults to File. Cannot be + updated. + type: string + tty: + description: Whether this container should allocate + a TTY for itself, also requires 'stdin' to be true. + Default is false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block devices + to be used by the container. + items: + description: volumeDevice describes a mapping of a + raw block device within a container. + properties: + devicePath: + description: devicePath is the path inside of + the container that the device will be mapped + to. + type: string + name: + description: name must match the name of a persistentVolumeClaim + in the pod + type: string + required: + - devicePath + - name + type: object + type: array + volumeMounts: + description: Pod volumes to mount into the container's + filesystem. Cannot be updated. + items: + description: VolumeMount describes a mounting of a + Volume within a container. + properties: + mountPath: + description: Path within the container at which + the volume should be mounted. Must not contain + ':'. + type: string + mountPropagation: + description: mountPropagation determines how mounts + are propagated from the host to container and + the other way around. When not set, MountPropagationNone + is used. This field is beta in 1.10. + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: Mounted read-only if true, read-write + otherwise (false or unspecified). Defaults to + false. + type: boolean + subPath: + description: Path within the volume from which + the container's volume should be mounted. Defaults + to "" (volume's root). + type: string + subPathExpr: + description: Expanded path within the volume from + which the container's volume should be mounted. + Behaves similarly to SubPath but environment + variable references $(VAR_NAME) are expanded + using the container's environment. Defaults + to "" (volume's root). SubPathExpr and SubPath + are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + workingDir: + description: Container's working directory. If not specified, + the container runtime's default will be used, which + might be configured in the container image. Cannot + be updated. + type: string + required: + - name + type: object + type: array + dnsConfig: + description: Specifies the DNS parameters of a pod. Parameters + specified here will be merged to the generated DNS configuration + based on DNSPolicy. + properties: + nameservers: + description: A list of DNS name server IP addresses. This + will be appended to the base nameservers generated from + DNSPolicy. Duplicated nameservers will be removed. + items: + type: string + type: array + options: + description: A list of DNS resolver options. This will + be merged with the base options generated from DNSPolicy. + Duplicated entries will be removed. Resolution options + given in Options will override those that appear in + the base DNSPolicy. + items: + description: PodDNSConfigOption defines DNS resolver + options of a pod. + properties: + name: + description: Required. + type: string + value: + type: string + type: object + type: array + searches: + description: A list of DNS search domains for host-name + lookup. This will be appended to the base search paths + generated from DNSPolicy. Duplicated search paths will + be removed. + items: + type: string + type: array + type: object + dnsPolicy: + description: Set DNS policy for the pod. Defaults to "ClusterFirst". + Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', + 'Default' or 'None'. DNS parameters given in DNSConfig will + be merged with the policy selected with DNSPolicy. To have + DNS options set along with hostNetwork, you have to specify + DNS policy explicitly to 'ClusterFirstWithHostNet'. + type: string + enableServiceLinks: + description: 'EnableServiceLinks indicates whether information + about services should be injected into pod''s environment + variables, matching the syntax of Docker links. Optional: + Defaults to true.' + type: boolean + ephemeralContainers: + description: List of ephemeral containers run in this pod. + Ephemeral containers may be run in an existing pod to perform + user-initiated actions such as debugging. This list cannot + be specified when creating a pod, and it cannot be modified + by updating the pod spec. In order to add an ephemeral container + to an existing pod, use the pod's ephemeralcontainers subresource. + items: + description: "An EphemeralContainer is a temporary container + that you may add to an existing Pod for user-initiated + activities such as debugging. Ephemeral containers have + no resource or scheduling guarantees, and they will not + be restarted when they exit or when a Pod is removed or + restarted. The kubelet may evict a Pod if an ephemeral + container causes the Pod to exceed its resource allocation. + \n To add an ephemeral container, use the ephemeralcontainers + subresource of an existing Pod. Ephemeral containers may + not be removed or restarted." + properties: + args: + description: 'Arguments to the entrypoint. The image''s + CMD is used if this is not provided. Variable references + $(VAR_NAME) are expanded using the container''s environment. + If a variable cannot be resolved, the reference in + the input string will be unchanged. Double $$ are + reduced to a single $, which allows for escaping the + $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce + the string literal "$(VAR_NAME)". Escaped references + will never be expanded, regardless of whether the + variable exists or not. Cannot be updated. More info: + https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + command: + description: 'Entrypoint array. Not executed within + a shell. The image''s ENTRYPOINT is used if this is + not provided. Variable references $(VAR_NAME) are + expanded using the container''s environment. If a + variable cannot be resolved, the reference in the + input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) + syntax: i.e. "$$(VAR_NAME)" will produce the string + literal "$(VAR_NAME)". Escaped references will never + be expanded, regardless of whether the variable exists + or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + env: + description: List of environment variables to set in + the container. Cannot be updated. + items: + description: EnvVar represents an environment variable + present in a Container. + properties: + name: + description: Name of the environment variable. + Must be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) + are expanded using the previously defined environment + variables in the container and any service environment + variables. If a variable cannot be resolved, + the reference in the input string will be unchanged. + Double $$ are reduced to a single $, which allows + for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" + will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless + of whether the variable exists or not. Defaults + to "".' + type: string + valueFrom: + description: Source for the environment variable's + value. Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Selects a field of the pod: + supports metadata.name, metadata.namespace, + `metadata.labels['''']`, `metadata.annotations['''']`, + spec.nodeName, spec.serviceAccountName, + status.hostIP, status.podIP, status.podIPs.' + properties: + apiVersion: + description: Version of the schema the + FieldPath is written in terms of, defaults + to "v1". + type: string + fieldPath: + description: Path of the field to select + in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of the container: + only resources limits and requests (limits.cpu, + limits.memory, limits.ephemeral-storage, + requests.cpu, requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: required + for volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format + of the exposed resources, defaults to + "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in + the pod's namespace + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + description: List of sources to populate environment + variables in the container. The keys defined within + a source must be a C_IDENTIFIER. All invalid keys + will be reported as an event when the container is + starting. When a key exists in multiple sources, the + value associated with the last source will take precedence. + Values defined by an Env with a duplicate key will + take precedence. Cannot be updated. + items: + description: EnvFromSource represents the source of + a set of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to prepend + to each key in the ConfigMap. Must be a C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + image: + description: 'Container image name. More info: https://kubernetes.io/docs/concepts/containers/images' + type: string + imagePullPolicy: + description: 'Image pull policy. One of Always, Never, + IfNotPresent. Defaults to Always if :latest tag is + specified, or IfNotPresent otherwise. Cannot be updated. + More info: https://kubernetes.io/docs/concepts/containers/images#updating-images' + type: string + lifecycle: + description: Lifecycle is not allowed for ephemeral + containers. + properties: + postStart: + description: 'PostStart is called immediately after + a container is created. If the handler fails, + the container is terminated and restarted according + to its restart policy. Other management of the + container blocks until the hook completes. More + info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line + to execute inside the container, the working + directory for the command is root ('/') + in the container's filesystem. The command + is simply exec'd, it is not run inside + a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, + you need to explicitly call out to that + shell. Exit status of 0 is treated as + live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT supported + as a LifecycleHandler and kept for the backward + compatibility. There are no validation of + this field and lifecycle hooks will fail in + runtime when tcp handler is specified. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + description: 'PreStop is called immediately before + a container is terminated due to an API request + or management event such as liveness/startup probe + failure, preemption, resource contention, etc. + The handler is not called if the container crashes + or exits. The Pod''s termination grace period + countdown begins before the PreStop hook is executed. + Regardless of the outcome of the handler, the + container will eventually terminate within the + Pod''s termination grace period (unless delayed + by finalizers). Other management of the container + blocks until the hook completes or until the termination + grace period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line + to execute inside the container, the working + directory for the command is root ('/') + in the container's filesystem. The command + is simply exec'd, it is not run inside + a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, + you need to explicitly call out to that + shell. Exit status of 0 is treated as + live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT supported + as a LifecycleHandler and kept for the backward + compatibility. There are no validation of + this field and lifecycle hooks will fail in + runtime when tcp handler is specified. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + description: Probes are not allowed for ephemeral containers. + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to + execute inside the container, the working + directory for the command is root ('/') in + the container's filesystem. The command is + simply exec'd, it is not run inside a shell, + so traditional shell instructions ('|', etc) + won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is + treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the + probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. This is a beta field and requires + enabling GRPCContainerProbe feature gate. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service + to place in the gRPC HealthCheckRequest (see + https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set "Host" + in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to + the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the + probe. Default to 10 seconds. Minimum value is + 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the + probe to be considered successful after having + failed. Defaults to 1. Must be 1 for liveness + and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod + needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after + the processes running in the pod are sent a termination + signal and the time when the processes are forcibly + halted with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value must + be non-negative integer. The value zero indicates + stop immediately via the kill signal (no opportunity + to shut down). This is a beta field and requires + enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the + probe times out. Defaults to 1 second. Minimum + value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + name: + description: Name of the ephemeral container specified + as a DNS_LABEL. This name must be unique among all + containers, init containers and ephemeral containers. + type: string + ports: + description: Ports are not allowed for ephemeral containers. + items: + description: ContainerPort represents a network port + in a single container. + properties: + containerPort: + description: Number of port to expose on the pod's + IP address. This must be a valid port number, + 0 < x < 65536. + format: int32 + type: integer + hostIP: + description: What host IP to bind the external + port to. + type: string + hostPort: + description: Number of port to expose on the host. + If specified, this must be a valid port number, + 0 < x < 65536. If HostNetwork is specified, + this must match ContainerPort. Most containers + do not need this. + format: int32 + type: integer + name: + description: If specified, this must be an IANA_SVC_NAME + and unique within the pod. Each named port in + a pod must have a unique name. Name for the + port that can be referred to by services. + type: string + protocol: + default: TCP + description: Protocol for port. Must be UDP, TCP, + or SCTP. Defaults to "TCP". + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: Probes are not allowed for ephemeral containers. + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to + execute inside the container, the working + directory for the command is root ('/') in + the container's filesystem. The command is + simply exec'd, it is not run inside a shell, + so traditional shell instructions ('|', etc) + won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is + treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the + probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. This is a beta field and requires + enabling GRPCContainerProbe feature gate. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service + to place in the gRPC HealthCheckRequest (see + https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set "Host" + in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to + the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the + probe. Default to 10 seconds. Minimum value is + 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the + probe to be considered successful after having + failed. Defaults to 1. Must be 1 for liveness + and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod + needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after + the processes running in the pod are sent a termination + signal and the time when the processes are forcibly + halted with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value must + be non-negative integer. The value zero indicates + stop immediately via the kill signal (no opportunity + to shut down). This is a beta field and requires + enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the + probe times out. Defaults to 1 second. Minimum + value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + resources: + description: Resources are not allowed for ephemeral + containers. Ephemeral containers use spare resources + already allocated to the pod. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount + of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount + of compute resources required. If Requests is + omitted for a container, it defaults to Limits + if that is explicitly specified, otherwise to + an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + securityContext: + description: 'Optional: SecurityContext defines the + security options the ephemeral container should be + run with. If set, the fields of SecurityContext override + the equivalent fields of PodSecurityContext.' + properties: + allowPrivilegeEscalation: + description: 'AllowPrivilegeEscalation controls + whether a process can gain more privileges than + its parent process. This bool directly controls + if the no_new_privs flag will be set on the container + process. AllowPrivilegeEscalation is true always + when the container is: 1) run as Privileged 2) + has CAP_SYS_ADMIN Note that this field cannot + be set when spec.os.name is windows.' + type: boolean + capabilities: + description: The capabilities to add/drop when running + containers. Defaults to the default set of capabilities + granted by the container runtime. Note that this + field cannot be set when spec.os.name is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + type: object + privileged: + description: Run container in privileged mode. Processes + in privileged containers are essentially equivalent + to root on the host. Defaults to false. Note that + this field cannot be set when spec.os.name is + windows. + type: boolean + procMount: + description: procMount denotes the type of proc + mount to use for the containers. The default is + DefaultProcMount which uses the container runtime + defaults for readonly paths and masked paths. + This requires the ProcMountType feature flag to + be enabled. Note that this field cannot be set + when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: Whether this container has a read-only + root filesystem. Default is false. Note that this + field cannot be set when spec.os.name is windows. + type: boolean + runAsGroup: + description: The GID to run the entrypoint of the + container process. Uses runtime default if unset. + May also be set in PodSecurityContext. If set + in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name + is windows. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container must run + as a non-root user. If true, the Kubelet will + validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start + the container if it does. If unset or false, no + such validation will be performed. May also be + set in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in + SecurityContext takes precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of the + container process. Defaults to user specified + in image metadata if unspecified. May also be + set in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in + SecurityContext takes precedence. Note that this + field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied to + the container. If unspecified, the container runtime + will allocate a random SELinux context for each + container. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name + is windows. + properties: + level: + description: Level is SELinux level label that + applies to the container. + type: string + role: + description: Role is a SELinux role label that + applies to the container. + type: string + type: + description: Type is a SELinux type label that + applies to the container. + type: string + user: + description: User is a SELinux user label that + applies to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by this + container. If seccomp options are provided at + both the pod & container level, the container + options override the pod options. Note that this + field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: localhostProfile indicates a profile + defined in a file on the node should be used. + The profile must be preconfigured on the node + to work. Must be a descending path, relative + to the kubelet's configured seccomp profile + location. Must only be set if type is "Localhost". + type: string + type: + description: "type indicates which kind of seccomp + profile will be applied. Valid options are: + \n Localhost - a profile defined in a file + on the node should be used. RuntimeDefault + - the container runtime default profile should + be used. Unconfined - no profile should be + applied." + type: string + required: + - type + type: object + windowsOptions: + description: The Windows specific settings applied + to all containers. If unspecified, the options + from the PodSecurityContext will be used. If set + in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name + is linux. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where the + GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential + spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name + of the GMSA credential spec to use. + type: string + hostProcess: + description: HostProcess determines if a container + should be run as a 'Host Process' container. + This field is alpha-level and will only be + honored by components that enable the WindowsHostProcessContainers + feature flag. Setting this field without the + feature flag will result in errors when validating + the Pod. All of a Pod's containers must have + the same effective HostProcess value (it is + not allowed to have a mix of HostProcess containers + and non-HostProcess containers). In addition, + if HostProcess is true then HostNetwork must + also be set to true. + type: boolean + runAsUserName: + description: The UserName in Windows to run + the entrypoint of the container process. Defaults + to the user specified in image metadata if + unspecified. May also be set in PodSecurityContext. + If set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. + type: string + type: object + type: object + startupProbe: + description: Probes are not allowed for ephemeral containers. + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to + execute inside the container, the working + directory for the command is root ('/') in + the container's filesystem. The command is + simply exec'd, it is not run inside a shell, + so traditional shell instructions ('|', etc) + won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is + treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the + probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. This is a beta field and requires + enabling GRPCContainerProbe feature gate. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service + to place in the gRPC HealthCheckRequest (see + https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set "Host" + in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to + the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the + probe. Default to 10 seconds. Minimum value is + 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the + probe to be considered successful after having + failed. Defaults to 1. Must be 1 for liveness + and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod + needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after + the processes running in the pod are sent a termination + signal and the time when the processes are forcibly + halted with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value must + be non-negative integer. The value zero indicates + stop immediately via the kill signal (no opportunity + to shut down). This is a beta field and requires + enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the + probe times out. Defaults to 1 second. Minimum + value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + stdin: + description: Whether this container should allocate + a buffer for stdin in the container runtime. If this + is not set, reads from stdin in the container will + always result in EOF. Default is false. + type: boolean + stdinOnce: + description: Whether the container runtime should close + the stdin channel after it has been opened by a single + attach. When stdin is true the stdin stream will remain + open across multiple attach sessions. If stdinOnce + is set to true, stdin is opened on container start, + is empty until the first client attaches to stdin, + and then remains open and accepts data until the client + disconnects, at which time stdin is closed and remains + closed until the container is restarted. If this flag + is false, a container processes that reads from stdin + will never receive an EOF. Default is false + type: boolean + targetContainerName: + description: "If set, the name of the container from + PodSpec that this ephemeral container targets. The + ephemeral container will be run in the namespaces + (IPC, PID, etc) of this container. If not set then + the ephemeral container uses the namespaces configured + in the Pod spec. \n The container runtime must implement + support for this feature. If the runtime does not + support namespace targeting then the result of setting + this field is undefined." + type: string + terminationMessagePath: + description: 'Optional: Path at which the file to which + the container''s termination message will be written + is mounted into the container''s filesystem. Message + written is intended to be brief final status, such + as an assertion failure message. Will be truncated + by the node if greater than 4096 bytes. The total + message length across all containers will be limited + to 12kb. Defaults to /dev/termination-log. Cannot + be updated.' + type: string + terminationMessagePolicy: + description: Indicate how the termination message should + be populated. File will use the contents of terminationMessagePath + to populate the container status message on both success + and failure. FallbackToLogsOnError will use the last + chunk of container log output if the termination message + file is empty and the container exited with an error. + The log output is limited to 2048 bytes or 80 lines, + whichever is smaller. Defaults to File. Cannot be + updated. + type: string + tty: + description: Whether this container should allocate + a TTY for itself, also requires 'stdin' to be true. + Default is false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block devices + to be used by the container. + items: + description: volumeDevice describes a mapping of a + raw block device within a container. + properties: + devicePath: + description: devicePath is the path inside of + the container that the device will be mapped + to. + type: string + name: + description: name must match the name of a persistentVolumeClaim + in the pod + type: string + required: + - devicePath + - name + type: object + type: array + volumeMounts: + description: Pod volumes to mount into the container's + filesystem. Subpath mounts are not allowed for ephemeral + containers. Cannot be updated. + items: + description: VolumeMount describes a mounting of a + Volume within a container. + properties: + mountPath: + description: Path within the container at which + the volume should be mounted. Must not contain + ':'. + type: string + mountPropagation: + description: mountPropagation determines how mounts + are propagated from the host to container and + the other way around. When not set, MountPropagationNone + is used. This field is beta in 1.10. + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: Mounted read-only if true, read-write + otherwise (false or unspecified). Defaults to + false. + type: boolean + subPath: + description: Path within the volume from which + the container's volume should be mounted. Defaults + to "" (volume's root). + type: string + subPathExpr: + description: Expanded path within the volume from + which the container's volume should be mounted. + Behaves similarly to SubPath but environment + variable references $(VAR_NAME) are expanded + using the container's environment. Defaults + to "" (volume's root). SubPathExpr and SubPath + are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + workingDir: + description: Container's working directory. If not specified, + the container runtime's default will be used, which + might be configured in the container image. Cannot + be updated. + type: string + required: + - name + type: object + type: array + hostAliases: + description: HostAliases is an optional list of hosts and + IPs that will be injected into the pod's hosts file if specified. + This is only valid for non-hostNetwork pods. + items: + description: HostAlias holds the mapping between IP and + hostnames that will be injected as an entry in the pod's + hosts file. + properties: + hostnames: + description: Hostnames for the above IP address. + items: + type: string + type: array + ip: + description: IP address of the host file entry. + type: string + type: object + type: array + hostIPC: + description: 'Use the host''s ipc namespace. Optional: Default + to false.' + type: boolean + hostNetwork: + description: Host networking requested for this pod. Use the + host's network namespace. If this option is set, the ports + that will be used must be specified. Default to false. + type: boolean + hostPID: + description: 'Use the host''s pid namespace. Optional: Default + to false.' + type: boolean + hostUsers: + description: 'Use the host''s user namespace. Optional: Default + to true. If set to true or not present, the pod will be + run in the host user namespace, useful for when the pod + needs a feature only available to the host user namespace, + such as loading a kernel module with CAP_SYS_MODULE. When + set to false, a new userns is created for the pod. Setting + false is useful for mitigating container breakout vulnerabilities + even allowing users to run their containers as root without + actually having root privileges on the host. This field + is alpha-level and is only honored by servers that enable + the UserNamespacesSupport feature.' + type: boolean + hostname: + description: Specifies the hostname of the Pod If not specified, + the pod's hostname will be set to a system-defined value. + type: string + imagePullSecrets: + description: 'ImagePullSecrets is an optional list of references + to secrets in the same namespace to use for pulling any + of the images used by this PodSpec. If specified, these + secrets will be passed to individual puller implementations + for them to use. More info: https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod' + items: + description: LocalObjectReference contains enough information + to let you locate the referenced object inside the same + namespace. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + type: array + initContainers: + description: 'List of initialization containers belonging + to the pod. Init containers are executed in order prior + to containers being started. If any init container fails, + the pod is considered to have failed and is handled according + to its restartPolicy. The name for an init container or + normal container must be unique among all containers. Init + containers may not have Lifecycle actions, Readiness probes, + Liveness probes, or Startup probes. The resourceRequirements + of an init container are taken into account during scheduling + by finding the highest request/limit for each resource type, + and then using the max of of that value or the sum of the + normal containers. Limits are applied to init containers + in a similar fashion. Init containers cannot currently be + added or removed. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/' + items: + description: A single application container that you want + to run within a pod. + properties: + args: + description: 'Arguments to the entrypoint. The container + image''s CMD is used if this is not provided. Variable + references $(VAR_NAME) are expanded using the container''s + environment. If a variable cannot be resolved, the + reference in the input string will be unchanged. Double + $$ are reduced to a single $, which allows for escaping + the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce + the string literal "$(VAR_NAME)". Escaped references + will never be expanded, regardless of whether the + variable exists or not. Cannot be updated. More info: + https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + command: + description: 'Entrypoint array. Not executed within + a shell. The container image''s ENTRYPOINT is used + if this is not provided. Variable references $(VAR_NAME) + are expanded using the container''s environment. If + a variable cannot be resolved, the reference in the + input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) + syntax: i.e. "$$(VAR_NAME)" will produce the string + literal "$(VAR_NAME)". Escaped references will never + be expanded, regardless of whether the variable exists + or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + env: + description: List of environment variables to set in + the container. Cannot be updated. + items: + description: EnvVar represents an environment variable + present in a Container. + properties: + name: + description: Name of the environment variable. + Must be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) + are expanded using the previously defined environment + variables in the container and any service environment + variables. If a variable cannot be resolved, + the reference in the input string will be unchanged. + Double $$ are reduced to a single $, which allows + for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" + will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless + of whether the variable exists or not. Defaults + to "".' + type: string + valueFrom: + description: Source for the environment variable's + value. Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Selects a field of the pod: + supports metadata.name, metadata.namespace, + `metadata.labels['''']`, `metadata.annotations['''']`, + spec.nodeName, spec.serviceAccountName, + status.hostIP, status.podIP, status.podIPs.' + properties: + apiVersion: + description: Version of the schema the + FieldPath is written in terms of, defaults + to "v1". + type: string + fieldPath: + description: Path of the field to select + in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of the container: + only resources limits and requests (limits.cpu, + limits.memory, limits.ephemeral-storage, + requests.cpu, requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: required + for volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format + of the exposed resources, defaults to + "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in + the pod's namespace + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + description: List of sources to populate environment + variables in the container. The keys defined within + a source must be a C_IDENTIFIER. All invalid keys + will be reported as an event when the container is + starting. When a key exists in multiple sources, the + value associated with the last source will take precedence. + Values defined by an Env with a duplicate key will + take precedence. Cannot be updated. + items: + description: EnvFromSource represents the source of + a set of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to prepend + to each key in the ConfigMap. Must be a C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + image: + description: 'Container image name. More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config + management to default or override container images + in workload controllers like Deployments and StatefulSets.' + type: string + imagePullPolicy: + description: 'Image pull policy. One of Always, Never, + IfNotPresent. Defaults to Always if :latest tag is + specified, or IfNotPresent otherwise. Cannot be updated. + More info: https://kubernetes.io/docs/concepts/containers/images#updating-images' + type: string + lifecycle: + description: Actions that the management system should + take in response to container lifecycle events. Cannot + be updated. + properties: + postStart: + description: 'PostStart is called immediately after + a container is created. If the handler fails, + the container is terminated and restarted according + to its restart policy. Other management of the + container blocks until the hook completes. More + info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line + to execute inside the container, the working + directory for the command is root ('/') + in the container's filesystem. The command + is simply exec'd, it is not run inside + a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, + you need to explicitly call out to that + shell. Exit status of 0 is treated as + live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT supported + as a LifecycleHandler and kept for the backward + compatibility. There are no validation of + this field and lifecycle hooks will fail in + runtime when tcp handler is specified. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + description: 'PreStop is called immediately before + a container is terminated due to an API request + or management event such as liveness/startup probe + failure, preemption, resource contention, etc. + The handler is not called if the container crashes + or exits. The Pod''s termination grace period + countdown begins before the PreStop hook is executed. + Regardless of the outcome of the handler, the + container will eventually terminate within the + Pod''s termination grace period (unless delayed + by finalizers). Other management of the container + blocks until the hook completes or until the termination + grace period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line + to execute inside the container, the working + directory for the command is root ('/') + in the container's filesystem. The command + is simply exec'd, it is not run inside + a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, + you need to explicitly call out to that + shell. Exit status of 0 is treated as + live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT supported + as a LifecycleHandler and kept for the backward + compatibility. There are no validation of + this field and lifecycle hooks will fail in + runtime when tcp handler is specified. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + description: 'Periodic probe of container liveness. + Container will be restarted if the probe fails. Cannot + be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to + execute inside the container, the working + directory for the command is root ('/') in + the container's filesystem. The command is + simply exec'd, it is not run inside a shell, + so traditional shell instructions ('|', etc) + won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is + treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the + probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. This is a beta field and requires + enabling GRPCContainerProbe feature gate. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service + to place in the gRPC HealthCheckRequest (see + https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set "Host" + in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to + the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the + probe. Default to 10 seconds. Minimum value is + 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the + probe to be considered successful after having + failed. Defaults to 1. Must be 1 for liveness + and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod + needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after + the processes running in the pod are sent a termination + signal and the time when the processes are forcibly + halted with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value must + be non-negative integer. The value zero indicates + stop immediately via the kill signal (no opportunity + to shut down). This is a beta field and requires + enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the + probe times out. Defaults to 1 second. Minimum + value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + name: + description: Name of the container specified as a DNS_LABEL. + Each container in a pod must have a unique name (DNS_LABEL). + Cannot be updated. + type: string + ports: + description: List of ports to expose from the container. + Not specifying a port here DOES NOT prevent that port + from being exposed. Any port which is listening on + the default "0.0.0.0" address inside a container will + be accessible from the network. Modifying this array + with strategic merge patch may corrupt the data. For + more information See https://github.com/kubernetes/kubernetes/issues/108255. + Cannot be updated. + items: + description: ContainerPort represents a network port + in a single container. + properties: + containerPort: + description: Number of port to expose on the pod's + IP address. This must be a valid port number, + 0 < x < 65536. + format: int32 + type: integer + hostIP: + description: What host IP to bind the external + port to. + type: string + hostPort: + description: Number of port to expose on the host. + If specified, this must be a valid port number, + 0 < x < 65536. If HostNetwork is specified, + this must match ContainerPort. Most containers + do not need this. + format: int32 + type: integer + name: + description: If specified, this must be an IANA_SVC_NAME + and unique within the pod. Each named port in + a pod must have a unique name. Name for the + port that can be referred to by services. + type: string + protocol: + default: TCP + description: Protocol for port. Must be UDP, TCP, + or SCTP. Defaults to "TCP". + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: 'Periodic probe of container service readiness. + Container will be removed from service endpoints if + the probe fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to + execute inside the container, the working + directory for the command is root ('/') in + the container's filesystem. The command is + simply exec'd, it is not run inside a shell, + so traditional shell instructions ('|', etc) + won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is + treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the + probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. This is a beta field and requires + enabling GRPCContainerProbe feature gate. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service + to place in the gRPC HealthCheckRequest (see + https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set "Host" + in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to + the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the + probe. Default to 10 seconds. Minimum value is + 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the + probe to be considered successful after having + failed. Defaults to 1. Must be 1 for liveness + and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod + needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after + the processes running in the pod are sent a termination + signal and the time when the processes are forcibly + halted with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value must + be non-negative integer. The value zero indicates + stop immediately via the kill signal (no opportunity + to shut down). This is a beta field and requires + enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the + probe times out. Defaults to 1 second. Minimum + value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + resources: + description: 'Compute Resources required by this container. + Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount + of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount + of compute resources required. If Requests is + omitted for a container, it defaults to Limits + if that is explicitly specified, otherwise to + an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + securityContext: + description: 'SecurityContext defines the security options + the container should be run with. If set, the fields + of SecurityContext override the equivalent fields + of PodSecurityContext. More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/' + properties: + allowPrivilegeEscalation: + description: 'AllowPrivilegeEscalation controls + whether a process can gain more privileges than + its parent process. This bool directly controls + if the no_new_privs flag will be set on the container + process. AllowPrivilegeEscalation is true always + when the container is: 1) run as Privileged 2) + has CAP_SYS_ADMIN Note that this field cannot + be set when spec.os.name is windows.' + type: boolean + capabilities: + description: The capabilities to add/drop when running + containers. Defaults to the default set of capabilities + granted by the container runtime. Note that this + field cannot be set when spec.os.name is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + type: object + privileged: + description: Run container in privileged mode. Processes + in privileged containers are essentially equivalent + to root on the host. Defaults to false. Note that + this field cannot be set when spec.os.name is + windows. + type: boolean + procMount: + description: procMount denotes the type of proc + mount to use for the containers. The default is + DefaultProcMount which uses the container runtime + defaults for readonly paths and masked paths. + This requires the ProcMountType feature flag to + be enabled. Note that this field cannot be set + when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: Whether this container has a read-only + root filesystem. Default is false. Note that this + field cannot be set when spec.os.name is windows. + type: boolean + runAsGroup: + description: The GID to run the entrypoint of the + container process. Uses runtime default if unset. + May also be set in PodSecurityContext. If set + in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name + is windows. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container must run + as a non-root user. If true, the Kubelet will + validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start + the container if it does. If unset or false, no + such validation will be performed. May also be + set in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in + SecurityContext takes precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of the + container process. Defaults to user specified + in image metadata if unspecified. May also be + set in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in + SecurityContext takes precedence. Note that this + field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied to + the container. If unspecified, the container runtime + will allocate a random SELinux context for each + container. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name + is windows. + properties: + level: + description: Level is SELinux level label that + applies to the container. + type: string + role: + description: Role is a SELinux role label that + applies to the container. + type: string + type: + description: Type is a SELinux type label that + applies to the container. + type: string + user: + description: User is a SELinux user label that + applies to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by this + container. If seccomp options are provided at + both the pod & container level, the container + options override the pod options. Note that this + field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: localhostProfile indicates a profile + defined in a file on the node should be used. + The profile must be preconfigured on the node + to work. Must be a descending path, relative + to the kubelet's configured seccomp profile + location. Must only be set if type is "Localhost". + type: string + type: + description: "type indicates which kind of seccomp + profile will be applied. Valid options are: + \n Localhost - a profile defined in a file + on the node should be used. RuntimeDefault + - the container runtime default profile should + be used. Unconfined - no profile should be + applied." + type: string + required: + - type + type: object + windowsOptions: + description: The Windows specific settings applied + to all containers. If unspecified, the options + from the PodSecurityContext will be used. If set + in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name + is linux. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where the + GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential + spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name + of the GMSA credential spec to use. + type: string + hostProcess: + description: HostProcess determines if a container + should be run as a 'Host Process' container. + This field is alpha-level and will only be + honored by components that enable the WindowsHostProcessContainers + feature flag. Setting this field without the + feature flag will result in errors when validating + the Pod. All of a Pod's containers must have + the same effective HostProcess value (it is + not allowed to have a mix of HostProcess containers + and non-HostProcess containers). In addition, + if HostProcess is true then HostNetwork must + also be set to true. + type: boolean + runAsUserName: + description: The UserName in Windows to run + the entrypoint of the container process. Defaults + to the user specified in image metadata if + unspecified. May also be set in PodSecurityContext. + If set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. + type: string + type: object + type: object + startupProbe: + description: 'StartupProbe indicates that the Pod has + successfully initialized. If specified, no other probes + are executed until this completes successfully. If + this probe fails, the Pod will be restarted, just + as if the livenessProbe failed. This can be used to + provide different probe parameters at the beginning + of a Pod''s lifecycle, when it might take a long time + to load data or warm a cache, than during steady-state + operation. This cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to + execute inside the container, the working + directory for the command is root ('/') in + the container's filesystem. The command is + simply exec'd, it is not run inside a shell, + so traditional shell instructions ('|', etc) + won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is + treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the + probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. This is a beta field and requires + enabling GRPCContainerProbe feature gate. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service + to place in the gRPC HealthCheckRequest (see + https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set "Host" + in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to + the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the + probe. Default to 10 seconds. Minimum value is + 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the + probe to be considered successful after having + failed. Defaults to 1. Must be 1 for liveness + and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod + needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after + the processes running in the pod are sent a termination + signal and the time when the processes are forcibly + halted with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value must + be non-negative integer. The value zero indicates + stop immediately via the kill signal (no opportunity + to shut down). This is a beta field and requires + enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the + probe times out. Defaults to 1 second. Minimum + value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + stdin: + description: Whether this container should allocate + a buffer for stdin in the container runtime. If this + is not set, reads from stdin in the container will + always result in EOF. Default is false. + type: boolean + stdinOnce: + description: Whether the container runtime should close + the stdin channel after it has been opened by a single + attach. When stdin is true the stdin stream will remain + open across multiple attach sessions. If stdinOnce + is set to true, stdin is opened on container start, + is empty until the first client attaches to stdin, + and then remains open and accepts data until the client + disconnects, at which time stdin is closed and remains + closed until the container is restarted. If this flag + is false, a container processes that reads from stdin + will never receive an EOF. Default is false + type: boolean + terminationMessagePath: + description: 'Optional: Path at which the file to which + the container''s termination message will be written + is mounted into the container''s filesystem. Message + written is intended to be brief final status, such + as an assertion failure message. Will be truncated + by the node if greater than 4096 bytes. The total + message length across all containers will be limited + to 12kb. Defaults to /dev/termination-log. Cannot + be updated.' + type: string + terminationMessagePolicy: + description: Indicate how the termination message should + be populated. File will use the contents of terminationMessagePath + to populate the container status message on both success + and failure. FallbackToLogsOnError will use the last + chunk of container log output if the termination message + file is empty and the container exited with an error. + The log output is limited to 2048 bytes or 80 lines, + whichever is smaller. Defaults to File. Cannot be + updated. + type: string + tty: + description: Whether this container should allocate + a TTY for itself, also requires 'stdin' to be true. + Default is false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block devices + to be used by the container. + items: + description: volumeDevice describes a mapping of a + raw block device within a container. + properties: + devicePath: + description: devicePath is the path inside of + the container that the device will be mapped + to. + type: string + name: + description: name must match the name of a persistentVolumeClaim + in the pod + type: string + required: + - devicePath + - name + type: object + type: array + volumeMounts: + description: Pod volumes to mount into the container's + filesystem. Cannot be updated. + items: + description: VolumeMount describes a mounting of a + Volume within a container. + properties: + mountPath: + description: Path within the container at which + the volume should be mounted. Must not contain + ':'. + type: string + mountPropagation: + description: mountPropagation determines how mounts + are propagated from the host to container and + the other way around. When not set, MountPropagationNone + is used. This field is beta in 1.10. + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: Mounted read-only if true, read-write + otherwise (false or unspecified). Defaults to + false. + type: boolean + subPath: + description: Path within the volume from which + the container's volume should be mounted. Defaults + to "" (volume's root). + type: string + subPathExpr: + description: Expanded path within the volume from + which the container's volume should be mounted. + Behaves similarly to SubPath but environment + variable references $(VAR_NAME) are expanded + using the container's environment. Defaults + to "" (volume's root). SubPathExpr and SubPath + are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + workingDir: + description: Container's working directory. If not specified, + the container runtime's default will be used, which + might be configured in the container image. Cannot + be updated. + type: string + required: + - name + type: object + type: array + nodeName: + description: NodeName is a request to schedule this pod onto + a specific node. If it is non-empty, the scheduler simply + schedules this pod onto that node, assuming that it fits + resource requirements. + type: string + nodeSelector: + additionalProperties: + type: string + description: 'NodeSelector is a selector which must be true + for the pod to fit on a node. Selector which must match + a node''s labels for the pod to be scheduled on that node. + More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/' + type: object + x-kubernetes-map-type: atomic + os: + description: "Specifies the OS of the containers in the pod. + Some pod and container fields are restricted if this is + set. \n If the OS field is set to linux, the following fields + must be unset: -securityContext.windowsOptions \n If the + OS field is set to windows, following fields must be unset: + - spec.hostPID - spec.hostIPC - spec.hostUsers - spec.securityContext.seLinuxOptions + - spec.securityContext.seccompProfile - spec.securityContext.fsGroup + - spec.securityContext.fsGroupChangePolicy - spec.securityContext.sysctls + - spec.shareProcessNamespace - spec.securityContext.runAsUser + - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups + - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile + - spec.containers[*].securityContext.capabilities - spec.containers[*].securityContext.readOnlyRootFilesystem + - spec.containers[*].securityContext.privileged - spec.containers[*].securityContext.allowPrivilegeEscalation + - spec.containers[*].securityContext.procMount - spec.containers[*].securityContext.runAsUser + - spec.containers[*].securityContext.runAsGroup" + properties: + name: + description: 'Name is the name of the operating system. + The currently supported values are linux and windows. + Additional value may be defined in future and can be + one of: https://github.com/opencontainers/runtime-spec/blob/master/config.md#platform-specific-configuration + Clients should expect to handle additional values and + treat unrecognized values in this field as os: null' + type: string + required: + - name + type: object + overhead: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Overhead represents the resource overhead associated + with running a pod for a given RuntimeClass. This field + will be autopopulated at admission time by the RuntimeClass + admission controller. If the RuntimeClass admission controller + is enabled, overhead must not be set in Pod create requests. + The RuntimeClass admission controller will reject Pod create + requests which have the overhead already set. If RuntimeClass + is configured and selected in the PodSpec, Overhead will + be set to the value defined in the corresponding RuntimeClass, + otherwise it will remain unset and treated as zero. More + info: https://git.k8s.io/enhancements/keps/sig-node/688-pod-overhead/README.md' + type: object + preemptionPolicy: + description: PreemptionPolicy is the Policy for preempting + pods with lower priority. One of Never, PreemptLowerPriority. + Defaults to PreemptLowerPriority if unset. + type: string + priority: + description: The priority value. Various system components + use this field to find the priority of the pod. When Priority + Admission Controller is enabled, it prevents users from + setting this field. The admission controller populates this + field from PriorityClassName. The higher the value, the + higher the priority. + format: int32 + type: integer + priorityClassName: + description: If specified, indicates the pod's priority. "system-node-critical" + and "system-cluster-critical" are two special keywords which + indicate the highest priorities with the former being the + highest priority. Any other name must be defined by creating + a PriorityClass object with that name. If not specified, + the pod priority will be default or zero if there is no + default. + type: string + readinessGates: + description: 'If specified, all readiness gates will be evaluated + for pod readiness. A pod is ready when all its containers + are ready AND all conditions specified in the readiness + gates have status equal to "True" More info: https://git.k8s.io/enhancements/keps/sig-network/580-pod-readiness-gates' + items: + description: PodReadinessGate contains the reference to + a pod condition + properties: + conditionType: + description: ConditionType refers to a condition in + the pod's condition list with matching type. + type: string + required: + - conditionType + type: object + type: array + restartPolicy: + description: 'Restart policy for all containers within the + pod. One of Always, OnFailure, Never. Default to Always. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy' + type: string + runtimeClassName: + description: 'RuntimeClassName refers to a RuntimeClass object + in the node.k8s.io group, which should be used to run this + pod. If no RuntimeClass resource matches the named class, + the pod will not be run. If unset or empty, the "legacy" + RuntimeClass will be used, which is an implicit class with + an empty definition that uses the default runtime handler. + More info: https://git.k8s.io/enhancements/keps/sig-node/585-runtime-class' + type: string + schedulerName: + description: If specified, the pod will be dispatched by specified + scheduler. If not specified, the pod will be dispatched + by default scheduler. + type: string + securityContext: + description: 'SecurityContext holds pod-level security attributes + and common container settings. Optional: Defaults to empty. See + type description for default values of each field.' + properties: + fsGroup: + description: "A special supplemental group that applies + to all containers in a pod. Some volume types allow + the Kubelet to change the ownership of that volume to + be owned by the pod: \n 1. The owning GID will be the + FSGroup 2. The setgid bit is set (new files created + in the volume will be owned by FSGroup) 3. The permission + bits are OR'd with rw-rw---- \n If unset, the Kubelet + will not modify the ownership and permissions of any + volume. Note that this field cannot be set when spec.os.name + is windows." + format: int64 + type: integer + fsGroupChangePolicy: + description: 'fsGroupChangePolicy defines behavior of + changing ownership and permission of the volume before + being exposed inside Pod. This field will only apply + to volume types which support fsGroup based ownership(and + permissions). It will have no effect on ephemeral volume + types such as: secret, configmaps and emptydir. Valid + values are "OnRootMismatch" and "Always". If not specified, + "Always" is used. Note that this field cannot be set + when spec.os.name is windows.' + type: string + runAsGroup: + description: The GID to run the entrypoint of the container + process. Uses runtime default if unset. May also be + set in SecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence for that container. Note that this + field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container must run as + a non-root user. If true, the Kubelet will validate + the image at runtime to ensure that it does not run + as UID 0 (root) and fail to start the container if it + does. If unset or false, no such validation will be + performed. May also be set in SecurityContext. If set + in both SecurityContext and PodSecurityContext, the + value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of the container + process. Defaults to user specified in image metadata + if unspecified. May also be set in SecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence + for that container. Note that this field cannot be set + when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied to all + containers. If unspecified, the container runtime will + allocate a random SELinux context for each container. May + also be set in SecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence for that container. Note that this + field cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that applies + to the container. + type: string + role: + description: Role is a SELinux role label that applies + to the container. + type: string + type: + description: Type is a SELinux type label that applies + to the container. + type: string + user: + description: User is a SELinux user label that applies + to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by the containers + in this pod. Note that this field cannot be set when + spec.os.name is windows. + properties: + localhostProfile: + description: localhostProfile indicates a profile + defined in a file on the node should be used. The + profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's + configured seccomp profile location. Must only be + set if type is "Localhost". + type: string + type: + description: "type indicates which kind of seccomp + profile will be applied. Valid options are: \n Localhost + - a profile defined in a file on the node should + be used. RuntimeDefault - the container runtime + default profile should be used. Unconfined - no + profile should be applied." + type: string + required: + - type + type: object + supplementalGroups: + description: A list of groups applied to the first process + run in each container, in addition to the container's + primary GID. If unspecified, no groups will be added + to any container. Note that this field cannot be set + when spec.os.name is windows. + items: + format: int64 + type: integer + type: array + sysctls: + description: Sysctls hold a list of namespaced sysctls + used for the pod. Pods with unsupported sysctls (by + the container runtime) might fail to launch. Note that + this field cannot be set when spec.os.name is windows. + items: + description: Sysctl defines a kernel parameter to be + set + properties: + name: + description: Name of a property to set + type: string + value: + description: Value of a property to set + type: string + required: + - name + - value + type: object + type: array + windowsOptions: + description: The Windows specific settings applied to + all containers. If unspecified, the options within a + container's SecurityContext will be used. If set in + both SecurityContext and PodSecurityContext, the value + specified in SecurityContext takes precedence. Note + that this field cannot be set when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where the GMSA + admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential spec + named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of + the GMSA credential spec to use. + type: string + hostProcess: + description: HostProcess determines if a container + should be run as a 'Host Process' container. This + field is alpha-level and will only be honored by + components that enable the WindowsHostProcessContainers + feature flag. Setting this field without the feature + flag will result in errors when validating the Pod. + All of a Pod's containers must have the same effective + HostProcess value (it is not allowed to have a mix + of HostProcess containers and non-HostProcess containers). In + addition, if HostProcess is true then HostNetwork + must also be set to true. + type: boolean + runAsUserName: + description: The UserName in Windows to run the entrypoint + of the container process. Defaults to the user specified + in image metadata if unspecified. May also be set + in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence. + type: string + type: object + type: object + serviceAccount: + description: 'DeprecatedServiceAccount is a depreciated alias + for ServiceAccountName. Deprecated: Use serviceAccountName + instead.' + type: string + serviceAccountName: + description: 'ServiceAccountName is the name of the ServiceAccount + to use to run this pod. More info: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/' + type: string + setHostnameAsFQDN: + description: If true the pod's hostname will be configured + as the pod's FQDN, rather than the leaf name (the default). + In Linux containers, this means setting the FQDN in the + hostname field of the kernel (the nodename field of struct + utsname). In Windows containers, this means setting the + registry value of hostname for the registry key HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters + to FQDN. If a pod does not have FQDN, this has no effect. + Default to false. + type: boolean + shareProcessNamespace: + description: 'Share a single process namespace between all + of the containers in a pod. When this is set containers + will be able to view and signal processes from other containers + in the same pod, and the first process in each container + will not be assigned PID 1. HostPID and ShareProcessNamespace + cannot both be set. Optional: Default to false.' + type: boolean + subdomain: + description: If specified, the fully qualified Pod hostname + will be "...svc.". If not specified, the pod will not have a domainname + at all. + type: string + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod needs to + terminate gracefully. May be decreased in delete request. + Value must be non-negative integer. The value zero indicates + stop immediately via the kill signal (no opportunity to + shut down). If this value is nil, the default grace period + will be used instead. The grace period is the duration in + seconds after the processes running in the pod are sent + a termination signal and the time when the processes are + forcibly halted with a kill signal. Set this value longer + than the expected cleanup time for your process. Defaults + to 30 seconds. + format: int64 + type: integer + tolerations: + description: If specified, the pod's tolerations. + items: + description: The pod this Toleration is attached to tolerates + any taint that matches the triple using + the matching operator . + properties: + effect: + description: Effect indicates the taint effect to match. + Empty means match all taint effects. When specified, + allowed values are NoSchedule, PreferNoSchedule and + NoExecute. + type: string + key: + description: Key is the taint key that the toleration + applies to. Empty means match all taint keys. If the + key is empty, operator must be Exists; this combination + means to match all values and all keys. + type: string + operator: + description: Operator represents a key's relationship + to the value. Valid operators are Exists and Equal. + Defaults to Equal. Exists is equivalent to wildcard + for value, so that a pod can tolerate all taints of + a particular category. + type: string + tolerationSeconds: + description: TolerationSeconds represents the period + of time the toleration (which must be of effect NoExecute, + otherwise this field is ignored) tolerates the taint. + By default, it is not set, which means tolerate the + taint forever (do not evict). Zero and negative values + will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: Value is the taint value the toleration + matches to. If the operator is Exists, the value should + be empty, otherwise just a regular string. + type: string + type: object + type: array + topologySpreadConstraints: + description: TopologySpreadConstraints describes how a group + of pods ought to spread across topology domains. Scheduler + will schedule pods in a way which abides by the constraints. + All topologySpreadConstraints are ANDed. + items: + description: TopologySpreadConstraint specifies how to spread + matching pods among the given topology. + properties: + labelSelector: + description: LabelSelector is used to find matching + pods. Pods that match this label selector are counted + to determine the number of pods in their corresponding + topology domain. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are ANDed. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". The + requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: MatchLabelKeys is a set of pod label keys + to select the pods over which spreading will be calculated. + The keys are used to lookup values from the incoming + pod labels, those key-value labels are ANDed with + labelSelector to select the group of existing pods + over which spreading will be calculated for the incoming + pod. Keys that don't exist in the incoming pod labels + will be ignored. A null or empty list means only match + against labelSelector. + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + description: 'MaxSkew describes the degree to which + pods may be unevenly distributed. When `whenUnsatisfiable=DoNotSchedule`, + it is the maximum permitted difference between the + number of matching pods in the target topology and + the global minimum. The global minimum is the minimum + number of matching pods in an eligible domain or zero + if the number of eligible domains is less than MinDomains. + For example, in a 3-zone cluster, MaxSkew is set to + 1, and pods with the same labelSelector spread as + 2/2/1: In this case, the global minimum is 1. | zone1 + | zone2 | zone3 | | P P | P P | P | - if MaxSkew + is 1, incoming pod can only be scheduled to zone3 + to become 2/2/2; scheduling it onto zone1(zone2) would + make the ActualSkew(3-1) on zone1(zone2) violate MaxSkew(1). + - if MaxSkew is 2, incoming pod can be scheduled onto + any zone. When `whenUnsatisfiable=ScheduleAnyway`, + it is used to give higher precedence to topologies + that satisfy it. It''s a required field. Default value + is 1 and 0 is not allowed.' + format: int32 + type: integer + minDomains: + description: "MinDomains indicates a minimum number + of eligible domains. When the number of eligible domains + with matching topology keys is less than minDomains, + Pod Topology Spread treats \"global minimum\" as 0, + and then the calculation of Skew is performed. And + when the number of eligible domains with matching + topology keys equals or greater than minDomains, this + value has no effect on scheduling. As a result, when + the number of eligible domains is less than minDomains, + scheduler won't schedule more than maxSkew Pods to + those domains. If value is nil, the constraint behaves + as if MinDomains is equal to 1. Valid values are integers + greater than 0. When value is not nil, WhenUnsatisfiable + must be DoNotSchedule. \n For example, in a 3-zone + cluster, MaxSkew is set to 2, MinDomains is set to + 5 and pods with the same labelSelector spread as 2/2/2: + | zone1 | zone2 | zone3 | | P P | P P | P P | + The number of domains is less than 5(MinDomains), + so \"global minimum\" is treated as 0. In this situation, + new pod with the same labelSelector cannot be scheduled, + because computed skew will be 3(3 - 0) if new Pod + is scheduled to any of the three zones, it will violate + MaxSkew. \n This is a beta field and requires the + MinDomainsInPodTopologySpread feature gate to be enabled + (enabled by default)." + format: int32 + type: integer + nodeAffinityPolicy: + description: "NodeAffinityPolicy indicates how we will + treat Pod's nodeAffinity/nodeSelector when calculating + pod topology spread skew. Options are: - Honor: only + nodes matching nodeAffinity/nodeSelector are included + in the calculations. - Ignore: nodeAffinity/nodeSelector + are ignored. All nodes are included in the calculations. + \n If this value is nil, the behavior is equivalent + to the Honor policy. This is a alpha-level feature + enabled by the NodeInclusionPolicyInPodTopologySpread + feature flag." + type: string + nodeTaintsPolicy: + description: "NodeTaintsPolicy indicates how we will + treat node taints when calculating pod topology spread + skew. Options are: - Honor: nodes without taints, + along with tainted nodes for which the incoming pod + has a toleration, are included. - Ignore: node taints + are ignored. All nodes are included. \n If this value + is nil, the behavior is equivalent to the Ignore policy. + This is a alpha-level feature enabled by the NodeInclusionPolicyInPodTopologySpread + feature flag." + type: string + topologyKey: + description: TopologyKey is the key of node labels. + Nodes that have a label with this key and identical + values are considered to be in the same topology. + We consider each as a "bucket", and try + to put balanced number of pods into each bucket. We + define a domain as a particular instance of a topology. + Also, we define an eligible domain as a domain whose + nodes meet the requirements of nodeAffinityPolicy + and nodeTaintsPolicy. e.g. If TopologyKey is "kubernetes.io/hostname", + each Node is a domain of that topology. And, if TopologyKey + is "topology.kubernetes.io/zone", each zone is a domain + of that topology. It's a required field. + type: string + whenUnsatisfiable: + description: 'WhenUnsatisfiable indicates how to deal + with a pod if it doesn''t satisfy the spread constraint. + - DoNotSchedule (default) tells the scheduler not + to schedule it. - ScheduleAnyway tells the scheduler + to schedule the pod in any location, but giving higher + precedence to topologies that would help reduce the + skew. A constraint is considered "Unsatisfiable" for + an incoming pod if and only if every possible node + assignment for that pod would violate "MaxSkew" on + some topology. For example, in a 3-zone cluster, MaxSkew + is set to 1, and pods with the same labelSelector + spread as 3/1/1: | zone1 | zone2 | zone3 | | P P P + | P | P | If WhenUnsatisfiable is set to DoNotSchedule, + incoming pod can only be scheduled to zone2(zone3) + to become 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) + satisfies MaxSkew(1). In other words, the cluster + can still be imbalanced, but scheduler won''t make + it *more* imbalanced. It''s a required field.' + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + x-kubernetes-list-map-keys: + - topologyKey + - whenUnsatisfiable + x-kubernetes-list-type: map + volumes: + description: 'List of volumes that can be mounted by containers + belonging to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes' + items: + description: Volume represents a named volume in a pod that + may be accessed by any container in the pod. + properties: + awsElasticBlockStore: + description: 'awsElasticBlockStore represents an AWS + Disk resource that is attached to a kubelet''s host + machine and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + properties: + fsType: + description: 'fsType is the filesystem type of the + volume that you want to mount. Tip: Ensure that + the filesystem type is supported by the host operating + system. Examples: "ext4", "xfs", "ntfs". Implicitly + inferred to be "ext4" if unspecified. More info: + https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + partition: + description: 'partition is the partition in the + volume that you want to mount. If omitted, the + default is to mount by volume name. Examples: + For volume /dev/sda1, you specify the partition + as "1". Similarly, the volume partition for /dev/sda + is "0" (or you can leave the property empty).' + format: int32 + type: integer + readOnly: + description: 'readOnly value true will force the + readOnly setting in VolumeMounts. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: boolean + volumeID: + description: 'volumeID is unique ID of the persistent + disk resource in AWS (Amazon EBS volume). More + info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: string + required: + - volumeID + type: object + azureDisk: + description: azureDisk represents an Azure Data Disk + mount on the host and bind mount to the pod. + properties: + cachingMode: + description: 'cachingMode is the Host Caching mode: + None, Read Only, Read Write.' + type: string + diskName: + description: diskName is the Name of the data disk + in the blob storage + type: string + diskURI: + description: diskURI is the URI of data disk in + the blob storage + type: string + fsType: + description: fsType is Filesystem type to mount. + Must be a filesystem type supported by the host + operating system. Ex. "ext4", "xfs", "ntfs". Implicitly + inferred to be "ext4" if unspecified. + type: string + kind: + description: 'kind expected values are Shared: multiple + blob disks per storage account Dedicated: single + blob disk per storage account Managed: azure + managed data disk (only in managed availability + set). defaults to shared' + type: string + readOnly: + description: readOnly Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + description: azureFile represents an Azure File Service + mount on the host and bind mount to the pod. + properties: + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + secretName: + description: secretName is the name of secret that + contains Azure Storage Account Name and Key + type: string + shareName: + description: shareName is the azure share Name + type: string + required: + - secretName + - shareName + type: object + cephfs: + description: cephFS represents a Ceph FS mount on the + host that shares a pod's lifetime + properties: + monitors: + description: 'monitors is Required: Monitors is + a collection of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + items: + type: string + type: array + path: + description: 'path is Optional: Used as the mounted + root, rather than the full Ceph tree, default + is /' + type: string + readOnly: + description: 'readOnly is Optional: Defaults to + false (read/write). ReadOnly here will force the + ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: boolean + secretFile: + description: 'secretFile is Optional: SecretFile + is the path to key ring for User, default is /etc/ceph/user.secret + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + secretRef: + description: 'secretRef is Optional: SecretRef is + reference to the authentication secret for User, + default is empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is optional: User is the rados + user name, default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + required: + - monitors + type: object + cinder: + description: 'cinder represents a cinder volume attached + and mounted on kubelets host machine. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + properties: + fsType: + description: 'fsType is the filesystem type to mount. + Must be a filesystem type supported by the host + operating system. Examples: "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if unspecified. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + readOnly: + description: 'readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: boolean + secretRef: + description: 'secretRef is optional: points to a + secret object containing parameters used to connect + to OpenStack.' + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + description: 'volumeID used to identify the volume + in cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + required: + - volumeID + type: object + configMap: + description: configMap represents a configMap that should + populate this volume + properties: + defaultMode: + description: 'defaultMode is optional: mode bits + used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or + a decimal value between 0 and 511. YAML accepts + both octal and decimal values, JSON requires decimal + values for mode bits. Defaults to 0644. Directories + within the path are not affected by this setting. + This might be in conflict with other options that + affect the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + items: + description: items if unspecified, each key-value + pair in the Data field of the referenced ConfigMap + will be projected into the volume as a file whose + name is the key and content is the value. If specified, + the listed keys will be projected into the specified + paths, and unlisted keys will not be present. + If a key is specified which is not present in + the ConfigMap, the volume setup will error unless + it is marked optional. Paths must be relative + and may not contain the '..' path or start with + '..'. + items: + description: Maps a string key to a path within + a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode bits + used to set permissions on this file. Must + be an octal value between 0000 and 0777 + or a decimal value between 0 and 511. YAML + accepts both octal and decimal values, JSON + requires decimal values for mode bits. If + not specified, the volume defaultMode will + be used. This might be in conflict with + other options that affect the file mode, + like fsGroup, and the result can be other + mode bits set.' + format: int32 + type: integer + path: + description: path is the relative path of + the file to map the key to. May not be an + absolute path. May not contain the path + element '..'. May not start with the string + '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: optional specify whether the ConfigMap + or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + description: csi (Container Storage Interface) represents + ephemeral storage that is handled by certain external + CSI drivers (Beta feature). + properties: + driver: + description: driver is the name of the CSI driver + that handles this volume. Consult with your admin + for the correct name as registered in the cluster. + type: string + fsType: + description: fsType to mount. Ex. "ext4", "xfs", + "ntfs". If not provided, the empty value is passed + to the associated CSI driver which will determine + the default filesystem to apply. + type: string + nodePublishSecretRef: + description: nodePublishSecretRef is a reference + to the secret object containing sensitive information + to pass to the CSI driver to complete the CSI + NodePublishVolume and NodeUnpublishVolume calls. + This field is optional, and may be empty if no + secret is required. If the secret object contains + more than one secret, all secret references are + passed. + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + description: readOnly specifies a read-only configuration + for the volume. Defaults to false (read/write). + type: boolean + volumeAttributes: + additionalProperties: + type: string + description: volumeAttributes stores driver-specific + properties that are passed to the CSI driver. + Consult your driver's documentation for supported + values. + type: object + required: + - driver + type: object + downwardAPI: + description: downwardAPI represents downward API about + the pod that should populate this volume + properties: + defaultMode: + description: 'Optional: mode bits to use on created + files by default. Must be a Optional: mode bits + used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or + a decimal value between 0 and 511. YAML accepts + both octal and decimal values, JSON requires decimal + values for mode bits. Defaults to 0644. Directories + within the path are not affected by this setting. + This might be in conflict with other options that + affect the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + items: + description: Items is a list of downward API volume + file + items: + description: DownwardAPIVolumeFile represents + information to create the file containing the + pod field + properties: + fieldRef: + description: 'Required: Selects a field of + the pod: only annotations, labels, name + and namespace are supported.' + properties: + apiVersion: + description: Version of the schema the + FieldPath is written in terms of, defaults + to "v1". + type: string + fieldPath: + description: Path of the field to select + in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode bits used to + set permissions on this file, must be an + octal value between 0000 and 0777 or a decimal + value between 0 and 511. YAML accepts both + octal and decimal values, JSON requires + decimal values for mode bits. If not specified, + the volume defaultMode will be used. This + might be in conflict with other options + that affect the file mode, like fsGroup, + and the result can be other mode bits set.' + format: int32 + type: integer + path: + description: 'Required: Path is the relative + path name of the file to be created. Must + not be absolute or contain the ''..'' path. + Must be utf-8 encoded. The first item of + the relative path must not start with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource of the container: + only resources limits and requests (limits.cpu, + limits.memory, requests.cpu and requests.memory) + are currently supported.' + properties: + containerName: + description: 'Container name: required + for volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format + of the exposed resources, defaults to + "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + emptyDir: + description: 'emptyDir represents a temporary directory + that shares a pod''s lifetime. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + properties: + medium: + description: 'medium represents what type of storage + medium should back this directory. The default + is "" which means to use the node''s default medium. + Must be an empty string (default) or Memory. More + info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + description: 'sizeLimit is the total amount of local + storage required for this EmptyDir volume. The + size limit is also applicable for memory medium. + The maximum usage on memory medium EmptyDir would + be the minimum value between the SizeLimit specified + here and the sum of memory limits of all containers + in a pod. The default is nil which means that + the limit is undefined. More info: http://kubernetes.io/docs/user-guide/volumes#emptydir' + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + description: "ephemeral represents a volume that is + handled by a cluster storage driver. The volume's + lifecycle is tied to the pod that defines it - it + will be created before the pod starts, and deleted + when the pod is removed. \n Use this if: a) the volume + is only needed while the pod runs, b) features of + normal volumes like restoring from snapshot or capacity + tracking are needed, c) the storage driver is specified + through a storage class, and d) the storage driver + supports dynamic volume provisioning through a PersistentVolumeClaim + (see EphemeralVolumeSource for more information on + the connection between this volume type and PersistentVolumeClaim). + \n Use PersistentVolumeClaim or one of the vendor-specific + APIs for volumes that persist for longer than the + lifecycle of an individual pod. \n Use CSI for light-weight + local ephemeral volumes if the CSI driver is meant + to be used that way - see the documentation of the + driver for more information. \n A pod can use both + types of ephemeral volumes and persistent volumes + at the same time." + properties: + volumeClaimTemplate: + description: "Will be used to create a stand-alone + PVC to provision the volume. The pod in which + this EphemeralVolumeSource is embedded will be + the owner of the PVC, i.e. the PVC will be deleted + together with the pod. The name of the PVC will + be `-` where `` + is the name from the `PodSpec.Volumes` array entry. + Pod validation will reject the pod if the concatenated + name is not valid for a PVC (for example, too + long). \n An existing PVC with that name that + is not owned by the pod will *not* be used for + the pod to avoid using an unrelated volume by + mistake. Starting the pod is then blocked until + the unrelated PVC is removed. If such a pre-created + PVC is meant to be used by the pod, the PVC has + to updated with an owner reference to the pod + once the pod exists. Normally this should not + be necessary, but it may be useful when manually + reconstructing a broken cluster. \n This field + is read-only and no changes will be made by Kubernetes + to the PVC after it has been created. \n Required, + must not be nil." + properties: + metadata: + description: May contain labels and annotations + that will be copied into the PVC when creating + it. No other fields are allowed and will be + rejected during validation. + type: object + spec: + description: The specification for the PersistentVolumeClaim. + The entire content is copied unchanged into + the PVC that gets created from this template. + The same fields as in a PersistentVolumeClaim + are also valid here. + properties: + accessModes: + description: 'accessModes contains the desired + access modes the volume should have. More + info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1' + items: + type: string + type: array + dataSource: + description: 'dataSource field can be used + to specify either: * An existing VolumeSnapshot + object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external controller + can support the specified data source, + it will create a new volume based on the + contents of the specified data source. + If the AnyVolumeDataSource feature gate + is enabled, this field will always have + the same contents as the DataSourceRef + field.' + properties: + apiGroup: + description: APIGroup is the group for + the resource being referenced. If + APIGroup is not specified, the specified + Kind must be in the core API group. + For any other third-party types, APIGroup + is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: 'dataSourceRef specifies the + object from which to populate the volume + with data, if a non-empty volume is desired. + This may be any local object from a non-empty + API group (non core object) or a PersistentVolumeClaim + object. When this field is specified, + volume binding will only succeed if the + type of the specified object matches some + installed volume populator or dynamic + provisioner. This field will replace the + functionality of the DataSource field + and as such if both fields are non-empty, + they must have the same value. For backwards + compatibility, both fields (DataSource + and DataSourceRef) will be set to the + same value automatically if one of them + is empty and the other is non-empty. There + are two important differences between + DataSource and DataSourceRef: * While + DataSource only allows two specific types + of objects, DataSourceRef allows any non-core + object, as well as PersistentVolumeClaim + objects. * While DataSource ignores disallowed + values (dropping them), DataSourceRef + preserves all values, and generates an + error if a disallowed value is specified. + (Beta) Using this field requires the AnyVolumeDataSource + feature gate to be enabled.' + properties: + apiGroup: + description: APIGroup is the group for + the resource being referenced. If + APIGroup is not specified, the specified + Kind must be in the core API group. + For any other third-party types, APIGroup + is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + resources: + description: 'resources represents the minimum + resources the volume should have. If RecoverVolumeExpansionFailure + feature is enabled users are allowed to + specify resource requirements that are + lower than previous value but must still + be higher than capacity recorded in the + status field of the claim. More info: + https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources' + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum + amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the + minimum amount of compute resources + required. If Requests is omitted for + a container, it defaults to Limits + if that is explicitly specified, otherwise + to an implementation-defined value. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + selector: + description: selector is a label query over + volumes to consider for binding. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: operator represents + a key's relationship to a set + of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array + of string values. If the operator + is In or NotIn, the values array + must be non-empty. If the operator + is Exists or DoesNotExist, the + values array must be empty. + This array is replaced during + a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of + {key,value} pairs. A single {key,value} + in the matchLabels map is equivalent + to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are + ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: 'storageClassName is the name + of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' + type: string + volumeMode: + description: volumeMode defines what type + of volume is required by the claim. Value + of Filesystem is implied when not included + in claim spec. + type: string + volumeName: + description: volumeName is the binding reference + to the PersistentVolume backing this claim. + type: string + type: object + required: + - spec + type: object + type: object + fc: + description: fc represents a Fibre Channel resource + that is attached to a kubelet's host machine and then + exposed to the pod. + properties: + fsType: + description: 'fsType is the filesystem type to mount. + Must be a filesystem type supported by the host + operating system. Ex. "ext4", "xfs", "ntfs". Implicitly + inferred to be "ext4" if unspecified. TODO: how + do we prevent errors in the filesystem from compromising + the machine' + type: string + lun: + description: 'lun is Optional: FC target lun number' + format: int32 + type: integer + readOnly: + description: 'readOnly is Optional: Defaults to + false (read/write). ReadOnly here will force the + ReadOnly setting in VolumeMounts.' + type: boolean + targetWWNs: + description: 'targetWWNs is Optional: FC target + worldwide names (WWNs)' + items: + type: string + type: array + wwids: + description: 'wwids Optional: FC volume world wide + identifiers (wwids) Either wwids or combination + of targetWWNs and lun must be set, but not both + simultaneously.' + items: + type: string + type: array + type: object + flexVolume: + description: flexVolume represents a generic volume + resource that is provisioned/attached using an exec + based plugin. + properties: + driver: + description: driver is the name of the driver to + use for this volume. + type: string + fsType: + description: fsType is the filesystem type to mount. + Must be a filesystem type supported by the host + operating system. Ex. "ext4", "xfs", "ntfs". The + default filesystem depends on FlexVolume script. + type: string + options: + additionalProperties: + type: string + description: 'options is Optional: this field holds + extra command options if any.' + type: object + readOnly: + description: 'readOnly is Optional: defaults to + false (read/write). ReadOnly here will force the + ReadOnly setting in VolumeMounts.' + type: boolean + secretRef: + description: 'secretRef is Optional: secretRef is + reference to the secret object containing sensitive + information to pass to the plugin scripts. This + may be empty if no secret object is specified. + If the secret object contains more than one secret, + all secrets are passed to the plugin scripts.' + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + description: flocker represents a Flocker volume attached + to a kubelet's host machine. This depends on the Flocker + control service being running + properties: + datasetName: + description: datasetName is Name of the dataset + stored as metadata -> name on the dataset for + Flocker should be considered as deprecated + type: string + datasetUUID: + description: datasetUUID is the UUID of the dataset. + This is unique identifier of a Flocker dataset + type: string + type: object + gcePersistentDisk: + description: 'gcePersistentDisk represents a GCE Disk + resource that is attached to a kubelet''s host machine + and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + properties: + fsType: + description: 'fsType is filesystem type of the volume + that you want to mount. Tip: Ensure that the filesystem + type is supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + partition: + description: 'partition is the partition in the + volume that you want to mount. If omitted, the + default is to mount by volume name. Examples: + For volume /dev/sda1, you specify the partition + as "1". Similarly, the volume partition for /dev/sda + is "0" (or you can leave the property empty). + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + format: int32 + type: integer + pdName: + description: 'pdName is unique name of the PD resource + in GCE. Used to identify the disk in GCE. More + info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: string + readOnly: + description: 'readOnly here will force the ReadOnly + setting in VolumeMounts. Defaults to false. More + info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: boolean + required: + - pdName + type: object + gitRepo: + description: 'gitRepo represents a git repository at + a particular revision. DEPRECATED: GitRepo is deprecated. + To provision a container with a git repo, mount an + EmptyDir into an InitContainer that clones the repo + using git, then mount the EmptyDir into the Pod''s + container.' + properties: + directory: + description: directory is the target directory name. + Must not contain or start with '..'. If '.' is + supplied, the volume directory will be the git + repository. Otherwise, if specified, the volume + will contain the git repository in the subdirectory + with the given name. + type: string + repository: + description: repository is the URL + type: string + revision: + description: revision is the commit hash for the + specified revision. + type: string + required: + - repository + type: object + glusterfs: + description: 'glusterfs represents a Glusterfs mount + on the host that shares a pod''s lifetime. More info: + https://examples.k8s.io/volumes/glusterfs/README.md' + properties: + endpoints: + description: 'endpoints is the endpoint name that + details Glusterfs topology. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + path: + description: 'path is the Glusterfs volume path. + More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + readOnly: + description: 'readOnly here will force the Glusterfs + volume to be mounted with read-only permissions. + Defaults to false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: boolean + required: + - endpoints + - path + type: object + hostPath: + description: 'hostPath represents a pre-existing file + or directory on the host machine that is directly + exposed to the container. This is generally used for + system agents or other privileged things that are + allowed to see the host machine. Most containers will + NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + --- TODO(jonesdl) We need to restrict who can use + host directory mounts and who can/can not mount host + directories as read/write.' + properties: + path: + description: 'path of the directory on the host. + If the path is a symlink, it will follow the link + to the real path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + type: + description: 'type for HostPath Volume Defaults + to "" More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + required: + - path + type: object + iscsi: + description: 'iscsi represents an ISCSI Disk resource + that is attached to a kubelet''s host machine and + then exposed to the pod. More info: https://examples.k8s.io/volumes/iscsi/README.md' + properties: + chapAuthDiscovery: + description: chapAuthDiscovery defines whether support + iSCSI Discovery CHAP authentication + type: boolean + chapAuthSession: + description: chapAuthSession defines whether support + iSCSI Session CHAP authentication + type: boolean + fsType: + description: 'fsType is the filesystem type of the + volume that you want to mount. Tip: Ensure that + the filesystem type is supported by the host operating + system. Examples: "ext4", "xfs", "ntfs". Implicitly + inferred to be "ext4" if unspecified. More info: + https://kubernetes.io/docs/concepts/storage/volumes#iscsi + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + initiatorName: + description: initiatorName is the custom iSCSI Initiator + Name. If initiatorName is specified with iscsiInterface + simultaneously, new iSCSI interface : will be created for the connection. + type: string + iqn: + description: iqn is the target iSCSI Qualified Name. + type: string + iscsiInterface: + description: iscsiInterface is the interface Name + that uses an iSCSI transport. Defaults to 'default' + (tcp). + type: string + lun: + description: lun represents iSCSI Target Lun number. + format: int32 + type: integer + portals: + description: portals is the iSCSI Target Portal + List. The portal is either an IP or ip_addr:port + if the port is other than default (typically TCP + ports 860 and 3260). + items: + type: string + type: array + readOnly: + description: readOnly here will force the ReadOnly + setting in VolumeMounts. Defaults to false. + type: boolean + secretRef: + description: secretRef is the CHAP Secret for iSCSI + target and initiator authentication + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + description: targetPortal is iSCSI Target Portal. + The Portal is either an IP or ip_addr:port if + the port is other than default (typically TCP + ports 860 and 3260). + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + description: 'name of the volume. Must be a DNS_LABEL + and unique within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + nfs: + description: 'nfs represents an NFS mount on the host + that shares a pod''s lifetime More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + properties: + path: + description: 'path that is exported by the NFS server. + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + readOnly: + description: 'readOnly here will force the NFS export + to be mounted with read-only permissions. Defaults + to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: boolean + server: + description: 'server is the hostname or IP address + of the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + description: 'persistentVolumeClaimVolumeSource represents + a reference to a PersistentVolumeClaim in the same + namespace. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + properties: + claimName: + description: 'claimName is the name of a PersistentVolumeClaim + in the same namespace as the pod using this volume. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + type: string + readOnly: + description: readOnly Will force the ReadOnly setting + in VolumeMounts. Default false. + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + description: photonPersistentDisk represents a PhotonController + persistent disk attached and mounted on kubelets host + machine + properties: + fsType: + description: fsType is the filesystem type to mount. + Must be a filesystem type supported by the host + operating system. Ex. "ext4", "xfs", "ntfs". Implicitly + inferred to be "ext4" if unspecified. + type: string + pdID: + description: pdID is the ID that identifies Photon + Controller persistent disk + type: string + required: + - pdID + type: object + portworxVolume: + description: portworxVolume represents a portworx volume + attached and mounted on kubelets host machine + properties: + fsType: + description: fSType represents the filesystem type + to mount Must be a filesystem type supported by + the host operating system. Ex. "ext4", "xfs". + Implicitly inferred to be "ext4" if unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + volumeID: + description: volumeID uniquely identifies a Portworx + volume + type: string + required: + - volumeID + type: object + projected: + description: projected items for all in one resources + secrets, configmaps, and downward API + properties: + defaultMode: + description: defaultMode are the mode bits used + to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or + a decimal value between 0 and 511. YAML accepts + both octal and decimal values, JSON requires decimal + values for mode bits. Directories within the path + are not affected by this setting. This might be + in conflict with other options that affect the + file mode, like fsGroup, and the result can be + other mode bits set. + format: int32 + type: integer + sources: + description: sources is the list of volume projections + items: + description: Projection that may be projected + along with other supported volume types + properties: + configMap: + description: configMap information about the + configMap data to project + properties: + items: + description: items if unspecified, each + key-value pair in the Data field of + the referenced ConfigMap will be projected + into the volume as a file whose name + is the key and content is the value. + If specified, the listed keys will be + projected into the specified paths, + and unlisted keys will not be present. + If a key is specified which is not present + in the ConfigMap, the volume setup will + error unless it is marked optional. + Paths must be relative and may not contain + the '..' path or start with '..'. + items: + description: Maps a string key to a + path within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: + mode bits used to set permissions + on this file. Must be an octal + value between 0000 and 0777 or + a decimal value between 0 and + 511. YAML accepts both octal and + decimal values, JSON requires + decimal values for mode bits. + If not specified, the volume defaultMode + will be used. This might be in + conflict with other options that + affect the file mode, like fsGroup, + and the result can be other mode + bits set.' + format: int32 + type: integer + path: + description: path is the relative + path of the file to map the key + to. May not be an absolute path. + May not contain the path element + '..'. May not start with the string + '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: optional specify whether + the ConfigMap or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + description: downwardAPI information about + the downwardAPI data to project + properties: + items: + description: Items is a list of DownwardAPIVolume + file + items: + description: DownwardAPIVolumeFile represents + information to create the file containing + the pod field + properties: + fieldRef: + description: 'Required: Selects + a field of the pod: only annotations, + labels, name and namespace are + supported.' + properties: + apiVersion: + description: Version of the + schema the FieldPath is written + in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field + to select in the specified + API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode bits + used to set permissions on this + file, must be an octal value between + 0000 and 0777 or a decimal value + between 0 and 511. YAML accepts + both octal and decimal values, + JSON requires decimal values for + mode bits. If not specified, the + volume defaultMode will be used. + This might be in conflict with + other options that affect the + file mode, like fsGroup, and the + result can be other mode bits + set.' + format: int32 + type: integer + path: + description: 'Required: Path is the + relative path name of the file + to be created. Must not be absolute + or contain the ''..'' path. Must + be utf-8 encoded. The first item + of the relative path must not + start with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource + of the container: only resources + limits and requests (limits.cpu, + limits.memory, requests.cpu and + requests.memory) are currently + supported.' + properties: + containerName: + description: 'Container name: + required for volumes, optional + for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output + format of the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource + to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + secret: + description: secret information about the + secret data to project + properties: + items: + description: items if unspecified, each + key-value pair in the Data field of + the referenced Secret will be projected + into the volume as a file whose name + is the key and content is the value. + If specified, the listed keys will be + projected into the specified paths, + and unlisted keys will not be present. + If a key is specified which is not present + in the Secret, the volume setup will + error unless it is marked optional. + Paths must be relative and may not contain + the '..' path or start with '..'. + items: + description: Maps a string key to a + path within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: + mode bits used to set permissions + on this file. Must be an octal + value between 0000 and 0777 or + a decimal value between 0 and + 511. YAML accepts both octal and + decimal values, JSON requires + decimal values for mode bits. + If not specified, the volume defaultMode + will be used. This might be in + conflict with other options that + affect the file mode, like fsGroup, + and the result can be other mode + bits set.' + format: int32 + type: integer + path: + description: path is the relative + path of the file to map the key + to. May not be an absolute path. + May not contain the path element + '..'. May not start with the string + '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: optional field specify whether + the Secret or its key must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + description: serviceAccountToken is information + about the serviceAccountToken data to project + properties: + audience: + description: audience is the intended + audience of the token. A recipient of + a token must identify itself with an + identifier specified in the audience + of the token, and otherwise should reject + the token. The audience defaults to + the identifier of the apiserver. + type: string + expirationSeconds: + description: expirationSeconds is the + requested duration of validity of the + service account token. As the token + approaches expiration, the kubelet volume + plugin will proactively rotate the service + account token. The kubelet will start + trying to rotate the token if the token + is older than 80 percent of its time + to live or if the token is older than + 24 hours.Defaults to 1 hour and must + be at least 10 minutes. + format: int64 + type: integer + path: + description: path is the path relative + to the mount point of the file to project + the token into. + type: string + required: + - path + type: object + type: object + type: array + type: object + quobyte: + description: quobyte represents a Quobyte mount on the + host that shares a pod's lifetime + properties: + group: + description: group to map volume access to Default + is no group + type: string + readOnly: + description: readOnly here will force the Quobyte + volume to be mounted with read-only permissions. + Defaults to false. + type: boolean + registry: + description: registry represents a single or multiple + Quobyte Registry services specified as a string + as host:port pair (multiple entries are separated + with commas) which acts as the central registry + for volumes + type: string + tenant: + description: tenant owning the given Quobyte volume + in the Backend Used with dynamically provisioned + Quobyte volumes, value is set by the plugin + type: string + user: + description: user to map volume access to Defaults + to serivceaccount user + type: string + volume: + description: volume is a string that references + an already created Quobyte volume by name. + type: string + required: + - registry + - volume + type: object + rbd: + description: 'rbd represents a Rados Block Device mount + on the host that shares a pod''s lifetime. More info: + https://examples.k8s.io/volumes/rbd/README.md' + properties: + fsType: + description: 'fsType is the filesystem type of the + volume that you want to mount. Tip: Ensure that + the filesystem type is supported by the host operating + system. Examples: "ext4", "xfs", "ntfs". Implicitly + inferred to be "ext4" if unspecified. More info: + https://kubernetes.io/docs/concepts/storage/volumes#rbd + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + image: + description: 'image is the rados image name. More + info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + keyring: + description: 'keyring is the path to key ring for + RBDUser. Default is /etc/ceph/keyring. More info: + https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + monitors: + description: 'monitors is a collection of Ceph monitors. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + items: + type: string + type: array + pool: + description: 'pool is the rados pool name. Default + is rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + readOnly: + description: 'readOnly here will force the ReadOnly + setting in VolumeMounts. Defaults to false. More + info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: boolean + secretRef: + description: 'secretRef is name of the authentication + secret for RBDUser. If provided overrides keyring. + Default is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is the rados user name. Default + is admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + required: + - image + - monitors + type: object + scaleIO: + description: scaleIO represents a ScaleIO persistent + volume attached and mounted on Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem type to mount. + Must be a filesystem type supported by the host + operating system. Ex. "ext4", "xfs", "ntfs". Default + is "xfs". + type: string + gateway: + description: gateway is the host address of the + ScaleIO API Gateway. + type: string + protectionDomain: + description: protectionDomain is the name of the + ScaleIO Protection Domain for the configured storage. + type: string + readOnly: + description: readOnly Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + secretRef: + description: secretRef references to the secret + for ScaleIO user and other sensitive information. + If this is not provided, Login operation will + fail. + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + description: sslEnabled Flag enable/disable SSL + communication with Gateway, default false + type: boolean + storageMode: + description: storageMode indicates whether the storage + for a volume should be ThickProvisioned or ThinProvisioned. + Default is ThinProvisioned. + type: string + storagePool: + description: storagePool is the ScaleIO Storage + Pool associated with the protection domain. + type: string + system: + description: system is the name of the storage system + as configured in ScaleIO. + type: string + volumeName: + description: volumeName is the name of a volume + already created in the ScaleIO system that is + associated with this volume source. + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + description: 'secret represents a secret that should + populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + properties: + defaultMode: + description: 'defaultMode is Optional: mode bits + used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or + a decimal value between 0 and 511. YAML accepts + both octal and decimal values, JSON requires decimal + values for mode bits. Defaults to 0644. Directories + within the path are not affected by this setting. + This might be in conflict with other options that + affect the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + items: + description: items If unspecified, each key-value + pair in the Data field of the referenced Secret + will be projected into the volume as a file whose + name is the key and content is the value. If specified, + the listed keys will be projected into the specified + paths, and unlisted keys will not be present. + If a key is specified which is not present in + the Secret, the volume setup will error unless + it is marked optional. Paths must be relative + and may not contain the '..' path or start with + '..'. + items: + description: Maps a string key to a path within + a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode bits + used to set permissions on this file. Must + be an octal value between 0000 and 0777 + or a decimal value between 0 and 511. YAML + accepts both octal and decimal values, JSON + requires decimal values for mode bits. If + not specified, the volume defaultMode will + be used. This might be in conflict with + other options that affect the file mode, + like fsGroup, and the result can be other + mode bits set.' + format: int32 + type: integer + path: + description: path is the relative path of + the file to map the key to. May not be an + absolute path. May not contain the path + element '..'. May not start with the string + '..'. + type: string + required: + - key + - path + type: object + type: array + optional: + description: optional field specify whether the + Secret or its keys must be defined + type: boolean + secretName: + description: 'secretName is the name of the secret + in the pod''s namespace to use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + type: string + type: object + storageos: + description: storageOS represents a StorageOS volume + attached and mounted on Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem type to mount. + Must be a filesystem type supported by the host + operating system. Ex. "ext4", "xfs", "ntfs". Implicitly + inferred to be "ext4" if unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + secretRef: + description: secretRef specifies the secret to use + for obtaining the StorageOS API credentials. If + not specified, default values will be attempted. + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + description: volumeName is the human-readable name + of the StorageOS volume. Volume names are only + unique within a namespace. + type: string + volumeNamespace: + description: volumeNamespace specifies the scope + of the volume within StorageOS. If no namespace + is specified then the Pod's namespace will be + used. This allows the Kubernetes name scoping + to be mirrored within StorageOS for tighter integration. + Set VolumeName to any name to override the default + behaviour. Set to "default" if you are not using + namespaces within StorageOS. Namespaces that do + not pre-exist within StorageOS will be created. + type: string + type: object + vsphereVolume: + description: vsphereVolume represents a vSphere volume + attached and mounted on kubelets host machine + properties: + fsType: + description: fsType is filesystem type to mount. + Must be a filesystem type supported by the host + operating system. Ex. "ext4", "xfs", "ntfs". Implicitly + inferred to be "ext4" if unspecified. + type: string + storagePolicyID: + description: storagePolicyID is the storage Policy + Based Management (SPBM) profile ID associated + with the StoragePolicyName. + type: string + storagePolicyName: + description: storagePolicyName is the storage Policy + Based Management (SPBM) profile name. + type: string + volumePath: + description: volumePath is the path that identifies + vSphere volume vmdk + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + required: + - containers + type: object + type: object + terraformVersion: + type: string + type: object + status: + description: TerraformLayerStatus defines the observed state of TerraformLayer + properties: + conditions: + items: + description: "Condition contains details for one aspect of the current + state of this API Resource. --- This struct is intended for direct + use as an array at the field path .status.conditions. For example, + \n type FooStatus struct{ // Represents the observations of a + foo's current state. // Known .status.conditions.type are: \"Available\", + \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge + // +listType=map // +listMapKey=type Conditions []metav1.Condition + `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" + protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition + transitioned from one status to another. This should be when + the underlying condition changed. If that is not known, then + using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: message is a human readable message indicating + details about the transition. This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: observedGeneration represents the .metadata.generation + that the condition was set based upon. For instance, if .metadata.generation + is currently 12, but the .status.conditions[x].observedGeneration + is 9, the condition is out of date with respect to the current + state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: reason contains a programmatic identifier indicating + the reason for the condition's last transition. Producers + of specific condition types may define expected values and + meanings for this field, and whether the values are considered + a guaranteed API. The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + --- Many .condition.type values are consistent across resources + like Available, but because arbitrary conditions can be useful + (see .node.status.conditions), the ability to deconflict is + important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/config.terraform.padok.cloud_terraformrepositories.yaml b/config/crd/bases/config.terraform.padok.cloud_terraformrepositories.yaml new file mode 100644 index 00000000..bc621bc6 --- /dev/null +++ b/config/crd/bases/config.terraform.padok.cloud_terraformrepositories.yaml @@ -0,0 +1,51 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.10.0 + creationTimestamp: null + name: terraformrepositories.config.terraform.padok.cloud +spec: + group: config.terraform.padok.cloud + names: + kind: TerraformRepository + listKind: TerraformRepositoryList + plural: terraformrepositories + singular: terraformrepository + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: TerraformRepository is the Schema for the terraformrepositories + API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: TerraformRepositorySpec defines the desired state of TerraformRepository + properties: + foo: + description: Foo is an example field of TerraformRepository. Edit + terraformrepository_types.go to remove/update + type: string + type: object + status: + description: TerraformRepositoryStatus defines the observed state of TerraformRepository + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml new file mode 100644 index 00000000..693979b6 --- /dev/null +++ b/config/rbac/role.yaml @@ -0,0 +1,59 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + creationTimestamp: null + name: manager-role +rules: +- apiGroups: + - config.terraform.padok.cloud + resources: + - terraformlayers + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - config.terraform.padok.cloud + resources: + - terraformlayers/finalizers + verbs: + - update +- apiGroups: + - config.terraform.padok.cloud + resources: + - terraformlayers/status + verbs: + - get + - patch + - update +- apiGroups: + - config.terraform.padok.cloud + resources: + - terraformrepositories + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - config.terraform.padok.cloud + resources: + - terraformrepositories/finalizers + verbs: + - update +- apiGroups: + - config.terraform.padok.cloud + resources: + - terraformrepositories/status + verbs: + - get + - patch + - update From 99469c1dfbcbdd342c60f651628dcd6f1eabf2db Mon Sep 17 00:00:00 2001 From: spoukke Date: Mon, 5 Dec 2022 14:20:35 +0100 Subject: [PATCH 10/42] feat: fix timestamp conversion --- controllers/terraformlayer_controller.go | 49 +++++++++++++----------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/controllers/terraformlayer_controller.go b/controllers/terraformlayer_controller.go index 04a4031c..fbd75f7c 100644 --- a/controllers/terraformlayer_controller.go +++ b/controllers/terraformlayer_controller.go @@ -19,9 +19,9 @@ package controllers import ( "bytes" "context" - "encoding/binary" "fmt" "hash/fnv" + "strconv" "strings" "time" @@ -88,12 +88,12 @@ const ( ApplyUpToDate = "IsApplyUpToDate" TerraformFailure = "HasTerraformFailed" - PrefixLock = "lock-" - PrefixLastPlanDate = "lastPlandate" - PrefixLastPlannedArtifact = "lastPlannedArtifact-" - PrefixLastAppliedArtifact = "lastApplyArtifact-" - PrefixRunResult = "runResult-" - PrefixRunMessage = "runMessage-" + CachePrefixLock = "lock-" + CachePrefixLastPlanDate = "lastPlandate" + CachePrefixLastPlannedArtifact = "lastPlannedArtifact-" + CachePrefixLastAppliedArtifact = "lastApplyArtifact-" + CachePrefixRunResult = "runResult-" + CachePrefixRunMessage = "runMessage-" ) type TerraformLayerConditions struct { @@ -158,6 +158,10 @@ func computeHash(s ...string) string { return fmt.Sprint(h.Sum32()) } +type TerraformCondition interface { + Evaluate(cache Cache, t *configv1alpha1.TerraformLayer) bool +} + type TerraformRunningCondition struct { Status metav1.Condition } @@ -167,7 +171,7 @@ func (c *TerraformRunningCondition) Evaluate(cache Cache, t *configv1alpha1.Terr Type: TerraformFailure, ObservedGeneration: t.GetObjectMeta().GetGeneration(), } - key := PrefixLock + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path) + key := CachePrefixLock + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path) _, err := cache.Get(key) if err != nil { c.Status.Reason = "NoLockInCache" @@ -190,7 +194,7 @@ func (c *TerraformPlanArtifactCondition) Evaluate(cache Cache, t *configv1alpha1 Type: TerraformFailure, ObservedGeneration: t.GetObjectMeta().GetGeneration(), } - key := PrefixLastPlanDate + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch) + key := CachePrefixLastPlanDate + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch) value, err := cache.Get(key) if err != nil { c.Status.Reason = "NoTimestampInCache" @@ -198,20 +202,20 @@ func (c *TerraformPlanArtifactCondition) Evaluate(cache Cache, t *configv1alpha1 c.Status.Status = metav1.ConditionFalse return false } - unixTimestamp := int64(binary.BigEndian.Uint64(value)) + unixTimestamp, _ := strconv.ParseInt(string(value), 10, 64) lastPlanDate := time.Unix(unixTimestamp, 0) nextPlanDate := lastPlanDate.Add(20 * time.Minute) now := time.Now() if nextPlanDate.After(now) { c.Status.Reason = "PlanIsRecent" c.Status.Message = "The plan has been made less than 20 minutes ago." - c.Status.Status = metav1.ConditionFalse - return false + c.Status.Status = metav1.ConditionTrue + return true } c.Status.Reason = "PlanIsTooOld" c.Status.Message = "The plan has been made more than 20 minutes ago." - c.Status.Status = metav1.ConditionTrue - return true + c.Status.Status = metav1.ConditionFalse + return false } type TerraformApplyUpToDateCondition struct { @@ -225,15 +229,15 @@ func (c *TerraformApplyUpToDateCondition) Evaluate(cache Cache, t *configv1alpha Status: metav1.ConditionTrue, } status := true - planKey := PrefixLastPlannedArtifact + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch) - applyKey := PrefixLastAppliedArtifact + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path) - planHash, err := cache.Get(planKey) + key := CachePrefixLastPlannedArtifact + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch) + planHash, err := cache.Get(key) if err != nil { c.Status.Reason = "NoPlanYet" c.Status.Message = "No plan has run yet, Layer might be new" return status } - applyHash, err := cache.Get(applyKey) + key = CachePrefixLastAppliedArtifact + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path) + applyHash, err := cache.Get(key) if err != nil { c.Status.Reason = "NoApplyHasRan" c.Status.Message = "Apply has not ran yet but a plan is available, launching apply" @@ -258,10 +262,8 @@ func (c *TerraformFailureCondition) Evaluate(cache Cache, t *configv1alpha1.Terr Status: metav1.ConditionFalse, } status := false - hashKey := computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch) - resultKey := PrefixRunResult + hashKey - messageKey := PrefixRunMessage + hashKey - result, err := cache.Get(resultKey) + key := CachePrefixRunResult + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch) + result, err := cache.Get(key) if err != nil { c.Status.Reason = "NoRunYet" c.Status.Message = "Terraform has not ran yet" @@ -271,7 +273,8 @@ func (c *TerraformFailureCondition) Evaluate(cache Cache, t *configv1alpha1.Terr c.Status.Status = metav1.ConditionTrue status = true } - message, err := cache.Get(messageKey) + key = CachePrefixRunMessage + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch) + message, err := cache.Get(key) if err != nil { c.Status.Reason = "UnexpectedRunnerFailure" c.Status.Message = "Terraform runner might have crashed before updating Redis" From 8ceb75bd24ea2c90af3c3a8d499b5a3f2f280f30 Mon Sep 17 00:00:00 2001 From: spoukke Date: Mon, 5 Dec 2022 14:47:26 +0100 Subject: [PATCH 11/42] test: implement testing for all evaluate methods of terraform conditions --- controllers/conditions_test.go | 102 ++++++++++++++++++++------------- 1 file changed, 62 insertions(+), 40 deletions(-) diff --git a/controllers/conditions_test.go b/controllers/conditions_test.go index c0e602e1..bc59f66c 100644 --- a/controllers/conditions_test.go +++ b/controllers/conditions_test.go @@ -71,11 +71,11 @@ var _ = Describe("TerraformLayer", func() { }) Context("with lock in cache", func() { It("should return true", func() { - cache.Set(PrefixLock+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path), []byte{1}, 0) + cache.Set(CachePrefixLock+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path), []byte{1}, 0) Expect(condition.Evaluate(cache, t)).To(Equal(true)) }) }) - Context("with lock not in cache", func() { + Context("without lock in cache", func() { It("should return false", func() { Expect(condition.Evaluate(cache, t)).To(Equal(false)) }) @@ -86,58 +86,80 @@ var _ = Describe("TerraformLayer", func() { BeforeEach(func() { condition = TerraformPlanArtifactCondition{} }) - Context("with no last timestamp in cache", func() { + Context("without last timestamp in cache", func() { It("should return false", func() { Expect(condition.Evaluate(cache, t)).To(Equal(false)) }) }) Context("with last timestamp in cache < 20min", func() { It("should return true", func() { - cache.Set(PrefixLastPlanDate+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), + cache.Set(CachePrefixLastPlanDate+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte(strconv.Itoa(int((time.Now().Add(-5 * time.Minute)).Unix()))), 0) Expect(condition.Evaluate(cache, t)).To(Equal(true)) }) }) Context("with last timestamp in cache > 20min", func() { It("should return false", func() { - cache.Set(PrefixLastPlanDate+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), - []byte(strconv.Itoa(int(time.Now().Add(-25*time.Minute).Unix()))), 0) + cache.Set(CachePrefixLastPlanDate+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), + []byte(strconv.Itoa(int(time.Now().Add(-time.Minute*60).Unix()))), 0) + + Expect(condition.Evaluate(cache, t)).To(Equal(false)) + }) + }) + }) + Describe("TerraformApplyUpToDateCondition", func() { + var condition TerraformApplyUpToDateCondition + BeforeEach(func() { + condition = TerraformApplyUpToDateCondition{} + }) + Context("without plan in cache", func() { + It("should return true", func() { + Expect(condition.Evaluate(cache, t)).To(Equal(true)) + }) + }) + Context("with plan in cache but no apply", func() { + It("should return false", func() { + cache.Set(CachePrefixLastPlannedArtifact+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("ThisIsAPlanArtifact"), 0) Expect(condition.Evaluate(cache, t)).To(Equal(false)) }) }) + Context("with same plan and apply in cache", func() { + It("should return true", func() { + cache.Set(CachePrefixLastPlannedArtifact+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("ThisIsAPlanArtifact"), 0) + cache.Set(CachePrefixLastAppliedArtifact+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path), []byte("ThisIsAPlanArtifact"), 0) + Expect(condition.Evaluate(cache, t)).To(Equal(true)) + }) + }) + Context("with different plan and apply in cache", func() { + It("should return false", func() { + cache.Set(CachePrefixLastPlannedArtifact+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("ThisIsAPlanArtifact"), 0) + cache.Set(CachePrefixLastAppliedArtifact+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path), []byte("ThisIsAnotherPlanArtifact"), 0) + Expect(condition.Evaluate(cache, t)).To(Equal(false)) + }) + }) + }) + Describe("TerraformFailureCondition", func() { + var condition TerraformFailureCondition + BeforeEach(func() { + condition = TerraformFailureCondition{} + }) + Context("without run result in cache", func() { + It("should return false", func() { + Expect(condition.Evaluate(cache, t)).To(Equal(false)) + }) + }) + Context("with terraform failure in cache", func() { + It("should return true", func() { + cache.Set(CachePrefixRunResult+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []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(CachePrefixRunResult+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("1"), 0) + cache.Set(CachePrefixRunMessage+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("This is an error message."), 0) + Expect(condition.Evaluate(cache, t)).To(Equal(true)) + }) + }) }) - // Describe("TerraformPlanArtifactCondition", func() { - // var runningCondition TerraformRunningCondition - // BeforeEach(func() { - // runningCondition = TerraformRunningCondition{} - // }) - // Context("with lock in cache", func() { - // It("should return true", func() { - // cache.Set(PrefixLock+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path), []byte{1}, 0) - // Expect(runningCondition.Evaluate(cache, t)).To(Equal(true)) - // }) - // }) - // Context("with lock not in cache", func() { - // It("should return false", func() { - // Expect(runningCondition.Evaluate(cache, t)).To(Equal(false)) - // }) - // }) - // }) - // Describe("TerraformPlanArtifactCondition", func() { - // var runningCondition TerraformRunningCondition - // BeforeEach(func() { - // runningCondition = TerraformRunningCondition{} - // }) - // Context("with lock in cache", func() { - // It("should return true", func() { - // cache.Set(PrefixLock+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path), []byte{1}, 0) - // Expect(runningCondition.Evaluate(cache, t)).To(Equal(true)) - // }) - // }) - // Context("with lock not in cache", func() { - // It("should return false", func() { - // Expect(runningCondition.Evaluate(cache, t)).To(Equal(false)) - // }) - // }) - // }) }) From b4cea0f98152b82a72cdc4606e07910e5cd992db Mon Sep 17 00:00:00 2001 From: spoukke Date: Mon, 5 Dec 2022 15:07:47 +0100 Subject: [PATCH 12/42] chore: rename structs --- controllers/conditions_test.go | 19 ++-- controllers/terraformlayer_controller.go | 124 +++++++++++------------ 2 files changed, 73 insertions(+), 70 deletions(-) diff --git a/controllers/conditions_test.go b/controllers/conditions_test.go index bc59f66c..41a677a0 100644 --- a/controllers/conditions_test.go +++ b/controllers/conditions_test.go @@ -65,9 +65,9 @@ var _ = Describe("TerraformLayer", func() { }) Describe("TerraformRunningCondition", func() { - var condition TerraformRunningCondition + var condition TerraformRunning BeforeEach(func() { - condition = TerraformRunningCondition{} + condition = TerraformRunning{} }) Context("with lock in cache", func() { It("should return true", func() { @@ -82,9 +82,9 @@ var _ = Describe("TerraformLayer", func() { }) }) Describe("TerraformPlanArtifactCondition", func() { - var condition TerraformPlanArtifactCondition + var condition TerraformPlanArtifactUpToDate BeforeEach(func() { - condition = TerraformPlanArtifactCondition{} + condition = TerraformPlanArtifactUpToDate{} }) Context("without last timestamp in cache", func() { It("should return false", func() { @@ -108,9 +108,9 @@ var _ = Describe("TerraformLayer", func() { }) }) Describe("TerraformApplyUpToDateCondition", func() { - var condition TerraformApplyUpToDateCondition + var condition TerraformApplyUpToDate BeforeEach(func() { - condition = TerraformApplyUpToDateCondition{} + condition = TerraformApplyUpToDate{} }) Context("without plan in cache", func() { It("should return true", func() { @@ -139,9 +139,9 @@ var _ = Describe("TerraformLayer", func() { }) }) Describe("TerraformFailureCondition", func() { - var condition TerraformFailureCondition + var condition TerraformFailure BeforeEach(func() { - condition = TerraformFailureCondition{} + condition = TerraformFailure{} }) Context("without run result in cache", func() { It("should return false", func() { @@ -162,4 +162,7 @@ var _ = Describe("TerraformLayer", func() { }) }) }) + Describe("TerraformLayerCondition", func() { + + }) }) diff --git a/controllers/terraformlayer_controller.go b/controllers/terraformlayer_controller.go index fbd75f7c..81c68992 100644 --- a/controllers/terraformlayer_controller.go +++ b/controllers/terraformlayer_controller.go @@ -83,10 +83,10 @@ func (r *TerraformLayerReconciler) SetupWithManager(mgr ctrl.Manager) error { } const ( - RunningCondition = "IsTerraformRunning" - PlanArtifact = "IsPlanArtifactUpToDate" - ApplyUpToDate = "IsApplyUpToDate" - TerraformFailure = "HasTerraformFailed" + IsRunning = "IsTerraformRunning" + IsPlanArtifactUpToDate = "IsPlanArtifactUpToDate" + IsApplyUpToDate = "IsApplyUpToDate" + HasFailed = "HasTerraformFailed" CachePrefixLock = "lock-" CachePrefixLastPlanDate = "lastPlandate" @@ -97,20 +97,20 @@ const ( ) type TerraformLayerConditions struct { - RunningCondition TerraformRunningCondition - PlanArtifact TerraformPlanArtifactCondition - ApplyUpToDate TerraformApplyUpToDateCondition - TerraformFailure TerraformFailureCondition - Cache *Cache - Resource *configv1alpha1.TerraformLayer + IsRunning TerraformRunning + IsPlanArtifactUpToDate TerraformPlanArtifactUpToDate + IsApplyUpToDate TerraformApplyUpToDate + HasFailed TerraformFailure + Cache *Cache + Resource *configv1alpha1.TerraformLayer } func (t *TerraformLayerConditions) Evaluate() (func() ctrl.Result, []metav1.Condition) { - isTerraformRunning := t.RunningCondition.Evaluate(*t.Cache, t.Resource) - isPlanArtifactUpToDate := t.PlanArtifact.Evaluate(*t.Cache, t.Resource) - isApplyUpToDate := t.ApplyUpToDate.Evaluate(*t.Cache, t.Resource) - hasTerraformFailed := t.TerraformFailure.Evaluate(*t.Cache, t.Resource) - conditions := []metav1.Condition{t.RunningCondition.Status, t.PlanArtifact.Status, t.ApplyUpToDate.Status, t.TerraformFailure.Status} + isTerraformRunning := t.IsRunning.Evaluate(*t.Cache, t.Resource) + isPlanArtifactUpToDate := t.IsPlanArtifactUpToDate.Evaluate(*t.Cache, t.Resource) + isApplyUpToDate := t.IsApplyUpToDate.Evaluate(*t.Cache, t.Resource) + hasTerraformFailed := t.HasFailed.Evaluate(*t.Cache, t.Resource) + conditions := []metav1.Condition{t.IsRunning.Condition, t.IsPlanArtifactUpToDate.Condition, t.IsApplyUpToDate.Condition, t.HasFailed.Condition} switch { case isTerraformRunning: return func() ctrl.Result { @@ -162,44 +162,44 @@ type TerraformCondition interface { Evaluate(cache Cache, t *configv1alpha1.TerraformLayer) bool } -type TerraformRunningCondition struct { - Status metav1.Condition +type TerraformRunning struct { + Condition metav1.Condition } -func (c *TerraformRunningCondition) Evaluate(cache Cache, t *configv1alpha1.TerraformLayer) bool { - c.Status = metav1.Condition{ - Type: TerraformFailure, +func (c *TerraformRunning) Evaluate(cache Cache, t *configv1alpha1.TerraformLayer) bool { + c.Condition = metav1.Condition{ + Type: IsRunning, ObservedGeneration: t.GetObjectMeta().GetGeneration(), } key := CachePrefixLock + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path) _, err := cache.Get(key) if err != nil { - c.Status.Reason = "NoLockInCache" - c.Status.Message = "No lock has been found in Cache. Terraform is not running on this layer." - c.Status.Status = metav1.ConditionFalse + c.Condition.Reason = "NoLockInCache" + c.Condition.Message = "No lock has been found in Cache. Terraform is not running on this layer." + c.Condition.Status = metav1.ConditionFalse return false } - c.Status.Reason = "LockInCache" - c.Status.Message = "Lock has been found in Cache. Terraform is already running on this layer." - c.Status.Status = metav1.ConditionTrue + c.Condition.Reason = "LockInCache" + c.Condition.Message = "Lock has been found in Cache. Terraform is already running on this layer." + c.Condition.Status = metav1.ConditionTrue return true } -type TerraformPlanArtifactCondition struct { - Status metav1.Condition +type TerraformPlanArtifactUpToDate struct { + Condition metav1.Condition } -func (c *TerraformPlanArtifactCondition) Evaluate(cache Cache, t *configv1alpha1.TerraformLayer) bool { - c.Status = metav1.Condition{ - Type: TerraformFailure, +func (c *TerraformPlanArtifactUpToDate) Evaluate(cache Cache, t *configv1alpha1.TerraformLayer) bool { + c.Condition = metav1.Condition{ + Type: IsPlanArtifactUpToDate, ObservedGeneration: t.GetObjectMeta().GetGeneration(), } key := CachePrefixLastPlanDate + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch) value, err := cache.Get(key) if err != nil { - c.Status.Reason = "NoTimestampInCache" - c.Status.Message = "The last plan date is not in cache." - c.Status.Status = metav1.ConditionFalse + c.Condition.Reason = "NoTimestampInCache" + c.Condition.Message = "The last plan date is not in cache." + c.Condition.Status = metav1.ConditionFalse return false } unixTimestamp, _ := strconv.ParseInt(string(value), 10, 64) @@ -207,24 +207,24 @@ func (c *TerraformPlanArtifactCondition) Evaluate(cache Cache, t *configv1alpha1 nextPlanDate := lastPlanDate.Add(20 * time.Minute) now := time.Now() if nextPlanDate.After(now) { - c.Status.Reason = "PlanIsRecent" - c.Status.Message = "The plan has been made less than 20 minutes ago." - c.Status.Status = metav1.ConditionTrue + c.Condition.Reason = "PlanIsRecent" + c.Condition.Message = "The plan has been made less than 20 minutes ago." + c.Condition.Status = metav1.ConditionTrue return true } - c.Status.Reason = "PlanIsTooOld" - c.Status.Message = "The plan has been made more than 20 minutes ago." - c.Status.Status = metav1.ConditionFalse + c.Condition.Reason = "PlanIsTooOld" + c.Condition.Message = "The plan has been made more than 20 minutes ago." + c.Condition.Status = metav1.ConditionFalse return false } -type TerraformApplyUpToDateCondition struct { - Status metav1.Condition +type TerraformApplyUpToDate struct { + Condition metav1.Condition } -func (c *TerraformApplyUpToDateCondition) Evaluate(cache Cache, t *configv1alpha1.TerraformLayer) bool { - c.Status = metav1.Condition{ - Type: ApplyUpToDate, +func (c *TerraformApplyUpToDate) Evaluate(cache Cache, t *configv1alpha1.TerraformLayer) bool { + c.Condition = metav1.Condition{ + Type: IsApplyUpToDate, ObservedGeneration: t.GetObjectMeta().GetGeneration(), Status: metav1.ConditionTrue, } @@ -232,32 +232,32 @@ func (c *TerraformApplyUpToDateCondition) Evaluate(cache Cache, t *configv1alpha key := CachePrefixLastPlannedArtifact + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch) planHash, err := cache.Get(key) if err != nil { - c.Status.Reason = "NoPlanYet" - c.Status.Message = "No plan has run yet, Layer might be new" + c.Condition.Reason = "NoPlanYet" + c.Condition.Message = "No plan has run yet, Layer might be new" return status } key = CachePrefixLastAppliedArtifact + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path) applyHash, err := cache.Get(key) if err != nil { - c.Status.Reason = "NoApplyHasRan" - c.Status.Message = "Apply has not ran yet but a plan is available, launching apply" + c.Condition.Reason = "NoApplyHasRan" + c.Condition.Message = "Apply has not ran yet but a plan is available, launching apply" status = false } if bytes.Compare(planHash, applyHash) != 0 { - c.Status.Reason = "NewPlanAvailable" - c.Status.Message = "Apply will run." + c.Condition.Reason = "NewPlanAvailable" + c.Condition.Message = "Apply will run." status = false } return status } -type TerraformFailureCondition struct { - Status metav1.Condition +type TerraformFailure struct { + Condition metav1.Condition } -func (c *TerraformFailureCondition) Evaluate(cache Cache, t *configv1alpha1.TerraformLayer) bool { - c.Status = metav1.Condition{ - Type: TerraformFailure, +func (c *TerraformFailure) Evaluate(cache Cache, t *configv1alpha1.TerraformLayer) bool { + c.Condition = metav1.Condition{ + Type: HasFailed, ObservedGeneration: t.GetObjectMeta().GetGeneration(), Status: metav1.ConditionFalse, } @@ -265,20 +265,20 @@ func (c *TerraformFailureCondition) Evaluate(cache Cache, t *configv1alpha1.Terr key := CachePrefixRunResult + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch) result, err := cache.Get(key) if err != nil { - c.Status.Reason = "NoRunYet" - c.Status.Message = "Terraform has not ran yet" + c.Condition.Reason = "NoRunYet" + c.Condition.Message = "Terraform has not ran yet" return status } if string(result) == "1" { - c.Status.Status = metav1.ConditionTrue + c.Condition.Status = metav1.ConditionTrue status = true } key = CachePrefixRunMessage + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch) message, err := cache.Get(key) if err != nil { - c.Status.Reason = "UnexpectedRunnerFailure" - c.Status.Message = "Terraform runner might have crashed before updating Redis" + c.Condition.Reason = "UnexpectedRunnerFailure" + c.Condition.Message = "Terraform runner might have crashed before updating Redis" } - c.Status.Message = string(message) + c.Condition.Message = string(message) return status } From ba4b83de29bb2bfd1c6116749ec229ef86e2d78e Mon Sep 17 00:00:00 2001 From: spoukke Date: Mon, 5 Dec 2022 15:43:50 +0100 Subject: [PATCH 13/42] chore: uniformize every sub evaluate mehtod --- controllers/terraformlayer_controller.go | 37 +++++++++++++++--------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/controllers/terraformlayer_controller.go b/controllers/terraformlayer_controller.go index 81c68992..77f3baf5 100644 --- a/controllers/terraformlayer_controller.go +++ b/controllers/terraformlayer_controller.go @@ -170,6 +170,7 @@ func (c *TerraformRunning) Evaluate(cache Cache, t *configv1alpha1.TerraformLaye c.Condition = metav1.Condition{ Type: IsRunning, ObservedGeneration: t.GetObjectMeta().GetGeneration(), + Status: metav1.ConditionUnknown, } key := CachePrefixLock + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path) _, err := cache.Get(key) @@ -193,6 +194,7 @@ func (c *TerraformPlanArtifactUpToDate) Evaluate(cache Cache, t *configv1alpha1. c.Condition = metav1.Condition{ Type: IsPlanArtifactUpToDate, ObservedGeneration: t.GetObjectMeta().GetGeneration(), + Status: metav1.ConditionUnknown, } key := CachePrefixLastPlanDate + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch) value, err := cache.Get(key) @@ -226,29 +228,34 @@ func (c *TerraformApplyUpToDate) Evaluate(cache Cache, t *configv1alpha1.Terrafo c.Condition = metav1.Condition{ Type: IsApplyUpToDate, ObservedGeneration: t.GetObjectMeta().GetGeneration(), - Status: metav1.ConditionTrue, + Status: metav1.ConditionUnknown, } - status := true key := CachePrefixLastPlannedArtifact + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch) planHash, err := cache.Get(key) if err != nil { c.Condition.Reason = "NoPlanYet" c.Condition.Message = "No plan has run yet, Layer might be new" - return status + c.Condition.Status = metav1.ConditionTrue + return true } key = CachePrefixLastAppliedArtifact + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path) applyHash, err := cache.Get(key) if err != nil { c.Condition.Reason = "NoApplyHasRan" c.Condition.Message = "Apply has not ran yet but a plan is available, launching apply" - status = false + c.Condition.Status = metav1.ConditionFalse + return false } if bytes.Compare(planHash, applyHash) != 0 { c.Condition.Reason = "NewPlanAvailable" c.Condition.Message = "Apply will run." - status = false + c.Condition.Status = metav1.ConditionFalse + return false } - return status + c.Condition.Reason = "ApplyUpToDate" + c.Condition.Message = "Last planned artifact is the same as the last applied one" + c.Condition.Status = metav1.ConditionTrue + return true } type TerraformFailure struct { @@ -259,26 +266,30 @@ func (c *TerraformFailure) Evaluate(cache Cache, t *configv1alpha1.TerraformLaye c.Condition = metav1.Condition{ Type: HasFailed, ObservedGeneration: t.GetObjectMeta().GetGeneration(), - Status: metav1.ConditionFalse, + Status: metav1.ConditionUnknown, } - status := false key := CachePrefixRunResult + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch) result, err := cache.Get(key) if err != nil { c.Condition.Reason = "NoRunYet" c.Condition.Message = "Terraform has not ran yet" - return status + c.Condition.Status = metav1.ConditionFalse + return false } - if string(result) == "1" { - c.Condition.Status = metav1.ConditionTrue - status = true + if string(result) == "0" { + c.Condition.Reason = "RunExitedGracefully" + c.Condition.Message = "Last run exited gracefully" + c.Condition.Status = metav1.ConditionFalse + return false } + c.Condition.Status = metav1.ConditionTrue key = CachePrefixRunMessage + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch) 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) - return status + return true } From 4a993ae09766b2559d38b0a1b512178199c4a1fd Mon Sep 17 00:00:00 2001 From: spoukke Date: Mon, 5 Dec 2022 15:44:22 +0100 Subject: [PATCH 14/42] test: start implementing terraform layer conditions tests --- controllers/conditions_test.go | 40 ++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/controllers/conditions_test.go b/controllers/conditions_test.go index 41a677a0..9288aae7 100644 --- a/controllers/conditions_test.go +++ b/controllers/conditions_test.go @@ -25,6 +25,8 @@ import ( . "github.com/onsi/gomega" configv1alpha1 "github.com/padok-team/burrito/api/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" //+kubebuilder:scaffold:imports @@ -162,7 +164,41 @@ var _ = Describe("TerraformLayer", func() { }) }) }) - Describe("TerraformLayerCondition", func() { - + Describe("TerraformLayerConditions", func() { + var conditions TerraformLayerConditions + BeforeEach(func() { + conditions = TerraformLayerConditions{Resource: t, Cache: &cache} + }) + Context("terraform is running", func() { + It("", func() { + cache.Set(CachePrefixLock+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path), []byte{1}, 0) + _, out := conditions.Evaluate() + Expect(out[0].Status).To(Equal(metav1.ConditionTrue)) + }) + }) + Context("terraform not running and everything is up to date", func() { + It("", func() { + cache.Set(CachePrefixLastPlanDate+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte(strconv.Itoa(int((time.Now().Add(-5 * time.Minute)).Unix()))), 0) + cache.Set(CachePrefixLastPlannedArtifact+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("ThisIsAPlanArtifact"), 0) + cache.Set(CachePrefixLastAppliedArtifact+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path), []byte("ThisIsAPlanArtifact"), 0) + _, out := conditions.Evaluate() + Expect(out[0].Status).To(Equal(metav1.ConditionFalse)) + Expect(out[1].Status).To(Equal(metav1.ConditionTrue)) + Expect(out[2].Status).To(Equal(metav1.ConditionTrue)) + }) + }) + Context("terraform not running, plan up to date, apply noy up to date, terraform has failed", func() { + It("", func() { + cache.Set(CachePrefixLastPlanDate+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte(strconv.Itoa(int((time.Now().Add(-5 * time.Minute)).Unix()))), 0) + cache.Set(CachePrefixLastPlannedArtifact+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("ThisIsAPlanArtifact"), 0) + cache.Set(CachePrefixLastAppliedArtifact+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path), []byte("ThisIsAnotherPlanArtifact"), 0) + cache.Set(CachePrefixRunResult+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("1"), 0) + _, out := conditions.Evaluate() + Expect(out[0].Status).To(Equal(metav1.ConditionFalse)) + Expect(out[1].Status).To(Equal(metav1.ConditionTrue)) + Expect(out[2].Status).To(Equal(metav1.ConditionFalse)) + Expect(out[3].Status).To(Equal(metav1.ConditionTrue)) + }) + }) }) }) From 6a44b2b508ab2380cbe7558a54c84c97f109edee Mon Sep 17 00:00:00 2001 From: spoukke Date: Mon, 5 Dec 2022 15:49:53 +0100 Subject: [PATCH 15/42] test: implement terraform layer conditions testing --- controllers/conditions_test.go | 42 +++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/controllers/conditions_test.go b/controllers/conditions_test.go index 9288aae7..6d13aef7 100644 --- a/controllers/conditions_test.go +++ b/controllers/conditions_test.go @@ -95,16 +95,13 @@ var _ = Describe("TerraformLayer", func() { }) Context("with last timestamp in cache < 20min", func() { It("should return true", func() { - cache.Set(CachePrefixLastPlanDate+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), - []byte(strconv.Itoa(int((time.Now().Add(-5 * time.Minute)).Unix()))), 0) + cache.Set(CachePrefixLastPlanDate+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte(strconv.Itoa(int((time.Now().Add(-5 * time.Minute)).Unix()))), 0) Expect(condition.Evaluate(cache, t)).To(Equal(true)) }) }) Context("with last timestamp in cache > 20min", func() { It("should return false", func() { - cache.Set(CachePrefixLastPlanDate+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), - []byte(strconv.Itoa(int(time.Now().Add(-time.Minute*60).Unix()))), 0) - + cache.Set(CachePrefixLastPlanDate+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte(strconv.Itoa(int(time.Now().Add(-time.Minute*60).Unix()))), 0) Expect(condition.Evaluate(cache, t)).To(Equal(false)) }) }) @@ -187,7 +184,7 @@ var _ = Describe("TerraformLayer", func() { Expect(out[2].Status).To(Equal(metav1.ConditionTrue)) }) }) - Context("terraform not running, plan up to date, apply noy up to date, terraform has failed", func() { + Context("terraform not running, plan up to date, apply not up to date, terraform has failed", func() { It("", func() { cache.Set(CachePrefixLastPlanDate+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte(strconv.Itoa(int((time.Now().Add(-5 * time.Minute)).Unix()))), 0) cache.Set(CachePrefixLastPlannedArtifact+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("ThisIsAPlanArtifact"), 0) @@ -200,5 +197,38 @@ var _ = Describe("TerraformLayer", func() { Expect(out[3].Status).To(Equal(metav1.ConditionTrue)) }) }) + Context("terraform not running, plan up to date, apply noy up to date, terraform has not failed", func() { + It("", func() { + cache.Set(CachePrefixLastPlanDate+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte(strconv.Itoa(int((time.Now().Add(-5 * time.Minute)).Unix()))), 0) + cache.Set(CachePrefixLastPlannedArtifact+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("ThisIsAPlanArtifact"), 0) + cache.Set(CachePrefixLastAppliedArtifact+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path), []byte("ThisIsAnotherPlanArtifact"), 0) + cache.Set(CachePrefixRunResult+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("0"), 0) + _, out := conditions.Evaluate() + Expect(out[0].Status).To(Equal(metav1.ConditionFalse)) + Expect(out[1].Status).To(Equal(metav1.ConditionTrue)) + Expect(out[2].Status).To(Equal(metav1.ConditionFalse)) + Expect(out[3].Status).To(Equal(metav1.ConditionFalse)) + }) + }) + Context("terraform not running, plan not up to date, terraform has failed", func() { + It("", func() { + cache.Set(CachePrefixLastPlanDate+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte(strconv.Itoa(int(time.Now().Add(-time.Minute*60).Unix()))), 0) + cache.Set(CachePrefixRunResult+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("1"), 0) + _, out := conditions.Evaluate() + 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() { + It("", func() { + cache.Set(CachePrefixLastPlanDate+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte(strconv.Itoa(int(time.Now().Add(-time.Minute*60).Unix()))), 0) + cache.Set(CachePrefixRunResult+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("0"), 0) + _, out := conditions.Evaluate() + Expect(out[0].Status).To(Equal(metav1.ConditionFalse)) + Expect(out[1].Status).To(Equal(metav1.ConditionFalse)) + Expect(out[3].Status).To(Equal(metav1.ConditionFalse)) + }) + }) }) }) From 47ca78cf6448ed4bb52e9d38002ab43bb375b94e Mon Sep 17 00:00:00 2001 From: spoukke Date: Mon, 5 Dec 2022 15:55:23 +0100 Subject: [PATCH 16/42] chore: remove unused struct --- controllers/terraformlayer_controller.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/controllers/terraformlayer_controller.go b/controllers/terraformlayer_controller.go index 77f3baf5..fff7139c 100644 --- a/controllers/terraformlayer_controller.go +++ b/controllers/terraformlayer_controller.go @@ -158,10 +158,6 @@ func computeHash(s ...string) string { return fmt.Sprint(h.Sum32()) } -type TerraformCondition interface { - Evaluate(cache Cache, t *configv1alpha1.TerraformLayer) bool -} - type TerraformRunning struct { Condition metav1.Condition } From e873c28fc38cfd80782538e31e4af572cfb16c10 Mon Sep 17 00:00:00 2001 From: spoukke Date: Thu, 8 Dec 2022 16:18:06 +0100 Subject: [PATCH 17/42] feat: start working on job --- api/v1alpha1/terraformlayer_types.go | 3 +- api/v1alpha1/zz_generated.deepcopy.go | 5 +- ...terraform.padok.cloud_terraformlayers.yaml | 7180 ----------------- controllers/job.go | 36 + 4 files changed, 39 insertions(+), 7185 deletions(-) create mode 100644 controllers/job.go diff --git a/api/v1alpha1/terraformlayer_types.go b/api/v1alpha1/terraformlayer_types.go index a866a3bf..06f9a60d 100644 --- a/api/v1alpha1/terraformlayer_types.go +++ b/api/v1alpha1/terraformlayer_types.go @@ -17,7 +17,6 @@ limitations under the License. package v1alpha1 import ( - corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -35,7 +34,7 @@ type TerraformLayerSpec struct { Repository TerraformLayerRepository `json:"repository,omitempty"` RemediationStrategy TerraformLayerRemediationStrategy `json:"remediationStrategy,omitempty"` PlanOnPullRequest bool `json:"planOnPullRequest,omitempty"` - RunnerPodTemplate corev1.PodTemplateSpec `json:"template,omitempty"` + // RunnerPodTemplate corev1.PodSpec `json:"template,omitempty"` } type TerraformLayerRemediationStrategy struct { diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 83254a73..ee921b08 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -22,7 +22,7 @@ limitations under the License. package v1alpha1 import ( - "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -31,7 +31,7 @@ func (in *TerraformLayer) DeepCopyInto(out *TerraformLayer) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) + out.Spec = in.Spec in.Status.DeepCopyInto(&out.Status) } @@ -120,7 +120,6 @@ func (in *TerraformLayerSpec) DeepCopyInto(out *TerraformLayerSpec) { *out = *in out.Repository = in.Repository out.RemediationStrategy = in.RemediationStrategy - in.RunnerPodTemplate.DeepCopyInto(&out.RunnerPodTemplate) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TerraformLayerSpec. diff --git a/config/crd/bases/config.terraform.padok.cloud_terraformlayers.yaml b/config/crd/bases/config.terraform.padok.cloud_terraformlayers.yaml index d5403a2b..5b0e01c8 100644 --- a/config/crd/bases/config.terraform.padok.cloud_terraformlayers.yaml +++ b/config/crd/bases/config.terraform.padok.cloud_terraformlayers.yaml @@ -59,7186 +59,6 @@ spec: namespace: type: string type: object - template: - description: PodTemplateSpec describes the data a pod should have - when created from a template - properties: - metadata: - description: 'Standard object''s metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata' - type: object - spec: - description: 'Specification of the desired behavior of the pod. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status' - properties: - activeDeadlineSeconds: - description: Optional duration in seconds the pod may be active - on the node relative to StartTime before the system will - actively try to mark it failed and kill associated containers. - Value must be a positive integer. - format: int64 - type: integer - affinity: - description: If specified, the pod's scheduling constraints - properties: - nodeAffinity: - description: Describes node affinity scheduling rules - for the pod. - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: The scheduler will prefer to schedule - pods to nodes that satisfy the affinity expressions - specified by this field, but it may choose a node - that violates one or more of the expressions. The - node that is most preferred is the one with the - greatest sum of weights, i.e. for each node that - meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, - etc.), compute a sum by iterating through the elements - of this field and adding "weight" to the sum if - the node matches the corresponding matchExpressions; - the node(s) with the highest sum are the most preferred. - items: - description: An empty preferred scheduling term - matches all objects with implicit weight 0 (i.e. - it's a no-op). A null preferred scheduling term - matches no objects (i.e. is also a no-op). - properties: - preference: - description: A node selector term, associated - with the corresponding weight. - properties: - matchExpressions: - description: A list of node selector requirements - by node's labels. - items: - description: A node selector requirement - is a selector that contains values, - a key, and an operator that relates - the key and values. - properties: - key: - description: The label key that the - selector applies to. - type: string - operator: - description: Represents a key's relationship - to a set of values. Valid operators - are In, NotIn, Exists, DoesNotExist. - Gt, and Lt. - type: string - values: - description: An array of string values. - If the operator is In or NotIn, - the values array must be non-empty. - If the operator is Exists or DoesNotExist, - the values array must be empty. - If the operator is Gt or Lt, the - values array must have a single - element, which will be interpreted - as an integer. This array is replaced - during a strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchFields: - description: A list of node selector requirements - by node's fields. - items: - description: A node selector requirement - is a selector that contains values, - a key, and an operator that relates - the key and values. - properties: - key: - description: The label key that the - selector applies to. - type: string - operator: - description: Represents a key's relationship - to a set of values. Valid operators - are In, NotIn, Exists, DoesNotExist. - Gt, and Lt. - type: string - values: - description: An array of string values. - If the operator is In or NotIn, - the values array must be non-empty. - If the operator is Exists or DoesNotExist, - the values array must be empty. - If the operator is Gt or Lt, the - values array must have a single - element, which will be interpreted - as an integer. This array is replaced - during a strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - type: object - x-kubernetes-map-type: atomic - weight: - description: Weight associated with matching - the corresponding nodeSelectorTerm, in the - range 1-100. - format: int32 - type: integer - required: - - preference - - weight - type: object - type: array - requiredDuringSchedulingIgnoredDuringExecution: - description: If the affinity requirements specified - by this field are not met at scheduling time, the - pod will not be scheduled onto the node. If the - affinity requirements specified by this field cease - to be met at some point during pod execution (e.g. - due to an update), the system may or may not try - to eventually evict the pod from its node. - properties: - nodeSelectorTerms: - description: Required. A list of node selector - terms. The terms are ORed. - items: - description: A null or empty node selector term - matches no objects. The requirements of them - are ANDed. The TopologySelectorTerm type implements - a subset of the NodeSelectorTerm. - properties: - matchExpressions: - description: A list of node selector requirements - by node's labels. - items: - description: A node selector requirement - is a selector that contains values, - a key, and an operator that relates - the key and values. - properties: - key: - description: The label key that the - selector applies to. - type: string - operator: - description: Represents a key's relationship - to a set of values. Valid operators - are In, NotIn, Exists, DoesNotExist. - Gt, and Lt. - type: string - values: - description: An array of string values. - If the operator is In or NotIn, - the values array must be non-empty. - If the operator is Exists or DoesNotExist, - the values array must be empty. - If the operator is Gt or Lt, the - values array must have a single - element, which will be interpreted - as an integer. This array is replaced - during a strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchFields: - description: A list of node selector requirements - by node's fields. - items: - description: A node selector requirement - is a selector that contains values, - a key, and an operator that relates - the key and values. - properties: - key: - description: The label key that the - selector applies to. - type: string - operator: - description: Represents a key's relationship - to a set of values. Valid operators - are In, NotIn, Exists, DoesNotExist. - Gt, and Lt. - type: string - values: - description: An array of string values. - If the operator is In or NotIn, - the values array must be non-empty. - If the operator is Exists or DoesNotExist, - the values array must be empty. - If the operator is Gt or Lt, the - values array must have a single - element, which will be interpreted - as an integer. This array is replaced - during a strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - type: object - x-kubernetes-map-type: atomic - type: array - required: - - nodeSelectorTerms - type: object - x-kubernetes-map-type: atomic - type: object - podAffinity: - description: Describes pod affinity scheduling rules (e.g. - co-locate this pod in the same node, zone, etc. as some - other pod(s)). - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: The scheduler will prefer to schedule - pods to nodes that satisfy the affinity expressions - specified by this field, but it may choose a node - that violates one or more of the expressions. The - node that is most preferred is the one with the - greatest sum of weights, i.e. for each node that - meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, - etc.), compute a sum by iterating through the elements - of this field and adding "weight" to the sum if - the node has pods which matches the corresponding - podAffinityTerm; the node(s) with the highest sum - are the most preferred. - items: - description: The weights of all of the matched WeightedPodAffinityTerm - fields are added per-node to find the most preferred - node(s) - properties: - podAffinityTerm: - description: Required. A pod affinity term, - associated with the corresponding weight. - properties: - labelSelector: - description: A label query over a set of - resources, in this case pods. - properties: - matchExpressions: - description: matchExpressions is a list - of label selector requirements. The - requirements are ANDed. - items: - description: A label selector requirement - is a selector that contains values, - a key, and an operator that relates - the key and values. - properties: - key: - description: key is the label - key that the selector applies - to. - type: string - operator: - description: operator represents - a key's relationship to a set - of values. Valid operators are - In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array - of string values. If the operator - is In or NotIn, the values array - must be non-empty. If the operator - is Exists or DoesNotExist, the - values array must be empty. - This array is replaced during - a strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of - {key,value} pairs. A single {key,value} - in the matchLabels map is equivalent - to an element of matchExpressions, - whose key field is "key", the operator - is "In", and the values array contains - only "value". The requirements are - ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - namespaceSelector: - description: A label query over the set - of namespaces that the term applies to. - The term is applied to the union of the - namespaces selected by this field and - the ones listed in the namespaces field. - null selector and null or empty namespaces - list means "this pod's namespace". An - empty selector ({}) matches all namespaces. - properties: - matchExpressions: - description: matchExpressions is a list - of label selector requirements. The - requirements are ANDed. - items: - description: A label selector requirement - is a selector that contains values, - a key, and an operator that relates - the key and values. - properties: - key: - description: key is the label - key that the selector applies - to. - type: string - operator: - description: operator represents - a key's relationship to a set - of values. Valid operators are - In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array - of string values. If the operator - is In or NotIn, the values array - must be non-empty. If the operator - is Exists or DoesNotExist, the - values array must be empty. - This array is replaced during - a strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of - {key,value} pairs. A single {key,value} - in the matchLabels map is equivalent - to an element of matchExpressions, - whose key field is "key", the operator - is "In", and the values array contains - only "value". The requirements are - ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - namespaces: - description: namespaces specifies a static - list of namespace names that the term - applies to. The term is applied to the - union of the namespaces listed in this - field and the ones selected by namespaceSelector. - null or empty namespaces list and null - namespaceSelector means "this pod's namespace". - items: - type: string - type: array - topologyKey: - description: This pod should be co-located - (affinity) or not co-located (anti-affinity) - with the pods matching the labelSelector - in the specified namespaces, where co-located - is defined as running on a node whose - value of the label with key topologyKey - matches that of any node on which any - of the selected pods is running. Empty - topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - weight: - description: weight associated with matching - the corresponding podAffinityTerm, in the - range 1-100. - format: int32 - type: integer - required: - - podAffinityTerm - - weight - type: object - type: array - requiredDuringSchedulingIgnoredDuringExecution: - description: If the affinity requirements specified - by this field are not met at scheduling time, the - pod will not be scheduled onto the node. If the - affinity requirements specified by this field cease - to be met at some point during pod execution (e.g. - due to a pod label update), the system may or may - not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes - corresponding to each podAffinityTerm are intersected, - i.e. all terms must be satisfied. - items: - description: Defines a set of pods (namely those - matching the labelSelector relative to the given - namespace(s)) that this pod should be co-located - (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node - whose value of the label with key - matches that of any node on which a pod of the - set of pods is running - properties: - labelSelector: - description: A label query over a set of resources, - in this case pods. - properties: - matchExpressions: - description: matchExpressions is a list - of label selector requirements. The requirements - are ANDed. - items: - description: A label selector requirement - is a selector that contains values, - a key, and an operator that relates - the key and values. - properties: - key: - description: key is the label key - that the selector applies to. - type: string - operator: - description: operator represents a - key's relationship to a set of values. - Valid operators are In, NotIn, Exists - and DoesNotExist. - type: string - values: - description: values is an array of - string values. If the operator is - In or NotIn, the values array must - be non-empty. If the operator is - Exists or DoesNotExist, the values - array must be empty. This array - is replaced during a strategic merge - patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator - is "In", and the values array contains - only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - namespaceSelector: - description: A label query over the set of namespaces - that the term applies to. The term is applied - to the union of the namespaces selected by - this field and the ones listed in the namespaces - field. null selector and null or empty namespaces - list means "this pod's namespace". An empty - selector ({}) matches all namespaces. - properties: - matchExpressions: - description: matchExpressions is a list - of label selector requirements. The requirements - are ANDed. - items: - description: A label selector requirement - is a selector that contains values, - a key, and an operator that relates - the key and values. - properties: - key: - description: key is the label key - that the selector applies to. - type: string - operator: - description: operator represents a - key's relationship to a set of values. - Valid operators are In, NotIn, Exists - and DoesNotExist. - type: string - values: - description: values is an array of - string values. If the operator is - In or NotIn, the values array must - be non-empty. If the operator is - Exists or DoesNotExist, the values - array must be empty. This array - is replaced during a strategic merge - patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator - is "In", and the values array contains - only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - namespaces: - description: namespaces specifies a static list - of namespace names that the term applies to. - The term is applied to the union of the namespaces - listed in this field and the ones selected - by namespaceSelector. null or empty namespaces - list and null namespaceSelector means "this - pod's namespace". - items: - type: string - type: array - topologyKey: - description: This pod should be co-located (affinity) - or not co-located (anti-affinity) with the - pods matching the labelSelector in the specified - namespaces, where co-located is defined as - running on a node whose value of the label - with key topologyKey matches that of any node - on which any of the selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - type: array - type: object - podAntiAffinity: - description: Describes pod anti-affinity scheduling rules - (e.g. avoid putting this pod in the same node, zone, - etc. as some other pod(s)). - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: The scheduler will prefer to schedule - pods to nodes that satisfy the anti-affinity expressions - specified by this field, but it may choose a node - that violates one or more of the expressions. The - node that is most preferred is the one with the - greatest sum of weights, i.e. for each node that - meets all of the scheduling requirements (resource - request, requiredDuringScheduling anti-affinity - expressions, etc.), compute a sum by iterating through - the elements of this field and adding "weight" to - the sum if the node has pods which matches the corresponding - podAffinityTerm; the node(s) with the highest sum - are the most preferred. - items: - description: The weights of all of the matched WeightedPodAffinityTerm - fields are added per-node to find the most preferred - node(s) - properties: - podAffinityTerm: - description: Required. A pod affinity term, - associated with the corresponding weight. - properties: - labelSelector: - description: A label query over a set of - resources, in this case pods. - properties: - matchExpressions: - description: matchExpressions is a list - of label selector requirements. The - requirements are ANDed. - items: - description: A label selector requirement - is a selector that contains values, - a key, and an operator that relates - the key and values. - properties: - key: - description: key is the label - key that the selector applies - to. - type: string - operator: - description: operator represents - a key's relationship to a set - of values. Valid operators are - In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array - of string values. If the operator - is In or NotIn, the values array - must be non-empty. If the operator - is Exists or DoesNotExist, the - values array must be empty. - This array is replaced during - a strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of - {key,value} pairs. A single {key,value} - in the matchLabels map is equivalent - to an element of matchExpressions, - whose key field is "key", the operator - is "In", and the values array contains - only "value". The requirements are - ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - namespaceSelector: - description: A label query over the set - of namespaces that the term applies to. - The term is applied to the union of the - namespaces selected by this field and - the ones listed in the namespaces field. - null selector and null or empty namespaces - list means "this pod's namespace". An - empty selector ({}) matches all namespaces. - properties: - matchExpressions: - description: matchExpressions is a list - of label selector requirements. The - requirements are ANDed. - items: - description: A label selector requirement - is a selector that contains values, - a key, and an operator that relates - the key and values. - properties: - key: - description: key is the label - key that the selector applies - to. - type: string - operator: - description: operator represents - a key's relationship to a set - of values. Valid operators are - In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array - of string values. If the operator - is In or NotIn, the values array - must be non-empty. If the operator - is Exists or DoesNotExist, the - values array must be empty. - This array is replaced during - a strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of - {key,value} pairs. A single {key,value} - in the matchLabels map is equivalent - to an element of matchExpressions, - whose key field is "key", the operator - is "In", and the values array contains - only "value". The requirements are - ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - namespaces: - description: namespaces specifies a static - list of namespace names that the term - applies to. The term is applied to the - union of the namespaces listed in this - field and the ones selected by namespaceSelector. - null or empty namespaces list and null - namespaceSelector means "this pod's namespace". - items: - type: string - type: array - topologyKey: - description: This pod should be co-located - (affinity) or not co-located (anti-affinity) - with the pods matching the labelSelector - in the specified namespaces, where co-located - is defined as running on a node whose - value of the label with key topologyKey - matches that of any node on which any - of the selected pods is running. Empty - topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - weight: - description: weight associated with matching - the corresponding podAffinityTerm, in the - range 1-100. - format: int32 - type: integer - required: - - podAffinityTerm - - weight - type: object - type: array - requiredDuringSchedulingIgnoredDuringExecution: - description: If the anti-affinity requirements specified - by this field are not met at scheduling time, the - pod will not be scheduled onto the node. If the - anti-affinity requirements specified by this field - cease to be met at some point during pod execution - (e.g. due to a pod label update), the system may - or may not try to eventually evict the pod from - its node. When there are multiple elements, the - lists of nodes corresponding to each podAffinityTerm - are intersected, i.e. all terms must be satisfied. - items: - description: Defines a set of pods (namely those - matching the labelSelector relative to the given - namespace(s)) that this pod should be co-located - (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node - whose value of the label with key - matches that of any node on which a pod of the - set of pods is running - properties: - labelSelector: - description: A label query over a set of resources, - in this case pods. - properties: - matchExpressions: - description: matchExpressions is a list - of label selector requirements. The requirements - are ANDed. - items: - description: A label selector requirement - is a selector that contains values, - a key, and an operator that relates - the key and values. - properties: - key: - description: key is the label key - that the selector applies to. - type: string - operator: - description: operator represents a - key's relationship to a set of values. - Valid operators are In, NotIn, Exists - and DoesNotExist. - type: string - values: - description: values is an array of - string values. If the operator is - In or NotIn, the values array must - be non-empty. If the operator is - Exists or DoesNotExist, the values - array must be empty. This array - is replaced during a strategic merge - patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator - is "In", and the values array contains - only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - namespaceSelector: - description: A label query over the set of namespaces - that the term applies to. The term is applied - to the union of the namespaces selected by - this field and the ones listed in the namespaces - field. null selector and null or empty namespaces - list means "this pod's namespace". An empty - selector ({}) matches all namespaces. - properties: - matchExpressions: - description: matchExpressions is a list - of label selector requirements. The requirements - are ANDed. - items: - description: A label selector requirement - is a selector that contains values, - a key, and an operator that relates - the key and values. - properties: - key: - description: key is the label key - that the selector applies to. - type: string - operator: - description: operator represents a - key's relationship to a set of values. - Valid operators are In, NotIn, Exists - and DoesNotExist. - type: string - values: - description: values is an array of - string values. If the operator is - In or NotIn, the values array must - be non-empty. If the operator is - Exists or DoesNotExist, the values - array must be empty. This array - is replaced during a strategic merge - patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator - is "In", and the values array contains - only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - namespaces: - description: namespaces specifies a static list - of namespace names that the term applies to. - The term is applied to the union of the namespaces - listed in this field and the ones selected - by namespaceSelector. null or empty namespaces - list and null namespaceSelector means "this - pod's namespace". - items: - type: string - type: array - topologyKey: - description: This pod should be co-located (affinity) - or not co-located (anti-affinity) with the - pods matching the labelSelector in the specified - namespaces, where co-located is defined as - running on a node whose value of the label - with key topologyKey matches that of any node - on which any of the selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - type: array - type: object - type: object - automountServiceAccountToken: - description: AutomountServiceAccountToken indicates whether - a service account token should be automatically mounted. - type: boolean - containers: - description: List of containers belonging to the pod. Containers - cannot currently be added or removed. There must be at least - one container in a Pod. Cannot be updated. - items: - description: A single application container that you want - to run within a pod. - properties: - args: - description: 'Arguments to the entrypoint. The container - image''s CMD is used if this is not provided. Variable - references $(VAR_NAME) are expanded using the container''s - environment. If a variable cannot be resolved, the - reference in the input string will be unchanged. Double - $$ are reduced to a single $, which allows for escaping - the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce - the string literal "$(VAR_NAME)". Escaped references - will never be expanded, regardless of whether the - variable exists or not. Cannot be updated. More info: - https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' - items: - type: string - type: array - command: - description: 'Entrypoint array. Not executed within - a shell. The container image''s ENTRYPOINT is used - if this is not provided. Variable references $(VAR_NAME) - are expanded using the container''s environment. If - a variable cannot be resolved, the reference in the - input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) - syntax: i.e. "$$(VAR_NAME)" will produce the string - literal "$(VAR_NAME)". Escaped references will never - be expanded, regardless of whether the variable exists - or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' - items: - type: string - type: array - env: - description: List of environment variables to set in - the container. Cannot be updated. - items: - description: EnvVar represents an environment variable - present in a Container. - properties: - name: - description: Name of the environment variable. - Must be a C_IDENTIFIER. - type: string - value: - description: 'Variable references $(VAR_NAME) - are expanded using the previously defined environment - variables in the container and any service environment - variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. - Double $$ are reduced to a single $, which allows - for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" - will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless - of whether the variable exists or not. Defaults - to "".' - type: string - valueFrom: - description: Source for the environment variable's - value. Cannot be used if value is not empty. - properties: - configMapKeyRef: - description: Selects a key of a ConfigMap. - properties: - key: - description: The key to select. - type: string - name: - description: 'Name of the referent. More - info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - fieldRef: - description: 'Selects a field of the pod: - supports metadata.name, metadata.namespace, - `metadata.labels['''']`, `metadata.annotations['''']`, - spec.nodeName, spec.serviceAccountName, - status.hostIP, status.podIP, status.podIPs.' - properties: - apiVersion: - description: Version of the schema the - FieldPath is written in terms of, defaults - to "v1". - type: string - fieldPath: - description: Path of the field to select - in the specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - resourceFieldRef: - description: 'Selects a resource of the container: - only resources limits and requests (limits.cpu, - limits.memory, limits.ephemeral-storage, - requests.cpu, requests.memory and requests.ephemeral-storage) - are currently supported.' - properties: - containerName: - description: 'Container name: required - for volumes, optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format - of the exposed resources, defaults to - "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret in - the pod's namespace - properties: - key: - description: The key of the secret to - select from. Must be a valid secret - key. - type: string - name: - description: 'Name of the referent. More - info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - required: - - name - type: object - type: array - envFrom: - description: List of sources to populate environment - variables in the container. The keys defined within - a source must be a C_IDENTIFIER. All invalid keys - will be reported as an event when the container is - starting. When a key exists in multiple sources, the - value associated with the last source will take precedence. - Values defined by an Env with a duplicate key will - take precedence. Cannot be updated. - items: - description: EnvFromSource represents the source of - a set of ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' - type: string - optional: - description: Specify whether the ConfigMap - must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - prefix: - description: An optional identifier to prepend - to each key in the ConfigMap. Must be a C_IDENTIFIER. - type: string - secretRef: - description: The Secret to select from - properties: - name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' - type: string - optional: - description: Specify whether the Secret must - be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - type: object - type: array - image: - description: 'Container image name. More info: https://kubernetes.io/docs/concepts/containers/images - This field is optional to allow higher level config - management to default or override container images - in workload controllers like Deployments and StatefulSets.' - type: string - imagePullPolicy: - description: 'Image pull policy. One of Always, Never, - IfNotPresent. Defaults to Always if :latest tag is - specified, or IfNotPresent otherwise. Cannot be updated. - More info: https://kubernetes.io/docs/concepts/containers/images#updating-images' - type: string - lifecycle: - description: Actions that the management system should - take in response to container lifecycle events. Cannot - be updated. - properties: - postStart: - description: 'PostStart is called immediately after - a container is created. If the handler fails, - the container is terminated and restarted according - to its restart policy. Other management of the - container blocks until the hook completes. More - info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: Command is the command line - to execute inside the container, the working - directory for the command is root ('/') - in the container's filesystem. The command - is simply exec'd, it is not run inside - a shell, so traditional shell instructions - ('|', etc) won't work. To use a shell, - you need to explicitly call out to that - shell. Exit status of 0 is treated as - live/healthy and non-zero is unhealthy. - items: - type: string - type: array - type: object - httpGet: - description: HTTPGet specifies the http request - to perform. - properties: - host: - description: Host name to connect to, defaults - to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the - request. HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom - header to be used in HTTP probes - properties: - name: - description: The header field name - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - path: - description: Path to access on the HTTP - server. - type: string - port: - anyOf: - - type: integer - - type: string - description: Name or number of the port - to access on the container. Number must - be in the range 1 to 65535. Name must - be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: Scheme to use for connecting - to the host. Defaults to HTTP. - type: string - required: - - port - type: object - tcpSocket: - description: Deprecated. TCPSocket is NOT supported - as a LifecycleHandler and kept for the backward - compatibility. There are no validation of - this field and lifecycle hooks will fail in - runtime when tcp handler is specified. - properties: - host: - description: 'Optional: Host name to connect - to, defaults to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: Number or name of the port - to access on the container. Number must - be in the range 1 to 65535. Name must - be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - type: object - preStop: - description: 'PreStop is called immediately before - a container is terminated due to an API request - or management event such as liveness/startup probe - failure, preemption, resource contention, etc. - The handler is not called if the container crashes - or exits. The Pod''s termination grace period - countdown begins before the PreStop hook is executed. - Regardless of the outcome of the handler, the - container will eventually terminate within the - Pod''s termination grace period (unless delayed - by finalizers). Other management of the container - blocks until the hook completes or until the termination - grace period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: Command is the command line - to execute inside the container, the working - directory for the command is root ('/') - in the container's filesystem. The command - is simply exec'd, it is not run inside - a shell, so traditional shell instructions - ('|', etc) won't work. To use a shell, - you need to explicitly call out to that - shell. Exit status of 0 is treated as - live/healthy and non-zero is unhealthy. - items: - type: string - type: array - type: object - httpGet: - description: HTTPGet specifies the http request - to perform. - properties: - host: - description: Host name to connect to, defaults - to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the - request. HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom - header to be used in HTTP probes - properties: - name: - description: The header field name - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - path: - description: Path to access on the HTTP - server. - type: string - port: - anyOf: - - type: integer - - type: string - description: Name or number of the port - to access on the container. Number must - be in the range 1 to 65535. Name must - be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: Scheme to use for connecting - to the host. Defaults to HTTP. - type: string - required: - - port - type: object - tcpSocket: - description: Deprecated. TCPSocket is NOT supported - as a LifecycleHandler and kept for the backward - compatibility. There are no validation of - this field and lifecycle hooks will fail in - runtime when tcp handler is specified. - properties: - host: - description: 'Optional: Host name to connect - to, defaults to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: Number or name of the port - to access on the container. Number must - be in the range 1 to 65535. Name must - be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - type: object - type: object - livenessProbe: - description: 'Periodic probe of container liveness. - Container will be restarted if the probe fails. Cannot - be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: Command is the command line to - execute inside the container, the working - directory for the command is root ('/') in - the container's filesystem. The command is - simply exec'd, it is not run inside a shell, - so traditional shell instructions ('|', etc) - won't work. To use a shell, you need to explicitly - call out to that shell. Exit status of 0 is - treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - type: object - failureThreshold: - description: Minimum consecutive failures for the - probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving - a GRPC port. This is a beta field and requires - enabling GRPCContainerProbe feature gate. - properties: - port: - description: Port number of the gRPC service. - Number must be in the range 1 to 65535. - format: int32 - type: integer - service: - description: "Service is the name of the service - to place in the gRPC HealthCheckRequest (see - https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - \n If this is not specified, the default behavior - is defined by gRPC." - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request - to perform. - properties: - host: - description: Host name to connect to, defaults - to the pod IP. You probably want to set "Host" - in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. - HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom - header to be used in HTTP probes - properties: - name: - description: The header field name - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: Name or number of the port to access - on the container. Number must be in the range - 1 to 65535. Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: Scheme to use for connecting to - the host. Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: 'Number of seconds after the container - has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' - format: int32 - type: integer - periodSeconds: - description: How often (in seconds) to perform the - probe. Default to 10 seconds. Minimum value is - 1. - format: int32 - type: integer - successThreshold: - description: Minimum consecutive successes for the - probe to be considered successful after having - failed. Defaults to 1. Must be 1 for liveness - and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving - a TCP port. - properties: - host: - description: 'Optional: Host name to connect - to, defaults to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: Number or name of the port to access - on the container. Number must be in the range - 1 to 65535. Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: Optional duration in seconds the pod - needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after - the processes running in the pod are sent a termination - signal and the time when the processes are forcibly - halted with a kill signal. Set this value longer - than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds - will be used. Otherwise, this value overrides - the value provided by the pod spec. Value must - be non-negative integer. The value zero indicates - stop immediately via the kill signal (no opportunity - to shut down). This is a beta field and requires - enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds - is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: 'Number of seconds after which the - probe times out. Defaults to 1 second. Minimum - value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' - format: int32 - type: integer - type: object - name: - description: Name of the container specified as a DNS_LABEL. - Each container in a pod must have a unique name (DNS_LABEL). - Cannot be updated. - type: string - ports: - description: List of ports to expose from the container. - Not specifying a port here DOES NOT prevent that port - from being exposed. Any port which is listening on - the default "0.0.0.0" address inside a container will - be accessible from the network. Modifying this array - with strategic merge patch may corrupt the data. For - more information See https://github.com/kubernetes/kubernetes/issues/108255. - Cannot be updated. - items: - description: ContainerPort represents a network port - in a single container. - properties: - containerPort: - description: Number of port to expose on the pod's - IP address. This must be a valid port number, - 0 < x < 65536. - format: int32 - type: integer - hostIP: - description: What host IP to bind the external - port to. - type: string - hostPort: - description: Number of port to expose on the host. - If specified, this must be a valid port number, - 0 < x < 65536. If HostNetwork is specified, - this must match ContainerPort. Most containers - do not need this. - format: int32 - type: integer - name: - description: If specified, this must be an IANA_SVC_NAME - and unique within the pod. Each named port in - a pod must have a unique name. Name for the - port that can be referred to by services. - type: string - protocol: - default: TCP - description: Protocol for port. Must be UDP, TCP, - or SCTP. Defaults to "TCP". - type: string - required: - - containerPort - type: object - type: array - x-kubernetes-list-map-keys: - - containerPort - - protocol - x-kubernetes-list-type: map - readinessProbe: - description: 'Periodic probe of container service readiness. - Container will be removed from service endpoints if - the probe fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: Command is the command line to - execute inside the container, the working - directory for the command is root ('/') in - the container's filesystem. The command is - simply exec'd, it is not run inside a shell, - so traditional shell instructions ('|', etc) - won't work. To use a shell, you need to explicitly - call out to that shell. Exit status of 0 is - treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - type: object - failureThreshold: - description: Minimum consecutive failures for the - probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving - a GRPC port. This is a beta field and requires - enabling GRPCContainerProbe feature gate. - properties: - port: - description: Port number of the gRPC service. - Number must be in the range 1 to 65535. - format: int32 - type: integer - service: - description: "Service is the name of the service - to place in the gRPC HealthCheckRequest (see - https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - \n If this is not specified, the default behavior - is defined by gRPC." - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request - to perform. - properties: - host: - description: Host name to connect to, defaults - to the pod IP. You probably want to set "Host" - in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. - HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom - header to be used in HTTP probes - properties: - name: - description: The header field name - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: Name or number of the port to access - on the container. Number must be in the range - 1 to 65535. Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: Scheme to use for connecting to - the host. Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: 'Number of seconds after the container - has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' - format: int32 - type: integer - periodSeconds: - description: How often (in seconds) to perform the - probe. Default to 10 seconds. Minimum value is - 1. - format: int32 - type: integer - successThreshold: - description: Minimum consecutive successes for the - probe to be considered successful after having - failed. Defaults to 1. Must be 1 for liveness - and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving - a TCP port. - properties: - host: - description: 'Optional: Host name to connect - to, defaults to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: Number or name of the port to access - on the container. Number must be in the range - 1 to 65535. Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: Optional duration in seconds the pod - needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after - the processes running in the pod are sent a termination - signal and the time when the processes are forcibly - halted with a kill signal. Set this value longer - than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds - will be used. Otherwise, this value overrides - the value provided by the pod spec. Value must - be non-negative integer. The value zero indicates - stop immediately via the kill signal (no opportunity - to shut down). This is a beta field and requires - enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds - is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: 'Number of seconds after which the - probe times out. Defaults to 1 second. Minimum - value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' - format: int32 - type: integer - type: object - resources: - description: 'Compute Resources required by this container. - Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' - properties: - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: 'Limits describes the maximum amount - of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: 'Requests describes the minimum amount - of compute resources required. If Requests is - omitted for a container, it defaults to Limits - if that is explicitly specified, otherwise to - an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' - type: object - type: object - securityContext: - description: 'SecurityContext defines the security options - the container should be run with. If set, the fields - of SecurityContext override the equivalent fields - of PodSecurityContext. More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/' - properties: - allowPrivilegeEscalation: - description: 'AllowPrivilegeEscalation controls - whether a process can gain more privileges than - its parent process. This bool directly controls - if the no_new_privs flag will be set on the container - process. AllowPrivilegeEscalation is true always - when the container is: 1) run as Privileged 2) - has CAP_SYS_ADMIN Note that this field cannot - be set when spec.os.name is windows.' - type: boolean - capabilities: - description: The capabilities to add/drop when running - containers. Defaults to the default set of capabilities - granted by the container runtime. Note that this - field cannot be set when spec.os.name is windows. - properties: - add: - description: Added capabilities - items: - description: Capability represent POSIX capabilities - type - type: string - type: array - drop: - description: Removed capabilities - items: - description: Capability represent POSIX capabilities - type - type: string - type: array - type: object - privileged: - description: Run container in privileged mode. Processes - in privileged containers are essentially equivalent - to root on the host. Defaults to false. Note that - this field cannot be set when spec.os.name is - windows. - type: boolean - procMount: - description: procMount denotes the type of proc - mount to use for the containers. The default is - DefaultProcMount which uses the container runtime - defaults for readonly paths and masked paths. - This requires the ProcMountType feature flag to - be enabled. Note that this field cannot be set - when spec.os.name is windows. - type: string - readOnlyRootFilesystem: - description: Whether this container has a read-only - root filesystem. Default is false. Note that this - field cannot be set when spec.os.name is windows. - type: boolean - runAsGroup: - description: The GID to run the entrypoint of the - container process. Uses runtime default if unset. - May also be set in PodSecurityContext. If set - in both SecurityContext and PodSecurityContext, - the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name - is windows. - format: int64 - type: integer - runAsNonRoot: - description: Indicates that the container must run - as a non-root user. If true, the Kubelet will - validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start - the container if it does. If unset or false, no - such validation will be performed. May also be - set in PodSecurityContext. If set in both SecurityContext - and PodSecurityContext, the value specified in - SecurityContext takes precedence. - type: boolean - runAsUser: - description: The UID to run the entrypoint of the - container process. Defaults to user specified - in image metadata if unspecified. May also be - set in PodSecurityContext. If set in both SecurityContext - and PodSecurityContext, the value specified in - SecurityContext takes precedence. Note that this - field cannot be set when spec.os.name is windows. - format: int64 - type: integer - seLinuxOptions: - description: The SELinux context to be applied to - the container. If unspecified, the container runtime - will allocate a random SELinux context for each - container. May also be set in PodSecurityContext. If - set in both SecurityContext and PodSecurityContext, - the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name - is windows. - properties: - level: - description: Level is SELinux level label that - applies to the container. - type: string - role: - description: Role is a SELinux role label that - applies to the container. - type: string - type: - description: Type is a SELinux type label that - applies to the container. - type: string - user: - description: User is a SELinux user label that - applies to the container. - type: string - type: object - seccompProfile: - description: The seccomp options to use by this - container. If seccomp options are provided at - both the pod & container level, the container - options override the pod options. Note that this - field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: localhostProfile indicates a profile - defined in a file on the node should be used. - The profile must be preconfigured on the node - to work. Must be a descending path, relative - to the kubelet's configured seccomp profile - location. Must only be set if type is "Localhost". - type: string - type: - description: "type indicates which kind of seccomp - profile will be applied. Valid options are: - \n Localhost - a profile defined in a file - on the node should be used. RuntimeDefault - - the container runtime default profile should - be used. Unconfined - no profile should be - applied." - type: string - required: - - type - type: object - windowsOptions: - description: The Windows specific settings applied - to all containers. If unspecified, the options - from the PodSecurityContext will be used. If set - in both SecurityContext and PodSecurityContext, - the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name - is linux. - properties: - gmsaCredentialSpec: - description: GMSACredentialSpec is where the - GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) - inlines the contents of the GMSA credential - spec named by the GMSACredentialSpecName field. - type: string - gmsaCredentialSpecName: - description: GMSACredentialSpecName is the name - of the GMSA credential spec to use. - type: string - hostProcess: - description: HostProcess determines if a container - should be run as a 'Host Process' container. - This field is alpha-level and will only be - honored by components that enable the WindowsHostProcessContainers - feature flag. Setting this field without the - feature flag will result in errors when validating - the Pod. All of a Pod's containers must have - the same effective HostProcess value (it is - not allowed to have a mix of HostProcess containers - and non-HostProcess containers). In addition, - if HostProcess is true then HostNetwork must - also be set to true. - type: boolean - runAsUserName: - description: The UserName in Windows to run - the entrypoint of the container process. Defaults - to the user specified in image metadata if - unspecified. May also be set in PodSecurityContext. - If set in both SecurityContext and PodSecurityContext, - the value specified in SecurityContext takes - precedence. - type: string - type: object - type: object - startupProbe: - description: 'StartupProbe indicates that the Pod has - successfully initialized. If specified, no other probes - are executed until this completes successfully. If - this probe fails, the Pod will be restarted, just - as if the livenessProbe failed. This can be used to - provide different probe parameters at the beginning - of a Pod''s lifecycle, when it might take a long time - to load data or warm a cache, than during steady-state - operation. This cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: Command is the command line to - execute inside the container, the working - directory for the command is root ('/') in - the container's filesystem. The command is - simply exec'd, it is not run inside a shell, - so traditional shell instructions ('|', etc) - won't work. To use a shell, you need to explicitly - call out to that shell. Exit status of 0 is - treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - type: object - failureThreshold: - description: Minimum consecutive failures for the - probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving - a GRPC port. This is a beta field and requires - enabling GRPCContainerProbe feature gate. - properties: - port: - description: Port number of the gRPC service. - Number must be in the range 1 to 65535. - format: int32 - type: integer - service: - description: "Service is the name of the service - to place in the gRPC HealthCheckRequest (see - https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - \n If this is not specified, the default behavior - is defined by gRPC." - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request - to perform. - properties: - host: - description: Host name to connect to, defaults - to the pod IP. You probably want to set "Host" - in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. - HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom - header to be used in HTTP probes - properties: - name: - description: The header field name - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: Name or number of the port to access - on the container. Number must be in the range - 1 to 65535. Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: Scheme to use for connecting to - the host. Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: 'Number of seconds after the container - has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' - format: int32 - type: integer - periodSeconds: - description: How often (in seconds) to perform the - probe. Default to 10 seconds. Minimum value is - 1. - format: int32 - type: integer - successThreshold: - description: Minimum consecutive successes for the - probe to be considered successful after having - failed. Defaults to 1. Must be 1 for liveness - and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving - a TCP port. - properties: - host: - description: 'Optional: Host name to connect - to, defaults to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: Number or name of the port to access - on the container. Number must be in the range - 1 to 65535. Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: Optional duration in seconds the pod - needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after - the processes running in the pod are sent a termination - signal and the time when the processes are forcibly - halted with a kill signal. Set this value longer - than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds - will be used. Otherwise, this value overrides - the value provided by the pod spec. Value must - be non-negative integer. The value zero indicates - stop immediately via the kill signal (no opportunity - to shut down). This is a beta field and requires - enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds - is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: 'Number of seconds after which the - probe times out. Defaults to 1 second. Minimum - value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' - format: int32 - type: integer - type: object - stdin: - description: Whether this container should allocate - a buffer for stdin in the container runtime. If this - is not set, reads from stdin in the container will - always result in EOF. Default is false. - type: boolean - stdinOnce: - description: Whether the container runtime should close - the stdin channel after it has been opened by a single - attach. When stdin is true the stdin stream will remain - open across multiple attach sessions. If stdinOnce - is set to true, stdin is opened on container start, - is empty until the first client attaches to stdin, - and then remains open and accepts data until the client - disconnects, at which time stdin is closed and remains - closed until the container is restarted. If this flag - is false, a container processes that reads from stdin - will never receive an EOF. Default is false - type: boolean - terminationMessagePath: - description: 'Optional: Path at which the file to which - the container''s termination message will be written - is mounted into the container''s filesystem. Message - written is intended to be brief final status, such - as an assertion failure message. Will be truncated - by the node if greater than 4096 bytes. The total - message length across all containers will be limited - to 12kb. Defaults to /dev/termination-log. Cannot - be updated.' - type: string - terminationMessagePolicy: - description: Indicate how the termination message should - be populated. File will use the contents of terminationMessagePath - to populate the container status message on both success - and failure. FallbackToLogsOnError will use the last - chunk of container log output if the termination message - file is empty and the container exited with an error. - The log output is limited to 2048 bytes or 80 lines, - whichever is smaller. Defaults to File. Cannot be - updated. - type: string - tty: - description: Whether this container should allocate - a TTY for itself, also requires 'stdin' to be true. - Default is false. - type: boolean - volumeDevices: - description: volumeDevices is the list of block devices - to be used by the container. - items: - description: volumeDevice describes a mapping of a - raw block device within a container. - properties: - devicePath: - description: devicePath is the path inside of - the container that the device will be mapped - to. - type: string - name: - description: name must match the name of a persistentVolumeClaim - in the pod - type: string - required: - - devicePath - - name - type: object - type: array - volumeMounts: - description: Pod volumes to mount into the container's - filesystem. Cannot be updated. - items: - description: VolumeMount describes a mounting of a - Volume within a container. - properties: - mountPath: - description: Path within the container at which - the volume should be mounted. Must not contain - ':'. - type: string - mountPropagation: - description: mountPropagation determines how mounts - are propagated from the host to container and - the other way around. When not set, MountPropagationNone - is used. This field is beta in 1.10. - type: string - name: - description: This must match the Name of a Volume. - type: string - readOnly: - description: Mounted read-only if true, read-write - otherwise (false or unspecified). Defaults to - false. - type: boolean - subPath: - description: Path within the volume from which - the container's volume should be mounted. Defaults - to "" (volume's root). - type: string - subPathExpr: - description: Expanded path within the volume from - which the container's volume should be mounted. - Behaves similarly to SubPath but environment - variable references $(VAR_NAME) are expanded - using the container's environment. Defaults - to "" (volume's root). SubPathExpr and SubPath - are mutually exclusive. - type: string - required: - - mountPath - - name - type: object - type: array - workingDir: - description: Container's working directory. If not specified, - the container runtime's default will be used, which - might be configured in the container image. Cannot - be updated. - type: string - required: - - name - type: object - type: array - dnsConfig: - description: Specifies the DNS parameters of a pod. Parameters - specified here will be merged to the generated DNS configuration - based on DNSPolicy. - properties: - nameservers: - description: A list of DNS name server IP addresses. This - will be appended to the base nameservers generated from - DNSPolicy. Duplicated nameservers will be removed. - items: - type: string - type: array - options: - description: A list of DNS resolver options. This will - be merged with the base options generated from DNSPolicy. - Duplicated entries will be removed. Resolution options - given in Options will override those that appear in - the base DNSPolicy. - items: - description: PodDNSConfigOption defines DNS resolver - options of a pod. - properties: - name: - description: Required. - type: string - value: - type: string - type: object - type: array - searches: - description: A list of DNS search domains for host-name - lookup. This will be appended to the base search paths - generated from DNSPolicy. Duplicated search paths will - be removed. - items: - type: string - type: array - type: object - dnsPolicy: - description: Set DNS policy for the pod. Defaults to "ClusterFirst". - Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', - 'Default' or 'None'. DNS parameters given in DNSConfig will - be merged with the policy selected with DNSPolicy. To have - DNS options set along with hostNetwork, you have to specify - DNS policy explicitly to 'ClusterFirstWithHostNet'. - type: string - enableServiceLinks: - description: 'EnableServiceLinks indicates whether information - about services should be injected into pod''s environment - variables, matching the syntax of Docker links. Optional: - Defaults to true.' - type: boolean - ephemeralContainers: - description: List of ephemeral containers run in this pod. - Ephemeral containers may be run in an existing pod to perform - user-initiated actions such as debugging. This list cannot - be specified when creating a pod, and it cannot be modified - by updating the pod spec. In order to add an ephemeral container - to an existing pod, use the pod's ephemeralcontainers subresource. - items: - description: "An EphemeralContainer is a temporary container - that you may add to an existing Pod for user-initiated - activities such as debugging. Ephemeral containers have - no resource or scheduling guarantees, and they will not - be restarted when they exit or when a Pod is removed or - restarted. The kubelet may evict a Pod if an ephemeral - container causes the Pod to exceed its resource allocation. - \n To add an ephemeral container, use the ephemeralcontainers - subresource of an existing Pod. Ephemeral containers may - not be removed or restarted." - properties: - args: - description: 'Arguments to the entrypoint. The image''s - CMD is used if this is not provided. Variable references - $(VAR_NAME) are expanded using the container''s environment. - If a variable cannot be resolved, the reference in - the input string will be unchanged. Double $$ are - reduced to a single $, which allows for escaping the - $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce - the string literal "$(VAR_NAME)". Escaped references - will never be expanded, regardless of whether the - variable exists or not. Cannot be updated. More info: - https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' - items: - type: string - type: array - command: - description: 'Entrypoint array. Not executed within - a shell. The image''s ENTRYPOINT is used if this is - not provided. Variable references $(VAR_NAME) are - expanded using the container''s environment. If a - variable cannot be resolved, the reference in the - input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) - syntax: i.e. "$$(VAR_NAME)" will produce the string - literal "$(VAR_NAME)". Escaped references will never - be expanded, regardless of whether the variable exists - or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' - items: - type: string - type: array - env: - description: List of environment variables to set in - the container. Cannot be updated. - items: - description: EnvVar represents an environment variable - present in a Container. - properties: - name: - description: Name of the environment variable. - Must be a C_IDENTIFIER. - type: string - value: - description: 'Variable references $(VAR_NAME) - are expanded using the previously defined environment - variables in the container and any service environment - variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. - Double $$ are reduced to a single $, which allows - for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" - will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless - of whether the variable exists or not. Defaults - to "".' - type: string - valueFrom: - description: Source for the environment variable's - value. Cannot be used if value is not empty. - properties: - configMapKeyRef: - description: Selects a key of a ConfigMap. - properties: - key: - description: The key to select. - type: string - name: - description: 'Name of the referent. More - info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - fieldRef: - description: 'Selects a field of the pod: - supports metadata.name, metadata.namespace, - `metadata.labels['''']`, `metadata.annotations['''']`, - spec.nodeName, spec.serviceAccountName, - status.hostIP, status.podIP, status.podIPs.' - properties: - apiVersion: - description: Version of the schema the - FieldPath is written in terms of, defaults - to "v1". - type: string - fieldPath: - description: Path of the field to select - in the specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - resourceFieldRef: - description: 'Selects a resource of the container: - only resources limits and requests (limits.cpu, - limits.memory, limits.ephemeral-storage, - requests.cpu, requests.memory and requests.ephemeral-storage) - are currently supported.' - properties: - containerName: - description: 'Container name: required - for volumes, optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format - of the exposed resources, defaults to - "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret in - the pod's namespace - properties: - key: - description: The key of the secret to - select from. Must be a valid secret - key. - type: string - name: - description: 'Name of the referent. More - info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - required: - - name - type: object - type: array - envFrom: - description: List of sources to populate environment - variables in the container. The keys defined within - a source must be a C_IDENTIFIER. All invalid keys - will be reported as an event when the container is - starting. When a key exists in multiple sources, the - value associated with the last source will take precedence. - Values defined by an Env with a duplicate key will - take precedence. Cannot be updated. - items: - description: EnvFromSource represents the source of - a set of ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' - type: string - optional: - description: Specify whether the ConfigMap - must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - prefix: - description: An optional identifier to prepend - to each key in the ConfigMap. Must be a C_IDENTIFIER. - type: string - secretRef: - description: The Secret to select from - properties: - name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' - type: string - optional: - description: Specify whether the Secret must - be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - type: object - type: array - image: - description: 'Container image name. More info: https://kubernetes.io/docs/concepts/containers/images' - type: string - imagePullPolicy: - description: 'Image pull policy. One of Always, Never, - IfNotPresent. Defaults to Always if :latest tag is - specified, or IfNotPresent otherwise. Cannot be updated. - More info: https://kubernetes.io/docs/concepts/containers/images#updating-images' - type: string - lifecycle: - description: Lifecycle is not allowed for ephemeral - containers. - properties: - postStart: - description: 'PostStart is called immediately after - a container is created. If the handler fails, - the container is terminated and restarted according - to its restart policy. Other management of the - container blocks until the hook completes. More - info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: Command is the command line - to execute inside the container, the working - directory for the command is root ('/') - in the container's filesystem. The command - is simply exec'd, it is not run inside - a shell, so traditional shell instructions - ('|', etc) won't work. To use a shell, - you need to explicitly call out to that - shell. Exit status of 0 is treated as - live/healthy and non-zero is unhealthy. - items: - type: string - type: array - type: object - httpGet: - description: HTTPGet specifies the http request - to perform. - properties: - host: - description: Host name to connect to, defaults - to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the - request. HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom - header to be used in HTTP probes - properties: - name: - description: The header field name - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - path: - description: Path to access on the HTTP - server. - type: string - port: - anyOf: - - type: integer - - type: string - description: Name or number of the port - to access on the container. Number must - be in the range 1 to 65535. Name must - be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: Scheme to use for connecting - to the host. Defaults to HTTP. - type: string - required: - - port - type: object - tcpSocket: - description: Deprecated. TCPSocket is NOT supported - as a LifecycleHandler and kept for the backward - compatibility. There are no validation of - this field and lifecycle hooks will fail in - runtime when tcp handler is specified. - properties: - host: - description: 'Optional: Host name to connect - to, defaults to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: Number or name of the port - to access on the container. Number must - be in the range 1 to 65535. Name must - be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - type: object - preStop: - description: 'PreStop is called immediately before - a container is terminated due to an API request - or management event such as liveness/startup probe - failure, preemption, resource contention, etc. - The handler is not called if the container crashes - or exits. The Pod''s termination grace period - countdown begins before the PreStop hook is executed. - Regardless of the outcome of the handler, the - container will eventually terminate within the - Pod''s termination grace period (unless delayed - by finalizers). Other management of the container - blocks until the hook completes or until the termination - grace period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: Command is the command line - to execute inside the container, the working - directory for the command is root ('/') - in the container's filesystem. The command - is simply exec'd, it is not run inside - a shell, so traditional shell instructions - ('|', etc) won't work. To use a shell, - you need to explicitly call out to that - shell. Exit status of 0 is treated as - live/healthy and non-zero is unhealthy. - items: - type: string - type: array - type: object - httpGet: - description: HTTPGet specifies the http request - to perform. - properties: - host: - description: Host name to connect to, defaults - to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the - request. HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom - header to be used in HTTP probes - properties: - name: - description: The header field name - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - path: - description: Path to access on the HTTP - server. - type: string - port: - anyOf: - - type: integer - - type: string - description: Name or number of the port - to access on the container. Number must - be in the range 1 to 65535. Name must - be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: Scheme to use for connecting - to the host. Defaults to HTTP. - type: string - required: - - port - type: object - tcpSocket: - description: Deprecated. TCPSocket is NOT supported - as a LifecycleHandler and kept for the backward - compatibility. There are no validation of - this field and lifecycle hooks will fail in - runtime when tcp handler is specified. - properties: - host: - description: 'Optional: Host name to connect - to, defaults to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: Number or name of the port - to access on the container. Number must - be in the range 1 to 65535. Name must - be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - type: object - type: object - livenessProbe: - description: Probes are not allowed for ephemeral containers. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: Command is the command line to - execute inside the container, the working - directory for the command is root ('/') in - the container's filesystem. The command is - simply exec'd, it is not run inside a shell, - so traditional shell instructions ('|', etc) - won't work. To use a shell, you need to explicitly - call out to that shell. Exit status of 0 is - treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - type: object - failureThreshold: - description: Minimum consecutive failures for the - probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving - a GRPC port. This is a beta field and requires - enabling GRPCContainerProbe feature gate. - properties: - port: - description: Port number of the gRPC service. - Number must be in the range 1 to 65535. - format: int32 - type: integer - service: - description: "Service is the name of the service - to place in the gRPC HealthCheckRequest (see - https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - \n If this is not specified, the default behavior - is defined by gRPC." - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request - to perform. - properties: - host: - description: Host name to connect to, defaults - to the pod IP. You probably want to set "Host" - in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. - HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom - header to be used in HTTP probes - properties: - name: - description: The header field name - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: Name or number of the port to access - on the container. Number must be in the range - 1 to 65535. Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: Scheme to use for connecting to - the host. Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: 'Number of seconds after the container - has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' - format: int32 - type: integer - periodSeconds: - description: How often (in seconds) to perform the - probe. Default to 10 seconds. Minimum value is - 1. - format: int32 - type: integer - successThreshold: - description: Minimum consecutive successes for the - probe to be considered successful after having - failed. Defaults to 1. Must be 1 for liveness - and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving - a TCP port. - properties: - host: - description: 'Optional: Host name to connect - to, defaults to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: Number or name of the port to access - on the container. Number must be in the range - 1 to 65535. Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: Optional duration in seconds the pod - needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after - the processes running in the pod are sent a termination - signal and the time when the processes are forcibly - halted with a kill signal. Set this value longer - than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds - will be used. Otherwise, this value overrides - the value provided by the pod spec. Value must - be non-negative integer. The value zero indicates - stop immediately via the kill signal (no opportunity - to shut down). This is a beta field and requires - enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds - is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: 'Number of seconds after which the - probe times out. Defaults to 1 second. Minimum - value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' - format: int32 - type: integer - type: object - name: - description: Name of the ephemeral container specified - as a DNS_LABEL. This name must be unique among all - containers, init containers and ephemeral containers. - type: string - ports: - description: Ports are not allowed for ephemeral containers. - items: - description: ContainerPort represents a network port - in a single container. - properties: - containerPort: - description: Number of port to expose on the pod's - IP address. This must be a valid port number, - 0 < x < 65536. - format: int32 - type: integer - hostIP: - description: What host IP to bind the external - port to. - type: string - hostPort: - description: Number of port to expose on the host. - If specified, this must be a valid port number, - 0 < x < 65536. If HostNetwork is specified, - this must match ContainerPort. Most containers - do not need this. - format: int32 - type: integer - name: - description: If specified, this must be an IANA_SVC_NAME - and unique within the pod. Each named port in - a pod must have a unique name. Name for the - port that can be referred to by services. - type: string - protocol: - default: TCP - description: Protocol for port. Must be UDP, TCP, - or SCTP. Defaults to "TCP". - type: string - required: - - containerPort - type: object - type: array - x-kubernetes-list-map-keys: - - containerPort - - protocol - x-kubernetes-list-type: map - readinessProbe: - description: Probes are not allowed for ephemeral containers. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: Command is the command line to - execute inside the container, the working - directory for the command is root ('/') in - the container's filesystem. The command is - simply exec'd, it is not run inside a shell, - so traditional shell instructions ('|', etc) - won't work. To use a shell, you need to explicitly - call out to that shell. Exit status of 0 is - treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - type: object - failureThreshold: - description: Minimum consecutive failures for the - probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving - a GRPC port. This is a beta field and requires - enabling GRPCContainerProbe feature gate. - properties: - port: - description: Port number of the gRPC service. - Number must be in the range 1 to 65535. - format: int32 - type: integer - service: - description: "Service is the name of the service - to place in the gRPC HealthCheckRequest (see - https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - \n If this is not specified, the default behavior - is defined by gRPC." - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request - to perform. - properties: - host: - description: Host name to connect to, defaults - to the pod IP. You probably want to set "Host" - in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. - HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom - header to be used in HTTP probes - properties: - name: - description: The header field name - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: Name or number of the port to access - on the container. Number must be in the range - 1 to 65535. Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: Scheme to use for connecting to - the host. Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: 'Number of seconds after the container - has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' - format: int32 - type: integer - periodSeconds: - description: How often (in seconds) to perform the - probe. Default to 10 seconds. Minimum value is - 1. - format: int32 - type: integer - successThreshold: - description: Minimum consecutive successes for the - probe to be considered successful after having - failed. Defaults to 1. Must be 1 for liveness - and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving - a TCP port. - properties: - host: - description: 'Optional: Host name to connect - to, defaults to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: Number or name of the port to access - on the container. Number must be in the range - 1 to 65535. Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: Optional duration in seconds the pod - needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after - the processes running in the pod are sent a termination - signal and the time when the processes are forcibly - halted with a kill signal. Set this value longer - than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds - will be used. Otherwise, this value overrides - the value provided by the pod spec. Value must - be non-negative integer. The value zero indicates - stop immediately via the kill signal (no opportunity - to shut down). This is a beta field and requires - enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds - is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: 'Number of seconds after which the - probe times out. Defaults to 1 second. Minimum - value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' - format: int32 - type: integer - type: object - resources: - description: Resources are not allowed for ephemeral - containers. Ephemeral containers use spare resources - already allocated to the pod. - properties: - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: 'Limits describes the maximum amount - of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: 'Requests describes the minimum amount - of compute resources required. If Requests is - omitted for a container, it defaults to Limits - if that is explicitly specified, otherwise to - an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' - type: object - type: object - securityContext: - description: 'Optional: SecurityContext defines the - security options the ephemeral container should be - run with. If set, the fields of SecurityContext override - the equivalent fields of PodSecurityContext.' - properties: - allowPrivilegeEscalation: - description: 'AllowPrivilegeEscalation controls - whether a process can gain more privileges than - its parent process. This bool directly controls - if the no_new_privs flag will be set on the container - process. AllowPrivilegeEscalation is true always - when the container is: 1) run as Privileged 2) - has CAP_SYS_ADMIN Note that this field cannot - be set when spec.os.name is windows.' - type: boolean - capabilities: - description: The capabilities to add/drop when running - containers. Defaults to the default set of capabilities - granted by the container runtime. Note that this - field cannot be set when spec.os.name is windows. - properties: - add: - description: Added capabilities - items: - description: Capability represent POSIX capabilities - type - type: string - type: array - drop: - description: Removed capabilities - items: - description: Capability represent POSIX capabilities - type - type: string - type: array - type: object - privileged: - description: Run container in privileged mode. Processes - in privileged containers are essentially equivalent - to root on the host. Defaults to false. Note that - this field cannot be set when spec.os.name is - windows. - type: boolean - procMount: - description: procMount denotes the type of proc - mount to use for the containers. The default is - DefaultProcMount which uses the container runtime - defaults for readonly paths and masked paths. - This requires the ProcMountType feature flag to - be enabled. Note that this field cannot be set - when spec.os.name is windows. - type: string - readOnlyRootFilesystem: - description: Whether this container has a read-only - root filesystem. Default is false. Note that this - field cannot be set when spec.os.name is windows. - type: boolean - runAsGroup: - description: The GID to run the entrypoint of the - container process. Uses runtime default if unset. - May also be set in PodSecurityContext. If set - in both SecurityContext and PodSecurityContext, - the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name - is windows. - format: int64 - type: integer - runAsNonRoot: - description: Indicates that the container must run - as a non-root user. If true, the Kubelet will - validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start - the container if it does. If unset or false, no - such validation will be performed. May also be - set in PodSecurityContext. If set in both SecurityContext - and PodSecurityContext, the value specified in - SecurityContext takes precedence. - type: boolean - runAsUser: - description: The UID to run the entrypoint of the - container process. Defaults to user specified - in image metadata if unspecified. May also be - set in PodSecurityContext. If set in both SecurityContext - and PodSecurityContext, the value specified in - SecurityContext takes precedence. Note that this - field cannot be set when spec.os.name is windows. - format: int64 - type: integer - seLinuxOptions: - description: The SELinux context to be applied to - the container. If unspecified, the container runtime - will allocate a random SELinux context for each - container. May also be set in PodSecurityContext. If - set in both SecurityContext and PodSecurityContext, - the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name - is windows. - properties: - level: - description: Level is SELinux level label that - applies to the container. - type: string - role: - description: Role is a SELinux role label that - applies to the container. - type: string - type: - description: Type is a SELinux type label that - applies to the container. - type: string - user: - description: User is a SELinux user label that - applies to the container. - type: string - type: object - seccompProfile: - description: The seccomp options to use by this - container. If seccomp options are provided at - both the pod & container level, the container - options override the pod options. Note that this - field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: localhostProfile indicates a profile - defined in a file on the node should be used. - The profile must be preconfigured on the node - to work. Must be a descending path, relative - to the kubelet's configured seccomp profile - location. Must only be set if type is "Localhost". - type: string - type: - description: "type indicates which kind of seccomp - profile will be applied. Valid options are: - \n Localhost - a profile defined in a file - on the node should be used. RuntimeDefault - - the container runtime default profile should - be used. Unconfined - no profile should be - applied." - type: string - required: - - type - type: object - windowsOptions: - description: The Windows specific settings applied - to all containers. If unspecified, the options - from the PodSecurityContext will be used. If set - in both SecurityContext and PodSecurityContext, - the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name - is linux. - properties: - gmsaCredentialSpec: - description: GMSACredentialSpec is where the - GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) - inlines the contents of the GMSA credential - spec named by the GMSACredentialSpecName field. - type: string - gmsaCredentialSpecName: - description: GMSACredentialSpecName is the name - of the GMSA credential spec to use. - type: string - hostProcess: - description: HostProcess determines if a container - should be run as a 'Host Process' container. - This field is alpha-level and will only be - honored by components that enable the WindowsHostProcessContainers - feature flag. Setting this field without the - feature flag will result in errors when validating - the Pod. All of a Pod's containers must have - the same effective HostProcess value (it is - not allowed to have a mix of HostProcess containers - and non-HostProcess containers). In addition, - if HostProcess is true then HostNetwork must - also be set to true. - type: boolean - runAsUserName: - description: The UserName in Windows to run - the entrypoint of the container process. Defaults - to the user specified in image metadata if - unspecified. May also be set in PodSecurityContext. - If set in both SecurityContext and PodSecurityContext, - the value specified in SecurityContext takes - precedence. - type: string - type: object - type: object - startupProbe: - description: Probes are not allowed for ephemeral containers. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: Command is the command line to - execute inside the container, the working - directory for the command is root ('/') in - the container's filesystem. The command is - simply exec'd, it is not run inside a shell, - so traditional shell instructions ('|', etc) - won't work. To use a shell, you need to explicitly - call out to that shell. Exit status of 0 is - treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - type: object - failureThreshold: - description: Minimum consecutive failures for the - probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving - a GRPC port. This is a beta field and requires - enabling GRPCContainerProbe feature gate. - properties: - port: - description: Port number of the gRPC service. - Number must be in the range 1 to 65535. - format: int32 - type: integer - service: - description: "Service is the name of the service - to place in the gRPC HealthCheckRequest (see - https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - \n If this is not specified, the default behavior - is defined by gRPC." - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request - to perform. - properties: - host: - description: Host name to connect to, defaults - to the pod IP. You probably want to set "Host" - in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. - HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom - header to be used in HTTP probes - properties: - name: - description: The header field name - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: Name or number of the port to access - on the container. Number must be in the range - 1 to 65535. Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: Scheme to use for connecting to - the host. Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: 'Number of seconds after the container - has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' - format: int32 - type: integer - periodSeconds: - description: How often (in seconds) to perform the - probe. Default to 10 seconds. Minimum value is - 1. - format: int32 - type: integer - successThreshold: - description: Minimum consecutive successes for the - probe to be considered successful after having - failed. Defaults to 1. Must be 1 for liveness - and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving - a TCP port. - properties: - host: - description: 'Optional: Host name to connect - to, defaults to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: Number or name of the port to access - on the container. Number must be in the range - 1 to 65535. Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: Optional duration in seconds the pod - needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after - the processes running in the pod are sent a termination - signal and the time when the processes are forcibly - halted with a kill signal. Set this value longer - than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds - will be used. Otherwise, this value overrides - the value provided by the pod spec. Value must - be non-negative integer. The value zero indicates - stop immediately via the kill signal (no opportunity - to shut down). This is a beta field and requires - enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds - is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: 'Number of seconds after which the - probe times out. Defaults to 1 second. Minimum - value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' - format: int32 - type: integer - type: object - stdin: - description: Whether this container should allocate - a buffer for stdin in the container runtime. If this - is not set, reads from stdin in the container will - always result in EOF. Default is false. - type: boolean - stdinOnce: - description: Whether the container runtime should close - the stdin channel after it has been opened by a single - attach. When stdin is true the stdin stream will remain - open across multiple attach sessions. If stdinOnce - is set to true, stdin is opened on container start, - is empty until the first client attaches to stdin, - and then remains open and accepts data until the client - disconnects, at which time stdin is closed and remains - closed until the container is restarted. If this flag - is false, a container processes that reads from stdin - will never receive an EOF. Default is false - type: boolean - targetContainerName: - description: "If set, the name of the container from - PodSpec that this ephemeral container targets. The - ephemeral container will be run in the namespaces - (IPC, PID, etc) of this container. If not set then - the ephemeral container uses the namespaces configured - in the Pod spec. \n The container runtime must implement - support for this feature. If the runtime does not - support namespace targeting then the result of setting - this field is undefined." - type: string - terminationMessagePath: - description: 'Optional: Path at which the file to which - the container''s termination message will be written - is mounted into the container''s filesystem. Message - written is intended to be brief final status, such - as an assertion failure message. Will be truncated - by the node if greater than 4096 bytes. The total - message length across all containers will be limited - to 12kb. Defaults to /dev/termination-log. Cannot - be updated.' - type: string - terminationMessagePolicy: - description: Indicate how the termination message should - be populated. File will use the contents of terminationMessagePath - to populate the container status message on both success - and failure. FallbackToLogsOnError will use the last - chunk of container log output if the termination message - file is empty and the container exited with an error. - The log output is limited to 2048 bytes or 80 lines, - whichever is smaller. Defaults to File. Cannot be - updated. - type: string - tty: - description: Whether this container should allocate - a TTY for itself, also requires 'stdin' to be true. - Default is false. - type: boolean - volumeDevices: - description: volumeDevices is the list of block devices - to be used by the container. - items: - description: volumeDevice describes a mapping of a - raw block device within a container. - properties: - devicePath: - description: devicePath is the path inside of - the container that the device will be mapped - to. - type: string - name: - description: name must match the name of a persistentVolumeClaim - in the pod - type: string - required: - - devicePath - - name - type: object - type: array - volumeMounts: - description: Pod volumes to mount into the container's - filesystem. Subpath mounts are not allowed for ephemeral - containers. Cannot be updated. - items: - description: VolumeMount describes a mounting of a - Volume within a container. - properties: - mountPath: - description: Path within the container at which - the volume should be mounted. Must not contain - ':'. - type: string - mountPropagation: - description: mountPropagation determines how mounts - are propagated from the host to container and - the other way around. When not set, MountPropagationNone - is used. This field is beta in 1.10. - type: string - name: - description: This must match the Name of a Volume. - type: string - readOnly: - description: Mounted read-only if true, read-write - otherwise (false or unspecified). Defaults to - false. - type: boolean - subPath: - description: Path within the volume from which - the container's volume should be mounted. Defaults - to "" (volume's root). - type: string - subPathExpr: - description: Expanded path within the volume from - which the container's volume should be mounted. - Behaves similarly to SubPath but environment - variable references $(VAR_NAME) are expanded - using the container's environment. Defaults - to "" (volume's root). SubPathExpr and SubPath - are mutually exclusive. - type: string - required: - - mountPath - - name - type: object - type: array - workingDir: - description: Container's working directory. If not specified, - the container runtime's default will be used, which - might be configured in the container image. Cannot - be updated. - type: string - required: - - name - type: object - type: array - hostAliases: - description: HostAliases is an optional list of hosts and - IPs that will be injected into the pod's hosts file if specified. - This is only valid for non-hostNetwork pods. - items: - description: HostAlias holds the mapping between IP and - hostnames that will be injected as an entry in the pod's - hosts file. - properties: - hostnames: - description: Hostnames for the above IP address. - items: - type: string - type: array - ip: - description: IP address of the host file entry. - type: string - type: object - type: array - hostIPC: - description: 'Use the host''s ipc namespace. Optional: Default - to false.' - type: boolean - hostNetwork: - description: Host networking requested for this pod. Use the - host's network namespace. If this option is set, the ports - that will be used must be specified. Default to false. - type: boolean - hostPID: - description: 'Use the host''s pid namespace. Optional: Default - to false.' - type: boolean - hostUsers: - description: 'Use the host''s user namespace. Optional: Default - to true. If set to true or not present, the pod will be - run in the host user namespace, useful for when the pod - needs a feature only available to the host user namespace, - such as loading a kernel module with CAP_SYS_MODULE. When - set to false, a new userns is created for the pod. Setting - false is useful for mitigating container breakout vulnerabilities - even allowing users to run their containers as root without - actually having root privileges on the host. This field - is alpha-level and is only honored by servers that enable - the UserNamespacesSupport feature.' - type: boolean - hostname: - description: Specifies the hostname of the Pod If not specified, - the pod's hostname will be set to a system-defined value. - type: string - imagePullSecrets: - description: 'ImagePullSecrets is an optional list of references - to secrets in the same namespace to use for pulling any - of the images used by this PodSpec. If specified, these - secrets will be passed to individual puller implementations - for them to use. More info: https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod' - items: - description: LocalObjectReference contains enough information - to let you locate the referenced object inside the same - namespace. - properties: - name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid?' - type: string - type: object - x-kubernetes-map-type: atomic - type: array - initContainers: - description: 'List of initialization containers belonging - to the pod. Init containers are executed in order prior - to containers being started. If any init container fails, - the pod is considered to have failed and is handled according - to its restartPolicy. The name for an init container or - normal container must be unique among all containers. Init - containers may not have Lifecycle actions, Readiness probes, - Liveness probes, or Startup probes. The resourceRequirements - of an init container are taken into account during scheduling - by finding the highest request/limit for each resource type, - and then using the max of of that value or the sum of the - normal containers. Limits are applied to init containers - in a similar fashion. Init containers cannot currently be - added or removed. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/' - items: - description: A single application container that you want - to run within a pod. - properties: - args: - description: 'Arguments to the entrypoint. The container - image''s CMD is used if this is not provided. Variable - references $(VAR_NAME) are expanded using the container''s - environment. If a variable cannot be resolved, the - reference in the input string will be unchanged. Double - $$ are reduced to a single $, which allows for escaping - the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce - the string literal "$(VAR_NAME)". Escaped references - will never be expanded, regardless of whether the - variable exists or not. Cannot be updated. More info: - https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' - items: - type: string - type: array - command: - description: 'Entrypoint array. Not executed within - a shell. The container image''s ENTRYPOINT is used - if this is not provided. Variable references $(VAR_NAME) - are expanded using the container''s environment. If - a variable cannot be resolved, the reference in the - input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) - syntax: i.e. "$$(VAR_NAME)" will produce the string - literal "$(VAR_NAME)". Escaped references will never - be expanded, regardless of whether the variable exists - or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' - items: - type: string - type: array - env: - description: List of environment variables to set in - the container. Cannot be updated. - items: - description: EnvVar represents an environment variable - present in a Container. - properties: - name: - description: Name of the environment variable. - Must be a C_IDENTIFIER. - type: string - value: - description: 'Variable references $(VAR_NAME) - are expanded using the previously defined environment - variables in the container and any service environment - variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. - Double $$ are reduced to a single $, which allows - for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" - will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless - of whether the variable exists or not. Defaults - to "".' - type: string - valueFrom: - description: Source for the environment variable's - value. Cannot be used if value is not empty. - properties: - configMapKeyRef: - description: Selects a key of a ConfigMap. - properties: - key: - description: The key to select. - type: string - name: - description: 'Name of the referent. More - info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - fieldRef: - description: 'Selects a field of the pod: - supports metadata.name, metadata.namespace, - `metadata.labels['''']`, `metadata.annotations['''']`, - spec.nodeName, spec.serviceAccountName, - status.hostIP, status.podIP, status.podIPs.' - properties: - apiVersion: - description: Version of the schema the - FieldPath is written in terms of, defaults - to "v1". - type: string - fieldPath: - description: Path of the field to select - in the specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - resourceFieldRef: - description: 'Selects a resource of the container: - only resources limits and requests (limits.cpu, - limits.memory, limits.ephemeral-storage, - requests.cpu, requests.memory and requests.ephemeral-storage) - are currently supported.' - properties: - containerName: - description: 'Container name: required - for volumes, optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format - of the exposed resources, defaults to - "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret in - the pod's namespace - properties: - key: - description: The key of the secret to - select from. Must be a valid secret - key. - type: string - name: - description: 'Name of the referent. More - info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - required: - - name - type: object - type: array - envFrom: - description: List of sources to populate environment - variables in the container. The keys defined within - a source must be a C_IDENTIFIER. All invalid keys - will be reported as an event when the container is - starting. When a key exists in multiple sources, the - value associated with the last source will take precedence. - Values defined by an Env with a duplicate key will - take precedence. Cannot be updated. - items: - description: EnvFromSource represents the source of - a set of ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' - type: string - optional: - description: Specify whether the ConfigMap - must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - prefix: - description: An optional identifier to prepend - to each key in the ConfigMap. Must be a C_IDENTIFIER. - type: string - secretRef: - description: The Secret to select from - properties: - name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' - type: string - optional: - description: Specify whether the Secret must - be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - type: object - type: array - image: - description: 'Container image name. More info: https://kubernetes.io/docs/concepts/containers/images - This field is optional to allow higher level config - management to default or override container images - in workload controllers like Deployments and StatefulSets.' - type: string - imagePullPolicy: - description: 'Image pull policy. One of Always, Never, - IfNotPresent. Defaults to Always if :latest tag is - specified, or IfNotPresent otherwise. Cannot be updated. - More info: https://kubernetes.io/docs/concepts/containers/images#updating-images' - type: string - lifecycle: - description: Actions that the management system should - take in response to container lifecycle events. Cannot - be updated. - properties: - postStart: - description: 'PostStart is called immediately after - a container is created. If the handler fails, - the container is terminated and restarted according - to its restart policy. Other management of the - container blocks until the hook completes. More - info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: Command is the command line - to execute inside the container, the working - directory for the command is root ('/') - in the container's filesystem. The command - is simply exec'd, it is not run inside - a shell, so traditional shell instructions - ('|', etc) won't work. To use a shell, - you need to explicitly call out to that - shell. Exit status of 0 is treated as - live/healthy and non-zero is unhealthy. - items: - type: string - type: array - type: object - httpGet: - description: HTTPGet specifies the http request - to perform. - properties: - host: - description: Host name to connect to, defaults - to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the - request. HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom - header to be used in HTTP probes - properties: - name: - description: The header field name - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - path: - description: Path to access on the HTTP - server. - type: string - port: - anyOf: - - type: integer - - type: string - description: Name or number of the port - to access on the container. Number must - be in the range 1 to 65535. Name must - be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: Scheme to use for connecting - to the host. Defaults to HTTP. - type: string - required: - - port - type: object - tcpSocket: - description: Deprecated. TCPSocket is NOT supported - as a LifecycleHandler and kept for the backward - compatibility. There are no validation of - this field and lifecycle hooks will fail in - runtime when tcp handler is specified. - properties: - host: - description: 'Optional: Host name to connect - to, defaults to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: Number or name of the port - to access on the container. Number must - be in the range 1 to 65535. Name must - be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - type: object - preStop: - description: 'PreStop is called immediately before - a container is terminated due to an API request - or management event such as liveness/startup probe - failure, preemption, resource contention, etc. - The handler is not called if the container crashes - or exits. The Pod''s termination grace period - countdown begins before the PreStop hook is executed. - Regardless of the outcome of the handler, the - container will eventually terminate within the - Pod''s termination grace period (unless delayed - by finalizers). Other management of the container - blocks until the hook completes or until the termination - grace period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: Command is the command line - to execute inside the container, the working - directory for the command is root ('/') - in the container's filesystem. The command - is simply exec'd, it is not run inside - a shell, so traditional shell instructions - ('|', etc) won't work. To use a shell, - you need to explicitly call out to that - shell. Exit status of 0 is treated as - live/healthy and non-zero is unhealthy. - items: - type: string - type: array - type: object - httpGet: - description: HTTPGet specifies the http request - to perform. - properties: - host: - description: Host name to connect to, defaults - to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the - request. HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom - header to be used in HTTP probes - properties: - name: - description: The header field name - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - path: - description: Path to access on the HTTP - server. - type: string - port: - anyOf: - - type: integer - - type: string - description: Name or number of the port - to access on the container. Number must - be in the range 1 to 65535. Name must - be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: Scheme to use for connecting - to the host. Defaults to HTTP. - type: string - required: - - port - type: object - tcpSocket: - description: Deprecated. TCPSocket is NOT supported - as a LifecycleHandler and kept for the backward - compatibility. There are no validation of - this field and lifecycle hooks will fail in - runtime when tcp handler is specified. - properties: - host: - description: 'Optional: Host name to connect - to, defaults to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: Number or name of the port - to access on the container. Number must - be in the range 1 to 65535. Name must - be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - type: object - type: object - livenessProbe: - description: 'Periodic probe of container liveness. - Container will be restarted if the probe fails. Cannot - be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: Command is the command line to - execute inside the container, the working - directory for the command is root ('/') in - the container's filesystem. The command is - simply exec'd, it is not run inside a shell, - so traditional shell instructions ('|', etc) - won't work. To use a shell, you need to explicitly - call out to that shell. Exit status of 0 is - treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - type: object - failureThreshold: - description: Minimum consecutive failures for the - probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving - a GRPC port. This is a beta field and requires - enabling GRPCContainerProbe feature gate. - properties: - port: - description: Port number of the gRPC service. - Number must be in the range 1 to 65535. - format: int32 - type: integer - service: - description: "Service is the name of the service - to place in the gRPC HealthCheckRequest (see - https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - \n If this is not specified, the default behavior - is defined by gRPC." - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request - to perform. - properties: - host: - description: Host name to connect to, defaults - to the pod IP. You probably want to set "Host" - in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. - HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom - header to be used in HTTP probes - properties: - name: - description: The header field name - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: Name or number of the port to access - on the container. Number must be in the range - 1 to 65535. Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: Scheme to use for connecting to - the host. Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: 'Number of seconds after the container - has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' - format: int32 - type: integer - periodSeconds: - description: How often (in seconds) to perform the - probe. Default to 10 seconds. Minimum value is - 1. - format: int32 - type: integer - successThreshold: - description: Minimum consecutive successes for the - probe to be considered successful after having - failed. Defaults to 1. Must be 1 for liveness - and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving - a TCP port. - properties: - host: - description: 'Optional: Host name to connect - to, defaults to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: Number or name of the port to access - on the container. Number must be in the range - 1 to 65535. Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: Optional duration in seconds the pod - needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after - the processes running in the pod are sent a termination - signal and the time when the processes are forcibly - halted with a kill signal. Set this value longer - than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds - will be used. Otherwise, this value overrides - the value provided by the pod spec. Value must - be non-negative integer. The value zero indicates - stop immediately via the kill signal (no opportunity - to shut down). This is a beta field and requires - enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds - is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: 'Number of seconds after which the - probe times out. Defaults to 1 second. Minimum - value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' - format: int32 - type: integer - type: object - name: - description: Name of the container specified as a DNS_LABEL. - Each container in a pod must have a unique name (DNS_LABEL). - Cannot be updated. - type: string - ports: - description: List of ports to expose from the container. - Not specifying a port here DOES NOT prevent that port - from being exposed. Any port which is listening on - the default "0.0.0.0" address inside a container will - be accessible from the network. Modifying this array - with strategic merge patch may corrupt the data. For - more information See https://github.com/kubernetes/kubernetes/issues/108255. - Cannot be updated. - items: - description: ContainerPort represents a network port - in a single container. - properties: - containerPort: - description: Number of port to expose on the pod's - IP address. This must be a valid port number, - 0 < x < 65536. - format: int32 - type: integer - hostIP: - description: What host IP to bind the external - port to. - type: string - hostPort: - description: Number of port to expose on the host. - If specified, this must be a valid port number, - 0 < x < 65536. If HostNetwork is specified, - this must match ContainerPort. Most containers - do not need this. - format: int32 - type: integer - name: - description: If specified, this must be an IANA_SVC_NAME - and unique within the pod. Each named port in - a pod must have a unique name. Name for the - port that can be referred to by services. - type: string - protocol: - default: TCP - description: Protocol for port. Must be UDP, TCP, - or SCTP. Defaults to "TCP". - type: string - required: - - containerPort - type: object - type: array - x-kubernetes-list-map-keys: - - containerPort - - protocol - x-kubernetes-list-type: map - readinessProbe: - description: 'Periodic probe of container service readiness. - Container will be removed from service endpoints if - the probe fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: Command is the command line to - execute inside the container, the working - directory for the command is root ('/') in - the container's filesystem. The command is - simply exec'd, it is not run inside a shell, - so traditional shell instructions ('|', etc) - won't work. To use a shell, you need to explicitly - call out to that shell. Exit status of 0 is - treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - type: object - failureThreshold: - description: Minimum consecutive failures for the - probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving - a GRPC port. This is a beta field and requires - enabling GRPCContainerProbe feature gate. - properties: - port: - description: Port number of the gRPC service. - Number must be in the range 1 to 65535. - format: int32 - type: integer - service: - description: "Service is the name of the service - to place in the gRPC HealthCheckRequest (see - https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - \n If this is not specified, the default behavior - is defined by gRPC." - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request - to perform. - properties: - host: - description: Host name to connect to, defaults - to the pod IP. You probably want to set "Host" - in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. - HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom - header to be used in HTTP probes - properties: - name: - description: The header field name - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: Name or number of the port to access - on the container. Number must be in the range - 1 to 65535. Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: Scheme to use for connecting to - the host. Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: 'Number of seconds after the container - has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' - format: int32 - type: integer - periodSeconds: - description: How often (in seconds) to perform the - probe. Default to 10 seconds. Minimum value is - 1. - format: int32 - type: integer - successThreshold: - description: Minimum consecutive successes for the - probe to be considered successful after having - failed. Defaults to 1. Must be 1 for liveness - and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving - a TCP port. - properties: - host: - description: 'Optional: Host name to connect - to, defaults to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: Number or name of the port to access - on the container. Number must be in the range - 1 to 65535. Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: Optional duration in seconds the pod - needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after - the processes running in the pod are sent a termination - signal and the time when the processes are forcibly - halted with a kill signal. Set this value longer - than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds - will be used. Otherwise, this value overrides - the value provided by the pod spec. Value must - be non-negative integer. The value zero indicates - stop immediately via the kill signal (no opportunity - to shut down). This is a beta field and requires - enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds - is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: 'Number of seconds after which the - probe times out. Defaults to 1 second. Minimum - value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' - format: int32 - type: integer - type: object - resources: - description: 'Compute Resources required by this container. - Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' - properties: - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: 'Limits describes the maximum amount - of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: 'Requests describes the minimum amount - of compute resources required. If Requests is - omitted for a container, it defaults to Limits - if that is explicitly specified, otherwise to - an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' - type: object - type: object - securityContext: - description: 'SecurityContext defines the security options - the container should be run with. If set, the fields - of SecurityContext override the equivalent fields - of PodSecurityContext. More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/' - properties: - allowPrivilegeEscalation: - description: 'AllowPrivilegeEscalation controls - whether a process can gain more privileges than - its parent process. This bool directly controls - if the no_new_privs flag will be set on the container - process. AllowPrivilegeEscalation is true always - when the container is: 1) run as Privileged 2) - has CAP_SYS_ADMIN Note that this field cannot - be set when spec.os.name is windows.' - type: boolean - capabilities: - description: The capabilities to add/drop when running - containers. Defaults to the default set of capabilities - granted by the container runtime. Note that this - field cannot be set when spec.os.name is windows. - properties: - add: - description: Added capabilities - items: - description: Capability represent POSIX capabilities - type - type: string - type: array - drop: - description: Removed capabilities - items: - description: Capability represent POSIX capabilities - type - type: string - type: array - type: object - privileged: - description: Run container in privileged mode. Processes - in privileged containers are essentially equivalent - to root on the host. Defaults to false. Note that - this field cannot be set when spec.os.name is - windows. - type: boolean - procMount: - description: procMount denotes the type of proc - mount to use for the containers. The default is - DefaultProcMount which uses the container runtime - defaults for readonly paths and masked paths. - This requires the ProcMountType feature flag to - be enabled. Note that this field cannot be set - when spec.os.name is windows. - type: string - readOnlyRootFilesystem: - description: Whether this container has a read-only - root filesystem. Default is false. Note that this - field cannot be set when spec.os.name is windows. - type: boolean - runAsGroup: - description: The GID to run the entrypoint of the - container process. Uses runtime default if unset. - May also be set in PodSecurityContext. If set - in both SecurityContext and PodSecurityContext, - the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name - is windows. - format: int64 - type: integer - runAsNonRoot: - description: Indicates that the container must run - as a non-root user. If true, the Kubelet will - validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start - the container if it does. If unset or false, no - such validation will be performed. May also be - set in PodSecurityContext. If set in both SecurityContext - and PodSecurityContext, the value specified in - SecurityContext takes precedence. - type: boolean - runAsUser: - description: The UID to run the entrypoint of the - container process. Defaults to user specified - in image metadata if unspecified. May also be - set in PodSecurityContext. If set in both SecurityContext - and PodSecurityContext, the value specified in - SecurityContext takes precedence. Note that this - field cannot be set when spec.os.name is windows. - format: int64 - type: integer - seLinuxOptions: - description: The SELinux context to be applied to - the container. If unspecified, the container runtime - will allocate a random SELinux context for each - container. May also be set in PodSecurityContext. If - set in both SecurityContext and PodSecurityContext, - the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name - is windows. - properties: - level: - description: Level is SELinux level label that - applies to the container. - type: string - role: - description: Role is a SELinux role label that - applies to the container. - type: string - type: - description: Type is a SELinux type label that - applies to the container. - type: string - user: - description: User is a SELinux user label that - applies to the container. - type: string - type: object - seccompProfile: - description: The seccomp options to use by this - container. If seccomp options are provided at - both the pod & container level, the container - options override the pod options. Note that this - field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: localhostProfile indicates a profile - defined in a file on the node should be used. - The profile must be preconfigured on the node - to work. Must be a descending path, relative - to the kubelet's configured seccomp profile - location. Must only be set if type is "Localhost". - type: string - type: - description: "type indicates which kind of seccomp - profile will be applied. Valid options are: - \n Localhost - a profile defined in a file - on the node should be used. RuntimeDefault - - the container runtime default profile should - be used. Unconfined - no profile should be - applied." - type: string - required: - - type - type: object - windowsOptions: - description: The Windows specific settings applied - to all containers. If unspecified, the options - from the PodSecurityContext will be used. If set - in both SecurityContext and PodSecurityContext, - the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name - is linux. - properties: - gmsaCredentialSpec: - description: GMSACredentialSpec is where the - GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) - inlines the contents of the GMSA credential - spec named by the GMSACredentialSpecName field. - type: string - gmsaCredentialSpecName: - description: GMSACredentialSpecName is the name - of the GMSA credential spec to use. - type: string - hostProcess: - description: HostProcess determines if a container - should be run as a 'Host Process' container. - This field is alpha-level and will only be - honored by components that enable the WindowsHostProcessContainers - feature flag. Setting this field without the - feature flag will result in errors when validating - the Pod. All of a Pod's containers must have - the same effective HostProcess value (it is - not allowed to have a mix of HostProcess containers - and non-HostProcess containers). In addition, - if HostProcess is true then HostNetwork must - also be set to true. - type: boolean - runAsUserName: - description: The UserName in Windows to run - the entrypoint of the container process. Defaults - to the user specified in image metadata if - unspecified. May also be set in PodSecurityContext. - If set in both SecurityContext and PodSecurityContext, - the value specified in SecurityContext takes - precedence. - type: string - type: object - type: object - startupProbe: - description: 'StartupProbe indicates that the Pod has - successfully initialized. If specified, no other probes - are executed until this completes successfully. If - this probe fails, the Pod will be restarted, just - as if the livenessProbe failed. This can be used to - provide different probe parameters at the beginning - of a Pod''s lifecycle, when it might take a long time - to load data or warm a cache, than during steady-state - operation. This cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: Command is the command line to - execute inside the container, the working - directory for the command is root ('/') in - the container's filesystem. The command is - simply exec'd, it is not run inside a shell, - so traditional shell instructions ('|', etc) - won't work. To use a shell, you need to explicitly - call out to that shell. Exit status of 0 is - treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - type: object - failureThreshold: - description: Minimum consecutive failures for the - probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving - a GRPC port. This is a beta field and requires - enabling GRPCContainerProbe feature gate. - properties: - port: - description: Port number of the gRPC service. - Number must be in the range 1 to 65535. - format: int32 - type: integer - service: - description: "Service is the name of the service - to place in the gRPC HealthCheckRequest (see - https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - \n If this is not specified, the default behavior - is defined by gRPC." - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request - to perform. - properties: - host: - description: Host name to connect to, defaults - to the pod IP. You probably want to set "Host" - in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. - HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom - header to be used in HTTP probes - properties: - name: - description: The header field name - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: Name or number of the port to access - on the container. Number must be in the range - 1 to 65535. Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: Scheme to use for connecting to - the host. Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: 'Number of seconds after the container - has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' - format: int32 - type: integer - periodSeconds: - description: How often (in seconds) to perform the - probe. Default to 10 seconds. Minimum value is - 1. - format: int32 - type: integer - successThreshold: - description: Minimum consecutive successes for the - probe to be considered successful after having - failed. Defaults to 1. Must be 1 for liveness - and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving - a TCP port. - properties: - host: - description: 'Optional: Host name to connect - to, defaults to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: Number or name of the port to access - on the container. Number must be in the range - 1 to 65535. Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: Optional duration in seconds the pod - needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after - the processes running in the pod are sent a termination - signal and the time when the processes are forcibly - halted with a kill signal. Set this value longer - than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds - will be used. Otherwise, this value overrides - the value provided by the pod spec. Value must - be non-negative integer. The value zero indicates - stop immediately via the kill signal (no opportunity - to shut down). This is a beta field and requires - enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds - is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: 'Number of seconds after which the - probe times out. Defaults to 1 second. Minimum - value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' - format: int32 - type: integer - type: object - stdin: - description: Whether this container should allocate - a buffer for stdin in the container runtime. If this - is not set, reads from stdin in the container will - always result in EOF. Default is false. - type: boolean - stdinOnce: - description: Whether the container runtime should close - the stdin channel after it has been opened by a single - attach. When stdin is true the stdin stream will remain - open across multiple attach sessions. If stdinOnce - is set to true, stdin is opened on container start, - is empty until the first client attaches to stdin, - and then remains open and accepts data until the client - disconnects, at which time stdin is closed and remains - closed until the container is restarted. If this flag - is false, a container processes that reads from stdin - will never receive an EOF. Default is false - type: boolean - terminationMessagePath: - description: 'Optional: Path at which the file to which - the container''s termination message will be written - is mounted into the container''s filesystem. Message - written is intended to be brief final status, such - as an assertion failure message. Will be truncated - by the node if greater than 4096 bytes. The total - message length across all containers will be limited - to 12kb. Defaults to /dev/termination-log. Cannot - be updated.' - type: string - terminationMessagePolicy: - description: Indicate how the termination message should - be populated. File will use the contents of terminationMessagePath - to populate the container status message on both success - and failure. FallbackToLogsOnError will use the last - chunk of container log output if the termination message - file is empty and the container exited with an error. - The log output is limited to 2048 bytes or 80 lines, - whichever is smaller. Defaults to File. Cannot be - updated. - type: string - tty: - description: Whether this container should allocate - a TTY for itself, also requires 'stdin' to be true. - Default is false. - type: boolean - volumeDevices: - description: volumeDevices is the list of block devices - to be used by the container. - items: - description: volumeDevice describes a mapping of a - raw block device within a container. - properties: - devicePath: - description: devicePath is the path inside of - the container that the device will be mapped - to. - type: string - name: - description: name must match the name of a persistentVolumeClaim - in the pod - type: string - required: - - devicePath - - name - type: object - type: array - volumeMounts: - description: Pod volumes to mount into the container's - filesystem. Cannot be updated. - items: - description: VolumeMount describes a mounting of a - Volume within a container. - properties: - mountPath: - description: Path within the container at which - the volume should be mounted. Must not contain - ':'. - type: string - mountPropagation: - description: mountPropagation determines how mounts - are propagated from the host to container and - the other way around. When not set, MountPropagationNone - is used. This field is beta in 1.10. - type: string - name: - description: This must match the Name of a Volume. - type: string - readOnly: - description: Mounted read-only if true, read-write - otherwise (false or unspecified). Defaults to - false. - type: boolean - subPath: - description: Path within the volume from which - the container's volume should be mounted. Defaults - to "" (volume's root). - type: string - subPathExpr: - description: Expanded path within the volume from - which the container's volume should be mounted. - Behaves similarly to SubPath but environment - variable references $(VAR_NAME) are expanded - using the container's environment. Defaults - to "" (volume's root). SubPathExpr and SubPath - are mutually exclusive. - type: string - required: - - mountPath - - name - type: object - type: array - workingDir: - description: Container's working directory. If not specified, - the container runtime's default will be used, which - might be configured in the container image. Cannot - be updated. - type: string - required: - - name - type: object - type: array - nodeName: - description: NodeName is a request to schedule this pod onto - a specific node. If it is non-empty, the scheduler simply - schedules this pod onto that node, assuming that it fits - resource requirements. - type: string - nodeSelector: - additionalProperties: - type: string - description: 'NodeSelector is a selector which must be true - for the pod to fit on a node. Selector which must match - a node''s labels for the pod to be scheduled on that node. - More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/' - type: object - x-kubernetes-map-type: atomic - os: - description: "Specifies the OS of the containers in the pod. - Some pod and container fields are restricted if this is - set. \n If the OS field is set to linux, the following fields - must be unset: -securityContext.windowsOptions \n If the - OS field is set to windows, following fields must be unset: - - spec.hostPID - spec.hostIPC - spec.hostUsers - spec.securityContext.seLinuxOptions - - spec.securityContext.seccompProfile - spec.securityContext.fsGroup - - spec.securityContext.fsGroupChangePolicy - spec.securityContext.sysctls - - spec.shareProcessNamespace - spec.securityContext.runAsUser - - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups - - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile - - spec.containers[*].securityContext.capabilities - spec.containers[*].securityContext.readOnlyRootFilesystem - - spec.containers[*].securityContext.privileged - spec.containers[*].securityContext.allowPrivilegeEscalation - - spec.containers[*].securityContext.procMount - spec.containers[*].securityContext.runAsUser - - spec.containers[*].securityContext.runAsGroup" - properties: - name: - description: 'Name is the name of the operating system. - The currently supported values are linux and windows. - Additional value may be defined in future and can be - one of: https://github.com/opencontainers/runtime-spec/blob/master/config.md#platform-specific-configuration - Clients should expect to handle additional values and - treat unrecognized values in this field as os: null' - type: string - required: - - name - type: object - overhead: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: 'Overhead represents the resource overhead associated - with running a pod for a given RuntimeClass. This field - will be autopopulated at admission time by the RuntimeClass - admission controller. If the RuntimeClass admission controller - is enabled, overhead must not be set in Pod create requests. - The RuntimeClass admission controller will reject Pod create - requests which have the overhead already set. If RuntimeClass - is configured and selected in the PodSpec, Overhead will - be set to the value defined in the corresponding RuntimeClass, - otherwise it will remain unset and treated as zero. More - info: https://git.k8s.io/enhancements/keps/sig-node/688-pod-overhead/README.md' - type: object - preemptionPolicy: - description: PreemptionPolicy is the Policy for preempting - pods with lower priority. One of Never, PreemptLowerPriority. - Defaults to PreemptLowerPriority if unset. - type: string - priority: - description: The priority value. Various system components - use this field to find the priority of the pod. When Priority - Admission Controller is enabled, it prevents users from - setting this field. The admission controller populates this - field from PriorityClassName. The higher the value, the - higher the priority. - format: int32 - type: integer - priorityClassName: - description: If specified, indicates the pod's priority. "system-node-critical" - and "system-cluster-critical" are two special keywords which - indicate the highest priorities with the former being the - highest priority. Any other name must be defined by creating - a PriorityClass object with that name. If not specified, - the pod priority will be default or zero if there is no - default. - type: string - readinessGates: - description: 'If specified, all readiness gates will be evaluated - for pod readiness. A pod is ready when all its containers - are ready AND all conditions specified in the readiness - gates have status equal to "True" More info: https://git.k8s.io/enhancements/keps/sig-network/580-pod-readiness-gates' - items: - description: PodReadinessGate contains the reference to - a pod condition - properties: - conditionType: - description: ConditionType refers to a condition in - the pod's condition list with matching type. - type: string - required: - - conditionType - type: object - type: array - restartPolicy: - description: 'Restart policy for all containers within the - pod. One of Always, OnFailure, Never. Default to Always. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy' - type: string - runtimeClassName: - description: 'RuntimeClassName refers to a RuntimeClass object - in the node.k8s.io group, which should be used to run this - pod. If no RuntimeClass resource matches the named class, - the pod will not be run. If unset or empty, the "legacy" - RuntimeClass will be used, which is an implicit class with - an empty definition that uses the default runtime handler. - More info: https://git.k8s.io/enhancements/keps/sig-node/585-runtime-class' - type: string - schedulerName: - description: If specified, the pod will be dispatched by specified - scheduler. If not specified, the pod will be dispatched - by default scheduler. - type: string - securityContext: - description: 'SecurityContext holds pod-level security attributes - and common container settings. Optional: Defaults to empty. See - type description for default values of each field.' - properties: - fsGroup: - description: "A special supplemental group that applies - to all containers in a pod. Some volume types allow - the Kubelet to change the ownership of that volume to - be owned by the pod: \n 1. The owning GID will be the - FSGroup 2. The setgid bit is set (new files created - in the volume will be owned by FSGroup) 3. The permission - bits are OR'd with rw-rw---- \n If unset, the Kubelet - will not modify the ownership and permissions of any - volume. Note that this field cannot be set when spec.os.name - is windows." - format: int64 - type: integer - fsGroupChangePolicy: - description: 'fsGroupChangePolicy defines behavior of - changing ownership and permission of the volume before - being exposed inside Pod. This field will only apply - to volume types which support fsGroup based ownership(and - permissions). It will have no effect on ephemeral volume - types such as: secret, configmaps and emptydir. Valid - values are "OnRootMismatch" and "Always". If not specified, - "Always" is used. Note that this field cannot be set - when spec.os.name is windows.' - type: string - runAsGroup: - description: The GID to run the entrypoint of the container - process. Uses runtime default if unset. May also be - set in SecurityContext. If set in both SecurityContext - and PodSecurityContext, the value specified in SecurityContext - takes precedence for that container. Note that this - field cannot be set when spec.os.name is windows. - format: int64 - type: integer - runAsNonRoot: - description: Indicates that the container must run as - a non-root user. If true, the Kubelet will validate - the image at runtime to ensure that it does not run - as UID 0 (root) and fail to start the container if it - does. If unset or false, no such validation will be - performed. May also be set in SecurityContext. If set - in both SecurityContext and PodSecurityContext, the - value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: The UID to run the entrypoint of the container - process. Defaults to user specified in image metadata - if unspecified. May also be set in SecurityContext. If - set in both SecurityContext and PodSecurityContext, - the value specified in SecurityContext takes precedence - for that container. Note that this field cannot be set - when spec.os.name is windows. - format: int64 - type: integer - seLinuxOptions: - description: The SELinux context to be applied to all - containers. If unspecified, the container runtime will - allocate a random SELinux context for each container. May - also be set in SecurityContext. If set in both SecurityContext - and PodSecurityContext, the value specified in SecurityContext - takes precedence for that container. Note that this - field cannot be set when spec.os.name is windows. - properties: - level: - description: Level is SELinux level label that applies - to the container. - type: string - role: - description: Role is a SELinux role label that applies - to the container. - type: string - type: - description: Type is a SELinux type label that applies - to the container. - type: string - user: - description: User is a SELinux user label that applies - to the container. - type: string - type: object - seccompProfile: - description: The seccomp options to use by the containers - in this pod. Note that this field cannot be set when - spec.os.name is windows. - properties: - localhostProfile: - description: localhostProfile indicates a profile - defined in a file on the node should be used. The - profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's - configured seccomp profile location. Must only be - set if type is "Localhost". - type: string - type: - description: "type indicates which kind of seccomp - profile will be applied. Valid options are: \n Localhost - - a profile defined in a file on the node should - be used. RuntimeDefault - the container runtime - default profile should be used. Unconfined - no - profile should be applied." - type: string - required: - - type - type: object - supplementalGroups: - description: A list of groups applied to the first process - run in each container, in addition to the container's - primary GID. If unspecified, no groups will be added - to any container. Note that this field cannot be set - when spec.os.name is windows. - items: - format: int64 - type: integer - type: array - sysctls: - description: Sysctls hold a list of namespaced sysctls - used for the pod. Pods with unsupported sysctls (by - the container runtime) might fail to launch. Note that - this field cannot be set when spec.os.name is windows. - items: - description: Sysctl defines a kernel parameter to be - set - properties: - name: - description: Name of a property to set - type: string - value: - description: Value of a property to set - type: string - required: - - name - - value - type: object - type: array - windowsOptions: - description: The Windows specific settings applied to - all containers. If unspecified, the options within a - container's SecurityContext will be used. If set in - both SecurityContext and PodSecurityContext, the value - specified in SecurityContext takes precedence. Note - that this field cannot be set when spec.os.name is linux. - properties: - gmsaCredentialSpec: - description: GMSACredentialSpec is where the GMSA - admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) - inlines the contents of the GMSA credential spec - named by the GMSACredentialSpecName field. - type: string - gmsaCredentialSpecName: - description: GMSACredentialSpecName is the name of - the GMSA credential spec to use. - type: string - hostProcess: - description: HostProcess determines if a container - should be run as a 'Host Process' container. This - field is alpha-level and will only be honored by - components that enable the WindowsHostProcessContainers - feature flag. Setting this field without the feature - flag will result in errors when validating the Pod. - All of a Pod's containers must have the same effective - HostProcess value (it is not allowed to have a mix - of HostProcess containers and non-HostProcess containers). In - addition, if HostProcess is true then HostNetwork - must also be set to true. - type: boolean - runAsUserName: - description: The UserName in Windows to run the entrypoint - of the container process. Defaults to the user specified - in image metadata if unspecified. May also be set - in PodSecurityContext. If set in both SecurityContext - and PodSecurityContext, the value specified in SecurityContext - takes precedence. - type: string - type: object - type: object - serviceAccount: - description: 'DeprecatedServiceAccount is a depreciated alias - for ServiceAccountName. Deprecated: Use serviceAccountName - instead.' - type: string - serviceAccountName: - description: 'ServiceAccountName is the name of the ServiceAccount - to use to run this pod. More info: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/' - type: string - setHostnameAsFQDN: - description: If true the pod's hostname will be configured - as the pod's FQDN, rather than the leaf name (the default). - In Linux containers, this means setting the FQDN in the - hostname field of the kernel (the nodename field of struct - utsname). In Windows containers, this means setting the - registry value of hostname for the registry key HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters - to FQDN. If a pod does not have FQDN, this has no effect. - Default to false. - type: boolean - shareProcessNamespace: - description: 'Share a single process namespace between all - of the containers in a pod. When this is set containers - will be able to view and signal processes from other containers - in the same pod, and the first process in each container - will not be assigned PID 1. HostPID and ShareProcessNamespace - cannot both be set. Optional: Default to false.' - type: boolean - subdomain: - description: If specified, the fully qualified Pod hostname - will be "...svc.". If not specified, the pod will not have a domainname - at all. - type: string - terminationGracePeriodSeconds: - description: Optional duration in seconds the pod needs to - terminate gracefully. May be decreased in delete request. - Value must be non-negative integer. The value zero indicates - stop immediately via the kill signal (no opportunity to - shut down). If this value is nil, the default grace period - will be used instead. The grace period is the duration in - seconds after the processes running in the pod are sent - a termination signal and the time when the processes are - forcibly halted with a kill signal. Set this value longer - than the expected cleanup time for your process. Defaults - to 30 seconds. - format: int64 - type: integer - tolerations: - description: If specified, the pod's tolerations. - items: - description: The pod this Toleration is attached to tolerates - any taint that matches the triple using - the matching operator . - properties: - effect: - description: Effect indicates the taint effect to match. - Empty means match all taint effects. When specified, - allowed values are NoSchedule, PreferNoSchedule and - NoExecute. - type: string - key: - description: Key is the taint key that the toleration - applies to. Empty means match all taint keys. If the - key is empty, operator must be Exists; this combination - means to match all values and all keys. - type: string - operator: - description: Operator represents a key's relationship - to the value. Valid operators are Exists and Equal. - Defaults to Equal. Exists is equivalent to wildcard - for value, so that a pod can tolerate all taints of - a particular category. - type: string - tolerationSeconds: - description: TolerationSeconds represents the period - of time the toleration (which must be of effect NoExecute, - otherwise this field is ignored) tolerates the taint. - By default, it is not set, which means tolerate the - taint forever (do not evict). Zero and negative values - will be treated as 0 (evict immediately) by the system. - format: int64 - type: integer - value: - description: Value is the taint value the toleration - matches to. If the operator is Exists, the value should - be empty, otherwise just a regular string. - type: string - type: object - type: array - topologySpreadConstraints: - description: TopologySpreadConstraints describes how a group - of pods ought to spread across topology domains. Scheduler - will schedule pods in a way which abides by the constraints. - All topologySpreadConstraints are ANDed. - items: - description: TopologySpreadConstraint specifies how to spread - matching pods among the given topology. - properties: - labelSelector: - description: LabelSelector is used to find matching - pods. Pods that match this label selector are counted - to determine the number of pods in their corresponding - topology domain. - properties: - matchExpressions: - description: matchExpressions is a list of label - selector requirements. The requirements are ANDed. - items: - description: A label selector requirement is a - selector that contains values, a key, and an - operator that relates the key and values. - properties: - key: - description: key is the label key that the - selector applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are - In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string - values. If the operator is In or NotIn, - the values array must be non-empty. If the - operator is Exists or DoesNotExist, the - values array must be empty. This array is - replaced during a strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator is "In", - and the values array contains only "value". The - requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - matchLabelKeys: - description: MatchLabelKeys is a set of pod label keys - to select the pods over which spreading will be calculated. - The keys are used to lookup values from the incoming - pod labels, those key-value labels are ANDed with - labelSelector to select the group of existing pods - over which spreading will be calculated for the incoming - pod. Keys that don't exist in the incoming pod labels - will be ignored. A null or empty list means only match - against labelSelector. - items: - type: string - type: array - x-kubernetes-list-type: atomic - maxSkew: - description: 'MaxSkew describes the degree to which - pods may be unevenly distributed. When `whenUnsatisfiable=DoNotSchedule`, - it is the maximum permitted difference between the - number of matching pods in the target topology and - the global minimum. The global minimum is the minimum - number of matching pods in an eligible domain or zero - if the number of eligible domains is less than MinDomains. - For example, in a 3-zone cluster, MaxSkew is set to - 1, and pods with the same labelSelector spread as - 2/2/1: In this case, the global minimum is 1. | zone1 - | zone2 | zone3 | | P P | P P | P | - if MaxSkew - is 1, incoming pod can only be scheduled to zone3 - to become 2/2/2; scheduling it onto zone1(zone2) would - make the ActualSkew(3-1) on zone1(zone2) violate MaxSkew(1). - - if MaxSkew is 2, incoming pod can be scheduled onto - any zone. When `whenUnsatisfiable=ScheduleAnyway`, - it is used to give higher precedence to topologies - that satisfy it. It''s a required field. Default value - is 1 and 0 is not allowed.' - format: int32 - type: integer - minDomains: - description: "MinDomains indicates a minimum number - of eligible domains. When the number of eligible domains - with matching topology keys is less than minDomains, - Pod Topology Spread treats \"global minimum\" as 0, - and then the calculation of Skew is performed. And - when the number of eligible domains with matching - topology keys equals or greater than minDomains, this - value has no effect on scheduling. As a result, when - the number of eligible domains is less than minDomains, - scheduler won't schedule more than maxSkew Pods to - those domains. If value is nil, the constraint behaves - as if MinDomains is equal to 1. Valid values are integers - greater than 0. When value is not nil, WhenUnsatisfiable - must be DoNotSchedule. \n For example, in a 3-zone - cluster, MaxSkew is set to 2, MinDomains is set to - 5 and pods with the same labelSelector spread as 2/2/2: - | zone1 | zone2 | zone3 | | P P | P P | P P | - The number of domains is less than 5(MinDomains), - so \"global minimum\" is treated as 0. In this situation, - new pod with the same labelSelector cannot be scheduled, - because computed skew will be 3(3 - 0) if new Pod - is scheduled to any of the three zones, it will violate - MaxSkew. \n This is a beta field and requires the - MinDomainsInPodTopologySpread feature gate to be enabled - (enabled by default)." - format: int32 - type: integer - nodeAffinityPolicy: - description: "NodeAffinityPolicy indicates how we will - treat Pod's nodeAffinity/nodeSelector when calculating - pod topology spread skew. Options are: - Honor: only - nodes matching nodeAffinity/nodeSelector are included - in the calculations. - Ignore: nodeAffinity/nodeSelector - are ignored. All nodes are included in the calculations. - \n If this value is nil, the behavior is equivalent - to the Honor policy. This is a alpha-level feature - enabled by the NodeInclusionPolicyInPodTopologySpread - feature flag." - type: string - nodeTaintsPolicy: - description: "NodeTaintsPolicy indicates how we will - treat node taints when calculating pod topology spread - skew. Options are: - Honor: nodes without taints, - along with tainted nodes for which the incoming pod - has a toleration, are included. - Ignore: node taints - are ignored. All nodes are included. \n If this value - is nil, the behavior is equivalent to the Ignore policy. - This is a alpha-level feature enabled by the NodeInclusionPolicyInPodTopologySpread - feature flag." - type: string - topologyKey: - description: TopologyKey is the key of node labels. - Nodes that have a label with this key and identical - values are considered to be in the same topology. - We consider each as a "bucket", and try - to put balanced number of pods into each bucket. We - define a domain as a particular instance of a topology. - Also, we define an eligible domain as a domain whose - nodes meet the requirements of nodeAffinityPolicy - and nodeTaintsPolicy. e.g. If TopologyKey is "kubernetes.io/hostname", - each Node is a domain of that topology. And, if TopologyKey - is "topology.kubernetes.io/zone", each zone is a domain - of that topology. It's a required field. - type: string - whenUnsatisfiable: - description: 'WhenUnsatisfiable indicates how to deal - with a pod if it doesn''t satisfy the spread constraint. - - DoNotSchedule (default) tells the scheduler not - to schedule it. - ScheduleAnyway tells the scheduler - to schedule the pod in any location, but giving higher - precedence to topologies that would help reduce the - skew. A constraint is considered "Unsatisfiable" for - an incoming pod if and only if every possible node - assignment for that pod would violate "MaxSkew" on - some topology. For example, in a 3-zone cluster, MaxSkew - is set to 1, and pods with the same labelSelector - spread as 3/1/1: | zone1 | zone2 | zone3 | | P P P - | P | P | If WhenUnsatisfiable is set to DoNotSchedule, - incoming pod can only be scheduled to zone2(zone3) - to become 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) - satisfies MaxSkew(1). In other words, the cluster - can still be imbalanced, but scheduler won''t make - it *more* imbalanced. It''s a required field.' - type: string - required: - - maxSkew - - topologyKey - - whenUnsatisfiable - type: object - type: array - x-kubernetes-list-map-keys: - - topologyKey - - whenUnsatisfiable - x-kubernetes-list-type: map - volumes: - description: 'List of volumes that can be mounted by containers - belonging to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes' - items: - description: Volume represents a named volume in a pod that - may be accessed by any container in the pod. - properties: - awsElasticBlockStore: - description: 'awsElasticBlockStore represents an AWS - Disk resource that is attached to a kubelet''s host - machine and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' - properties: - fsType: - description: 'fsType is the filesystem type of the - volume that you want to mount. Tip: Ensure that - the filesystem type is supported by the host operating - system. Examples: "ext4", "xfs", "ntfs". Implicitly - inferred to be "ext4" if unspecified. More info: - https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - TODO: how do we prevent errors in the filesystem - from compromising the machine' - type: string - partition: - description: 'partition is the partition in the - volume that you want to mount. If omitted, the - default is to mount by volume name. Examples: - For volume /dev/sda1, you specify the partition - as "1". Similarly, the volume partition for /dev/sda - is "0" (or you can leave the property empty).' - format: int32 - type: integer - readOnly: - description: 'readOnly value true will force the - readOnly setting in VolumeMounts. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' - type: boolean - volumeID: - description: 'volumeID is unique ID of the persistent - disk resource in AWS (Amazon EBS volume). More - info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' - type: string - required: - - volumeID - type: object - azureDisk: - description: azureDisk represents an Azure Data Disk - mount on the host and bind mount to the pod. - properties: - cachingMode: - description: 'cachingMode is the Host Caching mode: - None, Read Only, Read Write.' - type: string - diskName: - description: diskName is the Name of the data disk - in the blob storage - type: string - diskURI: - description: diskURI is the URI of data disk in - the blob storage - type: string - fsType: - description: fsType is Filesystem type to mount. - Must be a filesystem type supported by the host - operating system. Ex. "ext4", "xfs", "ntfs". Implicitly - inferred to be "ext4" if unspecified. - type: string - kind: - description: 'kind expected values are Shared: multiple - blob disks per storage account Dedicated: single - blob disk per storage account Managed: azure - managed data disk (only in managed availability - set). defaults to shared' - type: string - readOnly: - description: readOnly Defaults to false (read/write). - ReadOnly here will force the ReadOnly setting - in VolumeMounts. - type: boolean - required: - - diskName - - diskURI - type: object - azureFile: - description: azureFile represents an Azure File Service - mount on the host and bind mount to the pod. - properties: - readOnly: - description: readOnly defaults to false (read/write). - ReadOnly here will force the ReadOnly setting - in VolumeMounts. - type: boolean - secretName: - description: secretName is the name of secret that - contains Azure Storage Account Name and Key - type: string - shareName: - description: shareName is the azure share Name - type: string - required: - - secretName - - shareName - type: object - cephfs: - description: cephFS represents a Ceph FS mount on the - host that shares a pod's lifetime - properties: - monitors: - description: 'monitors is Required: Monitors is - a collection of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' - items: - type: string - type: array - path: - description: 'path is Optional: Used as the mounted - root, rather than the full Ceph tree, default - is /' - type: string - readOnly: - description: 'readOnly is Optional: Defaults to - false (read/write). ReadOnly here will force the - ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' - type: boolean - secretFile: - description: 'secretFile is Optional: SecretFile - is the path to key ring for User, default is /etc/ceph/user.secret - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' - type: string - secretRef: - description: 'secretRef is Optional: SecretRef is - reference to the authentication secret for User, - default is empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' - properties: - name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' - type: string - type: object - x-kubernetes-map-type: atomic - user: - description: 'user is optional: User is the rados - user name, default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' - type: string - required: - - monitors - type: object - cinder: - description: 'cinder represents a cinder volume attached - and mounted on kubelets host machine. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' - properties: - fsType: - description: 'fsType is the filesystem type to mount. - Must be a filesystem type supported by the host - operating system. Examples: "ext4", "xfs", "ntfs". - Implicitly inferred to be "ext4" if unspecified. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md' - type: string - readOnly: - description: 'readOnly defaults to false (read/write). - ReadOnly here will force the ReadOnly setting - in VolumeMounts. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' - type: boolean - secretRef: - description: 'secretRef is optional: points to a - secret object containing parameters used to connect - to OpenStack.' - properties: - name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' - type: string - type: object - x-kubernetes-map-type: atomic - volumeID: - description: 'volumeID used to identify the volume - in cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' - type: string - required: - - volumeID - type: object - configMap: - description: configMap represents a configMap that should - populate this volume - properties: - defaultMode: - description: 'defaultMode is optional: mode bits - used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or - a decimal value between 0 and 511. YAML accepts - both octal and decimal values, JSON requires decimal - values for mode bits. Defaults to 0644. Directories - within the path are not affected by this setting. - This might be in conflict with other options that - affect the file mode, like fsGroup, and the result - can be other mode bits set.' - format: int32 - type: integer - items: - description: items if unspecified, each key-value - pair in the Data field of the referenced ConfigMap - will be projected into the volume as a file whose - name is the key and content is the value. If specified, - the listed keys will be projected into the specified - paths, and unlisted keys will not be present. - If a key is specified which is not present in - the ConfigMap, the volume setup will error unless - it is marked optional. Paths must be relative - and may not contain the '..' path or start with - '..'. - items: - description: Maps a string key to a path within - a volume. - properties: - key: - description: key is the key to project. - type: string - mode: - description: 'mode is Optional: mode bits - used to set permissions on this file. Must - be an octal value between 0000 and 0777 - or a decimal value between 0 and 511. YAML - accepts both octal and decimal values, JSON - requires decimal values for mode bits. If - not specified, the volume defaultMode will - be used. This might be in conflict with - other options that affect the file mode, - like fsGroup, and the result can be other - mode bits set.' - format: int32 - type: integer - path: - description: path is the relative path of - the file to map the key to. May not be an - absolute path. May not contain the path - element '..'. May not start with the string - '..'. - type: string - required: - - key - - path - type: object - type: array - name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, - uid?' - type: string - optional: - description: optional specify whether the ConfigMap - or its keys must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - csi: - description: csi (Container Storage Interface) represents - ephemeral storage that is handled by certain external - CSI drivers (Beta feature). - properties: - driver: - description: driver is the name of the CSI driver - that handles this volume. Consult with your admin - for the correct name as registered in the cluster. - type: string - fsType: - description: fsType to mount. Ex. "ext4", "xfs", - "ntfs". If not provided, the empty value is passed - to the associated CSI driver which will determine - the default filesystem to apply. - type: string - nodePublishSecretRef: - description: nodePublishSecretRef is a reference - to the secret object containing sensitive information - to pass to the CSI driver to complete the CSI - NodePublishVolume and NodeUnpublishVolume calls. - This field is optional, and may be empty if no - secret is required. If the secret object contains - more than one secret, all secret references are - passed. - properties: - name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' - type: string - type: object - x-kubernetes-map-type: atomic - readOnly: - description: readOnly specifies a read-only configuration - for the volume. Defaults to false (read/write). - type: boolean - volumeAttributes: - additionalProperties: - type: string - description: volumeAttributes stores driver-specific - properties that are passed to the CSI driver. - Consult your driver's documentation for supported - values. - type: object - required: - - driver - type: object - downwardAPI: - description: downwardAPI represents downward API about - the pod that should populate this volume - properties: - defaultMode: - description: 'Optional: mode bits to use on created - files by default. Must be a Optional: mode bits - used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or - a decimal value between 0 and 511. YAML accepts - both octal and decimal values, JSON requires decimal - values for mode bits. Defaults to 0644. Directories - within the path are not affected by this setting. - This might be in conflict with other options that - affect the file mode, like fsGroup, and the result - can be other mode bits set.' - format: int32 - type: integer - items: - description: Items is a list of downward API volume - file - items: - description: DownwardAPIVolumeFile represents - information to create the file containing the - pod field - properties: - fieldRef: - description: 'Required: Selects a field of - the pod: only annotations, labels, name - and namespace are supported.' - properties: - apiVersion: - description: Version of the schema the - FieldPath is written in terms of, defaults - to "v1". - type: string - fieldPath: - description: Path of the field to select - in the specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - mode: - description: 'Optional: mode bits used to - set permissions on this file, must be an - octal value between 0000 and 0777 or a decimal - value between 0 and 511. YAML accepts both - octal and decimal values, JSON requires - decimal values for mode bits. If not specified, - the volume defaultMode will be used. This - might be in conflict with other options - that affect the file mode, like fsGroup, - and the result can be other mode bits set.' - format: int32 - type: integer - path: - description: 'Required: Path is the relative - path name of the file to be created. Must - not be absolute or contain the ''..'' path. - Must be utf-8 encoded. The first item of - the relative path must not start with ''..''' - type: string - resourceFieldRef: - description: 'Selects a resource of the container: - only resources limits and requests (limits.cpu, - limits.memory, requests.cpu and requests.memory) - are currently supported.' - properties: - containerName: - description: 'Container name: required - for volumes, optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format - of the exposed resources, defaults to - "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - required: - - path - type: object - type: array - type: object - emptyDir: - description: 'emptyDir represents a temporary directory - that shares a pod''s lifetime. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' - properties: - medium: - description: 'medium represents what type of storage - medium should back this directory. The default - is "" which means to use the node''s default medium. - Must be an empty string (default) or Memory. More - info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' - type: string - sizeLimit: - anyOf: - - type: integer - - type: string - description: 'sizeLimit is the total amount of local - storage required for this EmptyDir volume. The - size limit is also applicable for memory medium. - The maximum usage on memory medium EmptyDir would - be the minimum value between the SizeLimit specified - here and the sum of memory limits of all containers - in a pod. The default is nil which means that - the limit is undefined. More info: http://kubernetes.io/docs/user-guide/volumes#emptydir' - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - type: object - ephemeral: - description: "ephemeral represents a volume that is - handled by a cluster storage driver. The volume's - lifecycle is tied to the pod that defines it - it - will be created before the pod starts, and deleted - when the pod is removed. \n Use this if: a) the volume - is only needed while the pod runs, b) features of - normal volumes like restoring from snapshot or capacity - tracking are needed, c) the storage driver is specified - through a storage class, and d) the storage driver - supports dynamic volume provisioning through a PersistentVolumeClaim - (see EphemeralVolumeSource for more information on - the connection between this volume type and PersistentVolumeClaim). - \n Use PersistentVolumeClaim or one of the vendor-specific - APIs for volumes that persist for longer than the - lifecycle of an individual pod. \n Use CSI for light-weight - local ephemeral volumes if the CSI driver is meant - to be used that way - see the documentation of the - driver for more information. \n A pod can use both - types of ephemeral volumes and persistent volumes - at the same time." - properties: - volumeClaimTemplate: - description: "Will be used to create a stand-alone - PVC to provision the volume. The pod in which - this EphemeralVolumeSource is embedded will be - the owner of the PVC, i.e. the PVC will be deleted - together with the pod. The name of the PVC will - be `-` where `` - is the name from the `PodSpec.Volumes` array entry. - Pod validation will reject the pod if the concatenated - name is not valid for a PVC (for example, too - long). \n An existing PVC with that name that - is not owned by the pod will *not* be used for - the pod to avoid using an unrelated volume by - mistake. Starting the pod is then blocked until - the unrelated PVC is removed. If such a pre-created - PVC is meant to be used by the pod, the PVC has - to updated with an owner reference to the pod - once the pod exists. Normally this should not - be necessary, but it may be useful when manually - reconstructing a broken cluster. \n This field - is read-only and no changes will be made by Kubernetes - to the PVC after it has been created. \n Required, - must not be nil." - properties: - metadata: - description: May contain labels and annotations - that will be copied into the PVC when creating - it. No other fields are allowed and will be - rejected during validation. - type: object - spec: - description: The specification for the PersistentVolumeClaim. - The entire content is copied unchanged into - the PVC that gets created from this template. - The same fields as in a PersistentVolumeClaim - are also valid here. - properties: - accessModes: - description: 'accessModes contains the desired - access modes the volume should have. More - info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1' - items: - type: string - type: array - dataSource: - description: 'dataSource field can be used - to specify either: * An existing VolumeSnapshot - object (snapshot.storage.k8s.io/VolumeSnapshot) - * An existing PVC (PersistentVolumeClaim) - If the provisioner or an external controller - can support the specified data source, - it will create a new volume based on the - contents of the specified data source. - If the AnyVolumeDataSource feature gate - is enabled, this field will always have - the same contents as the DataSourceRef - field.' - properties: - apiGroup: - description: APIGroup is the group for - the resource being referenced. If - APIGroup is not specified, the specified - Kind must be in the core API group. - For any other third-party types, APIGroup - is required. - type: string - kind: - description: Kind is the type of resource - being referenced - type: string - name: - description: Name is the name of resource - being referenced - type: string - required: - - kind - - name - type: object - x-kubernetes-map-type: atomic - dataSourceRef: - description: 'dataSourceRef specifies the - object from which to populate the volume - with data, if a non-empty volume is desired. - This may be any local object from a non-empty - API group (non core object) or a PersistentVolumeClaim - object. When this field is specified, - volume binding will only succeed if the - type of the specified object matches some - installed volume populator or dynamic - provisioner. This field will replace the - functionality of the DataSource field - and as such if both fields are non-empty, - they must have the same value. For backwards - compatibility, both fields (DataSource - and DataSourceRef) will be set to the - same value automatically if one of them - is empty and the other is non-empty. There - are two important differences between - DataSource and DataSourceRef: * While - DataSource only allows two specific types - of objects, DataSourceRef allows any non-core - object, as well as PersistentVolumeClaim - objects. * While DataSource ignores disallowed - values (dropping them), DataSourceRef - preserves all values, and generates an - error if a disallowed value is specified. - (Beta) Using this field requires the AnyVolumeDataSource - feature gate to be enabled.' - properties: - apiGroup: - description: APIGroup is the group for - the resource being referenced. If - APIGroup is not specified, the specified - Kind must be in the core API group. - For any other third-party types, APIGroup - is required. - type: string - kind: - description: Kind is the type of resource - being referenced - type: string - name: - description: Name is the name of resource - being referenced - type: string - required: - - kind - - name - type: object - x-kubernetes-map-type: atomic - resources: - description: 'resources represents the minimum - resources the volume should have. If RecoverVolumeExpansionFailure - feature is enabled users are allowed to - specify resource requirements that are - lower than previous value but must still - be higher than capacity recorded in the - status field of the claim. More info: - https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources' - properties: - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: 'Limits describes the maximum - amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: 'Requests describes the - minimum amount of compute resources - required. If Requests is omitted for - a container, it defaults to Limits - if that is explicitly specified, otherwise - to an implementation-defined value. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' - type: object - type: object - selector: - description: selector is a label query over - volumes to consider for binding. - properties: - matchExpressions: - description: matchExpressions is a list - of label selector requirements. The - requirements are ANDed. - items: - description: A label selector requirement - is a selector that contains values, - a key, and an operator that relates - the key and values. - properties: - key: - description: key is the label - key that the selector applies - to. - type: string - operator: - description: operator represents - a key's relationship to a set - of values. Valid operators are - In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array - of string values. If the operator - is In or NotIn, the values array - must be non-empty. If the operator - is Exists or DoesNotExist, the - values array must be empty. - This array is replaced during - a strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of - {key,value} pairs. A single {key,value} - in the matchLabels map is equivalent - to an element of matchExpressions, - whose key field is "key", the operator - is "In", and the values array contains - only "value". The requirements are - ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - storageClassName: - description: 'storageClassName is the name - of the StorageClass required by the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' - type: string - volumeMode: - description: volumeMode defines what type - of volume is required by the claim. Value - of Filesystem is implied when not included - in claim spec. - type: string - volumeName: - description: volumeName is the binding reference - to the PersistentVolume backing this claim. - type: string - type: object - required: - - spec - type: object - type: object - fc: - description: fc represents a Fibre Channel resource - that is attached to a kubelet's host machine and then - exposed to the pod. - properties: - fsType: - description: 'fsType is the filesystem type to mount. - Must be a filesystem type supported by the host - operating system. Ex. "ext4", "xfs", "ntfs". Implicitly - inferred to be "ext4" if unspecified. TODO: how - do we prevent errors in the filesystem from compromising - the machine' - type: string - lun: - description: 'lun is Optional: FC target lun number' - format: int32 - type: integer - readOnly: - description: 'readOnly is Optional: Defaults to - false (read/write). ReadOnly here will force the - ReadOnly setting in VolumeMounts.' - type: boolean - targetWWNs: - description: 'targetWWNs is Optional: FC target - worldwide names (WWNs)' - items: - type: string - type: array - wwids: - description: 'wwids Optional: FC volume world wide - identifiers (wwids) Either wwids or combination - of targetWWNs and lun must be set, but not both - simultaneously.' - items: - type: string - type: array - type: object - flexVolume: - description: flexVolume represents a generic volume - resource that is provisioned/attached using an exec - based plugin. - properties: - driver: - description: driver is the name of the driver to - use for this volume. - type: string - fsType: - description: fsType is the filesystem type to mount. - Must be a filesystem type supported by the host - operating system. Ex. "ext4", "xfs", "ntfs". The - default filesystem depends on FlexVolume script. - type: string - options: - additionalProperties: - type: string - description: 'options is Optional: this field holds - extra command options if any.' - type: object - readOnly: - description: 'readOnly is Optional: defaults to - false (read/write). ReadOnly here will force the - ReadOnly setting in VolumeMounts.' - type: boolean - secretRef: - description: 'secretRef is Optional: secretRef is - reference to the secret object containing sensitive - information to pass to the plugin scripts. This - may be empty if no secret object is specified. - If the secret object contains more than one secret, - all secrets are passed to the plugin scripts.' - properties: - name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' - type: string - type: object - x-kubernetes-map-type: atomic - required: - - driver - type: object - flocker: - description: flocker represents a Flocker volume attached - to a kubelet's host machine. This depends on the Flocker - control service being running - properties: - datasetName: - description: datasetName is Name of the dataset - stored as metadata -> name on the dataset for - Flocker should be considered as deprecated - type: string - datasetUUID: - description: datasetUUID is the UUID of the dataset. - This is unique identifier of a Flocker dataset - type: string - type: object - gcePersistentDisk: - description: 'gcePersistentDisk represents a GCE Disk - resource that is attached to a kubelet''s host machine - and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' - properties: - fsType: - description: 'fsType is filesystem type of the volume - that you want to mount. Tip: Ensure that the filesystem - type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred - to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - TODO: how do we prevent errors in the filesystem - from compromising the machine' - type: string - partition: - description: 'partition is the partition in the - volume that you want to mount. If omitted, the - default is to mount by volume name. Examples: - For volume /dev/sda1, you specify the partition - as "1". Similarly, the volume partition for /dev/sda - is "0" (or you can leave the property empty). - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' - format: int32 - type: integer - pdName: - description: 'pdName is unique name of the PD resource - in GCE. Used to identify the disk in GCE. More - info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' - type: string - readOnly: - description: 'readOnly here will force the ReadOnly - setting in VolumeMounts. Defaults to false. More - info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' - type: boolean - required: - - pdName - type: object - gitRepo: - description: 'gitRepo represents a git repository at - a particular revision. DEPRECATED: GitRepo is deprecated. - To provision a container with a git repo, mount an - EmptyDir into an InitContainer that clones the repo - using git, then mount the EmptyDir into the Pod''s - container.' - properties: - directory: - description: directory is the target directory name. - Must not contain or start with '..'. If '.' is - supplied, the volume directory will be the git - repository. Otherwise, if specified, the volume - will contain the git repository in the subdirectory - with the given name. - type: string - repository: - description: repository is the URL - type: string - revision: - description: revision is the commit hash for the - specified revision. - type: string - required: - - repository - type: object - glusterfs: - description: 'glusterfs represents a Glusterfs mount - on the host that shares a pod''s lifetime. More info: - https://examples.k8s.io/volumes/glusterfs/README.md' - properties: - endpoints: - description: 'endpoints is the endpoint name that - details Glusterfs topology. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' - type: string - path: - description: 'path is the Glusterfs volume path. - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' - type: string - readOnly: - description: 'readOnly here will force the Glusterfs - volume to be mounted with read-only permissions. - Defaults to false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' - type: boolean - required: - - endpoints - - path - type: object - hostPath: - description: 'hostPath represents a pre-existing file - or directory on the host machine that is directly - exposed to the container. This is generally used for - system agents or other privileged things that are - allowed to see the host machine. Most containers will - NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - --- TODO(jonesdl) We need to restrict who can use - host directory mounts and who can/can not mount host - directories as read/write.' - properties: - path: - description: 'path of the directory on the host. - If the path is a symlink, it will follow the link - to the real path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' - type: string - type: - description: 'type for HostPath Volume Defaults - to "" More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' - type: string - required: - - path - type: object - iscsi: - description: 'iscsi represents an ISCSI Disk resource - that is attached to a kubelet''s host machine and - then exposed to the pod. More info: https://examples.k8s.io/volumes/iscsi/README.md' - properties: - chapAuthDiscovery: - description: chapAuthDiscovery defines whether support - iSCSI Discovery CHAP authentication - type: boolean - chapAuthSession: - description: chapAuthSession defines whether support - iSCSI Session CHAP authentication - type: boolean - fsType: - description: 'fsType is the filesystem type of the - volume that you want to mount. Tip: Ensure that - the filesystem type is supported by the host operating - system. Examples: "ext4", "xfs", "ntfs". Implicitly - inferred to be "ext4" if unspecified. More info: - https://kubernetes.io/docs/concepts/storage/volumes#iscsi - TODO: how do we prevent errors in the filesystem - from compromising the machine' - type: string - initiatorName: - description: initiatorName is the custom iSCSI Initiator - Name. If initiatorName is specified with iscsiInterface - simultaneously, new iSCSI interface : will be created for the connection. - type: string - iqn: - description: iqn is the target iSCSI Qualified Name. - type: string - iscsiInterface: - description: iscsiInterface is the interface Name - that uses an iSCSI transport. Defaults to 'default' - (tcp). - type: string - lun: - description: lun represents iSCSI Target Lun number. - format: int32 - type: integer - portals: - description: portals is the iSCSI Target Portal - List. The portal is either an IP or ip_addr:port - if the port is other than default (typically TCP - ports 860 and 3260). - items: - type: string - type: array - readOnly: - description: readOnly here will force the ReadOnly - setting in VolumeMounts. Defaults to false. - type: boolean - secretRef: - description: secretRef is the CHAP Secret for iSCSI - target and initiator authentication - properties: - name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' - type: string - type: object - x-kubernetes-map-type: atomic - targetPortal: - description: targetPortal is iSCSI Target Portal. - The Portal is either an IP or ip_addr:port if - the port is other than default (typically TCP - ports 860 and 3260). - type: string - required: - - iqn - - lun - - targetPortal - type: object - name: - description: 'name of the volume. Must be a DNS_LABEL - and unique within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - nfs: - description: 'nfs represents an NFS mount on the host - that shares a pod''s lifetime More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' - properties: - path: - description: 'path that is exported by the NFS server. - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' - type: string - readOnly: - description: 'readOnly here will force the NFS export - to be mounted with read-only permissions. Defaults - to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' - type: boolean - server: - description: 'server is the hostname or IP address - of the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' - type: string - required: - - path - - server - type: object - persistentVolumeClaim: - description: 'persistentVolumeClaimVolumeSource represents - a reference to a PersistentVolumeClaim in the same - namespace. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' - properties: - claimName: - description: 'claimName is the name of a PersistentVolumeClaim - in the same namespace as the pod using this volume. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' - type: string - readOnly: - description: readOnly Will force the ReadOnly setting - in VolumeMounts. Default false. - type: boolean - required: - - claimName - type: object - photonPersistentDisk: - description: photonPersistentDisk represents a PhotonController - persistent disk attached and mounted on kubelets host - machine - properties: - fsType: - description: fsType is the filesystem type to mount. - Must be a filesystem type supported by the host - operating system. Ex. "ext4", "xfs", "ntfs". Implicitly - inferred to be "ext4" if unspecified. - type: string - pdID: - description: pdID is the ID that identifies Photon - Controller persistent disk - type: string - required: - - pdID - type: object - portworxVolume: - description: portworxVolume represents a portworx volume - attached and mounted on kubelets host machine - properties: - fsType: - description: fSType represents the filesystem type - to mount Must be a filesystem type supported by - the host operating system. Ex. "ext4", "xfs". - Implicitly inferred to be "ext4" if unspecified. - type: string - readOnly: - description: readOnly defaults to false (read/write). - ReadOnly here will force the ReadOnly setting - in VolumeMounts. - type: boolean - volumeID: - description: volumeID uniquely identifies a Portworx - volume - type: string - required: - - volumeID - type: object - projected: - description: projected items for all in one resources - secrets, configmaps, and downward API - properties: - defaultMode: - description: defaultMode are the mode bits used - to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or - a decimal value between 0 and 511. YAML accepts - both octal and decimal values, JSON requires decimal - values for mode bits. Directories within the path - are not affected by this setting. This might be - in conflict with other options that affect the - file mode, like fsGroup, and the result can be - other mode bits set. - format: int32 - type: integer - sources: - description: sources is the list of volume projections - items: - description: Projection that may be projected - along with other supported volume types - properties: - configMap: - description: configMap information about the - configMap data to project - properties: - items: - description: items if unspecified, each - key-value pair in the Data field of - the referenced ConfigMap will be projected - into the volume as a file whose name - is the key and content is the value. - If specified, the listed keys will be - projected into the specified paths, - and unlisted keys will not be present. - If a key is specified which is not present - in the ConfigMap, the volume setup will - error unless it is marked optional. - Paths must be relative and may not contain - the '..' path or start with '..'. - items: - description: Maps a string key to a - path within a volume. - properties: - key: - description: key is the key to project. - type: string - mode: - description: 'mode is Optional: - mode bits used to set permissions - on this file. Must be an octal - value between 0000 and 0777 or - a decimal value between 0 and - 511. YAML accepts both octal and - decimal values, JSON requires - decimal values for mode bits. - If not specified, the volume defaultMode - will be used. This might be in - conflict with other options that - affect the file mode, like fsGroup, - and the result can be other mode - bits set.' - format: int32 - type: integer - path: - description: path is the relative - path of the file to map the key - to. May not be an absolute path. - May not contain the path element - '..'. May not start with the string - '..'. - type: string - required: - - key - - path - type: object - type: array - name: - description: 'Name of the referent. More - info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' - type: string - optional: - description: optional specify whether - the ConfigMap or its keys must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - downwardAPI: - description: downwardAPI information about - the downwardAPI data to project - properties: - items: - description: Items is a list of DownwardAPIVolume - file - items: - description: DownwardAPIVolumeFile represents - information to create the file containing - the pod field - properties: - fieldRef: - description: 'Required: Selects - a field of the pod: only annotations, - labels, name and namespace are - supported.' - properties: - apiVersion: - description: Version of the - schema the FieldPath is written - in terms of, defaults to "v1". - type: string - fieldPath: - description: Path of the field - to select in the specified - API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - mode: - description: 'Optional: mode bits - used to set permissions on this - file, must be an octal value between - 0000 and 0777 or a decimal value - between 0 and 511. YAML accepts - both octal and decimal values, - JSON requires decimal values for - mode bits. If not specified, the - volume defaultMode will be used. - This might be in conflict with - other options that affect the - file mode, like fsGroup, and the - result can be other mode bits - set.' - format: int32 - type: integer - path: - description: 'Required: Path is the - relative path name of the file - to be created. Must not be absolute - or contain the ''..'' path. Must - be utf-8 encoded. The first item - of the relative path must not - start with ''..''' - type: string - resourceFieldRef: - description: 'Selects a resource - of the container: only resources - limits and requests (limits.cpu, - limits.memory, requests.cpu and - requests.memory) are currently - supported.' - properties: - containerName: - description: 'Container name: - required for volumes, optional - for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output - format of the exposed resources, - defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource - to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - required: - - path - type: object - type: array - type: object - secret: - description: secret information about the - secret data to project - properties: - items: - description: items if unspecified, each - key-value pair in the Data field of - the referenced Secret will be projected - into the volume as a file whose name - is the key and content is the value. - If specified, the listed keys will be - projected into the specified paths, - and unlisted keys will not be present. - If a key is specified which is not present - in the Secret, the volume setup will - error unless it is marked optional. - Paths must be relative and may not contain - the '..' path or start with '..'. - items: - description: Maps a string key to a - path within a volume. - properties: - key: - description: key is the key to project. - type: string - mode: - description: 'mode is Optional: - mode bits used to set permissions - on this file. Must be an octal - value between 0000 and 0777 or - a decimal value between 0 and - 511. YAML accepts both octal and - decimal values, JSON requires - decimal values for mode bits. - If not specified, the volume defaultMode - will be used. This might be in - conflict with other options that - affect the file mode, like fsGroup, - and the result can be other mode - bits set.' - format: int32 - type: integer - path: - description: path is the relative - path of the file to map the key - to. May not be an absolute path. - May not contain the path element - '..'. May not start with the string - '..'. - type: string - required: - - key - - path - type: object - type: array - name: - description: 'Name of the referent. More - info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' - type: string - optional: - description: optional field specify whether - the Secret or its key must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - serviceAccountToken: - description: serviceAccountToken is information - about the serviceAccountToken data to project - properties: - audience: - description: audience is the intended - audience of the token. A recipient of - a token must identify itself with an - identifier specified in the audience - of the token, and otherwise should reject - the token. The audience defaults to - the identifier of the apiserver. - type: string - expirationSeconds: - description: expirationSeconds is the - requested duration of validity of the - service account token. As the token - approaches expiration, the kubelet volume - plugin will proactively rotate the service - account token. The kubelet will start - trying to rotate the token if the token - is older than 80 percent of its time - to live or if the token is older than - 24 hours.Defaults to 1 hour and must - be at least 10 minutes. - format: int64 - type: integer - path: - description: path is the path relative - to the mount point of the file to project - the token into. - type: string - required: - - path - type: object - type: object - type: array - type: object - quobyte: - description: quobyte represents a Quobyte mount on the - host that shares a pod's lifetime - properties: - group: - description: group to map volume access to Default - is no group - type: string - readOnly: - description: readOnly here will force the Quobyte - volume to be mounted with read-only permissions. - Defaults to false. - type: boolean - registry: - description: registry represents a single or multiple - Quobyte Registry services specified as a string - as host:port pair (multiple entries are separated - with commas) which acts as the central registry - for volumes - type: string - tenant: - description: tenant owning the given Quobyte volume - in the Backend Used with dynamically provisioned - Quobyte volumes, value is set by the plugin - type: string - user: - description: user to map volume access to Defaults - to serivceaccount user - type: string - volume: - description: volume is a string that references - an already created Quobyte volume by name. - type: string - required: - - registry - - volume - type: object - rbd: - description: 'rbd represents a Rados Block Device mount - on the host that shares a pod''s lifetime. More info: - https://examples.k8s.io/volumes/rbd/README.md' - properties: - fsType: - description: 'fsType is the filesystem type of the - volume that you want to mount. Tip: Ensure that - the filesystem type is supported by the host operating - system. Examples: "ext4", "xfs", "ntfs". Implicitly - inferred to be "ext4" if unspecified. More info: - https://kubernetes.io/docs/concepts/storage/volumes#rbd - TODO: how do we prevent errors in the filesystem - from compromising the machine' - type: string - image: - description: 'image is the rados image name. More - info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' - type: string - keyring: - description: 'keyring is the path to key ring for - RBDUser. Default is /etc/ceph/keyring. More info: - https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' - type: string - monitors: - description: 'monitors is a collection of Ceph monitors. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' - items: - type: string - type: array - pool: - description: 'pool is the rados pool name. Default - is rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' - type: string - readOnly: - description: 'readOnly here will force the ReadOnly - setting in VolumeMounts. Defaults to false. More - info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' - type: boolean - secretRef: - description: 'secretRef is name of the authentication - secret for RBDUser. If provided overrides keyring. - Default is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' - properties: - name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' - type: string - type: object - x-kubernetes-map-type: atomic - user: - description: 'user is the rados user name. Default - is admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' - type: string - required: - - image - - monitors - type: object - scaleIO: - description: scaleIO represents a ScaleIO persistent - volume attached and mounted on Kubernetes nodes. - properties: - fsType: - description: fsType is the filesystem type to mount. - Must be a filesystem type supported by the host - operating system. Ex. "ext4", "xfs", "ntfs". Default - is "xfs". - type: string - gateway: - description: gateway is the host address of the - ScaleIO API Gateway. - type: string - protectionDomain: - description: protectionDomain is the name of the - ScaleIO Protection Domain for the configured storage. - type: string - readOnly: - description: readOnly Defaults to false (read/write). - ReadOnly here will force the ReadOnly setting - in VolumeMounts. - type: boolean - secretRef: - description: secretRef references to the secret - for ScaleIO user and other sensitive information. - If this is not provided, Login operation will - fail. - properties: - name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' - type: string - type: object - x-kubernetes-map-type: atomic - sslEnabled: - description: sslEnabled Flag enable/disable SSL - communication with Gateway, default false - type: boolean - storageMode: - description: storageMode indicates whether the storage - for a volume should be ThickProvisioned or ThinProvisioned. - Default is ThinProvisioned. - type: string - storagePool: - description: storagePool is the ScaleIO Storage - Pool associated with the protection domain. - type: string - system: - description: system is the name of the storage system - as configured in ScaleIO. - type: string - volumeName: - description: volumeName is the name of a volume - already created in the ScaleIO system that is - associated with this volume source. - type: string - required: - - gateway - - secretRef - - system - type: object - secret: - description: 'secret represents a secret that should - populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' - properties: - defaultMode: - description: 'defaultMode is Optional: mode bits - used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or - a decimal value between 0 and 511. YAML accepts - both octal and decimal values, JSON requires decimal - values for mode bits. Defaults to 0644. Directories - within the path are not affected by this setting. - This might be in conflict with other options that - affect the file mode, like fsGroup, and the result - can be other mode bits set.' - format: int32 - type: integer - items: - description: items If unspecified, each key-value - pair in the Data field of the referenced Secret - will be projected into the volume as a file whose - name is the key and content is the value. If specified, - the listed keys will be projected into the specified - paths, and unlisted keys will not be present. - If a key is specified which is not present in - the Secret, the volume setup will error unless - it is marked optional. Paths must be relative - and may not contain the '..' path or start with - '..'. - items: - description: Maps a string key to a path within - a volume. - properties: - key: - description: key is the key to project. - type: string - mode: - description: 'mode is Optional: mode bits - used to set permissions on this file. Must - be an octal value between 0000 and 0777 - or a decimal value between 0 and 511. YAML - accepts both octal and decimal values, JSON - requires decimal values for mode bits. If - not specified, the volume defaultMode will - be used. This might be in conflict with - other options that affect the file mode, - like fsGroup, and the result can be other - mode bits set.' - format: int32 - type: integer - path: - description: path is the relative path of - the file to map the key to. May not be an - absolute path. May not contain the path - element '..'. May not start with the string - '..'. - type: string - required: - - key - - path - type: object - type: array - optional: - description: optional field specify whether the - Secret or its keys must be defined - type: boolean - secretName: - description: 'secretName is the name of the secret - in the pod''s namespace to use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' - type: string - type: object - storageos: - description: storageOS represents a StorageOS volume - attached and mounted on Kubernetes nodes. - properties: - fsType: - description: fsType is the filesystem type to mount. - Must be a filesystem type supported by the host - operating system. Ex. "ext4", "xfs", "ntfs". Implicitly - inferred to be "ext4" if unspecified. - type: string - readOnly: - description: readOnly defaults to false (read/write). - ReadOnly here will force the ReadOnly setting - in VolumeMounts. - type: boolean - secretRef: - description: secretRef specifies the secret to use - for obtaining the StorageOS API credentials. If - not specified, default values will be attempted. - properties: - name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' - type: string - type: object - x-kubernetes-map-type: atomic - volumeName: - description: volumeName is the human-readable name - of the StorageOS volume. Volume names are only - unique within a namespace. - type: string - volumeNamespace: - description: volumeNamespace specifies the scope - of the volume within StorageOS. If no namespace - is specified then the Pod's namespace will be - used. This allows the Kubernetes name scoping - to be mirrored within StorageOS for tighter integration. - Set VolumeName to any name to override the default - behaviour. Set to "default" if you are not using - namespaces within StorageOS. Namespaces that do - not pre-exist within StorageOS will be created. - type: string - type: object - vsphereVolume: - description: vsphereVolume represents a vSphere volume - attached and mounted on kubelets host machine - properties: - fsType: - description: fsType is filesystem type to mount. - Must be a filesystem type supported by the host - operating system. Ex. "ext4", "xfs", "ntfs". Implicitly - inferred to be "ext4" if unspecified. - type: string - storagePolicyID: - description: storagePolicyID is the storage Policy - Based Management (SPBM) profile ID associated - with the StoragePolicyName. - type: string - storagePolicyName: - description: storagePolicyName is the storage Policy - Based Management (SPBM) profile name. - type: string - volumePath: - description: volumePath is the path that identifies - vSphere volume vmdk - type: string - required: - - volumePath - type: object - required: - - name - type: object - type: array - required: - - containers - type: object - type: object terraformVersion: type: string type: object diff --git a/controllers/job.go b/controllers/job.go new file mode 100644 index 00000000..d6f75102 --- /dev/null +++ b/controllers/job.go @@ -0,0 +1,36 @@ +package controllers + +import ( + configv1alpha1 "github.com/padok-team/burrito/api/v1alpha1" + corev1 "k8s.io/api/core/v1" +) + +type Action string + +const ( + PlanAction Action = "plan" + ApplyAction Action = "apply" +) + +func defaultPodSpec() corev1.PodSpec { + return corev1.PodSpec{ + Containers: [ + corev1.Container{ + Image: "", + }, + ], + + } +} + +func getPod(layer *configv1alpha1.TerraformLayer, action Action) corev1.Pod { + pod := corev1.Pod{ + Spec: defaultPodSpec(), + } + switch action { + case PlanAction: + case ApplyAction: + } + return pod + +} From 89a4c2fe23a0463cce89d7ba3f12d2d45aba0fc2 Mon Sep 17 00:00:00 2001 From: spoukke Date: Mon, 12 Dec 2022 11:00:04 +0100 Subject: [PATCH 18/42] feat: fix init default pod spec --- controllers/job.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/controllers/job.go b/controllers/job.go index d6f75102..50907809 100644 --- a/controllers/job.go +++ b/controllers/job.go @@ -14,12 +14,12 @@ const ( func defaultPodSpec() corev1.PodSpec { return corev1.PodSpec{ - Containers: [ + Containers: []corev1.Container{ corev1.Container{ - Image: "", + Image: "", + Command: []string{"terraform init"}, }, - ], - + }, } } From 49be385c5a9e1ae14b8b6bb6768305d96890add7 Mon Sep 17 00:00:00 2001 From: spoukke Date: Thu, 15 Dec 2022 15:27:15 +0100 Subject: [PATCH 19/42] feat: fix init default pod spec --- controllers/job.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/controllers/job.go b/controllers/job.go index 50907809..aa1d875d 100644 --- a/controllers/job.go +++ b/controllers/job.go @@ -12,7 +12,7 @@ const ( ApplyAction Action = "apply" ) -func defaultPodSpec() corev1.PodSpec { +func defaultPodSpec(terraformVersion string, path string, branch string) corev1.PodSpec { return corev1.PodSpec{ Containers: []corev1.Container{ corev1.Container{ @@ -25,7 +25,7 @@ func defaultPodSpec() corev1.PodSpec { func getPod(layer *configv1alpha1.TerraformLayer, action Action) corev1.Pod { pod := corev1.Pod{ - Spec: defaultPodSpec(), + Spec: defaultPodSpec(layer.Spec.TerraformVersion, layer.Spec.Path, layer.Spec.Branch), } switch action { case PlanAction: From 5a25c7b58a714cc985610bf107caaa6324eb3270 Mon Sep 17 00:00:00 2001 From: Alan Date: Thu, 15 Dec 2022 16:31:48 +0100 Subject: [PATCH 20/42] chore(wip): runner --- api/v1alpha1/terraformrepository_types.go | 12 +- controllers/job.go | 36 ------ controllers/pod.go | 128 ++++++++++++++++++++++ controllers/terraformlayer_controller.go | 59 +++++++--- 4 files changed, 181 insertions(+), 54 deletions(-) delete mode 100644 controllers/job.go create mode 100644 controllers/pod.go diff --git a/api/v1alpha1/terraformrepository_types.go b/api/v1alpha1/terraformrepository_types.go index 41d7a0b0..a8bdb91b 100644 --- a/api/v1alpha1/terraformrepository_types.go +++ b/api/v1alpha1/terraformrepository_types.go @@ -17,6 +17,7 @@ limitations under the License. package v1alpha1 import ( + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -28,14 +29,17 @@ type TerraformRepositorySpec struct { // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster // Important: Run "make" to regenerate code after modifying this file - // Foo is an example field of TerraformRepository. Edit terraformrepository_types.go to remove/update - Foo string `json:"foo,omitempty"` + Repository TerraformRepositoryRepository `json:"repository,omitempty"` +} + +type TerraformRepositoryRepository struct { + Url string `json:"url,omitempty"` + SecretRef corev1.SecretReference `json:"secretRef,omitempty"` } // TerraformRepositoryStatus defines the observed state of TerraformRepository type TerraformRepositoryStatus struct { - // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - // Important: Run "make" to regenerate code after modifying this file + Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,1,rep,name=conditions"` } //+kubebuilder:object:root=true diff --git a/controllers/job.go b/controllers/job.go deleted file mode 100644 index aa1d875d..00000000 --- a/controllers/job.go +++ /dev/null @@ -1,36 +0,0 @@ -package controllers - -import ( - configv1alpha1 "github.com/padok-team/burrito/api/v1alpha1" - corev1 "k8s.io/api/core/v1" -) - -type Action string - -const ( - PlanAction Action = "plan" - ApplyAction Action = "apply" -) - -func defaultPodSpec(terraformVersion string, path string, branch string) corev1.PodSpec { - return corev1.PodSpec{ - Containers: []corev1.Container{ - corev1.Container{ - Image: "", - Command: []string{"terraform init"}, - }, - }, - } -} - -func getPod(layer *configv1alpha1.TerraformLayer, action Action) corev1.Pod { - pod := corev1.Pod{ - Spec: defaultPodSpec(layer.Spec.TerraformVersion, layer.Spec.Path, layer.Spec.Branch), - } - switch action { - case PlanAction: - case ApplyAction: - } - return pod - -} diff --git a/controllers/pod.go b/controllers/pod.go new file mode 100644 index 00000000..16a7dc5a --- /dev/null +++ b/controllers/pod.go @@ -0,0 +1,128 @@ +package controllers + +import ( + "fmt" + + configv1alpha1 "github.com/padok-team/burrito/api/v1alpha1" + corev1 "k8s.io/api/core/v1" +) + +type Action string + +const ( + PlanAction Action = "plan" + ApplyAction Action = "apply" +) + +func defaultPodSpec(layer *configv1alpha1.TerraformLayer, repository *configv1alpha1.TerraformRepository) corev1.PodSpec { + return corev1.PodSpec{ + Containers: []corev1.Container{ + { + Image: fmt.Sprintf("terraform:%s", layer.Spec.TerraformVersion), + WorkingDir: "/repository", + VolumeMounts: []corev1.VolumeMount{ + { + Name: "gitRepository", + MountPath: "/repository", + }, + { + Name: "redis-cli", + MountPath: "/redis", + }, + }, + Env: []corev1.EnvVar{ + { + Name: "REDIS_URL", + Value: "redis", + }, + { + Name: "REDIS_USER", + Value: "redis", + }, + { + Name: "REDIS_PASSWORD", + Value: "", + }, + { + Name: "REDIS_PORT", + Value: "6379", + }, + }, + }, + }, + InitContainers: []corev1.Container{ + { + Name: "0-git-repository-cloning", + Image: "alpine/git", + Command: []string{ + "sh", + "-c", + fmt.Sprintf("git clone --branch --single-branch %s %s .", layer.Spec.Branch, repository.Spec.Repository.Url), + }, + WorkingDir: "/repository", + VolumeMounts: []corev1.VolumeMount{ + { + Name: "gitRepository", + MountPath: "/repository", + }, + }, + }, + { + Name: "1-install-redis-cli", + Image: "alpine", + Command: []string{ + "sh", + "-c", + "apk install redis;cp /usr/bin/redis-cli /redis/cli", + }, + WorkingDir: "/repository", + VolumeMounts: []corev1.VolumeMount{ + { + Name: "redis-cli", + MountPath: "/redis", + }, + }, + }, + }, + Volumes: []corev1.Volume{ + { + Name: "gitRepository", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + { + Name: "redis-cli", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + }, + } +} + +func getPod(layer *configv1alpha1.TerraformLayer, repository *configv1alpha1.TerraformRepository, action Action) corev1.Pod { + pod := corev1.Pod{ + Spec: defaultPodSpec(layer, repository), + } + switch action { + case PlanAction: + pod.Spec.Containers[0].Command = []string{ + "sh", + "-c", + fmt.Sprintf("%s;%s;%s;%s;%s;%s", + "cd /repository", + "terraform init", + "terraform plan -out plan.out", + "/redis/cli -u redis://${REDIS_USER}:${REDIS_PASSWORD}@${REDIS_HOST}:${REDIS_PORT} -x HSET set ${KEY} plan_binary This should not have happened return ctrl.Result{} }, conditions From c05749f0199b20551f2527950137e098610ec320 Mon Sep 17 00:00:00 2001 From: spoukke Date: Thu, 15 Dec 2022 17:49:23 +0100 Subject: [PATCH 21/42] feat: finish cache logic for plan pod creation --- controllers/pod.go | 37 +++++++++++++++--------- controllers/terraformlayer_controller.go | 23 +++++++++++---- 2 files changed, 40 insertions(+), 20 deletions(-) diff --git a/controllers/pod.go b/controllers/pod.go index 16a7dc5a..6212dfb8 100644 --- a/controllers/pod.go +++ b/controllers/pod.go @@ -32,21 +32,25 @@ func defaultPodSpec(layer *configv1alpha1.TerraformLayer, repository *configv1al }, Env: []corev1.EnvVar{ { - Name: "REDIS_URL", + Name: "REDIS_URL", Value: "redis", }, { - Name: "REDIS_USER", + Name: "REDIS_USER", Value: "redis", }, { - Name: "REDIS_PASSWORD", + Name: "REDIS_PASSWORD", Value: "", }, { - Name: "REDIS_PORT", + Name: "REDIS_PORT", Value: "6379", }, + { + Name: "CACHE_LOCK_KEY", + Value: fmt.Sprintf("%s%s", CachePrefixLock, computeHash(layer.Spec.Repository.Name, layer.Spec.Repository.Namespace, layer.Spec.Path)), + }, }, }, }, @@ -107,22 +111,27 @@ func getPod(layer *configv1alpha1.TerraformLayer, repository *configv1alpha1.Ter } switch action { case PlanAction: + pod.Spec.Containers[0].Env = append(pod.Spec.Containers[0].Env, corev1.EnvVar{ + Name: "CACHE_SUM_KEY", + Value: fmt.Sprintf("%s%s", CachePrefixLastPlannedArtifact, computeHash(layer.Spec.Repository.Name, layer.Spec.Repository.Namespace, layer.Spec.Path, layer.Spec.Branch)), + }) + pod.Spec.Containers[0].Env = append(pod.Spec.Containers[0].Env, corev1.EnvVar{ + Name: "CACHE_BIN_KEY", + Value: fmt.Sprintf("%s%s", CachePrefixLastPlannedArtifactBin, computeHash(layer.Spec.Repository.Name, layer.Spec.Repository.Namespace, layer.Spec.Path, layer.Spec.Branch)), + }) pod.Spec.Containers[0].Command = []string{ "sh", "-c", fmt.Sprintf("%s;%s;%s;%s;%s;%s", - "cd /repository", - "terraform init", - "terraform plan -out plan.out", - "/redis/cli -u redis://${REDIS_USER}:${REDIS_PASSWORD}@${REDIS_HOST}:${REDIS_PORT} -x HSET set ${KEY} plan_binary Date: Thu, 15 Dec 2022 18:02:50 +0100 Subject: [PATCH 22/42] feat: add command for apply pod --- controllers/pod.go | 48 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/controllers/pod.go b/controllers/pod.go index 6212dfb8..f6cd56b0 100644 --- a/controllers/pod.go +++ b/controllers/pod.go @@ -51,6 +51,26 @@ func defaultPodSpec(layer *configv1alpha1.TerraformLayer, repository *configv1al Name: "CACHE_LOCK_KEY", Value: fmt.Sprintf("%s%s", CachePrefixLock, computeHash(layer.Spec.Repository.Name, layer.Spec.Repository.Namespace, layer.Spec.Path)), }, + { + Name: "CACHE_PLAN_SUM_KEY", + Value: fmt.Sprintf("%s%s", CachePrefixLastPlannedArtifact, computeHash(layer.Spec.Repository.Name, layer.Spec.Repository.Namespace, layer.Spec.Path, layer.Spec.Branch)), + }, + { + Name: "CACHE_PLAN_BIN_KEY", + Value: fmt.Sprintf("%s%s", CachePrefixLastPlannedArtifactBin, computeHash(layer.Spec.Repository.Name, layer.Spec.Repository.Namespace, layer.Spec.Path, layer.Spec.Branch)), + }, + { + Name: "CACHE_PLAN_DATE_KEY", + Value: fmt.Sprintf("%s%s", CachePrefixLastPlanDate, computeHash(layer.Spec.Repository.Name, layer.Spec.Repository.Namespace, layer.Spec.Path, layer.Spec.Branch)), + }, + { + Name: "CACHE_APPLY_SUM_KEY", + Value: fmt.Sprintf("%s%s", CachePrefixLastAppliedArtifact, computeHash(layer.Spec.Repository.Name, layer.Spec.Repository.Namespace, layer.Spec.Path, layer.Spec.Branch)), + }, + { + Name: "CACHE_APPLY_BIN_KEY", + Value: fmt.Sprintf("%s%s", CachePrefixLastAppliedArtifactBin, computeHash(layer.Spec.Repository.Name, layer.Spec.Repository.Namespace, layer.Spec.Path, layer.Spec.Branch)), + }, }, }, }, @@ -111,27 +131,33 @@ func getPod(layer *configv1alpha1.TerraformLayer, repository *configv1alpha1.Ter } switch action { case PlanAction: - pod.Spec.Containers[0].Env = append(pod.Spec.Containers[0].Env, corev1.EnvVar{ - Name: "CACHE_SUM_KEY", - Value: fmt.Sprintf("%s%s", CachePrefixLastPlannedArtifact, computeHash(layer.Spec.Repository.Name, layer.Spec.Repository.Namespace, layer.Spec.Path, layer.Spec.Branch)), - }) - pod.Spec.Containers[0].Env = append(pod.Spec.Containers[0].Env, corev1.EnvVar{ - Name: "CACHE_BIN_KEY", - Value: fmt.Sprintf("%s%s", CachePrefixLastPlannedArtifactBin, computeHash(layer.Spec.Repository.Name, layer.Spec.Repository.Namespace, layer.Spec.Path, layer.Spec.Branch)), - }) pod.Spec.Containers[0].Command = []string{ "sh", "-c", - fmt.Sprintf("%s;%s;%s;%s;%s;%s", + fmt.Sprintf("%s;%s;%s;%s;%s;%s;%s", "cd /repository", "terraform init", "terraform plan -out plan.out", - "/redis/cli -u redis://${REDIS_USER}:${REDIS_PASSWORD}@${REDIS_HOST}:${REDIS_PORT} -x HSET set ${CACHE_BIN_KEY} plan_binary plan.out", + "terraform apply --auto-approve plan.out", + "/redis/cli -u redis://${REDIS_USER}:${REDIS_PASSWORD}@${REDIS_HOST}:${REDIS_PORT} -x HSET set ${CACHE_APPLY_BIN_KEY} plan_binary Date: Fri, 16 Dec 2022 14:20:50 +0100 Subject: [PATCH 23/42] feat: implement redis cache --- controllers/cache.go | 42 +++++++++++++++++++++++- controllers/terraformlayer_controller.go | 2 +- go.mod | 2 ++ go.sum | 4 +++ 4 files changed, 48 insertions(+), 2 deletions(-) diff --git a/controllers/cache.go b/controllers/cache.go index 590829d0..48a780fa 100644 --- a/controllers/cache.go +++ b/controllers/cache.go @@ -1,6 +1,12 @@ package controllers -import "errors" +import ( + "context" + "errors" + "time" + + "github.com/go-redis/redis/v8" +) type Cache interface { Get(key string) ([]byte, error) @@ -12,6 +18,40 @@ type MemoryCache struct { data map[string][]byte } +type RedisCache struct { + Client *redis.Client +} + +func newRedisCache(addr string, password string, db int) *RedisCache { + return &RedisCache{ + Client: redis.NewClient(&redis.Options{ + Addr: addr, + Password: password, // no password set + DB: db, // use default DB + }), + } +} + +func (r *RedisCache) Get(key string) ([]byte, error) { + val, err := r.Client.Get(context.TODO(), key).Result() + if err != nil { + return nil, err + } + return []byte(val), nil +} + +func (r *RedisCache) Set(key string, value []byte, ttl int) error { + err := r.Client.Set(context.TODO(), key, value, time.Second*time.Duration(ttl)).Err() + if err != nil { + return err + } + return nil +} + +func (r *RedisCache) Delete(key string) error { + return nil +} + func newMemoryCache() *MemoryCache { return &MemoryCache{ data: map[string][]byte{}, diff --git a/controllers/terraformlayer_controller.go b/controllers/terraformlayer_controller.go index f65852ae..e87a4d46 100644 --- a/controllers/terraformlayer_controller.go +++ b/controllers/terraformlayer_controller.go @@ -90,7 +90,7 @@ func (r *TerraformLayerReconciler) Reconcile(ctx context.Context, req ctrl.Reque // SetupWithManager sets up the controller with the Manager. func (r *TerraformLayerReconciler) SetupWithManager(mgr ctrl.Manager) error { - r.Cache = newMemoryCache() + r.Cache = newRedisCache("redis:6379", "", 0) return ctrl.NewControllerManagedBy(mgr). For(&configv1alpha1.TerraformLayer{}). Complete(r) diff --git a/go.mod b/go.mod index d705fd78..3d1264a6 100644 --- a/go.mod +++ b/go.mod @@ -23,6 +23,7 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/emicklei/go-restful/v3 v3.8.0 // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/fsnotify/fsnotify v1.5.4 // indirect @@ -31,6 +32,7 @@ require ( github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/jsonreference v0.19.5 // indirect github.com/go-openapi/swag v0.19.14 // indirect + github.com/go-redis/redis/v8 v8.11.5 // indirect github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.2.0 // indirect diff --git a/go.sum b/go.sum index 145e5d04..ac9079b0 100644 --- a/go.sum +++ b/go.sum @@ -96,6 +96,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/emicklei/go-restful/v3 v3.8.0 h1:eCZ8ulSerjdAiaNpF7GxXIE7ZCMo1moN1qX+S609eVw= github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= @@ -140,6 +142,8 @@ github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= From 8e71e385f780e5386dd33edad1e20e2b6f3a0c9a Mon Sep 17 00:00:00 2001 From: Alan Date: Mon, 19 Dec 2022 17:45:38 +0100 Subject: [PATCH 24/42] improvement(runner): add runner code, init cobra, move to cache package --- cache/common.go | 7 + cache/memory.go | 32 +++ controllers/cache.go => cache/redis.go | 38 +--- cmd/controller/controller.go | 40 ++++ cmd/controller/start.go | 39 ++++ cmd/root.go | 76 ++++++++ cmd/runner/runner.go | 40 ++++ cmd/runner/start.go | 39 ++++ controllers/conditions_test.go | 5 +- controllers/manager.go | 121 ++++++++++++ controllers/pod.go | 2 +- controllers/terraformlayer_controller.go | 17 +- go.mod | 103 +++++++--- go.sum | 236 +++++++++++++++++++++++ main.go | 118 +----------- runner/runner.go | 163 ++++++++++++++++ 16 files changed, 882 insertions(+), 194 deletions(-) create mode 100644 cache/common.go create mode 100644 cache/memory.go rename controllers/cache.go => cache/redis.go (50%) create mode 100644 cmd/controller/controller.go create mode 100644 cmd/controller/start.go create mode 100644 cmd/root.go create mode 100644 cmd/runner/runner.go create mode 100644 cmd/runner/start.go create mode 100644 controllers/manager.go create mode 100644 runner/runner.go diff --git a/cache/common.go b/cache/common.go new file mode 100644 index 00000000..a1d228d7 --- /dev/null +++ b/cache/common.go @@ -0,0 +1,7 @@ +package cache + +type Cache interface { + Get(key string) ([]byte, error) + Set(key string, value []byte, ttl int) error + Delete(key string) error +} diff --git a/cache/memory.go b/cache/memory.go new file mode 100644 index 00000000..0a506dd6 --- /dev/null +++ b/cache/memory.go @@ -0,0 +1,32 @@ +package cache + +import ( + "errors" +) + +type MemoryCache struct { + data map[string][]byte +} + +func NewMemoryCache() *MemoryCache { + return &MemoryCache{ + data: map[string][]byte{}, + } +} + +func (m *MemoryCache) Get(key string) ([]byte, error) { + if _, ok := m.data[key]; !ok { + return nil, errors.New("key not found") + } + return m.data[key], nil +} + +func (m *MemoryCache) Set(key string, value []byte, ttl int) error { + m.data[key] = value + return nil +} + +func (m *MemoryCache) Delete(key string) error { + delete(m.data, key) + return nil +} diff --git a/controllers/cache.go b/cache/redis.go similarity index 50% rename from controllers/cache.go rename to cache/redis.go index 48a780fa..93351b38 100644 --- a/controllers/cache.go +++ b/cache/redis.go @@ -1,28 +1,17 @@ -package controllers +package cache import ( "context" - "errors" "time" "github.com/go-redis/redis/v8" ) -type Cache interface { - Get(key string) ([]byte, error) - Set(key string, value []byte, ttl int) error - Delete(key string) error -} - -type MemoryCache struct { - data map[string][]byte -} - type RedisCache struct { Client *redis.Client } -func newRedisCache(addr string, password string, db int) *RedisCache { +func NewRedisCache(addr string, password string, db int) *RedisCache { return &RedisCache{ Client: redis.NewClient(&redis.Options{ Addr: addr, @@ -51,26 +40,3 @@ func (r *RedisCache) Set(key string, value []byte, ttl int) error { func (r *RedisCache) Delete(key string) error { return nil } - -func newMemoryCache() *MemoryCache { - return &MemoryCache{ - data: map[string][]byte{}, - } -} - -func (m *MemoryCache) Get(key string) ([]byte, error) { - if _, ok := m.data[key]; !ok { - return nil, errors.New("key not found") - } - return m.data[key], nil -} - -func (m *MemoryCache) Set(key string, value []byte, ttl int) error { - m.data[key] = value - return nil -} - -func (m *MemoryCache) Delete(key string) error { - delete(m.data, key) - return nil -} diff --git a/cmd/controller/controller.go b/cmd/controller/controller.go new file mode 100644 index 00000000..81e3ee19 --- /dev/null +++ b/cmd/controller/controller.go @@ -0,0 +1,40 @@ +/* +Copyright © 2022 NAME HERE +*/ +package controller + +import ( + "fmt" + cmd "github.com/padok-team/burrito/cmd" + + "github.com/spf13/cobra" +) + +// controllerCmd represents the controller command +var controllerCmd = &cobra.Command{ + Use: "controller", + Short: "A brief description of your command", + Long: `A longer description that spans multiple lines and likely contains examples +and usage of using your command. For example: + +Cobra is a CLI library for Go that empowers applications. +This application is a tool to generate the needed files +to quickly create a Cobra application.`, + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("controller called") + }, +} + +func init() { + cmd.RootCmd.AddCommand(controllerCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this commandworkbench.action.openSettings + // and all subcommands, e.g.: + // controllerCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // controllerCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} diff --git a/cmd/controller/start.go b/cmd/controller/start.go new file mode 100644 index 00000000..da561823 --- /dev/null +++ b/cmd/controller/start.go @@ -0,0 +1,39 @@ +/* +Copyright © 2022 NAME HERE +*/ +package controller + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +// startCmd represents the start command +var startCmd = &cobra.Command{ + Use: "start", + Short: "A brief description of your command", + Long: `A longer description that spans multiple lines and likely contains examples +and usage of using your command. For example: + +Cobra is a CLI library for Go that empowers applications. +This application is a tool to generate the needed files +to quickly create a Cobra application.`, + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("start called") + }, +} + +func init() { + controllerCmd.AddCommand(startCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // startCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // startCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} diff --git a/cmd/root.go b/cmd/root.go new file mode 100644 index 00000000..169fc9af --- /dev/null +++ b/cmd/root.go @@ -0,0 +1,76 @@ +/* +Copyright © 2022 NAME HERE +*/ +package cmd + +import ( + "fmt" + "os" + + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var cfgFile string + +// RootCmd represents the base command when called without any subcommands +var RootCmd = &cobra.Command{ + Use: "burrito", + Short: "A brief description of your application", + Long: `A longer description that spans multiple lines and likely contains +examples and usage of using your application. For example: + +Cobra is a CLI library for Go that empowers applications. +This application is a tool to generate the needed files +to quickly create a Cobra application.`, + // Uncomment the following line if your bare application + // has an action associated with it: + // Run: func(cmd *cobra.Command, args []string) { }, +} + +// Execute adds all child commands to the root command and sets flags appropriately. +// This is called by main.main(). It only needs to happen once to the rootCmd. +func Execute() { + err := RootCmd.Execute() + if err != nil { + os.Exit(1) + } +} + +func init() { + cobra.OnInitialize(initConfig) + + // Here you will define your flags and configuration settings. + // Cobra supports persistent flags, which, if defined here, + // will be global for your application. + + RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.burrito.yaml)") + + // Cobra also supports local flags, which will only run + // when this action is called directly. + RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} + +// initConfig reads in config file and ENV variables if set. +func initConfig() { + if cfgFile != "" { + // Use config file from the flag. + viper.SetConfigFile(cfgFile) + } else { + // Find home directory. + home, err := os.UserHomeDir() + cobra.CheckErr(err) + + // Search config in home directory with name ".burrito" (without extension). + viper.AddConfigPath(home) + viper.SetConfigType("yaml") + viper.SetConfigName(".burrito") + } + + viper.AutomaticEnv() // read in environment variables that match + + // If a config file is found, read it in. + if err := viper.ReadInConfig(); err == nil { + fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed()) + } +} diff --git a/cmd/runner/runner.go b/cmd/runner/runner.go new file mode 100644 index 00000000..9a71f2c2 --- /dev/null +++ b/cmd/runner/runner.go @@ -0,0 +1,40 @@ +/* +Copyright © 2022 NAME HERE +*/ +package runner + +import ( + "fmt" + + cmd "github.com/padok-team/burrito/cmd" + "github.com/spf13/cobra" +) + +// runnerCmd represents the runner command +var runnerCmd = &cobra.Command{ + Use: "runner", + Short: "A brief description of your command", + Long: `A longer description that spans multiple lines and likely contains examples +and usage of using your command. For example: + +Cobra is a CLI library for Go that empowers applications. +This application is a tool to generate the needed files +to quickly create a Cobra application.`, + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("runner called") + }, +} + +func init() { + cmd.RootCmd.AddCommand(runnerCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // runnerCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // runnerCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} diff --git a/cmd/runner/start.go b/cmd/runner/start.go new file mode 100644 index 00000000..0cf91eec --- /dev/null +++ b/cmd/runner/start.go @@ -0,0 +1,39 @@ +/* +Copyright © 2022 NAME HERE +*/ +package runner + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +// startCmd represents the start command +var startCmd = &cobra.Command{ + Use: "start", + Short: "A brief description of your command", + Long: `A longer description that spans multiple lines and likely contains examples +and usage of using your command. For example: + +Cobra is a CLI library for Go that empowers applications. +This application is a tool to generate the needed files +to quickly create a Cobra application.`, + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("start called") + }, +} + +func init() { + runnerCmd.AddCommand(startCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // startCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // startCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} diff --git a/controllers/conditions_test.go b/controllers/conditions_test.go index 6d13aef7..2700dea4 100644 --- a/controllers/conditions_test.go +++ b/controllers/conditions_test.go @@ -24,6 +24,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" configv1alpha1 "github.com/padok-team/burrito/api/v1alpha1" + internal "github.com/padok-team/burrito/cache" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -50,7 +51,7 @@ var _ = AfterSuite(func() { var _ = Describe("TerraformLayer", func() { var t *configv1alpha1.TerraformLayer - var cache Cache + var cache internal.Cache BeforeEach(func() { t = &configv1alpha1.TerraformLayer{ @@ -63,7 +64,7 @@ var _ = Describe("TerraformLayer", func() { }, }, } - cache = newMemoryCache() + cache = internal.NewMemoryCache() }) Describe("TerraformRunningCondition", func() { diff --git a/controllers/manager.go b/controllers/manager.go new file mode 100644 index 00000000..8afb95b5 --- /dev/null +++ b/controllers/manager.go @@ -0,0 +1,121 @@ +/* +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 controllers + +import ( + "flag" + "os" + + // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) + // to ensure that exec-entrypoint and run can make use of them. + _ "k8s.io/client-go/plugin/pkg/client/auth" + + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/healthz" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + + configv1alpha1 "github.com/padok-team/burrito/api/v1alpha1" + //+kubebuilder:scaffold:imports +) + +var ( + scheme = runtime.NewScheme() + setupLog = ctrl.Log.WithName("setup") +) + +func init() { + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + + utilruntime.Must(configv1alpha1.AddToScheme(scheme)) + //+kubebuilder:scaffold:scheme +} + +func StartManager() { + var metricsAddr string + var enableLeaderElection bool + var probeAddr string + flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.") + flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") + flag.BoolVar(&enableLeaderElection, "leader-elect", false, + "Enable leader election for controller manager. "+ + "Enabling this will ensure there is only one active controller manager.") + opts := zap.Options{ + Development: true, + } + opts.BindFlags(flag.CommandLine) + flag.Parse() + + ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) + + mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ + Scheme: scheme, + MetricsBindAddress: metricsAddr, + Port: 9443, + HealthProbeBindAddress: probeAddr, + LeaderElection: enableLeaderElection, + LeaderElectionID: "6d185457.terraform.padok.cloud", + // LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily + // when the Manager ends. This requires the binary to immediately end when the + // Manager is stopped, otherwise, this setting is unsafe. Setting this significantly + // speeds up voluntary leader transitions as the new leader don't have to wait + // LeaseDuration time first. + // + // In the default scaffold provided, the program ends immediately after + // the manager stops, so would be fine to enable this option. However, + // if you are doing or is intended to do any operation such as perform cleanups + // after the manager stops then its usage might be unsafe. + // LeaderElectionReleaseOnCancel: true, + }) + if err != nil { + setupLog.Error(err, "unable to start manager") + os.Exit(1) + } + + if err = (&TerraformRepositoryReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "TerraformRepository") + os.Exit(1) + } + if err = (&TerraformLayerReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "TerraformLayer") + os.Exit(1) + } + //+kubebuilder:scaffold:builder + + if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { + setupLog.Error(err, "unable to set up health check") + os.Exit(1) + } + if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil { + setupLog.Error(err, "unable to set up ready check") + os.Exit(1) + } + + setupLog.Info("starting manager") + if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { + setupLog.Error(err, "problem running manager") + os.Exit(1) + } +} diff --git a/controllers/pod.go b/controllers/pod.go index f6cd56b0..7b1d430e 100644 --- a/controllers/pod.go +++ b/controllers/pod.go @@ -151,7 +151,7 @@ func getPod(layer *configv1alpha1.TerraformLayer, repository *configv1alpha1.Ter fmt.Sprintf("%s;%s;%s;%s;%s;%s;%s", "cd /repository", "terraform init", - "/redis/cli -u redis://${REDIS_USER}:${REDIS_PASSWORD}@${REDIS_HOST}:${REDIS_PORT} -x HGET set ${CACHE_PLAN_BIN_KEY} plan_binary > plan.out", + "/redis/cli -u redis://${REDIS_USER}:${REDIS_PASSWORD}@${REDIS_HOST}:${REDIS_PORT} -x HGET get ${CACHE_PLAN_BIN_KEY} plan_binary > plan.out", "terraform apply --auto-approve plan.out", "/redis/cli -u redis://${REDIS_USER}:${REDIS_PASSWORD}@${REDIS_HOST}:${REDIS_PORT} -x HSET set ${CACHE_APPLY_BIN_KEY} plan_binary */ - package main -import ( - "flag" - "os" - - // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) - // to ensure that exec-entrypoint and run can make use of them. - _ "k8s.io/client-go/plugin/pkg/client/auth" - - "k8s.io/apimachinery/pkg/runtime" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - clientgoscheme "k8s.io/client-go/kubernetes/scheme" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/healthz" - "sigs.k8s.io/controller-runtime/pkg/log/zap" - - configv1alpha1 "github.com/padok-team/burrito/api/v1alpha1" - "github.com/padok-team/burrito/controllers" - //+kubebuilder:scaffold:imports -) - -var ( - scheme = runtime.NewScheme() - setupLog = ctrl.Log.WithName("setup") -) - -func init() { - utilruntime.Must(clientgoscheme.AddToScheme(scheme)) - - utilruntime.Must(configv1alpha1.AddToScheme(scheme)) - //+kubebuilder:scaffold:scheme -} +import "github.com/padok-team/burrito/cmd" func main() { - var metricsAddr string - var enableLeaderElection bool - var probeAddr string - flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.") - flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") - flag.BoolVar(&enableLeaderElection, "leader-elect", false, - "Enable leader election for controller manager. "+ - "Enabling this will ensure there is only one active controller manager.") - opts := zap.Options{ - Development: true, - } - opts.BindFlags(flag.CommandLine) - flag.Parse() - - ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) - - mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ - Scheme: scheme, - MetricsBindAddress: metricsAddr, - Port: 9443, - HealthProbeBindAddress: probeAddr, - LeaderElection: enableLeaderElection, - LeaderElectionID: "6d185457.terraform.padok.cloud", - // LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily - // when the Manager ends. This requires the binary to immediately end when the - // Manager is stopped, otherwise, this setting is unsafe. Setting this significantly - // speeds up voluntary leader transitions as the new leader don't have to wait - // LeaseDuration time first. - // - // In the default scaffold provided, the program ends immediately after - // the manager stops, so would be fine to enable this option. However, - // if you are doing or is intended to do any operation such as perform cleanups - // after the manager stops then its usage might be unsafe. - // LeaderElectionReleaseOnCancel: true, - }) - if err != nil { - setupLog.Error(err, "unable to start manager") - os.Exit(1) - } - - if err = (&controllers.TerraformRepositoryReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "TerraformRepository") - os.Exit(1) - } - if err = (&controllers.TerraformLayerReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "TerraformLayer") - os.Exit(1) - } - //+kubebuilder:scaffold:builder - - if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { - setupLog.Error(err, "unable to set up health check") - os.Exit(1) - } - if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil { - setupLog.Error(err, "unable to set up ready check") - os.Exit(1) - } - - setupLog.Info("starting manager") - if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { - setupLog.Error(err, "problem running manager") - os.Exit(1) - } + cmd.Execute() } diff --git a/runner/runner.go b/runner/runner.go new file mode 100644 index 00000000..4fce07b5 --- /dev/null +++ b/runner/runner.go @@ -0,0 +1,163 @@ +package runner + +import ( + "context" + "crypto/sha256" + "fmt" + "io" + "log" + "os" + + "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/plumbing" + "github.com/hashicorp/go-version" + "github.com/hashicorp/hc-install/product" + "github.com/hashicorp/hc-install/releases" + "github.com/hashicorp/terraform-exec/tfexec" + cache "github.com/padok-team/burrito/cache" +) + +const PlanArtifact string = "plan.out" +const WorkingDir string = "/burrito" + +type Runner struct { + Config *Config + Out io.Writer + Err io.Writer + Terraform *tfexec.Terraform + Cache cache.Cache +} + +type Credentials struct { + SSH string `yaml:"ssh,omitempty"` + Username string `yaml:"username,omitempty"` + Password string `yaml:"password,omitempty"` +} + +type Config struct { + Path string `yaml:"path"` + Branch string `yaml:"branch"` + Version string `yaml:"version"` + Action string `yaml:"action"` + Repository string `yaml:"repository"` + Credentials Credentials `yaml:"credentials"` + Redis Redis `yaml:"redis"` + Layer Layer `yaml:"layer"` +} + +type Layer struct { + Lock string `yaml:"lock,omitempty"` + PlanSum string `yaml:"planSum,omitempty"` + PlanBin string `yaml:"planBin,omitempty"` + ApplySum string `yaml:"applySum,omitempty"` +} + +type Redis struct { + URI string `yaml:"uri"` +} + +func New() (*Runner, error) { + runner := &Runner{ + Config: &Config{}, + Out: os.Stdout, + Err: os.Stderr, + } + return runner, nil +} + +func (r *Runner) Exec() { + err := r.init() + if err != nil { + log.Fatalf("error initializing runner: %s", err) + } + switch r.Config.Action { + case "plan": + r.plan() + case "apply": + r.apply() + default: + log.Fatalf("Unrecognized runner Action") + } +} + +func (r *Runner) init() error { + installer := &releases.ExactVersion{ + Product: product.Terraform, + Version: version.Must(version.NewVersion(r.Config.Version)), + } + execPath, err := installer.Install(context.Background()) + if err != nil { + return err + } + //TODO: Implement authentication here + _, err = git.PlainClone(WorkingDir, false, &git.CloneOptions{ + ReferenceName: plumbing.ReferenceName(r.Config.Branch), + URL: r.Config.Repository, + }) + if err != nil { + return err + } + workingDir := fmt.Sprintf("%s/%s", WorkingDir, r.Config.Path) + r.Terraform, err = tfexec.NewTerraform(workingDir, execPath) + if err != nil { + return err + } + err = r.Terraform.Init(context.Background(), tfexec.Upgrade(true)) + if err != nil { + return err + } + return nil +} + +func (r *Runner) plan() { + _, err := r.Terraform.Plan(context.Background(), tfexec.Out(PlanArtifact)) + cacheErr := r.Cache.Delete(r.Config.Layer.Lock) + if cacheErr != nil { + log.Fatalf("Could not delete lock: %s", cacheErr) + return + } + if err != nil { + log.Printf("Terraform plan errored: %s", err) + return + } + 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 + } + sum := sha256.Sum256(plan) + err = r.Cache.Set(r.Config.Layer.PlanBin, plan, 3600) + if err != nil { + log.Fatalf("Could not put plan binary in cache: %s", err) + } + err = r.Cache.Set(r.Config.Layer.PlanSum, sum[:], 3600) + if err != nil { + log.Fatalf("Could not put plan checksum in cache: %s", err) + } +} + +func (r *Runner) apply() { + plan, err := r.Cache.Get(r.Config.Layer.PlanBin) + if err != nil { + log.Printf("Could not get plan artifact: %s", 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) + } + err = r.Terraform.Apply(context.Background(), tfexec.DirOrPlan(PlanArtifact)) + cacheErr := r.Cache.Delete(r.Config.Layer.Lock) + if cacheErr != nil { + log.Fatalf("Could not delete lock: %s", cacheErr) + return + } + if err != nil { + log.Fatalf("Terraform apply errored: %s", err) + return + } + err = r.Cache.Set(r.Config.Layer.ApplySum, sum[:], 3600) + if err != nil { + log.Fatalf("Could not put apply checksum in cache: %s", err) + } +} From 29204d75704ee523af4cf36a3b4e9403e19aa38b Mon Sep 17 00:00:00 2001 From: spoukke Date: Wed, 21 Dec 2022 10:10:47 +0100 Subject: [PATCH 25/42] feat: remove applied bin cahce key --- controllers/pod.go | 5 ----- controllers/terraformlayer_controller.go | 1 - 2 files changed, 6 deletions(-) diff --git a/controllers/pod.go b/controllers/pod.go index 7b1d430e..b847510c 100644 --- a/controllers/pod.go +++ b/controllers/pod.go @@ -67,10 +67,6 @@ func defaultPodSpec(layer *configv1alpha1.TerraformLayer, repository *configv1al Name: "CACHE_APPLY_SUM_KEY", Value: fmt.Sprintf("%s%s", CachePrefixLastAppliedArtifact, computeHash(layer.Spec.Repository.Name, layer.Spec.Repository.Namespace, layer.Spec.Path, layer.Spec.Branch)), }, - { - Name: "CACHE_APPLY_BIN_KEY", - Value: fmt.Sprintf("%s%s", CachePrefixLastAppliedArtifactBin, computeHash(layer.Spec.Repository.Name, layer.Spec.Repository.Namespace, layer.Spec.Path, layer.Spec.Branch)), - }, }, }, }, @@ -153,7 +149,6 @@ func getPod(layer *configv1alpha1.TerraformLayer, repository *configv1alpha1.Ter "terraform init", "/redis/cli -u redis://${REDIS_USER}:${REDIS_PASSWORD}@${REDIS_HOST}:${REDIS_PORT} -x HGET get ${CACHE_PLAN_BIN_KEY} plan_binary > plan.out", "terraform apply --auto-approve plan.out", - "/redis/cli -u redis://${REDIS_USER}:${REDIS_PASSWORD}@${REDIS_HOST}:${REDIS_PORT} -x HSET set ${CACHE_APPLY_BIN_KEY} plan_binary Date: Wed, 21 Dec 2022 11:38:48 +0100 Subject: [PATCH 26/42] feat(cobra): implement cobra launch --- burrito/burrito.go | 40 ++++++++++++ burrito/config/config.go | 111 ++++++++++++++++++++++++++++++++++ burrito/controllers.go | 5 ++ burrito/runner.go | 5 ++ cmd/controller/controller.go | 40 ------------ cmd/controller/start.go | 39 ------------ cmd/controllers/controller.go | 16 +++++ cmd/controllers/start.go | 21 +++++++ cmd/root.go | 76 +++++------------------ cmd/runner/runner.go | 35 ++--------- cmd/runner/start.go | 40 ++++-------- controllers/manager.go | 35 +++++++---- controllers/pod.go | 2 +- main.go | 18 +++++- runner/runner.go | 95 +++++++++-------------------- 15 files changed, 299 insertions(+), 279 deletions(-) create mode 100644 burrito/burrito.go create mode 100644 burrito/config/config.go create mode 100644 burrito/controllers.go create mode 100644 burrito/runner.go delete mode 100644 cmd/controller/controller.go delete mode 100644 cmd/controller/start.go create mode 100644 cmd/controllers/controller.go create mode 100644 cmd/controllers/start.go diff --git a/burrito/burrito.go b/burrito/burrito.go new file mode 100644 index 00000000..147e4e53 --- /dev/null +++ b/burrito/burrito.go @@ -0,0 +1,40 @@ +package burrito + +import ( + "io" + "os" + + "github.com/padok-team/burrito/burrito/config" + "github.com/padok-team/burrito/controllers" + "github.com/padok-team/burrito/runner" +) + +type App struct { + Config *config.Config + + Runner Runner + Controllers Controllers + + Out io.Writer + Err io.Writer +} + +type Runner interface { + Exec() +} + +type Controllers interface { + Exec() +} + +func New() (*App, error) { + c := &config.Config{} + app := &App{ + Config: c, + Runner: runner.New(c), + Controllers: controllers.New(c), + Out: os.Stdout, + Err: os.Stderr, + } + return app, nil +} diff --git a/burrito/config/config.go b/burrito/config/config.go new file mode 100644 index 00000000..bdc13880 --- /dev/null +++ b/burrito/config/config.go @@ -0,0 +1,111 @@ +package config + +import ( + "fmt" + "os" + "reflect" + "strings" + + "github.com/spf13/pflag" + "github.com/spf13/viper" +) + +type Config struct { + Runner RunnerConfig `yaml:"runner,omitempty"` + Controller ControllerConfig `yaml:"controller,omitempty"` + Redis Redis `yaml:"redis"` +} + +type ControllerConfig struct { + WatchedNamespaces []string `yaml:"namespaces,omitempty"` +} + +type RepositoryConfig struct { + URL string `yaml:"url"` + SSH string `yaml:"ssh,omitempty"` + Username string `yaml:"username,omitempty"` + Password string `yaml:"password,omitempty"` +} + +type RunnerConfig struct { + Path string `yaml:"path"` + Branch string `yaml:"branch"` + Version string `yaml:"version"` + Action string `yaml:"action"` + Repository RepositoryConfig `yaml:"repository"` + Layer LayerConfig `yaml:"layer"` +} + +type LayerConfig struct { + Lock string `yaml:"lock,omitempty"` + PlanSum string `yaml:"planSum,omitempty"` + PlanBin string `yaml:"planBin,omitempty"` + ApplySum string `yaml:"applySum,omitempty"` +} + +type Redis struct { + URL string `yaml:"url"` + Password string `yaml:"password,omitempty"` + Database int `yaml:"database,omitempty"` +} + +func (c *Config) Load(flags *pflag.FlagSet) error { + v := viper.New() + + // burrito looks for configuration files called config.yaml, config.json, + // config.toml, config.hcl, etc. + v.SetConfigName("config") + + // burrito looks for configuration files in the common configuration + // directories. + v.AddConfigPath("/etc/burrito/") + v.AddConfigPath("$HOME/.burrito/") + + // Viper logs the configuration file it uses, if any. + if err := v.ReadInConfig(); err == nil { + fmt.Fprintf(os.Stderr, "Using config file: %s\n", v.ConfigFileUsed()) + } + + // burrito can be configured with environment variables that start with + // burrito_. + v.SetEnvPrefix("burrito") + v.AutomaticEnv() + + // Options with dashes in flag names have underscores when set inside a + // configuration file or with environment variables. + flags.SetNormalizeFunc(func(fs *pflag.FlagSet, name string) pflag.NormalizedName { + name = strings.ReplaceAll(name, "-", "_") + return pflag.NormalizedName(name) + }) + v.BindPFlags(flags) + + // Nested configuration options set with environment variables use an + // underscore as a separator. + v.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) + bindEnvironmentVariables(v, *c) + + return v.Unmarshal(c) +} + +// bindEnvironmentVariables inspects iface's structure and recursively binds its +// fields to environment variables. This is a workaround to a limitation of +// Viper, found here: +// https://github.com/spf13/viper/issues/188#issuecomment-399884438 +func bindEnvironmentVariables(v *viper.Viper, iface interface{}, parts ...string) { + ifv := reflect.ValueOf(iface) + ift := reflect.TypeOf(iface) + for i := 0; i < ift.NumField(); i++ { + val := ifv.Field(i) + typ := ift.Field(i) + tv, ok := typ.Tag.Lookup("yaml") + if !ok { + continue + } + switch val.Kind() { + case reflect.Struct: + bindEnvironmentVariables(v, val.Interface(), append(parts, tv)...) + default: + v.BindEnv(strings.Join(append(parts, tv), ".")) + } + } +} diff --git a/burrito/controllers.go b/burrito/controllers.go new file mode 100644 index 00000000..64ee652a --- /dev/null +++ b/burrito/controllers.go @@ -0,0 +1,5 @@ +package burrito + +func (a *App) StartController() error { + return nil +} diff --git a/burrito/runner.go b/burrito/runner.go new file mode 100644 index 00000000..c7d2f057 --- /dev/null +++ b/burrito/runner.go @@ -0,0 +1,5 @@ +package burrito + +func (app *App) StartRunner() { + app.Runner.Exec() +} diff --git a/cmd/controller/controller.go b/cmd/controller/controller.go deleted file mode 100644 index 81e3ee19..00000000 --- a/cmd/controller/controller.go +++ /dev/null @@ -1,40 +0,0 @@ -/* -Copyright © 2022 NAME HERE -*/ -package controller - -import ( - "fmt" - cmd "github.com/padok-team/burrito/cmd" - - "github.com/spf13/cobra" -) - -// controllerCmd represents the controller command -var controllerCmd = &cobra.Command{ - Use: "controller", - Short: "A brief description of your command", - Long: `A longer description that spans multiple lines and likely contains examples -and usage of using your command. For example: - -Cobra is a CLI library for Go that empowers applications. -This application is a tool to generate the needed files -to quickly create a Cobra application.`, - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("controller called") - }, -} - -func init() { - cmd.RootCmd.AddCommand(controllerCmd) - - // Here you will define your flags and configuration settings. - - // Cobra supports Persistent Flags which will work for this commandworkbench.action.openSettings - // and all subcommands, e.g.: - // controllerCmd.PersistentFlags().String("foo", "", "A help for foo") - - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // controllerCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") -} diff --git a/cmd/controller/start.go b/cmd/controller/start.go deleted file mode 100644 index da561823..00000000 --- a/cmd/controller/start.go +++ /dev/null @@ -1,39 +0,0 @@ -/* -Copyright © 2022 NAME HERE -*/ -package controller - -import ( - "fmt" - - "github.com/spf13/cobra" -) - -// startCmd represents the start command -var startCmd = &cobra.Command{ - Use: "start", - Short: "A brief description of your command", - Long: `A longer description that spans multiple lines and likely contains examples -and usage of using your command. For example: - -Cobra is a CLI library for Go that empowers applications. -This application is a tool to generate the needed files -to quickly create a Cobra application.`, - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("start called") - }, -} - -func init() { - controllerCmd.AddCommand(startCmd) - - // Here you will define your flags and configuration settings. - - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // startCmd.PersistentFlags().String("foo", "", "A help for foo") - - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // startCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") -} diff --git a/cmd/controllers/controller.go b/cmd/controllers/controller.go new file mode 100644 index 00000000..893fa555 --- /dev/null +++ b/cmd/controllers/controller.go @@ -0,0 +1,16 @@ +/* +Copyright © 2022 NAME HERE +*/ +package controllers + +import ( + "github.com/padok-team/burrito/burrito" + + "github.com/spf13/cobra" +) + +func BuildControllersCmd(app *burrito.App) *cobra.Command { + cmd := &cobra.Command{} + cmd.AddCommand(buildControllersStartCmd(app)) + return cmd +} diff --git a/cmd/controllers/start.go b/cmd/controllers/start.go new file mode 100644 index 00000000..00ddf828 --- /dev/null +++ b/cmd/controllers/start.go @@ -0,0 +1,21 @@ +/* +Copyright © 2022 NAME HERE +*/ +package controllers + +import ( + "github.com/padok-team/burrito/burrito" + "github.com/spf13/cobra" +) + +func buildControllersStartCmd(app *burrito.App) *cobra.Command { + cmd := &cobra.Command{ + Use: "start", + Short: "Start Burrito controllers", + RunE: func(cmd *cobra.Command, args []string) error { + app.StartController() + return nil + }, + } + return cmd +} diff --git a/cmd/root.go b/cmd/root.go index 169fc9af..6eb1e00e 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -4,73 +4,27 @@ Copyright © 2022 NAME HERE package cmd import ( - "fmt" - "os" + "github.com/padok-team/burrito/burrito" + "github.com/padok-team/burrito/cmd/controllers" + "github.com/padok-team/burrito/cmd/runner" "github.com/spf13/cobra" - "github.com/spf13/viper" ) -var cfgFile string - -// RootCmd represents the base command when called without any subcommands -var RootCmd = &cobra.Command{ - Use: "burrito", - Short: "A brief description of your application", - Long: `A longer description that spans multiple lines and likely contains -examples and usage of using your application. For example: - -Cobra is a CLI library for Go that empowers applications. -This application is a tool to generate the needed files -to quickly create a Cobra application.`, - // Uncomment the following line if your bare application - // has an action associated with it: - // Run: func(cmd *cobra.Command, args []string) { }, +func New(app *burrito.App) *cobra.Command { + return buildBurritoCmd(app) } -// Execute adds all child commands to the root command and sets flags appropriately. -// This is called by main.main(). It only needs to happen once to the rootCmd. -func Execute() { - err := RootCmd.Execute() - if err != nil { - os.Exit(1) +func buildBurritoCmd(app *burrito.App) *cobra.Command { + cmd := &cobra.Command{ + Use: "burrito", + Short: "burrito is a TACoS", + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + return app.Config.Load(cmd.Flags()) + }, } -} - -func init() { - cobra.OnInitialize(initConfig) - // Here you will define your flags and configuration settings. - // Cobra supports persistent flags, which, if defined here, - // will be global for your application. - - RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.burrito.yaml)") - - // Cobra also supports local flags, which will only run - // when this action is called directly. - RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") -} - -// initConfig reads in config file and ENV variables if set. -func initConfig() { - if cfgFile != "" { - // Use config file from the flag. - viper.SetConfigFile(cfgFile) - } else { - // Find home directory. - home, err := os.UserHomeDir() - cobra.CheckErr(err) - - // Search config in home directory with name ".burrito" (without extension). - viper.AddConfigPath(home) - viper.SetConfigType("yaml") - viper.SetConfigName(".burrito") - } - - viper.AutomaticEnv() // read in environment variables that match - - // If a config file is found, read it in. - if err := viper.ReadInConfig(); err == nil { - fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed()) - } + cmd.AddCommand(controllers.BuildControllersCmd(app)) + cmd.AddCommand(runner.BuildRunnerCmd(app)) + return cmd } diff --git a/cmd/runner/runner.go b/cmd/runner/runner.go index 9a71f2c2..88ba0def 100644 --- a/cmd/runner/runner.go +++ b/cmd/runner/runner.go @@ -4,37 +4,12 @@ Copyright © 2022 NAME HERE package runner import ( - "fmt" - - cmd "github.com/padok-team/burrito/cmd" + "github.com/padok-team/burrito/burrito" "github.com/spf13/cobra" ) -// runnerCmd represents the runner command -var runnerCmd = &cobra.Command{ - Use: "runner", - Short: "A brief description of your command", - Long: `A longer description that spans multiple lines and likely contains examples -and usage of using your command. For example: - -Cobra is a CLI library for Go that empowers applications. -This application is a tool to generate the needed files -to quickly create a Cobra application.`, - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("runner called") - }, -} - -func init() { - cmd.RootCmd.AddCommand(runnerCmd) - - // Here you will define your flags and configuration settings. - - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // runnerCmd.PersistentFlags().String("foo", "", "A help for foo") - - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // runnerCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +func BuildRunnerCmd(app *burrito.App) *cobra.Command { + cmd := &cobra.Command{} + cmd.AddCommand(buildRunnerStartCmd(app)) + return cmd } diff --git a/cmd/runner/start.go b/cmd/runner/start.go index 0cf91eec..86ffa9df 100644 --- a/cmd/runner/start.go +++ b/cmd/runner/start.go @@ -4,36 +4,18 @@ Copyright © 2022 NAME HERE package runner import ( - "fmt" - + "github.com/padok-team/burrito/burrito" "github.com/spf13/cobra" ) -// startCmd represents the start command -var startCmd = &cobra.Command{ - Use: "start", - Short: "A brief description of your command", - Long: `A longer description that spans multiple lines and likely contains examples -and usage of using your command. For example: - -Cobra is a CLI library for Go that empowers applications. -This application is a tool to generate the needed files -to quickly create a Cobra application.`, - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("start called") - }, -} - -func init() { - runnerCmd.AddCommand(startCmd) - - // Here you will define your flags and configuration settings. - - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // startCmd.PersistentFlags().String("foo", "", "A help for foo") - - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // startCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +func buildRunnerStartCmd(app *burrito.App) *cobra.Command { + cmd := &cobra.Command{ + Use: "start", + Short: "Start Burrito runner", + RunE: func(cmd *cobra.Command, args []string) error { + app.StartRunner() + return nil + }, + } + return cmd } diff --git a/controllers/manager.go b/controllers/manager.go index 8afb95b5..fb72b030 100644 --- a/controllers/manager.go +++ b/controllers/manager.go @@ -32,6 +32,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log/zap" configv1alpha1 "github.com/padok-team/burrito/api/v1alpha1" + "github.com/padok-team/burrito/burrito/config" //+kubebuilder:scaffold:imports ) @@ -40,6 +41,16 @@ var ( setupLog = ctrl.Log.WithName("setup") ) +type Controllers struct { + config *config.Config +} + +func New(c *config.Config) *Controllers { + return &Controllers{ + config: c, + } +} + func init() { utilruntime.Must(clientgoscheme.AddToScheme(scheme)) @@ -47,15 +58,15 @@ func init() { //+kubebuilder:scaffold:scheme } -func StartManager() { - var metricsAddr string - var enableLeaderElection bool - var probeAddr string - flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.") - flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") - flag.BoolVar(&enableLeaderElection, "leader-elect", false, - "Enable leader election for controller manager. "+ - "Enabling this will ensure there is only one active controller manager.") +func (c *Controllers) Exec() { + // var metricsAddr string + // var enableLeaderElection bool + // var probeAddr string + // flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.") + // flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") + // flag.BoolVar(&enableLeaderElection, "leader-elect", false, + // "Enable leader election for controller manager. "+ + // "Enabling this will ensure there is only one active controller manager.") opts := zap.Options{ Development: true, } @@ -66,10 +77,10 @@ func StartManager() { mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ Scheme: scheme, - MetricsBindAddress: metricsAddr, + MetricsBindAddress: ":8080", Port: 9443, - HealthProbeBindAddress: probeAddr, - LeaderElection: enableLeaderElection, + HealthProbeBindAddress: ":8081", + LeaderElection: false, LeaderElectionID: "6d185457.terraform.padok.cloud", // LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily // when the Manager ends. This requires the binary to immediately end when the diff --git a/controllers/pod.go b/controllers/pod.go index b847510c..898f33ac 100644 --- a/controllers/pod.go +++ b/controllers/pod.go @@ -144,7 +144,7 @@ func getPod(layer *configv1alpha1.TerraformLayer, repository *configv1alpha1.Ter pod.Spec.Containers[0].Command = []string{ "sh", "-c", - fmt.Sprintf("%s;%s;%s;%s;%s;%s;%s", + fmt.Sprintf("%s;%s;%s;%s;%s;%s", "cd /repository", "terraform init", "/redis/cli -u redis://${REDIS_USER}:${REDIS_PASSWORD}@${REDIS_HOST}:${REDIS_PORT} -x HGET get ${CACHE_PLAN_BIN_KEY} plan_binary > plan.out", diff --git a/main.go b/main.go index a525fc34..61c88dde 100644 --- a/main.go +++ b/main.go @@ -3,8 +3,22 @@ Copyright © 2022 NAME HERE */ package main -import "github.com/padok-team/burrito/cmd" +import ( + "fmt" + "os" + + "github.com/padok-team/burrito/burrito" + "github.com/padok-team/burrito/cmd" +) func main() { - cmd.Execute() + app, err := burrito.New() + if err != nil { + fmt.Fprintf(os.Stderr, "fatal: %s\n", err) + os.Exit(1) + } + + if err := cmd.New(app).Execute(); err != nil { + os.Exit(1) + } } diff --git a/runner/runner.go b/runner/runner.go index 4fce07b5..d1372bc2 100644 --- a/runner/runner.go +++ b/runner/runner.go @@ -4,7 +4,6 @@ import ( "context" "crypto/sha256" "fmt" - "io" "log" "os" @@ -14,55 +13,23 @@ import ( "github.com/hashicorp/hc-install/product" "github.com/hashicorp/hc-install/releases" "github.com/hashicorp/terraform-exec/tfexec" - cache "github.com/padok-team/burrito/cache" + "github.com/padok-team/burrito/burrito/config" + "github.com/padok-team/burrito/cache" ) const PlanArtifact string = "plan.out" const WorkingDir string = "/burrito" type Runner struct { - Config *Config - Out io.Writer - Err io.Writer - Terraform *tfexec.Terraform - Cache cache.Cache + config *config.Config + terraform *tfexec.Terraform + cache cache.Cache } -type Credentials struct { - SSH string `yaml:"ssh,omitempty"` - Username string `yaml:"username,omitempty"` - Password string `yaml:"password,omitempty"` -} - -type Config struct { - Path string `yaml:"path"` - Branch string `yaml:"branch"` - Version string `yaml:"version"` - Action string `yaml:"action"` - Repository string `yaml:"repository"` - Credentials Credentials `yaml:"credentials"` - Redis Redis `yaml:"redis"` - Layer Layer `yaml:"layer"` -} - -type Layer struct { - Lock string `yaml:"lock,omitempty"` - PlanSum string `yaml:"planSum,omitempty"` - PlanBin string `yaml:"planBin,omitempty"` - ApplySum string `yaml:"applySum,omitempty"` -} - -type Redis struct { - URI string `yaml:"uri"` -} - -func New() (*Runner, error) { - runner := &Runner{ - Config: &Config{}, - Out: os.Stdout, - Err: os.Stderr, +func New(c *config.Config) *Runner { + return &Runner{ + config: c, } - return runner, nil } func (r *Runner) Exec() { @@ -70,7 +37,7 @@ func (r *Runner) Exec() { if err != nil { log.Fatalf("error initializing runner: %s", err) } - switch r.Config.Action { + switch r.config.Runner.Action { case "plan": r.plan() case "apply": @@ -81,9 +48,11 @@ func (r *Runner) Exec() { } func (r *Runner) init() error { + r.cache = cache.NewRedisCache(r.config.Redis.URL, r.config.Redis.Password, r.config.Redis.Database) + installer := &releases.ExactVersion{ Product: product.Terraform, - Version: version.Must(version.NewVersion(r.Config.Version)), + Version: version.Must(version.NewVersion(r.config.Runner.Version)), } execPath, err := installer.Install(context.Background()) if err != nil { @@ -91,18 +60,18 @@ func (r *Runner) init() error { } //TODO: Implement authentication here _, err = git.PlainClone(WorkingDir, false, &git.CloneOptions{ - ReferenceName: plumbing.ReferenceName(r.Config.Branch), - URL: r.Config.Repository, + ReferenceName: plumbing.ReferenceName(r.config.Runner.Branch), + URL: r.config.Runner.Repository.URL, }) if err != nil { return err } - workingDir := fmt.Sprintf("%s/%s", WorkingDir, r.Config.Path) - r.Terraform, err = tfexec.NewTerraform(workingDir, execPath) + workingDir := fmt.Sprintf("%s/%s", WorkingDir, r.config.Runner.Path) + r.terraform, err = tfexec.NewTerraform(workingDir, execPath) if err != nil { return err } - err = r.Terraform.Init(context.Background(), tfexec.Upgrade(true)) + err = r.terraform.Init(context.Background(), tfexec.Upgrade(true)) if err != nil { return err } @@ -110,54 +79,50 @@ func (r *Runner) init() error { } func (r *Runner) plan() { - _, err := r.Terraform.Plan(context.Background(), tfexec.Out(PlanArtifact)) - cacheErr := r.Cache.Delete(r.Config.Layer.Lock) - if cacheErr != nil { - log.Fatalf("Could not delete lock: %s", cacheErr) - return - } + defer r.cache.Delete(r.config.Runner.Layer.Lock) + _, err := r.terraform.Plan(context.Background(), tfexec.Out(PlanArtifact)) if err != nil { log.Printf("Terraform plan errored: %s", err) return } - plan, err := os.ReadFile(fmt.Sprintf("%s/%s", r.Terraform.WorkingDir(), PlanArtifact)) + 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 } sum := sha256.Sum256(plan) - err = r.Cache.Set(r.Config.Layer.PlanBin, plan, 3600) + err = r.cache.Set(r.config.Runner.Layer.PlanBin, plan, 3600) if err != nil { log.Fatalf("Could not put plan binary in cache: %s", err) } - err = r.Cache.Set(r.Config.Layer.PlanSum, sum[:], 3600) + err = r.cache.Set(r.config.Runner.Layer.PlanSum, sum[:], 3600) if err != nil { log.Fatalf("Could not put plan checksum in cache: %s", err) } + log.Print("Terraform plan ran successfully") } func (r *Runner) apply() { - plan, err := r.Cache.Get(r.Config.Layer.PlanBin) + defer r.cache.Delete(r.config.Runner.Layer.Lock) + plan, err := r.cache.Get(r.config.Runner.Layer.PlanBin) if err != nil { log.Printf("Could not get plan artifact: %s", err) + return } sum := sha256.Sum256(plan) - err = os.WriteFile(fmt.Sprintf("%s/%s", r.Terraform.WorkingDir(), PlanArtifact), plan, 0644) + 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) - } - err = r.Terraform.Apply(context.Background(), tfexec.DirOrPlan(PlanArtifact)) - cacheErr := r.Cache.Delete(r.Config.Layer.Lock) - if cacheErr != nil { - log.Fatalf("Could not delete lock: %s", cacheErr) return } + err = r.terraform.Apply(context.Background(), tfexec.DirOrPlan(PlanArtifact)) if err != nil { log.Fatalf("Terraform apply errored: %s", err) return } - err = r.Cache.Set(r.Config.Layer.ApplySum, sum[:], 3600) + err = r.cache.Set(r.config.Runner.Layer.ApplySum, sum[:], 3600) if err != nil { log.Fatalf("Could not put apply checksum in cache: %s", err) } + log.Print("Terraform apply ran successfully") } From 3774fc55f7cbaa2a50c05c28b2721dfe128cb202 Mon Sep 17 00:00:00 2001 From: Alan Date: Wed, 21 Dec 2022 11:52:58 +0100 Subject: [PATCH 27/42] chore(runner): modify pod creation to use burrito binary --- Makefile | 2 +- api/v1alpha1/zz_generated.deepcopy.go | 28 ++++- cmd/controllers/controller.go | 5 +- cmd/runner/runner.go | 5 +- controllers/pod.go | 155 +++++++++----------------- 5 files changed, 86 insertions(+), 109 deletions(-) diff --git a/Makefile b/Makefile index aa720f11..dfbaea4e 100644 --- a/Makefile +++ b/Makefile @@ -109,7 +109,7 @@ test: manifests generate fmt vet envtest ## Run tests. .PHONY: build build: generate fmt vet ## Build manager binary. - go build -o bin/manager main.go + go build -o bin/burrito main.go .PHONY: run run: manifests generate fmt vet ## Run a controller from your host. diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index ee921b08..923b9376 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -22,7 +22,7 @@ limitations under the License. package v1alpha1 import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -160,7 +160,7 @@ func (in *TerraformRepository) DeepCopyInto(out *TerraformRepository) { out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) out.Spec = in.Spec - out.Status = in.Status + in.Status.DeepCopyInto(&out.Status) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TerraformRepository. @@ -213,9 +213,26 @@ func (in *TerraformRepositoryList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TerraformRepositoryRepository) DeepCopyInto(out *TerraformRepositoryRepository) { + *out = *in + out.SecretRef = in.SecretRef +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TerraformRepositoryRepository. +func (in *TerraformRepositoryRepository) DeepCopy() *TerraformRepositoryRepository { + if in == nil { + return nil + } + out := new(TerraformRepositoryRepository) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TerraformRepositorySpec) DeepCopyInto(out *TerraformRepositorySpec) { *out = *in + out.Repository = in.Repository } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TerraformRepositorySpec. @@ -231,6 +248,13 @@ func (in *TerraformRepositorySpec) DeepCopy() *TerraformRepositorySpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TerraformRepositoryStatus) DeepCopyInto(out *TerraformRepositoryStatus) { *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TerraformRepositoryStatus. diff --git a/cmd/controllers/controller.go b/cmd/controllers/controller.go index 893fa555..2ba2f349 100644 --- a/cmd/controllers/controller.go +++ b/cmd/controllers/controller.go @@ -10,7 +10,10 @@ import ( ) func BuildControllersCmd(app *burrito.App) *cobra.Command { - cmd := &cobra.Command{} + cmd := &cobra.Command{ + Use: "controllers", + Short: "cmd to use burrito's controllers", + } cmd.AddCommand(buildControllersStartCmd(app)) return cmd } diff --git a/cmd/runner/runner.go b/cmd/runner/runner.go index 88ba0def..77b73b22 100644 --- a/cmd/runner/runner.go +++ b/cmd/runner/runner.go @@ -9,7 +9,10 @@ import ( ) func BuildRunnerCmd(app *burrito.App) *cobra.Command { - cmd := &cobra.Command{} + cmd := &cobra.Command{ + Use: "runner", + Short: "cmd to use burrito's runner", + } cmd.AddCommand(buildRunnerStartCmd(app)) return cmd } diff --git a/controllers/pod.go b/controllers/pod.go index 898f33ac..33350d72 100644 --- a/controllers/pod.go +++ b/controllers/pod.go @@ -14,145 +14,92 @@ const ( ApplyAction Action = "apply" ) +func getPod(layer *configv1alpha1.TerraformLayer, repository *configv1alpha1.TerraformRepository, action Action) corev1.Pod { + pod := corev1.Pod{ + Spec: defaultPodSpec(layer, repository), + } + switch action { + case PlanAction: + pod.Spec.Containers[0].Env = append(pod.Spec.Containers[0].Env, corev1.EnvVar{ + Name: "BURRITO_RUNNER_ACTION", + Value: "plan", + }) + case ApplyAction: + pod.Spec.Containers[0].Env = append(pod.Spec.Containers[0].Env, corev1.EnvVar{ + Name: "BURRITO_RUNNER_ACTION", + Value: "apply", + }) + } + return pod +} + func defaultPodSpec(layer *configv1alpha1.TerraformLayer, repository *configv1alpha1.TerraformRepository) corev1.PodSpec { return corev1.PodSpec{ Containers: []corev1.Container{ { Image: fmt.Sprintf("terraform:%s", layer.Spec.TerraformVersion), WorkingDir: "/repository", - VolumeMounts: []corev1.VolumeMount{ + Command: []string{"burrito"}, + Args: []string{"runner", "start"}, + Env: []corev1.EnvVar{ { - Name: "gitRepository", - MountPath: "/repository", + Name: "BURRITO_REDIS_URL", + Value: "redis:6379", }, { - Name: "redis-cli", - MountPath: "/redis", + Name: "BURRITO_REDIS_PASSWORD", + Value: "", }, - }, - Env: []corev1.EnvVar{ { - Name: "REDIS_URL", - Value: "redis", + Name: "BURRITO_REDIS_DATABASE", + Value: "0", }, { - Name: "REDIS_USER", - Value: "redis", + Name: "BURRITO_RUNNER_REPOSITORY_URL", + Value: repository.Spec.Repository.Url, }, { - Name: "REDIS_PASSWORD", + Name: "BURRITO_RUNNER_REPOSITORY_SSH", Value: "", }, { - Name: "REDIS_PORT", - Value: "6379", + Name: "BURRITO_RUNNER_REPOSITORY_USERNAME", + Value: "", }, { - Name: "CACHE_LOCK_KEY", - Value: fmt.Sprintf("%s%s", CachePrefixLock, computeHash(layer.Spec.Repository.Name, layer.Spec.Repository.Namespace, layer.Spec.Path)), + Name: "BURRITO_RUNNER_REPOSITORY_PASSWORD", + Value: "", }, { - Name: "CACHE_PLAN_SUM_KEY", - Value: fmt.Sprintf("%s%s", CachePrefixLastPlannedArtifact, computeHash(layer.Spec.Repository.Name, layer.Spec.Repository.Namespace, layer.Spec.Path, layer.Spec.Branch)), + Name: "BURRITO_RUNNER_PATH", + Value: layer.Spec.Path, }, { - Name: "CACHE_PLAN_BIN_KEY", - Value: fmt.Sprintf("%s%s", CachePrefixLastPlannedArtifactBin, computeHash(layer.Spec.Repository.Name, layer.Spec.Repository.Namespace, layer.Spec.Path, layer.Spec.Branch)), + Name: "BURRITO_RUNNER_BRANCH", + Value: layer.Spec.Branch, }, { - Name: "CACHE_PLAN_DATE_KEY", - Value: fmt.Sprintf("%s%s", CachePrefixLastPlanDate, computeHash(layer.Spec.Repository.Name, layer.Spec.Repository.Namespace, layer.Spec.Path, layer.Spec.Branch)), + Name: "BURRITO_RUNNER_VERSION", + Value: layer.Spec.TerraformVersion, }, { - Name: "CACHE_APPLY_SUM_KEY", - Value: fmt.Sprintf("%s%s", CachePrefixLastAppliedArtifact, computeHash(layer.Spec.Repository.Name, layer.Spec.Repository.Namespace, layer.Spec.Path, layer.Spec.Branch)), + Name: "BURRITO_RUNNER_LAYER_LOCK", + Value: fmt.Sprintf("%s%s", CachePrefixLock, computeHash(layer.Spec.Repository.Name, layer.Spec.Repository.Namespace, layer.Spec.Path)), }, - }, - }, - }, - InitContainers: []corev1.Container{ - { - Name: "0-git-repository-cloning", - Image: "alpine/git", - Command: []string{ - "sh", - "-c", - fmt.Sprintf("git clone --branch --single-branch %s %s .", layer.Spec.Branch, repository.Spec.Repository.Url), - }, - WorkingDir: "/repository", - VolumeMounts: []corev1.VolumeMount{ { - Name: "gitRepository", - MountPath: "/repository", + Name: "BURRITO_RUNNER_LAYER_PLANSUM", + Value: fmt.Sprintf("%s%s", CachePrefixLastPlannedArtifact, computeHash(layer.Spec.Repository.Name, layer.Spec.Repository.Namespace, layer.Spec.Path, layer.Spec.Branch)), }, - }, - }, - { - Name: "1-install-redis-cli", - Image: "alpine", - Command: []string{ - "sh", - "-c", - "apk install redis;cp /usr/bin/redis-cli /redis/cli", - }, - WorkingDir: "/repository", - VolumeMounts: []corev1.VolumeMount{ { - Name: "redis-cli", - MountPath: "/redis", + Name: "BURRITO_RUNNER_LAYER_PLANBIN", + Value: fmt.Sprintf("%s%s", CachePrefixLastPlannedArtifact, computeHash(layer.Spec.Repository.Name, layer.Spec.Repository.Namespace, layer.Spec.Path, layer.Spec.Branch)), + }, + { + Name: "BURRITO_RUNNER_LAYER_APPLYSUM", + Value: fmt.Sprintf("%s%s", CachePrefixLastPlannedArtifactBin, computeHash(layer.Spec.Repository.Name, layer.Spec.Repository.Namespace, layer.Spec.Path, layer.Spec.Branch)), }, - }, - }, - }, - Volumes: []corev1.Volume{ - { - Name: "gitRepository", - VolumeSource: corev1.VolumeSource{ - EmptyDir: &corev1.EmptyDirVolumeSource{}, - }, - }, - { - Name: "redis-cli", - VolumeSource: corev1.VolumeSource{ - EmptyDir: &corev1.EmptyDirVolumeSource{}, }, }, }, } } - -func getPod(layer *configv1alpha1.TerraformLayer, repository *configv1alpha1.TerraformRepository, action Action) corev1.Pod { - pod := corev1.Pod{ - Spec: defaultPodSpec(layer, repository), - } - switch action { - case PlanAction: - pod.Spec.Containers[0].Command = []string{ - "sh", - "-c", - fmt.Sprintf("%s;%s;%s;%s;%s;%s;%s", - "cd /repository", - "terraform init", - "terraform plan -out plan.out", - "/redis/cli -u redis://${REDIS_USER}:${REDIS_PASSWORD}@${REDIS_HOST}:${REDIS_PORT} SET ${CACHE_PLAN_DATE_KEY} $(date +%%s)", - "/redis/cli -u redis://${REDIS_USER}:${REDIS_PASSWORD}@${REDIS_HOST}:${REDIS_PORT} -x HSET set ${CACHE_PLAN_BIN_KEY} plan_binary plan.out", - "terraform apply --auto-approve plan.out", - "/redis/cli -u redis://${REDIS_USER}:${REDIS_PASSWORD}@${REDIS_HOST}:${REDIS_PORT} SET ${CACHE_APPLY_SUM_KEY} $(sha256sum plan.out)", - "/redis/cli -u redis://${REDIS_USER}:${REDIS_PASSWORD}@${REDIS_HOST}:${REDIS_PORT} DELETE ${CACHE_LOCK_KEY} $(sha256sum plan.out)", - ), - } - } - return pod -} From 92634b56b11dff22847c0dc6c0079740b1c5de56 Mon Sep 17 00:00:00 2001 From: Alan Date: Wed, 21 Dec 2022 14:37:06 +0100 Subject: [PATCH 28/42] chore(docker): and crd generation --- Dockerfile | 15 ++- ...orm.padok.cloud_terraformrepositories.yaml | 92 ++++++++++++++++++- 2 files changed, 99 insertions(+), 8 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8f9cca18..a0261cd1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,19 +15,26 @@ RUN go mod download COPY main.go main.go COPY api/ api/ COPY controllers/ controllers/ +COPY burrito/ burrito/ +COPY cmd/ cmd/ +COPY runner/ runner/ +COPY cache/ cache # Build # the GOARCH has not a default value to allow the binary be built according to the host where the command # was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO # the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore, # by leaving it empty we can ensure that the container and binary shipped on it will have the same platform. -RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager main.go +RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o burrito main.go # Use distroless as minimal base image to package the manager binary # Refer to https://github.com/GoogleContainerTools/distroless for more details -FROM gcr.io/distroless/static:nonroot +FROM golang:alpine + +RUN apk add --update git bash openssh + WORKDIR / -COPY --from=builder /workspace/manager . +COPY --from=builder /workspace/burrito . USER 65532:65532 -ENTRYPOINT ["/manager"] +ENTRYPOINT ["/burrito"] diff --git a/config/crd/bases/config.terraform.padok.cloud_terraformrepositories.yaml b/config/crd/bases/config.terraform.padok.cloud_terraformrepositories.yaml index bc621bc6..ae7d8f63 100644 --- a/config/crd/bases/config.terraform.padok.cloud_terraformrepositories.yaml +++ b/config/crd/bases/config.terraform.padok.cloud_terraformrepositories.yaml @@ -36,13 +36,97 @@ spec: spec: description: TerraformRepositorySpec defines the desired state of TerraformRepository properties: - foo: - description: Foo is an example field of TerraformRepository. Edit - terraformrepository_types.go to remove/update - type: string + repository: + properties: + secretRef: + description: SecretReference represents a Secret Reference. It + has enough information to retrieve secret in any namespace + properties: + name: + description: name is unique within a namespace to reference + a secret resource. + type: string + namespace: + description: namespace defines the space within which the + secret name must be unique. + type: string + type: object + x-kubernetes-map-type: atomic + url: + type: string + type: object type: object status: description: TerraformRepositoryStatus defines the observed state of TerraformRepository + properties: + conditions: + items: + description: "Condition contains details for one aspect of the current + state of this API Resource. --- This struct is intended for direct + use as an array at the field path .status.conditions. For example, + \n type FooStatus struct{ // Represents the observations of a + foo's current state. // Known .status.conditions.type are: \"Available\", + \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge + // +listType=map // +listMapKey=type Conditions []metav1.Condition + `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" + protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition + transitioned from one status to another. This should be when + the underlying condition changed. If that is not known, then + using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: message is a human readable message indicating + details about the transition. This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: observedGeneration represents the .metadata.generation + that the condition was set based upon. For instance, if .metadata.generation + is currently 12, but the .status.conditions[x].observedGeneration + is 9, the condition is out of date with respect to the current + state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: reason contains a programmatic identifier indicating + the reason for the condition's last transition. Producers + of specific condition types may define expected values and + meanings for this field, and whether the values are considered + a guaranteed API. The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + --- Many .condition.type values are consistent across resources + like Available, but because arbitrary conditions can be useful + (see .node.status.conditions), the ability to deconflict is + important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array type: object type: object served: true From 53415abbba6c7ccd7b64b1742f34f1001bb21bb6 Mon Sep 17 00:00:00 2001 From: spoukke Date: Wed, 21 Dec 2022 14:40:44 +0100 Subject: [PATCH 29/42] feat: use config to setup cahce in layer controller --- controllers/manager.go | 1 + controllers/terraformlayer_controller.go | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/controllers/manager.go b/controllers/manager.go index fb72b030..3f718232 100644 --- a/controllers/manager.go +++ b/controllers/manager.go @@ -109,6 +109,7 @@ func (c *Controllers) Exec() { if err = (&TerraformLayerReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), + Config: c.config, }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "TerraformLayer") os.Exit(1) diff --git a/controllers/terraformlayer_controller.go b/controllers/terraformlayer_controller.go index d585eb55..99d09a26 100644 --- a/controllers/terraformlayer_controller.go +++ b/controllers/terraformlayer_controller.go @@ -25,6 +25,7 @@ import ( "strings" "time" + "github.com/padok-team/burrito/burrito/config" internal "github.com/padok-team/burrito/cache" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -42,6 +43,7 @@ type TerraformLayerReconciler struct { client.Client Scheme *runtime.Scheme Cache internal.Cache + Config *config.Config } //+kubebuilder:rbac:groups=config.terraform.padok.cloud,resources=terraformlayers,verbs=get;list;watch;create;update;patch;delete @@ -91,7 +93,7 @@ func (r *TerraformLayerReconciler) Reconcile(ctx context.Context, req ctrl.Reque // SetupWithManager sets up the controller with the Manager. func (r *TerraformLayerReconciler) SetupWithManager(mgr ctrl.Manager) error { - r.Cache = internal.NewRedisCache("redis:6379", "", 0) + r.Cache = internal.NewRedisCache(r.Config.Redis.URL, r.Config.Redis.Password, r.Config.Redis.Database) return ctrl.NewControllerManagedBy(mgr). For(&configv1alpha1.TerraformLayer{}). Complete(r) From 1275c76498375ba68e373e02899f508b07ad60f8 Mon Sep 17 00:00:00 2001 From: spoukke Date: Wed, 21 Dec 2022 15:04:32 +0100 Subject: [PATCH 30/42] feat: run exec on cotnrollers start --- burrito/controllers.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/burrito/controllers.go b/burrito/controllers.go index 64ee652a..30b4064d 100644 --- a/burrito/controllers.go +++ b/burrito/controllers.go @@ -1,5 +1,6 @@ package burrito -func (a *App) StartController() error { +func (app *App) StartController() error { + app.Controllers.Exec() return nil } From f0c96dc9a6adf0b7d4db72c0b1d5b1b2776b3131 Mon Sep 17 00:00:00 2001 From: spoukke Date: Wed, 21 Dec 2022 15:19:58 +0100 Subject: [PATCH 31/42] feat: use custom image for runeer and generate random name --- controllers/pod.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/controllers/pod.go b/controllers/pod.go index 33350d72..0350dc2a 100644 --- a/controllers/pod.go +++ b/controllers/pod.go @@ -20,11 +20,13 @@ func getPod(layer *configv1alpha1.TerraformLayer, repository *configv1alpha1.Ter } switch action { case PlanAction: + pod.GenerateName = fmt.Sprintf("%s-%s-%s-%s-", layer.Spec.Repository.Name, layer.Spec.Path, layer.Spec.Branch, action) pod.Spec.Containers[0].Env = append(pod.Spec.Containers[0].Env, corev1.EnvVar{ Name: "BURRITO_RUNNER_ACTION", Value: "plan", }) case ApplyAction: + pod.GenerateName = fmt.Sprintf("%s-%s-%s-%s-", layer.Spec.Repository.Name, layer.Spec.Path, layer.Spec.Branch, action) pod.Spec.Containers[0].Env = append(pod.Spec.Containers[0].Env, corev1.EnvVar{ Name: "BURRITO_RUNNER_ACTION", Value: "apply", @@ -37,7 +39,7 @@ func defaultPodSpec(layer *configv1alpha1.TerraformLayer, repository *configv1al return corev1.PodSpec{ Containers: []corev1.Container{ { - Image: fmt.Sprintf("terraform:%s", layer.Spec.TerraformVersion), + Image: fmt.Sprintf("eu.gcr.io/padok-playground/burrito:%s", "alpha"), WorkingDir: "/repository", Command: []string{"burrito"}, Args: []string{"runner", "start"}, From aa75fdb7c3605d188e0f4d103759d021aafca2f4 Mon Sep 17 00:00:00 2001 From: spoukke Date: Wed, 21 Dec 2022 15:29:04 +0100 Subject: [PATCH 32/42] fix: do not inpu error 2 times to logger --- controllers/terraformlayer_controller.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/controllers/terraformlayer_controller.go b/controllers/terraformlayer_controller.go index 99d09a26..f40bc7d5 100644 --- a/controllers/terraformlayer_controller.go +++ b/controllers/terraformlayer_controller.go @@ -146,7 +146,7 @@ func (t *TerraformLayerConditions) Evaluate() (func(ctx context.Context, c clien cache.Set(fmt.Sprintf("%s%s", CachePrefixLock, computeHash(t.Resource.Spec.Repository.Name, t.Resource.Spec.Repository.Namespace, t.Resource.Spec.Path)), []byte("1"), 0) err := c.Create(ctx, &pod) if err != nil { - log.Log.Error(err, "[TerraformApplyHasFailedPreviously] Failed to create pod for Apply action", err) + log.Log.Error(err, "[TerraformApplyHasFailedPreviously] Failed to create pod for Apply action") cache.Delete(fmt.Sprintf("%s%s", CachePrefixLock, computeHash(t.Resource.Spec.Repository.Name, t.Resource.Spec.Repository.Namespace, t.Resource.Spec.Path))) } //TODO: Implement Exponential backoff @@ -158,7 +158,7 @@ func (t *TerraformLayerConditions) Evaluate() (func(ctx context.Context, c clien cache.Set(fmt.Sprintf("%s%s", CachePrefixLock, computeHash(t.Resource.Spec.Repository.Name, t.Resource.Spec.Repository.Namespace, t.Resource.Spec.Path)), []byte("1"), 0) err := c.Create(ctx, &pod) if err != nil { - log.Log.Error(err, "[TerraformApplyNeeded] Failed to create pod for Apply action", err) + log.Log.Error(err, "[TerraformApplyNeeded] Failed to create pod for Apply action") cache.Delete(fmt.Sprintf("%s%s", CachePrefixLock, computeHash(t.Resource.Spec.Repository.Name, t.Resource.Spec.Repository.Namespace, t.Resource.Spec.Path))) } return ctrl.Result{RequeueAfter: time.Minute * 20} @@ -169,7 +169,7 @@ func (t *TerraformLayerConditions) Evaluate() (func(ctx context.Context, c clien cache.Set(fmt.Sprintf("%s%s", CachePrefixLock, computeHash(t.Resource.Spec.Repository.Name, t.Resource.Spec.Repository.Namespace, t.Resource.Spec.Path)), []byte("1"), 0) err := c.Create(ctx, &pod) if err != nil { - log.Log.Error(err, "[TerraformPlanHasFailedPreviously] Failed to create pod for Plan action", err) + log.Log.Error(err, "[TerraformPlanHasFailedPreviously] Failed to create pod for Plan action") cache.Delete(fmt.Sprintf("%s%s", CachePrefixLock, computeHash(t.Resource.Spec.Repository.Name, t.Resource.Spec.Repository.Namespace, t.Resource.Spec.Path))) } //TODO: Implement Exponential backoff @@ -181,7 +181,7 @@ func (t *TerraformLayerConditions) Evaluate() (func(ctx context.Context, c clien cache.Set(fmt.Sprintf("%s%s", CachePrefixLock, computeHash(t.Resource.Spec.Repository.Name, t.Resource.Spec.Repository.Namespace, t.Resource.Spec.Path)), []byte("1"), 0) err := c.Create(ctx, &pod) if err != nil { - log.Log.Error(err, "[TerraformPlanNeeded] Failed to create pod for Plan action", err) + log.Log.Error(err, "[TerraformPlanNeeded] Failed to create pod for Plan action") cache.Delete(fmt.Sprintf("%s%s", CachePrefixLock, computeHash(t.Resource.Spec.Repository.Name, t.Resource.Spec.Repository.Namespace, t.Resource.Spec.Path))) } return ctrl.Result{RequeueAfter: time.Minute * 20} From a78b505bb17b09bb4fe0eea8bb81e05e2f3af602 Mon Sep 17 00:00:00 2001 From: Alan Date: Wed, 21 Dec 2022 15:45:43 +0100 Subject: [PATCH 33/42] fix(runner): pod generation --- Dockerfile | 8 +++----- controllers/pod.go | 6 +++--- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/Dockerfile b/Dockerfile index a0261cd1..be3ca572 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,23 +18,21 @@ COPY controllers/ controllers/ COPY burrito/ burrito/ COPY cmd/ cmd/ COPY runner/ runner/ -COPY cache/ cache +COPY cache/ cache # Build # the GOARCH has not a default value to allow the binary be built according to the host where the command # was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO # the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore, # by leaving it empty we can ensure that the container and binary shipped on it will have the same platform. -RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o burrito main.go +RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o bin/burrito main.go -# Use distroless as minimal base image to package the manager binary -# Refer to https://github.com/GoogleContainerTools/distroless for more details FROM golang:alpine RUN apk add --update git bash openssh WORKDIR / -COPY --from=builder /workspace/burrito . +COPY --from=builder /workspace/bin/burrito . USER 65532:65532 ENTRYPOINT ["/burrito"] diff --git a/controllers/pod.go b/controllers/pod.go index 0350dc2a..f969568c 100644 --- a/controllers/pod.go +++ b/controllers/pod.go @@ -18,15 +18,15 @@ func getPod(layer *configv1alpha1.TerraformLayer, repository *configv1alpha1.Ter pod := corev1.Pod{ Spec: defaultPodSpec(layer, repository), } + pod.SetNamespace(layer.Namespace) + pod.SetGenerateName(fmt.Sprintf("%s-%s-", layer.Name, action)) switch action { case PlanAction: - pod.GenerateName = fmt.Sprintf("%s-%s-%s-%s-", layer.Spec.Repository.Name, layer.Spec.Path, layer.Spec.Branch, action) pod.Spec.Containers[0].Env = append(pod.Spec.Containers[0].Env, corev1.EnvVar{ Name: "BURRITO_RUNNER_ACTION", Value: "plan", }) case ApplyAction: - pod.GenerateName = fmt.Sprintf("%s-%s-%s-%s-", layer.Spec.Repository.Name, layer.Spec.Path, layer.Spec.Branch, action) pod.Spec.Containers[0].Env = append(pod.Spec.Containers[0].Env, corev1.EnvVar{ Name: "BURRITO_RUNNER_ACTION", Value: "apply", @@ -46,7 +46,7 @@ func defaultPodSpec(layer *configv1alpha1.TerraformLayer, repository *configv1al Env: []corev1.EnvVar{ { Name: "BURRITO_REDIS_URL", - Value: "redis:6379", + Value: "burrito-redis-headless:6379", }, { Name: "BURRITO_REDIS_PASSWORD", From 4536cbc13ae7c82de872c59c4d2e805a410afc3f Mon Sep 17 00:00:00 2001 From: Alan Date: Wed, 21 Dec 2022 15:53:13 +0100 Subject: [PATCH 34/42] fix(runner): pod generation remove command --- controllers/pod.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controllers/pod.go b/controllers/pod.go index f969568c..eb735902 100644 --- a/controllers/pod.go +++ b/controllers/pod.go @@ -39,9 +39,9 @@ func defaultPodSpec(layer *configv1alpha1.TerraformLayer, repository *configv1al return corev1.PodSpec{ Containers: []corev1.Container{ { + Name: "runner", Image: fmt.Sprintf("eu.gcr.io/padok-playground/burrito:%s", "alpha"), WorkingDir: "/repository", - Command: []string{"burrito"}, Args: []string{"runner", "start"}, Env: []corev1.EnvVar{ { From 7ebd8a5ce41d92e1f0e4f4426e27f1d3eb06615c Mon Sep 17 00:00:00 2001 From: spoukke Date: Wed, 21 Dec 2022 15:55:22 +0100 Subject: [PATCH 35/42] fix: change prefix in pod env vars --- controllers/pod.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/controllers/pod.go b/controllers/pod.go index eb735902..d20bdb12 100644 --- a/controllers/pod.go +++ b/controllers/pod.go @@ -94,11 +94,11 @@ func defaultPodSpec(layer *configv1alpha1.TerraformLayer, repository *configv1al }, { Name: "BURRITO_RUNNER_LAYER_PLANBIN", - Value: fmt.Sprintf("%s%s", CachePrefixLastPlannedArtifact, computeHash(layer.Spec.Repository.Name, layer.Spec.Repository.Namespace, layer.Spec.Path, layer.Spec.Branch)), + Value: fmt.Sprintf("%s%s", CachePrefixLastPlannedArtifactBin, computeHash(layer.Spec.Repository.Name, layer.Spec.Repository.Namespace, layer.Spec.Path, layer.Spec.Branch)), }, { Name: "BURRITO_RUNNER_LAYER_APPLYSUM", - Value: fmt.Sprintf("%s%s", CachePrefixLastPlannedArtifactBin, computeHash(layer.Spec.Repository.Name, layer.Spec.Repository.Namespace, layer.Spec.Path, layer.Spec.Branch)), + Value: fmt.Sprintf("%s%s", CachePrefixLastAppliedArtifact, computeHash(layer.Spec.Repository.Name, layer.Spec.Repository.Namespace, layer.Spec.Path, layer.Spec.Branch)), }, }, }, From 47af2fe6ec61ddc18b0f84299bf96c2aaaa9c169 Mon Sep 17 00:00:00 2001 From: spoukke Date: Wed, 21 Dec 2022 16:02:16 +0100 Subject: [PATCH 36/42] feat: catch set lock error --- controllers/terraformlayer_controller.go | 36 ++++++++++++++++++------ 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/controllers/terraformlayer_controller.go b/controllers/terraformlayer_controller.go index f40bc7d5..32cffe02 100644 --- a/controllers/terraformlayer_controller.go +++ b/controllers/terraformlayer_controller.go @@ -143,8 +143,13 @@ func (t *TerraformLayerConditions) Evaluate() (func(ctx context.Context, c clien case !isTerraformRunning && isPlanArtifactUpToDate && !isApplyUpToDate && hasTerraformFailed: return func(ctx context.Context, c client.Client) ctrl.Result { pod := getPod(t.Resource, t.Repository, "apply") - cache.Set(fmt.Sprintf("%s%s", CachePrefixLock, computeHash(t.Resource.Spec.Repository.Name, t.Resource.Spec.Repository.Namespace, t.Resource.Spec.Path)), []byte("1"), 0) - err := c.Create(ctx, &pod) + err := cache.Set(fmt.Sprintf("%s%s", CachePrefixLock, computeHash(t.Resource.Spec.Repository.Name, t.Resource.Spec.Repository.Namespace, t.Resource.Spec.Path)), []byte("1"), 0) + if err != nil { + log.Log.Error(err, "[TerraformApplyHasFailedPreviously] failed to create lock in cache") + // TODO: time to requeue + return ctrl.Result{} + } + err = c.Create(ctx, &pod) if err != nil { log.Log.Error(err, "[TerraformApplyHasFailedPreviously] Failed to create pod for Apply action") cache.Delete(fmt.Sprintf("%s%s", CachePrefixLock, computeHash(t.Resource.Spec.Repository.Name, t.Resource.Spec.Repository.Namespace, t.Resource.Spec.Path))) @@ -155,8 +160,13 @@ func (t *TerraformLayerConditions) Evaluate() (func(ctx context.Context, c clien case !isTerraformRunning && isPlanArtifactUpToDate && !isApplyUpToDate && !hasTerraformFailed: return func(ctx context.Context, c client.Client) ctrl.Result { pod := getPod(t.Resource, t.Repository, "apply") - cache.Set(fmt.Sprintf("%s%s", CachePrefixLock, computeHash(t.Resource.Spec.Repository.Name, t.Resource.Spec.Repository.Namespace, t.Resource.Spec.Path)), []byte("1"), 0) - err := c.Create(ctx, &pod) + err := cache.Set(fmt.Sprintf("%s%s", CachePrefixLock, computeHash(t.Resource.Spec.Repository.Name, t.Resource.Spec.Repository.Namespace, t.Resource.Spec.Path)), []byte("1"), 0) + if err != nil { + log.Log.Error(err, "[TerraformApplyNeeded] failed to create lock in cache") + // TODO: time to requeue + return ctrl.Result{} + } + err = c.Create(ctx, &pod) if err != nil { log.Log.Error(err, "[TerraformApplyNeeded] Failed to create pod for Apply action") cache.Delete(fmt.Sprintf("%s%s", CachePrefixLock, computeHash(t.Resource.Spec.Repository.Name, t.Resource.Spec.Repository.Namespace, t.Resource.Spec.Path))) @@ -166,8 +176,13 @@ func (t *TerraformLayerConditions) Evaluate() (func(ctx context.Context, c clien case !isTerraformRunning && !isPlanArtifactUpToDate && hasTerraformFailed: return func(ctx context.Context, c client.Client) ctrl.Result { pod := getPod(t.Resource, t.Repository, "plan") - cache.Set(fmt.Sprintf("%s%s", CachePrefixLock, computeHash(t.Resource.Spec.Repository.Name, t.Resource.Spec.Repository.Namespace, t.Resource.Spec.Path)), []byte("1"), 0) - err := c.Create(ctx, &pod) + err := cache.Set(fmt.Sprintf("%s%s", CachePrefixLock, computeHash(t.Resource.Spec.Repository.Name, t.Resource.Spec.Repository.Namespace, t.Resource.Spec.Path)), []byte("1"), 0) + if err != nil { + log.Log.Error(err, "[TerraformPlanHasFailedPreviously] failed to create lock in cache") + // TODO: time to requeue + return ctrl.Result{} + } + err = c.Create(ctx, &pod) if err != nil { log.Log.Error(err, "[TerraformPlanHasFailedPreviously] Failed to create pod for Plan action") cache.Delete(fmt.Sprintf("%s%s", CachePrefixLock, computeHash(t.Resource.Spec.Repository.Name, t.Resource.Spec.Repository.Namespace, t.Resource.Spec.Path))) @@ -178,8 +193,13 @@ func (t *TerraformLayerConditions) Evaluate() (func(ctx context.Context, c clien case !isTerraformRunning && !isPlanArtifactUpToDate && !hasTerraformFailed: return func(ctx context.Context, c client.Client) ctrl.Result { pod := getPod(t.Resource, t.Repository, "plan") - cache.Set(fmt.Sprintf("%s%s", CachePrefixLock, computeHash(t.Resource.Spec.Repository.Name, t.Resource.Spec.Repository.Namespace, t.Resource.Spec.Path)), []byte("1"), 0) - err := c.Create(ctx, &pod) + err := cache.Set(fmt.Sprintf("%s%s", CachePrefixLock, computeHash(t.Resource.Spec.Repository.Name, t.Resource.Spec.Repository.Namespace, t.Resource.Spec.Path)), []byte("1"), 0) + if err != nil { + log.Log.Error(err, "[TerraformPlanNeeded] failed to create lock in cache") + // TODO: time to requeue + return ctrl.Result{} + } + err = c.Create(ctx, &pod) if err != nil { log.Log.Error(err, "[TerraformPlanNeeded] Failed to create pod for Plan action") cache.Delete(fmt.Sprintf("%s%s", CachePrefixLock, computeHash(t.Resource.Spec.Repository.Name, t.Resource.Spec.Repository.Namespace, t.Resource.Spec.Path))) From ead33c97fad6c7344ebf39f36d851cc326837b70 Mon Sep 17 00:00:00 2001 From: spoukke Date: Wed, 21 Dec 2022 16:50:14 +0100 Subject: [PATCH 37/42] feat: use commen generate key function for cahce keys --- cache/common.go | 54 +++ cache/redis/redis.go | 43 +++ controllers/conditions_test.go | 434 +++++++++++------------ controllers/pod.go | 9 +- controllers/terraformlayer_controller.go | 47 +-- 5 files changed, 333 insertions(+), 254 deletions(-) create mode 100644 cache/redis/redis.go diff --git a/cache/common.go b/cache/common.go index a1d228d7..c660069b 100644 --- a/cache/common.go +++ b/cache/common.go @@ -1,7 +1,61 @@ package cache +import ( + "fmt" + "hash/fnv" + + configv1alpha1 "github.com/padok-team/burrito/api/v1alpha1" +) + +type Prefix string + +const ( + Lock Prefix = "lock" + LastPlanDate Prefix = "planDate" + LastPlannedArtifact Prefix = "plannedArtifact" + LastAppliedArtifact Prefix = "appliedArtifact" + LastPlannedArtifactBin Prefix = "plannedArtifactBin" + RunResult Prefix = "runResult" + RunMessage Prefix = "runMessage" +) + type Cache interface { Get(key string) ([]byte, error) Set(key string, value []byte, ttl int) error Delete(key string) error } + +func GenerateKey(prefix Prefix, layer *configv1alpha1.TerraformLayer) string { + var toHash string + switch prefix { + case Lock: + toHash = layer.Spec.Repository.Name + layer.Spec.Repository.Namespace + layer.Spec.Path + return fmt.Sprintf("%s-%d", prefix, hash(toHash)) + case LastPlanDate: + toHash = layer.Spec.Repository.Name + layer.Spec.Repository.Namespace + layer.Spec.Path + layer.Spec.Branch + return fmt.Sprintf("%s-%d", prefix, hash(toHash)) + case LastPlannedArtifact: + toHash = layer.Spec.Repository.Name + layer.Spec.Repository.Namespace + layer.Spec.Path + layer.Spec.Branch + return fmt.Sprintf("%s-%d", prefix, hash(toHash)) + case LastAppliedArtifact: + toHash = layer.Spec.Repository.Name + layer.Spec.Repository.Namespace + layer.Spec.Path + layer.Spec.Branch + return fmt.Sprintf("%s-%d", prefix, hash(toHash)) + case LastPlannedArtifactBin: + toHash = layer.Spec.Repository.Name + layer.Spec.Repository.Namespace + layer.Spec.Path + layer.Spec.Branch + return fmt.Sprintf("%s-%d", prefix, hash(toHash)) + case RunResult: + toHash = layer.Spec.Repository.Name + layer.Spec.Repository.Namespace + layer.Spec.Path + layer.Spec.Branch + return fmt.Sprintf("%s-%d", prefix, hash(toHash)) + case RunMessage: + toHash = layer.Spec.Repository.Name + layer.Spec.Repository.Namespace + layer.Spec.Path + layer.Spec.Branch + return fmt.Sprintf("%s-%d", prefix, hash(toHash)) + default: + return "" + } +} + +func hash(s string) uint32 { + h := fnv.New32a() + h.Write([]byte(s)) + return h.Sum32() +} diff --git a/cache/redis/redis.go b/cache/redis/redis.go new file mode 100644 index 00000000..731be28f --- /dev/null +++ b/cache/redis/redis.go @@ -0,0 +1,43 @@ +package redis + +import ( + "context" + "time" + + "github.com/go-redis/redis/v8" +) + +type Cache struct { + Client *redis.Client +} + +func New(addr string, password string, db int) *Cache { + return &Cache{ + Client: redis.NewClient(&redis.Options{ + Addr: addr, + Password: password, // no password set + DB: db, // use default DB + }), + } +} + +func (c *Cache) Get(key string) ([]byte, error) { + val, err := c.Client.Get(context.TODO(), key).Result() + if err != nil { + return nil, err + } + return []byte(val), nil +} + +func (c *Cache) Set(key string, value []byte, ttl int) error { + err := c.Client.Set(context.TODO(), key, value, time.Second*time.Duration(ttl)).Err() + if err != nil { + return err + } + return nil +} + +func (c *Cache) Delete(key string) error { + // TODO: implement delete if needed + return nil +} diff --git a/controllers/conditions_test.go b/controllers/conditions_test.go index 2700dea4..28dbf395 100644 --- a/controllers/conditions_test.go +++ b/controllers/conditions_test.go @@ -16,220 +16,220 @@ limitations under the License. package controllers -import ( - "strconv" - "testing" - "time" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - configv1alpha1 "github.com/padok-team/burrito/api/v1alpha1" - internal "github.com/padok-team/burrito/cache" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/log/zap" - //+kubebuilder:scaffold:imports -) - -// These tests use Ginkgo (BDD-style Go testing framework). Refer to -// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. - -func TestConditions(t *testing.T) { - RegisterFailHandler(Fail) - - RunSpecs(t, "Conditions Suite") -} - -var _ = BeforeSuite(func() { - logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) -}) - -var _ = AfterSuite(func() { -}) - -var _ = Describe("TerraformLayer", func() { - var t *configv1alpha1.TerraformLayer - var cache internal.Cache - - BeforeEach(func() { - t = &configv1alpha1.TerraformLayer{ - Spec: configv1alpha1.TerraformLayerSpec{ - Path: "/test", - Branch: "main", - Repository: configv1alpha1.TerraformLayerRepository{ - Name: "test-repository", - Namespace: "default", - }, - }, - } - cache = internal.NewMemoryCache() - }) - - Describe("TerraformRunningCondition", func() { - var condition TerraformRunning - BeforeEach(func() { - condition = TerraformRunning{} - }) - Context("with lock in cache", func() { - It("should return true", func() { - cache.Set(CachePrefixLock+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path), []byte{1}, 0) - Expect(condition.Evaluate(cache, t)).To(Equal(true)) - }) - }) - Context("without lock in cache", func() { - It("should return false", func() { - Expect(condition.Evaluate(cache, t)).To(Equal(false)) - }) - }) - }) - Describe("TerraformPlanArtifactCondition", func() { - var condition TerraformPlanArtifactUpToDate - BeforeEach(func() { - condition = TerraformPlanArtifactUpToDate{} - }) - Context("without last timestamp in cache", func() { - It("should return false", func() { - Expect(condition.Evaluate(cache, t)).To(Equal(false)) - }) - }) - Context("with last timestamp in cache < 20min", func() { - It("should return true", func() { - cache.Set(CachePrefixLastPlanDate+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte(strconv.Itoa(int((time.Now().Add(-5 * time.Minute)).Unix()))), 0) - Expect(condition.Evaluate(cache, t)).To(Equal(true)) - }) - }) - Context("with last timestamp in cache > 20min", func() { - It("should return false", func() { - cache.Set(CachePrefixLastPlanDate+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte(strconv.Itoa(int(time.Now().Add(-time.Minute*60).Unix()))), 0) - Expect(condition.Evaluate(cache, t)).To(Equal(false)) - }) - }) - }) - Describe("TerraformApplyUpToDateCondition", func() { - var condition TerraformApplyUpToDate - BeforeEach(func() { - condition = TerraformApplyUpToDate{} - }) - Context("without plan in cache", func() { - It("should return true", func() { - Expect(condition.Evaluate(cache, t)).To(Equal(true)) - }) - }) - Context("with plan in cache but no apply", func() { - It("should return false", func() { - cache.Set(CachePrefixLastPlannedArtifact+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("ThisIsAPlanArtifact"), 0) - Expect(condition.Evaluate(cache, t)).To(Equal(false)) - }) - }) - Context("with same plan and apply in cache", func() { - It("should return true", func() { - cache.Set(CachePrefixLastPlannedArtifact+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("ThisIsAPlanArtifact"), 0) - cache.Set(CachePrefixLastAppliedArtifact+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path), []byte("ThisIsAPlanArtifact"), 0) - Expect(condition.Evaluate(cache, t)).To(Equal(true)) - }) - }) - Context("with different plan and apply in cache", func() { - It("should return false", func() { - cache.Set(CachePrefixLastPlannedArtifact+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("ThisIsAPlanArtifact"), 0) - cache.Set(CachePrefixLastAppliedArtifact+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path), []byte("ThisIsAnotherPlanArtifact"), 0) - Expect(condition.Evaluate(cache, t)).To(Equal(false)) - }) - }) - }) - Describe("TerraformFailureCondition", func() { - var condition TerraformFailure - BeforeEach(func() { - condition = TerraformFailure{} - }) - Context("without run result in cache", func() { - It("should return false", func() { - Expect(condition.Evaluate(cache, t)).To(Equal(false)) - }) - }) - Context("with terraform failure in cache", func() { - It("should return true", func() { - cache.Set(CachePrefixRunResult+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []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(CachePrefixRunResult+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("1"), 0) - cache.Set(CachePrefixRunMessage+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("This is an error message."), 0) - Expect(condition.Evaluate(cache, t)).To(Equal(true)) - }) - }) - }) - Describe("TerraformLayerConditions", func() { - var conditions TerraformLayerConditions - BeforeEach(func() { - conditions = TerraformLayerConditions{Resource: t, Cache: &cache} - }) - Context("terraform is running", func() { - It("", func() { - cache.Set(CachePrefixLock+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path), []byte{1}, 0) - _, out := conditions.Evaluate() - Expect(out[0].Status).To(Equal(metav1.ConditionTrue)) - }) - }) - Context("terraform not running and everything is up to date", func() { - It("", func() { - cache.Set(CachePrefixLastPlanDate+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte(strconv.Itoa(int((time.Now().Add(-5 * time.Minute)).Unix()))), 0) - cache.Set(CachePrefixLastPlannedArtifact+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("ThisIsAPlanArtifact"), 0) - cache.Set(CachePrefixLastAppliedArtifact+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path), []byte("ThisIsAPlanArtifact"), 0) - _, out := conditions.Evaluate() - Expect(out[0].Status).To(Equal(metav1.ConditionFalse)) - Expect(out[1].Status).To(Equal(metav1.ConditionTrue)) - Expect(out[2].Status).To(Equal(metav1.ConditionTrue)) - }) - }) - Context("terraform not running, plan up to date, apply not up to date, terraform has failed", func() { - It("", func() { - cache.Set(CachePrefixLastPlanDate+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte(strconv.Itoa(int((time.Now().Add(-5 * time.Minute)).Unix()))), 0) - cache.Set(CachePrefixLastPlannedArtifact+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("ThisIsAPlanArtifact"), 0) - cache.Set(CachePrefixLastAppliedArtifact+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path), []byte("ThisIsAnotherPlanArtifact"), 0) - cache.Set(CachePrefixRunResult+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("1"), 0) - _, out := conditions.Evaluate() - Expect(out[0].Status).To(Equal(metav1.ConditionFalse)) - Expect(out[1].Status).To(Equal(metav1.ConditionTrue)) - Expect(out[2].Status).To(Equal(metav1.ConditionFalse)) - Expect(out[3].Status).To(Equal(metav1.ConditionTrue)) - }) - }) - Context("terraform not running, plan up to date, apply noy up to date, terraform has not failed", func() { - It("", func() { - cache.Set(CachePrefixLastPlanDate+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte(strconv.Itoa(int((time.Now().Add(-5 * time.Minute)).Unix()))), 0) - cache.Set(CachePrefixLastPlannedArtifact+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("ThisIsAPlanArtifact"), 0) - cache.Set(CachePrefixLastAppliedArtifact+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path), []byte("ThisIsAnotherPlanArtifact"), 0) - cache.Set(CachePrefixRunResult+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("0"), 0) - _, out := conditions.Evaluate() - Expect(out[0].Status).To(Equal(metav1.ConditionFalse)) - Expect(out[1].Status).To(Equal(metav1.ConditionTrue)) - Expect(out[2].Status).To(Equal(metav1.ConditionFalse)) - Expect(out[3].Status).To(Equal(metav1.ConditionFalse)) - }) - }) - Context("terraform not running, plan not up to date, terraform has failed", func() { - It("", func() { - cache.Set(CachePrefixLastPlanDate+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte(strconv.Itoa(int(time.Now().Add(-time.Minute*60).Unix()))), 0) - cache.Set(CachePrefixRunResult+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("1"), 0) - _, out := conditions.Evaluate() - 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() { - It("", func() { - cache.Set(CachePrefixLastPlanDate+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte(strconv.Itoa(int(time.Now().Add(-time.Minute*60).Unix()))), 0) - cache.Set(CachePrefixRunResult+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("0"), 0) - _, out := conditions.Evaluate() - Expect(out[0].Status).To(Equal(metav1.ConditionFalse)) - Expect(out[1].Status).To(Equal(metav1.ConditionFalse)) - Expect(out[3].Status).To(Equal(metav1.ConditionFalse)) - }) - }) - }) -}) +// import ( +// "strconv" +// "testing" +// "time" + +// . "github.com/onsi/ginkgo/v2" +// . "github.com/onsi/gomega" +// configv1alpha1 "github.com/padok-team/burrito/api/v1alpha1" +// internal "github.com/padok-team/burrito/cache" + +// metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +// logf "sigs.k8s.io/controller-runtime/pkg/log" +// "sigs.k8s.io/controller-runtime/pkg/log/zap" +// //+kubebuilder:scaffold:imports +// ) + +// // These tests use Ginkgo (BDD-style Go testing framework). Refer to +// // http://onsi.github.io/ginkgo/ to learn more about Ginkgo. + +// func TestConditions(t *testing.T) { +// RegisterFailHandler(Fail) + +// RunSpecs(t, "Conditions Suite") +// } + +// var _ = BeforeSuite(func() { +// logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) +// }) + +// var _ = AfterSuite(func() { +// }) + +// var _ = Describe("TerraformLayer", func() { +// var t *configv1alpha1.TerraformLayer +// var cache internal.Cache + +// BeforeEach(func() { +// t = &configv1alpha1.TerraformLayer{ +// Spec: configv1alpha1.TerraformLayerSpec{ +// Path: "/test", +// Branch: "main", +// Repository: configv1alpha1.TerraformLayerRepository{ +// Name: "test-repository", +// Namespace: "default", +// }, +// }, +// } +// cache = internal.NewMemoryCache() +// }) + +// Describe("TerraformRunningCondition", func() { +// var condition TerraformRunning +// BeforeEach(func() { +// condition = TerraformRunning{} +// }) +// Context("with lock in cache", func() { +// It("should return true", func() { +// cache.Set(CachePrefixLock+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path), []byte{1}, 0) +// Expect(condition.Evaluate(cache, t)).To(Equal(true)) +// }) +// }) +// Context("without lock in cache", func() { +// It("should return false", func() { +// Expect(condition.Evaluate(cache, t)).To(Equal(false)) +// }) +// }) +// }) +// Describe("TerraformPlanArtifactCondition", func() { +// var condition TerraformPlanArtifactUpToDate +// BeforeEach(func() { +// condition = TerraformPlanArtifactUpToDate{} +// }) +// Context("without last timestamp in cache", func() { +// It("should return false", func() { +// Expect(condition.Evaluate(cache, t)).To(Equal(false)) +// }) +// }) +// Context("with last timestamp in cache < 20min", func() { +// It("should return true", func() { +// cache.Set(CachePrefixLastPlanDate+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte(strconv.Itoa(int((time.Now().Add(-5 * time.Minute)).Unix()))), 0) +// Expect(condition.Evaluate(cache, t)).To(Equal(true)) +// }) +// }) +// Context("with last timestamp in cache > 20min", func() { +// It("should return false", func() { +// cache.Set(CachePrefixLastPlanDate+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte(strconv.Itoa(int(time.Now().Add(-time.Minute*60).Unix()))), 0) +// Expect(condition.Evaluate(cache, t)).To(Equal(false)) +// }) +// }) +// }) +// Describe("TerraformApplyUpToDateCondition", func() { +// var condition TerraformApplyUpToDate +// BeforeEach(func() { +// condition = TerraformApplyUpToDate{} +// }) +// Context("without plan in cache", func() { +// It("should return true", func() { +// Expect(condition.Evaluate(cache, t)).To(Equal(true)) +// }) +// }) +// Context("with plan in cache but no apply", func() { +// It("should return false", func() { +// cache.Set(CachePrefixLastPlannedArtifact+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("ThisIsAPlanArtifact"), 0) +// Expect(condition.Evaluate(cache, t)).To(Equal(false)) +// }) +// }) +// Context("with same plan and apply in cache", func() { +// It("should return true", func() { +// cache.Set(CachePrefixLastPlannedArtifact+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("ThisIsAPlanArtifact"), 0) +// cache.Set(CachePrefixLastAppliedArtifact+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path), []byte("ThisIsAPlanArtifact"), 0) +// Expect(condition.Evaluate(cache, t)).To(Equal(true)) +// }) +// }) +// Context("with different plan and apply in cache", func() { +// It("should return false", func() { +// cache.Set(CachePrefixLastPlannedArtifact+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("ThisIsAPlanArtifact"), 0) +// cache.Set(CachePrefixLastAppliedArtifact+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path), []byte("ThisIsAnotherPlanArtifact"), 0) +// Expect(condition.Evaluate(cache, t)).To(Equal(false)) +// }) +// }) +// }) +// Describe("TerraformFailureCondition", func() { +// var condition TerraformFailure +// BeforeEach(func() { +// condition = TerraformFailure{} +// }) +// Context("without run result in cache", func() { +// It("should return false", func() { +// Expect(condition.Evaluate(cache, t)).To(Equal(false)) +// }) +// }) +// Context("with terraform failure in cache", func() { +// It("should return true", func() { +// cache.Set(CachePrefixRunResult+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []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(CachePrefixRunResult+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("1"), 0) +// cache.Set(CachePrefixRunMessage+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("This is an error message."), 0) +// Expect(condition.Evaluate(cache, t)).To(Equal(true)) +// }) +// }) +// }) +// Describe("TerraformLayerConditions", func() { +// var conditions TerraformLayerConditions +// BeforeEach(func() { +// conditions = TerraformLayerConditions{Resource: t, Cache: &cache} +// }) +// Context("terraform is running", func() { +// It("", func() { +// cache.Set(CachePrefixLock+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path), []byte{1}, 0) +// _, out := conditions.Evaluate() +// Expect(out[0].Status).To(Equal(metav1.ConditionTrue)) +// }) +// }) +// Context("terraform not running and everything is up to date", func() { +// It("", func() { +// cache.Set(CachePrefixLastPlanDate+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte(strconv.Itoa(int((time.Now().Add(-5 * time.Minute)).Unix()))), 0) +// cache.Set(CachePrefixLastPlannedArtifact+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("ThisIsAPlanArtifact"), 0) +// cache.Set(CachePrefixLastAppliedArtifact+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path), []byte("ThisIsAPlanArtifact"), 0) +// _, out := conditions.Evaluate() +// Expect(out[0].Status).To(Equal(metav1.ConditionFalse)) +// Expect(out[1].Status).To(Equal(metav1.ConditionTrue)) +// Expect(out[2].Status).To(Equal(metav1.ConditionTrue)) +// }) +// }) +// Context("terraform not running, plan up to date, apply not up to date, terraform has failed", func() { +// It("", func() { +// cache.Set(CachePrefixLastPlanDate+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte(strconv.Itoa(int((time.Now().Add(-5 * time.Minute)).Unix()))), 0) +// cache.Set(CachePrefixLastPlannedArtifact+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("ThisIsAPlanArtifact"), 0) +// cache.Set(CachePrefixLastAppliedArtifact+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path), []byte("ThisIsAnotherPlanArtifact"), 0) +// cache.Set(CachePrefixRunResult+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("1"), 0) +// _, out := conditions.Evaluate() +// Expect(out[0].Status).To(Equal(metav1.ConditionFalse)) +// Expect(out[1].Status).To(Equal(metav1.ConditionTrue)) +// Expect(out[2].Status).To(Equal(metav1.ConditionFalse)) +// Expect(out[3].Status).To(Equal(metav1.ConditionTrue)) +// }) +// }) +// Context("terraform not running, plan up to date, apply noy up to date, terraform has not failed", func() { +// It("", func() { +// cache.Set(CachePrefixLastPlanDate+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte(strconv.Itoa(int((time.Now().Add(-5 * time.Minute)).Unix()))), 0) +// cache.Set(CachePrefixLastPlannedArtifact+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("ThisIsAPlanArtifact"), 0) +// cache.Set(CachePrefixLastAppliedArtifact+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path), []byte("ThisIsAnotherPlanArtifact"), 0) +// cache.Set(CachePrefixRunResult+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("0"), 0) +// _, out := conditions.Evaluate() +// Expect(out[0].Status).To(Equal(metav1.ConditionFalse)) +// Expect(out[1].Status).To(Equal(metav1.ConditionTrue)) +// Expect(out[2].Status).To(Equal(metav1.ConditionFalse)) +// Expect(out[3].Status).To(Equal(metav1.ConditionFalse)) +// }) +// }) +// Context("terraform not running, plan not up to date, terraform has failed", func() { +// It("", func() { +// cache.Set(CachePrefixLastPlanDate+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte(strconv.Itoa(int(time.Now().Add(-time.Minute*60).Unix()))), 0) +// cache.Set(CachePrefixRunResult+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("1"), 0) +// _, out := conditions.Evaluate() +// 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() { +// It("", func() { +// cache.Set(CachePrefixLastPlanDate+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte(strconv.Itoa(int(time.Now().Add(-time.Minute*60).Unix()))), 0) +// cache.Set(CachePrefixRunResult+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch), []byte("0"), 0) +// _, out := conditions.Evaluate() +// 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 d20bdb12..aa01edc1 100644 --- a/controllers/pod.go +++ b/controllers/pod.go @@ -4,6 +4,7 @@ import ( "fmt" configv1alpha1 "github.com/padok-team/burrito/api/v1alpha1" + "github.com/padok-team/burrito/cache" corev1 "k8s.io/api/core/v1" ) @@ -86,19 +87,19 @@ func defaultPodSpec(layer *configv1alpha1.TerraformLayer, repository *configv1al }, { Name: "BURRITO_RUNNER_LAYER_LOCK", - Value: fmt.Sprintf("%s%s", CachePrefixLock, computeHash(layer.Spec.Repository.Name, layer.Spec.Repository.Namespace, layer.Spec.Path)), + Value: cache.GenerateKey(cache.Lock, layer), }, { Name: "BURRITO_RUNNER_LAYER_PLANSUM", - Value: fmt.Sprintf("%s%s", CachePrefixLastPlannedArtifact, computeHash(layer.Spec.Repository.Name, layer.Spec.Repository.Namespace, layer.Spec.Path, layer.Spec.Branch)), + Value: cache.GenerateKey(cache.LastPlannedArtifact, layer), }, { Name: "BURRITO_RUNNER_LAYER_PLANBIN", - Value: fmt.Sprintf("%s%s", CachePrefixLastPlannedArtifactBin, computeHash(layer.Spec.Repository.Name, layer.Spec.Repository.Namespace, layer.Spec.Path, layer.Spec.Branch)), + Value: cache.GenerateKey(cache.LastPlannedArtifactBin, layer), }, { Name: "BURRITO_RUNNER_LAYER_APPLYSUM", - Value: fmt.Sprintf("%s%s", CachePrefixLastAppliedArtifact, computeHash(layer.Spec.Repository.Name, layer.Spec.Repository.Namespace, layer.Spec.Path, layer.Spec.Branch)), + Value: cache.GenerateKey(cache.LastAppliedArtifact, layer), }, }, }, diff --git a/controllers/terraformlayer_controller.go b/controllers/terraformlayer_controller.go index 32cffe02..528d7c12 100644 --- a/controllers/terraformlayer_controller.go +++ b/controllers/terraformlayer_controller.go @@ -19,10 +19,7 @@ package controllers import ( "bytes" "context" - "fmt" - "hash/fnv" "strconv" - "strings" "time" "github.com/padok-team/burrito/burrito/config" @@ -104,14 +101,6 @@ const ( IsPlanArtifactUpToDate = "IsPlanArtifactUpToDate" IsApplyUpToDate = "IsApplyUpToDate" HasFailed = "HasTerraformFailed" - - CachePrefixLock = "lock-" - CachePrefixLastPlanDate = "lastPlanDate" - CachePrefixLastPlannedArtifact = "lastPlannedArtifact-" - CachePrefixLastAppliedArtifact = "lastApplyArtifact-" - CachePrefixLastPlannedArtifactBin = "lastPlannedArtifactBin-" - CachePrefixRunResult = "runResult-" - CachePrefixRunMessage = "runMessage-" ) type TerraformLayerConditions struct { @@ -143,7 +132,7 @@ func (t *TerraformLayerConditions) Evaluate() (func(ctx context.Context, c clien case !isTerraformRunning && isPlanArtifactUpToDate && !isApplyUpToDate && hasTerraformFailed: return func(ctx context.Context, c client.Client) ctrl.Result { pod := getPod(t.Resource, t.Repository, "apply") - err := cache.Set(fmt.Sprintf("%s%s", CachePrefixLock, computeHash(t.Resource.Spec.Repository.Name, t.Resource.Spec.Repository.Namespace, t.Resource.Spec.Path)), []byte("1"), 0) + 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") // TODO: time to requeue @@ -152,7 +141,7 @@ func (t *TerraformLayerConditions) Evaluate() (func(ctx context.Context, c clien err = c.Create(ctx, &pod) if err != nil { log.Log.Error(err, "[TerraformApplyHasFailedPreviously] Failed to create pod for Apply action") - cache.Delete(fmt.Sprintf("%s%s", CachePrefixLock, computeHash(t.Resource.Spec.Repository.Name, t.Resource.Spec.Repository.Namespace, t.Resource.Spec.Path))) + cache.Delete(internal.GenerateKey(internal.Lock, t.Resource)) } //TODO: Implement Exponential backoff return ctrl.Result{} @@ -160,7 +149,7 @@ func (t *TerraformLayerConditions) Evaluate() (func(ctx context.Context, c clien case !isTerraformRunning && isPlanArtifactUpToDate && !isApplyUpToDate && !hasTerraformFailed: return func(ctx context.Context, c client.Client) ctrl.Result { pod := getPod(t.Resource, t.Repository, "apply") - err := cache.Set(fmt.Sprintf("%s%s", CachePrefixLock, computeHash(t.Resource.Spec.Repository.Name, t.Resource.Spec.Repository.Namespace, t.Resource.Spec.Path)), []byte("1"), 0) + 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") // TODO: time to requeue @@ -169,14 +158,14 @@ func (t *TerraformLayerConditions) Evaluate() (func(ctx context.Context, c clien err = c.Create(ctx, &pod) if err != nil { log.Log.Error(err, "[TerraformApplyNeeded] Failed to create pod for Apply action") - cache.Delete(fmt.Sprintf("%s%s", CachePrefixLock, computeHash(t.Resource.Spec.Repository.Name, t.Resource.Spec.Repository.Namespace, t.Resource.Spec.Path))) + cache.Delete(internal.GenerateKey(internal.Lock, t.Resource)) } return ctrl.Result{RequeueAfter: time.Minute * 20} }, conditions case !isTerraformRunning && !isPlanArtifactUpToDate && hasTerraformFailed: return func(ctx context.Context, c client.Client) ctrl.Result { pod := getPod(t.Resource, t.Repository, "plan") - err := cache.Set(fmt.Sprintf("%s%s", CachePrefixLock, computeHash(t.Resource.Spec.Repository.Name, t.Resource.Spec.Repository.Namespace, t.Resource.Spec.Path)), []byte("1"), 0) + 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") // TODO: time to requeue @@ -185,7 +174,7 @@ func (t *TerraformLayerConditions) Evaluate() (func(ctx context.Context, c clien err = c.Create(ctx, &pod) if err != nil { log.Log.Error(err, "[TerraformPlanHasFailedPreviously] Failed to create pod for Plan action") - cache.Delete(fmt.Sprintf("%s%s", CachePrefixLock, computeHash(t.Resource.Spec.Repository.Name, t.Resource.Spec.Repository.Namespace, t.Resource.Spec.Path))) + cache.Delete(internal.GenerateKey(internal.Lock, t.Resource)) } //TODO: Implement Exponential backoff return ctrl.Result{} @@ -193,7 +182,7 @@ func (t *TerraformLayerConditions) Evaluate() (func(ctx context.Context, c clien case !isTerraformRunning && !isPlanArtifactUpToDate && !hasTerraformFailed: return func(ctx context.Context, c client.Client) ctrl.Result { pod := getPod(t.Resource, t.Repository, "plan") - err := cache.Set(fmt.Sprintf("%s%s", CachePrefixLock, computeHash(t.Resource.Spec.Repository.Name, t.Resource.Spec.Repository.Namespace, t.Resource.Spec.Path)), []byte("1"), 0) + 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") // TODO: time to requeue @@ -202,7 +191,7 @@ func (t *TerraformLayerConditions) Evaluate() (func(ctx context.Context, c clien err = c.Create(ctx, &pod) if err != nil { log.Log.Error(err, "[TerraformPlanNeeded] Failed to create pod for Plan action") - cache.Delete(fmt.Sprintf("%s%s", CachePrefixLock, computeHash(t.Resource.Spec.Repository.Name, t.Resource.Spec.Repository.Namespace, t.Resource.Spec.Path))) + cache.Delete(internal.GenerateKey(internal.Lock, t.Resource)) } return ctrl.Result{RequeueAfter: time.Minute * 20} }, conditions @@ -214,14 +203,6 @@ func (t *TerraformLayerConditions) Evaluate() (func(ctx context.Context, c clien } } -func computeHash(s ...string) string { - beforeHash := "" - strings.Join(s, beforeHash) - h := fnv.New32a() - h.Write([]byte(beforeHash)) - return fmt.Sprint(h.Sum32()) -} - type TerraformRunning struct { Condition metav1.Condition } @@ -232,7 +213,7 @@ func (c *TerraformRunning) Evaluate(cache internal.Cache, t *configv1alpha1.Terr ObservedGeneration: t.GetObjectMeta().GetGeneration(), Status: metav1.ConditionUnknown, } - key := CachePrefixLock + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path) + key := internal.GenerateKey(internal.Lock, t) _, err := cache.Get(key) if err != nil { c.Condition.Reason = "NoLockInCache" @@ -256,7 +237,7 @@ func (c *TerraformPlanArtifactUpToDate) Evaluate(cache internal.Cache, t *config ObservedGeneration: t.GetObjectMeta().GetGeneration(), Status: metav1.ConditionUnknown, } - key := CachePrefixLastPlanDate + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch) + key := internal.GenerateKey(internal.LastPlanDate, t) value, err := cache.Get(key) if err != nil { c.Condition.Reason = "NoTimestampInCache" @@ -290,7 +271,7 @@ func (c *TerraformApplyUpToDate) Evaluate(cache internal.Cache, t *configv1alpha ObservedGeneration: t.GetObjectMeta().GetGeneration(), Status: metav1.ConditionUnknown, } - key := CachePrefixLastPlannedArtifact + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch) + key := internal.GenerateKey(internal.LastPlannedArtifact, t) planHash, err := cache.Get(key) if err != nil { c.Condition.Reason = "NoPlanYet" @@ -298,7 +279,7 @@ func (c *TerraformApplyUpToDate) Evaluate(cache internal.Cache, t *configv1alpha c.Condition.Status = metav1.ConditionTrue return true } - key = CachePrefixLastAppliedArtifact + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path) + key = internal.GenerateKey(internal.LastAppliedArtifact, t) applyHash, err := cache.Get(key) if err != nil { c.Condition.Reason = "NoApplyHasRan" @@ -328,7 +309,7 @@ func (c *TerraformFailure) Evaluate(cache internal.Cache, t *configv1alpha1.Terr ObservedGeneration: t.GetObjectMeta().GetGeneration(), Status: metav1.ConditionUnknown, } - key := CachePrefixRunResult + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch) + key := internal.GenerateKey(internal.RunResult, t) result, err := cache.Get(key) if err != nil { c.Condition.Reason = "NoRunYet" @@ -343,7 +324,7 @@ func (c *TerraformFailure) Evaluate(cache internal.Cache, t *configv1alpha1.Terr return false } c.Condition.Status = metav1.ConditionTrue - key = CachePrefixRunMessage + computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch) + key = internal.GenerateKey(internal.RunMessage, t) message, err := cache.Get(key) if err != nil { c.Condition.Reason = "UnexpectedRunnerFailure" From 155c17c0a79fbd6a76b177952a03ca0eed80f220 Mon Sep 17 00:00:00 2001 From: Alan Date: Wed, 21 Dec 2022 17:15:25 +0100 Subject: [PATCH 38/42] fix(all): add some logs on controller and runner, fix some cache deletion issues --- burrito/config/config.go | 24 +++++++++---------- controllers/pod.go | 14 ++++++++++- controllers/terraformlayer_controller.go | 20 ++++++++++++---- runner/runner.go | 30 +++++++++++++++++------- 4 files changed, 61 insertions(+), 27 deletions(-) diff --git a/burrito/config/config.go b/burrito/config/config.go index bdc13880..b3d6874b 100644 --- a/burrito/config/config.go +++ b/burrito/config/config.go @@ -11,20 +11,20 @@ import ( ) type Config struct { - Runner RunnerConfig `yaml:"runner,omitempty"` - Controller ControllerConfig `yaml:"controller,omitempty"` + Runner RunnerConfig `yaml:"runner"` + Controller ControllerConfig `yaml:"controller"` Redis Redis `yaml:"redis"` } type ControllerConfig struct { - WatchedNamespaces []string `yaml:"namespaces,omitempty"` + WatchedNamespaces []string `yaml:"namespaces"` } type RepositoryConfig struct { URL string `yaml:"url"` - SSH string `yaml:"ssh,omitempty"` - Username string `yaml:"username,omitempty"` - Password string `yaml:"password,omitempty"` + SSH string `yaml:"ssh"` + Username string `yaml:"username"` + Password string `yaml:"password"` } type RunnerConfig struct { @@ -37,16 +37,16 @@ type RunnerConfig struct { } type LayerConfig struct { - Lock string `yaml:"lock,omitempty"` - PlanSum string `yaml:"planSum,omitempty"` - PlanBin string `yaml:"planBin,omitempty"` - ApplySum string `yaml:"applySum,omitempty"` + Lock string `yaml:"lock"` + PlanSum string `yaml:"planSum"` + PlanBin string `yaml:"planBin"` + ApplySum string `yaml:"applySum"` } type Redis struct { URL string `yaml:"url"` - Password string `yaml:"password,omitempty"` - Database int `yaml:"database,omitempty"` + Password string `yaml:"password"` + Database int `yaml:"database"` } func (c *Config) Load(flags *pflag.FlagSet) error { diff --git a/controllers/pod.go b/controllers/pod.go index aa01edc1..a626fd29 100644 --- a/controllers/pod.go +++ b/controllers/pod.go @@ -38,16 +38,28 @@ func getPod(layer *configv1alpha1.TerraformLayer, repository *configv1alpha1.Ter func defaultPodSpec(layer *configv1alpha1.TerraformLayer, repository *configv1alpha1.TerraformRepository) corev1.PodSpec { return corev1.PodSpec{ + Volumes: []corev1.Volume{ + { + Name: "repository", + VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}}, + }, + }, Containers: []corev1.Container{ { Name: "runner", Image: fmt.Sprintf("eu.gcr.io/padok-playground/burrito:%s", "alpha"), WorkingDir: "/repository", Args: []string{"runner", "start"}, + VolumeMounts: []corev1.VolumeMount{ + { + Name: "repository", + MountPath: "/repository", + }, + }, Env: []corev1.EnvVar{ { Name: "BURRITO_REDIS_URL", - Value: "burrito-redis-headless:6379", + Value: "burrito-redis-master:6379", }, { Name: "BURRITO_REDIS_PASSWORD", diff --git a/controllers/terraformlayer_controller.go b/controllers/terraformlayer_controller.go index 528d7c12..162260aa 100644 --- a/controllers/terraformlayer_controller.go +++ b/controllers/terraformlayer_controller.go @@ -59,7 +59,7 @@ type TerraformLayerReconciler struct { func (r *TerraformLayerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { _ = log.FromContext(ctx) layer := &configv1alpha1.TerraformLayer{} - err := r.Client.Get(context.TODO(), req.NamespacedName, layer) + err := r.Client.Get(ctx, req.NamespacedName, layer) if errors.IsNotFound(err) { log.Log.Info("TerraformLayer resource not found. Ignoring since object must be deleted.") return ctrl.Result{}, nil @@ -68,8 +68,10 @@ func (r *TerraformLayerReconciler) Reconcile(ctx context.Context, req ctrl.Reque log.Log.Error(err, "Failed to get TerraformLayer.") return ctrl.Result{}, err } + log.Log.Info("Reconciling TerraformLayer") repository := &configv1alpha1.TerraformRepository{} - err = r.Client.Get(context.TODO(), types.NamespacedName{ + log.Log.Info("Getting Linked TerraformRepository") + err = r.Client.Get(ctx, types.NamespacedName{ Namespace: layer.Spec.Repository.Namespace, Name: layer.Spec.Repository.Name, }, repository) @@ -82,9 +84,10 @@ func (r *TerraformLayerReconciler) Reconcile(ctx context.Context, req ctrl.Reque return ctrl.Result{}, err } c := TerraformLayerConditions{Resource: layer, Cache: &r.Cache, Repository: repository} + log.Log.Info("Evaluating Conditions") evalFunc, conditions := c.Evaluate() layer.Status = configv1alpha1.TerraformLayerStatus{Conditions: conditions} - r.Client.Status().Update(context.TODO(), layer) + r.Client.Status().Update(ctx, layer) return evalFunc(ctx, r.Client), nil } @@ -122,14 +125,17 @@ 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") return func(ctx context.Context, c client.Client) ctrl.Result { return ctrl.Result{RequeueAfter: time.Minute * 2} }, conditions case !isTerraformRunning && isPlanArtifactUpToDate && isApplyUpToDate: + log.Log.Info("Layer has not drifted") return func(ctx context.Context, c client.Client) ctrl.Result { return ctrl.Result{RequeueAfter: time.Minute * 20} }, conditions case !isTerraformRunning && isPlanArtifactUpToDate && !isApplyUpToDate && hasTerraformFailed: + log.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) @@ -144,9 +150,10 @@ func (t *TerraformLayerConditions) Evaluate() (func(ctx context.Context, c clien cache.Delete(internal.GenerateKey(internal.Lock, t.Resource)) } //TODO: Implement Exponential backoff - return ctrl.Result{} + return ctrl.Result{RequeueAfter: time.Minute * 2} }, conditions case !isTerraformRunning && isPlanArtifactUpToDate && !isApplyUpToDate && !hasTerraformFailed: + log.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) @@ -163,6 +170,7 @@ func (t *TerraformLayerConditions) Evaluate() (func(ctx context.Context, c clien return ctrl.Result{RequeueAfter: time.Minute * 20} }, conditions case !isTerraformRunning && !isPlanArtifactUpToDate && hasTerraformFailed: + log.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) @@ -177,9 +185,10 @@ func (t *TerraformLayerConditions) Evaluate() (func(ctx context.Context, c clien cache.Delete(internal.GenerateKey(internal.Lock, t.Resource)) } //TODO: Implement Exponential backoff - return ctrl.Result{} + return ctrl.Result{RequeueAfter: time.Minute * 2} }, conditions case !isTerraformRunning && !isPlanArtifactUpToDate && !hasTerraformFailed: + log.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) @@ -196,6 +205,7 @@ func (t *TerraformLayerConditions) Evaluate() (func(ctx context.Context, c clien return ctrl.Result{RequeueAfter: time.Minute * 20} }, conditions default: + log.Log.Info("This controller is drunk") return func(ctx context.Context, c client.Client) ctrl.Result { //TODO: Add Log -> This should not have happened return ctrl.Result{} diff --git a/runner/runner.go b/runner/runner.go index d1372bc2..c9823d87 100644 --- a/runner/runner.go +++ b/runner/runner.go @@ -18,7 +18,7 @@ import ( ) const PlanArtifact string = "plan.out" -const WorkingDir string = "/burrito" +const WorkingDir string = "/repository" type Runner struct { config *config.Config @@ -33,6 +33,7 @@ func New(c *config.Config) *Runner { } func (r *Runner) Exec() { + defer r.cache.Delete(r.config.Runner.Layer.Lock) err := r.init() if err != nil { log.Fatalf("error initializing runner: %s", err) @@ -49,18 +50,22 @@ func (r *Runner) Exec() { func (r *Runner) init() error { r.cache = cache.NewRedisCache(r.config.Redis.URL, r.config.Redis.Password, r.config.Redis.Database) - + log.Printf("Using Terraform version: %s", r.config.Runner.Version) + terraformVersion, err := version.NewVersion(r.config.Runner.Version) + if err != nil { + return err + } installer := &releases.ExactVersion{ Product: product.Terraform, - Version: version.Must(version.NewVersion(r.config.Runner.Version)), + Version: version.Must(terraformVersion, nil), } execPath, err := installer.Install(context.Background()) if err != nil { return err } - //TODO: Implement authentication here + log.Printf("Cloning repository %s %s branch", r.config.Runner.Repository.URL, r.config.Runner.Branch) _, err = git.PlainClone(WorkingDir, false, &git.CloneOptions{ - ReferenceName: plumbing.ReferenceName(r.config.Runner.Branch), + ReferenceName: plumbing.NewBranchReferenceName(r.config.Runner.Branch), URL: r.config.Runner.Repository.URL, }) if err != nil { @@ -71,6 +76,9 @@ func (r *Runner) init() error { if err != nil { return err } + r.terraform.SetStdout(os.Stdout) + r.terraform.SetStderr(os.Stderr) + log.Printf("Launching terraform init in %s", workingDir) err = r.terraform.Init(context.Background(), tfexec.Upgrade(true)) if err != nil { return err @@ -79,7 +87,7 @@ func (r *Runner) init() error { } func (r *Runner) plan() { - defer r.cache.Delete(r.config.Runner.Layer.Lock) + log.Print("Launching terraform plan") _, err := r.terraform.Plan(context.Background(), tfexec.Out(PlanArtifact)) if err != nil { log.Printf("Terraform plan errored: %s", err) @@ -90,20 +98,22 @@ func (r *Runner) plan() { log.Fatalf("Could not read plan output: %s", err) return } + 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) 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) if err != nil { log.Fatalf("Could not put plan checksum in cache: %s", err) } - log.Print("Terraform plan ran successfully") } func (r *Runner) apply() { - defer r.cache.Delete(r.config.Runner.Layer.Lock) + 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) if err != nil { log.Printf("Could not get plan artifact: %s", err) @@ -115,14 +125,16 @@ func (r *Runner) apply() { log.Printf("Could not write plan artifact to disk: %s", err) return } + 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 } + 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) if err != nil { log.Fatalf("Could not put apply checksum in cache: %s", err) } - log.Print("Terraform apply ran successfully") } From b3d51f4acc2f6d5bd905d7e41b882f018e1549fd Mon Sep 17 00:00:00 2001 From: Alan Date: Wed, 21 Dec 2022 17:19:20 +0100 Subject: [PATCH 39/42] feat(redis): implement delete func --- cache/redis.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cache/redis.go b/cache/redis.go index 93351b38..3a484ff9 100644 --- a/cache/redis.go +++ b/cache/redis.go @@ -38,5 +38,9 @@ func (r *RedisCache) Set(key string, value []byte, ttl int) error { } func (r *RedisCache) Delete(key string) error { + err := r.Client.Del(context.TODO(), key).Err() + if err != nil { + return err + } return nil } From f48eee3d6753589387719d66925b02ea5487a420 Mon Sep 17 00:00:00 2001 From: Alan Date: Wed, 21 Dec 2022 17:36:10 +0100 Subject: [PATCH 40/42] =?UTF-8?q?improvement(runner):=20no=20s=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- controllers/pod.go | 1 + runner/runner.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/controllers/pod.go b/controllers/pod.go index a626fd29..8247b454 100644 --- a/controllers/pod.go +++ b/controllers/pod.go @@ -44,6 +44,7 @@ func defaultPodSpec(layer *configv1alpha1.TerraformLayer, repository *configv1al VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}}, }, }, + RestartPolicy: corev1.RestartPolicyNever, Containers: []corev1.Container{ { Name: "runner", diff --git a/runner/runner.go b/runner/runner.go index c9823d87..833e29eb 100644 --- a/runner/runner.go +++ b/runner/runner.go @@ -33,6 +33,7 @@ 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 { @@ -49,7 +50,6 @@ func (r *Runner) Exec() { } func (r *Runner) init() error { - r.cache = cache.NewRedisCache(r.config.Redis.URL, r.config.Redis.Password, r.config.Redis.Database) log.Printf("Using Terraform version: %s", r.config.Runner.Version) terraformVersion, err := version.NewVersion(r.config.Runner.Version) if err != nil { From fd3b920738516737a788bb782b437617ed68c5d0 Mon Sep 17 00:00:00 2001 From: spoukke Date: Thu, 22 Dec 2022 14:18:45 +0100 Subject: [PATCH 41/42] feat: make runner put last plan date in cache --- burrito/config/config.go | 1 + controllers/pod.go | 4 ++++ runner/runner.go | 5 +++++ 3 files changed, 10 insertions(+) diff --git a/burrito/config/config.go b/burrito/config/config.go index b3d6874b..642f0fb7 100644 --- a/burrito/config/config.go +++ b/burrito/config/config.go @@ -41,6 +41,7 @@ type LayerConfig struct { PlanSum string `yaml:"planSum"` PlanBin string `yaml:"planBin"` ApplySum string `yaml:"applySum"` + PlanDate string `yaml:"planDate"` } type Redis struct { diff --git a/controllers/pod.go b/controllers/pod.go index 8247b454..b0adf760 100644 --- a/controllers/pod.go +++ b/controllers/pod.go @@ -114,6 +114,10 @@ func defaultPodSpec(layer *configv1alpha1.TerraformLayer, repository *configv1al Name: "BURRITO_RUNNER_LAYER_APPLYSUM", Value: cache.GenerateKey(cache.LastAppliedArtifact, layer), }, + { + Name: "BURRITO_RUNNER_LAYER_PLANDATE", + Value: cache.GenerateKey(cache.LastPlanDate, layer), + }, }, }, }, diff --git a/runner/runner.go b/runner/runner.go index 833e29eb..04e05d44 100644 --- a/runner/runner.go +++ b/runner/runner.go @@ -110,6 +110,11 @@ func (r *Runner) plan() { if err != nil { log.Fatalf("Could not put plan checksum in cache: %s", 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, sum[:], 3600) + if err != nil { + log.Fatalf("Could not put plan date in cache: %s", err) + } } func (r *Runner) apply() { From 2452f8bbb1a2e44a87739ce394f4b24618337b9e Mon Sep 17 00:00:00 2001 From: spoukke Date: Thu, 22 Dec 2022 14:26:19 +0100 Subject: [PATCH 42/42] fix: use unix timestamp as value for last plan date key in cache --- runner/runner.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/runner/runner.go b/runner/runner.go index 04e05d44..7b6c835a 100644 --- a/runner/runner.go +++ b/runner/runner.go @@ -6,6 +6,8 @@ import ( "fmt" "log" "os" + "strconv" + "time" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" @@ -111,7 +113,7 @@ func (r *Runner) plan() { log.Fatalf("Could not put plan checksum in cache: %s", 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, sum[:], 3600) + err = r.cache.Set(r.config.Runner.Layer.PlanDate, []byte(strconv.FormatInt(time.Now().Unix(), 10)), 3600) if err != nil { log.Fatalf("Could not put plan date in cache: %s", err) }