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/api/v1alpha1/releaseserviceconfig_types.go b/api/v1alpha1/releaseserviceconfig_types.go index 62e959274..e966457f3 100644 --- a/api/v1alpha1/releaseserviceconfig_types.go +++ b/api/v1alpha1/releaseserviceconfig_types.go @@ -17,6 +17,7 @@ limitations under the License. package v1alpha1 import ( + tektonv1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -28,6 +29,10 @@ type ReleaseServiceConfigSpec struct { // in debug mode // +optional Debug bool `json:"debug,omitempty"` + + // DefaultTimeouts contain the default Tekton timeouts to be used in case they are + // not specified in the ReleasePlanAdmission resource. + DefaultTimeouts tektonv1.TimeoutFields `json:"defaultTimeouts,omitempty"` } // ReleaseServiceConfigStatus defines the observed state of ReleaseServiceConfig. diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 3f989b42d..0510b735e 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -428,7 +428,7 @@ func (in *ReleaseServiceConfig) DeepCopyInto(out *ReleaseServiceConfig) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec + in.Spec.DeepCopyInto(&out.Spec) out.Status = in.Status } @@ -485,6 +485,7 @@ func (in *ReleaseServiceConfigList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ReleaseServiceConfigSpec) DeepCopyInto(out *ReleaseServiceConfigSpec) { *out = *in + in.DefaultTimeouts.DeepCopyInto(&out.DefaultTimeouts) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReleaseServiceConfigSpec. 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/crd/bases/appstudio.redhat.com_releaseserviceconfigs.yaml b/config/crd/bases/appstudio.redhat.com_releaseserviceconfigs.yaml index 3e0f56ddf..fee1f6f65 100644 --- a/config/crd/bases/appstudio.redhat.com_releaseserviceconfigs.yaml +++ b/config/crd/bases/appstudio.redhat.com_releaseserviceconfigs.yaml @@ -42,6 +42,25 @@ spec: description: Debug is the boolean that specifies whether or not the Release Service should run in debug mode type: boolean + defaultTimeouts: + description: DefaultTimeouts contain the default Tekton timeouts to + be used in case they are not specified in the ReleasePlanAdmission + resource. + properties: + finally: + description: Finally sets the maximum allowed duration of this + pipeline's finally + type: string + pipeline: + description: Pipeline sets the maximum allowed duration for execution + of the entire pipeline. The sum of individual timeouts for tasks + and finally must not exceed this value. + type: string + tasks: + description: Tasks sets the maximum allowed duration of this pipeline's + tasks + type: string + type: object type: object status: description: ReleaseServiceConfigStatus defines the observed state of 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..a1bfef63a 100644 --- a/controllers/release/adapter.go +++ b/controllers/release/adapter.go @@ -19,27 +19,24 @@ package release import ( "context" "fmt" - "os" - - "github.com/redhat-appstudio/operator-toolkit/controller" - "github.com/go-logr/logr" + libhandler "github.com/operator-framework/operator-lib/handler" + 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" - - libhandler "github.com/operator-framework/operator-lib/handler" + "github.com/redhat-appstudio/release-service/tekton/utils" tektonv1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "knative.dev/pkg/apis" + "os" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -336,21 +333,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", 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: metadata.ManagedPipelineType, + 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, &a.releaseServiceConfig.Spec.DefaultTimeouts). + 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..7e3986664 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")) }) 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(releasePlan.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)))) }) @@ -867,7 +878,7 @@ var _ = Describe("Release adapter", Ordered, func() { }) It("has release labels", func() { - Expect(pipelineRun.GetLabels()[metadata.PipelinesTypeLabel]).To(Equal("release")) + Expect(pipelineRun.GetLabels()[metadata.PipelinesTypeLabel]).To(Equal(metadata.ManagedPipelineType)) Expect(pipelineRun.GetLabels()[metadata.ReleaseNameLabel]).To(Equal(adapter.release.Name)) Expect(pipelineRun.GetLabels()[metadata.ReleaseNamespaceLabel]).To(Equal(testNamespace)) Expect(pipelineRun.GetLabels()[metadata.ReleaseSnapshotLabel]).To(Equal(adapter.release.Spec.Snapshot)) @@ -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 = "ReleasePlan" 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/go.mod b/go.mod index 96f0769e3..383e078ee 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/redhat-appstudio/release-service -go 1.20 +go 1.21 require ( github.com/enterprise-contract/enterprise-contract-controller/api v0.1.35 diff --git a/go.sum b/go.sum index a80b2a766..b88bc6417 100644 --- a/go.sum +++ b/go.sum @@ -64,6 +64,7 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudevents/sdk-go/v2 v2.14.0 h1:Nrob4FwVgi5L4tV9lhjzZcjYqFVyJzsA56CwPaPfv6s= +github.com/cloudevents/sdk-go/v2 v2.14.0/go.mod h1:xDmKfzNjM8gBvjaF8ijFjM1VYOVUEeUfapHMUX1T5To= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -78,6 +79,7 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= +github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= @@ -116,6 +118,7 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= +github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -199,6 +202,7 @@ github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9 github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= +github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= @@ -215,6 +219,7 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= +github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -223,6 +228,7 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -298,6 +304,7 @@ github.com/redhat-appstudio/operator-toolkit v0.0.0-20231201124606-2087182322ae/ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -320,10 +327,12 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stvp/go-udp-testing v0.0.0-20201019212854-469649b16807/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc= github.com/tektoncd/pipeline v0.56.0 h1:Gyti3F5u1ADjI08hG3mGtWgpaaiOfeaxnznL/U/N7tM= github.com/tektoncd/pipeline v0.56.0/go.mod h1:npl5qTu+yU74zqKIkTVnFfu/1pMhJFZjvnCrH6DlfLM= github.com/tonglil/buflogr v1.0.1 h1:WXFZLKxLfqcVSmckwiMCF8jJwjIgmStJmg63YKRF1p0= +github.com/tonglil/buflogr v1.0.1/go.mod h1:yYWwvSpn/3uAaqjf6mJg/XMiAciaR0QcRJH2gJGDxNE= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -339,6 +348,7 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= @@ -386,6 +396,7 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -620,6 +631,7 @@ google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac h1:ZL/Teoy/ZGnzyrqK/Optxxp2pmVh+fmJ97slxSRyzUg= +google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:+Rvu7ElI+aLzyDQhpHMFMMltsD6m7nqpuWDd2CwJw3k= google.golang.org/genproto/googleapis/api v0.0.0-20240122161410-6c6643bf1457 h1:KHBtwE+eQc3+NxpjmRFlQ3pJQ2FNnhhgB9xOV8kyBuU= google.golang.org/genproto/googleapis/api v0.0.0-20240122161410-6c6643bf1457/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac h1:nUQEQmH/csSvFECKYRv6HWEyypysidKl2I6Qpsglq/0= 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/metadata/labels.go b/metadata/labels.go index 1b16903af..539547f80 100644 --- a/metadata/labels.go +++ b/metadata/labels.go @@ -59,6 +59,9 @@ var ( // ApplicationNameLabel is the label used to specify the application associated with the PipelineRun ApplicationNameLabel = fmt.Sprintf("%s/%s", rhtapDomain, "application") + // ManagedPipelineType is the value to be used in the PipelinesTypeLabel for managed Pipelines + ManagedPipelineType = "managed" + // PipelinesTypeLabel is the label used to describe the type of pipeline PipelinesTypeLabel = fmt.Sprintf("%s/%s", pipelinesLabelPrefix, "type") 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..c3ab826d5 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: metadata.ManagedPipelineType}). + 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..8079a8862 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 == metadata.ManagedPipelineType } // 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 5253ec812..bad94465d 100644 --- a/tekton/utils/pipeline_run_builder.go +++ b/tekton/utils/pipeline_run_builder.go @@ -194,6 +194,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 } @@ -205,8 +229,12 @@ func (b *PipelineRunBuilder) WithServiceAccount(serviceAccount string) *Pipeline } // WithTimeouts sets the Timeouts for the PipelineRun. -func (b *PipelineRunBuilder) WithTimeouts(timeouts *tektonv1.TimeoutFields) *PipelineRunBuilder { - b.pipelineRun.Spec.Timeouts = timeouts +func (b *PipelineRunBuilder) WithTimeouts(timeouts, defaultTimeouts *tektonv1.TimeoutFields) *PipelineRunBuilder { + if timeouts == nil || *timeouts == (tektonv1.TimeoutFields{}) { + b.pipelineRun.Spec.Timeouts = defaultTimeouts + } else { + b.pipelineRun.Spec.Timeouts = timeouts + } return b } diff --git a/tekton/utils/pipeline_run_builder_test.go b/tekton/utils/pipeline_run_builder_test.go index b1e39814c..0e4f32e05 100644 --- a/tekton/utils/pipeline_run_builder_test.go +++ b/tekton/utils/pipeline_run_builder_test.go @@ -329,6 +329,30 @@ var _ = Describe("PipelineRun builder", func() { builder.WithPipelineRef(pipelineRef) Expect(builder.pipelineRun.Spec.PipelineRef).To(Equal(pipelineRef)) }) + + It("adds the taskGit pipeline parameters to the PipelineRun object when using a git resolver", func() { + builder := NewPipelineRunBuilder("testPrefix", "testNamespace") + + pipelineRef := &PipelineRef{ + Resolver: "git", + Params: []Param{ + { + Name: "url", + Value: "pipelineUrl", + }, + { + Name: "revision", + Value: "pipelineRevision", + }, + }, + } + + builder.WithPipelineRef(pipelineRef.ToTektonPipelineRef()) + Expect(builder.pipelineRun.Spec.Params[0].Name).To(Equal("taskGitUrl")) + Expect(builder.pipelineRun.Spec.Params[0].Value.StringVal).To(Equal("pipelineUrl")) + Expect(builder.pipelineRun.Spec.Params[1].Name).To(Equal("taskGitRevision")) + Expect(builder.pipelineRun.Spec.Params[1].Value.StringVal).To(Equal("pipelineRevision")) + }) }) When("WithServiceAccount method is called", func() { @@ -348,9 +372,20 @@ var _ = Describe("PipelineRun builder", func() { Tasks: &metav1.Duration{Duration: 1 * time.Hour}, Finally: &metav1.Duration{Duration: 1 * time.Hour}, } - builder.WithTimeouts(timeouts) + builder.WithTimeouts(timeouts, nil) Expect(builder.pipelineRun.Spec.Timeouts).To(Equal(timeouts)) }) + + It("should use the default timeouts if the given timeouts are empty", func() { + builder := NewPipelineRunBuilder("testPrefix", "testNamespace") + defaultTimeouts := &tektonv1.TimeoutFields{ + Pipeline: &metav1.Duration{Duration: 1 * time.Hour}, + Tasks: &metav1.Duration{Duration: 1 * time.Hour}, + Finally: &metav1.Duration{Duration: 1 * time.Hour}, + } + builder.WithTimeouts(nil, defaultTimeouts) + Expect(builder.pipelineRun.Spec.Timeouts).To(Equal(defaultTimeouts)) + }) }) When("WithWorkspaceFromVolumeTemplate method is called", func() { diff --git a/tekton/utils/suite_test.go b/tekton/utils/suite_test.go index 9252daa00..5487f546c 100644 --- a/tekton/utils/suite_test.go +++ b/tekton/utils/suite_test.go @@ -17,7 +17,6 @@ limitations under the License. package utils import ( - "context" "testing" . "github.com/onsi/ginkgo/v2" @@ -28,14 +27,6 @@ import ( //+kubebuilder:scaffold:imports ) -var ( - cfg *rest.Config - k8sClient client.Client - testEnv *envtest.Environment - ctx context.Context - cancel context.CancelFunc -) - func Test(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Tekton Utils Suite") @@ -43,28 +34,4 @@ func Test(t *testing.T) { var _ = BeforeSuite(func() { logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) - ctx, cancel = context.WithCancel(context.TODO()) - - // adding required CRDs, including tekton for PipelineRun Kind - testEnv = &envtest.Environment{} - - var err error - // cfg is defined in this file globally. - cfg, err = testEnv.Start() - Expect(err).NotTo(HaveOccurred()) - Expect(cfg).NotTo(BeNil()) - - //+kubebuilder:scaffold:scheme - k8sClient, err = client.New(cfg, client.Options{ - Scheme: clientsetscheme.Scheme, - }) - Expect(err).NotTo(HaveOccurred()) - Expect(k8sClient).NotTo(BeNil()) -}) - -var _ = AfterSuite(func() { - cancel() - By("tearing down the test environment") - err := testEnv.Stop() - Expect(err).NotTo(HaveOccurred()) }) diff --git a/tekton/utils_test.go b/tekton/utils_test.go index c8c070e5b..bf3904923 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 'managed'", 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 'managed'", func() { + pipelineRun, err := utils.NewPipelineRunBuilder("pipeline-run", "default"). + WithLabels(map[string]string{metadata.PipelinesTypeLabel: metadata.ManagedPipelineType}). + 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 'managed'", func() { + pipelineRun, err := utils.NewPipelineRunBuilder("pipeline-run", "default").Build() + Expect(err).NotTo(HaveOccurred()) + pipelineRun.Status.MarkSucceeded("", "") + Expect(hasPipelineSucceeded(pipelineRun)).To(BeTrue()) }) }) })