diff --git a/.tekton/release-service-pull-request.yaml b/.tekton/release-service-pull-request.yaml index 22431a984..77555d7b2 100644 --- a/.tekton/release-service-pull-request.yaml +++ b/.tekton/release-service-pull-request.yaml @@ -30,6 +30,8 @@ spec: value: . - name: revision value: '{{revision}}' + - name: build-source-image + value: 'true' pipelineSpec: finally: - name: show-sbom @@ -93,10 +95,6 @@ spec: description: Skip checks against built image name: skip-checks type: string - - default: "true" - description: Skip optional checks, set false if you want to run optional checks - name: skip-optional - type: string - default: "false" description: Execute the build with network isolation name: hermetic @@ -113,6 +111,10 @@ spec: description: Image tag expiration time, time values could be something like 1h, 2d, 3w for hours, days, and weeks, respectively. name: image-expires-after + - default: "true" + description: Build a source image. + name: build-source-image + type: string results: - description: "" name: IMAGE_URL @@ -138,18 +140,13 @@ spec: value: $(params.rebuild) - name: skip-checks value: $(params.skip-checks) - - name: skip-optional - value: $(params.skip-optional) - - name: pipelinerun-name - value: $(context.pipelineRun.name) - - name: pipelinerun-uid value: $(context.pipelineRun.uid) taskRef: params: - name: name value: init - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-init:0.1@sha256:c35cc37d6f40fef0f2ed614b502b058e13fe7af29c0888bc4799fd625b6f3374 + value: quay.io/redhat-appstudio-tekton-catalog/task-init:0.2@sha256:3d8f01fa59596a998d30dc700fcf7377f09d60008337290eebaeaf604512ce2b - name: kind value: task resolver: bundles @@ -191,7 +188,7 @@ spec: - name: name value: prefetch-dependencies - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:9630dd7d50002fdffb4a406fb0c538703ef98bf2f4318249ac3a2c229938dbea + value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:0b7bec23b6c08f37138a86e569835842763b3aa42f4455fd70ba3986350e07c7 - name: kind value: task resolver: bundles @@ -226,7 +223,7 @@ spec: - name: name value: buildah - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.1@sha256:9e7be6d3f2cde33fabfda9d454757530ce7f73e2414c00da1a3ebabf95fc52c5 + value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.1@sha256:351af2c0e5eeb92a5d6d4083847c1559475b596cda7671f489756d5302a4c847 - name: kind value: task resolver: bundles @@ -251,7 +248,7 @@ spec: - name: name value: inspect-image - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-inspect-image:0.1@sha256:ff8a4844ac36a8cbeecf02874e73952f314089cf497037ed762fa01dde397225 + value: quay.io/redhat-appstudio-tekton-catalog/task-inspect-image:0.1@sha256:ab050621d5f6addf0b6c07451e91a6b134b4d5f402c780abdbf9842a8ff18504 - name: kind value: task resolver: bundles @@ -263,6 +260,35 @@ spec: workspaces: - name: source workspace: workspace + - name: build-source-image + params: + - name: BINARY_IMAGE + value: $(params.output-image) + - name: BASE_IMAGES + value: $(tasks.build-container.results.BASE_IMAGES_DIGESTS) + runAfter: + - build-container + taskRef: + params: + - name: name + value: source-build + - name: bundle + value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:f8c5dec871fb5347eb2fc61d44754bcc101897aecf953b374ab3e8315e1a9804 + - name: kind + value: task + resolver: bundles + when: + - input: $(tasks.init.results.build) + operator: in + values: + - "true" + - input: $(params.build-source-image) + operator: in + values: + - "true" + workspaces: + - name: workspace + workspace: workspace - name: deprecated-base-image-check params: - name: BASE_IMAGES_DIGESTS @@ -272,7 +298,7 @@ spec: - name: name value: deprecated-image-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.3@sha256:61f9b273432c6d087393de6ab972a2f7af1c385a1cc36447b215dabf5d9ba0de + value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.3@sha256:d87f8c50a674f57527a0c4f3df6d9093941a2ae84739b55368b3c11702ce340c - name: kind value: task resolver: bundles @@ -294,7 +320,7 @@ spec: - name: name value: clair-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:fe27ccc0603b63b313329b76aa888523dabf7368fc25e976fcccc4d52bb3a5e3 + value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:fbe1ab58531d856fba360060d3884a0606310a966e2d01ba9305da9eb01ab916 - name: kind value: task resolver: bundles @@ -311,7 +337,7 @@ spec: - name: name value: sast-snyk-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:339903f4a95b45b3f2dd4e6941b84679eaa70683bde83f46b0d835680c7aae8b + value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:eee508768b14655275fbcc2f42f9da1ab553b872dcbe113b0896aa9bcf7e1adf - name: kind value: task resolver: bundles @@ -336,7 +362,7 @@ spec: - name: name value: clamav-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:de8c855a71d5bb6b838246f5c5a1a420747379b9cca047ce79b89c9b53812267 + value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:d72cb58db88289559676676c3db43906718028e07279f70ddb12ed8bdc8e2860 - name: kind value: task resolver: bundles @@ -358,7 +384,7 @@ spec: - name: name value: sbom-json-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sbom-json-check:0.1@sha256:563150a37f3802ab481be73b562f02f5a26ac3a11f116f247096620fe7a1ca48 + value: quay.io/redhat-appstudio-tekton-catalog/task-sbom-json-check:0.1@sha256:717e6e33f02dbe1a28fb743f32699e002c944680c251a50b644f27becb9208e9 - name: kind value: task resolver: bundles diff --git a/.tekton/release-service-push.yaml b/.tekton/release-service-push.yaml index df534ea1e..877fc6f74 100644 --- a/.tekton/release-service-push.yaml +++ b/.tekton/release-service-push.yaml @@ -27,6 +27,8 @@ spec: value: . - name: revision value: '{{revision}}' + - name: build-source-image + value: 'true' pipelineSpec: finally: - name: show-sbom @@ -38,7 +40,7 @@ spec: - name: name value: show-sbom - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-show-sbom:0.1@sha256:202d3c3385120ea847d8f0a82bd8d9d5e873d67f981d6f8a51fb1706caaf6bef + value: quay.io/redhat-appstudio-tekton-catalog/task-show-sbom:0.1@sha256:82737c8d365c620295fa526d21a481d4614f657800175ddc0ccd7846c54207f8 - name: kind value: task resolver: bundles @@ -90,10 +92,6 @@ spec: description: Skip checks against built image name: skip-checks type: string - - default: "true" - description: Skip optional checks, set false if you want to run optional checks - name: skip-optional - type: string - default: "false" description: Execute the build with network isolation name: hermetic @@ -110,6 +108,10 @@ spec: description: Image tag expiration time, time values could be something like 1h, 2d, 3w for hours, days, and weeks, respectively. name: image-expires-after + - default: "true" + description: Build a source image. + name: build-source-image + type: string results: - description: "" name: IMAGE_URL @@ -135,18 +137,12 @@ spec: value: $(params.rebuild) - name: skip-checks value: $(params.skip-checks) - - name: skip-optional - value: $(params.skip-optional) - - name: pipelinerun-name - value: $(context.pipelineRun.name) - - name: pipelinerun-uid - value: $(context.pipelineRun.uid) taskRef: params: - name: name value: init - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-init:0.1@sha256:c35cc37d6f40fef0f2ed614b502b058e13fe7af29c0888bc4799fd625b6f3374 + value: quay.io/redhat-appstudio-tekton-catalog/task-init:0.2@sha256:3d8f01fa59596a998d30dc700fcf7377f09d60008337290eebaeaf604512ce2b - name: kind value: task resolver: bundles @@ -188,7 +184,7 @@ spec: - name: name value: prefetch-dependencies - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:9630dd7d50002fdffb4a406fb0c538703ef98bf2f4318249ac3a2c229938dbea + value: quay.io/redhat-appstudio-tekton-catalog/task-prefetch-dependencies:0.1@sha256:0b7bec23b6c08f37138a86e569835842763b3aa42f4455fd70ba3986350e07c7 - name: kind value: task resolver: bundles @@ -223,7 +219,7 @@ spec: - name: name value: buildah - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.1@sha256:9e7be6d3f2cde33fabfda9d454757530ce7f73e2414c00da1a3ebabf95fc52c5 + value: quay.io/redhat-appstudio-tekton-catalog/task-buildah:0.1@sha256:351af2c0e5eeb92a5d6d4083847c1559475b596cda7671f489756d5302a4c847 - name: kind value: task resolver: bundles @@ -248,7 +244,7 @@ spec: - name: name value: inspect-image - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-inspect-image:0.1@sha256:ff8a4844ac36a8cbeecf02874e73952f314089cf497037ed762fa01dde397225 + value: quay.io/redhat-appstudio-tekton-catalog/task-inspect-image:0.1@sha256:d27c6ff7b9be6df786f489f8a5d4a8f0619d77e45f0d12e4a730157b60873c82 - name: kind value: task resolver: bundles @@ -260,6 +256,35 @@ spec: workspaces: - name: source workspace: workspace + - name: build-source-image + params: + - name: BINARY_IMAGE + value: $(params.output-image) + - name: BASE_IMAGES + value: $(tasks.build-container.results.BASE_IMAGES_DIGESTS) + runAfter: + - build-container + taskRef: + params: + - name: name + value: source-build + - name: bundle + value: quay.io/redhat-appstudio-tekton-catalog/task-source-build:0.1@sha256:f8c5dec871fb5347eb2fc61d44754bcc101897aecf953b374ab3e8315e1a9804 + - name: kind + value: task + resolver: bundles + when: + - input: $(tasks.init.results.build) + operator: in + values: + - "true" + - input: $(params.build-source-image) + operator: in + values: + - "true" + workspaces: + - name: workspace + workspace: workspace - name: deprecated-base-image-check params: - name: BASE_IMAGES_DIGESTS @@ -269,7 +294,7 @@ spec: - name: name value: deprecated-image-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.3@sha256:61f9b273432c6d087393de6ab972a2f7af1c385a1cc36447b215dabf5d9ba0de + value: quay.io/redhat-appstudio-tekton-catalog/task-deprecated-image-check:0.3@sha256:a299ff57d97f3924020634625dfb9bbc66547124ca23a3396e338c645f7b4a8e - name: kind value: task resolver: bundles @@ -291,7 +316,7 @@ spec: - name: name value: clair-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:fe27ccc0603b63b313329b76aa888523dabf7368fc25e976fcccc4d52bb3a5e3 + value: quay.io/redhat-appstudio-tekton-catalog/task-clair-scan:0.1@sha256:63b42c0fc23d05e26776a0e7c4f0ab00750096ebfe1eed9a7ba96f8b27713fbf - name: kind value: task resolver: bundles @@ -308,7 +333,7 @@ spec: - name: name value: sast-snyk-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:339903f4a95b45b3f2dd4e6941b84679eaa70683bde83f46b0d835680c7aae8b + value: quay.io/redhat-appstudio-tekton-catalog/task-sast-snyk-check:0.1@sha256:47515cb119225bba55c593876610bd890f8efcbb66bb57fb0c0881ddd47ce558 - name: kind value: task resolver: bundles @@ -333,7 +358,7 @@ spec: - name: name value: clamav-scan - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:de8c855a71d5bb6b838246f5c5a1a420747379b9cca047ce79b89c9b53812267 + value: quay.io/redhat-appstudio-tekton-catalog/task-clamav-scan:0.1@sha256:353fa2cda9855217cfcec3303973b666a10f384795630cf0eb13b874c24b0f7a - name: kind value: task resolver: bundles @@ -355,7 +380,7 @@ spec: - name: name value: sbom-json-check - name: bundle - value: quay.io/redhat-appstudio-tekton-catalog/task-sbom-json-check:0.1@sha256:563150a37f3802ab481be73b562f02f5a26ac3a11f116f247096620fe7a1ca48 + value: quay.io/redhat-appstudio-tekton-catalog/task-sbom-json-check:0.1@sha256:bf49861b3bbee2129e8d1b5966fc2a7c3f259d96a5fcef5674d05c9cb21ab540 - name: kind value: task resolver: bundles diff --git a/Dockerfile b/Dockerfile index 9593e1e3e..5f899003e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -28,7 +28,7 @@ ENV ENABLE_WEBHOOKS=${ENABLE_WEBHOOKS} # Use ubi-micro as minimal base image to package the manager binary # See https://catalog.redhat.com/software/containers/ubi9/ubi-micro/615bdf943f6014fa45ae1b58 -FROM registry.access.redhat.com/ubi9/ubi-micro:9.2-15.1696515526 +FROM registry.access.redhat.com/ubi9/ubi-micro:9.3-9 COPY --from=builder /opt/app-root/src/manager / # It is mandatory to set these labels diff --git a/Makefile b/Makefile index 197398976..c078888fb 100644 --- a/Makefile +++ b/Makefile @@ -8,10 +8,10 @@ TAG_NAME ?= next CERT_MANAGER_VERSION ?= v1.8.0 ENABLE_WEBHOOKS ?= true -# DEFAULT_PERSISTENT_VOLUME_CLAIM defines the default PVC to be used in the Release pipeline workspace declaration. +# DEFAULT_PERSISTENT_VOLUME_CLAIM defines the default PVC to be used in the managed Release Pipeline workspace declaration. DEFAULT_RELEASE_PVC ?= release-pvc -# DEFAULT_WORKSPACE_NAME defines the default name for the workspace that will be used in the Release pipeline. +# DEFAULT_WORKSPACE_NAME defines the default name for the workspace that will be used in the managed Release Pipeline. DEFAULT_RELEASE_WORKSPACE_NAME ?= release-workspace # CHANNELS define the bundle channels used in the bundle. diff --git a/README.md b/README.md index 8cc120b99..3e20c4cc5 100644 --- a/README.md +++ b/README.md @@ -67,4 +67,6 @@ by default, this operator exports the following custom metrics: | release_duration_seconds | Histogram | How long in seconds a Release takes to complete. | | release_post_actions_execution_duration_seconds | Histogram | How long in seconds Release post-actions take to complete. | | release_processing_duration_seconds | Histogram | How long in seconds a Release processing takes to complete. | +| release_pre_processing_duration_seconds | Histogram | How long in seconds a Release takes to start processing | +| release_validation_duration_seconds | Histogram | How long in seconds a Release takes to validate | | release_total | Counter | Total number of releases reconciled by the operator. | diff --git a/api/v1alpha1/release_types.go b/api/v1alpha1/release_types.go index 4a506e0cd..7d24da0d0 100644 --- a/api/v1alpha1/release_types.go +++ b/api/v1alpha1/release_types.go @@ -17,9 +17,10 @@ limitations under the License. package v1alpha1 import ( - "github.com/redhat-appstudio/operator-toolkit/conditions" "time" + "github.com/redhat-appstudio/operator-toolkit/conditions" + "github.com/redhat-appstudio/release-service/metrics" "k8s.io/apimachinery/pkg/runtime" @@ -39,7 +40,7 @@ type ReleaseSpec struct { // +required ReleasePlan string `json:"releasePlan"` - // Data is an unstructured key used for providing data for the release Pipeline + // Data is an unstructured key used for providing data for the managed Release Pipeline // +kubebuilder:pruning:PreserveUnknownFields // +optional Data *runtime.RawExtension `json:"data,omitempty"` @@ -138,7 +139,7 @@ type ProcessingInfo struct { // +optional CompletionTime *metav1.Time `json:"completionTime,omitempty"` - // PipelineRun contains the namespaced name of the release PipelineRun executed as part of this release + // PipelineRun contains the namespaced name of the managed Release PipelineRun executed as part of this release // +kubebuilder:validation:Pattern=^[a-z0-9]([-a-z0-9]*[a-z0-9])?\/[a-z0-9]([-a-z0-9]*[a-z0-9])?$ // +optional PipelineRun string `json:"pipelineRun,omitempty"` @@ -331,7 +332,12 @@ func (r *Release) MarkProcessing(message string) { conditions.SetConditionWithMessage(&r.Status.Conditions, processedConditionType, metav1.ConditionFalse, ProgressingReason, message) - go metrics.RegisterNewReleaseProcessing() + go metrics.RegisterNewReleaseProcessing( + r.Status.Processing.StartTime, + r.Status.StartTime, + ProgressingReason.String(), + r.Status.Target, + ) } // MarkProcessingFailed marks the Release processing as failed. @@ -463,6 +469,13 @@ func (r *Release) MarkValidated() { r.Status.Validation.Time = &metav1.Time{Time: time.Now()} conditions.SetCondition(&r.Status.Conditions, validatedConditionType, metav1.ConditionTrue, SucceededReason) + + go metrics.RegisterValidatedRelease( + r.Status.StartTime, + r.Status.Validation.Time, + SucceededReason.String(), + r.Status.Target, + ) } // MarkValidationFailed marks the Release validation as failed. @@ -473,6 +486,13 @@ func (r *Release) MarkValidationFailed(message string) { r.Status.Validation.Time = &metav1.Time{Time: time.Now()} conditions.SetConditionWithMessage(&r.Status.Conditions, validatedConditionType, metav1.ConditionFalse, FailedReason, message) + + go metrics.RegisterValidatedRelease( + r.Status.StartTime, + r.Status.Validation.Time, + FailedReason.String(), + r.Status.Target, + ) } // SetAutomated marks the Release as automated. diff --git a/api/v1alpha1/releaseplan_types.go b/api/v1alpha1/releaseplan_types.go index bbb688207..0ab91196d 100644 --- a/api/v1alpha1/releaseplan_types.go +++ b/api/v1alpha1/releaseplan_types.go @@ -35,13 +35,13 @@ type ReleasePlanSpec struct { // +required Application string `json:"application"` - // Data is an unstructured key used for providing data for the release Pipeline + // Data is an unstructured key used for providing data for the managed Release Pipeline // +kubebuilder:pruning:PreserveUnknownFields // +optional Data *runtime.RawExtension `json:"data,omitempty"` // PipelineRef is an optional reference to a Pipeline that would be executed - // before the release Pipeline + // before the managed Release Pipeline // +optional PipelineRef *tektonutils.PipelineRef `json:"pipelineRef,omitempty"` diff --git a/api/v1alpha1/releaseplanadmission_types.go b/api/v1alpha1/releaseplanadmission_types.go index 241e3ea05..0b1fadf79 100644 --- a/api/v1alpha1/releaseplanadmission_types.go +++ b/api/v1alpha1/releaseplanadmission_types.go @@ -34,7 +34,7 @@ type ReleasePlanAdmissionSpec struct { // +required Applications []string `json:"applications"` - // Data is an unstructured key used for providing data for the release Pipeline + // Data is an unstructured key used for providing data for the managed Release Pipeline // +kubebuilder:pruning:PreserveUnknownFields // +optional Data *runtime.RawExtension `json:"data,omitempty"` @@ -49,7 +49,7 @@ type ReleasePlanAdmissionSpec struct { // +required Origin string `json:"origin"` - // PipelineRef is a reference to the Pipeline to be executed by the release PipelineRun + // PipelineRef is a reference to the Pipeline to be executed by the managed Release PipelineRun // +required PipelineRef *tektonutils.PipelineRef `json:"pipelineRef"` @@ -59,7 +59,7 @@ type ReleasePlanAdmissionSpec struct { Policy string `json:"policy"` // ServiceAccount is the name of the service account to use in the - // release PipelineRun to gain elevated privileges + // managed Release PipelineRun to gain elevated privileges // +kubebuilder:validation:Pattern=^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ // +optional ServiceAccount string `json:"serviceAccount,omitempty"` diff --git a/config/crd/bases/appstudio.redhat.com_releaseplanadmissions.yaml b/config/crd/bases/appstudio.redhat.com_releaseplanadmissions.yaml index d1bdecddf..e989d143c 100644 --- a/config/crd/bases/appstudio.redhat.com_releaseplanadmissions.yaml +++ b/config/crd/bases/appstudio.redhat.com_releaseplanadmissions.yaml @@ -53,7 +53,7 @@ spec: type: array data: description: Data is an unstructured key used for providing data for - the release Pipeline + the managed Release Pipeline type: object x-kubernetes-preserve-unknown-fields: true environment: @@ -68,7 +68,7 @@ spec: type: string pipelineRef: description: PipelineRef is a reference to the Pipeline to be executed - by the release PipelineRun + by the managed Release PipelineRun properties: params: description: Params is a slice of parameters for a given resolver @@ -106,7 +106,7 @@ spec: type: string serviceAccount: description: ServiceAccount is the name of the service account to - use in the release PipelineRun to gain elevated privileges + use in the managed Release PipelineRun to gain elevated privileges pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ type: string required: diff --git a/config/crd/bases/appstudio.redhat.com_releaseplans.yaml b/config/crd/bases/appstudio.redhat.com_releaseplans.yaml index fe5f8e6e3..9b94667b8 100644 --- a/config/crd/bases/appstudio.redhat.com_releaseplans.yaml +++ b/config/crd/bases/appstudio.redhat.com_releaseplans.yaml @@ -51,12 +51,12 @@ spec: type: string data: description: Data is an unstructured key used for providing data for - the release Pipeline + the managed Release Pipeline type: object x-kubernetes-preserve-unknown-fields: true pipelineRef: description: PipelineRef is an optional reference to a Pipeline that - would be executed before the release Pipeline + would be executed before the managed Release Pipeline properties: params: description: Params is a slice of parameters for a given resolver diff --git a/config/crd/bases/appstudio.redhat.com_releases.yaml b/config/crd/bases/appstudio.redhat.com_releases.yaml index d72923494..300aaf51a 100644 --- a/config/crd/bases/appstudio.redhat.com_releases.yaml +++ b/config/crd/bases/appstudio.redhat.com_releases.yaml @@ -52,7 +52,7 @@ spec: properties: data: description: Data is an unstructured key used for providing data for - the release Pipeline + the managed Release Pipeline type: object x-kubernetes-preserve-unknown-fields: true releasePlan: @@ -209,8 +209,8 @@ spec: format: date-time type: string pipelineRun: - description: PipelineRun contains the namespaced name of the release - PipelineRun executed as part of this release + 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 startTime: diff --git a/controllers/release/adapter.go b/controllers/release/adapter.go index ad9fff1c8..dd3619196 100644 --- a/controllers/release/adapter.go +++ b/controllers/release/adapter.go @@ -244,14 +244,14 @@ func (a *adapter) EnsureReleaseIsRunning() (controller.OperationResult, error) { return controller.ContinueProcessing() } -// EnsureReleaseIsProcessed is an operation that will ensure that a release PipelineRun associated to the Release -// being processed exists. Otherwise, it will create a new release PipelineRun. +// EnsureReleaseIsProcessed is an operation that will ensure that a managed Release PipelineRun associated to the Release +// being processed exists. Otherwise, it will create a new managed Release PipelineRun. func (a *adapter) EnsureReleaseIsProcessed() (controller.OperationResult, error) { if a.release.HasProcessingFinished() { return controller.ContinueProcessing() } - pipelineRun, err := a.loader.GetReleasePipelineRun(a.ctx, a.client, a.release) + pipelineRun, err := a.loader.GetManagedReleasePipelineRun(a.ctx, a.client, a.release) if err != nil && !errors.IsNotFound(err) { return controller.RequeueWithError(err) } @@ -263,12 +263,12 @@ func (a *adapter) EnsureReleaseIsProcessed() (controller.OperationResult, error) } if pipelineRun == nil { - pipelineRun, err = a.createReleasePipelineRun(resources) + pipelineRun, err = a.createManagedPipelineRun(resources) if err != nil { return controller.RequeueWithError(err) } - a.logger.Info("Created release PipelineRun", + a.logger.Info("Created managed Release PipelineRun", "PipelineRun.Name", pipelineRun.Name, "PipelineRun.Namespace", pipelineRun.Namespace) } @@ -300,14 +300,14 @@ 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 +// EnsureReleaseProcessingIsTracked is an operation that will ensure that the managed Release PipelineRun status is tracked // in the Release being processed. func (a *adapter) EnsureReleaseProcessingIsTracked() (controller.OperationResult, error) { if !a.release.IsProcessing() || a.release.HasProcessingFinished() { return controller.ContinueProcessing() } - pipelineRun, err := a.loader.GetReleasePipelineRun(a.ctx, a.client, a.release) + pipelineRun, err := a.loader.GetManagedReleasePipelineRun(a.ctx, a.client, a.release) if err != nil { return controller.RequeueWithError(err) } @@ -331,12 +331,12 @@ func (a *adapter) EnsureReleaseProcessingIsTracked() (controller.OperationResult return controller.ContinueProcessing() } -// createReleasePipelineRun creates and returns a new release PipelineRun. The new PipelineRun will include owner +// createManagedPipelineRun creates and returns a new managed Release PipelineRun. The new PipelineRun will include owner // annotations, so it triggers Release reconciles whenever it changes. The Pipeline information and the parameters to it // will be extracted from the given ReleaseStrategy. The Release's Snapshot will also be passed to the release // PipelineRun. -func (a *adapter) createReleasePipelineRun(resources *loader.ProcessingResources) (*tektonv1.PipelineRun, error) { - pipelineRun := tekton.NewReleasePipelineRun("release-pipelinerun", resources.ReleasePlanAdmission.Namespace). +func (a *adapter) createManagedPipelineRun(resources *loader.ProcessingResources) (*tektonv1.PipelineRun, error) { + pipelineRun := tekton.NewReleasePipelineRun("managed-release", resources.ReleasePlanAdmission.Namespace). WithObjectReferences(a.release, resources.ReleasePlan, resources.ReleasePlanAdmission, resources.Snapshot). WithOwner(a.release). @@ -345,6 +345,7 @@ func (a *adapter) createReleasePipelineRun(resources *loader.ProcessingResources WithServiceAccount(resources.ReleasePlanAdmission.Spec.ServiceAccount). WithTimeout(resources.ReleasePlanAdmission.Spec.PipelineRef.Timeout). WithPipelineRef(resources.ReleasePlanAdmission.Spec.PipelineRef.ToTektonPipelineRef()). + WithTaskGitPipelineParameters(resources.ReleasePlanAdmission.Spec.PipelineRef). WithEnterpriseContractConfigMap(resources.EnterpriseContractConfigMap). WithEnterpriseContractPolicy(resources.EnterpriseContractPolicy). AsPipelineRun() @@ -406,7 +407,7 @@ func (a *adapter) createOrUpdateSnapshotEnvironmentBinding(releasePlanAdmission // 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) + pipelineRun, err := a.loader.GetManagedReleasePipelineRun(a.ctx, a.client, a.release) if err != nil { return err } @@ -516,7 +517,7 @@ func (a *adapter) registerProcessingData(releasePipelineRun *tektonv1.PipelineRu } // registerProcessingStatus updates the status of the Release being processed by monitoring the status of the -// associated release PipelineRun and setting the appropriate state in the Release. If the PipelineRun hasn't +// 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() { @@ -609,7 +610,7 @@ func (a *adapter) validateProcessingResources() *controller.ValidationResult { return &controller.ValidationResult{Valid: true} } -// validatePipelineRef checks that the release PipelineRun ref passes the checks from the ReleaseServiceConfig. +// validatePipelineRef checks that the managed Release PipelineRun ref passes the checks from the ReleaseServiceConfig. func (a *adapter) validatePipelineRef() *controller.ValidationResult { releasePlanAdmission, err := a.loader.GetActiveReleasePlanAdmissionFromRelease(a.ctx, a.client, a.release) if err != nil { diff --git a/controllers/release/adapter_test.go b/controllers/release/adapter_test.go index 8b5122655..0e093a0e6 100644 --- a/controllers/release/adapter_test.go +++ b/controllers/release/adapter_test.go @@ -168,7 +168,7 @@ var _ = Describe("Release adapter", Ordered, func() { Expect(result.RequeueRequest && !result.CancelRequest).To(BeTrue()) Expect(err).NotTo(HaveOccurred()) - pipelineRun, err := adapter.loader.GetReleasePipelineRun(adapter.ctx, adapter.client, adapter.release) + pipelineRun, err := adapter.loader.GetManagedReleasePipelineRun(adapter.ctx, adapter.client, adapter.release) Expect(pipelineRun).To(Or(BeNil(), HaveField("DeletionTimestamp", Not(BeNil())))) Expect(err).NotTo(HaveOccurred()) @@ -646,7 +646,7 @@ var _ = Describe("Release adapter", Ordered, func() { Expect(err).NotTo(HaveOccurred()) Expect(adapter.release.IsProcessing()).To(BeTrue()) - pipelineRun, err := adapter.loader.GetReleasePipelineRun(adapter.ctx, adapter.client, adapter.release) + pipelineRun, err := adapter.loader.GetManagedReleasePipelineRun(adapter.ctx, adapter.client, adapter.release) Expect(pipelineRun).NotTo(BeNil()) Expect(err).NotTo(HaveOccurred()) Expect(adapter.client.Delete(adapter.ctx, pipelineRun)).To(Succeed()) @@ -802,7 +802,7 @@ var _ = Describe("Release adapter", Ordered, func() { }) }) - When("createReleasePipelineRun is called", func() { + When("createManagedPipelineRun is called", func() { var ( adapter *adapter pipelineRun *tektonv1.PipelineRun @@ -825,13 +825,14 @@ var _ = Describe("Release adapter", Ordered, func() { } var err error - pipelineRun, err = adapter.createReleasePipelineRun(resources) + pipelineRun, err = adapter.createManagedPipelineRun(resources) Expect(pipelineRun).NotTo(BeNil()) Expect(err).NotTo(HaveOccurred()) }) - It("returns a PipelineRun", func() { + It("returns a PipelineRun with the right prefix", func() { Expect(reflect.TypeOf(pipelineRun)).To(Equal(reflect.TypeOf(&tektonv1.PipelineRun{}))) + Expect(pipelineRun.Name).To(HavePrefix("managed-release")) }) It("has the release reference", func() { @@ -871,14 +872,38 @@ var _ = Describe("Release adapter", Ordered, func() { }) It("references the pipeline specified in the ReleasePlanAdmission", func() { - var pipelineName string + var pipelineUrl string resolverParams := pipelineRun.Spec.PipelineRef.ResolverRef.Params for i := range resolverParams { - if resolverParams[i].Name == "name" { - pipelineName = resolverParams[i].Value.StringVal + if resolverParams[i].Name == "url" { + pipelineUrl = resolverParams[i].Value.StringVal } } - Expect(pipelineName).To(Equal(releasePlanAdmission.Spec.PipelineRef.Params[1].Value)) + Expect(pipelineUrl).To(Equal(releasePlanAdmission.Spec.PipelineRef.Params[0].Value)) + }) + + It("contains a parameter with the taskGitUrl", func() { + Expect(pipelineRun.Spec.Params).Should(ContainElement(HaveField("Name", "taskGitUrl"))) + var url string + resolverParams := pipelineRun.Spec.PipelineRef.ResolverRef.Params + for i := range resolverParams { + if resolverParams[i].Name == "url" { + url = resolverParams[i].Value.StringVal + } + } + Expect(pipelineRun.Spec.Params).Should(ContainElement(HaveField("Value.StringVal", url))) + }) + + It("contains a parameter with the taskGitRevision", func() { + Expect(pipelineRun.Spec.Params).Should(ContainElement(HaveField("Name", "taskGitRevision"))) + var revision string + resolverParams := pipelineRun.Spec.PipelineRef.ResolverRef.Params + for i := range resolverParams { + if resolverParams[i].Name == "revision" { + revision = resolverParams[i].Value.StringVal + } + } + Expect(pipelineRun.Spec.Params).Should(ContainElement(HaveField("Value.StringVal", revision))) }) It("contains the proper timeout value", func() { @@ -1003,12 +1028,12 @@ var _ = Describe("Release adapter", Ordered, func() { EnterpriseContractPolicy: enterpriseContractPolicy, Snapshot: snapshot, } - pipelineRun, err := adapter.createReleasePipelineRun(resources) + pipelineRun, err := adapter.createManagedPipelineRun(resources) Expect(pipelineRun).NotTo(BeNil()) Expect(err).NotTo(HaveOccurred()) Expect(adapter.finalizeRelease()).To(Succeed()) - pipelineRun, err = adapter.loader.GetReleasePipelineRun(adapter.ctx, adapter.client, adapter.release) + pipelineRun, err = adapter.loader.GetManagedReleasePipelineRun(adapter.ctx, adapter.client, adapter.release) Expect(err).NotTo(HaveOccurred()) Expect(pipelineRun).To(BeNil()) }) @@ -1688,11 +1713,11 @@ var _ = Describe("Release adapter", Ordered, func() { Origin: "default", Environment: environment.Name, PipelineRef: &tektonutils.PipelineRef{ - Resolver: "bundles", + Resolver: "git", Params: []tektonutils.Param{ - {Name: "bundle", Value: "quay.io/some/bundle"}, - {Name: "name", Value: "release-pipeline"}, - {Name: "kind", Value: "pipeline"}, + {Name: "url", Value: "my-url"}, + {Name: "revision", Value: "my-revision"}, + {Name: "pathInRepo", Value: "my-path"}, }, Timeout: "2h0m0s", }, diff --git a/loader/loader.go b/loader/loader.go index 148f79cea..a16460550 100644 --- a/loader/loader.go +++ b/loader/loader.go @@ -32,7 +32,7 @@ type ObjectLoader interface { GetMatchingReleasePlanAdmission(ctx context.Context, cli client.Client, releasePlan *v1alpha1.ReleasePlan) (*v1alpha1.ReleasePlanAdmission, error) GetMatchingReleasePlans(ctx context.Context, cli client.Client, releasePlanAdmission *v1alpha1.ReleasePlanAdmission) (*v1alpha1.ReleasePlanList, error) GetRelease(ctx context.Context, cli client.Client, name, namespace string) (*v1alpha1.Release, error) - GetReleasePipelineRun(ctx context.Context, cli client.Client, release *v1alpha1.Release) (*tektonv1.PipelineRun, error) + GetManagedReleasePipelineRun(ctx context.Context, cli client.Client, release *v1alpha1.Release) (*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) @@ -207,9 +207,9 @@ func (l *loader) GetRelease(ctx context.Context, cli client.Client, name, namesp return release, toolkit.GetObject(name, namespace, cli, ctx, release) } -// GetReleasePipelineRun returns the PipelineRun referenced by the given Release or nil if it's not found. In the case +// GetManagedReleasePipelineRun returns the managed 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) { +func (l *loader) GetManagedReleasePipelineRun(ctx context.Context, cli client.Client, release *v1alpha1.Release) (*tektonv1.PipelineRun, error) { pipelineRuns := &tektonv1.PipelineRunList{} err := cli.List(ctx, pipelineRuns, client.Limit(1), diff --git a/loader/loader_mock.go b/loader/loader_mock.go index 28a9568bf..f652d3fbf 100644 --- a/loader/loader_mock.go +++ b/loader/loader_mock.go @@ -130,10 +130,10 @@ func (l *mockLoader) GetRelease(ctx context.Context, cli client.Client, name, na return toolkit.GetMockedResourceAndErrorFromContext(ctx, ReleaseContextKey, &v1alpha1.Release{}) } -// GetReleasePipelineRun returns the resource and error passed as values of the context. -func (l *mockLoader) GetReleasePipelineRun(ctx context.Context, cli client.Client, release *v1alpha1.Release) (*tektonv1.PipelineRun, error) { +// GetManagedReleasePipelineRun returns the resource and error passed as values of the context. +func (l *mockLoader) GetManagedReleasePipelineRun(ctx context.Context, cli client.Client, release *v1alpha1.Release) (*tektonv1.PipelineRun, error) { if ctx.Value(ReleasePipelineRunContextKey) == nil { - return l.loader.GetReleasePipelineRun(ctx, cli, release) + return l.loader.GetManagedReleasePipelineRun(ctx, cli, release) } return toolkit.GetMockedResourceAndErrorFromContext(ctx, ReleasePipelineRunContextKey, &tektonv1.PipelineRun{}) } diff --git a/loader/loader_mock_test.go b/loader/loader_mock_test.go index f680761d5..1f961f27e 100644 --- a/loader/loader_mock_test.go +++ b/loader/loader_mock_test.go @@ -170,7 +170,7 @@ var _ = Describe("Release Adapter", Ordered, func() { }) }) - When("calling GetReleasePipelineRun", func() { + When("calling GetManagedReleasePipelineRun", func() { It("returns the resource and error from the context", func() { pipelineRun := &tektonv1.PipelineRun{} mockContext := toolkit.GetMockedContext(ctx, []toolkit.MockData{ @@ -179,7 +179,7 @@ var _ = Describe("Release Adapter", Ordered, func() { Resource: pipelineRun, }, }) - resource, err := loader.GetReleasePipelineRun(mockContext, nil, nil) + resource, err := loader.GetManagedReleasePipelineRun(mockContext, nil, nil) Expect(resource).To(Equal(pipelineRun)) Expect(err).To(BeNil()) }) diff --git a/loader/loader_test.go b/loader/loader_test.go index 55de1f336..489833ddd 100644 --- a/loader/loader_test.go +++ b/loader/loader_test.go @@ -274,9 +274,9 @@ var _ = Describe("Release Adapter", Ordered, func() { }) }) - When("calling GetReleasePipelineRun", func() { + When("calling GetManagedReleasePipelineRun", func() { It("returns a PipelineRun if the labels match with the release data", func() { - returnedObject, err := loader.GetReleasePipelineRun(ctx, k8sClient, release) + returnedObject, err := loader.GetManagedReleasePipelineRun(ctx, k8sClient, release) Expect(err).NotTo(HaveOccurred()) Expect(returnedObject).NotTo(Equal(&tektonv1.PipelineRun{})) Expect(returnedObject.Name).To(Equal(pipelineRun.Name)) @@ -286,7 +286,7 @@ var _ = Describe("Release Adapter", Ordered, func() { modifiedRelease := release.DeepCopy() modifiedRelease.Name = "non-existing-release" - returnedObject, err := loader.GetReleasePipelineRun(ctx, k8sClient, modifiedRelease) + returnedObject, err := loader.GetManagedReleasePipelineRun(ctx, k8sClient, modifiedRelease) Expect(err).NotTo(HaveOccurred()) Expect(returnedObject).To(BeNil()) }) diff --git a/metadata/labels.go b/metadata/labels.go index 72f8f17de..1b16903af 100644 --- a/metadata/labels.go +++ b/metadata/labels.go @@ -45,7 +45,7 @@ var ( ReleasePlanAdmissionLabel = fmt.Sprintf("release.%s/releasePlanAdmission", rhtapDomain) ) -// Prefixes to be used by Release Pipeline Labels +// Prefixes to be used by Release Pipelines labels var ( // pipelinesLabelPrefix is the prefix of the pipelines label pipelinesLabelPrefix = fmt.Sprintf("pipelines.%s", rhtapDomain) diff --git a/metrics/release.go b/metrics/release.go index 4d2db31ec..f7a2c148d 100644 --- a/metrics/release.go +++ b/metrics/release.go @@ -70,6 +70,34 @@ var ( Buckets: []float64{60, 150, 300, 450, 600, 750, 900, 1050, 1200, 1800, 3600}, } + ReleasePreProcessingDurationSeconds = prometheus.NewHistogramVec( + releasePreProcessingDurationSecondsOpts, + releasePreProcessingDurationSecondsLabels, + ) + releasePreProcessingDurationSecondsLabels = []string{ + "reason", + "target", + } + releasePreProcessingDurationSecondsOpts = prometheus.HistogramOpts{ + Name: "release_pre_processing_duration_seconds", + Help: "How long in seconds a Release takes to start processing", + Buckets: []float64{5, 10, 15, 30, 45, 60, 90, 120, 180, 240, 300}, + } + + ReleaseValidationDurationSeconds = prometheus.NewHistogramVec( + releaseValidationDurationSecondsOpts, + releaseValidationDurationSecondsLabels, + ) + releaseValidationDurationSecondsLabels = []string{ + "reason", + "target", + } + releaseValidationDurationSecondsOpts = prometheus.HistogramOpts{ + Name: "release_validation_duration_seconds", + Help: "How long in seconds a Release takes to validate", + Buckets: []float64{5, 10, 15, 30, 45, 60, 90, 120, 180, 240, 300}, + } + ReleaseDurationSeconds = prometheus.NewHistogramVec( releaseDurationSecondsOpts, releaseDurationSecondsLabels, @@ -208,6 +236,22 @@ func RegisterCompletedReleaseProcessing(startTime, completionTime *metav1.Time, ReleaseConcurrentProcessingsTotal.WithLabelValues().Dec() } +// RegisterValidatedRelease registers a Release as validated, adding a new observation for the +// Release validated seconds. If either the startTime or the validationTime are nil, +// no action will be taken. +func RegisterValidatedRelease(startTime, validationTime *metav1.Time, reason, target string) { + if validationTime == nil || startTime == nil { + return + } + + ReleaseValidationDurationSeconds. + With(prometheus.Labels{ + "reason": reason, + "target": target, + }). + Observe(validationTime.Sub(startTime.Time).Seconds()) +} + // RegisterNewRelease register a new Release, increasing the number of concurrent releases. func RegisterNewRelease() { ReleaseConcurrentTotal.WithLabelValues().Inc() @@ -218,8 +262,21 @@ func RegisterNewReleaseDeployment() { ReleaseConcurrentDeploymentsTotal.WithLabelValues().Inc() } -// RegisterNewReleaseProcessing register a new Release processing, increasing the number of concurrent processings. -func RegisterNewReleaseProcessing() { +// 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) { + if startTime == nil || processingStartTime == nil { + return + } + + ReleasePreProcessingDurationSeconds. + With(prometheus.Labels{ + "reason": reason, + "target": target, + }). + Observe(processingStartTime.Sub(startTime.Time).Seconds()) + ReleaseConcurrentProcessingsTotal.WithLabelValues().Inc() } @@ -236,6 +293,8 @@ func init() { ReleaseConcurrentProcessingsTotal, ReleaseConcurrentPostActionsExecutionsTotal, ReleaseDeploymentDurationSeconds, + ReleasePreProcessingDurationSeconds, + ReleaseValidationDurationSeconds, ReleaseDurationSeconds, ReleasePostActionsExecutionDurationSeconds, ReleaseProcessingDurationSeconds, diff --git a/metrics/release_test.go b/metrics/release_test.go index 6953701b3..643e875e6 100644 --- a/metrics/release_test.go +++ b/metrics/release_test.go @@ -17,12 +17,13 @@ limitations under the License. package metrics import ( + "time" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/prometheus/client_golang/prometheus/testutil" "github.com/redhat-appstudio/operator-toolkit/test" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "time" ) var _ = Describe("Release metrics", Ordered, func() { @@ -218,6 +219,38 @@ var _ = Describe("Release metrics", Ordered, func() { }) }) + When("RegisterValidatedRelease is called", func() { + var validationTime, startTime *metav1.Time + + BeforeEach(func() { + initializeMetrics() + + validationTime = &metav1.Time{} + startTime = &metav1.Time{Time: validationTime.Add(-60 * time.Second)} + }) + + It("does nothing if the validation start time is nil", func() { + RegisterValidatedRelease(nil, validationTime, "", "") + }) + + It("does nothing if the start time is nil", func() { + RegisterValidatedRelease(startTime, nil, "", "") + }) + + It("adds an observation to ReleaseValidationDurationSeconds", func() { + RegisterValidatedRelease(startTime, validationTime, + releaseValidationDurationSecondsLabels[0], + releaseValidationDurationSecondsLabels[1], + ) + Expect(testutil.CollectAndCompare(ReleaseValidationDurationSeconds, + test.NewHistogramReader( + releaseValidationDurationSecondsOpts, + releaseValidationDurationSecondsLabels, + startTime, validationTime, + ))).To(Succeed()) + }) + }) + When("RegisterNewRelease is called", func() { BeforeEach(func() { initializeMetrics() @@ -243,13 +276,46 @@ var _ = Describe("Release metrics", Ordered, func() { }) When("RegisterNewReleaseProcessing is called", func() { + var processingStartTime, startTime *metav1.Time + BeforeEach(func() { initializeMetrics() + + processingStartTime = &metav1.Time{} + startTime = &metav1.Time{Time: processingStartTime.Add(-60 * time.Second)} + }) + + It("does nothing if the processing start time is nil", func() { + Expect(testutil.ToFloat64(ReleaseConcurrentProcessingsTotal.WithLabelValues())).To(Equal(float64(0))) + RegisterNewReleaseProcessing(nil, processingStartTime, "", "") + Expect(testutil.ToFloat64(ReleaseConcurrentProcessingsTotal.WithLabelValues())).To(Equal(float64(0))) + }) + + It("does nothing if the start time is nil", func() { + Expect(testutil.ToFloat64(ReleaseConcurrentProcessingsTotal.WithLabelValues())).To(Equal(float64(0))) + RegisterNewReleaseProcessing(startTime, nil, "", "") + Expect(testutil.ToFloat64(ReleaseConcurrentProcessingsTotal.WithLabelValues())).To(Equal(float64(0))) + }) + + It("adds an observation to ReleasePreProcessingDurationSeconds", func() { + RegisterNewReleaseProcessing(startTime, processingStartTime, + releasePreProcessingDurationSecondsLabels[0], + releasePreProcessingDurationSecondsLabels[1], + ) + Expect(testutil.CollectAndCompare(ReleasePreProcessingDurationSeconds, + test.NewHistogramReader( + releasePreProcessingDurationSecondsOpts, + releasePreProcessingDurationSecondsLabels, + startTime, processingStartTime, + ))).To(Succeed()) }) It("increments ReleaseConcurrentProcessingsTotal", func() { Expect(testutil.ToFloat64(ReleaseConcurrentProcessingsTotal.WithLabelValues())).To(Equal(float64(0))) - RegisterNewReleaseProcessing() + RegisterNewReleaseProcessing(startTime, processingStartTime, + releasePreProcessingDurationSecondsLabels[0], + releasePreProcessingDurationSecondsLabels[1], + ) Expect(testutil.ToFloat64(ReleaseConcurrentProcessingsTotal.WithLabelValues())).To(Equal(float64(1))) }) }) @@ -272,6 +338,8 @@ var _ = Describe("Release metrics", Ordered, func() { ReleaseConcurrentProcessingsTotal.Reset() ReleaseConcurrentPostActionsExecutionsTotal.Reset() ReleaseDeploymentDurationSeconds.Reset() + ReleaseValidationDurationSeconds.Reset() + ReleasePreProcessingDurationSeconds.Reset() ReleaseDurationSeconds.Reset() ReleaseProcessingDurationSeconds.Reset() ReleasePostActionsExecutionDurationSeconds.Reset() diff --git a/tekton/pipeline_run.go b/tekton/pipeline_run.go index 46d09f87d..d754c3ffe 100644 --- a/tekton/pipeline_run.go +++ b/tekton/pipeline_run.go @@ -30,6 +30,7 @@ import ( ecapiv1alpha1 "github.com/enterprise-contract/enterprise-contract-controller/api/v1alpha1" "github.com/redhat-appstudio/release-service/metadata" + "github.com/redhat-appstudio/release-service/tekton/utils" libhandler "github.com/operator-framework/operator-lib/handler" integrationServiceGitopsPkg "github.com/redhat-appstudio/integration-service/gitops" @@ -43,7 +44,7 @@ import ( type PipelineType string const ( - // PipelineTypeRelease is the type for PipelineRuns created to run a release Pipeline + // PipelineTypeRelease is the type for PipelineRuns created to run a managed Release Pipeline PipelineTypeRelease = "release" ) @@ -71,7 +72,7 @@ func (r *ReleasePipelineRun) AsPipelineRun() *tektonv1.PipelineRun { return &r.PipelineRun } -// WithEnterpriseContractConfigMap adds a param providing the verify ec task bundle to the release PipelineRun. +// WithEnterpriseContractConfigMap adds a param providing the verify ec task bundle to the managed Release PipelineRun. func (r *ReleasePipelineRun) WithEnterpriseContractConfigMap(ecConfig *corev1.ConfigMap) *ReleasePipelineRun { enterpriseContractConfigMapBundleField := "verify_ec_task_bundle" @@ -85,7 +86,7 @@ func (r *ReleasePipelineRun) WithEnterpriseContractConfigMap(ecConfig *corev1.Co return r } -// WithEnterpriseContractPolicy adds a param containing the EnterpriseContractPolicy Spec as a json string to the release PipelineRun. +// WithEnterpriseContractPolicy adds a param containing the EnterpriseContractPolicy Spec as a json string to the managed Release PipelineRun. func (r *ReleasePipelineRun) WithEnterpriseContractPolicy(enterpriseContractPolicy *ecapiv1alpha1.EnterpriseContractPolicy) *ReleasePipelineRun { policyJson, _ := json.Marshal(enterpriseContractPolicy.Spec) @@ -100,7 +101,7 @@ func (r *ReleasePipelineRun) WithEnterpriseContractPolicy(enterpriseContractPoli return r } -// WithExtraParam adds an extra param to the release PipelineRun. If the parameter is not part of the Pipeline +// WithExtraParam adds an extra param to the managed Release PipelineRun. If the parameter is not part of the Pipeline // definition, it will be silently ignored. func (r *ReleasePipelineRun) WithExtraParam(name string, value tektonv1.ParamValue) *ReleasePipelineRun { r.Spec.Params = append(r.Spec.Params, tektonv1.Param{ @@ -125,7 +126,7 @@ func (r *ReleasePipelineRun) WithObjectReferences(objects ...client.Object) *Rel return r } -// WithOwner sets owner annotations to the release PipelineRun and a finalizer to prevent its deletion. +// WithOwner sets owner annotations to the managed Release PipelineRun and a finalizer to prevent its deletion. func (r *ReleasePipelineRun) WithOwner(release *v1alpha1.Release) *ReleasePipelineRun { _ = libhandler.SetOwnerAnnotations(release, r) controllerutil.AddFinalizer(r, metadata.ReleaseFinalizer) @@ -133,14 +134,14 @@ func (r *ReleasePipelineRun) WithOwner(release *v1alpha1.Release) *ReleasePipeli return r } -// WithPipelineRef sets the PipelineRef for the release PipelineRun. +// WithPipelineRef sets the PipelineRef for the managed Release PipelineRun. func (r *ReleasePipelineRun) WithPipelineRef(pipelineRef *tektonv1.PipelineRef) *ReleasePipelineRun { r.Spec.PipelineRef = pipelineRef return r } -// WithReleaseAndApplicationMetadata adds Release and Application metadata to the release PipelineRun. +// WithReleaseAndApplicationMetadata adds Release and Application metadata to the managed Release PipelineRun. func (r *ReleasePipelineRun) WithReleaseAndApplicationMetadata(release *v1alpha1.Release, applicationName string) *ReleasePipelineRun { r.ObjectMeta.Labels = map[string]string{ metadata.PipelinesTypeLabel: PipelineTypeRelease, @@ -163,6 +164,29 @@ func (r *ReleasePipelineRun) WithServiceAccount(serviceAccount string) *ReleaseP return r } +// WithTaskGitPipelineParameters adds the taskGitUrl and taskGitRevision parameters to the managed Release PipelineRun with +// the value of the url and revision from the pipelineRef if the pipelineRef is for a git resolver. +func (r *ReleasePipelineRun) WithTaskGitPipelineParameters(pipelineRef *utils.PipelineRef) *ReleasePipelineRun { + if pipelineRef.Resolver == "git" { + for _, p := range pipelineRef.Params { + if p.Name == "url" { + r.WithExtraParam("taskGitUrl", tektonv1.ParamValue{ + Type: tektonv1.ParamTypeString, + StringVal: p.Value, + }) + } + if p.Name == "revision" { + r.WithExtraParam("taskGitRevision", tektonv1.ParamValue{ + Type: tektonv1.ParamTypeString, + StringVal: p.Value, + }) + } + } + } + + return r +} + // WithTimeout overwrites the PipelineRun's default timeout value. func (r *ReleasePipelineRun) WithTimeout(timeout string) *ReleasePipelineRun { duration, err := time.ParseDuration(timeout) diff --git a/tekton/pipeline_run_test.go b/tekton/pipeline_run_test.go index 932358495..0f2c193c7 100644 --- a/tekton/pipeline_run_test.go +++ b/tekton/pipeline_run_test.go @@ -212,6 +212,45 @@ var _ = Describe("PipelineRun", func() { Expect(releasePipelineRun.Spec.TaskRunTemplate.ServiceAccountName).To(Equal(serviceAccountName)) }) + It("can add the taskGit pipeline parameters to the PipelineRun object when using a git resolver", func() { + pipelineRef := &tektonutils.PipelineRef{ + Resolver: "git", + Params: []tektonutils.Param{ + { + Name: "url", + Value: "my-url", + }, + { + Name: "revision", + Value: "my-revision", + }, + }, + } + releasePipelineRun.WithTaskGitPipelineParameters(pipelineRef) + Expect(releasePipelineRun.Spec.Params[0].Name).To(Equal("taskGitUrl")) + Expect(releasePipelineRun.Spec.Params[0].Value.StringVal).To(Equal("my-url")) + Expect(releasePipelineRun.Spec.Params[1].Name).To(Equal("taskGitRevision")) + Expect(releasePipelineRun.Spec.Params[1].Value.StringVal).To(Equal("my-revision")) + }) + + It("does not add the taskGit pipeline parameters to the PipelineRun object when using a bundles resolver", func() { + pipelineRef := &tektonutils.PipelineRef{ + Resolver: "bundles", + Params: []tektonutils.Param{ + { + Name: "url", + Value: "my-url", + }, + { + Name: "revision", + Value: "my-revision", + }, + }, + } + releasePipelineRun.WithTaskGitPipelineParameters(pipelineRef) + Expect(len(releasePipelineRun.Spec.Params)).To(Equal(0)) + }) + It("can add the timeout that should be used", func() { releasePipelineRun.WithTimeout(timeout) Expect(releasePipelineRun.Spec.Timeouts.Pipeline.Duration.String()).To(Equal(timeout)) diff --git a/tekton/predicates.go b/tekton/predicates.go index f11710026..4bb67dfa3 100644 --- a/tekton/predicates.go +++ b/tekton/predicates.go @@ -22,7 +22,7 @@ import ( ) // ReleasePipelineRunSucceededPredicate returns a predicate which filters out all objects except -// release PipelineRuns which have just succeeded. +// managed Release PipelineRuns which have just succeeded. func ReleasePipelineRunSucceededPredicate() predicate.Predicate { return predicate.Funcs{ CreateFunc: func(createEvent event.CreateEvent) bool { diff --git a/tekton/predicates_test.go b/tekton/predicates_test.go index 592ad675f..76bfee349 100644 --- a/tekton/predicates_test.go +++ b/tekton/predicates_test.go @@ -108,7 +108,7 @@ var _ = Describe("Predicates", func() { Expect(instance.Generic(contextEvent)).To(BeFalse()) }) - It("should return true when an updated event is received for a succeeded release PipelineRun", func() { + It("should return true when an updated event is received for a succeeded managed Release PipelineRun", func() { releasePipelineRun.AsPipelineRun().Status.InitializeConditions(clock.RealClock{}) contextEvent := event.UpdateEvent{ ObjectOld: releasePipelineRun.AsPipelineRun(), diff --git a/tekton/utils.go b/tekton/utils.go index 4d300d406..27dce9aae 100644 --- a/tekton/utils.go +++ b/tekton/utils.go @@ -23,7 +23,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" ) -// isReleasePipelineRun returns a boolean indicating whether the object passed is a release PipelineRun or not. +// isReleasePipelineRun returns a boolean indicating whether the object passed is a managed Release PipelineRun or not. func isReleasePipelineRun(object client.Object) bool { _, ok := object.(*tektonv1.PipelineRun) if !ok {