From 5a3821684243052247c528fc57f4d5c3fa740ca8 Mon Sep 17 00:00:00 2001 From: Johnny Bieren Date: Tue, 27 Aug 2024 20:53:38 -0400 Subject: [PATCH] feat(RELEASE-1109): allow tenant and managed pipelines to run in same release This commit modifies the release controller to execute both a tenant and managed pipelineRun in the same Release if both are defined. Signed-off-by: Johnny Bieren --- api/v1alpha1/release_conditions.go | 14 +- api/v1alpha1/release_types.go | 188 ++++++++++---- api/v1alpha1/releaseplanadmission_types.go | 4 +- api/v1alpha1/zz_generated.deepcopy.go | 35 +-- ...udio.redhat.com_releaseplanadmissions.yaml | 86 +++---- .../appstudio.redhat.com_releaseplans.yaml | 95 ++++--- .../bases/appstudio.redhat.com_releases.yaml | 152 ++++++----- ...udio.redhat.com_releaseserviceconfigs.yaml | 37 +-- config/rbac/role.yaml | 1 + config/webhook/manifests.yaml | 2 + controllers/release/adapter.go | 237 ++++++++++++------ controllers/release/controller.go | 3 +- loader/loader.go | 22 +- metrics/release.go | 120 ++++++--- tekton/utils/zz_generated.deepcopy.go | 1 + 15 files changed, 633 insertions(+), 364 deletions(-) diff --git a/api/v1alpha1/release_conditions.go b/api/v1alpha1/release_conditions.go index 6398ccbf..88129efd 100644 --- a/api/v1alpha1/release_conditions.go +++ b/api/v1alpha1/release_conditions.go @@ -9,8 +9,11 @@ const ( // postActionsExecutedConditionType is the type used to track the status of Release post-actions postActionsExecutedConditionType conditions.ConditionType = "PostActionsExecuted" - // processedConditionType is the type used to track the status of a Release processing - processedConditionType conditions.ConditionType = "Processed" + // managedProcessedConditionType is the type used to track the status of a Release Managed Pipeline processing + managedProcessedConditionType conditions.ConditionType = "ManagedPipelineProcessed" + + // tenantProcessedConditionType is the type used to track the status of a Release Tenant Pipeline processing + tenantProcessedConditionType conditions.ConditionType = "TenantPipelineProcessed" // releasedConditionType is the type used to track the status of a Release releasedConditionType conditions.ConditionType = "Released" @@ -23,9 +26,12 @@ const ( // FailedReason is the reason set when a failure occurs FailedReason conditions.ConditionReason = "Failed" - // ProgressingReason is the reason set when an action is progressing + // ProgressingReason is the reason set when a phase is progressing ProgressingReason conditions.ConditionReason = "Progressing" - // SucceededReason is the reason set when an action succeeds + // SucceededReason is the reason set when a phase succeeds SucceededReason conditions.ConditionReason = "Succeeded" + + // SkippedReason is the reason set when a phase is skipped + SkippedReason conditions.ConditionReason = "Skipped" ) diff --git a/api/v1alpha1/release_types.go b/api/v1alpha1/release_types.go index 08d3b6f0..5face6b8 100644 --- a/api/v1alpha1/release_types.go +++ b/api/v1alpha1/release_types.go @@ -68,11 +68,15 @@ type ReleaseStatus struct { // PostActionsExecution contains information about the post-actions execution // +optional - PostActionsExecution PostActionsExecutionInfo `json:"postActionsExecution,omitempty"` + PostActionsExecution PipelineInfo `json:"postActionsExecution,omitempty"` - // Processing contains information about the release processing + // ManagedProcessing contains information about the release managed processing // +optional - Processing ProcessingInfo `json:"processing,omitempty"` + ManagedProcessing PipelineInfo `json:"managedProcessing,omitempty"` + + // TenantProcessing contains information about the release tenant processing + // +optional + TenantProcessing PipelineInfo `json:"tenantProcessing,omitempty"` // Validation contains information about the release validation // +optional @@ -111,19 +115,8 @@ type AttributionInfo struct { StandingAuthorization bool `json:"standingAuthorization,omitempty"` } -// PostActionsExecutionInfo defines the observed state of the post-actions execution. -type PostActionsExecutionInfo struct { - // CompletionTime is the time when the Release post-actions execution was completed - // +optional - CompletionTime *metav1.Time `json:"completionTime,omitempty"` - - // StartTime is the time when the Release post-actions execution started - // +optional - StartTime *metav1.Time `json:"startTime,omitempty"` -} - -// ProcessingInfo defines the observed state of the release processing. -type ProcessingInfo struct { +// PipelineInfo defines the observed state of the release pipeline processing. +type PipelineInfo struct { // CompletionTime is the time when the Release processing was completed // +optional CompletionTime *metav1.Time `json:"completionTime,omitempty"` @@ -177,9 +170,14 @@ func (r *Release) HasEveryPostActionExecutionFinished() bool { return r.hasPhaseFinished(postActionsExecutedConditionType) } -// HasProcessingFinished checks whether the Release processing has finished, regardless of the result. -func (r *Release) HasProcessingFinished() bool { - return r.hasPhaseFinished(processedConditionType) +// HasManagedPipelineProcessingFinished checks whether the Release Managed Pipeline processing has finished, regardless of the result. +func (r *Release) HasManagedPipelineProcessingFinished() bool { + return r.hasPhaseFinished(managedProcessedConditionType) +} + +// HasTenantPipelineProcessingFinished checks whether the Release Tenant Pipeline processing has finished, regardless of the result. +func (r *Release) HasTenantPipelineProcessingFinished() bool { + return r.hasPhaseFinished(tenantProcessedConditionType) } // HasReleaseFinished checks whether the Release has finished, regardless of the result. @@ -207,14 +205,24 @@ func (r *Release) IsEachPostActionExecuting() bool { return r.isPhaseProgressing(postActionsExecutedConditionType) } -// IsProcessed checks whether the Release was successfully processed. -func (r *Release) IsProcessed() bool { - return meta.IsStatusConditionTrue(r.Status.Conditions, processedConditionType.String()) +// IsManagedPipelineProcessed checks whether the Release Managed Pipeline was successfully processed. +func (r *Release) IsManagedPipelineProcessed() bool { + return meta.IsStatusConditionTrue(r.Status.Conditions, managedProcessedConditionType.String()) +} + +// IsTenantPipelineProcessed checks whether the Release Tenant Pipeline was successfully processed. +func (r *Release) IsTenantPipelineProcessed() bool { + return meta.IsStatusConditionTrue(r.Status.Conditions, tenantProcessedConditionType.String()) +} + +// IsManagedPipelineProcessing checks whether the Release Managed Pipeline processing is in progress. +func (r *Release) IsManagedPipelineProcessing() bool { + return r.isPhaseProgressing(managedProcessedConditionType) } -// IsProcessing checks whether the Release processing is in progress. -func (r *Release) IsProcessing() bool { - return r.isPhaseProgressing(processedConditionType) +// IsTenantPipelineProcessing checks whether the Release Tenant Pipeline processing is in progress. +func (r *Release) IsTenantPipelineProcessing() bool { + return r.isPhaseProgressing(tenantProcessedConditionType) } // IsReleased checks whether the Release has finished successfully. @@ -232,60 +240,132 @@ func (r *Release) IsValid() bool { return meta.IsStatusConditionTrue(r.Status.Conditions, validatedConditionType.String()) } -// MarkProcessed marks the Release as processed. -func (r *Release) MarkProcessed() { - if !r.IsProcessing() || r.HasProcessingFinished() { +// MarkManagedPipelineProcessed marks the Release Managed Pipeline as processed. +func (r *Release) MarkManagedPipelineProcessed() { + if !r.IsManagedPipelineProcessing() || r.HasManagedPipelineProcessingFinished() { return } - r.Status.Processing.CompletionTime = &metav1.Time{Time: time.Now()} - conditions.SetCondition(&r.Status.Conditions, processedConditionType, metav1.ConditionTrue, SucceededReason) + r.Status.ManagedProcessing.CompletionTime = &metav1.Time{Time: time.Now()} + conditions.SetCondition(&r.Status.Conditions, managedProcessedConditionType, metav1.ConditionTrue, SucceededReason) - go metrics.RegisterCompletedReleaseProcessing( - r.Status.Processing.StartTime, - r.Status.Processing.CompletionTime, + go metrics.RegisterCompletedReleaseManagedPipelineProcessing( + r.Status.ManagedProcessing.StartTime, + r.Status.ManagedProcessing.CompletionTime, SucceededReason.String(), r.Status.Target, ) } -// MarkProcessing marks the Release as processing. -func (r *Release) MarkProcessing(message string) { - if r.HasProcessingFinished() { +// MarkTenantPipelineProcessed marks the Release Tenant Pipeline as processed. +func (r *Release) MarkTenantPipelineProcessed() { + if !r.IsTenantPipelineProcessing() || r.HasTenantPipelineProcessingFinished() { return } - if !r.IsProcessing() { - r.Status.Processing.StartTime = &metav1.Time{Time: time.Now()} + r.Status.TenantProcessing.CompletionTime = &metav1.Time{Time: time.Now()} + conditions.SetCondition(&r.Status.Conditions, tenantProcessedConditionType, metav1.ConditionTrue, SucceededReason) + + go metrics.RegisterCompletedReleaseTenantPipelineProcessing( + r.Status.TenantProcessing.StartTime, + r.Status.TenantProcessing.CompletionTime, + SucceededReason.String(), + r.Status.Target, + ) +} + +// MarkManagedPipelineProcessing marks the Release Managed Pipeline as processing. +func (r *Release) MarkManagedPipelineProcessing() { + if r.HasManagedPipelineProcessingFinished() { + return } - conditions.SetConditionWithMessage(&r.Status.Conditions, processedConditionType, metav1.ConditionFalse, ProgressingReason, message) + if !r.IsManagedPipelineProcessing() { + r.Status.ManagedProcessing.StartTime = &metav1.Time{Time: time.Now()} + } + + conditions.SetCondition(&r.Status.Conditions, managedProcessedConditionType, metav1.ConditionFalse, ProgressingReason) - go metrics.RegisterNewReleaseProcessing( - r.Status.Processing.StartTime, + go metrics.RegisterNewReleaseManagedPipelineProcessing( + r.Status.ManagedProcessing.StartTime, r.Status.StartTime, ProgressingReason.String(), r.Status.Target, ) } -// MarkProcessingFailed marks the Release processing as failed. -func (r *Release) MarkProcessingFailed(message string) { - if !r.IsProcessing() || r.HasProcessingFinished() { +// MarkTenantPipelineProcessing marks the Release Tenant Pipeline as processing. +func (r *Release) MarkTenantPipelineProcessing() { + if r.HasTenantPipelineProcessingFinished() { return } - r.Status.Processing.CompletionTime = &metav1.Time{Time: time.Now()} - conditions.SetConditionWithMessage(&r.Status.Conditions, processedConditionType, metav1.ConditionFalse, FailedReason, message) + if !r.IsTenantPipelineProcessing() { + r.Status.TenantProcessing.StartTime = &metav1.Time{Time: time.Now()} + } + + conditions.SetCondition(&r.Status.Conditions, tenantProcessedConditionType, metav1.ConditionFalse, ProgressingReason) - go metrics.RegisterCompletedReleaseProcessing( - r.Status.Processing.StartTime, - r.Status.Processing.CompletionTime, + go metrics.RegisterNewReleaseTenantPipelineProcessing( + r.Status.TenantProcessing.StartTime, + r.Status.StartTime, + ProgressingReason.String(), + r.Status.Target, + ) +} + +// MarkManagedPipelineProcessingFailed marks the Release Managed Pipeline processing as failed. +func (r *Release) MarkManagedPipelineProcessingFailed(message string) { + if !r.IsManagedPipelineProcessing() || r.HasManagedPipelineProcessingFinished() { + return + } + + r.Status.ManagedProcessing.CompletionTime = &metav1.Time{Time: time.Now()} + conditions.SetConditionWithMessage(&r.Status.Conditions, managedProcessedConditionType, metav1.ConditionFalse, FailedReason, message) + + go metrics.RegisterCompletedReleaseManagedPipelineProcessing( + r.Status.ManagedProcessing.StartTime, + r.Status.ManagedProcessing.CompletionTime, + FailedReason.String(), + r.Status.Target, + ) +} + +// MarkTenantPipelineProcessingFailed marks the Release Tenant Pipeline processing as failed. +func (r *Release) MarkTenantPipelineProcessingFailed(message string) { + if !r.IsTenantPipelineProcessing() || r.HasTenantPipelineProcessingFinished() { + return + } + + r.Status.TenantProcessing.CompletionTime = &metav1.Time{Time: time.Now()} + conditions.SetConditionWithMessage(&r.Status.Conditions, tenantProcessedConditionType, metav1.ConditionFalse, FailedReason, message) + + go metrics.RegisterCompletedReleaseTenantPipelineProcessing( + r.Status.TenantProcessing.StartTime, + r.Status.TenantProcessing.CompletionTime, FailedReason.String(), r.Status.Target, ) } +// MarkManagedPipelineProcessingSkipped marks the Release Managed Pipeline processing as skipped. +func (r *Release) MarkManagedPipelineProcessingSkipped() { + if r.HasManagedPipelineProcessingFinished() { + return + } + + conditions.SetCondition(&r.Status.Conditions, managedProcessedConditionType, metav1.ConditionTrue, SkippedReason) +} + +// MarkTenantPipelineProcessingSkipped marks the Release Tenant Pipeline processing as skipped. +func (r *Release) MarkTenantPipelineProcessingSkipped() { + if r.HasTenantPipelineProcessingFinished() { + return + } + + conditions.SetCondition(&r.Status.Conditions, tenantProcessedConditionType, metav1.ConditionTrue, SkippedReason) +} + // MarkPostActionsExecuted marks the Release post-actions as executed. func (r *Release) MarkPostActionsExecuted() { if !r.IsEachPostActionExecuting() || r.HasEveryPostActionExecutionFinished() { @@ -327,8 +407,8 @@ func (r *Release) MarkPostActionsExecutionFailed(message string) { conditions.SetConditionWithMessage(&r.Status.Conditions, postActionsExecutedConditionType, metav1.ConditionFalse, FailedReason, message) go metrics.RegisterCompletedReleasePostActionsExecuted( - r.Status.Processing.StartTime, - r.Status.Processing.CompletionTime, + r.Status.PostActionsExecution.StartTime, + r.Status.PostActionsExecution.CompletionTime, FailedReason.String(), ) } @@ -346,7 +426,8 @@ func (r *Release) MarkReleased() { r.Status.StartTime, r.Status.CompletionTime, r.getPhaseReason(postActionsExecutedConditionType), - r.getPhaseReason(processedConditionType), + r.getPhaseReason(tenantProcessedConditionType), + r.getPhaseReason(managedProcessedConditionType), SucceededReason.String(), r.Status.Target, r.getPhaseReason(validatedConditionType), @@ -381,7 +462,8 @@ func (r *Release) MarkReleaseFailed(message string) { r.Status.StartTime, r.Status.CompletionTime, r.getPhaseReason(postActionsExecutedConditionType), - r.getPhaseReason(processedConditionType), + r.getPhaseReason(tenantProcessedConditionType), + r.getPhaseReason(managedProcessedConditionType), FailedReason.String(), r.Status.Target, r.getPhaseReason(validatedConditionType), diff --git a/api/v1alpha1/releaseplanadmission_types.go b/api/v1alpha1/releaseplanadmission_types.go index 86ec5a13..4445c2bc 100644 --- a/api/v1alpha1/releaseplanadmission_types.go +++ b/api/v1alpha1/releaseplanadmission_types.go @@ -54,8 +54,8 @@ type ReleasePlanAdmissionSpec struct { Origin string `json:"origin"` // Pipeline contains all the information about the managed Pipeline - // +required - Pipeline *tektonutils.Pipeline `json:"pipeline"` + // +optional + Pipeline *tektonutils.Pipeline `json:"pipeline,omitempty"` // Policy to validate before releasing an artifact // +kubebuilder:validation:Pattern=^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index a2879bd1..e6f58ccb 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -1,4 +1,5 @@ //go:build !ignore_autogenerated +// +build !ignore_autogenerated /* Copyright 2022. @@ -107,7 +108,7 @@ func (in *Param) DeepCopy() *Param { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PostActionsExecutionInfo) DeepCopyInto(out *PostActionsExecutionInfo) { +func (in *PipelineInfo) DeepCopyInto(out *PipelineInfo) { *out = *in if in.CompletionTime != nil { in, out := &in.CompletionTime, &out.CompletionTime @@ -119,35 +120,12 @@ func (in *PostActionsExecutionInfo) DeepCopyInto(out *PostActionsExecutionInfo) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PostActionsExecutionInfo. -func (in *PostActionsExecutionInfo) DeepCopy() *PostActionsExecutionInfo { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PipelineInfo. +func (in *PipelineInfo) DeepCopy() *PipelineInfo { if in == nil { return nil } - out := new(PostActionsExecutionInfo) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ProcessingInfo) DeepCopyInto(out *ProcessingInfo) { - *out = *in - if in.CompletionTime != nil { - in, out := &in.CompletionTime, &out.CompletionTime - *out = (*in).DeepCopy() - } - if in.StartTime != nil { - in, out := &in.StartTime, &out.StartTime - *out = (*in).DeepCopy() - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProcessingInfo. -func (in *ProcessingInfo) DeepCopy() *ProcessingInfo { - if in == nil { - return nil - } - out := new(ProcessingInfo) + out := new(PipelineInfo) in.DeepCopyInto(out) return out } @@ -575,7 +553,8 @@ func (in *ReleaseStatus) DeepCopyInto(out *ReleaseStatus) { } } in.PostActionsExecution.DeepCopyInto(&out.PostActionsExecution) - in.Processing.DeepCopyInto(&out.Processing) + in.ManagedProcessing.DeepCopyInto(&out.ManagedProcessing) + in.TenantProcessing.DeepCopyInto(&out.TenantProcessing) in.Validation.DeepCopyInto(&out.Validation) if in.CompletionTime != nil { in, out := &in.CompletionTime, &out.CompletionTime diff --git a/config/crd/bases/appstudio.redhat.com_releaseplanadmissions.yaml b/config/crd/bases/appstudio.redhat.com_releaseplanadmissions.yaml index 710fcad6..12397082 100644 --- a/config/crd/bases/appstudio.redhat.com_releaseplanadmissions.yaml +++ b/config/crd/bases/appstudio.redhat.com_releaseplanadmissions.yaml @@ -3,7 +3,8 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.14.0 + controller-gen.kubebuilder.io/version: v0.8.0 + creationTimestamp: null name: releaseplanadmissions.appstudio.redhat.com spec: group: appstudio.redhat.com @@ -30,19 +31,14 @@ spec: API. properties: apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' type: string kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' type: string metadata: type: object @@ -172,7 +168,6 @@ spec: required: - applications - origin - - pipeline - policy type: object status: @@ -184,42 +179,42 @@ spec: for the releasePlanAdmission items: description: "Condition contains details for one aspect of the current - state of this API Resource.\n---\nThis struct is intended for - direct use as an array at the field path .status.conditions. For - example,\n\n\n\ttype FooStatus struct{\n\t // Represents the - observations of a foo's current state.\n\t // Known .status.conditions.type - are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // - +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t - \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" - patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t - \ // other fields\n\t}" + state of this API Resource. --- This struct is intended for direct + use as an array at the field path .status.conditions. For example, + \n type FooStatus struct{ // Represents the observations of a + foo's current state. // Known .status.conditions.type are: \"Available\", + \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge + // +listType=map // +listMapKey=type Conditions []metav1.Condition + `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" + protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" properties: lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + description: lastTransitionTime is the last time the condition + transitioned from one status to another. This should be when + the underlying condition changed. If that is not known, then + using the time when the API field changed is acceptable. format: date-time type: string message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. + description: message is a human readable message indicating + details about the transition. This may be an empty string. maxLength: 32768 type: string observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. + description: observedGeneration represents the .metadata.generation + that the condition was set based upon. For instance, if .metadata.generation + is currently 12, but the .status.conditions[x].observedGeneration + is 9, the condition is out of date with respect to the current + state of the instance. format: int64 minimum: 0 type: integer reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. + description: reason contains a programmatic identifier indicating + the reason for the condition's last transition. Producers + of specific condition types may define expected values and + meanings for this field, and whether the values are considered + a guaranteed API. The value should be a CamelCase string. This field may not be empty. maxLength: 1024 minLength: 1 @@ -233,12 +228,11 @@ spec: - Unknown type: string type: - description: |- - type of condition in CamelCase or in foo.example.com/CamelCase. - --- - Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be - useful (see .node.status.conditions), the ability to deconflict is important. - The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + description: type of condition in CamelCase or in foo.example.com/CamelCase. + --- Many .condition.type values are consistent across resources + like Available, but because arbitrary conditions can be useful + (see .node.status.conditions), the ability to deconflict is + important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) maxLength: 316 pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string @@ -273,3 +267,9 @@ spec: storage: true subresources: status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crd/bases/appstudio.redhat.com_releaseplans.yaml b/config/crd/bases/appstudio.redhat.com_releaseplans.yaml index 515d36b2..d53dab04 100644 --- a/config/crd/bases/appstudio.redhat.com_releaseplans.yaml +++ b/config/crd/bases/appstudio.redhat.com_releaseplans.yaml @@ -3,7 +3,8 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.14.0 + controller-gen.kubebuilder.io/version: v0.8.0 + creationTimestamp: null name: releaseplans.appstudio.redhat.com spec: group: appstudio.redhat.com @@ -29,19 +30,14 @@ spec: description: ReleasePlan is the Schema for the ReleasePlans API. properties: apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' type: string kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' type: string metadata: type: object @@ -172,9 +168,8 @@ spec: type: object releaseGracePeriodDays: default: 7 - description: |- - ReleaseGracePeriodDays is the number of days a Release should be kept - This value is used to define the Release ExpirationTime + description: ReleaseGracePeriodDays is the number of days a Release + should be kept This value is used to define the Release ExpirationTime type: integer target: description: Target references where to send the release requests @@ -191,42 +186,42 @@ spec: for the releasePlan items: description: "Condition contains details for one aspect of the current - state of this API Resource.\n---\nThis struct is intended for - direct use as an array at the field path .status.conditions. For - example,\n\n\n\ttype FooStatus struct{\n\t // Represents the - observations of a foo's current state.\n\t // Known .status.conditions.type - are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // - +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t - \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" - patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t - \ // other fields\n\t}" + state of this API Resource. --- This struct is intended for direct + use as an array at the field path .status.conditions. For example, + \n type FooStatus struct{ // Represents the observations of a + foo's current state. // Known .status.conditions.type are: \"Available\", + \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge + // +listType=map // +listMapKey=type Conditions []metav1.Condition + `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" + protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" properties: lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + description: lastTransitionTime is the last time the condition + transitioned from one status to another. This should be when + the underlying condition changed. If that is not known, then + using the time when the API field changed is acceptable. format: date-time type: string message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. + description: message is a human readable message indicating + details about the transition. This may be an empty string. maxLength: 32768 type: string observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. + description: observedGeneration represents the .metadata.generation + that the condition was set based upon. For instance, if .metadata.generation + is currently 12, but the .status.conditions[x].observedGeneration + is 9, the condition is out of date with respect to the current + state of the instance. format: int64 minimum: 0 type: integer reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. + description: reason contains a programmatic identifier indicating + the reason for the condition's last transition. Producers + of specific condition types may define expected values and + meanings for this field, and whether the values are considered + a guaranteed API. The value should be a CamelCase string. This field may not be empty. maxLength: 1024 minLength: 1 @@ -240,12 +235,11 @@ spec: - Unknown type: string type: - description: |- - type of condition in CamelCase or in foo.example.com/CamelCase. - --- - Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be - useful (see .node.status.conditions), the ability to deconflict is important. - The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + description: type of condition in CamelCase or in foo.example.com/CamelCase. + --- Many .condition.type values are consistent across resources + like Available, but because arbitrary conditions can be useful + (see .node.status.conditions), the ability to deconflict is + important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) maxLength: 316 pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string @@ -258,9 +252,8 @@ spec: type: object type: array releasePlanAdmission: - description: |- - ReleasePlanAdmission contains the information of the releasePlanAdmission this ReleasePlan is - matched to + description: ReleasePlanAdmission contains the information of the + releasePlanAdmission this ReleasePlan is matched to properties: active: description: Active indicates whether the ReleasePlanAdmission @@ -276,3 +269,9 @@ spec: storage: true subresources: status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crd/bases/appstudio.redhat.com_releases.yaml b/config/crd/bases/appstudio.redhat.com_releases.yaml index d299227d..3a12d0a4 100644 --- a/config/crd/bases/appstudio.redhat.com_releases.yaml +++ b/config/crd/bases/appstudio.redhat.com_releases.yaml @@ -3,7 +3,8 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.14.0 + controller-gen.kubebuilder.io/version: v0.8.0 + creationTimestamp: null name: releases.appstudio.redhat.com spec: group: appstudio.redhat.com @@ -35,19 +36,14 @@ spec: description: Release is the Schema for the releases API properties: apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' type: string kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' type: string metadata: type: object @@ -60,9 +56,8 @@ spec: type: object x-kubernetes-preserve-unknown-fields: true gracePeriodDays: - description: |- - GracePeriodDays is the number of days a Release should be kept - This value is used to define the Release ExpirationTime + description: GracePeriodDays is the number of days a Release should + be kept This value is used to define the Release ExpirationTime type: integer releasePlan: description: ReleasePlan to use for this particular Release @@ -110,42 +105,42 @@ spec: for the release items: description: "Condition contains details for one aspect of the current - state of this API Resource.\n---\nThis struct is intended for - direct use as an array at the field path .status.conditions. For - example,\n\n\n\ttype FooStatus struct{\n\t // Represents the - observations of a foo's current state.\n\t // Known .status.conditions.type - are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // - +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t - \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" - patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t - \ // other fields\n\t}" + state of this API Resource. --- This struct is intended for direct + use as an array at the field path .status.conditions. For example, + \n type FooStatus struct{ // Represents the observations of a + foo's current state. // Known .status.conditions.type are: \"Available\", + \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge + // +listType=map // +listMapKey=type Conditions []metav1.Condition + `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" + protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" properties: lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + description: lastTransitionTime is the last time the condition + transitioned from one status to another. This should be when + the underlying condition changed. If that is not known, then + using the time when the API field changed is acceptable. format: date-time type: string message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. + description: message is a human readable message indicating + details about the transition. This may be an empty string. maxLength: 32768 type: string observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. + description: observedGeneration represents the .metadata.generation + that the condition was set based upon. For instance, if .metadata.generation + is currently 12, but the .status.conditions[x].observedGeneration + is 9, the condition is out of date with respect to the current + state of the instance. format: int64 minimum: 0 type: integer reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. + description: reason contains a programmatic identifier indicating + the reason for the condition's last transition. Producers + of specific condition types may define expected values and + meanings for this field, and whether the values are considered + a guaranteed API. The value should be a CamelCase string. This field may not be empty. maxLength: 1024 minLength: 1 @@ -159,12 +154,11 @@ spec: - Unknown type: string type: - description: |- - type of condition in CamelCase or in foo.example.com/CamelCase. - --- - Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be - useful (see .node.status.conditions), the ability to deconflict is important. - The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + description: type of condition in CamelCase or in foo.example.com/CamelCase. + --- Many .condition.type values are consistent across resources + like Available, but because arbitrary conditions can be useful + (see .node.status.conditions), the ability to deconflict is + important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) maxLength: 316 pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string @@ -180,23 +174,35 @@ spec: description: ExpirationTime is the time when a Release can be purged format: date-time type: string - postActionsExecution: - description: PostActionsExecution contains information about the post-actions - execution + managedProcessing: + description: ManagedProcessing contains information about the release + managed processing properties: completionTime: - description: CompletionTime is the time when the Release post-actions - execution was completed + description: CompletionTime is the time when the Release processing + was completed format: date-time type: string + pipelineRun: + description: PipelineRun contains the namespaced name of the managed + Release PipelineRun executed as part of this release + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?\/[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + roleBinding: + description: RoleBinding contains the namespaced name of the roleBinding + created for the managed Release PipelineRun executed as part + of this release + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?\/[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string startTime: - description: StartTime is the time when the Release post-actions - execution started + description: StartTime is the time when the Release processing + started format: date-time type: string type: object - processing: - description: Processing contains information about the release processing + postActionsExecution: + description: PostActionsExecution contains information about the post-actions + execution properties: completionTime: description: CompletionTime is the time when the Release processing @@ -209,9 +215,9 @@ spec: pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?\/[a-z0-9]([-a-z0-9]*[a-z0-9])?$ type: string roleBinding: - description: |- - RoleBinding contains the namespaced name of the roleBinding created for the managed Release PipelineRun - executed as part of this release + description: RoleBinding contains the namespaced name of the roleBinding + created for the managed Release PipelineRun executed as part + of this release pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?\/[a-z0-9]([-a-z0-9]*[a-z0-9])?$ type: string startTime: @@ -229,6 +235,32 @@ spec: released to pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ type: string + tenantProcessing: + description: TenantProcessing contains information about the release + tenant processing + properties: + completionTime: + description: CompletionTime is the time when the Release processing + was completed + format: date-time + type: string + pipelineRun: + description: PipelineRun contains the namespaced name of the managed + Release PipelineRun executed as part of this release + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?\/[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + roleBinding: + description: RoleBinding contains the namespaced name of the roleBinding + created for the managed Release PipelineRun executed as part + of this release + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?\/[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + startTime: + description: StartTime is the time when the Release processing + started + format: date-time + type: string + type: object validation: description: Validation contains information about the release validation properties: @@ -248,3 +280,9 @@ spec: storage: true subresources: status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crd/bases/appstudio.redhat.com_releaseserviceconfigs.yaml b/config/crd/bases/appstudio.redhat.com_releaseserviceconfigs.yaml index 4ae0787c..c7cb89bc 100644 --- a/config/crd/bases/appstudio.redhat.com_releaseserviceconfigs.yaml +++ b/config/crd/bases/appstudio.redhat.com_releaseserviceconfigs.yaml @@ -3,7 +3,8 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.14.0 + controller-gen.kubebuilder.io/version: v0.8.0 + creationTimestamp: null name: releaseserviceconfigs.appstudio.redhat.com spec: group: appstudio.redhat.com @@ -23,19 +24,14 @@ spec: API properties: apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' type: string kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' type: string metadata: type: object @@ -47,14 +43,13 @@ spec: the managed release PipelineRun type: string debug: - description: |- - Debug is the boolean that specifies whether or not the Release Service should run - in debug mode + description: Debug is the boolean that specifies whether or not the + Release Service should run in debug mode type: boolean defaultTimeouts: - description: |- - DefaultTimeouts contain the default Tekton timeouts to be used in case they are - not specified in the ReleasePlanAdmission resource. + description: DefaultTimeouts contain the default Tekton timeouts to + be used in case they are not specified in the ReleasePlanAdmission + resource. properties: finally: description: Finally sets the maximum allowed duration of this @@ -80,3 +75,9 @@ spec: storage: true subresources: status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index bc3d9ecb..f3320bf3 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -2,6 +2,7 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: + creationTimestamp: null name: manager-role rules: - apiGroups: diff --git a/config/webhook/manifests.yaml b/config/webhook/manifests.yaml index e397c149..2b597696 100644 --- a/config/webhook/manifests.yaml +++ b/config/webhook/manifests.yaml @@ -2,6 +2,7 @@ apiVersion: admissionregistration.k8s.io/v1 kind: MutatingWebhookConfiguration metadata: + creationTimestamp: null name: mutating-webhook-configuration webhooks: - admissionReviewVersions: @@ -86,6 +87,7 @@ webhooks: apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration metadata: + creationTimestamp: null name: validating-webhook-configuration webhooks: - admissionReviewVersions: diff --git a/controllers/release/adapter.go b/controllers/release/adapter.go index 8915c851..6e010098 100644 --- a/controllers/release/adapter.go +++ b/controllers/release/adapter.go @@ -67,10 +67,10 @@ func newAdapter(ctx context.Context, client client.Client, release *v1alpha1.Rel } releaseAdapter.validations = []controller.ValidationFunction{ + releaseAdapter.validatePipelineDefined, releaseAdapter.validateProcessingResources, releaseAdapter.validateAuthor, releaseAdapter.validatePipelineRef, - releaseAdapter.validateSinglePipeline, } return releaseAdapter @@ -156,8 +156,8 @@ func (a *adapter) EnsureReleaseIsCompleted() (controller.OperationResult, error) return controller.ContinueProcessing() } - // The processing has to complete for a Release to be completed - if !a.release.HasProcessingFinished() { + // The managed pipeline processing has to complete for a Release to be completed + if !a.release.HasManagedPipelineProcessingFinished() { return controller.ContinueProcessing() } @@ -185,16 +185,16 @@ func (a *adapter) EnsureReleaseIsRunning() (controller.OperationResult, error) { // EnsureTenantPipelineIsProcessed is an operation that will ensure that a Tenant Release PipelineRun associated to the Release // being processed exist. Otherwise, it will be created. func (a *adapter) EnsureTenantPipelineIsProcessed() (controller.OperationResult, error) { - if a.release.HasProcessingFinished() { + if a.release.HasTenantPipelineProcessingFinished() { return controller.ContinueProcessing() } - pipelineRun, err := a.loader.GetReleasePipelineRun(a.ctx, a.client, a.release) + pipelineRun, err := a.loader.GetReleasePipelineRun(a.ctx, a.client, a.release, metadata.TenantPipelineType) if err != nil && !errors.IsNotFound(err) { return controller.RequeueWithError(err) } - if pipelineRun == nil || !a.release.IsProcessing() { + if pipelineRun == nil || !a.release.IsTenantPipelineProcessing() { releasePlan, err := a.loader.GetReleasePlan(a.ctx, a.client, a.release) if err != nil { return controller.RequeueWithError(err) @@ -202,7 +202,9 @@ func (a *adapter) EnsureTenantPipelineIsProcessed() (controller.OperationResult, if releasePlan.Spec.Pipeline == nil { // no tenant pipeline to run - return controller.ContinueProcessing() + patch := client.MergeFrom(a.release.DeepCopy()) + a.release.MarkTenantPipelineProcessingSkipped() + return controller.RequeueOnErrorOrContinue(a.client.Status().Patch(a.ctx, a.release, patch)) } if pipelineRun == nil { @@ -220,7 +222,7 @@ func (a *adapter) EnsureTenantPipelineIsProcessed() (controller.OperationResult, "PipelineRun.Name", pipelineRun.Name, "PipelineRun.Namespace", pipelineRun.Namespace) } - return controller.RequeueOnErrorOrContinue(a.registerProcessingData(pipelineRun, nil)) + return controller.RequeueOnErrorOrContinue(a.registerTenantProcessingData(pipelineRun)) } return controller.ContinueProcessing() @@ -229,11 +231,11 @@ func (a *adapter) EnsureTenantPipelineIsProcessed() (controller.OperationResult, // EnsureManagedPipelineIsProcessed is an operation that will ensure that a managed Release PipelineRun associated to the Release // being processed and a RoleBinding to grant its serviceAccount permissions exist. Otherwise, it will create them. func (a *adapter) EnsureManagedPipelineIsProcessed() (controller.OperationResult, error) { - if a.release.HasProcessingFinished() { + if a.release.HasManagedPipelineProcessingFinished() || !a.release.HasTenantPipelineProcessingFinished() { return controller.ContinueProcessing() } - pipelineRun, err := a.loader.GetReleasePipelineRun(a.ctx, a.client, a.release) + pipelineRun, err := a.loader.GetReleasePipelineRun(a.ctx, a.client, a.release, metadata.ManagedPipelineType) if err != nil && !errors.IsNotFound(err) { return controller.RequeueWithError(err) } @@ -243,13 +245,20 @@ func (a *adapter) EnsureManagedPipelineIsProcessed() (controller.OperationResult return controller.RequeueWithError(err) } - if pipelineRun == nil || !a.release.IsProcessing() { + if pipelineRun == nil || !a.release.IsManagedPipelineProcessing() { resources, err := a.loader.GetProcessingResources(a.ctx, a.client, a.release) if err != nil { return controller.RequeueWithError(err) } if pipelineRun == nil { + if resources.ReleasePlanAdmission.Spec.Pipeline == nil { + // no managed pipeline to run + patch := client.MergeFrom(a.release.DeepCopy()) + a.release.MarkManagedPipelineProcessingSkipped() + return controller.RequeueOnErrorOrContinue(a.client.Status().Patch(a.ctx, a.release, patch)) + } + // Only create a RoleBinding if a ServiceAccount is specified if roleBinding == nil && resources.ReleasePlanAdmission.Spec.Pipeline.ServiceAccountName != "" { // This string should probably be a constant somewhere @@ -268,7 +277,7 @@ func (a *adapter) EnsureManagedPipelineIsProcessed() (controller.OperationResult "PipelineRun.Name", pipelineRun.Name, "PipelineRun.Namespace", pipelineRun.Namespace) } - return controller.RequeueOnErrorOrContinue(a.registerProcessingData(pipelineRun, roleBinding)) + return controller.RequeueOnErrorOrContinue(a.registerManagedProcessingData(pipelineRun, roleBinding)) } return controller.ContinueProcessing() @@ -316,19 +325,19 @@ func (a *adapter) EnsureReleaseIsValid() (controller.OperationResult, error) { return controller.RequeueOnErrorOrStop(a.client.Status().Patch(a.ctx, a.release, patch)) } -// EnsureReleaseProcessingIsTracked is an operation that will ensure that the Release PipelineRun status is tracked -// in the Release being processed. -func (a *adapter) EnsureReleaseProcessingIsTracked() (controller.OperationResult, error) { - if !a.release.IsProcessing() || a.release.HasProcessingFinished() { +// EnsureReleaseTenantProcessingIsTracked is an operation that will ensure that the Release Tenant PipelineRun status +// is tracked in the Release being processed. +func (a *adapter) EnsureReleaseTenantProcessingIsTracked() (controller.OperationResult, error) { + if !a.release.IsTenantPipelineProcessing() || a.release.HasTenantPipelineProcessingFinished() { return controller.ContinueProcessing() } - pipelineRun, err := a.loader.GetReleasePipelineRun(a.ctx, a.client, a.release) + pipelineRun, err := a.loader.GetReleasePipelineRun(a.ctx, a.client, a.release, metadata.TenantPipelineType) if err != nil { return controller.RequeueWithError(err) } if pipelineRun != nil { - err = a.registerProcessingStatus(pipelineRun) + err = a.registerTenantProcessingStatus(pipelineRun) if err != nil { return controller.RequeueWithError(err) } @@ -337,24 +346,38 @@ func (a *adapter) EnsureReleaseProcessingIsTracked() (controller.OperationResult return controller.ContinueProcessing() } -// EnsureReleaseProcessingResourcesAreCleanedUp is an operation that will ensure that the resources created for the Release -// Processing step are cleaned up once processing is finished. -func (a *adapter) EnsureReleaseProcessingResourcesAreCleanedUp() (controller.OperationResult, error) { - if !a.release.HasProcessingFinished() { +// EnsureReleaseManagedProcessingIsTracked is an operation that will ensure that the Release Managed PipelineRun status +// is tracked in the Release being processed. +func (a *adapter) EnsureReleaseManagedProcessingIsTracked() (controller.OperationResult, error) { + if !a.release.IsManagedPipelineProcessing() || a.release.HasManagedPipelineProcessingFinished() { return controller.ContinueProcessing() } - pipelineRun, err := a.loader.GetReleasePipelineRun(a.ctx, a.client, a.release) - if err != nil && !errors.IsNotFound(err) { + pipelineRun, err := a.loader.GetReleasePipelineRun(a.ctx, a.client, a.release, metadata.ManagedPipelineType) + if err != nil { return controller.RequeueWithError(err) } + if pipelineRun != nil { + err = a.registerManagedProcessingStatus(pipelineRun) + if err != nil { + return controller.RequeueWithError(err) + } + } - roleBinding, err := a.loader.GetRoleBindingFromReleaseStatus(a.ctx, a.client, a.release) - if err != nil && !errors.IsNotFound(err) && !strings.Contains(err.Error(), "valid reference to a RoleBinding") { - return controller.RequeueWithError(err) + return controller.ContinueProcessing() +} + +// EnsureReleaseProcessingResourcesAreCleanedUp is an operation that will ensure that the resources created for any +// Release Processing phase are cleaned up once processing is finished. +func (a *adapter) EnsureReleaseProcessingResourcesAreCleanedUp() (controller.OperationResult, error) { + if !a.release.HasTenantPipelineProcessingFinished() || !a.release.HasManagedPipelineProcessingFinished() { + return controller.ContinueProcessing() } - return controller.RequeueOnErrorOrContinue(a.cleanupProcessingResources(pipelineRun, roleBinding)) + // finalizeRelease is called both here and in EnsureFinalizersAreCalled in case the Release is deleted + // or something similar happens, which would result in this operation's gates calling ContinueProcessing + // before finalizeRelease is called here. + return controller.RequeueOnErrorOrContinue(a.finalizeRelease()) } // cleanupProcessingResources cleans up the PipelineRun created for the Release Processing @@ -370,8 +393,19 @@ func (a *adapter) cleanupProcessingResources(pipelineRun *tektonv1.PipelineRun, if pipelineRun != nil { if controllerutil.ContainsFinalizer(pipelineRun, metadata.ReleaseFinalizer) { patch := client.MergeFrom(pipelineRun.DeepCopy()) - controllerutil.RemoveFinalizer(pipelineRun, metadata.ReleaseFinalizer) - return a.client.Patch(a.ctx, pipelineRun, patch) + removedFinalizer := controllerutil.RemoveFinalizer(pipelineRun, metadata.ReleaseFinalizer) + if !removedFinalizer { + return fmt.Errorf("finalizer not removed") + } + err := a.client.Patch(a.ctx, pipelineRun, patch) + if err != nil { + return err + } + } + + err := a.client.Delete(a.ctx, pipelineRun) + if err != nil && !errors.IsNotFound(err) { + return err } } @@ -497,30 +531,31 @@ func (a *adapter) createRoleBindingForClusterRole(clusterRole string, releasePla // finalizeRelease will finalize the Release being processed, removing the associated resources. func (a *adapter) finalizeRelease() error { - pipelineRun, err := a.loader.GetReleasePipelineRun(a.ctx, a.client, a.release) + // Cleanup Tenant Processing Resources + pipelineRun, err := a.loader.GetReleasePipelineRun(a.ctx, a.client, a.release, metadata.TenantPipelineType) + if err != nil && !errors.IsNotFound(err) { + return err + } + + err = a.cleanupProcessingResources(pipelineRun, nil) if err != nil { return err } - if pipelineRun != nil { - // The finalizer could still exist at this point in the case of the PipelineRun not having succeeded at the time - // of finalizing the Release. - if controllerutil.ContainsFinalizer(pipelineRun, metadata.ReleaseFinalizer) { - patch := client.MergeFrom(pipelineRun.DeepCopy()) - removedFinalizer := controllerutil.RemoveFinalizer(pipelineRun, metadata.ReleaseFinalizer) - if !removedFinalizer { - return fmt.Errorf("finalizer not removed") - } - err := a.client.Patch(a.ctx, pipelineRun, patch) - if err != nil { - return err - } - } + // Cleanup Managed Processing Resources + pipelineRun, err = a.loader.GetReleasePipelineRun(a.ctx, a.client, a.release, metadata.ManagedPipelineType) + if err != nil && !errors.IsNotFound(err) { + return err + } - err = a.client.Delete(a.ctx, pipelineRun) - if err != nil && !errors.IsNotFound(err) { - return err - } + roleBinding, err := a.loader.GetRoleBindingFromReleaseStatus(a.ctx, a.client, a.release) + if err != nil && !errors.IsNotFound(err) && !strings.Contains(err.Error(), "valid reference to a RoleBinding") { + return err + } + + err = a.cleanupProcessingResources(pipelineRun, roleBinding) + if err != nil { + return err } a.logger.Info("Successfully finalized Release") @@ -540,46 +575,83 @@ func (a *adapter) getEmptyReleaseServiceConfig(namespace string) *v1alpha1.Relea return releaseServiceConfig } -// registerProcessingData adds all the Release processing information to its Status and marks it as processing. -func (a *adapter) registerProcessingData(releasePipelineRun *tektonv1.PipelineRun, roleBinding *rbac.RoleBinding) error { +// registerTenantProcessingData adds all the Release Tenant processing information to its Status and marks it as tenant processing. +func (a *adapter) registerTenantProcessingData(releasePipelineRun *tektonv1.PipelineRun) error { + if releasePipelineRun == nil { + return nil + } + + patch := client.MergeFrom(a.release.DeepCopy()) + + a.release.Status.TenantProcessing.PipelineRun = fmt.Sprintf("%s%c%s", + releasePipelineRun.Namespace, types.Separator, releasePipelineRun.Name) + + a.release.MarkTenantPipelineProcessing() + + return a.client.Status().Patch(a.ctx, a.release, patch) +} + +// registerProcessingData adds all the Release Managed processing information to its Status and marks it as managed processing. +func (a *adapter) registerManagedProcessingData(releasePipelineRun *tektonv1.PipelineRun, roleBinding *rbac.RoleBinding) error { if releasePipelineRun == nil { return nil } patch := client.MergeFrom(a.release.DeepCopy()) - a.release.Status.Processing.PipelineRun = fmt.Sprintf("%s%c%s", + a.release.Status.ManagedProcessing.PipelineRun = fmt.Sprintf("%s%c%s", releasePipelineRun.Namespace, types.Separator, releasePipelineRun.Name) if roleBinding != nil { - a.release.Status.Processing.RoleBinding = fmt.Sprintf("%s%c%s", + a.release.Status.ManagedProcessing.RoleBinding = fmt.Sprintf("%s%c%s", roleBinding.Namespace, types.Separator, roleBinding.Name) } - a.release.Status.Target = releasePipelineRun.Namespace - a.release.MarkProcessing("") + a.release.MarkManagedPipelineProcessing() + + return a.client.Status().Patch(a.ctx, a.release, patch) +} + +// registerTenantProcessingStatus updates the status of the Release being processed by monitoring the status of the +// associated tenant Release PipelineRun and setting the appropriate state in the Release. If the PipelineRun hasn't +// started/succeeded, no action will be taken. +func (a *adapter) registerTenantProcessingStatus(pipelineRun *tektonv1.PipelineRun) error { + if pipelineRun == nil || !pipelineRun.IsDone() { + return nil + } + + patch := client.MergeFrom(a.release.DeepCopy()) + + condition := pipelineRun.Status.GetCondition(apis.ConditionSucceeded) + if condition.IsTrue() { + a.release.MarkTenantPipelineProcessed() + } else { + a.release.MarkTenantPipelineProcessingFailed(condition.Message) + a.release.MarkManagedPipelineProcessingSkipped() // Do not run managed pipeline if tenant pipeline fails + a.release.MarkReleaseFailed("Release processing failed on tenant pipelineRun") + } return a.client.Status().Patch(a.ctx, a.release, patch) } -// registerProcessingStatus updates the status of the Release being processed by monitoring the status of the +// registerManagedProcessingStatus updates the status of the Release being processed by monitoring the status of the // associated managed Release PipelineRun and setting the appropriate state in the Release. If the PipelineRun hasn't // started/succeeded, no action will be taken. -func (a *adapter) registerProcessingStatus(pipelineRun *tektonv1.PipelineRun) error { - if pipelineRun != nil && pipelineRun.IsDone() { - patch := client.MergeFrom(a.release.DeepCopy()) +func (a *adapter) registerManagedProcessingStatus(pipelineRun *tektonv1.PipelineRun) error { + if pipelineRun == nil || !pipelineRun.IsDone() { + return nil + } - condition := pipelineRun.Status.GetCondition(apis.ConditionSucceeded) - if condition.IsTrue() { - a.release.MarkProcessed() - } else { - a.release.MarkProcessingFailed(condition.Message) - a.release.MarkReleaseFailed("Release processing failed") - } + patch := client.MergeFrom(a.release.DeepCopy()) - return a.client.Status().Patch(a.ctx, a.release, patch) + condition := pipelineRun.Status.GetCondition(apis.ConditionSucceeded) + if condition.IsTrue() { + a.release.MarkManagedPipelineProcessed() + } else { + a.release.MarkManagedPipelineProcessingFailed(condition.Message) + a.release.MarkReleaseFailed("Release processing failed on managed pipelineRun") } - return nil + return a.client.Status().Patch(a.ctx, a.release, patch) } // validateAuthor will ensure that a valid author exists for the Release and add it to its status. If the Release @@ -681,8 +753,8 @@ func (a *adapter) validatePipelineRef() *controller.ValidationResult { return &controller.ValidationResult{Valid: true} } -// validateSinglePipeline checks that the Pipeline is defined exclusively in the ReleasePlan or in the ReleasePlanAdmission. -func (a *adapter) validateSinglePipeline() *controller.ValidationResult { +// validatePipelineDefined checks that a Pipeline is defined in either the ReleasePlan or in the ReleasePlanAdmission. +func (a *adapter) validatePipelineDefined() *controller.ValidationResult { releasePlan, err := a.loader.GetReleasePlan(a.ctx, a.client, a.release) if err != nil { if errors.IsNotFound(err) { @@ -693,9 +765,28 @@ func (a *adapter) validateSinglePipeline() *controller.ValidationResult { return &controller.ValidationResult{Err: err} } - if releasePlan.Spec.Pipeline != nil && releasePlan.Spec.Target != "" { - a.release.MarkValidationFailed("pipeline should be set only in the ReleasePlan or in the ReleasePlanAdmission") - return &controller.ValidationResult{Valid: false} + if releasePlan.Spec.Pipeline == nil { + if releasePlan.Spec.Target == "" { + a.release.Status.Target = releasePlan.Namespace + errString := "releasePlan has no pipeline or target. Each Release should define a tenant pipeline, managed pipeline, or both" + a.release.MarkValidationFailed(errString) + return &controller.ValidationResult{Valid: false} + } + a.release.Status.Target = releasePlan.Spec.Target + releasePlanAdmission, err := a.loader.GetActiveReleasePlanAdmissionFromRelease(a.ctx, a.client, a.release) + if err != nil { + if errors.IsNotFound(err) { + a.release.MarkValidationFailed(err.Error()) + return &controller.ValidationResult{Valid: false} + } + + return &controller.ValidationResult{Err: err} + } + if releasePlanAdmission.Spec.Pipeline == nil { + errString := "releasePlan and releasePlanAdmission both have no pipeline. Each Release should define a tenant pipeline, managed pipeline, or both" + a.release.MarkValidationFailed(errString) + return &controller.ValidationResult{Valid: false} + } } return &controller.ValidationResult{Valid: true} diff --git a/controllers/release/controller.go b/controllers/release/controller.go index d6d569a2..eef5dad3 100644 --- a/controllers/release/controller.go +++ b/controllers/release/controller.go @@ -82,8 +82,9 @@ func (c *Controller) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu adapter.EnsureFinalizerIsAdded, adapter.EnsureReleaseExpirationTimeIsAdded, adapter.EnsureTenantPipelineIsProcessed, + adapter.EnsureReleaseTenantProcessingIsTracked, adapter.EnsureManagedPipelineIsProcessed, - adapter.EnsureReleaseProcessingIsTracked, + adapter.EnsureReleaseManagedProcessingIsTracked, adapter.EnsureReleaseProcessingResourcesAreCleanedUp, adapter.EnsureReleaseIsCompleted, }) diff --git a/loader/loader.go b/loader/loader.go index b7b309a4..b49bac3e 100644 --- a/loader/loader.go +++ b/loader/loader.go @@ -3,11 +3,12 @@ package loader import ( "context" "fmt" - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/runtime/schema" "os" "strings" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/utils/strings/slices" toolkit "github.com/konflux-ci/operator-toolkit/loader" @@ -34,7 +35,7 @@ type ObjectLoader interface { GetPreviousRelease(ctx context.Context, cli client.Client, release *v1alpha1.Release) (*v1alpha1.Release, error) GetRelease(ctx context.Context, cli client.Client, name, namespace string) (*v1alpha1.Release, error) GetRoleBindingFromReleaseStatus(ctx context.Context, cli client.Client, release *v1alpha1.Release) (*rbac.RoleBinding, error) - GetReleasePipelineRun(ctx context.Context, cli client.Client, release *v1alpha1.Release) (*tektonv1.PipelineRun, error) + GetReleasePipelineRun(ctx context.Context, cli client.Client, release *v1alpha1.Release, pipelineType string) (*tektonv1.PipelineRun, error) GetReleasePlan(ctx context.Context, cli client.Client, release *v1alpha1.Release) (*v1alpha1.ReleasePlan, error) GetReleaseServiceConfig(ctx context.Context, cli client.Client, name, namespace string) (*v1alpha1.ReleaseServiceConfig, error) GetSnapshot(ctx context.Context, cli client.Client, release *v1alpha1.Release) (*applicationapiv1alpha1.Snapshot, error) @@ -220,10 +221,10 @@ func (l *loader) GetRelease(ctx context.Context, cli client.Client, name, namesp // by the namespaced name stored in the Release's status. func (l *loader) GetRoleBindingFromReleaseStatus(ctx context.Context, cli client.Client, release *v1alpha1.Release) (*rbac.RoleBinding, error) { roleBinding := &rbac.RoleBinding{} - roleBindingNamespacedName := strings.Split(release.Status.Processing.RoleBinding, string(types.Separator)) + roleBindingNamespacedName := strings.Split(release.Status.ManagedProcessing.RoleBinding, string(types.Separator)) if len(roleBindingNamespacedName) != 2 { return nil, fmt.Errorf("release doesn't contain a valid reference to a RoleBinding ('%s')", - release.Status.Processing.RoleBinding) + release.Status.ManagedProcessing.RoleBinding) } err := cli.Get(ctx, types.NamespacedName{ @@ -237,15 +238,20 @@ func (l *loader) GetRoleBindingFromReleaseStatus(ctx context.Context, cli client return roleBinding, nil } -// GetReleasePipelineRun returns the Release PipelineRun referenced by the given Release or nil if it's not found. In the case -// the List operation fails, an error will be returned. -func (l *loader) GetReleasePipelineRun(ctx context.Context, cli client.Client, release *v1alpha1.Release) (*tektonv1.PipelineRun, error) { +// GetReleasePipelineRun returns the Release PipelineRun of the specified type referenced by the given Release +// or nil if it's not found. In the case the List operation fails, an error will be returned. +func (l *loader) GetReleasePipelineRun(ctx context.Context, cli client.Client, release *v1alpha1.Release, pipelineType string) (*tektonv1.PipelineRun, error) { + if pipelineType != metadata.ManagedPipelineType && pipelineType != metadata.TenantPipelineType { + return nil, fmt.Errorf("cannot fetch Release PipelineRun with invalid type %s", pipelineType) + } + pipelineRuns := &tektonv1.PipelineRunList{} err := cli.List(ctx, pipelineRuns, client.Limit(1), client.MatchingLabels{ metadata.ReleaseNameLabel: release.Name, metadata.ReleaseNamespaceLabel: release.Namespace, + metadata.PipelinesTypeLabel: pipelineType, }) if err == nil && len(pipelineRuns.Items) > 0 { return &pipelineRuns.Items[0], nil diff --git a/metrics/release.go b/metrics/release.go index 2ed7db6a..1f2e165a 100644 --- a/metrics/release.go +++ b/metrics/release.go @@ -39,10 +39,18 @@ var ( []string{}, ) - ReleaseConcurrentProcessingsTotal = prometheus.NewGaugeVec( + ReleaseConcurrentManagedPipelineProcessingsTotal = prometheus.NewGaugeVec( prometheus.GaugeOpts{ - Name: "release_concurrent_processings_total", - Help: "Total number of concurrent release processing attempts", + Name: "release_concurrent_managed_pipeline_processings_total", + Help: "Total number of concurrent release managed pipeline processing attempts", + }, + []string{}, + ) + + ReleaseConcurrentTenantPipelineProcessingsTotal = prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "release_concurrent_tenant_pipeline_processings_total", + Help: "Total number of concurrent release tenant pipeline processing attempts", }, []string{}, ) @@ -81,7 +89,8 @@ var ( ) releaseDurationSecondsLabels = []string{ "post_actions_reason", - "processing_reason", + "tenant_pipeline_processing_reason", + "managed_pipeline_processing_reason", "release_reason", "target", "validation_reason", @@ -105,17 +114,27 @@ var ( Buckets: []float64{60, 150, 300, 450, 600, 750, 900, 1050, 1200, 1800, 3600}, } - ReleaseProcessingDurationSeconds = prometheus.NewHistogramVec( - releaseProcessingDurationSecondsOpts, + ReleaseManagedPipelineProcessingDurationSeconds = prometheus.NewHistogramVec( + releaseManagedPipelineProcessingDurationSecondsOpts, releaseProcessingDurationSecondsLabels, ) releaseProcessingDurationSecondsLabels = []string{ "reason", "target", } - releaseProcessingDurationSecondsOpts = prometheus.HistogramOpts{ - Name: "release_processing_duration_seconds", - Help: "How long in seconds a Release processing takes to complete", + releaseManagedPipelineProcessingDurationSecondsOpts = prometheus.HistogramOpts{ + Name: "release_managed_pipeline_processing_duration_seconds", + Help: "How long in seconds a Release Managed Pipeline processing takes to complete", + Buckets: []float64{60, 150, 300, 450, 600, 750, 900, 1050, 1200, 1800, 3600}, + } + + ReleaseTenantPipelineProcessingDurationSeconds = prometheus.NewHistogramVec( + releaseTenantPipelineProcessingDurationSecondsOpts, + releaseProcessingDurationSecondsLabels, + ) + releaseTenantPipelineProcessingDurationSecondsOpts = prometheus.HistogramOpts{ + Name: "release_tenant_pipeline_processing_duration_seconds", + Help: "How long in seconds a Release Tenant Pipeline processing takes to complete", Buckets: []float64{60, 150, 300, 450, 600, 750, 900, 1050, 1200, 1800, 3600}, } @@ -125,7 +144,8 @@ var ( ) releaseTotalLabels = []string{ "post_actions_reason", - "processing_reason", + "tenant_pipeline_processing_reason", + "managed_pipeline_processing_reason", "release_reason", "target", "validation_reason", @@ -140,17 +160,18 @@ var ( // observation for the Release duration and increasing the total number of releases. If either the startTime or the // completionTime parameters are nil, no action will be taken. func RegisterCompletedRelease(startTime, completionTime *metav1.Time, - postActionsReason, processingReason, releaseReason, target, validationReason string) { + postActionsReason, tenantProcessingReason, managedProcessingReason, releaseReason, target, validationReason string) { if startTime == nil || completionTime == nil { return } labels := prometheus.Labels{ - "post_actions_reason": postActionsReason, - "processing_reason": processingReason, - "release_reason": releaseReason, - "target": target, - "validation_reason": validationReason, + "post_actions_reason": postActionsReason, + "tenant_pipeline_processing_reason": tenantProcessingReason, + "managed_pipeline_processing_reason": managedProcessingReason, + "release_reason": releaseReason, + "target": target, + "validation_reason": validationReason, } ReleaseConcurrentTotal.WithLabelValues().Dec() ReleaseDurationSeconds. @@ -175,21 +196,40 @@ func RegisterCompletedReleasePostActionsExecuted(startTime, completionTime *meta ReleaseConcurrentPostActionsExecutionsTotal.WithLabelValues().Dec() } -// RegisterCompletedReleaseProcessing registers a Release processing as complete, adding a new observation for the -// Release processing duration and decreasing the number of concurrent processings. If either the startTime or the -// completionTime parameters are nil, no action will be taken. -func RegisterCompletedReleaseProcessing(startTime, completionTime *metav1.Time, reason, target string) { +// RegisterCompletedReleaseManagedPipelineProcessing registers a Release processing as complete, adding a +// new observation for the Release Managed Pipeline processing duration and decreasing the number of +// concurrent processings. If either the startTime or the completionTime parameters are nil, no action +// will be taken. +func RegisterCompletedReleaseManagedPipelineProcessing(startTime, completionTime *metav1.Time, reason, target string) { if startTime == nil || completionTime == nil { return } - ReleaseProcessingDurationSeconds. + ReleaseManagedPipelineProcessingDurationSeconds. With(prometheus.Labels{ "reason": reason, "target": target, }). Observe(completionTime.Sub(startTime.Time).Seconds()) - ReleaseConcurrentProcessingsTotal.WithLabelValues().Dec() + ReleaseConcurrentManagedPipelineProcessingsTotal.WithLabelValues().Dec() +} + +// RegisterCompletedReleaseTenantPipelineProcessing registers a Release processing as complete, adding a +// new observation for the Release Tenant Pipeline processing duration and decreasing the number of +// concurrent processings. If either the startTime or the completionTime parameters are nil, no action +// will be taken. +func RegisterCompletedReleaseTenantPipelineProcessing(startTime, completionTime *metav1.Time, reason, target string) { + if startTime == nil || completionTime == nil { + return + } + + ReleaseTenantPipelineProcessingDurationSeconds. + With(prometheus.Labels{ + "reason": reason, + "target": target, + }). + Observe(completionTime.Sub(startTime.Time).Seconds()) + ReleaseConcurrentTenantPipelineProcessingsTotal.WithLabelValues().Dec() } // RegisterValidatedRelease registers a Release as validated, adding a new observation for the @@ -213,10 +253,30 @@ func RegisterNewRelease() { ReleaseConcurrentTotal.WithLabelValues().Inc() } -// RegisterNewReleaseProcessing registers a new Release processing, adding a new observation for the -// Release start processing duration and increasing the number of concurrent processings. If either the -// startTime or the processingStartTime are nil, no action will be taken. -func RegisterNewReleaseProcessing(startTime, processingStartTime *metav1.Time, reason, target string) { +// RegisterNewReleaseManagedPipelineProcessing registers a new Release Managed Pipeline processing, +// adding a new observation for the Release start managed pipeline processing duration and increasing +// the number of concurrent processings. If either the startTime or the processingStartTime are nil, no +// action will be taken. +func RegisterNewReleaseManagedPipelineProcessing(startTime, processingStartTime *metav1.Time, reason, target string) { + if startTime == nil || processingStartTime == nil { + return + } + + ReleasePreProcessingDurationSeconds. + With(prometheus.Labels{ + "reason": reason, + "target": target, + }). + Observe(processingStartTime.Sub(startTime.Time).Seconds()) + + ReleaseConcurrentManagedPipelineProcessingsTotal.WithLabelValues().Inc() +} + +// RegisterNewReleaseTenantPipelineProcessing registers a new Release Tenant Pipeline processing, +// adding a new observation for the Release start tenant pipeline processing duration and increasing +// the number of concurrent processings. If either the startTime or the processingStartTime are nil, no +// action will be taken. +func RegisterNewReleaseTenantPipelineProcessing(startTime, processingStartTime *metav1.Time, reason, target string) { if startTime == nil || processingStartTime == nil { return } @@ -228,7 +288,7 @@ func RegisterNewReleaseProcessing(startTime, processingStartTime *metav1.Time, r }). Observe(processingStartTime.Sub(startTime.Time).Seconds()) - ReleaseConcurrentProcessingsTotal.WithLabelValues().Inc() + ReleaseConcurrentTenantPipelineProcessingsTotal.WithLabelValues().Inc() } // RegisterNewReleasePostActionsExecution register a new Release post-actions execution, increasing the number of @@ -240,13 +300,15 @@ func RegisterNewReleasePostActionsExecution() { func init() { metrics.Registry.MustRegister( ReleaseConcurrentTotal, - ReleaseConcurrentProcessingsTotal, + ReleaseConcurrentManagedPipelineProcessingsTotal, + ReleaseConcurrentTenantPipelineProcessingsTotal, ReleaseConcurrentPostActionsExecutionsTotal, ReleasePreProcessingDurationSeconds, ReleaseValidationDurationSeconds, ReleaseDurationSeconds, ReleasePostActionsExecutionDurationSeconds, - ReleaseProcessingDurationSeconds, + ReleaseManagedPipelineProcessingDurationSeconds, + ReleaseTenantPipelineProcessingDurationSeconds, ReleaseTotal, ) } diff --git a/tekton/utils/zz_generated.deepcopy.go b/tekton/utils/zz_generated.deepcopy.go index 063d5824..aa8d4482 100644 --- a/tekton/utils/zz_generated.deepcopy.go +++ b/tekton/utils/zz_generated.deepcopy.go @@ -1,4 +1,5 @@ //go:build !ignore_autogenerated +// +build !ignore_autogenerated /* Copyright 2022.