diff --git a/.github/actions/deploy-klt-on-cluster/action.yml b/.github/actions/deploy-klt-on-cluster/action.yml index 9d4cee6963..9b03aea25f 100644 --- a/.github/actions/deploy-klt-on-cluster/action.yml +++ b/.github/actions/deploy-klt-on-cluster/action.yml @@ -39,7 +39,7 @@ runs: path: ~/download/artifacts - name: "Create single kind Cluster" - uses: helm/kind-action@v1.7.0 + uses: helm/kind-action@v1.8.0 with: cluster_name: ${{ inputs.cluster-name }} version: ${{ inputs.kind-version }} diff --git a/.github/workflows/validate-helm-chart.yml b/.github/workflows/validate-helm-chart.yml index 2edce0b758..1140e3d95c 100644 --- a/.github/workflows/validate-helm-chart.yml +++ b/.github/workflows/validate-helm-chart.yml @@ -20,7 +20,7 @@ jobs: uses: actions/checkout@v3 - name: Set up Node - uses: actions/setup-node@v3.6.0 + uses: actions/setup-node@v3.7.0 with: node-version: 16 diff --git a/README.md b/README.md index f597afbe4a..2a91d3f105 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Status of the different features: K8s Custom Metrics: expose your Observability platform via the [Custom Metric API](https://github.com/kubernetes/design-proposals-archive/blob/main/instrumentation/custom-metrics-api.md). - ![status](https://img.shields.io/badge/status-alpha-orange) Release lifecycle: handle pre- and post-checks of your Application deployment. -- ![status](https://img.shields.io/badge/status-beta-yellow) +- ![status](https://img.shields.io/badge/status-stable-brightgreen) Certificate Manager: automatically configure TLS certificates for [secure communication with the Kube API](https://kubernetes.io/docs/concepts/security/controlling-access/#transport-security). @@ -29,6 +29,8 @@ beta ![status](https://img.shields.io/badge/status-beta-yellow) ) stable ![status](https://img.shields.io/badge/status-stable-brightgreen) ) --> +The status follows the [Kubernetes API versioning schema](https://kubernetes.io/docs/reference/using-api/#api-versioning). + For more info about the features, please refer to our [documentation](https://lifecycle.keptn.sh/docs/). ## Watch the KubeCon 2022 Detroit Demo diff --git a/docs/content/en/partials/_index-data-access-right.md b/docs/content/en/partials/_index-data-access-right.md index 3efa239380..4efea7c786 100644 --- a/docs/content/en/partials/_index-data-access-right.md +++ b/docs/content/en/partials/_index-data-access-right.md @@ -7,4 +7,4 @@ The Keptn Metrics Server provides: * Define Keptn Metrics once for Dynatrace, DataDog, AWS, Azure, GCP, ... * Access all those metrics via Prometheus or K8s Metric API -* Eliminate the need of multiple plugins for Argo Roolouts, KEDA, HPA, ... +* Eliminate the need of multiple plugins for Argo Rollouts, KEDA, HPA, ... diff --git a/metrics-operator/go.mod b/metrics-operator/go.mod index f3da62acce..40ddff2484 100644 --- a/metrics-operator/go.mod +++ b/metrics-operator/go.mod @@ -8,7 +8,7 @@ require ( github.com/go-logr/logr v1.2.4 github.com/gorilla/mux v1.8.0 github.com/kelseyhightower/envconfig v1.4.0 - github.com/keptn/lifecycle-toolkit/klt-cert-manager v0.0.0-20230630070122-4ad9bbf74960 + github.com/keptn/lifecycle-toolkit/klt-cert-manager v0.0.0-20230721062615-0b618c4bf152 github.com/open-feature/go-sdk v1.4.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.16.0 diff --git a/metrics-operator/go.sum b/metrics-operator/go.sum index 16c4076c50..c1390845e9 100644 --- a/metrics-operator/go.sum +++ b/metrics-operator/go.sum @@ -265,8 +265,8 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= -github.com/keptn/lifecycle-toolkit/klt-cert-manager v0.0.0-20230630070122-4ad9bbf74960 h1:SbVqELW4soNryi9Aq/rxAg0L9AwBevD8Tc1zcKcTMz0= -github.com/keptn/lifecycle-toolkit/klt-cert-manager v0.0.0-20230630070122-4ad9bbf74960/go.mod h1:CBNZ9l66hix9FW1Fs08MV3Xa5BxvFHyizMYObq9j7L8= +github.com/keptn/lifecycle-toolkit/klt-cert-manager v0.0.0-20230721062615-0b618c4bf152 h1:ohSCaA9U8NFit9XMEBymOsfqdjtoJzinqXGFqTkSWfE= +github.com/keptn/lifecycle-toolkit/klt-cert-manager v0.0.0-20230721062615-0b618c4bf152/go.mod h1:CBNZ9l66hix9FW1Fs08MV3Xa5BxvFHyizMYObq9j7L8= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= diff --git a/operator/apis/lifecycle/v1alpha3/common/common.go b/operator/apis/lifecycle/v1alpha3/common/common.go index 1fee458789..13872a60cb 100644 --- a/operator/apis/lifecycle/v1alpha3/common/common.go +++ b/operator/apis/lifecycle/v1alpha3/common/common.go @@ -9,6 +9,7 @@ import ( operatorcommon "github.com/keptn/lifecycle-toolkit/operator/common" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/metric" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) const WorkloadAnnotation = "keptn.sh/workload" @@ -200,3 +201,8 @@ func MergeMaps(m1 map[string]string, m2 map[string]string) map[string]string { } return merged } + +// IsOwnerSupported returns whether the owner of the given object is supported to be considered a KeptnWorklooad +func IsOwnerSupported(owner metav1.OwnerReference) bool { + return owner.Kind == "ReplicaSet" || owner.Kind == "Deployment" || owner.Kind == "StatefulSet" || owner.Kind == "DaemonSet" || owner.Kind == "Rollout" +} diff --git a/operator/apis/lifecycle/v1alpha3/common/common_test.go b/operator/apis/lifecycle/v1alpha3/common/common_test.go index 293f3f9251..c39eaed9fe 100644 --- a/operator/apis/lifecycle/v1alpha3/common/common_test.go +++ b/operator/apis/lifecycle/v1alpha3/common/common_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/stretchr/testify/require" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) const ExtraLongName = "loooooooooooooooooooooo00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ooooooo01234567891234567890123456789" @@ -415,3 +416,76 @@ func Test_MergeMaps(t *testing.T) { }) } } + +func TestIsOwnerSupported(t *testing.T) { + type args struct { + owner v1.OwnerReference + } + tests := []struct { + name string + args args + want bool + }{ + { + name: "Deployment -> true", + args: args{ + owner: v1.OwnerReference{ + Kind: "Deployment", + }, + }, + want: true, + }, + { + name: "DaemonSet-> true", + args: args{ + owner: v1.OwnerReference{ + Kind: "DaemonSet", + }, + }, + want: true, + }, + { + name: "ReplicaSet-> true", + args: args{ + owner: v1.OwnerReference{ + Kind: "ReplicaSet", + }, + }, + want: true, + }, + { + name: "StatefulSet-> true", + args: args{ + owner: v1.OwnerReference{ + Kind: "StatefulSet", + }, + }, + want: true, + }, + { + name: "Rollout-> true", + args: args{ + owner: v1.OwnerReference{ + Kind: "Rollout", + }, + }, + want: true, + }, + { + name: "Job-> false", + args: args{ + owner: v1.OwnerReference{ + Kind: "Job", + }, + }, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := IsOwnerSupported(tt.args.owner); got != tt.want { + t.Errorf("IsOwnerSupported() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/operator/apis/lifecycle/v1alpha3/common/phases.go b/operator/apis/lifecycle/v1alpha3/common/phases.go index 35144c969e..a54e31ff74 100644 --- a/operator/apis/lifecycle/v1alpha3/common/phases.go +++ b/operator/apis/lifecycle/v1alpha3/common/phases.go @@ -26,14 +26,19 @@ var phases = []KeptnPhaseType{ PhaseAppDeployment, PhaseReconcileEvaluation, PhaseReconcileTask, + PhaseReconcileWorkload, + PhaseUpdateWorkload, PhaseCreateEvaluation, PhaseCreateTask, - PhaseCreateApp, + PhaseCreateAppCreationRequest, PhaseCreateWorkload, PhaseCreateWorklodInstance, PhaseCreateAppVersion, - PhaseCompleted, + PhaseAppCompleted, + PhaseWorkloadCompleted, + PhaseDeprecateAppVersion, PhaseDeprecated, + PhaseAppCompleted, } func (p KeptnPhaseType) IsEvaluation() bool { @@ -77,26 +82,31 @@ func GetShortPhaseName(phase string) string { } var ( - PhaseWorkloadPreDeployment = KeptnPhaseType{LongName: "Workload Pre-Deployment Tasks", ShortName: "WorkloadPreDeployTasks"} - PhaseWorkloadPostDeployment = KeptnPhaseType{LongName: "Workload Post-Deployment Tasks", ShortName: "WorkloadPostDeployTasks"} - PhaseWorkloadPreEvaluation = KeptnPhaseType{LongName: "Workload Pre-Deployment Evaluations", ShortName: "WorkloadPreDeployEvaluations"} - PhaseWorkloadPostEvaluation = KeptnPhaseType{LongName: "Workload Post-Deployment Evaluations", ShortName: "WorkloadPostDeployEvaluations"} - PhaseWorkloadDeployment = KeptnPhaseType{LongName: "Workload Deployment", ShortName: "WorkloadDeploy"} - PhaseAppPreDeployment = KeptnPhaseType{LongName: "App Pre-Deployment Tasks", ShortName: "AppPreDeployTasks"} - PhaseAppPostDeployment = KeptnPhaseType{LongName: "App Post-Deployment Tasks", ShortName: "AppPostDeployTasks"} - PhaseAppPreEvaluation = KeptnPhaseType{LongName: "App Pre-Deployment Evaluations", ShortName: "AppPreDeployEvaluations"} - PhaseAppPostEvaluation = KeptnPhaseType{LongName: "App Post-Deployment Evaluations", ShortName: "AppPostDeployEvaluations"} - PhaseAppDeployment = KeptnPhaseType{LongName: "App Deployment", ShortName: "AppDeploy"} - PhaseReconcileEvaluation = KeptnPhaseType{LongName: "Reconcile Evaluation", ShortName: "ReconcileEvaluation"} - PhaseReconcileTask = KeptnPhaseType{LongName: "Reconcile Task", ShortName: "ReconcileTask"} - PhaseCreateEvaluation = KeptnPhaseType{LongName: "Create Evaluation", ShortName: "CreateEvaluation"} - PhaseCreateTask = KeptnPhaseType{LongName: "Create Task", ShortName: "CreateTask"} - PhaseCreateApp = KeptnPhaseType{LongName: "Create App", ShortName: "CreateApp"} - PhaseCreateWorkload = KeptnPhaseType{LongName: "Create Workload", ShortName: "CreateWorkload"} - PhaseCreateWorklodInstance = KeptnPhaseType{LongName: "Create WorkloadInstance", ShortName: "CreateWorkloadInstance"} - PhaseCreateAppVersion = KeptnPhaseType{LongName: "Create AppVersion", ShortName: "CreateAppVersion"} - PhaseCompleted = KeptnPhaseType{LongName: "Completed", ShortName: "Completed"} - PhaseDeprecated = KeptnPhaseType{LongName: "Deprecated", ShortName: "Deprecated"} + PhaseWorkloadPreDeployment = KeptnPhaseType{LongName: "Workload Pre-Deployment Tasks", ShortName: "WorkloadPreDeployTasks"} + PhaseWorkloadPostDeployment = KeptnPhaseType{LongName: "Workload Post-Deployment Tasks", ShortName: "WorkloadPostDeployTasks"} + PhaseWorkloadPreEvaluation = KeptnPhaseType{LongName: "Workload Pre-Deployment Evaluations", ShortName: "WorkloadPreDeployEvaluations"} + PhaseWorkloadPostEvaluation = KeptnPhaseType{LongName: "Workload Post-Deployment Evaluations", ShortName: "WorkloadPostDeployEvaluations"} + PhaseWorkloadDeployment = KeptnPhaseType{LongName: "Workload Deployment", ShortName: "WorkloadDeploy"} + PhaseAppPreDeployment = KeptnPhaseType{LongName: "App Pre-Deployment Tasks", ShortName: "AppPreDeployTasks"} + PhaseAppPostDeployment = KeptnPhaseType{LongName: "App Post-Deployment Tasks", ShortName: "AppPostDeployTasks"} + PhaseAppPreEvaluation = KeptnPhaseType{LongName: "App Pre-Deployment Evaluations", ShortName: "AppPreDeployEvaluations"} + PhaseAppPostEvaluation = KeptnPhaseType{LongName: "App Post-Deployment Evaluations", ShortName: "AppPostDeployEvaluations"} + PhaseAppDeployment = KeptnPhaseType{LongName: "App Deployment", ShortName: "AppDeploy"} + PhaseReconcileEvaluation = KeptnPhaseType{LongName: "Reconcile Evaluation", ShortName: "ReconcileEvaluation"} + PhaseReconcileTask = KeptnPhaseType{LongName: "Reconcile Task", ShortName: "ReconcileTask"} + PhaseReconcileWorkload = KeptnPhaseType{LongName: "Reconcile Workloads", ShortName: "ReconcileWorkload"} + PhaseCreateEvaluation = KeptnPhaseType{LongName: "Create Evaluation", ShortName: "CreateEvaluation"} + PhaseCreateTask = KeptnPhaseType{LongName: "Create Task", ShortName: "CreateTask"} + PhaseCreateAppCreationRequest = KeptnPhaseType{LongName: "Create AppCreationRequest", ShortName: "CreateAppCreationRequest"} + PhaseCreateWorkload = KeptnPhaseType{LongName: "Create Workload", ShortName: "CreateWorkload"} + PhaseUpdateWorkload = KeptnPhaseType{LongName: "Update Workload", ShortName: "UpdateWorkload"} + PhaseCreateWorklodInstance = KeptnPhaseType{LongName: "Create WorkloadInstance", ShortName: "CreateWorkloadInstance"} + PhaseCreateAppVersion = KeptnPhaseType{LongName: "Create AppVersion", ShortName: "CreateAppVersion"} + PhaseDeprecateAppVersion = KeptnPhaseType{LongName: "Deprecate AppVersion", ShortName: "DeprecateAppVersion"} + PhaseAppCompleted = KeptnPhaseType{LongName: "App Completed", ShortName: "AppCompleted"} + PhaseWorkloadCompleted = KeptnPhaseType{LongName: "Workload Completed", ShortName: "WorkloadCompleted"} + PhaseCompleted = KeptnPhaseType{LongName: "Completed", ShortName: "Completed"} + PhaseDeprecated = KeptnPhaseType{LongName: "Deprecated", ShortName: "Deprecated"} ) type PhaseTraceID map[string]propagation.MapCarrier @@ -109,3 +119,13 @@ func (pid PhaseTraceID) SetPhaseTraceID(phase string, carrier propagation.MapCar func (pid PhaseTraceID) GetPhaseTraceID(phase string) propagation.MapCarrier { return pid[GetShortPhaseName(phase)] } + +var ( + PhaseStateFinished = "Finished" + PhaseStateStarted = "Started" + PhaseStateFailed = "Failed" + PhaseStateStatusChanged = "StatusChanged" + PhaseStateReconcileError = "ReconcileError" + PhaseStateReconcileTimeout = "ReconcileTimeout" + PhaseStateNotFound = "NotFound" +) diff --git a/operator/controllers/common/evaluationhandler.go b/operator/controllers/common/evaluationhandler.go index 19fe33559c..78148b01a7 100644 --- a/operator/controllers/common/evaluationhandler.go +++ b/operator/controllers/common/evaluationhandler.go @@ -55,7 +55,7 @@ func (r EvaluationHandler) ReconcileEvaluations(ctx context.Context, phaseCtx co evaluationExists := false if oldstatus != evaluationStatus.Status { - r.EventSender.SendK8sEvent(apicommon.PhaseReconcileEvaluation, "Normal", reconcileObject, "EvaluationStatusChanged", fmt.Sprintf("evaluation status changed from %s to %s", oldstatus, evaluationStatus.Status), piWrapper.GetVersion()) + r.EventSender.SendK8sEvent(apicommon.PhaseReconcileEvaluation, "Normal", reconcileObject, apicommon.PhaseStateStatusChanged, fmt.Sprintf("evaluation status changed from %s to %s", oldstatus, evaluationStatus.Status), piWrapper.GetVersion()) } // Check if evaluation has already succeeded or failed @@ -105,9 +105,7 @@ func (r EvaluationHandler) ReconcileEvaluations(ctx context.Context, phaseCtx co for _, ns := range newStatus { summary = apicommon.UpdateStatusSummary(ns.Status, summary) } - if apicommon.GetOverallState(summary) != apicommon.StateSucceeded { - r.EventSender.SendK8sEvent(apicommon.PhaseReconcileEvaluation, "Warning", reconcileObject, "NotFinished", "has not finished", piWrapper.GetVersion()) - } + return newStatus, summary, nil } @@ -128,10 +126,9 @@ func (r EvaluationHandler) CreateKeptnEvaluation(ctx context.Context, namespace err = r.Client.Create(ctx, &newEvaluation) if err != nil { r.Log.Error(err, "could not create KeptnEvaluation") - r.EventSender.SendK8sEvent(phase, "Warning", reconcileObject, "CreateFailed", "could not create KeptnEvaluation", piWrapper.GetVersion()) + r.EventSender.SendK8sEvent(phase, "Warning", reconcileObject, apicommon.PhaseStateFailed, "could not create KeptnEvaluation", piWrapper.GetVersion()) return "", err } - r.EventSender.SendK8sEvent(phase, "Normal", reconcileObject, "Created", "created", piWrapper.GetVersion()) return newEvaluation.Name, nil } @@ -145,7 +142,7 @@ func (r EvaluationHandler) emitEvaluationFailureEvents(evaluation *klcv1alpha3.K k8sEventMessage = fmt.Sprintf("%s\n%s", k8sEventMessage, msg) } } - r.EventSender.SendK8sEvent(apicommon.PhaseReconcileEvaluation, "Warning", evaluation, "Failed", k8sEventMessage, piWrapper.GetVersion()) + r.EventSender.SendK8sEvent(apicommon.PhaseReconcileEvaluation, "Warning", evaluation, apicommon.PhaseStateFailed, k8sEventMessage, piWrapper.GetVersion()) } func (r EvaluationHandler) setupEvaluations(evaluationCreateAttributes CreateEvaluationAttributes, piWrapper *interfaces.PhaseItemWrapper) ([]string, []klcv1alpha3.ItemStatus) { @@ -190,7 +187,6 @@ func (r EvaluationHandler) handleEvaluationExists(phaseCtx context.Context, piWr if evaluationStatus.Status.IsSucceeded() { spanEvaluationTrace.AddEvent(evaluation.Name + " has finished") spanEvaluationTrace.SetStatus(codes.Ok, "Finished") - r.EventSender.SendK8sEvent(apicommon.PhaseReconcileEvaluation, "Normal", evaluation, "Succeeded", "evaluation succeeded", piWrapper.GetVersion()) } else { spanEvaluationTrace.AddEvent(evaluation.Name + " has failed") r.emitEvaluationFailureEvents(evaluation, spanEvaluationTrace, piWrapper) diff --git a/operator/controllers/common/evaluationhandler_test.go b/operator/controllers/common/evaluationhandler_test.go index 53b812a4a7..9f2394620a 100644 --- a/operator/controllers/common/evaluationhandler_test.go +++ b/operator/controllers/common/evaluationhandler_test.go @@ -20,6 +20,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/fake" ) +//nolint:dupl func TestEvaluationHandler(t *testing.T) { tests := []struct { name string @@ -248,9 +249,6 @@ func TestEvaluationHandler(t *testing.T) { wantErr: nil, getSpanCalls: 1, unbindSpanCalls: 1, - events: []string{ - "ReconcileEvaluationSucceeded", - }, }, } diff --git a/operator/controllers/common/phasehandler.go b/operator/controllers/common/phasehandler.go index 0417261cfc..4fe8b77158 100644 --- a/operator/controllers/common/phasehandler.go +++ b/operator/controllers/common/phasehandler.go @@ -38,9 +38,11 @@ func (r PhaseHandler) HandlePhase(ctx context.Context, ctxTrace context.Context, if shouldAbortPhase(oldStatus) { return &PhaseResult{Continue: false, Result: ctrl.Result{}}, nil } - piWrapper.SetCurrentPhase(phase.ShortName) + if oldPhase != phase.ShortName { + r.EventSender.SendK8sEvent(phase, "Normal", reconcileObject, apicommon.PhaseStateStarted, "has started", piWrapper.GetVersion()) + piWrapper.SetCurrentPhase(phase.ShortName) + } - r.Log.Info(phase.LongName + " not finished") spanPhaseCtx, spanPhaseTrace, err := r.SpanHandler.GetSpan(ctxTrace, tracer, reconcileObject, phase.ShortName) if err != nil { r.Log.Error(err, "could not get span") @@ -49,15 +51,11 @@ func (r PhaseHandler) HandlePhase(ctx context.Context, ctxTrace context.Context, state, err := reconcilePhase(spanPhaseCtx) if err != nil { spanPhaseTrace.AddEvent(phase.LongName + " could not get reconciled") - r.EventSender.SendK8sEvent(phase, "Warning", reconcileObject, "ReconcileErrored", "could not get reconciled", piWrapper.GetVersion()) + r.EventSender.SendK8sEvent(phase, "Warning", reconcileObject, apicommon.PhaseStateReconcileError, "could not get reconciled", piWrapper.GetVersion()) span.SetStatus(codes.Error, err.Error()) return &PhaseResult{Continue: false, Result: requeueResult}, err } - if state.IsPending() { - state = apicommon.StateProgressing - } - defer func(ctx context.Context, oldStatus apicommon.KeptnState, oldPhase string, reconcileObject client.Object) { piWrapper, _ := interfaces.NewPhaseItemWrapperFromClientObject(reconcileObject) if oldStatus != piWrapper.GetState() || oldPhase != piWrapper.GetCurrentPhase() { @@ -72,7 +70,6 @@ func (r PhaseHandler) HandlePhase(ctx context.Context, ctxTrace context.Context, } piWrapper.SetState(apicommon.StateProgressing) - r.EventSender.SendK8sEvent(phase, "Warning", reconcileObject, "NotFinished", "has not finished", piWrapper.GetVersion()) return &PhaseResult{Continue: false, Result: requeueResult}, nil } @@ -91,7 +88,7 @@ func (r PhaseHandler) handleCompletedPhase(state apicommon.KeptnState, piWrapper if err := r.SpanHandler.UnbindSpan(reconcileObject, phase.ShortName); err != nil { r.Log.Error(err, controllererrors.ErrCouldNotUnbindSpan, reconcileObject.GetName()) } - r.EventSender.SendK8sEvent(phase, "Warning", reconcileObject, "Failed", "has failed", piWrapper.GetVersion()) + r.EventSender.SendK8sEvent(phase, "Warning", reconcileObject, apicommon.PhaseStateFailed, "has failed", piWrapper.GetVersion()) piWrapper.DeprecateRemainingPhases(phase) return &PhaseResult{Continue: false, Result: ctrl.Result{}}, nil } @@ -103,7 +100,7 @@ func (r PhaseHandler) handleCompletedPhase(state apicommon.KeptnState, piWrapper if err := r.SpanHandler.UnbindSpan(reconcileObject, phase.ShortName); err != nil { r.Log.Error(err, controllererrors.ErrCouldNotUnbindSpan, reconcileObject.GetName()) } - r.EventSender.SendK8sEvent(phase, "Normal", reconcileObject, "Succeeded", "has succeeded", piWrapper.GetVersion()) + r.EventSender.SendK8sEvent(phase, "Normal", reconcileObject, apicommon.PhaseStateFinished, "has finished", piWrapper.GetVersion()) return &PhaseResult{Continue: true, Result: ctrl.Result{Requeue: true, RequeueAfter: 5 * time.Second}}, nil } diff --git a/operator/controllers/common/taskhandler.go b/operator/controllers/common/taskhandler.go index 41ad2aa797..eaf790fe8a 100644 --- a/operator/controllers/common/taskhandler.go +++ b/operator/controllers/common/taskhandler.go @@ -57,7 +57,7 @@ func (r TaskHandler) ReconcileTasks(ctx context.Context, phaseCtx context.Contex taskExists := false if oldstatus != taskStatus.Status { - r.EventSender.SendK8sEvent(phase, "Normal", reconcileObject, "TaskStatusChanged", fmt.Sprintf("task status changed from %s to %s", oldstatus, taskStatus.Status), piWrapper.GetVersion()) + r.EventSender.SendK8sEvent(phase, "Normal", reconcileObject, apicommon.PhaseStateStatusChanged, fmt.Sprintf("task status changed from %s to %s", oldstatus, taskStatus.Status), piWrapper.GetVersion()) } // Check if task has already succeeded or failed @@ -109,9 +109,7 @@ func (r TaskHandler) ReconcileTasks(ctx context.Context, phaseCtx context.Contex for _, ns := range newStatus { summary = apicommon.UpdateStatusSummary(ns.Status, summary) } - if apicommon.GetOverallState(summary) != apicommon.StateSucceeded { - r.EventSender.SendK8sEvent(phase, "Warning", reconcileObject, "NotFinished", "has not finished", piWrapper.GetVersion()) - } + return newStatus, summary, nil } @@ -132,10 +130,9 @@ func (r TaskHandler) CreateKeptnTask(ctx context.Context, namespace string, reco err = r.Client.Create(ctx, &newTask) if err != nil { r.Log.Error(err, "could not create KeptnTask") - r.EventSender.SendK8sEvent(phase, "Warning", reconcileObject, "CreateFailed", "could not create KeptnTask", piWrapper.GetVersion()) + r.EventSender.SendK8sEvent(phase, "Warning", reconcileObject, apicommon.PhaseStateFailed, "could not create KeptnTask", piWrapper.GetVersion()) return "", err } - r.EventSender.SendK8sEvent(phase, "Normal", reconcileObject, "Created", "created", piWrapper.GetVersion()) return newTask.Name, nil } diff --git a/operator/controllers/lifecycle/keptnapp/controller.go b/operator/controllers/lifecycle/keptnapp/controller.go index e9b90d4fe0..1582dcaf15 100644 --- a/operator/controllers/lifecycle/keptnapp/controller.go +++ b/operator/controllers/lifecycle/keptnapp/controller.go @@ -105,10 +105,9 @@ func (r *KeptnAppReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c if err != nil { r.Log.Error(err, "could not create AppVersion") span.SetStatus(codes.Error, err.Error()) - r.EventSender.SendK8sEvent(common.PhaseCreateAppVersion, "Warning", appVersion, "AppVersionNotCreated", "Could not create KeptnAppVersion", appVersion.Spec.Version) + r.EventSender.SendK8sEvent(common.PhaseCreateAppVersion, "Warning", appVersion, common.PhaseStateFailed, "Could not create KeptnAppVersion", appVersion.Spec.Version) return ctrl.Result{}, err } - r.EventSender.SendK8sEvent(common.PhaseCreateAppVersion, "Normal", appVersion, "AppVersionCreated", "created KeptnAppVersion", appVersion.Spec.Version) app.Status.CurrentVersion = app.Spec.Version if err := r.Client.Status().Update(ctx, app); err != nil { @@ -172,10 +171,9 @@ func (r *KeptnAppReconciler) handleGenerationBump(ctx context.Context, app *klcv if app.Generation != 1 { if err := r.deprecateAppVersions(ctx, app); err != nil { r.Log.Error(err, "could not deprecate appVersions for appVersion %s", app.GetAppVersionName()) - r.EventSender.SendK8sEvent(common.PhaseCreateAppVersion, "Warning", app, "AppVersionNotDeprecated", fmt.Sprintf("could not deprecate KeptnAppVersions for KeptnAppVersion: %s", app.GetAppVersionName()), app.Spec.Version) + r.EventSender.SendK8sEvent(common.PhaseDeprecateAppVersion, "Warning", app, common.PhaseStateFailed, fmt.Sprintf("could not deprecate outdated revisions of KeptnAppVersion: %s", app.GetAppVersionName()), app.Spec.Version) return err } - r.EventSender.SendK8sEvent(common.PhaseCreateAppVersion, "Normal", app, "AppVersionDeprecated", fmt.Sprintf("deprecated KeptnAppVersions for KeptnAppVersion: %s", app.GetAppVersionName()), app.Spec.Version) } return nil } diff --git a/operator/controllers/lifecycle/keptnapp/controller_test.go b/operator/controllers/lifecycle/keptnapp/controller_test.go index 857e101fbb..65cd0747ec 100644 --- a/operator/controllers/lifecycle/keptnapp/controller_test.go +++ b/operator/controllers/lifecycle/keptnapp/controller_test.go @@ -73,13 +73,13 @@ func TestKeptnAppReconciler_createAppVersionWithLongName(t *testing.T) { func TestKeptnAppReconciler_reconcile(t *testing.T) { - r, eventChannel, tracer := setupReconciler() + r, _, tracer := setupReconciler() tests := []struct { - name string - req ctrl.Request - wantErr error - event string //check correct events are generated + name string + req ctrl.Request + wantErr error + appVersionName string }{ { name: "test simple create appVersion", @@ -90,7 +90,6 @@ func TestKeptnAppReconciler_reconcile(t *testing.T) { }, }, wantErr: nil, - event: `Normal CreateAppVersionAppVersionCreated Create AppVersion: created KeptnAppVersion / Namespace: default, Name: myapp-1.0.0-6b86b273, Version: 1.0.0`, }, { name: "test simple notfound should not return error nor event", @@ -131,13 +130,13 @@ func TestKeptnAppReconciler_reconcile(t *testing.T) { t.Errorf("Reconcile() error = %v, wantErr %v", err, tt.wantErr) return } - if tt.event != "" { - event := <-eventChannel - assert.Matches(t, event, tt.event) + if tt.appVersionName != "" { + keptnappversion := &lfcv1alpha3.KeptnAppVersion{} + err = r.Client.Get(context.TODO(), types.NamespacedName{Namespace: "default", Name: "myapp-1.0.0-6b86b273"}, keptnappversion) + require.Nil(t, err) } }) - } // check correct traces @@ -152,7 +151,7 @@ func TestKeptnAppReconciler_reconcile(t *testing.T) { } func TestKeptnAppReconciler_deprecateAppVersions(t *testing.T) { - r, eventChannel, _ := setupReconciler() + r, _, _ := setupReconciler() err := controllercommon.AddApp(r.Client, "myapp") require.Nil(t, err) @@ -166,8 +165,9 @@ func TestKeptnAppReconciler_deprecateAppVersions(t *testing.T) { require.Nil(t, err) - event := <-eventChannel - assert.Matches(t, event, `Normal CreateAppVersionAppVersionCreated Create AppVersion: created KeptnAppVersion / Namespace: default, Name: myapp-1.0.0-6b86b273, Version: 1.0.0`) + keptnappversion := &lfcv1alpha3.KeptnAppVersion{} + err = r.Client.Get(context.TODO(), types.NamespacedName{Namespace: "default", Name: "myapp-1.0.0-6b86b273"}, keptnappversion) + require.Nil(t, err) err = controllercommon.UpdateAppRevision(r.Client, "myapp", 2) require.Nil(t, err) @@ -181,11 +181,12 @@ func TestKeptnAppReconciler_deprecateAppVersions(t *testing.T) { require.Nil(t, err) - event = <-eventChannel - assert.Matches(t, event, `Normal CreateAppVersionAppVersionCreated Create AppVersion: created KeptnAppVersion / Namespace: default, Name: myapp-1.0.0-d4735e3a, Version: 1.0.0`) + err = r.Client.Get(context.TODO(), types.NamespacedName{Namespace: "default", Name: "myapp-1.0.0-d4735e3a"}, keptnappversion) + require.Nil(t, err) - event = <-eventChannel - assert.Matches(t, event, `Normal CreateAppVersionAppVersionDeprecated Create AppVersion: deprecated KeptnAppVersions for KeptnAppVersion: myapp-1.0.0-d4735e3a / Namespace: default, Name: myapp, Version: 1.0.0`) + err = r.Client.Get(context.TODO(), types.NamespacedName{Namespace: "default", Name: "myapp-1.0.0-6b86b273"}, keptnappversion) + require.Nil(t, err) + require.Equal(t, apicommon.StateDeprecated, keptnappversion.Status.Status) } func setupReconciler() (*KeptnAppReconciler, chan string, *fake.ITracerMock) { diff --git a/operator/controllers/lifecycle/keptnappversion/controller.go b/operator/controllers/lifecycle/keptnappversion/controller.go index 3866b229e9..aaf5387a84 100644 --- a/operator/controllers/lifecycle/keptnappversion/controller.go +++ b/operator/controllers/lifecycle/keptnappversion/controller.go @@ -103,7 +103,6 @@ func (r *KeptnAppVersionReconciler) Reconcile(ctx context.Context, req ctrl.Requ if appVersion.Status.CurrentPhase == "" { appVersion.SetSpanAttributes(spanAppTrace) spanAppTrace.AddEvent("App Version Pre-Deployment Tasks started", trace.WithTimestamp(time.Now())) - r.EventSender.SendK8sEvent(phase, "Normal", appVersion, "Started", "have started", appVersion.GetVersion()) } if !appVersion.IsPreDeploymentSucceeded() { @@ -160,7 +159,6 @@ func (r *KeptnAppVersionReconciler) Reconcile(ctx context.Context, req ctrl.Requ } } - r.EventSender.SendK8sEvent(phase, "Normal", appVersion, "Finished", "is finished", appVersion.GetVersion()) err = r.Client.Status().Update(ctx, appVersion) if err != nil { span.SetStatus(codes.Error, err.Error()) @@ -183,6 +181,8 @@ func (r *KeptnAppVersionReconciler) finishKeptnAppVersionReconcile(ctx context.C return ctrl.Result{Requeue: true}, err } + r.EventSender.SendK8sEvent(apicommon.PhaseAppCompleted, "Normal", appVersion, apicommon.PhaseStateFinished, "has finished", appVersion.GetVersion()) + attrs := appVersion.GetMetricsAttributes() // metrics: add app duration diff --git a/operator/controllers/lifecycle/keptnappversion/controller_test.go b/operator/controllers/lifecycle/keptnappversion/controller_test.go index 4ed3dd19a8..2832100b0e 100644 --- a/operator/controllers/lifecycle/keptnappversion/controller_test.go +++ b/operator/controllers/lifecycle/keptnappversion/controller_test.go @@ -11,9 +11,9 @@ import ( apicommon "github.com/keptn/lifecycle-toolkit/operator/apis/lifecycle/v1alpha3/common" controllercommon "github.com/keptn/lifecycle-toolkit/operator/controllers/common" "github.com/keptn/lifecycle-toolkit/operator/controllers/common/fake" - "github.com/magiconair/properties/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/trace" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/tools/record" @@ -50,11 +50,14 @@ func TestKeptnAppVersionReconciler_reconcile(t *testing.T) { wantErr: nil, events: []string{ `AppPreDeployTasksStarted`, - `AppPreDeployTasksSucceeded`, - `AppPreDeployEvaluationsSucceeded`, - `AppDeploySucceeded`, - `AppPostDeployTasksSucceeded`, - `AppPostDeployEvaluationsSucceeded`, + `AppPreDeployTasksFinished`, + `AppPreDeployEvaluationsStarted`, + `AppPreDeployEvaluationsFinished`, + `AppDeployStarted`, + `AppDeployFinished`, + `AppPostDeployTasksStarted`, + `AppPostDeployTasksFinished`, + `AppPostDeployEvaluationsStarted`, `AppPostDeployEvaluationsFinished`, }, startTrace: true, @@ -69,25 +72,21 @@ func TestKeptnAppVersionReconciler_reconcile(t *testing.T) { }, wantErr: nil, }, - { - name: "existing appVersion has finished", - req: ctrl.Request{ - NamespacedName: types.NamespacedName{ - Namespace: "default", - Name: "myfinishedapp-1.0.0", - }, - }, - wantErr: nil, - events: []string{`AppPostDeployEvaluationsFinished`}, - startTrace: true, - }, + } + + pendingStatus := lfcv1alpha3.KeptnAppVersionStatus{ + CurrentPhase: "", + Status: apicommon.StatePending, + PreDeploymentStatus: apicommon.StatePending, + PreDeploymentEvaluationStatus: apicommon.StatePending, + WorkloadOverallStatus: apicommon.StatePending, + PostDeploymentStatus: apicommon.StatePending, + PostDeploymentEvaluationStatus: apicommon.StatePending, } //setting up fakeclient CRD data - err := controllercommon.AddAppVersion(r.Client, "default", "myappversion", "1.0.0", nil, lfcv1alpha3.KeptnAppVersionStatus{Status: apicommon.StatePending}) - require.Nil(t, err) - err = controllercommon.AddAppVersion(r.Client, "default", "myfinishedapp", "1.0.0", nil, createFinishedAppVersionStatus()) + err := controllercommon.AddAppVersion(r.Client, "default", "myappversion", "1.0.0", nil, pendingStatus) require.Nil(t, err) traces := 0 @@ -102,16 +101,16 @@ func TestKeptnAppVersionReconciler_reconcile(t *testing.T) { if tt.events != nil { for _, e := range tt.events { event := <-eventChannel - assert.Equal(t, strings.Contains(event, tt.req.Name), true, "wrong appversion") - assert.Equal(t, strings.Contains(event, tt.req.Namespace), true, "wrong namespace") - assert.Equal(t, strings.Contains(event, e), true, fmt.Sprintf("no %s found in %s", e, event)) + require.Equal(t, strings.Contains(event, tt.req.Name), true, "wrong appversion") + require.Equal(t, strings.Contains(event, tt.req.Namespace), true, "wrong namespace") + require.Equal(t, strings.Contains(event, e), true, fmt.Sprintf("no %s found in %s", e, event)) } } if tt.startTrace { //A different trace for each app-version - assert.Equal(t, tracer.StartCalls()[traces].SpanName, "reconcile_app_version") - assert.Equal(t, tracer.StartCalls()[traces].Ctx.Value(CONTEXTID), tt.req.Name) + require.Equal(t, tracer.StartCalls()[traces].SpanName, "reconcile_app_version") + require.Equal(t, tracer.StartCalls()[traces].Ctx.Value(CONTEXTID), tt.req.Name) traces++ } }) @@ -120,6 +119,117 @@ func TestKeptnAppVersionReconciler_reconcile(t *testing.T) { } +func TestKeptnAppVersionReconciler_ReconcileFailed(t *testing.T) { + r, eventChannel, tracer, _ := setupReconciler() + + status := lfcv1alpha3.KeptnAppVersionStatus{ + CurrentPhase: apicommon.PhaseAppPreDeployment.ShortName, + Status: apicommon.StateProgressing, + PreDeploymentStatus: apicommon.StateProgressing, + PreDeploymentTaskStatus: []lfcv1alpha3.ItemStatus{ + { + Name: "pre-task", + DefinitionName: "task", + Status: apicommon.StateFailed, + }, + }, + PreDeploymentEvaluationStatus: apicommon.StatePending, + WorkloadOverallStatus: apicommon.StatePending, + PostDeploymentStatus: apicommon.StatePending, + PostDeploymentEvaluationStatus: apicommon.StatePending, + } + + appVersionName := fmt.Sprintf("%s-%s", "myapp", "1.0.0") + app := &lfcv1alpha3.KeptnAppVersion{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + Name: appVersionName, + Namespace: "default", + Generation: 1, + }, + Spec: lfcv1alpha3.KeptnAppVersionSpec{ + KeptnAppSpec: lfcv1alpha3.KeptnAppSpec{ + Version: "1.0.0", + PreDeploymentTasks: []string{ + "task", + }, + }, + AppName: "myapp", + TraceId: map[string]string{ + "traceparent": "parent-trace", + }, + }, + Status: status, + } + err := r.Client.Create(context.TODO(), app) + require.Nil(t, err) + + req := ctrl.Request{ + NamespacedName: types.NamespacedName{ + Namespace: "default", + Name: "myapp-1.0.0", + }, + } + + result, err := r.Reconcile(context.WithValue(context.TODO(), CONTEXTID, req.Name), req) + require.Nil(t, err) + + expectedEvents := []string{ + "AppPreDeployTasksFailed", + } + + for _, e := range expectedEvents { + event := <-eventChannel + require.Equal(t, strings.Contains(event, req.Name), true, "wrong appversion") + require.Equal(t, strings.Contains(event, req.Namespace), true, "wrong namespace") + require.Equal(t, strings.Contains(event, e), true, fmt.Sprintf("no %s found in %s", e, event)) + } + + require.Equal(t, tracer.StartCalls()[0].SpanName, "reconcile_app_version") + require.Equal(t, tracer.StartCalls()[0].Ctx.Value(CONTEXTID), req.Name) + + require.Nil(t, err) + + // do not requeue since we reached completion + require.False(t, result.Requeue) +} + +func TestKeptnAppVersionReconciler_ReconcileReachCompletion(t *testing.T) { + r, eventChannel, tracer, _ := setupReconciler() + + err := controllercommon.AddAppVersion(r.Client, "default", "myfinishedapp", "1.0.0", nil, createFinishedAppVersionStatus()) + require.Nil(t, err) + + req := ctrl.Request{ + NamespacedName: types.NamespacedName{ + Namespace: "default", + Name: "myfinishedapp-1.0.0", + }, + } + + result, err := r.Reconcile(context.WithValue(context.TODO(), CONTEXTID, req.Name), req) + require.Nil(t, err) + + expectedEvents := []string{ + "CompletedFinished", + } + + for _, e := range expectedEvents { + event := <-eventChannel + require.Equal(t, strings.Contains(event, req.Name), true, "wrong appversion") + require.Equal(t, strings.Contains(event, req.Namespace), true, "wrong namespace") + require.Equal(t, strings.Contains(event, e), true, fmt.Sprintf("no %s found in %s", e, event)) + } + + require.Equal(t, tracer.StartCalls()[0].SpanName, "reconcile_app_version") + require.Equal(t, tracer.StartCalls()[0].Ctx.Value(CONTEXTID), req.Name) + + require.Nil(t, err) + + // do not requeue since we reached completion + require.False(t, result.Requeue) +} + func createFinishedAppVersionStatus() lfcv1alpha3.KeptnAppVersionStatus { return lfcv1alpha3.KeptnAppVersionStatus{ CurrentPhase: apicommon.PhaseCompleted.ShortName, diff --git a/operator/controllers/lifecycle/keptnappversion/reconcile_workloadsstate.go b/operator/controllers/lifecycle/keptnappversion/reconcile_workloadsstate.go index d4d43d0f05..4f1636eb2c 100644 --- a/operator/controllers/lifecycle/keptnappversion/reconcile_workloadsstate.go +++ b/operator/controllers/lifecycle/keptnappversion/reconcile_workloadsstate.go @@ -2,6 +2,7 @@ package keptnappversion import ( "context" + "fmt" klcv1alpha3 "github.com/keptn/lifecycle-toolkit/operator/apis/lifecycle/v1alpha3" apicommon "github.com/keptn/lifecycle-toolkit/operator/apis/lifecycle/v1alpha3/common" @@ -14,10 +15,7 @@ func (r *KeptnAppVersionReconciler) reconcileWorkloads(ctx context.Context, appV var summary apicommon.StatusSummary summary.Total = len(appVersion.Spec.Workloads) - phase := apicommon.KeptnPhaseType{ - ShortName: "ReconcileWorkload", - LongName: "Reconcile Workloads", - } + phase := apicommon.PhaseReconcileWorkload workloadInstanceList, err := r.getWorkloadInstanceList(ctx, appVersion.Namespace, appVersion.Spec.AppName) if err != nil { @@ -43,7 +41,7 @@ func (r *KeptnAppVersionReconciler) reconcileWorkloads(ctx context.Context, appV } if !found { - r.EventSender.SendK8sEvent(phase, "Warning", appVersion, "NotFound", "workloadInstance not found", appVersion.GetVersion()) + r.EventSender.SendK8sEvent(phase, "Warning", appVersion, apicommon.PhaseStateNotFound, fmt.Sprintf("could not find KeptnWorkloadInstance for KeptnWorkload: %s ", w.Name), appVersion.GetVersion()) } newStatus = append(newStatus, klcv1alpha3.WorkloadStatus{ diff --git a/operator/controllers/lifecycle/keptnevaluation/controller.go b/operator/controllers/lifecycle/keptnevaluation/controller.go index f76fa9eda0..1b6c5a8029 100644 --- a/operator/controllers/lifecycle/keptnevaluation/controller.go +++ b/operator/controllers/lifecycle/keptnevaluation/controller.go @@ -138,19 +138,17 @@ func (r *KeptnEvaluationReconciler) handleEvaluationIncomplete(ctx context.Conte // Evaluation is uncompleted, update status anyway this avoids updating twice in case of completion err := r.Client.Status().Update(ctx, evaluation) if err != nil { - r.EventSender.SendK8sEvent(apicommon.PhaseReconcileEvaluation, "Warning", evaluation, "ReconcileErrored", "could not update status", "") + r.EventSender.SendK8sEvent(apicommon.PhaseReconcileEvaluation, "Warning", evaluation, apicommon.PhaseStateReconcileError, "could not update status", "") span.SetStatus(codes.Error, err.Error()) return err } - r.EventSender.SendK8sEvent(apicommon.PhaseReconcileEvaluation, "Normal", evaluation, "NotFinished", "has not finished", "") - return nil } func (r *KeptnEvaluationReconciler) handleEvaluationExceededRetries(ctx context.Context, evaluation *klcv1alpha3.KeptnEvaluation, span trace.Span) { - r.EventSender.SendK8sEvent(apicommon.PhaseReconcileEvaluation, "Warning", evaluation, "ReconcileTimeOut", "retryCount exceeded", "") + r.EventSender.SendK8sEvent(apicommon.PhaseReconcileEvaluation, "Warning", evaluation, apicommon.PhaseStateReconcileTimeout, "retryCount exceeded", "") err := controllererrors.ErrRetryCountExceeded span.SetStatus(codes.Error, err.Error()) evaluation.Status.OverallStatus = apicommon.StateFailed @@ -239,7 +237,7 @@ func (r *KeptnEvaluationReconciler) updateFinishedEvaluationMetrics(ctx context. err := r.Client.Status().Update(ctx, evaluation) if err != nil { span.SetStatus(codes.Error, err.Error()) - r.EventSender.SendK8sEvent(apicommon.PhaseReconcileEvaluation, "Warning", evaluation, "ReconcileErrored", "could not update status", "") + r.EventSender.SendK8sEvent(apicommon.PhaseReconcileEvaluation, "Warning", evaluation, apicommon.PhaseStateReconcileError, "could not update status", "") return err } diff --git a/operator/controllers/lifecycle/keptntask/job_utils.go b/operator/controllers/lifecycle/keptntask/job_utils.go index 8633a171ca..a0f4068dbf 100644 --- a/operator/controllers/lifecycle/keptntask/job_utils.go +++ b/operator/controllers/lifecycle/keptntask/job_utils.go @@ -20,7 +20,8 @@ func (r *KeptnTaskReconciler) createJob(ctx context.Context, req ctrl.Request, t jobName := "" definition, err := controllercommon.GetTaskDefinition(r.Client, r.Log, ctx, task.Spec.TaskDefinition, req.Namespace) if err != nil { - r.EventSender.SendK8sEvent(apicommon.PhaseCreateTask, "Warning", task, "TaskDefinitionNotFound", fmt.Sprintf("could not find KeptnTaskDefinition: %s ", task.Spec.TaskDefinition), "") + r.Log.Error(err, fmt.Sprintf("could not find KeptnTaskDefinition: %s ", task.Spec.TaskDefinition)) + r.EventSender.SendK8sEvent(apicommon.PhaseCreateTask, "Warning", task, apicommon.PhaseStateNotFound, fmt.Sprintf("could not find KeptnTaskDefinition: %s ", task.Spec.TaskDefinition), "") return err } @@ -45,12 +46,11 @@ func (r *KeptnTaskReconciler) createFunctionJob(ctx context.Context, req ctrl.Re } err = r.Client.Create(ctx, job) if err != nil { - r.Log.Error(err, "could not create job") - r.EventSender.SendK8sEvent(apicommon.PhaseCreateTask, "Warning", task, "JobNotCreated", fmt.Sprintf("could not create Job: %s ", task.Name), "") + r.Log.Error(err, "could not create Job") + r.EventSender.SendK8sEvent(apicommon.PhaseCreateTask, "Warning", task, apicommon.PhaseStateFailed, fmt.Sprintf("could not create Job: %s ", task.Name), "") return job.Name, err } - r.EventSender.SendK8sEvent(apicommon.PhaseReconcileTask, "Normal", task, "JobCreated", fmt.Sprintf("created Job: %s ", task.Name), "") return job.Name, nil } diff --git a/operator/controllers/lifecycle/keptntask/runtime_builder.go b/operator/controllers/lifecycle/keptntask/runtime_builder.go index a91644031d..633746c5a9 100644 --- a/operator/controllers/lifecycle/keptntask/runtime_builder.go +++ b/operator/controllers/lifecycle/keptntask/runtime_builder.go @@ -4,7 +4,7 @@ import ( "encoding/json" "fmt" - "github.com/imdario/mergo" + "dario.cat/mergo" klcv1alpha3 "github.com/keptn/lifecycle-toolkit/operator/apis/lifecycle/v1alpha3" apicommon "github.com/keptn/lifecycle-toolkit/operator/apis/lifecycle/v1alpha3/common" controllercommon "github.com/keptn/lifecycle-toolkit/operator/controllers/common" @@ -157,7 +157,7 @@ func (fb *RuntimeBuilder) getParams(ctx context.Context) (*RuntimeExecutionParam if len(fb.options.task.Spec.Parameters.Inline) > 0 { err = mergo.Merge(¶ms.Parameters, fb.options.task.Spec.Parameters.Inline) if err != nil { - fb.options.eventSender.SendK8sEvent(apicommon.PhaseCreateTask, "Warning", fb.options.task, "TaskDefinitionMergeFailure", fmt.Sprintf("could not merge KeptnTaskDefinition: %s ", fb.options.task.Spec.TaskDefinition), "") + fb.options.eventSender.SendK8sEvent(apicommon.PhaseCreateTask, "Warning", fb.options.task, apicommon.PhaseStateFailed, fmt.Sprintf("could not merge KeptnTaskDefinition: %s ", fb.options.task.Spec.TaskDefinition), "") return nil, err } } @@ -211,7 +211,7 @@ func (fb *RuntimeBuilder) handleParent(ctx context.Context, params *RuntimeExecu var parentJobParams RuntimeExecutionParams parentDefinition, err := controllercommon.GetTaskDefinition(fb.options.Client, fb.options.Log, ctx, fb.options.funcSpec.FunctionReference.Name, fb.options.req.Namespace) if err != nil { - fb.options.eventSender.SendK8sEvent(apicommon.PhaseCreateTask, "Warning", fb.options.task, "TaskDefinitionNotFound", fmt.Sprintf("could not find KeptnTaskDefinition: %s ", fb.options.task.Spec.TaskDefinition), "") + fb.options.eventSender.SendK8sEvent(apicommon.PhaseCreateTask, "Warning", fb.options.task, apicommon.PhaseStateNotFound, fmt.Sprintf("could not find KeptnTaskDefinition: %s ", fb.options.task.Spec.TaskDefinition), "") return err } parSpec := controllercommon.GetRuntimeSpec(parentDefinition) @@ -223,7 +223,7 @@ func (fb *RuntimeBuilder) handleParent(ctx context.Context, params *RuntimeExecu // merge parameter to make sure we use child task data for env var and secrets err = mergo.Merge(params, parentJobParams) if err != nil { - fb.options.eventSender.SendK8sEvent(apicommon.PhaseCreateTask, "Warning", fb.options.task, "TaskDefinitionMergeFailure", fmt.Sprintf("could not merge KeptnTaskDefinition: %s ", fb.options.task.Spec.TaskDefinition), "") + fb.options.eventSender.SendK8sEvent(apicommon.PhaseCreateTask, "Warning", fb.options.task, apicommon.PhaseStateFailed, fmt.Sprintf("could not merge KeptnTaskDefinition: %s ", fb.options.task.Spec.TaskDefinition), "") return err } diff --git a/operator/controllers/lifecycle/keptntaskdefinition/reconcile_function.go b/operator/controllers/lifecycle/keptntaskdefinition/reconcile_function.go index ffd57ee9ae..25d5d51f4d 100644 --- a/operator/controllers/lifecycle/keptntaskdefinition/reconcile_function.go +++ b/operator/controllers/lifecycle/keptntaskdefinition/reconcile_function.go @@ -31,18 +31,17 @@ func (r *KeptnTaskDefinitionReconciler) reconcileConfigMap(ctx context.Context, if (cm == nil || reflect.DeepEqual(cm, &corev1.ConfigMap{})) && functionCm != nil { //cm does not exist or new taskdef with inline func err := r.Client.Create(ctx, functionCm) if err != nil { - r.EventSender.SendK8sEvent(apicommon.PhaseReconcileTask, "Warning", functionCm, "ConfigMapNotCreated", "could not create configmap", "") + r.Log.Error(err, "could not create ConfigMap") + r.EventSender.SendK8sEvent(apicommon.PhaseReconcileTask, "Warning", functionCm, apicommon.PhaseStateFailed, "could not create configmap", "") return } - r.EventSender.SendK8sEvent(apicommon.PhaseReconcileTask, "Normal", functionCm, "ConfigMapCreated", "created configmap", "") - } else if !reflect.DeepEqual(cm, functionCm) && functionCm != nil { //cm and inline func exists but differ err := r.Client.Update(ctx, functionCm) if err != nil { - r.EventSender.SendK8sEvent(apicommon.PhaseReconcileTask, "Warning", functionCm, "ConfigMapNotUpdated", "uould not update configmap", "") + r.Log.Error(err, "could not update ConfigMap") + r.EventSender.SendK8sEvent(apicommon.PhaseReconcileTask, "Warning", functionCm, apicommon.PhaseStateFailed, "could not update configmap", "") return } - r.EventSender.SendK8sEvent(apicommon.PhaseReconcileTask, "Normal", functionCm, "ConfigMapUpdated", "updated configmap", "") } //nothing changed } diff --git a/operator/controllers/lifecycle/keptnworkload/controller.go b/operator/controllers/lifecycle/keptnworkload/controller.go index 682bc006f2..ee906024c7 100644 --- a/operator/controllers/lifecycle/keptnworkload/controller.go +++ b/operator/controllers/lifecycle/keptnworkload/controller.go @@ -102,12 +102,11 @@ func (r *KeptnWorkloadReconciler) Reconcile(ctx context.Context, req ctrl.Reques } err = r.Client.Create(ctx, workloadInstance) if err != nil { - r.Log.Error(err, "could not create Workload Instance") + r.Log.Error(err, "could not create WorkloadInstance") span.SetStatus(codes.Error, err.Error()) - r.EventSender.SendK8sEvent(apicommon.PhaseCreateWorklodInstance, "Warning", workloadInstance, "WorkloadInstanceNotCreated", "could not create KeptnWorkloadInstance ", workloadInstance.Spec.Version) + r.EventSender.SendK8sEvent(apicommon.PhaseCreateWorklodInstance, "Warning", workloadInstance, apicommon.PhaseStateFailed, "could not create KeptnWorkloadInstance ", workloadInstance.Spec.Version) return ctrl.Result{}, err } - r.EventSender.SendK8sEvent(apicommon.PhaseCreateWorklodInstance, "Normal", workloadInstance, "WorkloadInstanceCreated", "created KeptnWorkloadInstance ", workloadInstance.Spec.Version) workload.Status.CurrentVersion = workload.Spec.Version if err := r.Client.Status().Update(ctx, workload); err != nil { r.Log.Error(err, "could not update Current Version of Workload") @@ -116,7 +115,7 @@ func (r *KeptnWorkloadReconciler) Reconcile(ctx context.Context, req ctrl.Reques return ctrl.Result{}, nil } if err != nil { - r.Log.Error(err, "could not get Workload Instance") + r.Log.Error(err, "could not get WorkloadInstance") span.SetStatus(codes.Error, err.Error()) return ctrl.Result{}, err } diff --git a/operator/controllers/lifecycle/keptnworkloadinstance/controller.go b/operator/controllers/lifecycle/keptnworkloadinstance/controller.go index bc433d6fa7..23d3571b0d 100644 --- a/operator/controllers/lifecycle/keptnworkloadinstance/controller.go +++ b/operator/controllers/lifecycle/keptnworkloadinstance/controller.go @@ -72,7 +72,7 @@ type KeptnWorkloadInstanceReconciler struct { // //nolint:gocyclo func (r *KeptnWorkloadInstanceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - r.Log.Info("Searching for Keptn Workload Instance") + r.Log.Info("Searching for KeptnWorkloadInstance") // retrieve workload instance workloadInstance := &klcv1alpha3.KeptnWorkloadInstance{} @@ -82,7 +82,7 @@ func (r *KeptnWorkloadInstanceReconciler) Reconcile(ctx context.Context, req ctr } if err != nil { - r.Log.Error(err, "Workload Instance not found") + r.Log.Error(err, "WorkloadInstance not found") return reconcile.Result{}, fmt.Errorf(controllererrors.ErrCannotRetrieveWorkloadInstancesMsg, err) } @@ -113,7 +113,6 @@ func (r *KeptnWorkloadInstanceReconciler) Reconcile(ctx context.Context, req ctr if workloadInstance.Status.CurrentPhase == "" { spanWorkloadTrace.AddEvent("WorkloadInstance Pre-Deployment Tasks started", trace.WithTimestamp(time.Now())) - r.EventSender.SendK8sEvent(phase, "Normal", workloadInstance, "Started", "have started", workloadInstance.GetVersion()) } if !workloadInstance.IsPreDeploymentSucceeded() { @@ -191,6 +190,8 @@ func (r *KeptnWorkloadInstanceReconciler) finishKeptnWorkloadInstanceReconcile(c return ctrl.Result{Requeue: true}, err } + r.EventSender.SendK8sEvent(apicommon.PhaseWorkloadCompleted, "Normal", workloadInstance, apicommon.PhaseStateFinished, "has finished", workloadInstance.GetVersion()) + attrs := workloadInstance.GetMetricsAttributes() // metrics: add deployment duration @@ -204,8 +205,6 @@ func (r *KeptnWorkloadInstanceReconciler) finishKeptnWorkloadInstanceReconcile(c r.Log.Error(err, controllererrors.ErrCouldNotUnbindSpan, workloadInstance.Name) } - r.EventSender.SendK8sEvent(phase, "Normal", workloadInstance, "Finished", "is finished", workloadInstance.GetVersion()) - return ctrl.Result{}, nil } @@ -225,9 +224,8 @@ func (r *KeptnWorkloadInstanceReconciler) SetupWithManager(mgr ctrl.Manager) err func (r *KeptnWorkloadInstanceReconciler) sendUnfinishedPreEvaluationEvents(appPreEvalStatus apicommon.KeptnState, phase apicommon.KeptnPhaseType, workloadInstance *klcv1alpha3.KeptnWorkloadInstance) { if appPreEvalStatus.IsFailed() { - r.EventSender.SendK8sEvent(phase, "Warning", workloadInstance, "Failed", "has failed since app has failed", workloadInstance.GetVersion()) + r.EventSender.SendK8sEvent(phase, "Warning", workloadInstance, apicommon.PhaseStateFailed, "has failed since app has failed", workloadInstance.GetVersion()) } - r.EventSender.SendK8sEvent(phase, "Normal", workloadInstance, "NotFinished", "Pre evaluations tasks for app not finished", workloadInstance.GetVersion()) } func (r *KeptnWorkloadInstanceReconciler) setupSpansContexts(ctx context.Context, workloadInstance *klcv1alpha3.KeptnWorkloadInstance) (context.Context, trace.Span, func(span trace.Span, workloadInstance *klcv1alpha3.KeptnWorkloadInstance)) { @@ -276,8 +274,6 @@ func (r *KeptnWorkloadInstanceReconciler) checkPreEvaluationStatusOfApp(ctx cont return true, nil } - r.EventSender.SendK8sEvent(phase, "Normal", workloadInstance, "FinishedSuccess", "Pre evaluations tasks for app have finished successfully", workloadInstance.GetVersion()) - // set the App trace id if not already set if len(workloadInstance.Spec.TraceId) < 1 { appDeploymentTraceID := appVersion.Status.PhaseTraceIDs[apicommon.PhaseAppDeployment.ShortName] diff --git a/operator/controllers/lifecycle/keptnworkloadinstance/controller_test.go b/operator/controllers/lifecycle/keptnworkloadinstance/controller_test.go index de3f5165f3..67a5020cd6 100644 --- a/operator/controllers/lifecycle/keptnworkloadinstance/controller_test.go +++ b/operator/controllers/lifecycle/keptnworkloadinstance/controller_test.go @@ -801,7 +801,7 @@ func TestKeptnWorkloadInstanceReconciler_ReconcileNoActionRequired(t *testing.T) require.NotNil(t, result) } -func TestKeptnWorkloadInstanceReconciler_ReconcileDoNotStartBeforeAppPreEvaluationIsDone(t *testing.T) { +func TestKeptnWorkloadInstanceReconciler_ReconcileReachCompletion(t *testing.T) { r, eventChannel, _ := setupReconciler() testNamespace := "some-ns" @@ -821,7 +821,17 @@ func TestKeptnWorkloadInstanceReconciler_ReconcileDoNotStartBeforeAppPreEvaluati PreviousVersion: "", TraceId: nil, }, - Status: klcv1alpha3.KeptnWorkloadInstanceStatus{}, + Status: klcv1alpha3.KeptnWorkloadInstanceStatus{ + DeploymentStatus: apicommon.StateSucceeded, + PreDeploymentStatus: apicommon.StateSucceeded, + PostDeploymentStatus: apicommon.StateSucceeded, + PreDeploymentEvaluationStatus: apicommon.StateSucceeded, + PostDeploymentEvaluationStatus: apicommon.StateSucceeded, + CurrentPhase: apicommon.PhaseWorkloadPostEvaluation.ShortName, + Status: apicommon.StateSucceeded, + StartTime: metav1.Time{}, + EndTime: metav1.Time{}, + }, } err := r.Client.Create(context.TODO(), wi) @@ -839,7 +849,9 @@ func TestKeptnWorkloadInstanceReconciler_ReconcileDoNotStartBeforeAppPreEvaluati Version: "1.0.0", }, }, - klcv1alpha3.KeptnAppVersionStatus{}, + klcv1alpha3.KeptnAppVersionStatus{ + PreDeploymentEvaluationStatus: apicommon.StateSucceeded, + }, ) require.Nil(t, err) @@ -853,21 +865,25 @@ func TestKeptnWorkloadInstanceReconciler_ReconcileDoNotStartBeforeAppPreEvaluati result, err := r.Reconcile(context.TODO(), req) require.Nil(t, err) - require.True(t, result.Requeue) + // do not requeue since we reached completion + require.False(t, result.Requeue) + + // here we do not expect an event about the application preEvaluation being finished since that will have been sent in + // one of the previous reconciliation loops that lead to the first phase being reached expectedEvents := []string{ - "AppPreDeployEvaluationsNotFinished", + "CompletedFinished", } for _, e := range expectedEvents { event := <-eventChannel - assert.Equal(t, strings.Contains(event, req.Name), true, "wrong appversion") + assert.Equal(t, strings.Contains(event, req.Name), true, "wrong workloadinstance") assert.Equal(t, strings.Contains(event, req.Namespace), true, "wrong namespace") assert.Equal(t, strings.Contains(event, e), true, fmt.Sprintf("no %s found in %s", e, event)) } } -func TestKeptnWorkloadInstanceReconciler_ReconcileReachCompletion(t *testing.T) { +func TestKeptnWorkloadInstanceReconciler_ReconcileFailed(t *testing.T) { r, eventChannel, _ := setupReconciler() testNamespace := "some-ns" @@ -882,21 +898,29 @@ func TestKeptnWorkloadInstanceReconciler_ReconcileReachCompletion(t *testing.T) KeptnWorkloadSpec: klcv1alpha3.KeptnWorkloadSpec{ AppName: "some-app", Version: "1.0.0", + PreDeploymentTasks: []string{ + "task", + }, }, WorkloadName: "some-app-some-workload", PreviousVersion: "", TraceId: nil, }, Status: klcv1alpha3.KeptnWorkloadInstanceStatus{ - DeploymentStatus: apicommon.StateSucceeded, - PreDeploymentStatus: apicommon.StateSucceeded, - PostDeploymentStatus: apicommon.StateSucceeded, - PreDeploymentEvaluationStatus: apicommon.StateSucceeded, - PostDeploymentEvaluationStatus: apicommon.StateSucceeded, - CurrentPhase: apicommon.PhaseWorkloadPostEvaluation.ShortName, - Status: apicommon.StateSucceeded, - StartTime: metav1.Time{}, - EndTime: metav1.Time{}, + DeploymentStatus: apicommon.StatePending, + PreDeploymentStatus: apicommon.StateProgressing, + PostDeploymentStatus: apicommon.StatePending, + PreDeploymentEvaluationStatus: apicommon.StatePending, + PostDeploymentEvaluationStatus: apicommon.StatePending, + CurrentPhase: apicommon.PhaseWorkloadPreDeployment.ShortName, + Status: apicommon.StateProgressing, + PreDeploymentTaskStatus: []klcv1alpha3.ItemStatus{ + { + Name: "pre-task", + DefinitionName: "task", + Status: apicommon.StateFailed, + }, + }, }, } @@ -938,14 +962,14 @@ func TestKeptnWorkloadInstanceReconciler_ReconcileReachCompletion(t *testing.T) // here we do not expect an event about the application preEvaluation being finished since that will have been sent in // one of the previous reconciliation loops that lead to the first phase being reached expectedEvents := []string{ - "WorkloadPostDeployEvaluationsFinished", + "WorkloadPreDeployTasksFailed", } for _, e := range expectedEvents { event := <-eventChannel - assert.Equal(t, strings.Contains(event, req.Name), true, "wrong appversion") - assert.Equal(t, strings.Contains(event, req.Namespace), true, "wrong namespace") - assert.Equal(t, strings.Contains(event, e), true, fmt.Sprintf("no %s found in %s", e, event)) + require.Equal(t, strings.Contains(event, req.Name), true, "wrong workloadinstance") + require.Equal(t, strings.Contains(event, req.Namespace), true, "wrong namespace") + require.Equal(t, strings.Contains(event, e), true, fmt.Sprintf("no %s found in %s", e, event)) } } diff --git a/operator/go.mod b/operator/go.mod index 9e9eb2e6c8..e208e28d7b 100644 --- a/operator/go.mod +++ b/operator/go.mod @@ -3,12 +3,12 @@ module github.com/keptn/lifecycle-toolkit/operator go 1.20 require ( + dario.cat/mergo v1.0.0 github.com/argoproj/argo-rollouts v1.5.1 github.com/benbjohnson/clock v1.3.5 github.com/go-logr/logr v1.2.4 - github.com/imdario/mergo v0.3.16 github.com/kelseyhightower/envconfig v1.4.0 - github.com/keptn/lifecycle-toolkit/klt-cert-manager v0.0.0-20230630070122-4ad9bbf74960 + github.com/keptn/lifecycle-toolkit/klt-cert-manager v0.0.0-20230721062615-0b618c4bf152 github.com/magiconair/properties v1.8.7 github.com/onsi/ginkgo/v2 v2.11.0 github.com/onsi/gomega v1.27.8 @@ -23,7 +23,7 @@ require ( go.opentelemetry.io/otel/sdk v1.15.1 go.opentelemetry.io/otel/sdk/metric v0.38.1 go.opentelemetry.io/otel/trace v1.15.1 - google.golang.org/grpc v1.55.0 + google.golang.org/grpc v1.56.2 k8s.io/api v0.26.6 k8s.io/apiextensions-apiserver v0.26.6 k8s.io/apimachinery v0.26.6 @@ -68,6 +68,7 @@ require ( github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect github.com/google/uuid v1.3.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect + github.com/imdario/mergo v0.3.13 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/mailru/easyjson v0.7.7 // indirect @@ -89,7 +90,7 @@ require ( golang.org/x/tools v0.9.3 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/operator/go.sum b/operator/go.sum index e85415ac93..b221bfafe4 100644 --- a/operator/go.sum +++ b/operator/go.sum @@ -35,6 +35,8 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= @@ -195,8 +197,8 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 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.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= -github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= @@ -206,8 +208,8 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= -github.com/keptn/lifecycle-toolkit/klt-cert-manager v0.0.0-20230630070122-4ad9bbf74960 h1:SbVqELW4soNryi9Aq/rxAg0L9AwBevD8Tc1zcKcTMz0= -github.com/keptn/lifecycle-toolkit/klt-cert-manager v0.0.0-20230630070122-4ad9bbf74960/go.mod h1:CBNZ9l66hix9FW1Fs08MV3Xa5BxvFHyizMYObq9j7L8= +github.com/keptn/lifecycle-toolkit/klt-cert-manager v0.0.0-20230721062615-0b618c4bf152 h1:ohSCaA9U8NFit9XMEBymOsfqdjtoJzinqXGFqTkSWfE= +github.com/keptn/lifecycle-toolkit/klt-cert-manager v0.0.0-20230721062615-0b618c4bf152/go.mod h1:CBNZ9l66hix9FW1Fs08MV3Xa5BxvFHyizMYObq9j7L8= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= @@ -569,8 +571,8 @@ google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= -google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -591,8 +593,8 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= -google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= +google.golang.org/grpc v1.56.2 h1:fVRFRnXvU+x6C4IlHZewvJOVHoOv1TUuQyoRsYnB4bI= +google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -623,6 +625,7 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/operator/webhooks/pod_mutator/pod_mutating_webhook.go b/operator/webhooks/pod_mutator/pod_mutating_webhook.go index 3a43b61368..04f2e34aec 100644 --- a/operator/webhooks/pod_mutator/pod_mutating_webhook.go +++ b/operator/webhooks/pod_mutator/pod_mutating_webhook.go @@ -81,6 +81,15 @@ func (a *PodMutatingWebhook) Handle(ctx context.Context, req admission.Request) return admission.Allowed("namespace is not enabled for lifecycle controller") } + // check the OwnerReference of the pod to see if it is supported and intended to be managed by KLT + ownerRef := a.getOwnerReference(pod.ObjectMeta) + + if ownerRef.Kind == "" { + msg := "owner of pod is not supported by lifecycle controller" + logger.Info(msg, "namespace", req.Namespace, "pod", req.Name) + return admission.Allowed(msg) + } + logger.Info(fmt.Sprintf("Pod annotations: %v", pod.Annotations)) podIsAnnotated := a.isPodAnnotated(pod) @@ -139,7 +148,7 @@ func (a *PodMutatingWebhook) isPodAnnotated(pod *corev1.Pod) bool { } func (a *PodMutatingWebhook) copyAnnotationsIfParentAnnotated(ctx context.Context, req *admission.Request, pod *corev1.Pod) bool { - podOwner := a.getOwnerReference(&pod.ObjectMeta) + podOwner := a.getOwnerReference(pod.ObjectMeta) if podOwner.UID == "" { return false } @@ -152,7 +161,7 @@ func (a *PodMutatingWebhook) copyAnnotationsIfParentAnnotated(ctx context.Contex } a.Log.Info("Done fetching RS") - rsOwner := a.getOwnerReference(&rs.ObjectMeta) + rsOwner := a.getOwnerReference(rs.ObjectMeta) if rsOwner.UID == "" { return false } @@ -279,12 +288,11 @@ func (a *PodMutatingWebhook) handleWorkload(ctx context.Context, logger logr.Log err = a.Client.Create(ctx, workload) if err != nil { logger.Error(err, "Could not create Workload") - a.EventSender.SendK8sEvent(apicommon.PhaseCreateWorkload, "Warning", workload, "WorkloadNotCreated", "could not create KeptnWorkload", workload.Spec.Version) + a.EventSender.SendK8sEvent(apicommon.PhaseCreateWorkload, "Warning", workload, apicommon.PhaseStateFailed, "could not create KeptnWorkload", workload.Spec.Version) span.SetStatus(codes.Error, err.Error()) return err } - a.EventSender.SendK8sEvent(apicommon.PhaseCreateWorkload, "Normal", workload, "WorkloadCreated", "created KeptnWorkload", workload.Spec.Version) return nil } @@ -304,13 +312,11 @@ func (a *PodMutatingWebhook) handleWorkload(ctx context.Context, logger logr.Log err = a.Client.Update(ctx, workload) if err != nil { logger.Error(err, "Could not update Workload") - a.EventSender.SendK8sEvent(apicommon.PhaseCreateWorkload, "Warning", workload, "WorkloadNotUpdated", "could not update KeptnWorkload", workload.Spec.Version) + a.EventSender.SendK8sEvent(apicommon.PhaseUpdateWorkload, "Warning", workload, apicommon.PhaseStateFailed, "could not update KeptnWorkload", workload.Spec.Version) span.SetStatus(codes.Error, err.Error()) return err } - a.EventSender.SendK8sEvent(apicommon.PhaseCreateWorkload, "Normal", workload, "WorkloadUpdated", "updated KeptnWorkload", workload.Spec.Version) - return nil } @@ -333,13 +339,12 @@ func (a *PodMutatingWebhook) handleApp(ctx context.Context, logger logr.Logger, appCreationRequest = newAppCreationRequest err = a.Client.Create(ctx, appCreationRequest) if err != nil { - logger.Error(err, "Could not create App") - a.EventSender.SendK8sEvent(apicommon.PhaseCreateApp, "Warning", appCreationRequest, "AppCreationRequestNotCreated", "could not create KeptnAppCreationRequest", appCreationRequest.Spec.AppName) + logger.Error(err, "Could not create AppCreationRequest") + a.EventSender.SendK8sEvent(apicommon.PhaseCreateAppCreationRequest, "Warning", appCreationRequest, apicommon.PhaseStateFailed, "could not create KeptnAppCreationRequest", appCreationRequest.Spec.AppName) span.SetStatus(codes.Error, err.Error()) return err } - a.EventSender.SendK8sEvent(apicommon.PhaseCreateApp, "Normal", appCreationRequest, "AppCreationRequestCreated", "created KeptnAppCreationRequest", appCreationRequest.Spec.AppName) return nil } @@ -381,7 +386,7 @@ func (a *PodMutatingWebhook) generateWorkload(ctx context.Context, pod *corev1.P traceContextCarrier := propagation.MapCarrier{} otel.GetTextMapPropagator().Inject(ctx, traceContextCarrier) - ownerRef := a.getOwnerReference(&pod.ObjectMeta) + ownerRef := a.getOwnerReference(pod.ObjectMeta) return &klcv1alpha3.KeptnWorkload{ ObjectMeta: metav1.ObjectMeta{ @@ -441,11 +446,11 @@ func (a *PodMutatingWebhook) getAppName(pod *corev1.Pod) string { return strings.ToLower(applicationName) } -func (a *PodMutatingWebhook) getOwnerReference(resource *metav1.ObjectMeta) metav1.OwnerReference { +func (a *PodMutatingWebhook) getOwnerReference(resource metav1.ObjectMeta) metav1.OwnerReference { reference := metav1.OwnerReference{} if len(resource.OwnerReferences) != 0 { for _, owner := range resource.OwnerReferences { - if owner.Kind == "ReplicaSet" || owner.Kind == "Deployment" || owner.Kind == "StatefulSet" || owner.Kind == "DaemonSet" || owner.Kind == "Rollout" { + if apicommon.IsOwnerSupported(owner) { reference.UID = owner.UID reference.Kind = owner.Kind reference.Name = owner.Name diff --git a/operator/webhooks/pod_mutator/pod_mutating_webhook_test.go b/operator/webhooks/pod_mutator/pod_mutating_webhook_test.go index 7562b1d18b..764a79781c 100644 --- a/operator/webhooks/pod_mutator/pod_mutating_webhook_test.go +++ b/operator/webhooks/pod_mutator/pod_mutating_webhook_test.go @@ -17,6 +17,7 @@ import ( admissionv1 "k8s.io/api/admission/v1" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" @@ -34,7 +35,7 @@ func TestPodMutatingWebhook_getOwnerReference(t *testing.T) { Log logr.Logger } type args struct { - resource *metav1.ObjectMeta + resource metav1.ObjectMeta } tests := []struct { name string @@ -45,7 +46,7 @@ func TestPodMutatingWebhook_getOwnerReference(t *testing.T) { { name: "Test simple return when UID and Kind is set", args: args{ - resource: &metav1.ObjectMeta{ + resource: metav1.ObjectMeta{ UID: "the-pod-uid", OwnerReferences: []metav1.OwnerReference{ { @@ -65,7 +66,7 @@ func TestPodMutatingWebhook_getOwnerReference(t *testing.T) { { name: "Test return is input argument if owner is not found", args: args{ - resource: &metav1.ObjectMeta{ + resource: metav1.ObjectMeta{ UID: "the-pod-uid", OwnerReferences: []metav1.OwnerReference{ { @@ -1007,6 +1008,102 @@ func TestPodMutatingWebhook_Handle_DisabledNamespace(t *testing.T) { require.True(t, resp.Allowed) } +func TestPodMutatingWebhook_Handle_UnsupportedOwner(t *testing.T) { + fakeClient := fakeclient.NewClient(&corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "default", + Annotations: map[string]string{ + apicommon.NamespaceEnabledAnnotation: "enabled", + }, + }, + }) + + tr := &fakeclient.ITracerMock{StartFunc: func(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, trace.Span) { + return ctx, trace.SpanFromContext(ctx) + }} + + decoder, err := admission.NewDecoder(runtime.NewScheme()) + require.Nil(t, err) + + wh := &PodMutatingWebhook{ + Client: fakeClient, + Tracer: tr, + Decoder: decoder, + EventSender: controllercommon.NewEventSender(record.NewFakeRecorder(100)), + Log: testr.New(t), + } + + pod := &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "example-pod", + Namespace: "default", + Annotations: map[string]string{ + apicommon.WorkloadAnnotation: "my-workload", + apicommon.VersionAnnotation: "0.1", + }, + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: "batchv1", + Kind: "Job", + Name: "my-job", + UID: "1234", + }, + }, + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "example-container", + Image: "nginx", + }, + }, + }, + } + + // Convert the Pod object to a byte array + podBytes, err := json.Marshal(pod) + require.Nil(t, err) + + // Create an AdmissionRequest object + request := admissionv1.AdmissionRequest{ + UID: "12345", + Kind: metav1.GroupVersionKind{Group: "", Version: "v1", Kind: "Pod"}, + Operation: admissionv1.Create, + Object: runtime.RawExtension{ + Raw: podBytes, + }, + Namespace: "default", + } + + resp := wh.Handle(context.TODO(), admission.Request{ + AdmissionRequest: request, + }) + + require.NotNil(t, resp) + require.True(t, resp.Allowed) + + // if we get an unsupported owner for the pod, we expect not to have any KLT resources to have been created + kacr := &klcv1alpha3.KeptnAppCreationRequest{} + + err = fakeClient.Get(context.Background(), types.NamespacedName{ + Namespace: "default", + Name: "my-workload", + }, kacr) + + require.NotNil(t, err) + require.True(t, errors.IsNotFound(err)) + + workload := &klcv1alpha3.KeptnWorkload{} + + err = fakeClient.Get(context.TODO(), types.NamespacedName{ + Namespace: "default", + Name: "my-workload-my-workload", + }, workload) + + require.NotNil(t, err) + require.True(t, errors.IsNotFound(err)) +} + func TestPodMutatingWebhook_Handle_SingleService(t *testing.T) { fakeClient := fakeclient.NewClient(&corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ diff --git a/scheduler/go.mod b/scheduler/go.mod index 06c6204daf..7699d5a787 100644 --- a/scheduler/go.mod +++ b/scheduler/go.mod @@ -13,7 +13,7 @@ require ( go.opentelemetry.io/otel/exporters/stdout v0.20.0 go.opentelemetry.io/otel/sdk v0.20.0 go.opentelemetry.io/otel/trace v0.20.0 - google.golang.org/grpc v1.55.0 + google.golang.org/grpc v1.56.2 k8s.io/api v0.25.11 k8s.io/apimachinery v0.25.11 k8s.io/apiserver v0.25.11 @@ -69,7 +69,6 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.0.2 // indirect github.com/opencontainers/selinux v1.10.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.12.2 // indirect @@ -93,7 +92,7 @@ require ( go.uber.org/zap v1.21.0 // indirect golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd // indirect golang.org/x/net v0.10.0 // indirect - golang.org/x/oauth2 v0.6.0 // indirect + golang.org/x/oauth2 v0.7.0 // indirect golang.org/x/sync v0.2.0 // indirect golang.org/x/sys v0.9.0 // indirect golang.org/x/term v0.8.0 // indirect @@ -101,7 +100,7 @@ require ( golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect golang.org/x/tools v0.9.3 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect diff --git a/scheduler/go.sum b/scheduler/go.sum index a8b873feea..97fa5d2abe 100644 --- a/scheduler/go.sum +++ b/scheduler/go.sum @@ -20,7 +20,7 @@ cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvf cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.18.0 h1:FEigFqoDbys2cvFkZ9Fjq4gnHBP55anJ0yQyau2f9oY= +cloud.google.com/go/compute v1.19.1 h1:am86mquDUgjGNWxiGn+5PGLbmgiWXlE/yNWpIpNvuXY= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= @@ -71,6 +71,7 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= @@ -82,8 +83,6 @@ github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ 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/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= -github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= @@ -97,6 +96,7 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v0.10.1 h1:c0g45+xCJhdgFGw7a5QAfdS4byAbud7miNWJ1WwEVf8= github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= @@ -271,7 +271,6 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW 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.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= @@ -279,8 +278,6 @@ github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc= github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJKFnNQ= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= -github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/selinux v1.10.0 h1:rAiKF8hTcgLI3w0DHm6i0ylVVcOrlgR1kK99DRLDhyU= github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -449,8 +446,8 @@ golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw= -golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= +golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g= +golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -640,8 +637,8 @@ google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= -google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -658,8 +655,8 @@ google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTp google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= -google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= +google.golang.org/grpc v1.56.2 h1:fVRFRnXvU+x6C4IlHZewvJOVHoOv1TUuQyoRsYnB4bI= +google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -686,7 +683,6 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= 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= diff --git a/test/integration/unsupported-owner-of-pod/00-assert.yaml b/test/integration/unsupported-owner-of-pod/00-assert.yaml new file mode 100644 index 0000000000..1280385103 --- /dev/null +++ b/test/integration/unsupported-owner-of-pod/00-assert.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: Pod +metadata: + labels: + app: test diff --git a/test/integration/unsupported-owner-of-pod/00-install.yaml b/test/integration/unsupported-owner-of-pod/00-install.yaml new file mode 100644 index 0000000000..f933121e7e --- /dev/null +++ b/test/integration/unsupported-owner-of-pod/00-install.yaml @@ -0,0 +1,19 @@ +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: test +spec: + template: + metadata: + labels: + app: test + annotations: + keptn.sh/workload: waiter + keptn.sh/version: "0.4" + spec: + restartPolicy: Never + containers: + - name: init-myservice + image: busybox:1.36.1 + command: ['sh', '-c', 'sleep 60'] diff --git a/test/integration/unsupported-owner-of-pod/00-teststep.yaml b/test/integration/unsupported-owner-of-pod/00-teststep.yaml new file mode 100644 index 0000000000..ad4f1d95d5 --- /dev/null +++ b/test/integration/unsupported-owner-of-pod/00-teststep.yaml @@ -0,0 +1,4 @@ +apiVersion: kuttl.dev/v1 +kind: TestStep +commands: + - script: kubectl annotate ns $NAMESPACE keptn.sh/lifecycle-toolkit='enabled'