From cd2f8cbf71b7e8a792563a95578764cf48aa0dd4 Mon Sep 17 00:00:00 2001 From: Florian Bacher Date: Mon, 21 Nov 2022 15:51:59 +0100 Subject: [PATCH] feat(operator): store trace IDs for each phase of AppVersion Signed-off-by: Florian Bacher --- operator/api/v1alpha1/common/phases.go | 16 +- .../api/v1alpha1/keptnappversion_types.go | 21 +- .../v1alpha1/keptnworkloadinstance_types.go | 24 +- .../api/v1alpha1/zz_generated.deepcopy.go | 35 ++ .../lifecycle.keptn.sh_keptnappversions.yaml | 8 + ...cycle.keptn.sh_keptnworkloadinstances.yaml | 8 + .../controllers/common/fake/phaseitem_mock.go | 360 ++++++++++++------ operator/controllers/common/phaseitem.go | 8 +- operator/controllers/common/spanhandler.go | 11 +- operator/controllers/keptnapp/controller.go | 2 +- .../keptnworkloadinstance/controller.go | 34 +- 11 files changed, 378 insertions(+), 149 deletions(-) diff --git a/operator/api/v1alpha1/common/phases.go b/operator/api/v1alpha1/common/phases.go index 06f403d1012..54f09ae5ebf 100644 --- a/operator/api/v1alpha1/common/phases.go +++ b/operator/api/v1alpha1/common/phases.go @@ -1,6 +1,10 @@ package common -import "strings" +import ( + "strings" + + "go.opentelemetry.io/otel/propagation" +) type KeptnPhase KeptnPhaseType @@ -47,3 +51,13 @@ var ( PhaseCompleted = KeptnPhaseType{LongName: "Completed", ShortName: "Completed"} PhaseCancelled = KeptnPhaseType{LongName: "Cancelled", ShortName: "Cancelled"} ) + +type PhaseTraceID map[string]propagation.MapCarrier + +func (pid PhaseTraceID) SetPhaseTraceID(phase string, carrier propagation.MapCarrier) { + pid[phase] = carrier +} + +func (pid PhaseTraceID) GetPhaseTraceID(phase string) propagation.MapCarrier { + return pid[phase] +} diff --git a/operator/api/v1alpha1/keptnappversion_types.go b/operator/api/v1alpha1/keptnappversion_types.go index 16da556e681..cf0d41a8f18 100644 --- a/operator/api/v1alpha1/keptnappversion_types.go +++ b/operator/api/v1alpha1/keptnappversion_types.go @@ -52,13 +52,14 @@ type KeptnAppVersionStatus struct { // +kubebuilder:default:=Pending PostDeploymentEvaluationStatus common.KeptnState `json:"postDeploymentEvaluationStatus,omitempty"` // +kubebuilder:default:=Pending - WorkloadOverallStatus common.KeptnState `json:"workloadOverallStatus,omitempty"` - WorkloadStatus []WorkloadStatus `json:"workloadStatus,omitempty"` - CurrentPhase string `json:"currentPhase,omitempty"` - PreDeploymentTaskStatus []TaskStatus `json:"preDeploymentTaskStatus,omitempty"` - PostDeploymentTaskStatus []TaskStatus `json:"postDeploymentTaskStatus,omitempty"` - PreDeploymentEvaluationTaskStatus []EvaluationStatus `json:"preDeploymentEvaluationTaskStatus,omitempty"` - PostDeploymentEvaluationTaskStatus []EvaluationStatus `json:"postDeploymentEvaluationTaskStatus,omitempty"` + WorkloadOverallStatus common.KeptnState `json:"workloadOverallStatus,omitempty"` + WorkloadStatus []WorkloadStatus `json:"workloadStatus,omitempty"` + CurrentPhase string `json:"currentPhase,omitempty"` + PreDeploymentTaskStatus []TaskStatus `json:"preDeploymentTaskStatus,omitempty"` + PostDeploymentTaskStatus []TaskStatus `json:"postDeploymentTaskStatus,omitempty"` + PreDeploymentEvaluationTaskStatus []EvaluationStatus `json:"preDeploymentEvaluationTaskStatus,omitempty"` + PostDeploymentEvaluationTaskStatus []EvaluationStatus `json:"postDeploymentEvaluationTaskStatus,omitempty"` + PhaseTraceIDs map[string]propagation.MapCarrier `json:"phaseTraceIDs,omitempty"` // +kubebuilder:default:=Pending Status common.KeptnState `json:"status,omitempty"` @@ -373,5 +374,11 @@ func (a *KeptnAppVersion) CancelRemainingPhases(phase common.KeptnPhaseType) { a.Status.PostDeploymentStatus = common.StateCancelled a.Status.PostDeploymentEvaluationStatus = common.StateCancelled a.Status.Status = common.StateFailed +} +func (a *KeptnAppVersion) SetPhaseTraceID(phase string, carrier propagation.MapCarrier) { + if a.Status.PhaseTraceIDs == nil { + a.Status.PhaseTraceIDs = map[string]propagation.MapCarrier{} + } + a.Status.PhaseTraceIDs[phase] = carrier } diff --git a/operator/api/v1alpha1/keptnworkloadinstance_types.go b/operator/api/v1alpha1/keptnworkloadinstance_types.go index 0400e2bb8a6..9ae58c1c6fb 100644 --- a/operator/api/v1alpha1/keptnworkloadinstance_types.go +++ b/operator/api/v1alpha1/keptnworkloadinstance_types.go @@ -50,14 +50,15 @@ type KeptnWorkloadInstanceStatus struct { // +kubebuilder:default:=Pending PostDeploymentEvaluationStatus common.KeptnState `json:"postDeploymentEvaluationStatus,omitempty"` // +kubebuilder:default:=Pending - PostDeploymentStatus common.KeptnState `json:"postDeploymentStatus,omitempty"` - PreDeploymentTaskStatus []TaskStatus `json:"preDeploymentTaskStatus,omitempty"` - PostDeploymentTaskStatus []TaskStatus `json:"postDeploymentTaskStatus,omitempty"` - PreDeploymentEvaluationTaskStatus []EvaluationStatus `json:"preDeploymentEvaluationTaskStatus,omitempty"` - PostDeploymentEvaluationTaskStatus []EvaluationStatus `json:"postDeploymentEvaluationTaskStatus,omitempty"` - StartTime metav1.Time `json:"startTime,omitempty"` - EndTime metav1.Time `json:"endTime,omitempty"` - CurrentPhase string `json:"currentPhase,omitempty"` + PostDeploymentStatus common.KeptnState `json:"postDeploymentStatus,omitempty"` + PreDeploymentTaskStatus []TaskStatus `json:"preDeploymentTaskStatus,omitempty"` + PostDeploymentTaskStatus []TaskStatus `json:"postDeploymentTaskStatus,omitempty"` + PreDeploymentEvaluationTaskStatus []EvaluationStatus `json:"preDeploymentEvaluationTaskStatus,omitempty"` + PostDeploymentEvaluationTaskStatus []EvaluationStatus `json:"postDeploymentEvaluationTaskStatus,omitempty"` + StartTime metav1.Time `json:"startTime,omitempty"` + EndTime metav1.Time `json:"endTime,omitempty"` + CurrentPhase string `json:"currentPhase,omitempty"` + PhaseTraceIDs map[string]propagation.MapCarrier `json:"phaseTraceIDs,omitempty"` // +kubebuilder:default:=Pending Status common.KeptnState `json:"status,omitempty"` } @@ -411,3 +412,10 @@ func (w *KeptnWorkloadInstance) CancelRemainingPhases(phase common.KeptnPhaseTyp w.Status.PostDeploymentEvaluationStatus = common.StateCancelled w.Status.Status = common.StateFailed } + +func (w *KeptnWorkloadInstance) SetPhaseTraceID(phase string, carrier propagation.MapCarrier) { + if w.Status.PhaseTraceIDs == nil { + w.Status.PhaseTraceIDs = map[string]propagation.MapCarrier{} + } + w.Status.PhaseTraceIDs[phase] = carrier +} diff --git a/operator/api/v1alpha1/zz_generated.deepcopy.go b/operator/api/v1alpha1/zz_generated.deepcopy.go index 63a9da4e5bd..413cb65468c 100644 --- a/operator/api/v1alpha1/zz_generated.deepcopy.go +++ b/operator/api/v1alpha1/zz_generated.deepcopy.go @@ -22,6 +22,7 @@ limitations under the License. package v1alpha1 import ( + "go.opentelemetry.io/otel/propagation" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -400,6 +401,23 @@ func (in *KeptnAppVersionStatus) DeepCopyInto(out *KeptnAppVersionStatus) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.PhaseTraceIDs != nil { + in, out := &in.PhaseTraceIDs, &out.PhaseTraceIDs + *out = make(map[string]propagation.MapCarrier, len(*in)) + for key, val := range *in { + var outVal map[string]string + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = make(propagation.MapCarrier, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + (*out)[key] = outVal + } + } in.StartTime.DeepCopyInto(&out.StartTime) in.EndTime.DeepCopyInto(&out.EndTime) } @@ -1023,6 +1041,23 @@ func (in *KeptnWorkloadInstanceStatus) DeepCopyInto(out *KeptnWorkloadInstanceSt } in.StartTime.DeepCopyInto(&out.StartTime) in.EndTime.DeepCopyInto(&out.EndTime) + if in.PhaseTraceIDs != nil { + in, out := &in.PhaseTraceIDs, &out.PhaseTraceIDs + *out = make(map[string]propagation.MapCarrier, len(*in)) + for key, val := range *in { + var outVal map[string]string + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = make(propagation.MapCarrier, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + (*out)[key] = outVal + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeptnWorkloadInstanceStatus. diff --git a/operator/config/crd/bases/lifecycle.keptn.sh_keptnappversions.yaml b/operator/config/crd/bases/lifecycle.keptn.sh_keptnappversions.yaml index 0728af1b288..0399839fe0e 100644 --- a/operator/config/crd/bases/lifecycle.keptn.sh_keptnappversions.yaml +++ b/operator/config/crd/bases/lifecycle.keptn.sh_keptnappversions.yaml @@ -117,6 +117,14 @@ spec: endTime: format: date-time type: string + phaseTraceIDs: + additionalProperties: + additionalProperties: + type: string + description: MapCarrier is a TextMapCarrier that uses a map held + in memory as a storage medium for propagated key-value pairs. + type: object + type: object postDeploymentEvaluationStatus: default: Pending type: string diff --git a/operator/config/crd/bases/lifecycle.keptn.sh_keptnworkloadinstances.yaml b/operator/config/crd/bases/lifecycle.keptn.sh_keptnworkloadinstances.yaml index 5b72b0bda05..f9b30dc12cd 100644 --- a/operator/config/crd/bases/lifecycle.keptn.sh_keptnworkloadinstances.yaml +++ b/operator/config/crd/bases/lifecycle.keptn.sh_keptnworkloadinstances.yaml @@ -134,6 +134,14 @@ spec: endTime: format: date-time type: string + phaseTraceIDs: + additionalProperties: + additionalProperties: + type: string + description: MapCarrier is a TextMapCarrier that uses a map held + in memory as a storage medium for propagated key-value pairs. + type: object + type: object postDeploymentEvaluationStatus: default: Pending type: string diff --git a/operator/controllers/common/fake/phaseitem_mock.go b/operator/controllers/common/fake/phaseitem_mock.go index 98369f66d66..9d7ffee5aea 100644 --- a/operator/controllers/common/fake/phaseitem_mock.go +++ b/operator/controllers/common/fake/phaseitem_mock.go @@ -15,100 +15,106 @@ import ( // PhaseItemMock is a mock implementation of common.PhaseItem. // -// func TestSomethingThatUsesPhaseItem(t *testing.T) { +// func TestSomethingThatUsesPhaseItem(t *testing.T) { // -// // make and configure a mocked common.PhaseItem -// mockedPhaseItem := &PhaseItemMock{ -// CancelRemainingPhasesFunc: func(phase apicommon.KeptnPhaseType) { -// panic("mock out the CancelRemainingPhases method") -// }, -// CompleteFunc: func() { -// panic("mock out the Complete method") -// }, -// GenerateEvaluationFunc: func(traceContextCarrier propagation.MapCarrier, evaluationDefinition string, checkType apicommon.CheckType) klcv1alpha1.KeptnEvaluation { -// panic("mock out the GenerateEvaluation method") -// }, -// GenerateTaskFunc: func(traceContextCarrier propagation.MapCarrier, taskDefinition string, checkType apicommon.CheckType) klcv1alpha1.KeptnTask { -// panic("mock out the GenerateTask method") -// }, -// GetAppNameFunc: func() string { -// panic("mock out the GetAppName method") -// }, -// GetCurrentPhaseFunc: func() string { -// panic("mock out the GetCurrentPhase method") -// }, -// GetEndTimeFunc: func() time.Time { -// panic("mock out the GetEndTime method") -// }, -// GetNamespaceFunc: func() string { -// panic("mock out the GetNamespace method") -// }, -// GetParentNameFunc: func() string { -// panic("mock out the GetParentName method") -// }, -// GetPostDeploymentEvaluationTaskStatusFunc: func() []klcv1alpha1.EvaluationStatus { -// panic("mock out the GetPostDeploymentEvaluationTaskStatus method") -// }, -// GetPostDeploymentEvaluationsFunc: func() []string { -// panic("mock out the GetPostDeploymentEvaluations method") -// }, -// GetPostDeploymentTaskStatusFunc: func() []klcv1alpha1.TaskStatus { -// panic("mock out the GetPostDeploymentTaskStatus method") -// }, -// GetPostDeploymentTasksFunc: func() []string { -// panic("mock out the GetPostDeploymentTasks method") -// }, -// GetPreDeploymentEvaluationTaskStatusFunc: func() []klcv1alpha1.EvaluationStatus { -// panic("mock out the GetPreDeploymentEvaluationTaskStatus method") -// }, -// GetPreDeploymentEvaluationsFunc: func() []string { -// panic("mock out the GetPreDeploymentEvaluations method") -// }, -// GetPreDeploymentTaskStatusFunc: func() []klcv1alpha1.TaskStatus { -// panic("mock out the GetPreDeploymentTaskStatus method") -// }, -// GetPreDeploymentTasksFunc: func() []string { -// panic("mock out the GetPreDeploymentTasks method") -// }, -// GetPreviousVersionFunc: func() string { -// panic("mock out the GetPreviousVersion method") -// }, -// GetSpanAttributesFunc: func() []attribute.KeyValue { -// panic("mock out the GetSpanAttributes method") -// }, -// GetSpanKeyFunc: func(phase string) string { -// panic("mock out the GetSpanKey method") -// }, -// GetSpanNameFunc: func(phase string) string { -// panic("mock out the GetSpanName method") -// }, -// GetStartTimeFunc: func() time.Time { -// panic("mock out the GetStartTime method") -// }, -// GetStateFunc: func() apicommon.KeptnState { -// panic("mock out the GetState method") -// }, -// GetVersionFunc: func() string { -// panic("mock out the GetVersion method") -// }, -// IsEndTimeSetFunc: func() bool { -// panic("mock out the IsEndTimeSet method") -// }, -// SetCurrentPhaseFunc: func(s string) { -// panic("mock out the SetCurrentPhase method") -// }, -// SetSpanAttributesFunc: func(span trace.Span) { -// panic("mock out the SetSpanAttributes method") -// }, -// SetStateFunc: func(keptnState apicommon.KeptnState) { -// panic("mock out the SetState method") -// }, -// } +// // make and configure a mocked common.PhaseItem +// mockedPhaseItem := &PhaseItemMock{ +// CancelRemainingPhasesFunc: func(phase apicommon.KeptnPhaseType) { +// panic("mock out the CancelRemainingPhases method") +// }, +// CompleteFunc: func() { +// panic("mock out the Complete method") +// }, +// GenerateEvaluationFunc: func(traceContextCarrier propagation.MapCarrier, evaluationDefinition string, checkType apicommon.CheckType) klcv1alpha1.KeptnEvaluation { +// panic("mock out the GenerateEvaluation method") +// }, +// GenerateTaskFunc: func(traceContextCarrier propagation.MapCarrier, taskDefinition string, checkType apicommon.CheckType) klcv1alpha1.KeptnTask { +// panic("mock out the GenerateTask method") +// }, +// GetAppNameFunc: func() string { +// panic("mock out the GetAppName method") +// }, +// GetCurrentPhaseFunc: func() string { +// panic("mock out the GetCurrentPhase method") +// }, +// GetEndTimeFunc: func() time.Time { +// panic("mock out the GetEndTime method") +// }, +// GetNamespaceFunc: func() string { +// panic("mock out the GetNamespace method") +// }, +// GetParentNameFunc: func() string { +// panic("mock out the GetParentName method") +// }, +// GetPhaseTraceIDFunc: func(phase string) propagation.MapCarrier { +// panic("mock out the GetPhaseTraceID method") +// }, +// GetPostDeploymentEvaluationTaskStatusFunc: func() []klcv1alpha1.EvaluationStatus { +// panic("mock out the GetPostDeploymentEvaluationTaskStatus method") +// }, +// GetPostDeploymentEvaluationsFunc: func() []string { +// panic("mock out the GetPostDeploymentEvaluations method") +// }, +// GetPostDeploymentTaskStatusFunc: func() []klcv1alpha1.TaskStatus { +// panic("mock out the GetPostDeploymentTaskStatus method") +// }, +// GetPostDeploymentTasksFunc: func() []string { +// panic("mock out the GetPostDeploymentTasks method") +// }, +// GetPreDeploymentEvaluationTaskStatusFunc: func() []klcv1alpha1.EvaluationStatus { +// panic("mock out the GetPreDeploymentEvaluationTaskStatus method") +// }, +// GetPreDeploymentEvaluationsFunc: func() []string { +// panic("mock out the GetPreDeploymentEvaluations method") +// }, +// GetPreDeploymentTaskStatusFunc: func() []klcv1alpha1.TaskStatus { +// panic("mock out the GetPreDeploymentTaskStatus method") +// }, +// GetPreDeploymentTasksFunc: func() []string { +// panic("mock out the GetPreDeploymentTasks method") +// }, +// GetPreviousVersionFunc: func() string { +// panic("mock out the GetPreviousVersion method") +// }, +// GetSpanAttributesFunc: func() []attribute.KeyValue { +// panic("mock out the GetSpanAttributes method") +// }, +// GetSpanKeyFunc: func(phase string) string { +// panic("mock out the GetSpanKey method") +// }, +// GetSpanNameFunc: func(phase string) string { +// panic("mock out the GetSpanName method") +// }, +// GetStartTimeFunc: func() time.Time { +// panic("mock out the GetStartTime method") +// }, +// GetStateFunc: func() apicommon.KeptnState { +// panic("mock out the GetState method") +// }, +// GetVersionFunc: func() string { +// panic("mock out the GetVersion method") +// }, +// IsEndTimeSetFunc: func() bool { +// panic("mock out the IsEndTimeSet method") +// }, +// SetCurrentPhaseFunc: func(s string) { +// panic("mock out the SetCurrentPhase method") +// }, +// SetPhaseTraceIDFunc: func(phase string, carrier propagation.MapCarrier) { +// panic("mock out the SetPhaseTraceID method") +// }, +// SetSpanAttributesFunc: func(span trace.Span) { +// panic("mock out the SetSpanAttributes method") +// }, +// SetStateFunc: func(keptnState apicommon.KeptnState) { +// panic("mock out the SetState method") +// }, +// } // -// // use mockedPhaseItem in code that requires common.PhaseItem -// // and then make assertions. +// // use mockedPhaseItem in code that requires common.PhaseItem +// // and then make assertions. // -// } +// } type PhaseItemMock struct { // CancelRemainingPhasesFunc mocks the CancelRemainingPhases method. CancelRemainingPhasesFunc func(phase apicommon.KeptnPhaseType) @@ -137,6 +143,9 @@ type PhaseItemMock struct { // GetParentNameFunc mocks the GetParentName method. GetParentNameFunc func() string + // GetPhaseTraceIDFunc mocks the GetPhaseTraceID method. + GetPhaseTraceIDFunc func(phase string) propagation.MapCarrier + // GetPostDeploymentEvaluationTaskStatusFunc mocks the GetPostDeploymentEvaluationTaskStatus method. GetPostDeploymentEvaluationTaskStatusFunc func() []klcv1alpha1.EvaluationStatus @@ -188,6 +197,9 @@ type PhaseItemMock struct { // SetCurrentPhaseFunc mocks the SetCurrentPhase method. SetCurrentPhaseFunc func(s string) + // SetPhaseTraceIDFunc mocks the SetPhaseTraceID method. + SetPhaseTraceIDFunc func(phase string, carrier propagation.MapCarrier) + // SetSpanAttributesFunc mocks the SetSpanAttributes method. SetSpanAttributesFunc func(span trace.Span) @@ -237,6 +249,11 @@ type PhaseItemMock struct { // GetParentName holds details about calls to the GetParentName method. GetParentName []struct { } + // GetPhaseTraceID holds details about calls to the GetPhaseTraceID method. + GetPhaseTraceID []struct { + // Phase is the phase argument value. + Phase string + } // GetPostDeploymentEvaluationTaskStatus holds details about calls to the GetPostDeploymentEvaluationTaskStatus method. GetPostDeploymentEvaluationTaskStatus []struct { } @@ -294,6 +311,13 @@ type PhaseItemMock struct { // S is the s argument value. S string } + // SetPhaseTraceID holds details about calls to the SetPhaseTraceID method. + SetPhaseTraceID []struct { + // Phase is the phase argument value. + Phase string + // Carrier is the carrier argument value. + Carrier propagation.MapCarrier + } // SetSpanAttributes holds details about calls to the SetSpanAttributes method. SetSpanAttributes []struct { // Span is the span argument value. @@ -314,6 +338,7 @@ type PhaseItemMock struct { lockGetEndTime sync.RWMutex lockGetNamespace sync.RWMutex lockGetParentName sync.RWMutex + lockGetPhaseTraceID sync.RWMutex lockGetPostDeploymentEvaluationTaskStatus sync.RWMutex lockGetPostDeploymentEvaluations sync.RWMutex lockGetPostDeploymentTaskStatus sync.RWMutex @@ -331,6 +356,7 @@ type PhaseItemMock struct { lockGetVersion sync.RWMutex lockIsEndTimeSet sync.RWMutex lockSetCurrentPhase sync.RWMutex + lockSetPhaseTraceID sync.RWMutex lockSetSpanAttributes sync.RWMutex lockSetState sync.RWMutex } @@ -353,7 +379,8 @@ func (mock *PhaseItemMock) CancelRemainingPhases(phase apicommon.KeptnPhaseType) // CancelRemainingPhasesCalls gets all the calls that were made to CancelRemainingPhases. // Check the length with: -// len(mockedPhaseItem.CancelRemainingPhasesCalls()) +// +// len(mockedPhaseItem.CancelRemainingPhasesCalls()) func (mock *PhaseItemMock) CancelRemainingPhasesCalls() []struct { Phase apicommon.KeptnPhaseType } { @@ -381,7 +408,8 @@ func (mock *PhaseItemMock) Complete() { // CompleteCalls gets all the calls that were made to Complete. // Check the length with: -// len(mockedPhaseItem.CompleteCalls()) +// +// len(mockedPhaseItem.CompleteCalls()) func (mock *PhaseItemMock) CompleteCalls() []struct { } { var calls []struct { @@ -414,7 +442,8 @@ func (mock *PhaseItemMock) GenerateEvaluation(traceContextCarrier propagation.Ma // GenerateEvaluationCalls gets all the calls that were made to GenerateEvaluation. // Check the length with: -// len(mockedPhaseItem.GenerateEvaluationCalls()) +// +// len(mockedPhaseItem.GenerateEvaluationCalls()) func (mock *PhaseItemMock) GenerateEvaluationCalls() []struct { TraceContextCarrier propagation.MapCarrier EvaluationDefinition string @@ -453,7 +482,8 @@ func (mock *PhaseItemMock) GenerateTask(traceContextCarrier propagation.MapCarri // GenerateTaskCalls gets all the calls that were made to GenerateTask. // Check the length with: -// len(mockedPhaseItem.GenerateTaskCalls()) +// +// len(mockedPhaseItem.GenerateTaskCalls()) func (mock *PhaseItemMock) GenerateTaskCalls() []struct { TraceContextCarrier propagation.MapCarrier TaskDefinition string @@ -485,7 +515,8 @@ func (mock *PhaseItemMock) GetAppName() string { // GetAppNameCalls gets all the calls that were made to GetAppName. // Check the length with: -// len(mockedPhaseItem.GetAppNameCalls()) +// +// len(mockedPhaseItem.GetAppNameCalls()) func (mock *PhaseItemMock) GetAppNameCalls() []struct { } { var calls []struct { @@ -511,7 +542,8 @@ func (mock *PhaseItemMock) GetCurrentPhase() string { // GetCurrentPhaseCalls gets all the calls that were made to GetCurrentPhase. // Check the length with: -// len(mockedPhaseItem.GetCurrentPhaseCalls()) +// +// len(mockedPhaseItem.GetCurrentPhaseCalls()) func (mock *PhaseItemMock) GetCurrentPhaseCalls() []struct { } { var calls []struct { @@ -537,7 +569,8 @@ func (mock *PhaseItemMock) GetEndTime() time.Time { // GetEndTimeCalls gets all the calls that were made to GetEndTime. // Check the length with: -// len(mockedPhaseItem.GetEndTimeCalls()) +// +// len(mockedPhaseItem.GetEndTimeCalls()) func (mock *PhaseItemMock) GetEndTimeCalls() []struct { } { var calls []struct { @@ -563,7 +596,8 @@ func (mock *PhaseItemMock) GetNamespace() string { // GetNamespaceCalls gets all the calls that were made to GetNamespace. // Check the length with: -// len(mockedPhaseItem.GetNamespaceCalls()) +// +// len(mockedPhaseItem.GetNamespaceCalls()) func (mock *PhaseItemMock) GetNamespaceCalls() []struct { } { var calls []struct { @@ -589,7 +623,8 @@ func (mock *PhaseItemMock) GetParentName() string { // GetParentNameCalls gets all the calls that were made to GetParentName. // Check the length with: -// len(mockedPhaseItem.GetParentNameCalls()) +// +// len(mockedPhaseItem.GetParentNameCalls()) func (mock *PhaseItemMock) GetParentNameCalls() []struct { } { var calls []struct { @@ -600,6 +635,38 @@ func (mock *PhaseItemMock) GetParentNameCalls() []struct { return calls } +// GetPhaseTraceID calls GetPhaseTraceIDFunc. +func (mock *PhaseItemMock) GetPhaseTraceID(phase string) propagation.MapCarrier { + if mock.GetPhaseTraceIDFunc == nil { + panic("PhaseItemMock.GetPhaseTraceIDFunc: method is nil but PhaseItem.GetPhaseTraceID was just called") + } + callInfo := struct { + Phase string + }{ + Phase: phase, + } + mock.lockGetPhaseTraceID.Lock() + mock.calls.GetPhaseTraceID = append(mock.calls.GetPhaseTraceID, callInfo) + mock.lockGetPhaseTraceID.Unlock() + return mock.GetPhaseTraceIDFunc(phase) +} + +// GetPhaseTraceIDCalls gets all the calls that were made to GetPhaseTraceID. +// Check the length with: +// +// len(mockedPhaseItem.GetPhaseTraceIDCalls()) +func (mock *PhaseItemMock) GetPhaseTraceIDCalls() []struct { + Phase string +} { + var calls []struct { + Phase string + } + mock.lockGetPhaseTraceID.RLock() + calls = mock.calls.GetPhaseTraceID + mock.lockGetPhaseTraceID.RUnlock() + return calls +} + // GetPostDeploymentEvaluationTaskStatus calls GetPostDeploymentEvaluationTaskStatusFunc. func (mock *PhaseItemMock) GetPostDeploymentEvaluationTaskStatus() []klcv1alpha1.EvaluationStatus { if mock.GetPostDeploymentEvaluationTaskStatusFunc == nil { @@ -615,7 +682,8 @@ func (mock *PhaseItemMock) GetPostDeploymentEvaluationTaskStatus() []klcv1alpha1 // GetPostDeploymentEvaluationTaskStatusCalls gets all the calls that were made to GetPostDeploymentEvaluationTaskStatus. // Check the length with: -// len(mockedPhaseItem.GetPostDeploymentEvaluationTaskStatusCalls()) +// +// len(mockedPhaseItem.GetPostDeploymentEvaluationTaskStatusCalls()) func (mock *PhaseItemMock) GetPostDeploymentEvaluationTaskStatusCalls() []struct { } { var calls []struct { @@ -641,7 +709,8 @@ func (mock *PhaseItemMock) GetPostDeploymentEvaluations() []string { // GetPostDeploymentEvaluationsCalls gets all the calls that were made to GetPostDeploymentEvaluations. // Check the length with: -// len(mockedPhaseItem.GetPostDeploymentEvaluationsCalls()) +// +// len(mockedPhaseItem.GetPostDeploymentEvaluationsCalls()) func (mock *PhaseItemMock) GetPostDeploymentEvaluationsCalls() []struct { } { var calls []struct { @@ -667,7 +736,8 @@ func (mock *PhaseItemMock) GetPostDeploymentTaskStatus() []klcv1alpha1.TaskStatu // GetPostDeploymentTaskStatusCalls gets all the calls that were made to GetPostDeploymentTaskStatus. // Check the length with: -// len(mockedPhaseItem.GetPostDeploymentTaskStatusCalls()) +// +// len(mockedPhaseItem.GetPostDeploymentTaskStatusCalls()) func (mock *PhaseItemMock) GetPostDeploymentTaskStatusCalls() []struct { } { var calls []struct { @@ -693,7 +763,8 @@ func (mock *PhaseItemMock) GetPostDeploymentTasks() []string { // GetPostDeploymentTasksCalls gets all the calls that were made to GetPostDeploymentTasks. // Check the length with: -// len(mockedPhaseItem.GetPostDeploymentTasksCalls()) +// +// len(mockedPhaseItem.GetPostDeploymentTasksCalls()) func (mock *PhaseItemMock) GetPostDeploymentTasksCalls() []struct { } { var calls []struct { @@ -719,7 +790,8 @@ func (mock *PhaseItemMock) GetPreDeploymentEvaluationTaskStatus() []klcv1alpha1. // GetPreDeploymentEvaluationTaskStatusCalls gets all the calls that were made to GetPreDeploymentEvaluationTaskStatus. // Check the length with: -// len(mockedPhaseItem.GetPreDeploymentEvaluationTaskStatusCalls()) +// +// len(mockedPhaseItem.GetPreDeploymentEvaluationTaskStatusCalls()) func (mock *PhaseItemMock) GetPreDeploymentEvaluationTaskStatusCalls() []struct { } { var calls []struct { @@ -745,7 +817,8 @@ func (mock *PhaseItemMock) GetPreDeploymentEvaluations() []string { // GetPreDeploymentEvaluationsCalls gets all the calls that were made to GetPreDeploymentEvaluations. // Check the length with: -// len(mockedPhaseItem.GetPreDeploymentEvaluationsCalls()) +// +// len(mockedPhaseItem.GetPreDeploymentEvaluationsCalls()) func (mock *PhaseItemMock) GetPreDeploymentEvaluationsCalls() []struct { } { var calls []struct { @@ -771,7 +844,8 @@ func (mock *PhaseItemMock) GetPreDeploymentTaskStatus() []klcv1alpha1.TaskStatus // GetPreDeploymentTaskStatusCalls gets all the calls that were made to GetPreDeploymentTaskStatus. // Check the length with: -// len(mockedPhaseItem.GetPreDeploymentTaskStatusCalls()) +// +// len(mockedPhaseItem.GetPreDeploymentTaskStatusCalls()) func (mock *PhaseItemMock) GetPreDeploymentTaskStatusCalls() []struct { } { var calls []struct { @@ -797,7 +871,8 @@ func (mock *PhaseItemMock) GetPreDeploymentTasks() []string { // GetPreDeploymentTasksCalls gets all the calls that were made to GetPreDeploymentTasks. // Check the length with: -// len(mockedPhaseItem.GetPreDeploymentTasksCalls()) +// +// len(mockedPhaseItem.GetPreDeploymentTasksCalls()) func (mock *PhaseItemMock) GetPreDeploymentTasksCalls() []struct { } { var calls []struct { @@ -823,7 +898,8 @@ func (mock *PhaseItemMock) GetPreviousVersion() string { // GetPreviousVersionCalls gets all the calls that were made to GetPreviousVersion. // Check the length with: -// len(mockedPhaseItem.GetPreviousVersionCalls()) +// +// len(mockedPhaseItem.GetPreviousVersionCalls()) func (mock *PhaseItemMock) GetPreviousVersionCalls() []struct { } { var calls []struct { @@ -849,7 +925,8 @@ func (mock *PhaseItemMock) GetSpanAttributes() []attribute.KeyValue { // GetSpanAttributesCalls gets all the calls that were made to GetSpanAttributes. // Check the length with: -// len(mockedPhaseItem.GetSpanAttributesCalls()) +// +// len(mockedPhaseItem.GetSpanAttributesCalls()) func (mock *PhaseItemMock) GetSpanAttributesCalls() []struct { } { var calls []struct { @@ -878,7 +955,8 @@ func (mock *PhaseItemMock) GetSpanKey(phase string) string { // GetSpanKeyCalls gets all the calls that were made to GetSpanKey. // Check the length with: -// len(mockedPhaseItem.GetSpanKeyCalls()) +// +// len(mockedPhaseItem.GetSpanKeyCalls()) func (mock *PhaseItemMock) GetSpanKeyCalls() []struct { Phase string } { @@ -909,7 +987,8 @@ func (mock *PhaseItemMock) GetSpanName(phase string) string { // GetSpanNameCalls gets all the calls that were made to GetSpanName. // Check the length with: -// len(mockedPhaseItem.GetSpanNameCalls()) +// +// len(mockedPhaseItem.GetSpanNameCalls()) func (mock *PhaseItemMock) GetSpanNameCalls() []struct { Phase string } { @@ -937,7 +1016,8 @@ func (mock *PhaseItemMock) GetStartTime() time.Time { // GetStartTimeCalls gets all the calls that were made to GetStartTime. // Check the length with: -// len(mockedPhaseItem.GetStartTimeCalls()) +// +// len(mockedPhaseItem.GetStartTimeCalls()) func (mock *PhaseItemMock) GetStartTimeCalls() []struct { } { var calls []struct { @@ -963,7 +1043,8 @@ func (mock *PhaseItemMock) GetState() apicommon.KeptnState { // GetStateCalls gets all the calls that were made to GetState. // Check the length with: -// len(mockedPhaseItem.GetStateCalls()) +// +// len(mockedPhaseItem.GetStateCalls()) func (mock *PhaseItemMock) GetStateCalls() []struct { } { var calls []struct { @@ -989,7 +1070,8 @@ func (mock *PhaseItemMock) GetVersion() string { // GetVersionCalls gets all the calls that were made to GetVersion. // Check the length with: -// len(mockedPhaseItem.GetVersionCalls()) +// +// len(mockedPhaseItem.GetVersionCalls()) func (mock *PhaseItemMock) GetVersionCalls() []struct { } { var calls []struct { @@ -1015,7 +1097,8 @@ func (mock *PhaseItemMock) IsEndTimeSet() bool { // IsEndTimeSetCalls gets all the calls that were made to IsEndTimeSet. // Check the length with: -// len(mockedPhaseItem.IsEndTimeSetCalls()) +// +// len(mockedPhaseItem.IsEndTimeSetCalls()) func (mock *PhaseItemMock) IsEndTimeSetCalls() []struct { } { var calls []struct { @@ -1044,7 +1127,8 @@ func (mock *PhaseItemMock) SetCurrentPhase(s string) { // SetCurrentPhaseCalls gets all the calls that were made to SetCurrentPhase. // Check the length with: -// len(mockedPhaseItem.SetCurrentPhaseCalls()) +// +// len(mockedPhaseItem.SetCurrentPhaseCalls()) func (mock *PhaseItemMock) SetCurrentPhaseCalls() []struct { S string } { @@ -1057,6 +1141,42 @@ func (mock *PhaseItemMock) SetCurrentPhaseCalls() []struct { return calls } +// SetPhaseTraceID calls SetPhaseTraceIDFunc. +func (mock *PhaseItemMock) SetPhaseTraceID(phase string, carrier propagation.MapCarrier) { + if mock.SetPhaseTraceIDFunc == nil { + panic("PhaseItemMock.SetPhaseTraceIDFunc: method is nil but PhaseItem.SetPhaseTraceID was just called") + } + callInfo := struct { + Phase string + Carrier propagation.MapCarrier + }{ + Phase: phase, + Carrier: carrier, + } + mock.lockSetPhaseTraceID.Lock() + mock.calls.SetPhaseTraceID = append(mock.calls.SetPhaseTraceID, callInfo) + mock.lockSetPhaseTraceID.Unlock() + mock.SetPhaseTraceIDFunc(phase, carrier) +} + +// SetPhaseTraceIDCalls gets all the calls that were made to SetPhaseTraceID. +// Check the length with: +// +// len(mockedPhaseItem.SetPhaseTraceIDCalls()) +func (mock *PhaseItemMock) SetPhaseTraceIDCalls() []struct { + Phase string + Carrier propagation.MapCarrier +} { + var calls []struct { + Phase string + Carrier propagation.MapCarrier + } + mock.lockSetPhaseTraceID.RLock() + calls = mock.calls.SetPhaseTraceID + mock.lockSetPhaseTraceID.RUnlock() + return calls +} + // SetSpanAttributes calls SetSpanAttributesFunc. func (mock *PhaseItemMock) SetSpanAttributes(span trace.Span) { if mock.SetSpanAttributesFunc == nil { @@ -1075,7 +1195,8 @@ func (mock *PhaseItemMock) SetSpanAttributes(span trace.Span) { // SetSpanAttributesCalls gets all the calls that were made to SetSpanAttributes. // Check the length with: -// len(mockedPhaseItem.SetSpanAttributesCalls()) +// +// len(mockedPhaseItem.SetSpanAttributesCalls()) func (mock *PhaseItemMock) SetSpanAttributesCalls() []struct { Span trace.Span } { @@ -1106,7 +1227,8 @@ func (mock *PhaseItemMock) SetState(keptnState apicommon.KeptnState) { // SetStateCalls gets all the calls that were made to SetState. // Check the length with: -// len(mockedPhaseItem.SetStateCalls()) +// +// len(mockedPhaseItem.SetStateCalls()) func (mock *PhaseItemMock) SetStateCalls() []struct { KeptnState apicommon.KeptnState } { diff --git a/operator/controllers/common/phaseitem.go b/operator/controllers/common/phaseitem.go index a6befa40abd..9812902dfb7 100644 --- a/operator/controllers/common/phaseitem.go +++ b/operator/controllers/common/phaseitem.go @@ -12,8 +12,9 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" ) +// PhaseItem represents an object which has reconcile phases +// //go:generate moq -pkg fake --skip-ensure -out ./fake/phaseitem_mock.go . PhaseItem -//PhaseItem represents an object which has reconcile phases type PhaseItem interface { GetState() apicommon.KeptnState SetState(apicommon.KeptnState) @@ -42,6 +43,7 @@ type PhaseItem interface { GetSpanKey(phase string) string GetSpanName(phase string) string SetSpanAttributes(span trace.Span) + SetPhaseTraceID(phase string, carrier propagation.MapCarrier) CancelRemainingPhases(phase common.KeptnPhaseType) } @@ -168,3 +170,7 @@ func (pw PhaseItemWrapper) GetSpanName(phase string) string { func (pw PhaseItemWrapper) CancelRemainingPhases(phase common.KeptnPhaseType) { pw.Obj.CancelRemainingPhases(phase) } + +func (pw PhaseItemWrapper) SetPhaseTraceID(phase string, carrier propagation.MapCarrier) { + pw.Obj.SetPhaseTraceID(phase, carrier) +} diff --git a/operator/controllers/common/spanhandler.go b/operator/controllers/common/spanhandler.go index e61fbf3d9e9..5ab64cbd935 100644 --- a/operator/controllers/common/spanhandler.go +++ b/operator/controllers/common/spanhandler.go @@ -2,6 +2,8 @@ package common import ( "context" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/propagation" "sync" "go.opentelemetry.io/otel/trace" @@ -34,10 +36,15 @@ func (r *SpanHandler) GetSpan(ctx context.Context, tracer trace.Tracer, reconcil return ctx, span, nil } spanName := piWrapper.GetSpanName(phase) - ctx, span := tracer.Start(ctx, spanName, trace.WithSpanKind(trace.SpanKindConsumer)) + childCtx, span := tracer.Start(ctx, spanName, trace.WithSpanKind(trace.SpanKindConsumer)) piWrapper.SetSpanAttributes(span) + + traceContextCarrier := propagation.MapCarrier{} + otel.GetTextMapPropagator().Inject(childCtx, traceContextCarrier) + piWrapper.SetPhaseTraceID(phase, traceContextCarrier) + r.bindCRDSpan[appvName] = span - return ctx, span, nil + return childCtx, span, nil } func (r *SpanHandler) UnbindSpan(reconcileObject client.Object, phase string) error { diff --git a/operator/controllers/keptnapp/controller.go b/operator/controllers/keptnapp/controller.go index 0f2a85b740f..c5d980b1ccc 100644 --- a/operator/controllers/keptnapp/controller.go +++ b/operator/controllers/keptnapp/controller.go @@ -136,7 +136,7 @@ func (r *KeptnAppReconciler) createAppVersion(ctx context.Context, app *klcv1alp ctx, span := r.Tracer.Start(ctx, "create_app_version", trace.WithSpanKind(trace.SpanKindProducer)) defer span.End() - ctxAppTrace, spanAppTrace := r.Tracer.Start(ctx, "appversion_deployment", trace.WithNewRoot(), trace.WithSpanKind(trace.SpanKindServer)) + ctxAppTrace, spanAppTrace := r.Tracer.Start(ctx, app.GetAppVersionName(), trace.WithNewRoot(), trace.WithSpanKind(trace.SpanKindServer)) defer spanAppTrace.End() app.SetSpanAttributes(span) diff --git a/operator/controllers/keptnworkloadinstance/controller.go b/operator/controllers/keptnworkloadinstance/controller.go index 2f18ff7e343..7fc35f5bf93 100644 --- a/operator/controllers/keptnworkloadinstance/controller.go +++ b/operator/controllers/keptnworkloadinstance/controller.go @@ -122,9 +122,6 @@ func (r *KeptnWorkloadInstanceReconciler) Reconcile(ctx context.Context, req ctr return reconcile.Result{Requeue: true, RequeueAfter: 10 * time.Second}, fmt.Errorf(controllercommon.ErrCannotFetchAppVersionForWorkloadInstanceMsg) } - appTraceContextCarrier := propagation.MapCarrier(appVersion.Spec.TraceId) - ctxAppTrace := otel.GetTextMapPropagator().Extract(context.TODO(), appTraceContextCarrier) - appPreEvalStatus := appVersion.Status.PreDeploymentEvaluationStatus if !appPreEvalStatus.IsSucceeded() { if appPreEvalStatus.IsFailed() { @@ -148,18 +145,31 @@ func (r *KeptnWorkloadInstanceReconciler) Reconcile(ctx context.Context, req ctr // set the App trace id if not already set if len(workloadInstance.Spec.TraceId) < 1 { - workloadInstance.Spec.TraceId = appVersion.Spec.TraceId + appDeploymentTraceID := appVersion.Status.PhaseTraceIDs[common.PhaseAppDeployment.ShortName] + if appDeploymentTraceID != nil { + workloadInstance.Spec.TraceId = appDeploymentTraceID + } else { + workloadInstance.Spec.TraceId = appVersion.Spec.TraceId + } if err := r.Update(ctx, workloadInstance); err != nil { return ctrl.Result{}, err } } + appTraceContextCarrier := propagation.MapCarrier(workloadInstance.Spec.TraceId) + ctxAppTrace := otel.GetTextMapPropagator().Extract(context.TODO(), appTraceContextCarrier) + + ctxWorkloadTrace, spanTrace, err := r.SpanHandler.GetSpan(ctxAppTrace, r.Tracer, workloadInstance, workloadInstance.Name) + if err != nil { + r.Log.Error(err, "could not get span") + } + if workloadInstance.Status.CurrentPhase == "" { if err := r.SpanHandler.UnbindSpan(workloadInstance, phase.ShortName); err != nil { r.Log.Error(err, "cannot unbind span") } var spanAppTrace trace.Span - ctxAppTrace, spanAppTrace, err = r.SpanHandler.GetSpan(ctxAppTrace, r.Tracer, workloadInstance, phase.ShortName) + ctxAppTrace, spanAppTrace, err = r.SpanHandler.GetSpan(ctxWorkloadTrace, r.Tracer, workloadInstance, phase.ShortName) if err != nil { r.Log.Error(err, "could not get span") } @@ -172,7 +182,7 @@ func (r *KeptnWorkloadInstanceReconciler) Reconcile(ctx context.Context, req ctr reconcilePre := func() (common.KeptnState, error) { return r.reconcilePrePostDeployment(ctx, workloadInstance, common.PreDeploymentCheckType) } - result, err := phaseHandler.HandlePhase(ctx, ctxAppTrace, r.Tracer, workloadInstance, phase, span, reconcilePre) + result, err := phaseHandler.HandlePhase(ctx, ctxWorkloadTrace, r.Tracer, workloadInstance, phase, span, reconcilePre) if !result.Continue { return result.Result, err } @@ -184,7 +194,7 @@ func (r *KeptnWorkloadInstanceReconciler) Reconcile(ctx context.Context, req ctr reconcilePreEval := func() (common.KeptnState, error) { return r.reconcilePrePostEvaluation(ctx, workloadInstance, common.PreDeploymentEvaluationCheckType) } - result, err := phaseHandler.HandlePhase(ctx, ctxAppTrace, r.Tracer, workloadInstance, phase, span, reconcilePreEval) + result, err := phaseHandler.HandlePhase(ctx, ctxWorkloadTrace, r.Tracer, workloadInstance, phase, span, reconcilePreEval) if !result.Continue { return result.Result, err } @@ -196,7 +206,7 @@ func (r *KeptnWorkloadInstanceReconciler) Reconcile(ctx context.Context, req ctr reconcileWorkloadInstance := func() (common.KeptnState, error) { return r.reconcileDeployment(ctx, workloadInstance) } - result, err := phaseHandler.HandlePhase(ctx, ctxAppTrace, r.Tracer, workloadInstance, phase, span, reconcileWorkloadInstance) + result, err := phaseHandler.HandlePhase(ctx, ctxWorkloadTrace, r.Tracer, workloadInstance, phase, span, reconcileWorkloadInstance) if !result.Continue { return result.Result, err } @@ -208,7 +218,7 @@ func (r *KeptnWorkloadInstanceReconciler) Reconcile(ctx context.Context, req ctr reconcilePostDeployment := func() (common.KeptnState, error) { return r.reconcilePrePostDeployment(ctx, workloadInstance, common.PostDeploymentCheckType) } - result, err := phaseHandler.HandlePhase(ctx, ctxAppTrace, r.Tracer, workloadInstance, phase, span, reconcilePostDeployment) + result, err := phaseHandler.HandlePhase(ctx, ctxWorkloadTrace, r.Tracer, workloadInstance, phase, span, reconcilePostDeployment) if !result.Continue { return result.Result, err } @@ -220,7 +230,7 @@ func (r *KeptnWorkloadInstanceReconciler) Reconcile(ctx context.Context, req ctr reconcilePostEval := func() (common.KeptnState, error) { return r.reconcilePrePostEvaluation(ctx, workloadInstance, common.PostDeploymentEvaluationCheckType) } - result, err := phaseHandler.HandlePhase(ctx, ctxAppTrace, r.Tracer, workloadInstance, phase, span, reconcilePostEval) + result, err := phaseHandler.HandlePhase(ctx, ctxWorkloadTrace, r.Tracer, workloadInstance, phase, span, reconcilePostEval) if !result.Continue { return result.Result, err } @@ -245,6 +255,10 @@ func (r *KeptnWorkloadInstanceReconciler) Reconcile(ctx context.Context, req ctr duration := workloadInstance.Status.EndTime.Time.Sub(workloadInstance.Status.StartTime.Time) r.Meters.DeploymentDuration.Record(ctx, duration.Seconds(), attrs...) + spanTrace.AddEvent(workloadInstance.Name + " has finished") + spanTrace.SetStatus(codes.Ok, "Finished") + spanTrace.End() + controllercommon.RecordEvent(r.Recorder, phase, "Normal", workloadInstance, "Finished", "is finished", workloadInstance.GetVersion()) return ctrl.Result{}, nil