diff --git a/Makefile b/Makefile index c078888fb..4195acf90 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,9 @@ DEFAULT_RELEASE_PVC ?= release-pvc # 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 +# DEFAULT_WORKSPACE_SIZE defines the default size for the workspace that will be used in the managed Release Pipeline. +DEFAULT_RELEASE_WORKSPACE_SIZE ?= 1Gi + # CHANNELS define the bundle channels used in the bundle. # Add a new line here if you would like to change its default config. (E.g CHANNELS = "candidate,fast,stable") # To re-generate a bundle for other specific channels without changing the standard setup, you can: @@ -158,6 +161,7 @@ deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG} DEFAULT_RELEASE_PVC=${DEFAULT_RELEASE_PVC} \ DEFAULT_RELEASE_WORKSPACE_NAME=${DEFAULT_RELEASE_WORKSPACE_NAME} \ + DEFAULT_RELEASE_WORKSPACE_SIZE=${DEFAULT_RELEASE_WORKSPACE_SIZE} \ $(KUSTOMIZE) build config/default | kubectl apply -f - .PHONY: undeploy diff --git a/config/crd/bases/appstudio.redhat.com_releaseplanadmissions.yaml b/config/crd/bases/appstudio.redhat.com_releaseplanadmissions.yaml index 7f166b412..842e93e32 100644 --- a/config/crd/bases/appstudio.redhat.com_releaseplanadmissions.yaml +++ b/config/crd/bases/appstudio.redhat.com_releaseplanadmissions.yaml @@ -103,12 +103,6 @@ spec: the execution of the Pipeline pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ type: string - timeout: - default: "0" - description: "Timeout is a value to use to override the tekton - default Pipelinerun timeout \n This field is DEPRECATED and - will be replaced by Timeouts in a future change." - type: string timeouts: description: Timeouts defines the different Timeouts to use in the PipelineRun execution diff --git a/config/manager/manager.properties b/config/manager/manager.properties index 5a4381629..649f93e44 100644 --- a/config/manager/manager.properties +++ b/config/manager/manager.properties @@ -1,2 +1,3 @@ DEFAULT_RELEASE_PVC DEFAULT_RELEASE_WORKSPACE_NAME +DEFAULT_RELEASE_WORKSPACE_SIZE diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml index 2d1eaf0b3..fbc6493b2 100644 --- a/config/manager/manager.yaml +++ b/config/manager/manager.yaml @@ -70,6 +70,12 @@ spec: key: DEFAULT_RELEASE_WORKSPACE_NAME name: manager-properties optional: true + - name: DEFAULT_RELEASE_WORKSPACE_SIZE + valueFrom: + configMapKeyRef: + key: DEFAULT_RELEASE_WORKSPACE_SIZE + name: manager-properties + optional: true - name: SERVICE_NAMESPACE valueFrom: fieldRef: diff --git a/controllers/release/adapter.go b/controllers/release/adapter.go index ce74f8731..2df4e79dc 100644 --- a/controllers/release/adapter.go +++ b/controllers/release/adapter.go @@ -19,19 +19,18 @@ package release import ( "context" "fmt" - "os" - - "github.com/redhat-appstudio/operator-toolkit/controller" - "github.com/go-logr/logr" + applicationapiv1alpha1 "github.com/redhat-appstudio/application-api/api/v1alpha1" + integrationgitops "github.com/redhat-appstudio/integration-service/gitops" + "github.com/redhat-appstudio/operator-toolkit/controller" "github.com/redhat-appstudio/release-service/api/v1alpha1" "github.com/redhat-appstudio/release-service/gitops" "github.com/redhat-appstudio/release-service/loader" "github.com/redhat-appstudio/release-service/metadata" "github.com/redhat-appstudio/release-service/syncer" - "github.com/redhat-appstudio/release-service/tekton" - - applicationapiv1alpha1 "github.com/redhat-appstudio/application-api/api/v1alpha1" + "github.com/redhat-appstudio/release-service/tekton/utils" + "os" + "strings" libhandler "github.com/operator-framework/operator-lib/handler" tektonv1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" @@ -336,21 +335,34 @@ func (a *adapter) EnsureReleaseProcessingIsTracked() (controller.OperationResult // will be extracted from the given ReleaseStrategy. The Release's Snapshot will also be passed to the release // PipelineRun. 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). + pipelineRun, err := utils.NewPipelineRunBuilder("managed-pr", resources.ReleasePlanAdmission.Namespace). + WithAnnotations(metadata.GetAnnotationsWithPrefix(a.release, integrationgitops.PipelinesAsCodePrefix)). + WithFinalizer(metadata.ReleaseFinalizer). + WithLabels(map[string]string{ + metadata.ApplicationNameLabel: resources.ReleasePlan.Spec.Application, + metadata.PipelinesTypeLabel: strings.ToLower(a.release.Kind), + metadata.ReleaseNameLabel: a.release.Name, + metadata.ReleaseNamespaceLabel: a.release.Namespace, + metadata.ReleaseSnapshotLabel: a.release.Spec.Snapshot, + }). + WithObjectReferences(a.release, resources.ReleasePlan, resources.ReleasePlanAdmission, resources.Snapshot). + WithObjectSpecsAsJson(resources.EnterpriseContractPolicy). WithOwner(a.release). - WithReleaseAndApplicationMetadata(a.release, resources.Snapshot.Spec.Application). - WithWorkspace(os.Getenv("DEFAULT_RELEASE_WORKSPACE_NAME"), os.Getenv("DEFAULT_RELEASE_PVC")). - WithServiceAccount(resources.ReleasePlanAdmission.Spec.Pipeline.ServiceAccount). - WithTimeout(resources.ReleasePlanAdmission.Spec.Pipeline.Timeout). + WithParamsFromConfigMap(resources.EnterpriseContractConfigMap, []string{"verify_ec_task_bundle"}). WithPipelineRef(resources.ReleasePlanAdmission.Spec.Pipeline.PipelineRef.ToTektonPipelineRef()). - WithTaskGitPipelineParameters(&resources.ReleasePlanAdmission.Spec.Pipeline.PipelineRef). - WithEnterpriseContractConfigMap(resources.EnterpriseContractConfigMap). - WithEnterpriseContractPolicy(resources.EnterpriseContractPolicy). - AsPipelineRun() + WithServiceAccount(resources.ReleasePlanAdmission.Spec.Pipeline.ServiceAccount). + WithTimeouts(&resources.ReleasePlanAdmission.Spec.Pipeline.Timeouts). + WithWorkspaceFromVolumeTemplate( + os.Getenv("DEFAULT_RELEASE_WORKSPACE_NAME"), + os.Getenv("DEFAULT_RELEASE_WORKSPACE_SIZE"), + ). + Build() + + if err != nil { + return nil, err + } - err := a.client.Create(a.ctx, pipelineRun) + err = a.client.Create(a.ctx, pipelineRun) if err != nil { return nil, err } diff --git a/controllers/release/adapter_test.go b/controllers/release/adapter_test.go index 54bf7494b..85fab2e77 100644 --- a/controllers/release/adapter_test.go +++ b/controllers/release/adapter_test.go @@ -23,6 +23,8 @@ import ( "os" "reflect" "strings" + "time" + "unicode" tektonutils "github.com/redhat-appstudio/release-service/tekton/utils" @@ -70,6 +72,9 @@ var _ = Describe("Release adapter", Ordered, func() { }) BeforeAll(func() { + Expect(os.Setenv("DEFAULT_RELEASE_WORKSPACE_NAME", "release-workspace")).To(Succeed()) + Expect(os.Setenv("DEFAULT_RELEASE_WORKSPACE_SIZE", "1Gi")).To(Succeed()) + createResources() }) @@ -834,7 +839,7 @@ var _ = Describe("Release adapter", Ordered, 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")) + Expect(pipelineRun.Name).To(HavePrefix("managed-pr")) }) It("has the release reference", func() { @@ -844,13 +849,19 @@ var _ = Describe("Release adapter", Ordered, func() { }) It("has the releasePlan reference", func() { - Expect(pipelineRun.Spec.Params).Should(ContainElement(HaveField("Name", strings.ToLower(releasePlan.Kind)))) + name := []rune(releasePlanAdmission.Kind) + name[0] = unicode.ToLower(name[0]) + + Expect(pipelineRun.Spec.Params).Should(ContainElement(HaveField("Name", string(name)))) Expect(pipelineRun.Spec.Params).Should(ContainElement(HaveField("Value.StringVal", fmt.Sprintf("%s%c%s", releasePlan.Namespace, types.Separator, releasePlan.Name)))) }) It("has the releasePlanAdmission reference", func() { - Expect(pipelineRun.Spec.Params).Should(ContainElement(HaveField("Name", strings.ToLower(releasePlanAdmission.Kind)))) + name := []rune(releasePlanAdmission.Kind) + name[0] = unicode.ToLower(name[0]) + + Expect(pipelineRun.Spec.Params).Should(ContainElement(HaveField("Name", string(name)))) Expect(pipelineRun.Spec.Params).Should(ContainElement(HaveField("Value.StringVal", fmt.Sprintf("%s%c%s", releasePlanAdmission.Namespace, types.Separator, releasePlanAdmission.Name)))) }) @@ -909,8 +920,7 @@ var _ = Describe("Release adapter", Ordered, func() { }) It("contains the proper timeout value", func() { - timeout := releasePlanAdmission.Spec.Pipeline.Timeout - Expect(pipelineRun.Spec.Timeouts.Pipeline.Duration.String()).To(Equal(string(timeout))) + Expect(pipelineRun.Spec.Timeouts.Pipeline).To(Equal(releasePlanAdmission.Spec.Pipeline.Timeouts.Pipeline)) }) It("contains a parameter with the verify ec task bundle", func() { @@ -1695,6 +1705,7 @@ var _ = Describe("Release adapter", Ordered, func() { }, } Expect(k8sClient.Create(ctx, releasePlan)).To(Succeed()) + releasePlan.Kind = "Snapshot" releaseServiceConfig = &v1alpha1.ReleaseServiceConfig{ ObjectMeta: metav1.ObjectMeta{ @@ -1725,7 +1736,9 @@ var _ = Describe("Release adapter", Ordered, func() { {Name: "pathInRepo", Value: "my-path"}, }, }, - Timeout: "2h0m0s", + Timeouts: tektonv1.TimeoutFields{ + Pipeline: &metav1.Duration{Duration: 1 * time.Hour}, + }, }, Policy: enterpriseContractPolicy.Name, }, diff --git a/main.go b/main.go index dccbd998c..1ec1caa88 100644 --- a/main.go +++ b/main.go @@ -127,6 +127,15 @@ func main() { } } + // Set a default value for the DEFAULT_RELEASE_WORKSPACE_SIZE environment variable + if os.Getenv("DEFAULT_RELEASE_WORKSPACE_SIZE") == "" { + err := os.Setenv("DEFAULT_RELEASE_WORKSPACE_SIZE", "1Gi") + if err != nil { + setupLog.Error(err, "unable to setup DEFAULT_RELEASE_WORKSPACE_SIZE environment variable") + os.Exit(1) + } + } + setUpControllers(mgr) setUpWebhooks(mgr) diff --git a/tekton/pipeline_run.go b/tekton/pipeline_run.go deleted file mode 100644 index d754c3ffe..000000000 --- a/tekton/pipeline_run.go +++ /dev/null @@ -1,216 +0,0 @@ -/* -Copyright 2022. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package tekton - -import ( - "encoding/json" - "fmt" - "strings" - "time" - "unicode" - - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - - 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" - "github.com/redhat-appstudio/release-service/api/v1alpha1" - tektonv1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" - corev1 "k8s.io/api/core/v1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// PipelineType represents a PipelineRun type within AppStudio -type PipelineType string - -const ( - // PipelineTypeRelease is the type for PipelineRuns created to run a managed Release Pipeline - PipelineTypeRelease = "release" -) - -// ReleasePipelineRun is a PipelineRun alias, so we can add new methods to it in this file. -type ReleasePipelineRun struct { - tektonv1.PipelineRun -} - -// NewReleasePipelineRun creates an empty PipelineRun in the given namespace. The name will be autogenerated, -// using the prefix passed as an argument to the function. -func NewReleasePipelineRun(prefix, namespace string) *ReleasePipelineRun { - pipelineRun := tektonv1.PipelineRun{ - ObjectMeta: v1.ObjectMeta{ - GenerateName: prefix + "-", - Namespace: namespace, - }, - Spec: tektonv1.PipelineRunSpec{}, - } - - return &ReleasePipelineRun{pipelineRun} -} - -// AsPipelineRun casts the ReleasePipelineRun to PipelineRun, so it can be used in the Kubernetes client. -func (r *ReleasePipelineRun) AsPipelineRun() *tektonv1.PipelineRun { - return &r.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" - - ecTaskBundle := ecConfig.Data[enterpriseContractConfigMapBundleField] - - r.WithExtraParam(enterpriseContractConfigMapBundleField, tektonv1.ParamValue{ - Type: tektonv1.ParamTypeString, - StringVal: string(ecTaskBundle), - }) - - return r -} - -// 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) - - policyKindRunes := []rune(enterpriseContractPolicy.Kind) - policyKindRunes[0] = unicode.ToLower(policyKindRunes[0]) - - r.WithExtraParam(string(policyKindRunes), tektonv1.ParamValue{ - Type: tektonv1.ParamTypeString, - StringVal: string(policyJson), - }) - - return r -} - -// 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{ - Name: name, - Value: value, - }) - - return r -} - -// WithObjectReferences adds new parameters to the PipelineRun for each object passed as an argument to the function. -// The new parameters will be named after the kind of the object and its values will be a reference to the object itself -// in the form of "namespace/name". -func (r *ReleasePipelineRun) WithObjectReferences(objects ...client.Object) *ReleasePipelineRun { - for _, object := range objects { - r.WithExtraParam(strings.ToLower(object.GetObjectKind().GroupVersionKind().Kind), tektonv1.ParamValue{ - Type: tektonv1.ParamTypeString, - StringVal: fmt.Sprintf("%s%c%s", object.GetNamespace(), types.Separator, object.GetName()), - }) - } - - return r -} - -// 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) - - return r -} - -// 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 managed Release PipelineRun. -func (r *ReleasePipelineRun) WithReleaseAndApplicationMetadata(release *v1alpha1.Release, applicationName string) *ReleasePipelineRun { - r.ObjectMeta.Labels = map[string]string{ - metadata.PipelinesTypeLabel: PipelineTypeRelease, - metadata.ReleaseNameLabel: release.Name, - metadata.ReleaseNamespaceLabel: release.Namespace, - metadata.ApplicationNameLabel: applicationName, - metadata.ReleaseSnapshotLabel: release.Spec.Snapshot, - } - metadata.AddAnnotations(r.AsPipelineRun(), metadata.GetAnnotationsWithPrefix(release, integrationServiceGitopsPkg.PipelinesAsCodePrefix)) - metadata.AddLabels(r.AsPipelineRun(), metadata.GetLabelsWithPrefix(release, integrationServiceGitopsPkg.PipelinesAsCodePrefix)) - - return r -} - -// WithServiceAccount adds a reference to the service account to be used to gain elevated privileges during the -// execution of the different Pipeline tasks. -func (r *ReleasePipelineRun) WithServiceAccount(serviceAccount string) *ReleasePipelineRun { - r.Spec.TaskRunTemplate.ServiceAccountName = serviceAccount - - 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) - if err == nil { - r.Spec.Timeouts = &tektonv1.TimeoutFields{} - r.Spec.Timeouts.Pipeline = &v1.Duration{Duration: duration} - } - - return r -} - -// WithWorkspace adds a workspace to the PipelineRun using the given name and PersistentVolumeClaim. -// If any of those values is empty, no workspace will be added. -func (r *ReleasePipelineRun) WithWorkspace(name, persistentVolumeClaim string) *ReleasePipelineRun { - if name == "" || persistentVolumeClaim == "" { - return r - } - - r.Spec.Workspaces = append(r.Spec.Workspaces, tektonv1.WorkspaceBinding{ - Name: name, - PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{ - ClaimName: persistentVolumeClaim, - }, - }) - - return r -} diff --git a/tekton/pipeline_run_test.go b/tekton/pipeline_run_test.go deleted file mode 100644 index e942c8b14..000000000 --- a/tekton/pipeline_run_test.go +++ /dev/null @@ -1,295 +0,0 @@ -/* -Copyright 2022 Red Hat Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package tekton - -import ( - "context" - "encoding/json" - "fmt" - "reflect" - "strings" - - tektonutils "github.com/redhat-appstudio/release-service/tekton/utils" - - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/types" - - ecapiv1alpha1 "github.com/enterprise-contract/enterprise-contract-controller/api/v1alpha1" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "github.com/redhat-appstudio/release-service/api/v1alpha1" - - tektonv1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -type ExtraParams struct { - Name string - Value tektonv1.ParamValue -} - -var _ = Describe("PipelineRun", func() { - const ( - pipelineRunPrefixName = "test-pipeline" - namespace = "default" - workspace = "test-workspace" - persistentVolumeClaim = "test-pvc" - serviceAccountName = "test-service-account" - timeout = "1h0m0s" - apiVersion = "appstudio.redhat.com/v1alpha1" - applicationName = "test-application" - ) - var ( - release *v1alpha1.Release - extraParams *ExtraParams - releasePipelineRun *ReleasePipelineRun - releasePlanAdmission *v1alpha1.ReleasePlanAdmission - enterpriseContractConfigMap *corev1.ConfigMap - enterpriseContractPolicy *ecapiv1alpha1.EnterpriseContractPolicy - ) - BeforeEach(func() { - extraParams = &ExtraParams{ - Name: "extraConfigPath", - Value: tektonv1.ParamValue{ - Type: tektonv1.ParamTypeString, - StringVal: "path/to/extra/config.yaml", - }, - } - release = &v1alpha1.Release{ - TypeMeta: metav1.TypeMeta{ - APIVersion: apiVersion, - Kind: "Release", - }, - ObjectMeta: metav1.ObjectMeta{ - GenerateName: "myrelease-", - Namespace: namespace, - }, - Spec: v1alpha1.ReleaseSpec{ - Snapshot: "testsnapshot", - ReleasePlan: "testreleaseplan", - }, - } - enterpriseContractConfigMap = &corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-cm", - }, - TypeMeta: metav1.TypeMeta{ - Kind: "ConfigMap", - }, - Data: map[string]string{ - "verify_ec_task_bundle": "test-bundle", - }, - } - enterpriseContractPolicy = &ecapiv1alpha1.EnterpriseContractPolicy{ - ObjectMeta: metav1.ObjectMeta{ - Name: "testpolicy", - }, - TypeMeta: metav1.TypeMeta{ - Kind: "EnterpriseContractPolicy", - }, - Spec: ecapiv1alpha1.EnterpriseContractPolicySpec{ - Description: "test-policy-description", - Sources: []ecapiv1alpha1.Source{ - { - Name: "foo", - Policy: []string{"https://github.com/company/policy"}, - Data: []string{"https://github.com/company/data"}, - }, - }, - }, - } - releasePlanAdmission = &v1alpha1.ReleasePlanAdmission{ - Spec: v1alpha1.ReleasePlanAdmissionSpec{ - Applications: []string{"application"}, - Pipeline: &tektonutils.Pipeline{ - PipelineRef: tektonutils.PipelineRef{ - Resolver: "bundles", - Params: []tektonutils.Param{ - {Name: "bundle", Value: "testbundle"}, - {Name: "name", Value: "release-pipeline"}, - {Name: "kind", Value: "pipeline"}, - }, - }, - ServiceAccount: serviceAccountName, - }, - Policy: "testpolicy", - }, - } - - ctx := context.Background() - - // The code below sets the ownership for the Release Object - kind := reflect.TypeOf(v1alpha1.Release{}).Name() - gvk := v1alpha1.GroupVersion.WithKind(kind) - controllerRef := metav1.NewControllerRef(release, gvk) - - // Creating a release - Expect(k8sClient.Create(ctx, release)).Should(Succeed()) - release.SetOwnerReferences([]metav1.OwnerReference{*controllerRef}) - - // Need to set the Kind and APIVersion as it loses it due to: - // https://github.com/kubernetes-sigs/controller-runtime/issues/1870 - release.TypeMeta.APIVersion = apiVersion - release.TypeMeta.Kind = "Release" - - // Creates the PipelineRun Object - releasePipelineRun = NewReleasePipelineRun(pipelineRunPrefixName, namespace) - Expect(k8sClient.Create(ctx, releasePipelineRun.AsPipelineRun())).Should(Succeed()) - }) - - AfterEach(func() { - _ = k8sClient.Delete(ctx, release) - _ = k8sClient.Delete(ctx, releasePipelineRun.AsPipelineRun()) - }) - - When("managing a new PipelineRun", func() { - - It("can create a PipelineRun and the returned object name is prefixed with the provided GenerateName", func() { - Expect(releasePipelineRun.ObjectMeta.Name). - Should(HavePrefix(pipelineRunPrefixName)) - Expect(releasePipelineRun.ObjectMeta.Namespace).To(Equal(namespace)) - }) - - It("can append extra params to PipelineRun and these parameters are present in the object Specs", func() { - releasePipelineRun.WithExtraParam(extraParams.Name, extraParams.Value) - Expect(releasePipelineRun.Spec.Params[0].Name).To(Equal(extraParams.Name)) - Expect(releasePipelineRun.Spec.Params[0].Value.StringVal). - To(Equal(extraParams.Value.StringVal)) - }) - - It("can append owner release information to the object as annotations", func() { - releasePipelineRun.WithOwner(release) - Expect(releasePipelineRun.Annotations).NotTo(BeNil()) - Expect(releasePipelineRun.Finalizers).NotTo(BeEmpty()) - }) - - It("can append the release Name, Namespace, and Application to a PipelineRun object and that these label key names match the correct label format", func() { - releasePipelineRun.WithReleaseAndApplicationMetadata(release, applicationName) - Expect(releasePipelineRun.Labels["release.appstudio.openshift.io/name"]). - To(Equal(release.Name)) - Expect(releasePipelineRun.Labels["release.appstudio.openshift.io/namespace"]). - To(Equal(release.Namespace)) - Expect(releasePipelineRun.Labels["appstudio.openshift.io/application"]). - To(Equal(applicationName)) - Expect(releasePipelineRun.Labels["appstudio.openshift.io/snapshot"]). - To(Equal(release.Spec.Snapshot)) - }) - - It("can return a PipelineRun object from a PipelineRun object", func() { - Expect(reflect.TypeOf(releasePipelineRun.AsPipelineRun())). - To(Equal(reflect.TypeOf(&tektonv1.PipelineRun{}))) - }) - - It("can add the PipelineRef to a PipelineRun object ", func() { - releasePipelineRun.WithPipelineRef(releasePlanAdmission.Spec.Pipeline.PipelineRef.ToTektonPipelineRef()) - Expect(releasePipelineRun.Spec.PipelineRef.ResolverRef).NotTo(Equal(tektonv1.ResolverRef{})) - Expect(releasePipelineRun.Spec.PipelineRef.ResolverRef.Resolver).To(Equal(tektonv1.ResolverName("bundles"))) - Expect(releasePipelineRun.Spec.PipelineRef.ResolverRef.Params).To(HaveLen(3)) - Expect(releasePipelineRun.Spec.PipelineRef.ResolverRef.Params[0].Name).To(Equal("bundle")) - Expect(releasePipelineRun.Spec.PipelineRef.ResolverRef.Params[0].Value.StringVal).To(Equal(releasePlanAdmission.Spec.Pipeline.PipelineRef.Params[0].Value)) - Expect(releasePipelineRun.Spec.PipelineRef.ResolverRef.Params[1].Name).To(Equal("name")) - Expect(releasePipelineRun.Spec.PipelineRef.ResolverRef.Params[1].Value.StringVal).To(Equal(releasePlanAdmission.Spec.Pipeline.PipelineRef.Params[1].Value)) - Expect(releasePipelineRun.Spec.PipelineRef.ResolverRef.Params[2].Name).To(Equal("kind")) - Expect(releasePipelineRun.Spec.PipelineRef.ResolverRef.Params[2].Value.StringVal).To(Equal("pipeline")) - }) - - It("can add the reference to the service account that should be used", func() { - releasePipelineRun.WithServiceAccount(serviceAccountName) - 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)) - }) - - It("can add a workspace to the PipelineRun using the given name and PVC", func() { - releasePipelineRun.WithWorkspace(workspace, persistentVolumeClaim) - Expect(releasePipelineRun.Spec.Workspaces).Should(ContainElement(HaveField("Name", Equal(workspace)))) - Expect(releasePipelineRun.Spec.Workspaces).Should(ContainElement(HaveField("PersistentVolumeClaim.ClaimName", Equal(persistentVolumeClaim)))) - }) - - It("can add the EC task bundle parameter to the PipelineRun", func() { - releasePipelineRun.WithEnterpriseContractConfigMap(enterpriseContractConfigMap) - Expect(releasePipelineRun.Spec.Params).Should(ContainElement(HaveField("Value.StringVal", Equal(string("test-bundle"))))) - }) - - It("can add an EnterpriseContractPolicy to the PipelineRun", func() { - releasePipelineRun.WithEnterpriseContractPolicy(enterpriseContractPolicy) - jsonSpec, _ := json.Marshal(enterpriseContractPolicy.Spec) - Expect(releasePipelineRun.Spec.Params).Should(ContainElement(HaveField("Value.StringVal", Equal(string(jsonSpec))))) - }) - }) - - When("calling WithObjectReferences is called", func() { - It("does nothing if no objects are passed", func() { - releasePipelineRun.WithObjectReferences() - Expect(releasePipelineRun.Spec.Params).To(HaveLen(0)) - }) - - It("adds a new parameter to the Pipeline with a reference to the object", func() { - releasePipelineRun.WithObjectReferences(release) - - Expect(releasePipelineRun.Spec.Params).To(HaveLen(1)) - Expect(releasePipelineRun.Spec.Params[0].Name).To(Equal(strings.ToLower(release.Kind))) - Expect(releasePipelineRun.Spec.Params[0].Value.Type).To(Equal(tektonv1.ParamTypeString)) - Expect(releasePipelineRun.Spec.Params[0].Value.StringVal).To(Equal( - fmt.Sprintf("%s%c%s", release.Namespace, types.Separator, release.Name))) - }) - }) -}) diff --git a/tekton/predicates_test.go b/tekton/predicates_test.go index 76bfee349..c3e498396 100644 --- a/tekton/predicates_test.go +++ b/tekton/predicates_test.go @@ -17,109 +17,61 @@ limitations under the License. package tekton import ( - "context" - "reflect" - - "k8s.io/utils/clock" - . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "github.com/redhat-appstudio/release-service/metadata" + "github.com/redhat-appstudio/release-service/tekton/utils" + v1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" - "github.com/redhat-appstudio/release-service/api/v1alpha1" "sigs.k8s.io/controller-runtime/pkg/event" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -var _ = Describe("Predicates", func() { - - const ( - pipelineRunPrefixName = "test-pipeline" - applicationName = "test-application" - apiVersion = "appstudio.redhat.com/v1alpha1" - namespace = "default" - ) - - var release *v1alpha1.Release - var releasePipelineRun *ReleasePipelineRun - - BeforeEach(func() { - release = &v1alpha1.Release{ - TypeMeta: metav1.TypeMeta{ - APIVersion: apiVersion, - Kind: "Release", - }, - ObjectMeta: metav1.ObjectMeta{ - GenerateName: "testrelease-", - Namespace: namespace, - }, - Spec: v1alpha1.ReleaseSpec{ - Snapshot: "testsnapshot", - ReleasePlan: "testreleaseplan", - }, - } - ctx := context.Background() - - // The code below sets the ownership for the Release Object - kind := reflect.TypeOf(v1alpha1.Release{}).Name() - gvk := v1alpha1.GroupVersion.WithKind(kind) - controllerRef := metav1.NewControllerRef(release, gvk) - - // Creating a release - Expect(k8sClient.Create(ctx, release)).Should(Succeed()) - release.SetOwnerReferences([]metav1.OwnerReference{*controllerRef}) - - // Need to set the Kind and APIVersion as it loses it due to: - // https://github.com/kubernetes-sigs/controller-runtime/issues/1870 - release.TypeMeta.APIVersion = apiVersion - release.TypeMeta.Kind = "Release" - - // Creates the PipelineRun Object - releasePipelineRun = NewReleasePipelineRun(pipelineRunPrefixName, namespace) - Expect(k8sClient.Create(ctx, releasePipelineRun.AsPipelineRun())).Should(Succeed()) - }) - - AfterEach(func() { - _ = k8sClient.Delete(ctx, release) - _ = k8sClient.Delete(ctx, releasePipelineRun.AsPipelineRun()) - }) - +var _ = Describe("Predicates", Ordered, func() { When("testing ReleasePipelineRunSucceededPredicate predicate", func() { - instance := ReleasePipelineRunSucceededPredicate() + var err error + var pipelineRun *v1.PipelineRun + + BeforeAll(func() { + pipelineRun, err = utils.NewPipelineRunBuilder("pipeline-run", "default").Build() + Expect(err).NotTo(HaveOccurred()) + }) It("should ignore creating events", func() { contextEvent := event.CreateEvent{ - Object: releasePipelineRun.AsPipelineRun(), + Object: pipelineRun, } - Expect(instance.Create(contextEvent)).To(BeFalse()) + Expect(ReleasePipelineRunSucceededPredicate().Create(contextEvent)).To(BeFalse()) }) It("should ignore deleting events", func() { contextEvent := event.DeleteEvent{ - Object: releasePipelineRun.AsPipelineRun(), + Object: pipelineRun, } - Expect(instance.Delete(contextEvent)).To(BeFalse()) + Expect(ReleasePipelineRunSucceededPredicate().Delete(contextEvent)).To(BeFalse()) }) It("should ignore generic events", func() { contextEvent := event.GenericEvent{ - Object: releasePipelineRun.AsPipelineRun(), + Object: pipelineRun, } - Expect(instance.Generic(contextEvent)).To(BeFalse()) + Expect(ReleasePipelineRunSucceededPredicate().Generic(contextEvent)).To(BeFalse()) }) - It("should return true when an updated event is received for a succeeded managed Release PipelineRun", func() { - releasePipelineRun.AsPipelineRun().Status.InitializeConditions(clock.RealClock{}) + It("should return true when an updated event is received for a succeeded managed PipelineRun", func() { + var releasePipelineRun *v1.PipelineRun + releasePipelineRun, err = utils.NewPipelineRunBuilder("pipeline-run", "default"). + WithLabels(map[string]string{metadata.PipelinesTypeLabel: "release"}). + Build() + Expect(err).NotTo(HaveOccurred()) contextEvent := event.UpdateEvent{ - ObjectOld: releasePipelineRun.AsPipelineRun(), - ObjectNew: releasePipelineRun.WithServiceAccount("test-service-account"). - WithReleaseAndApplicationMetadata(release, applicationName). - AsPipelineRun(), + ObjectOld: pipelineRun, + ObjectNew: releasePipelineRun, } releasePipelineRun.Status.MarkRunning("Predicate function tests", "Set it to Unknown") - Expect(instance.Update(contextEvent)).To(BeFalse()) + Expect(ReleasePipelineRunSucceededPredicate().Update(contextEvent)).To(BeFalse()) + releasePipelineRun.Status.MarkSucceeded("Predicate function tests", "Set it to Succeeded") - Expect(instance.Update(contextEvent)).To(BeTrue()) + Expect(ReleasePipelineRunSucceededPredicate().Update(contextEvent)).To(BeTrue()) }) }) }) diff --git a/tekton/utils.go b/tekton/utils.go index 27dce9aae..99ffff902 100644 --- a/tekton/utils.go +++ b/tekton/utils.go @@ -32,7 +32,7 @@ func isReleasePipelineRun(object client.Object) bool { labelValue, found := object.GetLabels()[metadata.PipelinesTypeLabel] - return found && labelValue == PipelineTypeRelease + return found && labelValue == "release" } // hasPipelineSucceeded returns a boolean indicating whether the PipelineRun succeeded or not. diff --git a/tekton/utils/pipeline.go b/tekton/utils/pipeline.go index 0492fdee2..962c5f188 100644 --- a/tekton/utils/pipeline.go +++ b/tekton/utils/pipeline.go @@ -48,14 +48,6 @@ type Pipeline struct { // +optional ServiceAccount string `json:"serviceAccountName,omitempty"` - // Timeout is a value to use to override the tekton default Pipelinerun timeout - // - // This field is DEPRECATED and will be replaced by Timeouts in a future change. - // - // +kubebuilder:default="0" - // +optional - Timeout string `json:"timeout,omitempty"` - // Timeouts defines the different Timeouts to use in the PipelineRun execution // +optional Timeouts tektonv1.TimeoutFields `json:"timeouts,omitempty"` diff --git a/tekton/utils/pipeline_run_builder.go b/tekton/utils/pipeline_run_builder.go index 5a884ef32..0efe0d5e4 100644 --- a/tekton/utils/pipeline_run_builder.go +++ b/tekton/utils/pipeline_run_builder.go @@ -193,6 +193,30 @@ func (b *PipelineRunBuilder) WithParamsFromConfigMap(configMap *corev1.ConfigMap func (b *PipelineRunBuilder) WithPipelineRef(pipelineRef *tektonv1.PipelineRef) *PipelineRunBuilder { b.pipelineRun.Spec.PipelineRef = pipelineRef + if pipelineRef.Resolver == "git" { + for _, param := range pipelineRef.Params { + if param.Name == "revision" { + b.WithParams(tektonv1.Param{ + Name: "taskGitRevision", + Value: tektonv1.ParamValue{ + Type: tektonv1.ParamTypeString, + StringVal: param.Value.StringVal, + }, + }) + } + + if param.Name == "url" { + b.WithParams(tektonv1.Param{ + Name: "taskGitUrl", + Value: tektonv1.ParamValue{ + Type: tektonv1.ParamTypeString, + StringVal: param.Value.StringVal, + }, + }) + } + } + } + return b } diff --git a/tekton/utils/suite_test.go b/tekton/utils/suite_test.go index 9252daa00..7ed42f491 100644 --- a/tekton/utils/suite_test.go +++ b/tekton/utils/suite_test.go @@ -18,10 +18,14 @@ package utils import ( "context" + clientsetscheme "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/envtest" "testing" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/log/zap" logf "sigs.k8s.io/controller-runtime/pkg/log" diff --git a/tekton/utils_test.go b/tekton/utils_test.go index c8c070e5b..1043c702f 100644 --- a/tekton/utils_test.go +++ b/tekton/utils_test.go @@ -17,86 +17,41 @@ limitations under the License. package tekton import ( - "context" - "reflect" - - "k8s.io/utils/clock" - . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - - "github.com/redhat-appstudio/release-service/api/v1alpha1" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "github.com/redhat-appstudio/release-service/metadata" + "github.com/redhat-appstudio/release-service/tekton/utils" ) -var _ = Describe("Utils", func() { - - const ( - pipelineRunPrefixName = "test-pipeline" - applicationName = "test-application" - apiVersion = "appstudio.redhat.com/v1alpha1" - namespace = "default" - ) - - var release *v1alpha1.Release - var releasePipelineRun *ReleasePipelineRun - - BeforeEach(func() { - release = &v1alpha1.Release{ - TypeMeta: metav1.TypeMeta{ - APIVersion: apiVersion, - Kind: "Release", - }, - ObjectMeta: metav1.ObjectMeta{ - GenerateName: "testrelease-", - Namespace: namespace, - }, - Spec: v1alpha1.ReleaseSpec{ - Snapshot: "testsnapshot", - ReleasePlan: "testreleaseplan", - }, - } - ctx := context.Background() - - // The code below sets the ownership for the Release Object - kind := reflect.TypeOf(v1alpha1.Release{}).Name() - gvk := v1alpha1.GroupVersion.WithKind(kind) - controllerRef := metav1.NewControllerRef(release, gvk) - - // Creating a release - Expect(k8sClient.Create(ctx, release)).Should(Succeed()) - release.SetOwnerReferences([]metav1.OwnerReference{*controllerRef}) - - // Need to set the Kind and APIVersion as it loses it due to: - // https://github.com/kubernetes-sigs/controller-runtime/issues/1870 - release.TypeMeta.APIVersion = apiVersion - release.TypeMeta.Kind = "Release" - - // Creates the PipelineRun Object - releasePipelineRun = NewReleasePipelineRun(pipelineRunPrefixName, namespace) - Expect(k8sClient.Create(ctx, releasePipelineRun.AsPipelineRun())).Should(Succeed()) - }) +var _ = Describe("Utils", Ordered, func() { + When("isReleasePipelineRun is called", func() { + It("should return false when the PipelineRun is not of type 'release'", func() { + pipelineRun, err := utils.NewPipelineRunBuilder("pipeline-run", "default").Build() + Expect(err).NotTo(HaveOccurred()) + Expect(isReleasePipelineRun(pipelineRun)).To(BeFalse()) + }) - AfterEach(func() { - _ = k8sClient.Delete(ctx, release) - _ = k8sClient.Delete(ctx, releasePipelineRun.AsPipelineRun()) + It("should return true when the PipelineRun is of type 'release'", func() { + pipelineRun, err := utils.NewPipelineRunBuilder("pipeline-run", "default"). + WithLabels(map[string]string{metadata.PipelinesTypeLabel: "release"}). + Build() + Expect(err).NotTo(HaveOccurred()) + Expect(isReleasePipelineRun(pipelineRun)).To(BeTrue()) + }) }) - When("using utility functions on PipelineRun objects", func() { - It("is a PipelineRun object and contains the required labels that identifies it as one", func() { - Expect(isReleasePipelineRun(releasePipelineRun. - WithReleaseAndApplicationMetadata(release, applicationName). - AsPipelineRun())).To(Equal(true)) + When("hasPipelineSucceeded is called", func() { + It("should return false when the PipelineRun has not succeeded", func() { + pipelineRun, err := utils.NewPipelineRunBuilder("pipeline-run", "default").Build() + Expect(err).NotTo(HaveOccurred()) + Expect(hasPipelineSucceeded(pipelineRun)).To(BeFalse()) }) - It("returns true when PipelineRun.Status is `Succeeded` or false otherwise", func() { - releasePipelineRun.AsPipelineRun().Status.InitializeConditions(clock.RealClock{}) - // MarkRunning sets Status to Unknown - releasePipelineRun.Status.MarkRunning("PipelineRun Tests", "sets it to Unknown") - Expect(hasPipelineSucceeded(releasePipelineRun.AsPipelineRun())).Should(BeFalse()) - releasePipelineRun.Status.MarkSucceeded("PipelineRun Tests", "sets it to Succeeded") - Expect(hasPipelineSucceeded(releasePipelineRun.AsPipelineRun())).Should(BeTrue()) + It("should return true when the PipelineRun is of type 'release'", func() { + pipelineRun, err := utils.NewPipelineRunBuilder("pipeline-run", "default").Build() + Expect(err).NotTo(HaveOccurred()) + pipelineRun.Status.MarkSucceeded("", "") + Expect(hasPipelineSucceeded(pipelineRun)).To(BeTrue()) }) }) })