From e7953b690f55bcc7be03c08a559c5ea8622c9ef8 Mon Sep 17 00:00:00 2001 From: gferreir Date: Thu, 17 Sep 2026 10:57:13 -0300 Subject: [PATCH 01/19] chore(gke-deploy): copy task from 0.1 to 0.2 Signed-off-by: gferreir --- task/gke-deploy/0.2/README.md | 81 +++++++ task/gke-deploy/0.2/gke-deploy.yaml | 30 +++ task/gke-deploy/0.2/samples/app/Dockerfile | 20 ++ task/gke-deploy/0.2/samples/app/app.py | 25 ++ .../0.2/samples/app/config/app.yaml | 53 +++++ .../samples/build-push-gke-deploy-example.md | 219 ++++++++++++++++++ .../0.2/samples/deployed-objects.png | Bin 0 -> 42698 bytes task/gke-deploy/0.2/samples/response.png | Bin 0 -> 3448 bytes 8 files changed, 428 insertions(+) create mode 100644 task/gke-deploy/0.2/README.md create mode 100644 task/gke-deploy/0.2/gke-deploy.yaml create mode 100644 task/gke-deploy/0.2/samples/app/Dockerfile create mode 100644 task/gke-deploy/0.2/samples/app/app.py create mode 100644 task/gke-deploy/0.2/samples/app/config/app.yaml create mode 100644 task/gke-deploy/0.2/samples/build-push-gke-deploy-example.md create mode 100644 task/gke-deploy/0.2/samples/deployed-objects.png create mode 100644 task/gke-deploy/0.2/samples/response.png diff --git a/task/gke-deploy/0.2/README.md b/task/gke-deploy/0.2/README.md new file mode 100644 index 0000000000..d436cc4850 --- /dev/null +++ b/task/gke-deploy/0.2/README.md @@ -0,0 +1,81 @@ + # `gke-deploy` `Task` + +This Task deploys an application to a Google Kubernetes Engine cluster using [`gke-deploy`](https://github.com/GoogleCloudPlatform/cloud-builders/tree/master/gke-deploy). + +## Install the Task + +``` +kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/gke-deploy/0.1/gke-deploy.yaml +``` + +## Parameters + +* **ARGS**: The arguments to pass to `gke-deploy` CLI. + + _default_: `["--help"]` + + See [here](https://github.com/GoogleCloudPlatform/cloud-builders/tree/master/gke-deploy#usage) + for the arguments to `gke-deploy`. + +## Workspaces + +* **source**: The Git source repository that contains your application's Kubernetes configs. + +## Platforms + +The Task can be run on `linux/amd64` platform. + +## Usage + +### Authorizing `gke-deploy` commands + +See [Authorizing `gcloud` +commands](../../gcloud/0.1/README.md#authorizing-gcloud-commands) for authorizing the +`gke-deploy` Task using a Google IAM Service Account (the instructions describe +authorizing `gcloud`, but the steps are the same). + +In order for the `gke-deploy` Task to deploy to a GKE cluster in your project, +the service account that the Task runs as must have the +[`roles/container.developer`](https://cloud.google.com/iam/docs/understanding-roles#kubernetes-engine-roles) role, which can be achieved with the command below: + +```bash +gcloud iam service-accounts [CLUSTER_PROJECT] add-iam-policy-binding \ + --role roles/container.developer\ + --member "serviceAccount:[SERVICE_ACCOUNT_EMAIL]" +``` + +### Running the Task + +You can invoke `gke-deploy` to deploy manifests in a Git repository by +providing a TaskRun: + +```yaml +apiVersion: tekton.dev/v1beta1 +kind: TaskRun +metadata: + name: gke-deploy-repo +spec: + serviceAccountName: workload-identity-sa # <-- a SA configured with Workload Identity + taskRef: + name: gke-deploy + workspaces: + - name: source + persistentVolumeClaim: + claimName: my-source + params: + - name: ARGS + value: + - run + - --filename="$(inputs.resources.source-repo.path)/[PATH_TO_KUBERNETES_CONFIGS]" + - --cluster=[CLUSTER_NAME] + - --location=[CLUSTER_LOCATION] + - --project=[CLUSTER_PROJECT] +``` + +See +[here](https://github.com/tektoncd/pipeline/blob/main/docs/resources.md#git-resource) +for more on how to use the Git Resource. + +See +[here](https://github.com/tektoncd/pipeline/blob/main/docs/auth.md#ssh-authentication-git) +to learn how to access private Git repositories using Tekton. diff --git a/task/gke-deploy/0.2/gke-deploy.yaml b/task/gke-deploy/0.2/gke-deploy.yaml new file mode 100644 index 0000000000..2d71fe374d --- /dev/null +++ b/task/gke-deploy/0.2/gke-deploy.yaml @@ -0,0 +1,30 @@ +apiVersion: tekton.dev/v1beta1 +kind: Task +metadata: + name: gke-deploy + labels: + app.kubernetes.io/version: "0.1" + annotations: + tekton.dev/pipelines.minVersion: "0.12.1" + tekton.dev/categories: Deployment + tekton.dev/tags: deploy + tekton.dev/displayName: "gke deploy" + tekton.dev/platforms: "linux/amd64" +spec: + description: >- + This Task deploys an application to a Google Kubernetes Engine + cluster using gke-deploy + + workspaces: + - name: source + params: + - name: ARGS + type: array + description: gke-deploy CLI arguments to run + default: ["--help"] + steps: + - name: gke-deploy + image: gcr.io/cloud-builders/gke-deploy@sha256:6d18a1efabf8a7ea7f2169c93f3e01fc5b8247b12099618c496ab097aaae341f + command: ["/gke-deploy"] + workingDir: $(workspaces.source.path) + args: ["$(params.ARGS)"] diff --git a/task/gke-deploy/0.2/samples/app/Dockerfile b/task/gke-deploy/0.2/samples/app/Dockerfile new file mode 100644 index 0000000000..58aefc7666 --- /dev/null +++ b/task/gke-deploy/0.2/samples/app/Dockerfile @@ -0,0 +1,20 @@ +# Copyright 2019 Google LLC +# +# 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 +# +# https://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. + +FROM python:3.7-slim +RUN pip install flask +WORKDIR /app +COPY app.py /app/app.py +ENTRYPOINT ["python"] +CMD ["/app/app.py"] diff --git a/task/gke-deploy/0.2/samples/app/app.py b/task/gke-deploy/0.2/samples/app/app.py new file mode 100644 index 0000000000..69c78d5baf --- /dev/null +++ b/task/gke-deploy/0.2/samples/app/app.py @@ -0,0 +1,25 @@ +# Copyright 2019 Google LLC +# +# 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 +# +# https://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. + +"""Server that returns a declaration to the world.""" +from flask import Flask +app = Flask('test-app') + + +@app.route('/') +def hello(): + return 'Hello, World!\n' + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=80) diff --git a/task/gke-deploy/0.2/samples/app/config/app.yaml b/task/gke-deploy/0.2/samples/app/config/app.yaml new file mode 100644 index 0000000000..9f67b8935c --- /dev/null +++ b/task/gke-deploy/0.2/samples/app/config/app.yaml @@ -0,0 +1,53 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: gke-deploy-tekton-demo + labels: + app: gke-deploy-tekton-demo +spec: + replicas: 3 + selector: + matchLabels: + app: gke-deploy-tekton-demo + template: + metadata: + labels: + app: gke-deploy-tekton-demo + spec: + containers: + - name: gke-deploy-tekton-demo + image: gcr.io/@IMAGE_REGISTRY_PROJECT@/gke-deploy-tekton-demo +--- +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: gke-deploy-tekton-demo-hpa + labels: + app: gke-deploy-tekton-demo +spec: + scaleTargetRef: + kind: Deployment + name: gke-deploy-tekton-demo + apiVersion: apps/v1 + minReplicas: 1 + maxReplicas: 5 + metrics: + - type: Resource + resource: + name: cpu + targetAverageUtilization: 80 +--- +apiVersion: v1 +kind: Service +metadata: + name: gke-deploy-tekton-demo-service + labels: + app: gke-deploy-tekton-demo +spec: + selector: + app: gke-deploy-tekton-demo + ports: + - protocol: TCP + port: 80 + targetPort: 80 + type: LoadBalancer diff --git a/task/gke-deploy/0.2/samples/build-push-gke-deploy-example.md b/task/gke-deploy/0.2/samples/build-push-gke-deploy-example.md new file mode 100644 index 0000000000..519e388d14 --- /dev/null +++ b/task/gke-deploy/0.2/samples/build-push-gke-deploy-example.md @@ -0,0 +1,219 @@ +# Build, push, and deploy with the `build-push-gke-deploy` Pipeline Example + +This guide walks through a detailed example that demonstrates using the `build-push-gke-deploy` Pipeline to build, push, and deploy an application in a Git repository to a GKE cluster. + +## Set up your Tekton cluster, Google service account, and Kubernetes service account + +1. Follow the instructions [here](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity#enable_workload_identity_on_a_new_cluster) to create a new GKE cluster with Workload Identity enabled, create a Google service account, and create a Kubernetes service account for your Pipeline that binds to the Google service account. + +1. Follow the instructions [here](https://github.com/tektoncd/pipeline/blob/main/docs/install.md#installing-tekton-pipelines-1) to install Tekton Pipelines onto your cluster. + + Alternatively, set the variables below and run the script to automate the above steps. + ```bash + TEKTON_CLUSTER_NAME=[NAME] + TEKTON_CLUSTER_LOCATION=[REGION/ZONE] + TEKTON_CLUSTER_PROJECT=[PROJECT_ID] + K8S_SA_NAME=[KUBERNETES_SERVICE_ACCOUNT_NAME] + GOOGLE_SA_NAME=[GOOGLE_SERVICE_ACCOUNT_NAME] + + # Create a GKE cluster with Workload Identity enabled + gcloud beta container clusters create $TEKTON_CLUSTER_NAME \ + --zone=$TEKTON_CLUSTER_LOCATION \ + --project=$TEKTON_CLUSTER_PROJECT \ + --identity-namespace=$TEKTON_CLUSTER_PROJECT.svc.id.goog + + # Configure kubectl to communicate with the cluster + gcloud container clusters get-credentials $TEKTON_CLUSTER_NAME \ + --zone=$TEKTON_CLUSTER_LOCATION \ + --project=$TEKTON_CLUSTER_PROJECT + + # Create the Kubernetes service account that your TaskRun will run as + kubectl create serviceaccount $K8S_SA_NAME + + # Create the Google service account that the Kubernetes service account will bind to + gcloud iam service-accounts create $GOOGLE_SA_NAME --project=$TEKTON_CLUSTER_PROJECT + + # Bind the Google service account and Kubernetes service account. + gcloud iam service-accounts add-iam-policy-binding \ + --role roles/iam.workloadIdentityUser \ + --project=$TEKTON_CLUSTER_PROJECT \ + --member "serviceAccount:$TEKTON_CLUSTER_PROJECT.svc.id.goog[default/$K8S_SA_NAME]" $GOOGLE_SA_NAME@$TEKTON_CLUSTER_PROJECT.iam.gserviceaccount.com + kubectl annotate serviceaccount $K8S_SA_NAME iam.gke.io/gcp-service-account=$GOOGLE_SA_NAME@$TEKTON_CLUSTER_PROJECT.iam.gserviceaccount.com + + # Install Tekton Pipelines + kubectl apply --filename https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml + ``` + +## Install Tekton Pipelines CLI + +Install the Tekton Pipelines CLI to view your logs by following the instructions for your machine at https://github.com/tektoncd/cli. + +## Set up your repo + +1. Fork and clone this [GitHub repo](https://github.com/tektoncd/catalog). See [here](https://help.github.com/en/github/getting-started-with-github/fork-a-repo) for more information on forking a repo. + +2. Clone the forked repo onto your local machine and cd into the directory. + + ```bash + GITHUB_USER=[YOUR_USERNAME] + git clone https://github.com/$GITHUB_USER/catalog + # Use `git clone git@github.com:$GITHUB_USER/catalog.git` if you use two-factor authentication + cd catalog + ``` + +3. Modify the manifests in the demo app to use a project you own for its image (this may be the same project as the one with the cluster that is running Tekton Pipelines). + + ```bash + IMAGE_REGISTRY_PROJECT=[PROJECT_ID] + sed -i "s/@IMAGE_REGISTRY_PROJECT@/$IMAGE_REGISTRY_PROJECT/g" gke-deploy/example/app/config/app.yaml + ``` + +4. Commit and push your changes to a new branch. + + ```bash + git checkout -b gke-deploy-demo + git commit -a -m "Set gke-deploy demo image project name." + git push + ``` + +## Run Pipeline + +1. Create the target cluster that gke-deploy will deploy your application to. + + ```bash + DEPLOY_CLUSTER_NAME=[NAME] + DEPLOY_CLUSTER_LOCATION=[REGION/ZONE] + DEPLOY_CLUSTER_PROJECT=[PROJECT_ID] + gcloud container clusters create $DEPLOY_CLUSTER_NAME --zone=$DEPLOY_CLUSTER_LOCATION --project=$DEPLOY_CLUSTER_PROJECT + ``` + +2. Add the `roles/storage.admin` role to the Google service account set up above in the project that the image will be pushed to (this may be the same project as the one with the cluster that is running Tekton Pipelines). This will allow the Pipeline to push an image to your project, as defined [here](https://cloud.google.com/container-registry/docs/access-control). + + ```bash + IMAGE_REGISTRY_PROJECT=[PROJECT_ID] + GOOGLE_SA_NAME=[GOOGLE_SERVICE_ACCOUNT_NAME] + TEKTON_CLUSTER_PROJECT=[PROJECT_ID] + gcloud projects add-iam-policy-binding $IMAGE_REGISTRY_PROJECT --role roles/storage.admin --member "serviceAccount:$GOOGLE_SA_NAME@$TEKTON_CLUSTER_PROJECT.iam.gserviceaccount.com" --project=$IMAGE_REGISTRY_PROJECT + ``` + +3. Add the `roles/container.developer` role to the Google service account set up above in the project of the target cluster (this may be the same project as the one with the cluster that is running Tekton Pipelines). This will allow the Pipeline to deploy your application to your cluster. + + ```bash + DEPLOY_CLUSTER_PROJECT=[PROJECT_ID] + GOOGLE_SA_NAME=[GOOGLE_SERVICE_ACCOUNT_NAME] + TEKTON_CLUSTER_PROJECT=[PROJECT_ID] + gcloud projects add-iam-policy-binding $DEPLOY_CLUSTER_PROJECT --role roles/container.developer --member "serviceAccount:$GOOGLE_SA_NAME@$TEKTON_CLUSTER_PROJECT.iam.gserviceaccount.com" --project=$DEPLOY_CLUSTER_PROJECT + ``` + +4. Install the `build-push-gke-deploy` Pipeline. + + ```bash + kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/gke-deploy/ + ``` + +5. Create the `PipelineRun` config to run your Pipeline. + + ```bash + K8S_SA_NAME=[KUBERNETES_SERVICE_ACCOUNT_NAME] + GITHUB_USER=[YOUR_USERNAME] + IMAGE_REGISTRY_PROJECT=[PROJECT_ID] + DEPLOY_CLUSTER_NAME=[NAME] + DEPLOY_CLUSTER_LOCATION=[REGION/ZONE] + DEPLOY_CLUSTER_PROJECT=[PROJECT_ID] + + cat >build-push-gke-deploy-run.yaml <lnWhIYor*7jyL4yRD#E*S12gnNst8mfa_vR@yk>}7cMZHR^iK@`Fw1m$*0{e%jcA| z?~qY9Ib3IW>seo?QYKAz^7SZ%z6usz(HL(4JgJ%`WTJLlWMAlr zQ{GH?D@i4Q=Fc&QbKElMeD=}X`5B>k*(}Nj=tI`t4ma8-QE98!c#0p+5qnDoR;|Vr zv);ODiI+7*w_2Fa=Q*PQzyQEu9#pp&tl(Pv1`0@S!lXmVbh*Jtd3Dt zBXMy?zhk`2KgBOA)lWIS6#Nkma_T)R#8RV9S~u<(Ef%2G(_#E)cvjox6!#2Cdva!k z*ne!joCq>R-VMYn+422{#nVk+l5^FjjDu+-pJ&DyH$}Hhnl7T(neA%$PSeUYg@8K_ihCndeSIY0ld@M;t2;%81d5jNQ7ex9n*2f!TAvKnpwKss zRFffi#q{T<*niwg@DAQ01$!tO&P_bIsH(2JXiei*NltLyZjMZdLhNk887{V{YO^nc zgQE#s;#7xK;mG|F>;2y~>n$;_OIA}XA z^=^rjObqyYyE2VE@$`r~E@Az(&fN0+1ouJ#{fQKvOiE{gL>W0K$stM?8*k6R{Necu zwS6YzaJ^4s4!*6@ZnvnlVBzyAD&-n2gz(5)+~ZK$j?{Xq>)qr&*NJDJA-eVpE;HvD^QKIpC`=B*}^k?N1>QLxPYA_f^i; z-`}7|Hh(5QJ6UJVt#|msfu)Gfo_C7fR)oTyJXMC(e8=~}UiqTfuQwTmZ5p%~*jV3M zC%OP^xC%m!&6?K#l7X`Mg#sUf>KGJ%khVITYC-C6ir_lZo6mNnXrr|gC^90IG$psPM1Vxie_lqE<{W zHRT^xOwJKbyjdal-(HaU>WMGM5jm1V4dXOKXP$sGCyQq$ff}6^licT27a{`4QfJbb z!)-ChGV{W54Ir~#ap9wwjH$b8b!fhzy?<#jAM>X@{B?4xPz)ZZX^n|ug4AOdhL0=J z8=OB{W|nRa=>n&3(gT+@SKm&$%OZw0ZI8?Wy}L~cX9xU^ z(16^M4u3#nQ7xwyP{ZR(Mm7+9^gyAbtcgVge6BF=AjaJM70mITsK7Tbvy^C%RKy&= zOfa_gct}ELUKc625S&F4@mihLOwzLbQ{V8EtzRvEx8o&OkZ(FQ@^2{sA+!A3=ud$l z!|F6M!RD#@L{6HjMC8uZEHCCCyNVpu6O1vCb83WRE;cI=&z)u*jn%Kgq-CA`XjIjS zC)#mQ6aK#LVJKJf)6K7F36+~Ab$0$p_b#bi_ z?zpZ;8t7d>qq9Bd!?;32H#Jth)75#}9wAlUU-f(yq#j|(qj|P6dW>Dpy_u!PQuF*E zrO$Efc-$pf$><+w>cZekL6dC%5@|q3X*BnX;|E^S6pfSx?kBdp-hqt@=eh$kAgKO2 z{xq+QaF9iWC!Zh(oY(Xfu2%-tq(_sV=WwF(cw^~JQS_(q8IY)OsP+yy_GDWd?mu4i z{cD5>ko4x=pRqFi$O%XB3u3+zMee$IirvLdYz0X^DM|1|1S8X1OUj&&uW0`zx3QL{ zvAo_FE=sJ(eJJu2Ogchv%lvJm-UZBoRjkVF{fITH!@r2^F^h*9PZina47=N zVO?Z^gfq@;mOCAHWuk`hJ%TY0uurOPuN#-~p4y-$a*gp&A75&<4ARySIgWex*L66+ zBs4PSuTGPdrUd};`T3iVS06yGlHVp3$(m7=@T}@uA`E%nQy;H=OyQ)O2xKmlii%j< zC@@rd<9@2N-|DSLdw;h6*cP^OHDfZ^9Obzf=K$i9K1g?ad6$x>n#ZN2hw)bb@9p`X zBDF*A!_Cgw!NIHJQW)!RgR%4m$Tn^y8Mp+zlTBYs>+X=e`>VDzv$3?@CVIMLwve}V ziTDH?(y%C_OIOI0zG>N@`pq~hO(WlsO3f~O&J{ZvqYRa%!1M1JbII2!-Y*&WEQ|E& zLMEkIIQ!rd4Z6WsSVNZ#AJ=BGxQ^BQ{X6d1+=y#RLh?DxuPTEau*rQ0sM75!Yp>V4 z-o*4qzhA8zsx8yWlTS%nS<#`8r)>>_1UlI`$!0R3V-6)D0WObEaUIY~?w3UdhdGWK zx{Ae#hfGLn{LX3b2VbEzW!O+_!Vsu4R@0u!+i%JEev>8}<%pAVKdygbCg6*EhOetw z9pWL%m7TH8o_?|KAZ!NDzF^xUc@1NEX9t9GWP{Xa#sXy?0f|!D`|?tm6>q9Qh<}A{ z%;xklV_TQO&+7<5n6bkqNH2WLU#h69)$$CR#d}@%><@B9oBZ0UuKEb4cQrmTLI|RN z5<#D(XNu)094VMA?)=(t4ZuA)lJpl~Q@EfL;a*J8Ez zU9+jVLB$tshB2+CP{EO_J7w5EH-?leE4hR5LAK z!`p7OS~OyfsY&59jWs=OW)39RRi|}H*k4bpWR!D4GLbOI{Hj~M=pr7>66K+d)COZE z(Wq^-EDBsC&fxx<`57E?{*8^6lCQK6xWWjPrByM!Z2vml^e5)tW=ZZ&Jgyri0zmIf zYX$anxL5n8uT>IOpPZ*>sp*juB}D+@j*Y~odDW=Lx%+L#T!gC!vl_v~l4&-Ck1e9c z^SkgwC4!ZB#q3H~VS9(h@>Ck!0U9;%g(UQ7P$R5&ZbcOFV*vCA=*JAfe?a@#HeOYH z`e&Z>`Wzn;z-%BhQ7slJUe`dP0aXrT&@}No<$ZCeGB215x%ifxB=?#rmN=}vy}2;- z{j{)>S<4netj#FC17s0cpvZ$yLvF|ySJTwsU`ief01KrGavM(X{xBNV(Xq#M_vW}^ zZPhZ0I<$|UYA8rUn9Y@qlk$4J4d@EaMe!Z2?Ccw&5~4*FS|8%8tJs3^j!`zn69#>G zM5y}`$$zimkU7LW$uesd-S07fXi^r9;V%uhe{dujy@c~C%6}Yci*W~w|IMce{L`M- z3s@(_2zL8}+jgo(td~+Cc(9LJ|9XLpl<3YG`J86tdbP)4DZGN~RoYSZxIoiDzxTEw zo9IK7)c%DKpI5ePwjgBKf1NBvHrEr7AC;r7%#oM?@`TM9E%)Aes^z21ohJ`#?Fhjq z?We&z<0mhD$&Y)pqZfi&&sX|o)3XhXt|uw(%^9OE)qwZJZ#o#A(|pCtZ}pkmsV-N0 zRnRGgMz=e=Z18(=QmW4zL9&@U0!ZyQip+6}KL%o_8v$9Wr!ibxNOr&NGKY};S*Ms40S8$_~ndVc8D*0fF} zB-1m~9As^OIosSE?)_%MS^t`lC!08jSUHjH<+Q{Us;%vL+;chdf)4rjCBBUnD$T1e zG``^7=N?{zpg*V*{Y(O5j*jVtZDcwBY%n;@*bTk&E{lK;MF~7r>LTQ*BVLK6DV%Z! z2c4&NK>>*+ZQc*to2^8?Ec=I?tv4pW*ifzb%96X;q&jVS44GCA9Cw~^beIk=H68j^ z>jk?MgnpDYI2+9)8#k{o;;&--A;Q|EH>bg-b_GnKX~df+mP+4^2bjEIiTb19wWBde zuq%^H{IjztZ{@8bCLrIzGRh4~7||h)OrQ6B5hl=>R&Ho#FZg*Ph8cr{og9OQMqv;O z>#3P{wYC1%l^EbU>wVm$_&D8vTXpf89T2q>T_|=bNKZW)MO|okc<;g_tDbRGJUV!9 z)b4kKvS{nvAU}IISy%NI5%}SOL5?$Yeg4H1{cVm)Rx!6$30TAIcy&@4#Xyb5osMarPH`2DeBckDfVS*$bNa# zlALVn=USffy5z%boW_6;rlrUj69R#Jc2To$%t{z+VxfZV0C56#x}_xM;sLq3sJ&N- zP^#di)C1;sGhc9?j*}V>MB9zix#><@hY%Wsr)Sid5@uAf(vH`?FFJO)FWlp90HhmDq9sGA9|AF@H7t(k#@#9asv&gZ3{R>NjLOW zv_76-NoJ)ZSy|k#+Xy}ENyI|&O-B6HNYkOIw}ze8q_<@} zs1~)=Nl}A(bu6a&(VwfGj_}S$Z`jqYZ*spJ8YtsEyAre5w~9madEITiQsTw{?rATrsjvh9zSY`1qAO0Lz{Pser@ldc^a z0#Ch48s52k5glQV!tSw8>Z^mV-9`sPP@F66nVoE>4jlE@1(9SFRfE5g%ZB%>@eTU} zV|59$xaP1zWXaM1Fvvzf6q@O(R^Bd4&@rQII*T3eKrNBpj#KSTFNx1l zdmqsQqy3p~5M7Pb_opYJGOK^=J9Z}RBd{3uGwn^iK~}ww)&2>)JEi#hhDakl-fS&` zFL%Y^B&2yGAktlzG~d6{*SV~ry&tWJu;i?biMvN7^E(^&BeEGg;F zX1k_Lf^~u%8hh+9LG94XX&K65a6_r~xxnb?mKs=pDj zXEEFj-fFjdd`Pi**hR0el@q9w&^uKkgHjQE>3s09&k%GyJVtH5OQF0TH$6?+mIB6> z3vPEiQ!RFzZgG;=Mjr?1e+fB!6kencQoJeyxp`!5cSxhIJe={tOvV>HE()a}%tpg| zN2|=BXgL*V(3aF5jh&J7>b07bt1UfVDr(m8H?%G}FDphdUE{eZDvn5VG0Ms4US?QM zQrei8WThIOxNbLUc287fc$;mep@JS$>#sk8rS-W?# zmHjYTggX3l!5rKBQh5cH_`8ys58-Qm@@Rm08mHcZMg;emj>4B?m}>5O<`%>50$c^j zHwu4A)<;ku$p=;>Cya)s=$cO}DlSz!Q$Ht`iHR1qr?}3XJO{GnQ`F&G)NkijNK_J+nyQj z*((xJx!b`4@i_r@NIX*CD{p1zS1hcDUoNhxI9D8YXPBhvSq?#$_o^AKclD0_Swso7 z`tW7S)Zw}BsPzD5a@Dew@r&ofMYciw#cgCU_d1Xkaf^%ouQjb%GQKMrlM)Cs&*wH` zS;gvvq05@(O^Nf3yh+DkAy1H*Oi2rk_wLOpElgO2v@Hank>Yt4=hdsLAO;OYci!)_ zJ<1Xd9cNi#`(wE;8|dyc5qrh1POWIwSv-!Kil4>t`1S3^#^sB%&6Su(Xh@$e-}?s^ zG)H}>s>K``HtW>keLYi){^IZ4L&fBEr|hwQ#-u!$alf-Es7d;oJaThkf+^#<1FNp=td~8;)hWJ!L1_nDT$`)R zbEXq8+qs2IV-3|Vp1A1cnfGI1#igXaO(y>~6&u5GFeht(Gq1F`ky&-cifR%Fld8z_ zJz;xe4#4)401~Rca1b?hl^-l1ey}^S<99zH#=`$Qa?itURXKeDJ8)1*Ko(awe!!-_ zI1;|~{kg|B1T2aK7LB`?;&Q}VUjjz_NxQ{BHpP<^@XCAQbc(Vg&0Fdi0 zk@$;dCtWUbiH$;e@kAI>4FC#nX6k&oIP2>i&_W@+koIcE*KxfJbj=nfxotrZWu+ym zJU!4M6445J)B@8 z7w)YFCzi&zxU*e!?7^C@ z{XX9(r%HWBbN3q@;<-C9-GZkkshF=<08V$G!)A0sI0WdbSc2t)G6uAb$tI0pJmcUBU=1j=56@9Q|8qT zCTEnQuZ~?<=_DapH06clKVvAr zacBA%FaLrbOB|CJ)8;as&0|n}Go)%mG{@AMir5fPBER;YrWw|{zrY>k=`vo`PNu6p zkwP-tdjgfhpP*;rIV{n_YtZuPaHD1{Lr$lfJD2A&?dxT5tpXB;86G|M;QfbcwGU_T z%1z>V`4U{|_z119!9l%ucjEK+>ogc~H1$Pf$NR!aL#8EVJZvswn@mz??y=PUj8-wO?+QN_b=$$|CmZ4@0sJP*+|yMn+k_S<-2)d>_n(8U#s)|n81nX$RO zg`LAY5BMk&q}^l-#?qy{|0psfgjvrz8nDz3Two5^0TZHCJ8jfLq4M2kR=CR>;{QQn z5VJ2|mo}rq0etd`_U{B+$GvqFwyxrSl|z01kiuZIsfL0s#m7CFKOE{nic~ydNZxR_ zkE`6f!l&$Z%AB}Tty0k_=&A4FQ}p7nb6W9o{9d^F#LgLplpmualtRNPVZc07>AF^% z(cUzGcUuMJaZ50tTdgy|028pKz|d`Cs6G}cV8I{mFyYgV^ZguKD{Ltdjp=|7_@F^c zFUgcK5JKhUCZiD3w(s{E(`lRBtDXujal1G!e`cXp4*S@JaCJ$N6$?qi-S$FsV}oDd z=%~zKyLlzQtIO*EynB#C-NpM{f)9r{3ZIDG9bkO(fYB{)tWk zdMXT@Q8udWF};(Hr(DG-+nb1GB(f&6p$1*deOcDC_BFc3&icCL=8jfVo>Odn<_DK& zVZ|{)=Cl{nO^Ffl)4+^hk!ku$*_eY07Un*Gc$wtWwJSX2QU^&H(>LVs7&B$fBz7{A zRLP0nhnPsg$L~4Qb`iciUpl)cDzLc4?rei{St!Qq8SJe}RB5J6^6Tqy5aPfQ5AZn) zj|jP@^4)Ta0XmR%UsEzeOs{wp&pnu>&CJHp?mQquVUKE4jaNYioOB_ben=TC9pIZH za8=aXiuq-aoHwEK$RLE&hhi+`cYMfY9|>0!%aLkU3nH-XD`&k~AqC4PD(EAh5V76r zo*ouVgD>&j886{*>zXUnI&a~_CELwC6-K|AdKJ|JKKD!I#8MNd&ySb`sBQh9j~vlq z#7AZ9nOybg7hWN|xxL~W!{YP0)cC*~cQuR*Yu$psh zy+CN@cX|{B#>D<%fUQi_HDf}bb@TC8q)h{b+E}x>3935G{ z=H^$={2nc7JbKZp^-4-kB@xgU!Mn( zwdwi_f&mgW4_(w%02RG#h-tP85^_T{Z9lT^Ns8gPJ1Y5b7|!Z?pA!Zqh*ONJ zYq+mZW=)p%RSGXZKYv>IFpLaqSsBK{uk9`3XtW(j?PJ$%Jj42?Q7V$D)vknP?N2$U z)e9GOk=tWg&;a0viObE_oy2^dIv5{i#AF!^o|`(sh?GC|e#~30s(nElr5;SEoolWC zITzh}>ayO5UAta|t;JT5S0U=nI2QMG(QBc*>v)S3Ff(PcTZb5*aA7(TXg}h&frj(6sV{vVOU7 zKi-j!oEMd-cpoa$z4#R^=|b!2!84nL? zqub?3wUKCyiS48j1^t4TJ*PRV2^KB?iLl4RN~m2ChK5ZoDQIOb>tPXJcWu1MEjk(Tsi3)9p7t54 z3TE3izse{hrqyAq0dv?gJ#BKG`^GlA?QU-`WUyDg&_`%1jD95X7Jek(p;o;PLntjU^{OE$f zLor=q!$ZesUpRik?B&o%kVqb27tSLBrXi6bt@6oJ2PW6bH1pHzsZG~|RHpbwJi0Ac zR?~?BE1vW`l%UmJkWNQ7(m-+7;wm3+48HB}F$;LxL~5~*{(JAw5c)x z#K`(Tp6k;y^}Z_#cR=rRy~wI)EUm^THV!91ywUmd&VaXhr1p2{M+|*u>TQlH&_(LUf66Ak&gKRE@FU+s5uJH4ep=(=W8; zI37g_<%!JONP)3mh1Dj;KxkV%!Jn&3Mq+G5kxRjgOk*>&dtZ8NjJDJG9ID{FX{D zC@O?QF!-Hn?`x#(*QFOm9E@4H?gO+p1KNI*28IHC2LgY6i>5i^nF-A)R@XF#RFg9R z+i{+hBigSf1VIRqweHBPa{Dum0i=DVd?Xg!UltImxDSEZvPI4*qEP>GC&sudy@mK= z`8*|$o^YK_bBgH|z0TRrB)s15`NaX1A;awWuaOxVgFjouVFRqTt{NZ6G}Ud(Bbg!* zH^z#~JD>A-kUzM?k-O?=(G)=llX04l)hkQM5n0FFLfAstvpnk{Y zr9E^{5;=8!GrrE~gwl%=snNc+jiZ%z>`16+Uy3&_9c7Y`fB)Fnudn zyqTqA$$|QCcS&b=E{q=T@< z+D``hH5F%ZAO2ED7Boj{QFSONBw-PtFyWKy)XbV^&C;OD87Zvd>ao%-_t?h(idc@s z5;=7Tc?7Um$`t;-Ydi0^I8vnQp6pTg{=wxOn!-Ub^(;vQMc%5f$~kp{+24@U8or78 z^amxy(KaMWpfKHxtIK3@3-N{QjV`!)bOBq^XBQ_QNh)3hPQiZ{9U`Jzd0N;q#I@O!zJj$ zZU4gvs+lD0mwsX#9p}azov@~s8Y%t-f6@&$;^$W0z( z5HH~2uhP-?2zNC9l;10@8#*zeS=a-E(6L6m7&Qv0%kuB9MiOF9_}w0h$`%ZkDGf=1qS@xMO_5*YPo8*F;?!>rhyIqYℑNotc%)1 zEo1>a@klg#5XD2CaklSc)5y*+9K(K%E)P?|%9I^PEr>1@}@K=s47F85wJ{1rmi`JpBO?`K` z8h>Z8KzDGw%z^~24<8)lhC5ljZHg-eJ-&||-LE!s)3b26DlGR}Ty zgAwI{DG6`Atx`jzB-Ki6Vfii&=_BU(@I1+*jhRdMS303!HDVB$w&S-EhY$wF;)Gc$ z-@c)5?~b-5PN#?;Wu}w9P{u5A0H?S!NY!PIi1B=t{SKLOt8H{yw{1^-0{o)$cMKOK#h7{diSxD&j3m9m1%jS)w82yR$IA}oV)hP2&#?{ zH3zC|m;To;J+|0_^_Qn78B5n^j65&^wD-);Zie*f^U3~hTM>J=<-OUWZfkJdn8Qvx zemZ|{o)vUp?O9`*rlK0V@yX%-=klS!rC}4d%qD}&nDOmI!_yZuApp?MD@C`w46~y zZPU)}Q*=7G>(X!w(|B7E8##$Y)RE1|mkX;9jm@%dD%=~t%v7g!Eb>tg<@G@2#yfEE zvRJ$em?)H=qPYh9+Hv;@hyb7bc{Up@+L!0WUi}@v)HxW011NWkiJj5w<$L?VwFI{1 z*}U}lWU_~6Q=Z|ZZ=6vl1a89_pFz)gySMB}Ug49i+F%Fs+OYRpPv7Q2n+Ir>iR+rz z9rnYp%$cL9kB43s^t9XBy!UC0U+iPeeacDeF{RK$y13WpTuUr}+l1V<^s9`*PW=-t?XzVd>L(rXoKdxRyNi*3%8wz za9h}EPfvS&ALNIWSB0K0&UK-ny`)^LZc_{JNftH$qlS>{`jaktqpA z)NU^c@g28{yZ1*Al~&9|y%$|PSz!tu-uIuY@WZE!)UCeFDa)8JPH4*wZ*I7E)4D=*On0J!Q}yr?u^4-wScoP0ob~ zhsoNqOk5?ah-*7@Pv!A>q8BPuOPxll$FPS`d1?0VT1BJC0b?O=+!s=ehF`ODvA)F>x4+up%nw$puNFMu;WQw(q2 zoxsfAy1P<`B$~`U(GOxoOh8Jy;tTF8RmaEPG5@Aoqck}56f%aDlI@?yw1w3jEQLh) z{krvI)@@7po-Ga^oFSZenGO#2N!J*=qa!ZQMt5R(?Ib@uVCC)_@y+CnJi8GZ_`%=R znF=rET%PMbwaWSblH(x&HEnCNP^~oHGEN}T$4b+o3>Zq7UEZ&Dcz!rq_T!zW7v%Fx zfrtf-R4l-=KUu25?sRymci|jy4*P|D*`_}aqD}9J)nGK;F zSHX7pndybE@ouAGWdF{AwSbgaw)APn=&Oqq1Sa`2*+Tj_65dT61#7@4by3peWA}D<-6Y}a+I{KVTX}^;0Qh5XhVvc8E0ei8z;LmdC z=@q+j&mVm;6#fCeOsszhsrJ0&+JVT#2UpGY{vcT>*(WB3wNP88lnKv=cp;1|zd^n`{PUhFzd&igfBQ0t&b_25G@u zWdo0-r$(S_QB4M$AHSXL+qi!@*$-N0wQdh99Erqj$=YY#h*i{cjysc@spR_3rid7U{%fOLbm3`1tUZ1s-UygxAr2|68$e>b^oBwl%@ zJQxpdd$Jal5fhuA@5B_BO*?+tOoqg?pSu5JCcX>D zFwTnobGUg)#zTEUaO0E2mrLSu)df8UYSD3xz)p!?co-zyU~w)oqsj00OAU}%!e%jg z0n1GS_LzWhG&Js_Tx(nX!P6U~>!&K$P959*Ss9!CSz?nB?}K{~UTW^D&3!ABcT|es z(eV0zblVf_##)mxVZb|0$?Si^VIA}EMMOAwY3C^WEP(v(aNFv`!f5F3Ptpz}#~Nw7 z))t9O4rC4uMBvIvDy67!-;&9Ob9~CwI$GHg?(Hj2a*tewPh_T<8qykY-VS6f*l%ql zzTn^O5B!VWzRkt$e@eRBZ5s!r5RSJX0g_f|FQ8^6Qwb$9&Z@S>x5|w^7(UOc=HcT^ z9UHl;u{R4r_HVoR=PMn}y%BQvYMYf7R+H6pQqVwTI@j#>lDMfm#9ptTNKdlsWy{UU z0q#dmE&?9?hrOA#A#a=mGfMt1(_$F|Mu6xCDL zlTZ*AQfa#(bh)dIE-WC77N6dPY14k84Z2&FVmVS>kYXuk$C19*9G%gAoC~7jO!Yjw zEJoJ}smG3!)`bRK(22AORd;@8YmxZgWhR04cK^+UnwOoz>cy2Ot6!LUWof$PprF>R z!=M>#j|c7fTGYD}FRyka8{eduqZL#+0FYPmuE75%8p17qjIh>4U*N3vN#SfZBh#^@ z#C9MR^d&e_DyoY0YzsE~;%dM*HJgvZErcX_P5SXeLbjShy9M84dpFukD3{`wpFs;F z$zyaW%1&dc287`W+}dYM-bvb54>ttN2r3+dhGtV@|W%3 zA(C8Asa6UL|^pV(^6ak9dQEG8sQs$OwxJ*VpuoWtbd*f1I$n&ZLRqQ{n<;MX2 z%isPlN+PSeac!C~YX^ALUq-$izJbv3N)6l5>Pi@sWds0e#mRF|w;WJQ?yr5CZ`yFQ z5uBPUy}yktPPX|nDVX~rxJr3_A8gMjS&GA3or|w@7KfA{Z@8>=D|0>0RJc{P{2E(| zZPH!t%|M&@>MSWbZp^NAyA_Y471{-H+ib&g8KzzLCX^YTfnfQyB+&Yv^a}H#~UAqPi`} zLgSb78bH`hQssBQ>4RX??$C%XSDVwQF6ztip_?X~CI0FUoOZN!>oMZ_l&+Ezx|(Y2 z1~Eptst}Hrecz{_=R{-wX`8}7(QLee<(p<#3j zZ5Ec0F_bfcNji{`CLS>6*KE}O_bvrBbjgx!JgDK#fZ#k`I@_;j>qwG@64^GII}0im z3WdWTZETn@sK4uoLICS;@X-(DAp5T=AbjxKsHOBEi(BuNDzC?R%PMG;hpus8>C>BK zvyEZkmq)qc${-`@6V$&u7xG->cl@IKwu>i~*LtJrg&RpY;03)nYqLXusz7DIJ^mRq zkzn}S-HHZ&=3Ca5xYvj#$l)tKDHNb5Hk`4$Vz;Iwwz)>evt3kuE5Lh-Hwr~%*@_Id zw`>vN5?J!I2S-RQlPO+(TgM00#;dwjWj3joleQYfuQ-;uA6AGBbDm~b>x4hMH+{qs z^73N8CywIJ+3<4A6&c0|q@cek@!AaI_m42pDm#ax6lyr`;yD$(xP=R|NEezA#w5`9 z5z5%!>Z0^LeuGPJU^L#3zgRQXlf?K+O6Wg01AYci#j%Vi zh(u4vD!S?qn<&dIt}h!v2K-y&vAr#0E3hzSBUbW?j@C6MmpQvaQKzB3^r2HqRl4ij zgh%~8i*Wk5q(~-5?}S?s>>p(c7bhP~V*)+=+ln&Rl}t9H8M=`iDG5FGy)0$i1BX{@ zN7#OMT5K?eJ0gZwDq+{t#6m&uBF-)=(>Ws}-C#CXNr3xmSEFy6m4u;ypQy-EA$+UM zBOB16xE)$W163@DkQ!;aRig}y9OH@<`6-A8abHN+%h|1VNioU)MV4}xeE&{E!{YFT z(H(4yswCiz%h~uN(_Q_x<@o)ywKHH9cXbS#NuT#@@LbpRgaFh&U7EVnRwJe`dgvZX zA=0g-!&D2%F1R}(@5jE3g7Pvza>bsr{>~msCi~QM$2zf1U&djxn%VYv4-lQ7cXLih z)V-TB(hQE4D{|usbX;q0^EGFepSBciOp6Q3-n#GZUosK4;i}q<6Hhx@E;fe}^Ve<@ z&#GE2lcNs0STE|rr2{PwN%gA!`$OJb{H_x2w+&{v7y zDtW824=%5*!IU>y;N{4aP57qF4MxFyFn9N#86o*ys7-tG#N~9@t?lsc1=t&!^UiL3^KAQ(QGPu_4s{eUdvfqKUJS zXQ@y67ip1>=b-w0l4yie@OjSQb_W4zoZ%4q?7eE{4|9bm~x0emihdFKHC$9Ce=iBEo{_L_dHD76B zm#xS+v@Euq-L=U#HrU}+WpDJIJAEP!^rTs+cX0eU@(d%J5%nH;9dUylbo8czf zjLad-ZPqfTWV@^2E7d>a3lN;l{|Az#& zSmE(^#TuR%-J%7BmGk!x0$4UK1SWP6P{$ee_=4xaY~49R-lwcW#e?OYu{9o(Q*)^O zbp`_(saJzF2>YM(o^%qggXc^HR;1g`hh z1_EBInO_V*UM_E)A7bY2Sx!biD68i`Z5-ZE2$4AmOZljEnutH1l~08 zGmw8Pqvuxb!|8+hVy3LR{xXpYo73w5t>wp9+>{RqdJ6mAB5fWODp&s_(BR9pLQJJ! zEZdgwy&w|;HwJ$~rHAi&%gEbH-rVy_>VMpH@&n`+@&Bj%o!<7}5Q^w|{~;8mD0XZ# zpS0V5$)%!Xn!9wr9n(ER*j?*MIZvB%5itN1)w zf1hQ+Ib<~J0qWdbRk~TAC1u+OwYiPEgPM`QdCMSNei=_&1g#(vZ##|0lIobfSMxGY zA)fO%b|3}cx91dAN5x;KU8Pkf4-9TkdF~Xh6*its^YfLT}XCP5Vdo znX6`S7lK};A9E43opH*}vDmnpOlflpDU^Okdp6(c&8R!od0NO{jJ4AltO7KrJL zD=@HKl8dNXenoL=i&jM=re$$Znz>~ST)AY;?$SOY2qz?{b<9!k zZ$2?ba(gI$h>lj+1x4F~fAnI}=6*eD`!0)O?&T%)QZ&XS?2ddvULQlr)n(3|N`^Wu z+va(86OjQ<$L(w;c$Frxj(-`{DaGHO7uD`1muT7NebRb)(*Dd9E9?E#So@5{wcFb0 z_37cOreF~(`*Fi=lX21hpephT(kObvE%u4Wbx|Nqy4*|bd* zgKm7&QRwn3!=H7?=KF&Rld3OWEK~sw&R!~5gv|CqTo9ZoU~lppJ|POw_r=*&k4d4Z zhBD8CN-;?H3?8G7fj(U|V%w8RDx22lbsX>NT)~GU&uT3Mpy~1IMJv(%SnKu$GvHsl zX`ldR*W#{G&~wSouWS4+S%JrT=Rqh{hLnCHVT8>Ild1N4<1QHskmJB{5S+D)tzSPD zlM$iCL$9~sw-3)Z6QcEkH4Ne{M;fd8O;nmKTl=afH$vAL?KY#w*&WtVRR#_jp8(Yh zimJ|?edg?$hFoN;wyfz+)S6yfs-uRQmg%V1e3b9O7P*7I`r9`+tF@fGw&(GVFL}Bi zV1b$0zaE`wci#EQLiFACqb8U2Qp>jPDX|&*Mv%T)z>x!13^CDhFJM2JRazm$bA9{* zGCghCOetP~ds#}!l~iq-aH!8sVa$xvS7(s$?W7}tF&gN-#gf;BJ3#&7^Xe;grVj~; zCYtaW%&VHXPl(I@C(F5XX_C$}t?fd|j32E<%)XCZKHrIN?<`%GUM{)!3KXc!cp|Xj z@vitrNZK*>JUh{lUkv#dTGIR={BXzI>`lfr+;nw_#QR9CR_trsi zyxqR<5C{@9xCVE3m*DR1?hxE12`~hAcXxLuxVt+fxHG`uocX=`?t9;J_t{nV{Bi3{ zP1RI&^;6T+^YqiJ*XR3PYf#(p4 z5ggnQnx2+fB%0=5O;3w&ge9}iK8JxE@)?ol#y0lB392RUFZ319mA9%3 zNIBU+_mek#oLwaO^+!)h8>y!joG>$$tI0fop&P;}6DSq;!`-x;KZ@^T-vTz`%PAJL zKLHL~Cv=Z2#lq18Wm>fuD4Xg!$J%cPlU{#ymqzA$UP&_d2M%F&#BZZ!Deh^dSQ)Mb zUaNqq^W83a5koazZYJMKE9-4dY)+D1aUu*#RBP=n5ttk!5yXBIzd#Z2RkvDs zNJ;JhG+$4TROz6=I*EQ$FfE?q87r>lA#Wd2mXgBg10rBx@w1Y5rRlo;Q&w1i5`IPx z7vOvQKtpDEbU#nbTI66XKBduC#klnQSE5ML`eUdQ(o6lmKijZGwYZL6--z&IAY| z%?K5Rg}Vkjg%DjVMQWYIpRbII8-SED!TAUlI}?xTIhG=fNK1Sr3* zl;*{vhm=;O!PJXUQ9@bsAVc>?F*34{=#71Xd{=mVx=UDtjuN$KR4~3Q6kum5`5s`N zQJ9xku`X)ijgZ&O)a69US@`gEBO7k*rCtrGOBqjs87cZmLnoyzD50#d&<<5aR9$sL z>(vamJr>D2AC6V&QUr=q7Pw#3Vx~fT}6<#1A2oINl4T#n!l!cEq-v}??#KS&u zdQ6e+kV)_-xFnLZ)54~pK>QGKq0BXb_+5Q$yfmh1n^P4e;H%z1jV- znu1rrAo}SUKMsGF)}fU4cX>T2R$?EtM$oy|c+gs6zKZC;yjU{@v0w(Td%@s^Fxq1+y>zA!p_KvsJEq1KyiQH>nFC@Tsl0=!{qs_2q{RIWT7TN?P$cn@hQvyqS0rDyY&1CK^LK<4RcjDM@0mLH$)^nS$!*N zLBCprP_(b11$))ms;ZYwo}_Zy2ihAO{-{iYx#_7)<6|euWw2duZ}n4Ng4f;H!?oF7 zZ?v_}YWrGBgOP2{^eK50qqvQKpCr`AQY|t*pi;V&$ zbL(e~`>LA{sN%w)05XjW?lG7`694)O_;zXYunn`2-6i~k&XvZ&J|$X7 zs%X$Cs|>c9vBmkt-LFn}zaF5rCQ(4ry$ny z_@u8_I=`&$xk{HQ;e#73@qT1fE3}cXkC-TV3SMUNpoqWY<|vj58h{;RC8a5$ao5PC z0VFGj(b%~>Fa<D}pGuksd;W;ySThGXRbEmzNM_ zI8yYhjMObh4=;fnK<~;_=WsVi3eNBrv;66bKiSSH^5w+T>yB!fzN`4Cp6y4*z$!T~ z;hiTJSyG>8UOun2qfxoNw6mB(pW5tYveu-U^e-=bj%T?w{7Iu8LMJh6YZ|ptLa2qoMe4JaD)QVzWEyvIGUS` zHT|f>@VsdDNNWB&=^I7fr(n;(Qr|>XQ)&kjZe3NG7_VRa+?Z?AX&EM}dY{``*hbD= zEif`T$mDj0o?Y7CH#dt(K{@@cu0{W`!d|=Pr0c|m$qU{UERL_Cc0jy2@Pj>J8n@H!Y8! ztmkK;F?GFqAB(_roR`qm+jIp-=OFhon zHd<>fG`2MTz;>X#E5B8CT1bM?3Vnnm=jPjAu<1u@F6N=MPD_iSmXrva?$7i;M}xai zeYoN@ZD=HPZYMiG)>QkP&u$sHQg~o!G2ee4^vm4n;tDS93KYCs1Zz$umb{@AOrm^h z|0qKJbjBQPX|A*UO;bLnAwXv9$B4_HS^C3=-A!`$u0Tx}$K`4A`|2lS=cQtdNAyjy z6Iz!A;q701DyxKzjYDQ!g{^s1yE(X73`#bkZ^>wRlvW;&QDhPs=guBm8e zVOsjkfj1_41G#^h{k($})1usH@6NItwgXoTA)AM9rwRe67r2nNq^TfI%lVK5*$zwncw1R;Ik_mDap=~JD+22$7-__cHW^)u*K&!C$h#M{VPzJb3oHO zthDoOP>)DXQ_6m&VeIG9thPqx-A;Y+$E@%dHU1bEu5SN5hSeoHrsyso+Ihy#akM?( z;rnPW&&}+4L;`x(OUX^zFTBM{CixG0-C~{G5dY*8wpez()gZrCM&j`+#+w8S8dH61b!ay}G|869AbGnz+?HGf z*LTW_eg3)aX>U?()Z;PijHqj;p*Yb({GPh9W=5$>=*iw~ah57Ii`uyU^=k=0d8w%9 zP1HJw;c(%e2$->C|7eny&$qjGr`Lz&7#u#Mtgiq1)O!{5t-I@DHn2y@VUaf9ZCYho zg#3h|sGiq)z57c8Y1tbPKRD3TtxjNnzGRzH+!{fnR%ZRT&CQsS=1OVBD#;mT4f*G;o@$z51u;eN-j9=w%Ldx*-bX$l|4ZH zaKqnD0#fHizM9oKd51>A045eJwj_nEI)!|c{CwCgelAokY!8#T?UShENnB#&O(o%4 z%{>&6+7kjW_k>a3@M<0(j0PIu%{C4i^pJaUK%-d!22;PBtsI2A8w1wIHl3~0DDsI- zq66L+EDK)8TZWVwET1yIM#29OA%RUc1YL;_ZVrG(abZQ!v(@*;!glp}kK*>EIjh^=q}Qk~kS7~0{!#;( z@Od_-#93AV$vzp!W!MqWafGV{QI~zYhRMg3?8KKO8-Ih#8W=-CUX&|oc>%uZG?sX& zPCWEe;II{khxss@v1NC>eu_VK`o=0#+IysLWSEOcW%t=a(xUJ;hl-u9kqy z(@A#jm|yyBo`&A5(~pK&3pphmqaL_)r1a(mmfl)@!`P9(m$tp^?h&)iw4!pho@WY% zT3L33)?&P;S6DHi&&Q~dXRVSCxexGuUmCp4cwOczk-_c7PM4qp{A*u&*Oa;6>WZa^ z@0Lc-GtCg2H~gkr6vRnxqlTB~66)tt6UTe7v{00zl^ZcB6ALNS7p0Y%W?W(O=;89l zrs<*gWb0|!pJQC{Vr<{4uUG<1j)7tE+uM4)R$D(QpXc2Iu{1FW4M8=rHW584-0&jA z_e-nWJ!v*Sj`atHKiJJ#y?4}mRx2#KMhl%(HK+(zUF8d&M~!*}__^sD&iDF0$uKJI z%RY@LlsIm8dK?}!r4ndW=kRwPcKs5mD0$DGVtLqP=dLk)G3kEA*f=GQp^0LR!6kVM z7zg{-zW$kw@H*%vvJCXT1J{rdb~KP!vYkY^E(iFS1%D357yw+SG~Irx6VX;@GcNG^ z`-hbU3=2v ztNLAU#R>23m{#IWVS2^<$`zGXk@wDEOqel*2`y<^`1L^*0XG#DujOT%zPpxs`5oL+ zU*f&j@Inm}Uh}Sk#^+eM84`hI?T7J01c~ogcm=OXx%!0 zbWu}Y;V)bgjzCl;Zalupz|5SsJoQ98$}|3{=nU^RrPQON35&V?_@}w>V7-u!$e#ck zHkQ`nXbq&iEh7`Wy&)3eC#uyJ11Ykc8o&m@4Qe1yyHi?gVHI7;-vADy6)5994o@*a z3{!g`2~%A*OzySer!4lqT-vwY={V$*Z9~=!S`3^hZb!LDVVA1x#%t~Rsf2mm`}J)3 z?hgRm=C4~ALu+g4>?~=GMTUt)S#P!CumIe3O4EcKwL|r&POg)V;7HAVWQE~K1J2EO z8X8$;C+N+{y5jbM@v^WFybzVXTlSH#H%BP41En+84XdG8lpaR(MnqMieYdUL-D6x_ z$G3qGI4G-$E<(GGalz_#-m)~irMs2Grz5`#_-LmTaUVkFIp%jxGP#Xw$U&^aiec;34zQ{BILIb>rI=cbi zF%2&DnlF9yf!eR=G^OX0 zTY>_3N2e zU|F7Mj5K&OM$qj&rC8V0|goN8n!T>VWTf5Km(z)>g5-^}aV!ddf*lzEapsmMl+ z`-{BfSxDkKf_-XUI$*-0nvwB<^+4~j>V0~t!AsfL)(J!QWe$_&SucwTH5dX5OED6f znZ|qMKheaWx#r>(Qo=HhE_Sm!4YLBolzJW!1q3QF`_97ser!yP`!Bf|Y4vBcEASm2F`aA6ImYx!6}d0Voxe*)iwQ8_2guIYE5?D-%hSB z=cS_<(nt(#zfGpFaRJ6u{m_;Q^>yZS_;&kCf4Vv&n{)&VG-#6>4m06#P)HT|Z~|MT zMQxiqPug#{lW^yMlUir4m(J?5S7AE{!O>N~N?f}Bk%ivY67~s<-+RKzF!Xmdx`|CQ zK@p_CJ}c>YpY%cf{mA^@<+B;s9ZlB1^=|*QWbbC+8;$}>M$?&ec5q<8YvfgIZJKMl z5YS2|y`@C|;pBZwyZvO+A+WLgYJ1uc)%=+5OKd*D}Ch4W$)6<9$X=EBqO{DSmW|Q;9nFPI1Pv*Mphwu3h z3*~sb2`R)rw-2Jm^}M#e50$(o4F|!K=^aPo9h~Pc3uls|5$#7%dHvz2oy~ufJ`xY6 zcQ;-yia^hpKL%Xai<5oKC75BAMW7YM1f=#4MFrpf-AG?}P+dk~Ua_8-Nc2&`8*{oX zk4fe^Al&G5J5FB~;`8c~UsFrT+kVQ*VRU8UZ90!Cs@Q&caAO+Re2n|92+X(kG3Zgo zA_ydp%#&;JLzCTj*o)HIUctB|6k1da*-e|8Z@$n!M0?&}f5te0pOIwNI7%)60FK`N zY{Yw1>o-0mF}5h+yli(QFmi^3t^r60-aC^4X2sE*myxg&3=e~Gv2Le|f=TFAgDTlEXMGy`}d5x9nJ%vg11AS*wA&3DSo1$*QY=g3oe+S=*W3LGrXVD z=R~G@uslzs&(iFg>M!I{XJ@Wa?B(NKX)jvj@Zzk#h+D}0IA`e#U46yyw%ID$t~Z;a z9@dIW{k*&$i$d?fR3}SJK_&# zzjGcQ7T`)dzFBZBSxY;;?;oD1=z0G40+Tg!3TQbq^323f6{;6F1Co~dLT-mHwxKs3 zM95`vX)WK9m&=Yneom5DuK7Ep&s;(J-Ey*d0E#8~&Q(}Bw-4g>!FyvbUP*chIC4YpX%_&^ zy+sHLinW6?L;C3g9xVgaHFcV5Iqt^ZA_l9~sM>5Ek~1p1z@ROo%i_N&h#~vO%Zjfm z)Yf?sH~&fy`4vBRjh|qDC4FILi9GQdzW=SU{MVw`95<8qRl;#v_7A=> zm&R@?w=q(VI1v;#_iJY>;!*rEaV}}TN+_HJAeIr8+-x1#h1)j>031dl5^OmOvwa0K(*8SE zn1En~P72O2qu6Bn#OwL^$Ct*lPtbOHYVsL{B`Ep3Q*mZsSD2SbyB-OxyU&JEDR74g zrGkGJ@@SUi*1HXljc&%l+;)lHKgNtO(~y76dRsWr9924)!MTra)sU?ijE}&X_yN#c#dr=i!X+anrqvQMc7rbJ@K0L6R{A=qRS>oD z(V_&`Cyy=M5SMVaqMpeWj#^DdX8B8gaA{%dk1GvB7tjv=LzS?LuRn8>ZaJe9U<^*c zk;`pq&s!}NWWU0|7tN}0bS_c(wX-Bz;CR2dso?~0G`Mo9=ZLAOxRBO^8+LcFC)|@7yO3Q@8XfsT{ z&8?1elsv*!O9G5>i>>L}TRaa}33&lxRlyb~Vvr@d`?pz?3#za!9LadR+Q}gtoZh>$ z%%K8N8IlCofYerm7br-~*Rs&!5a&Rk^V!P7zvPF_6vP$$c*mh3m*CEl$fcmvvU0@i zFzSU#=Q2prDO4_iiDPtiAHm-y1VtG#K;cIrJfd>34w$n?w zl#TD7->1oMua~u9^|p{e#{O%q6r}s9L8Tc}W~i!kEz2YiB_*(|F@s~Z<$9~G@xD5~ zJfx&CkBYeh!Z_NwK>tx z+O@u-;UG#;XP78*eetlNX1Z0C5G)TKW~l^Yp*Nx{y3*D+2^D-lV2|VvNH;hR8JoiL z#b>N(XZwCQn6!37SQeR&lZ~S##PnS>@2ERSbXJeO{`e``f*-@2ZmbNtA)~=!U3Mr+ z@Htwz+%_%_d%oo?dl^HZOJcB57nJwzws4IY5uD}k6+ylF8j~nnq;#UUL3MWCQqq#? zdn%HD5Y}-K{xp+qr-dnQ@yJ^vn+c z;6^FRD$1ln>v#t`A5o@M^?fKnl;F5jcuK9$*dRcS;q!xwp zYAnU55bEaEvbxVBtxICI7*|9(R$*Cb**9T*|JvjDRWx|O%t|QrnuIBOrF<(F2ioXy z^8sP!>8O0;!VC`V_$ckAcR9s3kOybT_I}o+oDSv zCV-uV^_a6(;h#~)rfdWK6kk^=SsD*`_e9(lKJhCBk`b_t(GNfKMLU_9rBbwX=34DD z=@7VHcHnC4jUxaef14TuTH91|rUQ_0ZQQ!3#49&;F+*3_hr|@#N?7vIcEJbsHIp^ zv(6}%Fq%Kn*a1{JjR})p}8Qi7{NF0JNld<(BRqQotF#VQc%)Jp&M88 z!2{6f%Zv?RSy;qaeY!(e4W?n~q>i*W%z87Hl0QT#K=_32pM zz4rS6FyjY(d7jfZB=qfJsWJnHeXrr}WakG5$rZUw`usl#M#9r$f0k4M7QpajI=V8v z`~*QjgS4C!03UE$RjG9VoaVwmjt%5(pLYI47jh{oQEPKwPX{Scab=V4-J@s7nNCsI zn5V1mtK&LPAZ~r1axwuFu@>nE^91tIh-o<9H z2mU{3hI?o-`Nek!38;4=E1sMK0+= zlXdL}NocmzNp~ zsVHl=rbH!$w9z&!YlPJ1Ern4WzNdac*o&h)+msa0`+|^soYM5IqwP0;vo`| ztL9hCBojp0@p0ep>uA@C)Tf*soJy9--^HrTbYdnO*K$i;981%K$!7a#SEjYphAOIC zk3#ZXTRlz^M;!<6OY(Q_jk_ytaFhC27hjiGmD@SHdN6dB?lQ2%4l0e<=4RK1=>0Yc zg_95r{{?S&tH*`3&qiSk?tCCCqcc^F4&Iri*(tC0Vz@Ee?mT7f+DPyfj-=%bK22}(5q{SJK7|6?@A3>+c2s;x!C;o;Kc$z{3Y zQdZi^acwChhyX}U>yR@RX)!^{g7%&Q+z_hh;}1p>&??II*y5w1n-98EjVDClf7lR+ zdaf4o3IE@qIe#@I(%ns;nU;VpDA^pbT!`p<#Ola(8ir(aHG$Wf!|{us3GOTFbKN;K zv8)7JD{a1(ki9QV6=X(z%i)o0ZVHbut1%pNL%d`Qe%Pw(BHuD-IlS!~8r$el@eG%W zK2}Sm>2AG5yPRC?i0K}TEjiPEe!k5N49KcRSfa7z|2q zP3pN2(o-yH=TouqremgWQac@^ZU(mhGlvNr7Oz-Bw%ME3(&OThPpKoDAO7eD0gcs& zRMdg-%|Y{jlX5C+S*>UXeoh=27-b)CJ(UT9h9~t1G?@(Fu7&i-y$eX_pUlai7AAl6 zDMLhEJy<$ZW#{}z+*PYL{cIBMeS@bh!SoyOSRd%_gXWq8O??T!UL{g)?-T%xEQOhQ;}uv zxEH$8DkO2n)r9mxITkeh$lb|+@A^i2|p-goZp-RlImgtaXs<=xtsOf zn}=ju3muEzg#IJbPUDjU?_NE?lQ6`LZ1M+?i}vn)HSIMy{7!}jKcLn}`1)2hDfyi8 zEz0J#MB*68>Ihn`0&Y(~{#ER$Mi^>sXeKt&?Qz(@;AvcX$g%p~87V^2n7=F_pyJGZ z?Z*a$iVZG&TRkynISbkla99-xWKZuT6_mNPmw|)CS?e}aYov{Ib){JHSyktFB#dQD zi;Y=jjzzb4f=(8J1#l4Ly@+C~6~EUQiD==51dwi%-aah*3_rk*=t#iPFBKoBs!Yxf z_VqTbB@56RQ>zXOSjr=)pFID$Gy$%N*vkCX9tjU)Iy3Lf=dbvlmd z_S>8>f1)&!V>8ADUqsr*E=l>q#%|JNSKL=`koXFPw1sH#TO z+NDUIfeGiGJf0No*Vm7mE-M=$c3jT#$3&dosL}p@4{xAMAE;gyb5IznlpM_Ua1T!c zn8L~(0*D4cGBr)N|H*g$g^RLHV6P?P{(aLCRw-)Czrmy6fGeaducyi%1iWzCX|P=Mf4wU zA@m8tfgap8>tp|* zuz9XCan^5#!!uq1c2L%Gz=SWXQm%-=JIl}Qj+eaaEr}d)lmXHlrSt;z?OmN|E@(Tk zO)sDEQ&gG=GPJd;2LST*+8+)}4JUCQ zr)8o2>OqKFE#5u`-xl>eDl5(OGlcU`yuHlGuGJx58YxHD8B-N-5j`#lU%YdjD>%%P zD`dk!=cK%MFios4{+@$hvyGVlmdWcwXGjAF$n~y%cN?s9=ioH<>))V$Ag=!zm^e}nQv%~4y)aZvM)w` zQTxtPw^9tXDzRH6p0A=otMwD^J1LiCWOVw^!uKoz52hv%@U;p@!a&_rxdJKIl(9>c z0S!9|X@w?7G}BuSsnw!%nSC2lNL2r=b1w&b4^J{if7R$H4#Gyu@Nl(cPfsK8*W`y| zuUc+*oe>F`3WNlUO1lvzHA-R3V%8rXpP?kEQ35)HwjHha|FUzgmj&t0L=Sdw=19BN1NG9+rfPSu;{Bk?(B7` zY1}b>Vy~$!I&BWHy}AdAwT)3%=Klp(8A-WErzN;Jhj1~|F_5>@aG$t|uF~5L-G)cczFQMzUCk2R^u(2l@Ol z;Zmbw!vD6Bj2rk@SJ389op}~@Nz+-2U>f8XvDgPeo+X-^IIWD?Y~;FV`1xK^%(!`38MY= zD6<@M$)BKJ0RTLewkZC;fEZ!jko>FVyVYpo=Zkwy$wKW|JlD4)rItr@<>a*~-e%)* z1y+Rb{0vVQp;wJyO~T0%G$Qt#`^95!N%v^iPG`OYWI!zCnPE4tDzRcgv9FTXkE}Zo zxa4yAGeB80KFOu#uv{1P0YZOVpI3_(JGv_f-fbUfaMV=Qug0w|bFkk}JNjKCgmgQo ztJr}o8LLKLjI_Hg_Q5jfxou2>Fa4%k_}}yQ&N5Gv0Eg@F&?5r@-{#OpJrz^I|+Z2nPxXyU9U8i89%9=4rXVwaZxO*}MV4OVf zL1?hr?mOA+o0VXfdK^4ivd#Kvb0?*>05KMj`rBAVZE;mvsckDaU1ha_T{G;qQ+#>^ zX8V^)Il*f`&OCh?CgM`M45NR*}A`(fx*=AsvX)^^77Z|b-2jk4?Q9>-L!JJ2bZ8kQ$G6;|9i z4Dmpi=&Gq;9jSQlJ8{e9_rKVzz!1kT7t@2T^!yl~X>E3Ja1gW2HB)IK_?*xHp1OP` z(>-QGP=7uk&7l&uB~y|?1zSbye*vFYvVakV_i1~1ync^Q;R#o-VJ)r}yVN(9A8(Wp zyT2Pbrsch-asQNB&7#3Xd##3Ct|!cK>U8w8jm&}&DJ_|OA!P;=2KVe{zo2&)-zzXX z0EFY^rA-^WiuL%REiL7_a=*J8C}_bb)e55E2K3h6T(R{2f&^!hS^b$)pr>UdD=AC6xBkAw z+jO7Ib7O@|`Pjn7HkL95#x}*up|42X)XUN70zU?N;|T~4?0-N3EZGE%mnaD2iu3C< z9R;_>$8psRT2XbAOnH5$!kl)|_6l9EJtHUzEypXW<=zd#ScwRK4z)$$Pjb$mh=d%9 zSS;oq`8(>{>^z@HT`H;Sznjiie7lhQ!p1(4$KS~Me0&+$uqEd7HXc}G2)VHrjMRdK z^=8Ui1+Ld668bF}`Qxc~bBu(^1t{zfGOH=A800|riHJt8+XQl2U2W$vOE_=OtEWF0 z3i>sO~xUFx9YV}C*CdKTV*cZGC1}TzJ#u_LHuidod!KD2!?pS zyF2XuY^+9T`UUW|BvAwhZcVWg36E-d3r|?~i8HI5ZMq=<{vEF^+XRU9-0=(R9q7B* zu0sx>=kfYjKe-C4Itv$mz{nWMpnX3`d2a~kTj$eIw%6fRnFrmMF!@6pJ_U#~ak zuL$liNBH*b`!oPR`#VodVHQ0OV}QjtB>a8{UqGtNqB?Fk-#@S8@E&}5y;@BA77!rz z`DUu5CWd1OFft@uL)n{JW;V&6!Nc}hT(x`>9#1U1{U9%1vr&l(jYOrz9pn{(PdpGbyo8JC^T-P_~2A*iLhwG8rtKasI)mgtms!ZG`7dO+Kg|PKh+n2XunL zGe5@cCkyD};;*r)<8~P7yqq$Me0g1%<~Ix+9T(34%Qnqea}fTmudXF2QpK}8y|4vB z&1_1-)VjD7HZ)%df=`)oqR;%^Er=VaE0N6b@%QT6+lNE(;6$0--30@}ME4!9OYQn5 z1^g9kNDjBd`Q0h*Cz^D1loTYzhWTq*Wu}T+x0x)&v%S%h7(X`m!{=nTQ2wvL+y5?X z8wcq8Bkj+uIzwjEC}tl3J05>T1y3)xM&rs# zJGfH^gMX#i*T?t;97z_7Xse|?A3k=axa_Zm{SXmA>GvGs2%VD?&X%RCs2=Hd*=doA zi6JuuIx_pW|Iq*ua=6=f|*b6M{Tk33O10+eQk zwg07A2VpToO9^s^eLOyS&#%s0>4B$ zxJxLtDMdYUaMno1W_+*#K;$z9Dv}}=qe4YG3=IKru?e{*J-1B3X9>hzpxu<7<>%_R zzx~G>)TK!5#2qjDc}dFwVdrT%xHMhri$yo+Nn-}qxTSr_lM^f?y0VDt2qb!l!5W|R zmZ$dq{|9wZG&N7#Q;B{G+x*QqS_o^Ez}81d#i*{l@~^R4+3_Uy3(C@Aq6P z2&cLbh$;MQ9VC)rjh}0y<8IrwPrLsS{ylPigqrT^m&2PSNy&4d#X!#J3vSK z%kyvb9-3Cnxf@A((U0)w)x7HzBj-5RROi#~-o9c8w`{g#4DTYzjN}Ns zXU4~#$*+{pTm0FxTcBy^{FL-|b)$S$ov@)nDqH~ID@_9Ytgj<#KL9?AL_>LX>Ghj= zXl}vt+y9OI^lC&ilV&k-`|gq4EPQc|>)X%Hs5hzer;(^vM|y6|B9@(=Ntv*t6}kE| z?FG)}6!nja!hO^cVobCz=_#x!GY?eF?ffO7CarKiUpPAE5RYS?wG8ljL3^?e z-qDb?8F4y-o)||YPuXqzYu-^6-m07bczqT^`T@01(CXxBy#wW+p=|$QVvVK|>4;-J zkLgo{?5%uL-Ks|~lvplo%57TNZr9_5Hk%wmzvm>Gp5hl3#Pmry*`m3gp++83K8sCY zSbtP}xhT~&-Q~HO^QTjcyr7iN@U|n(3;j6;wX2P0^Ti8&=W%`2jiOlg=97~(OB8Gn zU2<4*`$cWQf55s4J|5)2H9zwI>YeH+(RJ@r6J_k=BRKiA3U;0!$A7hXG`zf}D65Qz z>3vc!l@xL3qOiTNH_F)k%rdb(>^U(JC1;rSun0Wo=IfB6i4gjqOj78oXzQ1m^QIHZ^@ows@8GkZh4sT!3SFLct z!GF3E?~s=NnS`(mgeBwMT*?gc?1DvSY-$=%hSN73jghm_Vp?QlZ;17b9n=3&XVA8E zD@i&zw;1vxPF&3ltksGS2zf1zhq;~72t`U_5Ts2%Li z$C~FA5RbmDMVaHS#DB3}r7`~>wq1QR{x7yGVbYB9kn_}>u+PO6-caA|!+R1sZRQ79 z#pp#dVOl(G=Z`R7`p_TU-T@V^MNR%^B^|iGz9Rj9c2(8>gY*JdCm(HGFgI6|q(V9H z0JUBM{PlF@(iYp3avRP^)rK2v# zAy+!q8Q2i}3I#Oj<>1PP7Fb#yj5P4lFI716Wl9fAN@Cq2EyuFk(ySv8C9AH0>TP51 z1MYq-sn?YTNZ16hem4DP7rf6E2k32VwhSt*0~afopY~0BSoV7w9Y_z#@HC(=`IYrH z6Oqq^Y+9cq3JpNpdpS#v!;tT?idN;}ZV2T|b3bIL=j5-p6%U4H_IqL5ero61 z7=c)BpmnG(HXP3B97Z$1_)@_cE8529b_#|n%kY@9x;nI!ZSr87uk&7zGEs$RU!7%K zr404GVw^qW2Kn9;3^)(pEamJ6ixR!X(@|!I`09fb)nFHYnoiOML0rCRW&)Q?( zOPOL6)ZUvFo3YFnV%&FlAe=FFxzFiusvW4l;y*BB8<<{kYrfM}j$L+*Q_t|@)A^Vp zOL5lg6)Uz^MeeO((Sd*OogPFw)&+5gsgjIGMwY)>Y7UI}hN4SI27s*K>T<26C_padv7^A_eFZ_+xoq|3 ztgW4H{q~&sLO&9H$F=S*rZXbFLLp z}2TcFR#8WR&MC6u$_9xm%V7Q)!sjIO)pi~)nba@(1UP6BmX6eOmP)@0`*el>YtG~7)r3zh=kY*KG; zF1BydqAwf)02gNs9RvQ=OCOa531`SdAk*7i=&&`c8O`L^V= z?F3rPq89de`Ov2}?Z@anNP1wBhRFt2M&&*PG$#W|fld*!%Mb{+ad4GaE|){esQ4&^ zh6*;c@pWid6w^*l$H;J|{rz@wP%W{@|tGP=06n)+kBD1UEm0Md{a z!m=zcn0`QQ0$JTq{_;YPxQaVtc9D<_${cGcK#TsYY@IUqc2N=go>9UoV>=?hmV81p z@y@<&nVw>1ZEdmN#HRoWKvE1lRH<+ObupdJA!?a&r2l}*dZSp+kZw@4-yU4MTKb&; zJ7@V-^d+dAw0TTUeE$y8_FB81&$K^V1G_PLsC=&yE`^ivNd0flns;Ku^*M&sXtSoX z^Vyyft=S=%(Fk25;}b_25{r}MtyEG zi%Q9?*f93Q+MM437(&?&xDnhhQ`_mejFAA`W7$O`# z6PRGP!5GMSds#2tYS5r-Kqh_gAI3g-y0h~nY{_lX+#m3JzK#j25-bB^4sS+&!{a|t zxecOT0gAgn%{3njT8gQ@B6GsO4;-0#kCntkqs#tRa~us0N&!PTr8;^!_a%Fbs6MrG zYMcF>3(7kDY3Uy;sf(>=S1Wevb$;#c&!<*Slc_VaBh&3YzMxS%taSgMX|O#_HKz}f zDer`YaN%$ z7og(qzfy33Sk1R9o)CxCLuwaAG@`|SKg9!_4^IB}*ejBGXLYUh>h9-`VS4*&->Q}1)oqeLO{RV^MU@$W4n^o*U zr?;KK+(LMOY~5_qgAx225*#gdf#xSN+#o`0(^Vgi0V0j|9a*^dXtln$fNAnHE)=q( zN!cWL2fTm@-G0qGetU+l|FB>0D}R@bQ)oPaay_8?tt3Q++Nz!b!Rr@2G{%-OGdz~m z)*6bg4wDYJS<}PY+_|YC8wJ0qiRL-`ib*Tv~-_eNi)BGa66E&9#K|DG;X_; zI3#SnPfvS(vU|BEc!cd|^kbEbAu=9+DazLgbA>tKON$}(uCzU%InsZ*y&Kqj#0Sg` z91s6X@?j#hCu`!~ZhyeOf4&ZJNY>g&%^jK60PH;LtOLb%UK+O`k`F3z-f&?5!2tJk zhl)r`J0_iZry=&(EvZmMix+b{s|xjwS!? z^x6J@0X1<^H$d=(Ugc7YW=dvg?S*^C%V(IZJo>tCu)$xYC_p@%C9z}Ulzf$t z$cI>eiAJ2D)tyD;aZ zmxq@zWHLHM$8?o;p_TCs_{li;l3Y#_TiYZ(itIJ5Uah?DkVc%U^UEZTEdZxeQo}<( zY0BA`w-dCKum{~Zg8QkB2Fb5?*M59}JwM&Su7Gem!QGat+fSIrH-I!zk2XaFp=Pk{ z?iF@`pApT9s8KN#Du@#U)Y*752}hF3nF9RE^%(h21>qPa5`CH@Jqf9z{SUb&oh3>3 zKyva&thN63om#4TONbFke_8;*L`dl{T_maPL-m(h!c(f!j7}(lG^#@bRFbEzQ#cUy zX~vuBUajMg+}HzxUw8IzdsQ>LO4M4N-%}&4LV$0ykBexkwDXGpjg{T~mlj=r$-6BV z<7QCqg~vz%Ff`Fat>@u zdBzF&F8|@?&m>cmZZ+Pq9%z@RJGIGMnT-Dv19VHx?UtGbN!Z+4XWYN34(%}+M)dRo z2Zww){wcofC}W9+4Bv(Qy6PUrf8h`BC(pT+@V@VU!iON2Ia^suUuch={>DFg-g3r_ zjgoauJ2lNxokp2jZ?^s^>a>AwJ1FlXd_9f4zIEtydW}Yj=0i98aZYw-idgUo2!M@2 zL2fWR&Rh0@bTP%t_A?4Y<0%kDk{5l(yBgn5;B`QiDcORSq+@Fs!6S$&YjG4 z0=n)y4o9Re-NeJ;Cxz4y-^FJR5|>%OthcycFcQQfFwxc7J-;B6GKfS89;a}woro#I zn*$1nhCg>-2|C1SXr~t09@i4S3mYO35D*rsdH*@uNDEJc@^);eF)xzutv{n^M21lV z^!VH4olF366ikC{ed|1i?8d3mwrUSQTdy|DoVU$TDn<7x=uM<-p`l?YS=_c}m|uln ztw-)`8+)NUsuETGjb<#GnH~2#E11DoDosI8wDee4zs@Id{pUx1QH??u#4Xvl$II&- z@bKUDH}5^tX$v>w#!eac;`xqsM7>?Dr3ml2Na|KDqI%F;Xu(igukP1FZbe+H>4Vmq z^&u3$e6N$ZN|5b*$Nxueg`QL^wl#x$s?HqBolQ}f_YZ8YxA&h+LqpgKQOr?U0qA}=t4j?g+I^CHn(QF zIW~K+FtK+hLp<;^C$1rNJb)8PD2TO@%I#qSC@(mLL~A_O#swM7B|pbI*a(14yF z4FNblluPf}Fu4AN_pIfJ;91)j(hJAUW0cDn%{x-+c$!Gr-uq$MIoNl#sp!%3i>}cp zvV%Fu8lR14^XZ!TF*bzXjwwtNR?)Db`{S{Fc53btGF}o!a&dC{VQ2S9q^hmc>rdTE z>P9!RY@Pw#Fx(2&cY90TLZN~LNQ8V6{4Tf~LjbHBqw?55gYlm%a* z2;9!5B*G>!n;al+>v6WE?fc?7>n1x}l-koq;k$}%t7Nq7kLtMzRE&&N-`pptBc`l& z+~eU(`jq8b`rjE5|Hjwo={4cG;3(A*8ps8eeyja}$wt*;g9cSLn%*=15`N)zv=opI zjIqeCFj|izqV%@Op*V{%0M%0gt5cNcFDBZjE-O<8tVvX>%2wQ#otjw4i4?$!Ng^%f zkr1iW=QW5yt0s0QgzB}TCmB$b#e9cWZjloAx2d{M@=ph{VII2Dos^$$8kV}gD3C?9XfKXWlzVozVoLq zzi#rb6tni|%_9hE=;Ed44F&?Qb(Z{1~6}T>!Ed2XJE8&`FUuq8+?ADb78^GJ zz-V)New)YMw;_Af4noOM4f8M(?3P%#bsMqxQK?2oR8!dZaxSn2Le@*k1vd=B26PXm zUdTqoYkOTIO0bk#iIS$-j}j_wHaL^=Q%mpAO%}6%B- z73xbbR<@9$UF*OH4B8zTJ;S35b<+!6Be^8SsGIR_RZM1?39{vcEMi|x(!}?_Qw8Sj zO|!?ff-=}$wb*zu{fKAY>9mM(q>NtBPc$S zB34ZIfy`TaE+nv*j-%vQ0LIbOGiwDbA^oj4EQi3@PIXLet-$Kn&Z?f@W$>m$) z;DNb8)FX^&M$i;fRg_qEY{2{o7mXcTsr)hcdI{9Pw|Fg>9ACekFeF>3eQ z&!HH!o@*hNL5}KCXN01}A&EhHuM^hdtM@6N1SfyW!sz$S!~x5v>SfK>DRUDI=bJ%m z5t?+ge@7EDX_TSU3~5gU-M6|o*1tPU%?Ut{`BfO~t`6@!p&@$qGdQTnr92wpR1}pF z*1MtjQZ@R{o?_Iq({{+4N7Sumy~!{6mrnDwz6j;8 z_)_}9fnDDPE;S>SJ`1s|n3&ywNs2G*`v}_~ycg5+i3zN*tra*KpO^GB;<|1n!|Q0- zz^)j00KU8!qRZEI)G%p%31WsWl)OEQQtokz8<9e3U~k-Vd#rF7&MPF~^7+!`h z8R+-9?ejbmTxfoud%ka)h;8e$N(KhAxgxB|Oc_pptkEa%i1l9k%o{2;o6919t<=5} z=B3MY(KAbb3%P+do~alP@105Gc#3QS%Lliynq_`UVq-4T9Q04Pu9L4r|9LZhH7+&q zmp+@&c1<(o9;1qbeNA8Hu)-y0J_~_Fg_0_JbMDP_)+aLI3NTm1k?UjW1hcBRyJ94X z4Hm1dR$!&k_}*3~=(a=6wEbLJy*jR0(ofz5v-ZyJo4xg{7#sPu)y8W^yaCt_?ZL z2Z4OqmE1AT&Oa%~qqY&aJpJ+xJT<`iR8H#yC$SO!;OGV!@Ns=tAdGmqGo!+>zQ%=ojO}WOrYR~g;+JR9F)UO_AoOb;IhN`t~Py>wdM0D3@Vz`` zcpll$A@B0XoM9$y7QBKl=|}+UWv)v|yVGlW<3;JIxgX93&y-zxN@kn@6DPGb1&*ZF z(blqh4WTlGF#_wjXMnzFS_vzE-kxY!#9!?>W7+9#V`erAoDma#j9-1*G10uXP&R{2 zM&O)iXF#nry2%O1&QbH5(WsoB(v@5al>to_9|lo(2H$9{$P&uw^w# zq4aU78h`UD`gkS$=u!J5x~<4t|HuF~q18>QefD%rCn4E#&=|@0ftTg2A|K&wYAVdb zArwdIdc;I&$Djd=0zlOPFQv7Pp7SAMFY?;5A>EcccDX8U8dk)b*jJ(xRslZswYAwM z06ox_ruVtZcd2tVF3GG7fH|V1X9YxxB9yCW=PW4>{Tn{_rkxvGjX_z${8`jvcLvx; zy7_RakzTu`NBCa{&rkzjJbd+p zwHxgAe8E}u$CvyHZO1q6f)H6eLo@vzce-08-07ij^MpNc*wgn+x!rkXj1bt=pYIi@ zH$D^L?HtLfN#*w0+2U<>v1thh%Gj-Nn5`{i*2}a zrqrw)m#0~%y?HO~+uW|?X@V{QiNy7AN|+t6R&&oh3A6*XF=O&%jE9FQ2hQ3~8AP>I z+_Q}rXFof(@}w_lJ%PsoLkNkI*@k3(nAMgAho=|7F>act*`be&>4JrU?_$-)K=a}0 zM3nx;_F)Uh_3lYK?4qloTI)N4lmt`p>CY0J^$sFBnPr{4KPM`-CF=MhYpJ~@af}K2 zH2QN@0nZVM>%@i9mRYHA6sKP zVkfa8KKaqsFUt{KM`_AWc}E4U_HT3vncoN3&&0pZJ1Y6Ao6+qTZRPy^o6vmj^Xabz zx~iQfmTu05K17}pDmAlYnIIKy5zz%PKTbED|xv1Gm7P}O?m{N@(#0|2IOV}LjaZ5hXiJu@TkdA(Wz-VnHdj}*bq7e(hGwS%yUg>160so>UVux)Gz z3aIYczUtTuQ>kbnm+@H@h@R4`3&4MOfEMVcPVeyQPP!0XD44|zp%bWqU4X)QfP*y> zIYCnj)=rHRg4!%py-M~*0K;zoeRUNv{?qB;)ou{QZji+L?RP@Hbvs_LUY4K5`7!4W zkL8_Sx4bkyxrFS&CuNcz=QYX}#7k}m-m9JqAf#Awd@$SLMLs5P zhpN2#)%;-gyusts!MZT%*>Sx7YTykMV*}OmZYO@5WPvxito@oxPXT*Gv!{6QDH(lT=-__=mFo9VU!p zG=92pu*)X`@GCpo-a%8>z~=Whs(*%4Vw7;p8s9bCz574UKSO$3on8)QUU$eyq*wvb z#IxO{BbJbkV*}LvUFOEGbxj~&LC-SwW5XDy!@19W^eIo^qbOzXe%b z@|G|*!<+-1Qm2RyKuCm>jxh$Nk8A11GmVb-Oys{?NZM>E#MJ-0ZPhYtz-nq|pFql8 zStueFr0~w%;S2BrEt~U=e7z?%9{bn!#~0f0rT&}*sw#pF;N5WESvvTw?Tku4SzE** z>W2iMYs5(6E9pTU20w?4WBlkrUrHUpS>gYe18pq$6Sy))gg7n_8QG!Y|sMmsGy|Ez%1w|3DCCW9|7R6Yi$s<;B?Wkz1A&Nvn z5z%;aV-zf?;3BZdHaaW_3(M}zxgS7W0fzK=F<5q46HUD!@^QHuIGL-C3N1VZ`lzM$8(ikUl)xQ zU5KvaW?DH+7o10+l51FXL%V&@PSzZU5g{Q{hP&Gs60*{Q%$sKp$J{BQ2$!&fJ7?KQ z<5$kzoq?Q!_Z$j#kY4^~#@8l^SJPpqgt3Giz#d(s(`wYn|1bn`bdTaaEPz5Rb4*=jcL6hICR>xzohi1n9 zn8Zve0w_Kmb7}CdiGI#;N3u!K@d=n}`}p9zsFX4U0PrkREv0iC*Ej#-6==JkUgqO% zaUxepb$MMhT5k^_x{_bh(qWh`vh_zEZjibIlfHw=aLch9w=eb9gW5vg1Chee?h`+6 z%VT#+)T$b{oG^d7B;)S&EA@H~wrnk|^LaF%l5NyyysrnV^j7xkVVtm^w)^}{9hR(! zcjv;f*k7~h=PgL&JPDu&KZ#yBXSq}~)Y zdKA@4Bx*NDWslNd$eVtU%6Bptkish)7XOcN8 z*)rp!D<+S2OgNU?Ni|CJOVp3nt3spBP6v{z&Ps^?tt8k1Apigz0|L)FzdbIk3IPcA z#rBI`B8Gze0*FG=0Y?ZL%s%caDK4HHpCc_ji+R9DrJl_E)PV@;^O zxVQ>z3=ME7X@3o_=MlVN^O)+GH9uStz4<`c<#o|$y(RS4l2vGVfiZjJ=>vH?@w7DP z{GtR^^7AVwV7ZMLZrQlf!}V;e4R8QJjT5()jt&8!X>Q&_eZQc3SsemQ-^fU#b7^51 z25cQp>*r@o$IihNN=x5((q`!znVFez*&ULg>w{`^4e=f6ab)#+lhBWRt7DfSP`36uIu4H z`%~)C{=21!Rtw{Lhkv)xui?_pU!JqAot*#xlvRZVWp${_>!Q)33DK0SLL2YH-q~IN z0F>xT&-8p$6$tG-+<3L~et*gHYXZqQyd(yhJn4NLP z3&wbQj+*R+Q7>f4ap`3=qd!?yCbyapJZ!eHJ_oBW6J%Z8x%YTVIRyZyu3oFJfA~04 zE*t7A1)2Zdx$0!1xc%iYrsoq8z0A9D5Vc!;U@(v`&V(;InM(p9wOuF7^tUq9Xei4~ z|9M?Z+^cu0sPgvSHTv@xOPYuVa?p8G~fULTEjM7PS`ue>{U;(yd%z} z90}=3&@==fa}Lk{=kPHzcieBafs!WFwXi%RPG4$ujWq|a{`vY36O22z>*w8)*BH3s z*Tm>xd&YH5eBd2HN(v;%%);c2GB8666OAg7NZR>-tTJ>NYRq7mwxjRt@PMK2R(en+ zNKcB5KAm3rE<0*41FwJu3nqFy8xb{<%p0c+i%tus8S%R)ipEI!!Yfs+hZ44 zURygSD#OIW48*r3R6AN&j|p4O1QkW?E*mmuytkbmlIEP{{jzP*g7 z;`<57m0hqo@*}6+F$}XDyLv~si}3umMWG88Z%;vft2YHWyu;E8x1O|mOQ1FH=-N4R zmw$JS9RBsjCH-|ed!tBt%CcXl-=v`j6yGJ&v?QbP;V^_lCh|6A0T zQziw5e0PagOF!;u_MNkS^)NDN>sND@N8h)f;Ai!LPXgUfa|f|J79C4XPP~mtVL3-T2 zGtYYXj_b$iaOT<11lRnc|O1Cg9}QU&#$2Rwm7K1 zzMiV9tz#_K#Ovv*45Nppb}FKZ?M$^o@;;xN3f4q?8mC>GvDb zx8`|Hm4ctixBkaq3%N*CN~xtqbKcg;Q&O?;rIw|oVPmghS{7D@Ejy6RJry3XEu~hi z-2V==w@_8`E}qNK|9r)oY2MBjrdCdFLqDG%Ios>?(1&EX*&@yWzwtfIj0_F**ebSY zGej2LNY2(BHE-c?XG=4i{{D++_L1JadSCXs8D`+S>dfh*k-i3MS&S+Xh!y6Rx;f7T zB-HVqm6%y^3x#5(T3TnqKl0<;;T zgz?|6V~2-_eIIK`)D}LwxogA0G}TE3)6wBz=w)$fy?Qf^QY0uOl{Hzp3IJ5Z Date: Thu, 17 Sep 2026 10:57:13 -0300 Subject: [PATCH 02/19] chore(gke-deploy): bump apiVersion to tekton.dev/v1 Ref: tektoncd/catalog#1381 Signed-off-by: gferreir --- task/gke-deploy/0.2/README.md | 4 ++-- task/gke-deploy/0.2/gke-deploy.yaml | 6 +++--- .../gke-deploy/0.2/samples/build-push-gke-deploy-example.md | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/task/gke-deploy/0.2/README.md b/task/gke-deploy/0.2/README.md index d436cc4850..41f0cd9b1f 100644 --- a/task/gke-deploy/0.2/README.md +++ b/task/gke-deploy/0.2/README.md @@ -5,7 +5,7 @@ This Task deploys an application to a Google Kubernetes Engine cluster using [`g ## Install the Task ``` -kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/gke-deploy/0.1/gke-deploy.yaml +kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/gke-deploy/0.2/gke-deploy.yaml ``` ## Parameters @@ -50,7 +50,7 @@ You can invoke `gke-deploy` to deploy manifests in a Git repository by providing a TaskRun: ```yaml -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: TaskRun metadata: name: gke-deploy-repo diff --git a/task/gke-deploy/0.2/gke-deploy.yaml b/task/gke-deploy/0.2/gke-deploy.yaml index 2d71fe374d..bc4078b877 100644 --- a/task/gke-deploy/0.2/gke-deploy.yaml +++ b/task/gke-deploy/0.2/gke-deploy.yaml @@ -1,11 +1,11 @@ -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: Task metadata: name: gke-deploy labels: - app.kubernetes.io/version: "0.1" + app.kubernetes.io/version: "0.2" annotations: - tekton.dev/pipelines.minVersion: "0.12.1" + tekton.dev/pipelines.minVersion: "0.50.0" tekton.dev/categories: Deployment tekton.dev/tags: deploy tekton.dev/displayName: "gke deploy" diff --git a/task/gke-deploy/0.2/samples/build-push-gke-deploy-example.md b/task/gke-deploy/0.2/samples/build-push-gke-deploy-example.md index 519e388d14..cb6eab8fab 100644 --- a/task/gke-deploy/0.2/samples/build-push-gke-deploy-example.md +++ b/task/gke-deploy/0.2/samples/build-push-gke-deploy-example.md @@ -122,7 +122,7 @@ Install the Tekton Pipelines CLI to view your logs by following the instructions DEPLOY_CLUSTER_PROJECT=[PROJECT_ID] cat >build-push-gke-deploy-run.yaml < Date: Thu, 17 Sep 2026 10:57:13 -0300 Subject: [PATCH 03/19] chore(kn-apply): copy task from 0.2 to 0.3 Signed-off-by: gferreir --- task/kn-apply/0.3/README.md | 73 ++++++++++++++++++++++ task/kn-apply/0.3/kn-apply.yaml | 36 +++++++++++ task/kn-apply/0.3/support/kn-deployer.yaml | 31 +++++++++ 3 files changed, 140 insertions(+) create mode 100644 task/kn-apply/0.3/README.md create mode 100644 task/kn-apply/0.3/kn-apply.yaml create mode 100644 task/kn-apply/0.3/support/kn-deployer.yaml diff --git a/task/kn-apply/0.3/README.md b/task/kn-apply/0.3/README.md new file mode 100644 index 0000000000..74a2ae327f --- /dev/null +++ b/task/kn-apply/0.3/README.md @@ -0,0 +1,73 @@ +# Knative with `kn` + +This task deploys a given image to a Knative Service using +[`kn`](https://github.com/knative/client) command line interface. + +## Install the Task + +``` +kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/kn-apply/0.2/kn-apply.yaml +``` + +## Parameters + +* **KN_IMAGE**: `kn` CLI container image to run this task. + + _default_: `gcr.io/knative-releases/knative.dev/client/cmd/kn:latest` + + You can use nightly build of the `kn` CLI using + `gcr.io/knative-nightly/knative.dev/client/cmd/kn`. + +* **SERVICE**: Name of the Knative Service to deploy the given image to. + The service will be created or updated if it exists. + +* **IMAGE**: Container image to run. + +## Platforms + +The Task can be run on `linux/amd64`, `linux/s390x`, `linux/arm64` and `linux/ppc64le` platforms. + +## Usage + +### Authorizing the Deployment + +In order to create Knative services, you must first define a `ServiceAccount` +with permission to manage Knative resources. + +To create a `ServiceAccount` with these permissions, you can run: + +``` +kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/kn-apply/0.2/support/kn-deployer.yaml +``` + +The service account is being created for 'default' namespace, please edit the +file before applying if you are operating in different namespace. + +### Running the Task + +- Following TaskRun deploys a Knative Service using given image. + +``` +apiVersion: tekton.dev/v1beta1 +kind: TaskRun +metadata: + generateName: kn-apply- +spec: + serviceAccountName: kn-deployer-account # <-- run as the authorized SA + taskRef: + name: kn-apply + params: + - name: SERVICE + value: "hello" + - name: IMAGE + value: "gcr.io/knative-samples/helloworld-go:latest" +``` + +Run this with: + +``` +kubectl create -f kn-apply-taskrun.yaml +``` + +For the first run, this will create the service 'hello' and any subsequent +runs will update the 'hello' service based on your image updates. diff --git a/task/kn-apply/0.3/kn-apply.yaml b/task/kn-apply/0.3/kn-apply.yaml new file mode 100644 index 0000000000..e486004d1e --- /dev/null +++ b/task/kn-apply/0.3/kn-apply.yaml @@ -0,0 +1,36 @@ +apiVersion: tekton.dev/v1beta1 +kind: Task +metadata: + name: kn-apply + labels: + app.kubernetes.io/version: "0.2" + annotations: + tekton.dev/displayName: "kn apply" + tekton.dev/pipelines.minVersion: "0.12.1" + tekton.dev/categories: Deployment + tekton.dev/tags: cli + tekton.dev/platforms: "linux/amd64,linux/s390x,linux/ppc64le,linux/arm64" +spec: + description: >- + This task deploys a given image to a Knative Service. + + It uses `kn service apply` to create or update given knative service. + params: + - name: KN_IMAGE + description: kn CLI container image to run this task + default: gcr.io/knative-releases/knative.dev/client/cmd/kn:latest + - name: SERVICE + description: Knative service name + - name: IMAGE + description: Image to deploy + steps: + - name: kn + image: "$(params.KN_IMAGE)" + command: ["/ko-app/kn"] + args: ["service", "apply", "$(params.SERVICE)", "--image", "$(params.IMAGE)"] + securityContext: + runAsNonRoot: true + runAsUser: 65532 + env: + - name: HOME + value: /tekton/home diff --git a/task/kn-apply/0.3/support/kn-deployer.yaml b/task/kn-apply/0.3/support/kn-deployer.yaml new file mode 100644 index 0000000000..c07f1d4d92 --- /dev/null +++ b/task/kn-apply/0.3/support/kn-deployer.yaml @@ -0,0 +1,31 @@ +# Define a ServiceAccount named kn-deployer-account that has permission to +# manage Knative services. +apiVersion: v1 +kind: ServiceAccount +metadata: + name: kn-deployer-account + namespace: default +--- + +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: kn-deployer +rules: + - apiGroups: ["serving.knative.dev"] + resources: ["services", "revisions", "routes"] + verbs: ["get", "list", "create", "update", "delete", "patch", "watch"] +--- + +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: kn-deployer-binding +subjects: +- kind: ServiceAccount + name: kn-deployer-account + namespace: default +roleRef: + kind: ClusterRole + name: kn-deployer + apiGroup: rbac.authorization.k8s.io From 8637762004b7a44c32dad949f15378ba171cb85f Mon Sep 17 00:00:00 2001 From: gferreir Date: Thu, 17 Sep 2026 10:57:13 -0300 Subject: [PATCH 04/19] chore(kn-apply): bump apiVersion to tekton.dev/v1 Ref: tektoncd/catalog#1381 Signed-off-by: gferreir --- task/kn-apply/0.3/README.md | 6 +++--- task/kn-apply/0.3/kn-apply.yaml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/task/kn-apply/0.3/README.md b/task/kn-apply/0.3/README.md index 74a2ae327f..39ed3738d9 100644 --- a/task/kn-apply/0.3/README.md +++ b/task/kn-apply/0.3/README.md @@ -6,7 +6,7 @@ This task deploys a given image to a Knative Service using ## Install the Task ``` -kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/kn-apply/0.2/kn-apply.yaml +kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/kn-apply/0.3/kn-apply.yaml ``` ## Parameters @@ -37,7 +37,7 @@ with permission to manage Knative resources. To create a `ServiceAccount` with these permissions, you can run: ``` -kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/kn-apply/0.2/support/kn-deployer.yaml +kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/kn-apply/0.3/support/kn-deployer.yaml ``` The service account is being created for 'default' namespace, please edit the @@ -48,7 +48,7 @@ file before applying if you are operating in different namespace. - Following TaskRun deploys a Knative Service using given image. ``` -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: TaskRun metadata: generateName: kn-apply- diff --git a/task/kn-apply/0.3/kn-apply.yaml b/task/kn-apply/0.3/kn-apply.yaml index e486004d1e..b58894dbb5 100644 --- a/task/kn-apply/0.3/kn-apply.yaml +++ b/task/kn-apply/0.3/kn-apply.yaml @@ -1,12 +1,12 @@ -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: Task metadata: name: kn-apply labels: - app.kubernetes.io/version: "0.2" + app.kubernetes.io/version: "0.3" annotations: tekton.dev/displayName: "kn apply" - tekton.dev/pipelines.minVersion: "0.12.1" + tekton.dev/pipelines.minVersion: "0.50.0" tekton.dev/categories: Deployment tekton.dev/tags: cli tekton.dev/platforms: "linux/amd64,linux/s390x,linux/ppc64le,linux/arm64" From 5f110d292c5e4ff373f0700ef6c17c2fe69fb9ed Mon Sep 17 00:00:00 2001 From: gferreir Date: Thu, 17 Sep 2026 10:57:13 -0300 Subject: [PATCH 05/19] chore(argocd-task-sync-and-wait): copy task from 0.2 to 0.3 Signed-off-by: gferreir --- task/argocd-task-sync-and-wait/0.3/README.md | 77 +++++++++++++++++++ .../0.3/argocd-task-sync-and-wait.yaml | 48 ++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 task/argocd-task-sync-and-wait/0.3/README.md create mode 100644 task/argocd-task-sync-and-wait/0.3/argocd-task-sync-and-wait.yaml diff --git a/task/argocd-task-sync-and-wait/0.3/README.md b/task/argocd-task-sync-and-wait/0.3/README.md new file mode 100644 index 0000000000..81678dcc6e --- /dev/null +++ b/task/argocd-task-sync-and-wait/0.3/README.md @@ -0,0 +1,77 @@ +# Argo CD + +This task syncs (deploys) an [Argo CD](https://argoproj.github.io/argo-cd/) application and waits for it to be healthy. To do so, it requires the address of the Argo CD server and some form of authentication - either a username/password or an authentication token. + +## Install the Task + +``` +kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/argocd-task-sync-and-wait/0.2/argocd-task-sync-and-wait.yaml +``` + +## Parameters + +* **application-name:** Name of the application to sync + +* **revision:** The revision to sync to (_default:_ `HEAD`) + +* **flags:** Flags to append after commands, e.g. `--insecure` (_default:_ `--`) + +## Platforms + +The Task can be run on `linux/amd64` platform. + +## Usage + +This `Pipeline` implements the typical CD flow using GitOps, as explained [here](https://argoproj.github.io/argo-cd/user-guide/ci_automation/). It runs a sample `Task` that makes and pushes a change to a Git repository, after which it runs the Argo CD `Task` to sync an application based on that repository. + +The `ConfigMap` and `Secret` give an example of how to define the Argo CD server address and give credentials for logging in. + +```YAML +apiVersion: v1 +kind: ConfigMap +metadata: + name: argocd-env-configmap +data: + ARGOCD_SERVER: +--- +apiVersion: v1 +kind: Secret +metadata: + name: argocd-env-secret +data: + # choose one of username/password or auth token + ARGOCD_USERNAME: + ARGOCD_PASSWORD: + ARGOCD_AUTH_TOKEN: +--- +apiVersion: tekton.dev/v1beta1 +kind: Pipeline +metadata: + name: argocd-pipeline +spec: + tasks: + - name: push-to-git + taskRef: + name: some-git-task # pushes to the Git repository used by the application in the next task + - name: sync-application + taskRef: + name: argocd-task-sync-and-wait + params: + - name: application-name + value: some-application + - name: flags + value: --insecure # needed in this example only because the Argo CD server is locally hosted +``` + +For the `Secret`, choose one of username/password or auth token for logging in. Either of the following are acceptable: + +```YAML +data: + ARGOCD_USERNAME: + ARGOCD_PASSWORD: +``` + +```YAML +data: + ARGOCD_AUTH_TOKEN: +``` diff --git a/task/argocd-task-sync-and-wait/0.3/argocd-task-sync-and-wait.yaml b/task/argocd-task-sync-and-wait/0.3/argocd-task-sync-and-wait.yaml new file mode 100644 index 0000000000..b140b2fb66 --- /dev/null +++ b/task/argocd-task-sync-and-wait/0.3/argocd-task-sync-and-wait.yaml @@ -0,0 +1,48 @@ +apiVersion: tekton.dev/v1beta1 +kind: Task +metadata: + name: argocd-task-sync-and-wait + labels: + app.kubernetes.io/version: "0.2" + annotations: + tekton.dev/pipelines.minVersion: "0.12.1" + tekton.dev/categories: Deployment + tekton.dev/tags: deploy + tekton.dev/displayName: "argocd" + tekton.dev/platforms: "linux/amd64" +spec: + description: >- + This task syncs (deploys) an Argo CD application and waits for it to be healthy. + + To do so, it requires the address of the Argo CD server and some form of + authentication either a username/password or an authentication token. + + params: + - name: application-name + description: name of the application to sync + type: string + - name: revision + description: the revision to sync to + default: HEAD + type: string + - name: flags + default: -- + type: string + - name: argocd-version + default: v2.2.2 + type: string + stepTemplate: + envFrom: + - configMapRef: + name: argocd-env-configmap # used for server address + - secretRef: + name: argocd-env-secret # used for authentication (username/password or auth token) + steps: + - name: login + image: quay.io/argoproj/argocd:$(params.argocd-version) + script: | + if [ -z "$ARGOCD_AUTH_TOKEN" ]; then + yes | argocd login "$ARGOCD_SERVER" --username="$ARGOCD_USERNAME" --password="$ARGOCD_PASSWORD"; + fi + argocd app sync "$(params.application-name)" --revision "$(params.revision)" "$(params.flags)" + argocd app wait "$(params.application-name)" --health "$(params.flags)" From c1d248d1c0ee3ceabef9b07b7887af441891779c Mon Sep 17 00:00:00 2001 From: gferreir Date: Thu, 17 Sep 2026 10:57:13 -0300 Subject: [PATCH 06/19] chore(argocd-task-sync-and-wait): bump apiVersion to tekton.dev/v1 Ref: tektoncd/catalog#1381 Signed-off-by: gferreir --- task/argocd-task-sync-and-wait/0.3/README.md | 4 ++-- .../0.3/argocd-task-sync-and-wait.yaml | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/task/argocd-task-sync-and-wait/0.3/README.md b/task/argocd-task-sync-and-wait/0.3/README.md index 81678dcc6e..e897429b51 100644 --- a/task/argocd-task-sync-and-wait/0.3/README.md +++ b/task/argocd-task-sync-and-wait/0.3/README.md @@ -5,7 +5,7 @@ This task syncs (deploys) an [Argo CD](https://argoproj.github.io/argo-cd/) appl ## Install the Task ``` -kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/argocd-task-sync-and-wait/0.2/argocd-task-sync-and-wait.yaml +kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/argocd-task-sync-and-wait/0.3/argocd-task-sync-and-wait.yaml ``` ## Parameters @@ -44,7 +44,7 @@ data: ARGOCD_PASSWORD: ARGOCD_AUTH_TOKEN: --- -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: Pipeline metadata: name: argocd-pipeline diff --git a/task/argocd-task-sync-and-wait/0.3/argocd-task-sync-and-wait.yaml b/task/argocd-task-sync-and-wait/0.3/argocd-task-sync-and-wait.yaml index b140b2fb66..8486ddaeb5 100644 --- a/task/argocd-task-sync-and-wait/0.3/argocd-task-sync-and-wait.yaml +++ b/task/argocd-task-sync-and-wait/0.3/argocd-task-sync-and-wait.yaml @@ -1,11 +1,11 @@ -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: Task metadata: name: argocd-task-sync-and-wait labels: - app.kubernetes.io/version: "0.2" + app.kubernetes.io/version: "0.3" annotations: - tekton.dev/pipelines.minVersion: "0.12.1" + tekton.dev/pipelines.minVersion: "0.50.0" tekton.dev/categories: Deployment tekton.dev/tags: deploy tekton.dev/displayName: "argocd" From 42bb894383e73a36e7cb5e2d381f0e84c93e471b Mon Sep 17 00:00:00 2001 From: gferreir Date: Thu, 17 Sep 2026 10:57:13 -0300 Subject: [PATCH 07/19] chore(argocd-task-connect-repo): copy task from 0.1 to 0.2 Signed-off-by: gferreir --- task/argocd-task-connect-repo/0.2/README.md | 77 +++++++++++++++++++ .../0.2/argocd-task-connect-repo.yaml | 54 +++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 task/argocd-task-connect-repo/0.2/README.md create mode 100644 task/argocd-task-connect-repo/0.2/argocd-task-connect-repo.yaml diff --git a/task/argocd-task-connect-repo/0.2/README.md b/task/argocd-task-connect-repo/0.2/README.md new file mode 100644 index 0000000000..f7746b58f5 --- /dev/null +++ b/task/argocd-task-connect-repo/0.2/README.md @@ -0,0 +1,77 @@ +# ArgoCD + + This task connects a repository to Argo CD. To do so, it requires the address of the Argo CD server and some form of authentication either a username/password or an authentication token, as well as the desired repo. + +## Install the Task + +``` +kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/argocd-task-connect-repo/0.1/argocd-task-connect-repo.yaml +``` + +## Parameters + +* **repository-url:** Name of the application to sync e.g. `https://charts.bitnami.com/bitnami` + +* **repository-name:** The name you want to give to the repo, e.g. `bitnami` + +* **flags:** Flags to append after commands, e.g. `--insecure` (_default:_ `--`) + +## Platforms + +The Task can be run on `linux/amd64` platform. + +## Usage + +``` +apiVersion: v1 +kind: ConfigMap +metadata: + name: argocd-env-configmap + namespace: argocd +data: + ARGOCD_SERVER: +--- +apiVersion: v1 +kind: Secret +metadata: + name: argocd-env-secret + namespace: argocd +data: + # choose one of username/password or auth token + ARGOCD_USERNAME: + ARGOCD_PASSWORD: + ARGOCD_AUTH_TOKEN: +--- +apiVersion: tekton.dev/v1beta1 +kind: Pipeline +metadata: + name: argocd-pipeline-test + namespace: argocd +spec: + tasks: + - name: connect-repo + taskRef: + name: argocd-task-connect-repo + params: + - name: repository-url + value: https://charts.bitnami.com/bitnami + - name: repository-type + value: helm + - name: repository-name + value: concourse + - name: flags + value: --insecure +``` + +For the `Secret`, choose one of username/password or auth token for logging in. Either of the following are acceptable: + +```YAML +data: + ARGOCD_USERNAME: + ARGOCD_PASSWORD: +``` + +```YAML +data: + ARGOCD_AUTH_TOKEN: +``` \ No newline at end of file diff --git a/task/argocd-task-connect-repo/0.2/argocd-task-connect-repo.yaml b/task/argocd-task-connect-repo/0.2/argocd-task-connect-repo.yaml new file mode 100644 index 0000000000..8625d3bf4f --- /dev/null +++ b/task/argocd-task-connect-repo/0.2/argocd-task-connect-repo.yaml @@ -0,0 +1,54 @@ +apiVersion: tekton.dev/v1beta1 +kind: Task +metadata: + name: argocd-task-connect-repo + namespace: argocd + labels: + app.kubernetes.io/version: "0.1" + annotations: + tekton.dev/pipelines.minVersion: "0.12.1" + tekton.dev/categories: Deployment + tekton.dev/tags: generic + tekton.dev/displayName: "argocd-repository" + tekton.dev/platforms: "linux/amd64" +spec: + description: >- + This task adds an http repo in Argo CD. + + To do so, it requires the address of the Argo CD server and some form of + authentication either a username/password or an authentication token, + as well as the desired repository to connect to. + params: + - name: repository-url + description: url of the repository you want to add + type: string + - name: repository-type + description: repository type (helm or git) + type: string + - name: repository-name + description: name you want to give to the repository + type: string + - name: flags + default: -- + type: string + - name: argocd-version + default: v2.3.4 + type: string + stepTemplate: + envFrom: + - configMapRef: + name: argocd-env-configmap # used for server address + - secretRef: + name: argocd-env-secret # used for authentication (username/password or auth token) + steps: + - name: connect-repo + image: quay.io/argoproj/argocd:$(params.argocd-version) + script: | + if [ -z "$ARGOCD_AUTH_TOKEN" ]; then + yes | argocd login "$ARGOCD_SERVER" --username="$ARGOCD_USERNAME" --password="$ARGOCD_PASSWORD" --insecure; + fi + if [ "$(params.repository-type)" != "helm" ]; then + argocd repo add "$(params.repository-url)" "$(params.flags)"; + else + argocd repo add "$(params.repository-url)" --type helm --name "$(params.repository-name)" "$(params.flags)"; + fi From 556b590f0f0e7f1cfb584ad2b8a5b71ac43c3cdc Mon Sep 17 00:00:00 2001 From: gferreir Date: Thu, 17 Sep 2026 10:57:13 -0300 Subject: [PATCH 08/19] chore(argocd-task-connect-repo): bump apiVersion to tekton.dev/v1 Ref: tektoncd/catalog#1381 Signed-off-by: gferreir --- task/argocd-task-connect-repo/0.2/README.md | 4 ++-- .../0.2/argocd-task-connect-repo.yaml | 7 +++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/task/argocd-task-connect-repo/0.2/README.md b/task/argocd-task-connect-repo/0.2/README.md index f7746b58f5..e4f695a2ed 100644 --- a/task/argocd-task-connect-repo/0.2/README.md +++ b/task/argocd-task-connect-repo/0.2/README.md @@ -5,7 +5,7 @@ ## Install the Task ``` -kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/argocd-task-connect-repo/0.1/argocd-task-connect-repo.yaml +kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/argocd-task-connect-repo/0.2/argocd-task-connect-repo.yaml ``` ## Parameters @@ -42,7 +42,7 @@ data: ARGOCD_PASSWORD: ARGOCD_AUTH_TOKEN: --- -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: Pipeline metadata: name: argocd-pipeline-test diff --git a/task/argocd-task-connect-repo/0.2/argocd-task-connect-repo.yaml b/task/argocd-task-connect-repo/0.2/argocd-task-connect-repo.yaml index 8625d3bf4f..07cb554f00 100644 --- a/task/argocd-task-connect-repo/0.2/argocd-task-connect-repo.yaml +++ b/task/argocd-task-connect-repo/0.2/argocd-task-connect-repo.yaml @@ -1,12 +1,11 @@ -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: Task metadata: name: argocd-task-connect-repo - namespace: argocd labels: - app.kubernetes.io/version: "0.1" + app.kubernetes.io/version: "0.2" annotations: - tekton.dev/pipelines.minVersion: "0.12.1" + tekton.dev/pipelines.minVersion: "0.50.0" tekton.dev/categories: Deployment tekton.dev/tags: generic tekton.dev/displayName: "argocd-repository" From f807ea1bb7b7eaae4c268cbbf27fac48084c3002 Mon Sep 17 00:00:00 2001 From: gferreir Date: Thu, 17 Sep 2026 10:57:13 -0300 Subject: [PATCH 09/19] chore(blue-green-deploy): copy task from 0.2 to 0.3 Signed-off-by: gferreir --- task/blue-green-deploy/0.3/README.md | 89 ++++++++++ .../0.3/blue-green-deploy.yaml | 153 ++++++++++++++++++ task/blue-green-deploy/0.3/samples/run.yaml | 16 ++ .../samples/v1-deploy/blue-deployment.yaml | 23 +++ .../0.3/samples/v1-deploy/service.yaml | 14 ++ .../samples/v2-deploy/green-deployment.yaml | 23 +++ .../0.3/support/clusterrolebinding.yaml | 12 ++ .../0.3/tests/pre-apply-task-hook.sh | 46 ++++++ .../0.3/tests/resources.yaml | 37 +++++ task/blue-green-deploy/0.3/tests/run.yaml | 17 ++ 10 files changed, 430 insertions(+) create mode 100644 task/blue-green-deploy/0.3/README.md create mode 100644 task/blue-green-deploy/0.3/blue-green-deploy.yaml create mode 100644 task/blue-green-deploy/0.3/samples/run.yaml create mode 100644 task/blue-green-deploy/0.3/samples/v1-deploy/blue-deployment.yaml create mode 100644 task/blue-green-deploy/0.3/samples/v1-deploy/service.yaml create mode 100644 task/blue-green-deploy/0.3/samples/v2-deploy/green-deployment.yaml create mode 100644 task/blue-green-deploy/0.3/support/clusterrolebinding.yaml create mode 100644 task/blue-green-deploy/0.3/tests/pre-apply-task-hook.sh create mode 100644 task/blue-green-deploy/0.3/tests/resources.yaml create mode 100644 task/blue-green-deploy/0.3/tests/run.yaml diff --git a/task/blue-green-deploy/0.3/README.md b/task/blue-green-deploy/0.3/README.md new file mode 100644 index 0000000000..3784b00be5 --- /dev/null +++ b/task/blue-green-deploy/0.3/README.md @@ -0,0 +1,89 @@ +# Blue Green Deploy on Kubernetes + +The following task can help you to deploy an application using the Blue-Green deployment strategy. This task gives you the flexibility to deploy a version of the application from the blue zone to the green zone without disturbing the previous version in the blue zone. It works by making the service point to the newer version of the application deployed. + +- If you are deploying the first version of the application then it will go into the blue zone and for that you need to provide deployment and service manifests via the `workspaces` and in the `params` the service name and version. Sample Kubernetes manifests for version v1 can be found [here](./samples/v1-deploy). +- For further new deployments, it will get deployed in the other zone and then the current service will now point to the new deployment. For example if we have a deployment running in the blue zone then we will deploy the next deployment in the green zone and make the service point to the green zone or vice versa. + +## Installing the Task + +``` +kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/blue-green-deploy/0.2/blue-green-deploy.yaml +``` + +## Installing the ClusterRoleBinding + +``` +kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/blue-green-deploy/0.2/support/clusterrolebinding.yaml +``` + +## Optional Workspaces + +- **manifest-dir**: Manifest files can be provided via the workspaces +- **kubeconfig-dir**: If you want to deploy you application to another cluster then you can mount your `kubeconfig` file via this `workspace` + +## Parameters + +- **SERVICE_NAME**: The service name pointing to the existing deployment. (_Note_: The service name for the new deployment should be same) +- **NEW_VERSION**: The version of the deployment to be deployed in the green/blue zone +- **MANIFEST**: The deployment manifest URL file path provided in case the manifest is present on Github. (_Example_: "https://raw.githubusercontent.com/tektoncd/catalog/main/task/blue-green-deploy/0.2/samples/v1-deploy/blue-deployment.yaml") +- **NAMESPACE**: Target namespace in which operation needs to be performed +- **IMAGE**: Image which has kubectl binary present (_Default_: `quay.io/openshift/origin-cli:4.9`) + +## Platforms + +The Task can be run on `linux/amd64` platform. + +# Usage + +This TaskRun runs the Task to deploy the given Kubernetes resource in the green/blue zone and toggle the service to point to the new zone. + +## Without using ConfigMap + +TaskRun :- + +```yaml +apiVersion: tekton.dev/v1beta1 +kind: TaskRun +metadata: + name: blue-green-deploy-run +spec: + taskRef: + name: blue-green-deploy-k8s + params: + - name: SERVICE_NAME + value: myapp + - name: NEW_VERSION + value: v2 + - name: MANIFEST + value: "https://raw.githubusercontent.com/tektoncd/catalog/main/task/blue-green-deploy/0.2/samples/v2-deploy/green-deployment.yaml" +``` + +## Using ConfigMap + +1. Create the `ConfigMap` + +```bash +kubectl create configmap manifests --from-file="green-deployment.yaml" +``` + +2. TaskRun:- + +```yaml +apiVersion: tekton.dev/v1beta1 +kind: TaskRun +metadata: + name: blue-green-deploy-run +spec: + taskRef: + name: blue-green-deploy-k8s + params: + - name: SERVICE_NAME + value: myapp + - name: NEW_VERSION + value: v2 + workspaces: + - name: manifest-dir + configMap: + name: manifests +``` diff --git a/task/blue-green-deploy/0.3/blue-green-deploy.yaml b/task/blue-green-deploy/0.3/blue-green-deploy.yaml new file mode 100644 index 0000000000..0b9b825973 --- /dev/null +++ b/task/blue-green-deploy/0.3/blue-green-deploy.yaml @@ -0,0 +1,153 @@ +apiVersion: tekton.dev/v1beta1 +kind: Task +metadata: + name: blue-green-deploy + labels: + app.kubernetes.io/version: "0.2" + annotations: + tekton.dev/pipelines.minVersion: "0.17.0" + tekton.dev/categories: Deployment + tekton.dev/tags: deployment + tekton.dev/displayName: "blue green deployment" + tekton.dev/platforms: "linux/amd64" +spec: + description: >- + This task can be used to do Blue-Green deployment + workspaces: + - name: manifest-dir + description: Consisting of kubernetes manifests + optional: true + - name: kubeconfig-dir + description: Can be used in case kubeconfig file is mounted + optional: true + params: + - name: SERVICE_NAME + type: string + description: Name of the service which is pointing to existing deployment + - name: NEW_VERSION + type: string + description: The version of newer deployment which is to be patched to existing service + - name: MANIFEST + type: string + default: "." + description: The newer version of the deployment to be deployed in another zone + - name: NAMESPACE + type: string + description: Target namespace in which operation needs to be performed + - name: IMAGE + description: Image which has kubectl binary present + type: string + default: "quay.io/openshift/origin-cli:4.9" + steps: + - name: change-deployment + image: $(params.IMAGE) + script: | + #!/usr/bin/env bash + set -u -o pipefail + + [[ "$(workspaces.manifest-dir.bound)" == "true" ]] && cd $(workspaces.manifest-dir.path) + + if [[ "$(workspaces.kubeconfig-dir.bound)" == "true" ]] && [[ -f $(workspaces.kubeconfig-dir.path)/kubeconfig ]]; then + export KUBECONFIG=$(workspaces.kubeconfig-dir.path)/kubeconfig + fi + + getReasons() { + local deploy_name=$1 + kubectl -n $(params.NAMESPACE) get deploy "$deploy_name" \ + -o jsonpath='{range .status.conditions[*]}{.reason}{"\n"}{end}' + } + + # Getting the status at particular index + getStatusAtIndex() { + local deploy_name=$1 + local index=$2 + kubectl -n $(params.NAMESPACE) get deploy "$deploy_name" \ + -o jsonpath='{range .status.conditions['$index']}{.status}{"\n"}{end}' + } + + # Checking for unavailable pods in case the deployment is + # patched with a newer image + checkUnavailableReplicas() { + local deploy_name=$1 + local replicasUnavailable=$(kubectl -n $(params.NAMESPACE) get deploy "$deploy_name" -o jsonpath='{.status.unavailableReplicas}') + [[ "$replicasUnavailable" == "" ]] && return 0 || return 1 + } + + getMinimumReplicaStatus() { + local deploy_name=$1 + local INDEX=0 + for reason in $(getReasons $deploy_name); do + if [[ "$reason" == "MinimumReplicasAvailable" ]]; then + local ready=$(getStatusAtIndex $deploy_name ${INDEX}) + [[ "$ready" != "True" ]] && return 1 || return 0 + fi + ((INDEX++)) + done + return 1 + } + + checkProgressDeadline() { + local deploy_name=$1 + local INDEX=0 + for reason in $(getReasons $deploy_name); do + if [[ "$reason" == "ProgressDeadlineExceeded" ]]; then + local status=$(getStatusAtIndex $deploy_name ${INDEX}) + [[ "$status" == "True" ]] && return 0 || return 1 + fi + ((INDEX++)) + done + return 1 + } + + switchService() { + kubectl -n $(params.NAMESPACE) patch svc ${service} \ + -p "{\"spec\":{\"selector\": {\"app\": \"${service}\", \"version\": \"${version}\"}}}" + } + + main() { + local deploy_name=$(params.SERVICE_NAME)-$(params.NEW_VERSION) + local service=$(params.SERVICE_NAME) + local version=$(params.NEW_VERSION) + + kubectl -n $(params.NAMESPACE) apply -f $(params.MANIFEST) + + # Wait until the Deployment is ready by checking the + # MinimumReplicasAvailable condition. + # Also checking for the ProgressDeadlineExceeded + # condition + while true; do + getMinimumReplicaStatus ${deploy_name} + [[ $? -eq 0 ]] && break + checkProgressDeadline ${deploy_name} + [[ $? -eq 0 ]] && break + sleep 5 + done + # If ProgressDeadlineExceeded then break from the main + # and avoid checking for the next condition + checkProgressDeadline ${deploy_name} + if [[ $? -eq 0 ]]; then + echo "Failed to change the service" && break + fi + # If MinimumReplicas are available then check + # for the unavailable Pods + # Also checking for the ProgressDeadlineExceeded condition + while true; do + checkUnavailableReplicas ${deploy_name} + [[ $? -eq 0 ]] && break + checkProgressDeadline ${deploy_name} + [[ $? -eq 0 ]] && break + sleep 5 + done + + # Update the service selector with the new version + # if ProgressDeadline not exceeded + checkProgressDeadline ${deploy_name} + if [[ $? -eq 0 ]]; then + echo "Failed to change the service" + else + switchService ${service} ${version} + [[ $? -eq 0 ]] && echo "Done." || exit 1 + fi + } + + main "$@" diff --git a/task/blue-green-deploy/0.3/samples/run.yaml b/task/blue-green-deploy/0.3/samples/run.yaml new file mode 100644 index 0000000000..8d1809082e --- /dev/null +++ b/task/blue-green-deploy/0.3/samples/run.yaml @@ -0,0 +1,16 @@ +apiVersion: tekton.dev/v1beta1 +kind: TaskRun +metadata: + name: blue-green-deploy-run +spec: + taskRef: + name: blue-green-deploy + params: + - name: SERVICE_NAME + value: myapp + - name: NEW_VERSION + value: v2 + - name: MANIFEST + value: "https://raw.githubusercontent.com/vinamra28/blue-green-deployment-k8s/master/deployment%2Bservice/green-deployment.yaml" + - name: NAMESPACE + value: default diff --git a/task/blue-green-deploy/0.3/samples/v1-deploy/blue-deployment.yaml b/task/blue-green-deploy/0.3/samples/v1-deploy/blue-deployment.yaml new file mode 100644 index 0000000000..e6963ed546 --- /dev/null +++ b/task/blue-green-deploy/0.3/samples/v1-deploy/blue-deployment.yaml @@ -0,0 +1,23 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myapp-v1 +spec: + replicas: 1 + selector: + matchLabels: + app: myapp + version: v1 + template: + metadata: + labels: + app: "myapp" + version: "v1" + spec: + containers: + - name: myapp + image: quay.io/vinamra2807/social-client:v1 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 3000 + name: http diff --git a/task/blue-green-deploy/0.3/samples/v1-deploy/service.yaml b/task/blue-green-deploy/0.3/samples/v1-deploy/service.yaml new file mode 100644 index 0000000000..1b01e8cfbe --- /dev/null +++ b/task/blue-green-deploy/0.3/samples/v1-deploy/service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: myapp + labels: + app: myapp +spec: + type: NodePort + ports: + - port: 3000 + name: http + selector: + app: myapp + version: v1 diff --git a/task/blue-green-deploy/0.3/samples/v2-deploy/green-deployment.yaml b/task/blue-green-deploy/0.3/samples/v2-deploy/green-deployment.yaml new file mode 100644 index 0000000000..a11cbc3602 --- /dev/null +++ b/task/blue-green-deploy/0.3/samples/v2-deploy/green-deployment.yaml @@ -0,0 +1,23 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myapp-v2 +spec: + replicas: 1 + selector: + matchLabels: + app: myapp + version: v2 + template: + metadata: + labels: + app: "myapp" + version: "v2" + spec: + containers: + - name: myapp + image: quay.io/vinamra2807/social-client:v2 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 3000 + name: http diff --git a/task/blue-green-deploy/0.3/support/clusterrolebinding.yaml b/task/blue-green-deploy/0.3/support/clusterrolebinding.yaml new file mode 100644 index 0000000000..2d087b5074 --- /dev/null +++ b/task/blue-green-deploy/0.3/support/clusterrolebinding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: default-blue-green +subjects: + - kind: ServiceAccount + name: default + namespace: default +roleRef: + kind: ClusterRole + name: cluster-admin + apiGroup: rbac.authorization.k8s.io diff --git a/task/blue-green-deploy/0.3/tests/pre-apply-task-hook.sh b/task/blue-green-deploy/0.3/tests/pre-apply-task-hook.sh new file mode 100644 index 0000000000..ef87180767 --- /dev/null +++ b/task/blue-green-deploy/0.3/tests/pre-apply-task-hook.sh @@ -0,0 +1,46 @@ +#!/bin/bash +#This will create a sample deployment version v1 of the application and a service which will point to that deployment + +cat < Date: Thu, 17 Sep 2026 10:57:13 -0300 Subject: [PATCH 10/19] chore(blue-green-deploy): bump apiVersion to tekton.dev/v1 Ref: tektoncd/catalog#1381 Signed-off-by: gferreir --- task/blue-green-deploy/0.3/README.md | 12 ++++++------ task/blue-green-deploy/0.3/blue-green-deploy.yaml | 6 +++--- task/blue-green-deploy/0.3/samples/run.yaml | 2 +- task/blue-green-deploy/0.3/tests/resources.yaml | 4 ++-- task/blue-green-deploy/0.3/tests/run.yaml | 4 ++-- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/task/blue-green-deploy/0.3/README.md b/task/blue-green-deploy/0.3/README.md index 3784b00be5..543e58127e 100644 --- a/task/blue-green-deploy/0.3/README.md +++ b/task/blue-green-deploy/0.3/README.md @@ -8,13 +8,13 @@ The following task can help you to deploy an application using the Blue-Green de ## Installing the Task ``` -kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/blue-green-deploy/0.2/blue-green-deploy.yaml +kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/blue-green-deploy/0.3/blue-green-deploy.yaml ``` ## Installing the ClusterRoleBinding ``` -kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/blue-green-deploy/0.2/support/clusterrolebinding.yaml +kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/blue-green-deploy/0.3/support/clusterrolebinding.yaml ``` ## Optional Workspaces @@ -26,7 +26,7 @@ kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/bl - **SERVICE_NAME**: The service name pointing to the existing deployment. (_Note_: The service name for the new deployment should be same) - **NEW_VERSION**: The version of the deployment to be deployed in the green/blue zone -- **MANIFEST**: The deployment manifest URL file path provided in case the manifest is present on Github. (_Example_: "https://raw.githubusercontent.com/tektoncd/catalog/main/task/blue-green-deploy/0.2/samples/v1-deploy/blue-deployment.yaml") +- **MANIFEST**: The deployment manifest URL file path provided in case the manifest is present on Github. (_Example_: "https://raw.githubusercontent.com/tektoncd/catalog/main/task/blue-green-deploy/0.3/samples/v1-deploy/blue-deployment.yaml") - **NAMESPACE**: Target namespace in which operation needs to be performed - **IMAGE**: Image which has kubectl binary present (_Default_: `quay.io/openshift/origin-cli:4.9`) @@ -43,7 +43,7 @@ This TaskRun runs the Task to deploy the given Kubernetes resource in the green/ TaskRun :- ```yaml -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: TaskRun metadata: name: blue-green-deploy-run @@ -56,7 +56,7 @@ spec: - name: NEW_VERSION value: v2 - name: MANIFEST - value: "https://raw.githubusercontent.com/tektoncd/catalog/main/task/blue-green-deploy/0.2/samples/v2-deploy/green-deployment.yaml" + value: "https://raw.githubusercontent.com/tektoncd/catalog/main/task/blue-green-deploy/0.3/samples/v2-deploy/green-deployment.yaml" ``` ## Using ConfigMap @@ -70,7 +70,7 @@ kubectl create configmap manifests --from-file="green-deployment.yaml" 2. TaskRun:- ```yaml -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: TaskRun metadata: name: blue-green-deploy-run diff --git a/task/blue-green-deploy/0.3/blue-green-deploy.yaml b/task/blue-green-deploy/0.3/blue-green-deploy.yaml index 0b9b825973..5790a66fcc 100644 --- a/task/blue-green-deploy/0.3/blue-green-deploy.yaml +++ b/task/blue-green-deploy/0.3/blue-green-deploy.yaml @@ -1,11 +1,11 @@ -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: Task metadata: name: blue-green-deploy labels: - app.kubernetes.io/version: "0.2" + app.kubernetes.io/version: "0.3" annotations: - tekton.dev/pipelines.minVersion: "0.17.0" + tekton.dev/pipelines.minVersion: "0.50.0" tekton.dev/categories: Deployment tekton.dev/tags: deployment tekton.dev/displayName: "blue green deployment" diff --git a/task/blue-green-deploy/0.3/samples/run.yaml b/task/blue-green-deploy/0.3/samples/run.yaml index 8d1809082e..af9ca4aaef 100644 --- a/task/blue-green-deploy/0.3/samples/run.yaml +++ b/task/blue-green-deploy/0.3/samples/run.yaml @@ -1,4 +1,4 @@ -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: TaskRun metadata: name: blue-green-deploy-run diff --git a/task/blue-green-deploy/0.3/tests/resources.yaml b/task/blue-green-deploy/0.3/tests/resources.yaml index 7ef6015306..efa9d130d2 100644 --- a/task/blue-green-deploy/0.3/tests/resources.yaml +++ b/task/blue-green-deploy/0.3/tests/resources.yaml @@ -3,7 +3,7 @@ apiVersion: v1 kind: ServiceAccount metadata: name: blue-green-account - namespace: blue-green-deploy-0-2 + namespace: blue-green-deploy-0-3 --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 @@ -30,7 +30,7 @@ metadata: subjects: - kind: ServiceAccount name: blue-green-account - namespace: blue-green-deploy-0-2 + namespace: blue-green-deploy-0-3 roleRef: kind: ClusterRole name: blue-green-cluster-role diff --git a/task/blue-green-deploy/0.3/tests/run.yaml b/task/blue-green-deploy/0.3/tests/run.yaml index b9223a3e58..88c4517677 100644 --- a/task/blue-green-deploy/0.3/tests/run.yaml +++ b/task/blue-green-deploy/0.3/tests/run.yaml @@ -1,4 +1,4 @@ -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: TaskRun metadata: name: blue-green-deploy-run @@ -14,4 +14,4 @@ spec: - name: MANIFEST value: "https://raw.githubusercontent.com/vinamra28/blue-green-deployment-k8s/master/deployment%2Bservice/green-deployment.yaml" - name: NAMESPACE - value: blue-green-deploy-0-2 + value: blue-green-deploy-0-3 From 8333731f797a80eaa2c0e5f2a749c499aca2a2ad Mon Sep 17 00:00:00 2001 From: gferreir Date: Thu, 17 Sep 2026 10:57:14 -0300 Subject: [PATCH 11/19] chore(helm-upgrade-from-source): copy task from 0.4 to 0.5 Signed-off-by: gferreir --- task/helm-upgrade-from-source/0.5/README.md | 65 +++++++++++++++++++ .../0.5/helm-upgrade-from-source.yaml | 52 +++++++++++++++ ...elm-upgrade-from-source-task-run.yaml.tmpl | 20 ++++++ .../0.5/tests/pre-apply-task-hook.sh | 10 +++ .../0.5/tests/resources.yaml | 11 ++++ .../0.5/tests/run.yaml | 54 +++++++++++++++ 6 files changed, 212 insertions(+) create mode 100644 task/helm-upgrade-from-source/0.5/README.md create mode 100644 task/helm-upgrade-from-source/0.5/helm-upgrade-from-source.yaml create mode 100644 task/helm-upgrade-from-source/0.5/samples/helm-upgrade-from-source-task-run.yaml.tmpl create mode 100755 task/helm-upgrade-from-source/0.5/tests/pre-apply-task-hook.sh create mode 100644 task/helm-upgrade-from-source/0.5/tests/resources.yaml create mode 100644 task/helm-upgrade-from-source/0.5/tests/run.yaml diff --git a/task/helm-upgrade-from-source/0.5/README.md b/task/helm-upgrade-from-source/0.5/README.md new file mode 100644 index 0000000000..3764f15b0b --- /dev/null +++ b/task/helm-upgrade-from-source/0.5/README.md @@ -0,0 +1,65 @@ +# Helm + +These tasks will install / upgrade a helm chart into your Kubernetes / OpenShift Cluster using [Helm](https://github.com/helm/helm). + +## Install the Task + +### helm install / upgrade from source code + +``` +kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/helm-upgrade-from-source/0.3/helm-upgrade-from-source.yaml +``` + +#### Parameters + +- **charts_dir**: The directory in the source repository where the installable chart should be found. +- **release_version**: The version of the release (*default: v1.0.0*) +- **release_name**: The name of the release (*default: helm-release*) +- **release_namespace**: The namespace in which the release is to be installed (*default: ""*) +- **overwrite_values**: The values to be overwritten (*default: ""*) +- **values_file**: The values file to be used, + assumes the values file is in the same dir as your charts_dir (*default: "values.yaml"*) +- **helm_image**: The helm image which should be used (*default: lachlanevenson/k8s-helm:v3.3.4*) +- **upgrade_extra_params**: Extra parameters passed for the helm upgrade command (*default: ""*) + +#### Workspaces + +* **source**: A [Workspace](https://github.com/tektoncd/pipeline/blob/main/docs/workspaces.md) containing the helm chart. + +#### Platforms + +The Task can be run on `linux/amd64`, `linux/s390x`, `linux/arm64` and `linux/ppc64le` platforms. + +## Usage + +### PipelineRun + +An example `Pipeline` with a `PipelineRun` can be found in the subdirectory `tests`. + +### TaskRun + +This `TaskRun` runs the task to retrieve a Git repo and then installs/updates the helm chart that is in the Git repo. + +```yaml +# example upgrade from source +apiVersion: tekton.dev/v1beta1 +kind: TaskRun +metadata: + name: example-helm-upgrade-from-source +spec: + taskRef: + name: helm-upgrade-from-source + params: + - name: charts_dir + value: helm-sample-chart + - name: releases_version + value: v1.0.0 + - name: release_name + value: helm-source-sample + - name: overwrite_values + value: "autoscaling.enabled=true,autoscaling.maxReplicas=3" + workspaces: + - name: source + persistentVolumeClaim: + claimName: my-source +``` \ No newline at end of file diff --git a/task/helm-upgrade-from-source/0.5/helm-upgrade-from-source.yaml b/task/helm-upgrade-from-source/0.5/helm-upgrade-from-source.yaml new file mode 100644 index 0000000000..ec1647054f --- /dev/null +++ b/task/helm-upgrade-from-source/0.5/helm-upgrade-from-source.yaml @@ -0,0 +1,52 @@ +apiVersion: tekton.dev/v1beta1 +kind: Task +metadata: + name: helm-upgrade-from-source + labels: + app.kubernetes.io/version: "0.4" + annotations: + tekton.dev/pipelines.minVersion: "0.12.1" + tekton.dev/categories: Deployment + tekton.dev/tags: helm + tekton.dev/platforms: "linux/amd64,linux/s390x,linux/ppc64le,linux/arm64" +spec: + description: >- + These tasks will install / upgrade a helm chart into your Kubernetes / + OpenShift Cluster using Helm + + params: + - name: charts_dir + description: The directory in source that contains the helm chart + - name: release_version + description: The helm release version in semantic versioning format + default: "v1.0.0" + - name: release_name + description: The helm release name + default: "helm-release" + - name: release_namespace + description: The helm release namespace + default: "" + - name: overwrite_values + description: "Specify the values you want to overwrite, comma separated: autoscaling.enabled=true,replicas=1" + default: "" + - name: values_file + description: "The values file to be used" + default: "values.yaml" + - name: helm_image + description: "helm image to be used" + default: "docker.io/lachlanevenson/k8s-helm@sha256:0a068ae407e21d1836c6a89a1e9e81af1e55fa56890998e33d5caabdbb51e77b" # tag: v3.10.2 + - name: upgrade_extra_params + description: "Extra parameters passed for the helm upgrade command" + default: "" + workspaces: + - name: source + steps: + - name: upgrade + image: $(params.helm_image) + workingDir: /workspace/source + script: | + echo current installed helm releases + helm list --namespace "$(params.release_namespace)" + + echo installing helm chart... + helm upgrade --install --wait --values "$(params.charts_dir)/$(params.values_file)" --namespace "$(params.release_namespace)" --version "$(params.release_version)" "$(params.release_name)" "$(params.charts_dir)" --debug --set "$(params.overwrite_values)" $(params.upgrade_extra_params) diff --git a/task/helm-upgrade-from-source/0.5/samples/helm-upgrade-from-source-task-run.yaml.tmpl b/task/helm-upgrade-from-source/0.5/samples/helm-upgrade-from-source-task-run.yaml.tmpl new file mode 100644 index 0000000000..1af95701ed --- /dev/null +++ b/task/helm-upgrade-from-source/0.5/samples/helm-upgrade-from-source-task-run.yaml.tmpl @@ -0,0 +1,20 @@ +apiVersion: tekton.dev/v1beta1 +kind: TaskRun +metadata: + name: example-helm-upgrade-from-source +spec: + taskRef: + name: helm-upgrade-from-source + params: + - name: charts_dir + value: helm-sample-chart + - name: releases_version + value: v1.0.0 + - name: release_name + value: helm-source-sample + - name: overwrite_values + value: "autoscaling.enabled=true,autoscaling.maxReplicas=3" + workspaces: + - name: source + persistentVolumeClaim: + claimName: my-source \ No newline at end of file diff --git a/task/helm-upgrade-from-source/0.5/tests/pre-apply-task-hook.sh b/task/helm-upgrade-from-source/0.5/tests/pre-apply-task-hook.sh new file mode 100755 index 0000000000..69b7af1548 --- /dev/null +++ b/task/helm-upgrade-from-source/0.5/tests/pre-apply-task-hook.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +# Add git-clone +add_task git-clone latest + +# Add service account +kubectl -n ${tns} create serviceaccount helm-pipeline-run-sa + +# Add edit role to service account +kubectl -n ${tns} create rolebinding helm-pipeline-run-sa-edit --clusterrole edit --serviceaccount ${tns}:helm-pipeline-run-sa -o yaml --dry-run=client | kubectl apply -f - diff --git a/task/helm-upgrade-from-source/0.5/tests/resources.yaml b/task/helm-upgrade-from-source/0.5/tests/resources.yaml new file mode 100644 index 0000000000..5610684da6 --- /dev/null +++ b/task/helm-upgrade-from-source/0.5/tests/resources.yaml @@ -0,0 +1,11 @@ +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: helm-source-pvc +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 200Mi diff --git a/task/helm-upgrade-from-source/0.5/tests/run.yaml b/task/helm-upgrade-from-source/0.5/tests/run.yaml new file mode 100644 index 0000000000..8b5d03e994 --- /dev/null +++ b/task/helm-upgrade-from-source/0.5/tests/run.yaml @@ -0,0 +1,54 @@ +--- +apiVersion: tekton.dev/v1beta1 +kind: Pipeline +metadata: + name: helm-upgrade-test-pipeline +spec: + workspaces: + - name: shared-workspace + tasks: + - name: fetch-repository + taskRef: + name: git-clone + workspaces: + - name: output + workspace: shared-workspace + params: + - name: url + value: https://github.com/helm/examples + - name: subdirectory + value: "" + - name: deleteExisting + value: "true" + - name: helm-upgrade-from-source + taskRef: + name: helm-upgrade-from-source + runAfter: + - fetch-repository + workspaces: + - name: source + workspace: shared-workspace + params: + - name: charts_dir + value: charts/hello-world + - name: release_version + value: v1.0.0 + - name: release_name + value: helm-source-sample + - name: overwrite_values + value: "autoscaling.enabled=true,autoscaling.maxReplicas=3" + - name: upgrade_extra_params + value: "--force" +--- +apiVersion: tekton.dev/v1beta1 +kind: PipelineRun +metadata: + name: helm-upgrade-test-pipeline-run +spec: + serviceAccountName: helm-pipeline-run-sa + pipelineRef: + name: helm-upgrade-test-pipeline + workspaces: + - name: shared-workspace + persistentVolumeClaim: + claimName: helm-source-pvc \ No newline at end of file From 55a2b90b16ade333a316b118a699973436a394be Mon Sep 17 00:00:00 2001 From: gferreir Date: Thu, 17 Sep 2026 10:57:14 -0300 Subject: [PATCH 12/19] chore(helm-upgrade-from-source): bump apiVersion to tekton.dev/v1 Ref: tektoncd/catalog#1381 Signed-off-by: gferreir --- task/helm-upgrade-from-source/0.5/README.md | 4 ++-- .../0.5/helm-upgrade-from-source.yaml | 6 +++--- .../0.5/samples/helm-upgrade-from-source-task-run.yaml.tmpl | 2 +- task/helm-upgrade-from-source/0.5/tests/run.yaml | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/task/helm-upgrade-from-source/0.5/README.md b/task/helm-upgrade-from-source/0.5/README.md index 3764f15b0b..29330e0b05 100644 --- a/task/helm-upgrade-from-source/0.5/README.md +++ b/task/helm-upgrade-from-source/0.5/README.md @@ -7,7 +7,7 @@ These tasks will install / upgrade a helm chart into your Kubernetes / OpenShift ### helm install / upgrade from source code ``` -kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/helm-upgrade-from-source/0.3/helm-upgrade-from-source.yaml +kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/helm-upgrade-from-source/0.5/helm-upgrade-from-source.yaml ``` #### Parameters @@ -42,7 +42,7 @@ This `TaskRun` runs the task to retrieve a Git repo and then installs/updates th ```yaml # example upgrade from source -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: TaskRun metadata: name: example-helm-upgrade-from-source diff --git a/task/helm-upgrade-from-source/0.5/helm-upgrade-from-source.yaml b/task/helm-upgrade-from-source/0.5/helm-upgrade-from-source.yaml index ec1647054f..d4778acd2a 100644 --- a/task/helm-upgrade-from-source/0.5/helm-upgrade-from-source.yaml +++ b/task/helm-upgrade-from-source/0.5/helm-upgrade-from-source.yaml @@ -1,11 +1,11 @@ -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: Task metadata: name: helm-upgrade-from-source labels: - app.kubernetes.io/version: "0.4" + app.kubernetes.io/version: "0.5" annotations: - tekton.dev/pipelines.minVersion: "0.12.1" + tekton.dev/pipelines.minVersion: "0.50.0" tekton.dev/categories: Deployment tekton.dev/tags: helm tekton.dev/platforms: "linux/amd64,linux/s390x,linux/ppc64le,linux/arm64" diff --git a/task/helm-upgrade-from-source/0.5/samples/helm-upgrade-from-source-task-run.yaml.tmpl b/task/helm-upgrade-from-source/0.5/samples/helm-upgrade-from-source-task-run.yaml.tmpl index 1af95701ed..62fa4a7539 100644 --- a/task/helm-upgrade-from-source/0.5/samples/helm-upgrade-from-source-task-run.yaml.tmpl +++ b/task/helm-upgrade-from-source/0.5/samples/helm-upgrade-from-source-task-run.yaml.tmpl @@ -1,4 +1,4 @@ -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: TaskRun metadata: name: example-helm-upgrade-from-source diff --git a/task/helm-upgrade-from-source/0.5/tests/run.yaml b/task/helm-upgrade-from-source/0.5/tests/run.yaml index 8b5d03e994..d3ed76174c 100644 --- a/task/helm-upgrade-from-source/0.5/tests/run.yaml +++ b/task/helm-upgrade-from-source/0.5/tests/run.yaml @@ -1,5 +1,5 @@ --- -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: Pipeline metadata: name: helm-upgrade-test-pipeline @@ -40,7 +40,7 @@ spec: - name: upgrade_extra_params value: "--force" --- -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: PipelineRun metadata: name: helm-upgrade-test-pipeline-run From ea9425a663dd7cdeed2ab76cccd1bac6eab42844 Mon Sep 17 00:00:00 2001 From: gferreir Date: Thu, 17 Sep 2026 10:57:14 -0300 Subject: [PATCH 13/19] chore(kamel-run): copy task from 0.1 to 0.2 Signed-off-by: gferreir --- task/kamel-run/0.2/README.md | 52 ++++++ task/kamel-run/0.2/kamel-run.yaml | 58 +++++++ .../0.2/samples/run-external-build.yaml | 106 +++++++++++++ .../0.2/samples/run-operator-build.yaml | 50 ++++++ .../kamel-run/0.2/support/camel-k-tekton.yaml | 40 +++++ .../0.2/tests/pre-apply-task-hook.sh | 12 ++ task/kamel-run/0.2/tests/resources.yaml | 40 +++++ task/kamel-run/0.2/tests/run.yaml | 149 ++++++++++++++++++ 8 files changed, 507 insertions(+) create mode 100644 task/kamel-run/0.2/README.md create mode 100644 task/kamel-run/0.2/kamel-run.yaml create mode 100644 task/kamel-run/0.2/samples/run-external-build.yaml create mode 100644 task/kamel-run/0.2/samples/run-operator-build.yaml create mode 100644 task/kamel-run/0.2/support/camel-k-tekton.yaml create mode 100755 task/kamel-run/0.2/tests/pre-apply-task-hook.sh create mode 100644 task/kamel-run/0.2/tests/resources.yaml create mode 100644 task/kamel-run/0.2/tests/run.yaml diff --git a/task/kamel-run/0.2/README.md b/task/kamel-run/0.2/README.md new file mode 100644 index 0000000000..e3577a77e5 --- /dev/null +++ b/task/kamel-run/0.2/README.md @@ -0,0 +1,52 @@ +# Kamel run + +This Task creates and run a [Camel K](https://github.com/apache/camel-k) Integration. + +If you have installed Camel K operator, you can configure the `kamel-run` task the step to create the Integration that will be operated by Camel K. You can configure the parameter to delegate the build of your application to Camel K or do it as a part of previous pipelines steps. + +## Install the Task + +```shell +kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/kamel-run/0.1/kamel-run.yaml +``` + +## Parameters + +- **camel-k-image**: The name of the image containing the Kamel CLI (_default:_ docker.io/apache/camel-k:1.12.0). +- **filename**: the file containing the Integration source. +- **namespace**: the namespace where to run the Integration (_default:_ the task execution namespace). +- **container-image**: the container image to use for this Integration. Useful when you want to build your own container for the Integration (_default:_ empty, will trigger an Integration build). +- **wait**: wait for the Integration to run before finishing the task. Useful when you want to get the **integration-phase** result (_default:_ "false"). + +## Workspaces + +* **source**: A [Workspace](https://github.com/tektoncd/pipeline/blob/main/docs/workspaces.md) containing the Integration source to run. + +## Results + +- **integration-name**: the Integration name which was created/updated. +- **integration-phase**: the status of the Integration, tipycally used with **wait: true** input parameter. + +## Platforms + +The Task can be run on `linux/amd64` platform. + +## Usage + +The Task can be used in several ways to accomodate the different build and deployment strategy you may have. + +### Create the Service Account + +As we will do delegate the task, the creation of an Integration, we need to provide a `ServiceAccount` with the privileges required by the tasks: + +```shell +kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/kamel-run/0.1/support/camel-k-tekton.yaml +``` + +### Delegate build to operator + +Use the [Tekton Camel K operator builder sample](../0.1/samples/run-operator-build.yaml) in order to fetch a Git repository and run a Camel K Integration delegating the build to the Camel K operator. + +### Full pipeline with custom build + +Use the [Tekton Camel K external builder sample](../0.1/samples/run-external-build.yaml) as a reference for a full pipeline where you define your own process of building the Camel application and using the `kamel-run` Task as last step in order to deploy the Integration and let Camel K operator managing it. \ No newline at end of file diff --git a/task/kamel-run/0.2/kamel-run.yaml b/task/kamel-run/0.2/kamel-run.yaml new file mode 100644 index 0000000000..976c3b3a47 --- /dev/null +++ b/task/kamel-run/0.2/kamel-run.yaml @@ -0,0 +1,58 @@ +apiVersion: tekton.dev/v1beta1 +kind: Task +metadata: + name: kamel-run + labels: + app.kubernetes.io/version: "0.1" + annotations: + tekton.dev/categories: Deployment + tekton.dev/pipelines.minVersion: "0.17.0" + tekton.dev/tags: cli + tekton.dev/platforms: "linux/amd64" + tekton.dev/displayName: "kamel run" +spec: + description: >- + Run a Camel Integration + + Kamel-run task creates a Camel K Integration which will be taken and operated by Camel K operator. You can either use this task to + run a build from source or build the application in previous tasks and use this last task to deploy and let Camel K operates it. + params: + - name: camel-k-image + description: The location of Camel K CLI image. + default: docker.io/apache/camel-k:2.0.0 + - name: filename + description: the Integration source we want to run + - name: namespace + description: the namespace where to run the integration + default: "" + - name: container-image + description: the custom container image to use (if the build was performed as part of previous tasks) + default: "" + - name: wait + description: wait for the Integration to run before exiting the task + default: "false" + results: + - name: integration-name + description: The name of the integration created + - name: integration-phase + description: The phase of the integration created (when used with input `wait` parameter) + workspaces: + - name: source + steps: + - name: execute + image: $(params.camel-k-image) + workingDir: $(workspaces.source.path) + script: | + #!/usr/bin/env bash + + KAMEL_RUN_ARGS=() + + KAMEL_RUN_ARGS+=("$(params.filename)") + [[ ! "$(params.namespace)" == "" ]] && KAMEL_RUN_ARGS+=(-n "$(params.namespace)") + [[ ! "$(params.container-image)" == "" ]] && KAMEL_RUN_ARGS+=(-t "container.image=$(params.container-image)") + [[ "$(params.wait)" == "true" ]] && KAMEL_RUN_ARGS+=(--wait) + kamel_output=$(kamel run "${KAMEL_RUN_ARGS[@]}") + echo "$kamel_output" + # Let's use the output produced to scrape the integration name and phase + echo "$kamel_output" | grep -oP 'Integration ".*?" (updated|created|unchanged)' | awk -F ' ' '{print $2}' | sed "s/\"//g" | tr -d '\n' | tee "$(results.integration-name.path)" + kamel get "$(cat "$(results.integration-name.path)")" 2>/dev/null | tail -n +2 | awk -F ' ' '{print $2}' | tr -d '\n' | tee "$(results.integration-phase.path)" \ No newline at end of file diff --git a/task/kamel-run/0.2/samples/run-external-build.yaml b/task/kamel-run/0.2/samples/run-external-build.yaml new file mode 100644 index 0000000000..14543a6239 --- /dev/null +++ b/task/kamel-run/0.2/samples/run-external-build.yaml @@ -0,0 +1,106 @@ +--- +apiVersion: tekton.dev/v1beta1 +kind: Pipeline +metadata: + name: external-build +spec: + workspaces: + - name: shared-workspace + - name: maven-settings + tasks: + # Fetch git repo + - name: fetch-repository + taskRef: + name: git-clone + workspaces: + - name: output + workspace: shared-workspace + params: + - name: url + value: https://github.com/apache/camel-k-runtime + # Build the application + - name: maven-build + taskRef: + name: maven + runAfter: + - fetch-repository + workspaces: + - name: source + workspace: shared-workspace + - name: maven-settings + workspace: maven-settings + params: + - name: CONTEXT_DIR + value: "examples/yaml" + - name: GOALS + value: + - clean + - package + # Create the dockerfile (could be already in the git project, in such case, just skip this task) + - name: create-dockerfile + runAfter: + - maven-build + workspaces: + - name: source + workspace: shared-workspace + taskSpec: + steps: + - name: bash + image: ubuntu + script: | + echo "FROM docker.io/eclipse-temurin:17-jdk" > $(workspaces.source.path)/examples/yaml/Dockerfile + echo "COPY target/quarkus-app/ /deployments/dependencies/" >> $(workspaces.source.path)/examples/yaml/Dockerfile + # Build and push the container with the Camel application + - name: docker-build + taskRef: + name: buildah + runAfter: + - create-dockerfile + workspaces: + - name: source + workspace: shared-workspace + params: + - name: IMAGE + # Provide your container registry configuration accordingly! + value: 10.110.149.72/camel-k/my-camel-image + - name: TLSVERIFY + value: "false" + - name: CONTEXT + value: $(workspaces.source.path)/examples/yaml + # Run the Camel Integration, using the container image built previously + - name: kamel-run + taskRef: + name: kamel-run + runAfter: + - docker-build + workspaces: + - name: source + workspace: shared-workspace + params: + - name: filename + value: examples/yaml/data/routes.yaml + - name: container-image + value: $(tasks.docker-build.results.IMAGE_URL) + +--- +apiVersion: tekton.dev/v1beta1 +kind: PipelineRun +metadata: + name: external-build-run +spec: + pipelineRef: + name: external-build + taskRunSpecs: + - pipelineTaskName: kamel-run + taskServiceAccountName: camel-k-tekton + workspaces: + - name: shared-workspace + volumeClaimTemplate: + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + - name: maven-settings + emptyDir: {} diff --git a/task/kamel-run/0.2/samples/run-operator-build.yaml b/task/kamel-run/0.2/samples/run-operator-build.yaml new file mode 100644 index 0000000000..57dd958173 --- /dev/null +++ b/task/kamel-run/0.2/samples/run-operator-build.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: tekton.dev/v1beta1 +kind: Pipeline +metadata: + name: operator-build +spec: + workspaces: + - name: shared-workspace + tasks: + - name: fetch-repository + taskRef: + name: git-clone + workspaces: + - name: output + workspace: shared-workspace + params: + - name: url + value: https://github.com/apache/camel-k-examples/ + - name: kamel-run + taskRef: + name: kamel-run + runAfter: + - fetch-repository + workspaces: + - name: source + workspace: shared-workspace + params: + - name: filename + value: generic-examples/languages/routes.yaml + +--- +apiVersion: tekton.dev/v1beta1 +kind: PipelineRun +metadata: + name: operator-build-run +spec: + pipelineRef: + name: operator-build + taskRunSpecs: + - pipelineTaskName: kamel-run + taskServiceAccountName: camel-k-tekton + workspaces: + - name: shared-workspace + volumeClaimTemplate: + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi diff --git a/task/kamel-run/0.2/support/camel-k-tekton.yaml b/task/kamel-run/0.2/support/camel-k-tekton.yaml new file mode 100644 index 0000000000..ca98efdab6 --- /dev/null +++ b/task/kamel-run/0.2/support/camel-k-tekton.yaml @@ -0,0 +1,40 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: camel-k-tekton +--- +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: camel-k-integrations +rules: +- apiGroups: + - camel.apache.org + resources: + - integrations + verbs: + - create + - get + - list + - patch + - update + - watch +- apiGroups: + - camel.apache.org + resources: + - camelcatalogs + verbs: + - list +--- +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: camel-k-tekton-integrations +subjects: +- kind: ServiceAccount + name: camel-k-tekton +roleRef: + kind: Role + name: camel-k-integrations + apiGroup: rbac.authorization.k8s.io diff --git a/task/kamel-run/0.2/tests/pre-apply-task-hook.sh b/task/kamel-run/0.2/tests/pre-apply-task-hook.sh new file mode 100755 index 0000000000..ecadfb1930 --- /dev/null +++ b/task/kamel-run/0.2/tests/pre-apply-task-hook.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +add_sidecar_registry ${TMPF} + +# Install Camel K operator +wget https://github.com/apache/camel-k/releases/download/v2.0.0/camel-k-client-2.0.0-linux-amd64.tar.gz +tar -xvf camel-k-client-2.0.0-linux-amd64.tar.gz +./kamel install --registry localhost:5000 --registry-insecure --wait + +# Add git-clone +add_task git-clone latest +add_task buildah latest +add_task maven latest \ No newline at end of file diff --git a/task/kamel-run/0.2/tests/resources.yaml b/task/kamel-run/0.2/tests/resources.yaml new file mode 100644 index 0000000000..ca98efdab6 --- /dev/null +++ b/task/kamel-run/0.2/tests/resources.yaml @@ -0,0 +1,40 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: camel-k-tekton +--- +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: camel-k-integrations +rules: +- apiGroups: + - camel.apache.org + resources: + - integrations + verbs: + - create + - get + - list + - patch + - update + - watch +- apiGroups: + - camel.apache.org + resources: + - camelcatalogs + verbs: + - list +--- +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: camel-k-tekton-integrations +subjects: +- kind: ServiceAccount + name: camel-k-tekton +roleRef: + kind: Role + name: camel-k-integrations + apiGroup: rbac.authorization.k8s.io diff --git a/task/kamel-run/0.2/tests/run.yaml b/task/kamel-run/0.2/tests/run.yaml new file mode 100644 index 0000000000..4086f34801 --- /dev/null +++ b/task/kamel-run/0.2/tests/run.yaml @@ -0,0 +1,149 @@ +--- +apiVersion: tekton.dev/v1beta1 +kind: Pipeline +metadata: + name: kamel-run-basic-test +spec: + workspaces: + - name: shared-workspace + tasks: + - name: fetch-repository + taskRef: + name: git-clone + workspaces: + - name: output + workspace: shared-workspace + params: + - name: url + value: https://github.com/apache/camel-k-examples/ + - name: kamel-run + taskRef: + name: kamel-run + runAfter: + - fetch-repository + workspaces: + - name: source + workspace: shared-workspace + params: + - name: filename + value: generic-examples/languages/routes.yaml + - name: wait + value: "false" + - name: verify-it-phase + runAfter: + - kamel-run + params: + - name: it-name + value: "$(tasks.kamel-run.results.integration-name)" + taskSpec: + params: + - name: it-name + steps: + - name: bash + image: ubuntu + script: | + #!/usr/bin/env bash + set -e + + if [ "$(params.it-name)" != "routes" ]; then + echo "Expected integration name routes (was $(params.it-name))" + exit 1 + fi + exit 0 + +--- +apiVersion: tekton.dev/v1beta1 +kind: PipelineRun +metadata: + name: kamel-run-basic-test-run +spec: + pipelineRef: + name: kamel-run-basic-test + taskRunSpecs: + - pipelineTaskName: kamel-run + taskServiceAccountName: camel-k-tekton + workspaces: + - name: shared-workspace + volumeClaimTemplate: + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + +--- +apiVersion: tekton.dev/v1beta1 +kind: Pipeline +metadata: + name: kamel-run-image-test +spec: + workspaces: + - name: shared-workspace + tasks: + - name: fetch-repository + taskRef: + name: git-clone + workspaces: + - name: output + workspace: shared-workspace + params: + - name: url + value: https://github.com/apache/camel-k-examples/ + - name: kamel-run + taskRef: + name: kamel-run + runAfter: + - fetch-repository + workspaces: + - name: source + workspace: shared-workspace + params: + - name: filename + value: generic-examples/languages/routes.yaml + - name: wait + value: "false" + - name: container-image + value: docker.io/apache/camel-k:2.0.0 + - name: verify-it-phase + runAfter: + - kamel-run + params: + - name: it-name + value: "$(tasks.kamel-run.results.integration-name)" + taskSpec: + params: + - name: it-name + steps: + - name: bash + image: ubuntu + script: | + #!/usr/bin/env bash + set -e + + if [ "$(params.it-name)" != "routes" ]; then + echo "Expected integration name routes (was $(params.it-name))" + exit 1 + fi + exit 0 + +--- +apiVersion: tekton.dev/v1beta1 +kind: PipelineRun +metadata: + name: kamel-run-image-test-run +spec: + pipelineRef: + name: kamel-run-image-test + taskRunSpecs: + - pipelineTaskName: kamel-run + taskServiceAccountName: camel-k-tekton + workspaces: + - name: shared-workspace + volumeClaimTemplate: + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi \ No newline at end of file From 18e64dd12aa4426c8bf96708ba1ff3f27cd7ab1e Mon Sep 17 00:00:00 2001 From: gferreir Date: Thu, 17 Sep 2026 10:57:14 -0300 Subject: [PATCH 14/19] chore(kamel-run): bump apiVersion to tekton.dev/v1 Ref: tektoncd/catalog#1381 Signed-off-by: gferreir --- task/kamel-run/0.2/README.md | 8 ++++---- task/kamel-run/0.2/kamel-run.yaml | 6 +++--- task/kamel-run/0.2/samples/run-external-build.yaml | 4 ++-- task/kamel-run/0.2/samples/run-operator-build.yaml | 4 ++-- task/kamel-run/0.2/tests/run.yaml | 8 ++++---- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/task/kamel-run/0.2/README.md b/task/kamel-run/0.2/README.md index e3577a77e5..f7fc71ccd5 100644 --- a/task/kamel-run/0.2/README.md +++ b/task/kamel-run/0.2/README.md @@ -7,7 +7,7 @@ If you have installed Camel K operator, you can configure the `kamel-run` task t ## Install the Task ```shell -kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/kamel-run/0.1/kamel-run.yaml +kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/kamel-run/0.2/kamel-run.yaml ``` ## Parameters @@ -40,13 +40,13 @@ The Task can be used in several ways to accomodate the different build and deplo As we will do delegate the task, the creation of an Integration, we need to provide a `ServiceAccount` with the privileges required by the tasks: ```shell -kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/kamel-run/0.1/support/camel-k-tekton.yaml +kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/kamel-run/0.2/support/camel-k-tekton.yaml ``` ### Delegate build to operator -Use the [Tekton Camel K operator builder sample](../0.1/samples/run-operator-build.yaml) in order to fetch a Git repository and run a Camel K Integration delegating the build to the Camel K operator. +Use the [Tekton Camel K operator builder sample](../0.2/samples/run-operator-build.yaml) in order to fetch a Git repository and run a Camel K Integration delegating the build to the Camel K operator. ### Full pipeline with custom build -Use the [Tekton Camel K external builder sample](../0.1/samples/run-external-build.yaml) as a reference for a full pipeline where you define your own process of building the Camel application and using the `kamel-run` Task as last step in order to deploy the Integration and let Camel K operator managing it. \ No newline at end of file +Use the [Tekton Camel K external builder sample](../0.2/samples/run-external-build.yaml) as a reference for a full pipeline where you define your own process of building the Camel application and using the `kamel-run` Task as last step in order to deploy the Integration and let Camel K operator managing it. \ No newline at end of file diff --git a/task/kamel-run/0.2/kamel-run.yaml b/task/kamel-run/0.2/kamel-run.yaml index 976c3b3a47..5ff09909de 100644 --- a/task/kamel-run/0.2/kamel-run.yaml +++ b/task/kamel-run/0.2/kamel-run.yaml @@ -1,12 +1,12 @@ -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: Task metadata: name: kamel-run labels: - app.kubernetes.io/version: "0.1" + app.kubernetes.io/version: "0.2" annotations: tekton.dev/categories: Deployment - tekton.dev/pipelines.minVersion: "0.17.0" + tekton.dev/pipelines.minVersion: "0.50.0" tekton.dev/tags: cli tekton.dev/platforms: "linux/amd64" tekton.dev/displayName: "kamel run" diff --git a/task/kamel-run/0.2/samples/run-external-build.yaml b/task/kamel-run/0.2/samples/run-external-build.yaml index 14543a6239..110ace3341 100644 --- a/task/kamel-run/0.2/samples/run-external-build.yaml +++ b/task/kamel-run/0.2/samples/run-external-build.yaml @@ -1,5 +1,5 @@ --- -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: Pipeline metadata: name: external-build @@ -83,7 +83,7 @@ spec: value: $(tasks.docker-build.results.IMAGE_URL) --- -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: PipelineRun metadata: name: external-build-run diff --git a/task/kamel-run/0.2/samples/run-operator-build.yaml b/task/kamel-run/0.2/samples/run-operator-build.yaml index 57dd958173..1574f965f2 100644 --- a/task/kamel-run/0.2/samples/run-operator-build.yaml +++ b/task/kamel-run/0.2/samples/run-operator-build.yaml @@ -1,5 +1,5 @@ --- -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: Pipeline metadata: name: operator-build @@ -29,7 +29,7 @@ spec: value: generic-examples/languages/routes.yaml --- -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: PipelineRun metadata: name: operator-build-run diff --git a/task/kamel-run/0.2/tests/run.yaml b/task/kamel-run/0.2/tests/run.yaml index 4086f34801..0aff732d9f 100644 --- a/task/kamel-run/0.2/tests/run.yaml +++ b/task/kamel-run/0.2/tests/run.yaml @@ -1,5 +1,5 @@ --- -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: Pipeline metadata: name: kamel-run-basic-test @@ -52,7 +52,7 @@ spec: exit 0 --- -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: PipelineRun metadata: name: kamel-run-basic-test-run @@ -73,7 +73,7 @@ spec: storage: 1Gi --- -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: Pipeline metadata: name: kamel-run-image-test @@ -128,7 +128,7 @@ spec: exit 0 --- -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: PipelineRun metadata: name: kamel-run-image-test-run From af7047a269fe94ee1b51f5aa1d087d619b4c24f3 Mon Sep 17 00:00:00 2001 From: gferreir Date: Thu, 17 Sep 2026 10:57:14 -0300 Subject: [PATCH 15/19] chore(helm-upgrade-from-repo): copy task from 0.3 to 0.4 Signed-off-by: gferreir --- task/helm-upgrade-from-repo/0.4/README.md | 60 +++++++++++++++++++ .../0.4/helm-upgrade-from-repo.yaml | 51 ++++++++++++++++ .../helm-upgrade-from-repo-task-run.yaml.tmpl | 18 ++++++ .../0.4/tests/pre-apply-task-hook.sh | 7 +++ .../helm-upgrade-from-repo/0.4/tests/run.yaml | 30 ++++++++++ 5 files changed, 166 insertions(+) create mode 100644 task/helm-upgrade-from-repo/0.4/README.md create mode 100644 task/helm-upgrade-from-repo/0.4/helm-upgrade-from-repo.yaml create mode 100644 task/helm-upgrade-from-repo/0.4/samples/helm-upgrade-from-repo-task-run.yaml.tmpl create mode 100755 task/helm-upgrade-from-repo/0.4/tests/pre-apply-task-hook.sh create mode 100644 task/helm-upgrade-from-repo/0.4/tests/run.yaml diff --git a/task/helm-upgrade-from-repo/0.4/README.md b/task/helm-upgrade-from-repo/0.4/README.md new file mode 100644 index 0000000000..91efd3ec54 --- /dev/null +++ b/task/helm-upgrade-from-repo/0.4/README.md @@ -0,0 +1,60 @@ +# Helm + +These tasks will install / upgrade a helm chart into your Kubernetes / OpenShift Cluster using [Helm](https://github.com/helm/helm). + +## Install the Task + +#### Workspaces + +* **source**: A [Workspace](https://github.com/tektoncd/pipeline/blob/main/docs/workspaces.md) volume containing the helm chart. + +### helm install / upgrade from repo + +``` +kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/helm-upgrade-from-repo/0.3/helm-upgrade-from-repo.yaml +``` + +#### Parameters + +- **chart_name**: The directory in the source repository where the installable chart should be found. +- **release_version**: The version of the release (*default: v1.0.0*) +- **release_name**: The name of the release (*default: helm-release*) +- **release_namespace**: The namespace in which the release is to be installed (*default: ""*) +- **overwrite_values**: The values to be overwritten (*default: ""*) +- **helm_image**: The helm image which should be used (default: lachlanevenson/k8s-helm:v3.5.0) + +#### Platforms + +The Task can be run on `linux/amd64`, `linux/s390x`, `linux/arm64` and `linux/ppc64le` platforms. + +## Usage + +### PipelineRun + +An example `Pipeline` with a `PipelineRun` can be found in the subdirectory `tests`. + +### TaskRun + +This `TaskRun` runs the task to retrieve a Git repo and then installs/updates the helm chart that is in the Git repo. + +```yaml +# example upgrade from repo +apiVersion: tekton.dev/v1beta1 +kind: TaskRun +metadata: + name: example-helm-upgrade-from-repo +spec: + taskRef: + name: helm-upgrade-from-repo + params: + - name: helm_repo + value: https://kubernetes-charts.storage.googleapis.com + - name: chart_name + value: stable/envoy + - name: release_version + value: v1.0.0 + - name: release_name + value: helm-repo-sample + - name: overwrite_values + value: autoscaling.enabled=true,autoscaling.maxReplicas=3 +``` diff --git a/task/helm-upgrade-from-repo/0.4/helm-upgrade-from-repo.yaml b/task/helm-upgrade-from-repo/0.4/helm-upgrade-from-repo.yaml new file mode 100644 index 0000000000..0343bbcb0a --- /dev/null +++ b/task/helm-upgrade-from-repo/0.4/helm-upgrade-from-repo.yaml @@ -0,0 +1,51 @@ +# This Task will do a helm upgrade based on the given helm repo and chart +apiVersion: tekton.dev/v1beta1 +kind: Task +metadata: + name: helm-upgrade-from-repo + labels: + app.kubernetes.io/version: "0.3" + annotations: + tekton.dev/categories: Deployment + tekton.dev/pipelines.minVersion: "0.12.1" + tekton.dev/tags: helm + tekton.dev/platforms: "linux/amd64,linux/s390x,linux/ppc64le,linux/arm64" +spec: + description: >- + These tasks will install / upgrade a helm chart into your Kubernetes / + OpenShift Cluster using Helm + + params: + - name: helm_repo + description: "Specify a specific helm repo" + - name: chart_name + description: "Specify chart name that will be deployed" + - name: release_version + description: The helm release version in semantic versioning format + default: "v1.0.0" + - name: release_name + description: The helm release name + default: "helm-release" + - name: release_namespace + description: The helm release namespace + default: "" + - name: overwrite_values + description: "Specify the values you want to overwrite, comma separated: autoscaling.enabled=true,replicas=1" + default: "" + - name: helm_image + description: "Specify a specific helm image" + default: "docker.io/lachlanevenson/k8s-helm@sha256:0a068ae407e21d1836c6a89a1e9e81af1e55fa56890998e33d5caabdbb51e77b" # tag: v3.10.2 + steps: + - name: upgrade-from-repo + image: $(params.helm_image) + script: | + echo current installed helm releases + helm list --namespace "$(params.release_namespace)" + echo parsing helms repo name... + REPO=`echo "$(params.chart_name)" | cut -d "/" -f 1` + echo adding helm repo... + helm repo add $REPO "$(params.helm_repo)" + echo adding updating repo... + helm repo update + echo installing helm chart... + helm upgrade --wait --install --namespace "$(params.release_namespace)" $(params.release_name) $(params.chart_name) --debug --set "$(params.overwrite_values)" diff --git a/task/helm-upgrade-from-repo/0.4/samples/helm-upgrade-from-repo-task-run.yaml.tmpl b/task/helm-upgrade-from-repo/0.4/samples/helm-upgrade-from-repo-task-run.yaml.tmpl new file mode 100644 index 0000000000..fc2824ec96 --- /dev/null +++ b/task/helm-upgrade-from-repo/0.4/samples/helm-upgrade-from-repo-task-run.yaml.tmpl @@ -0,0 +1,18 @@ +apiVersion: tekton.dev/v1beta1 +kind: TaskRun +metadata: + name: example-helm-upgrade-from-repo +spec: + taskRef: + name: helm-upgrade-from-repo + params: + - name: helm_repo + value: https://charts.helm.sh/stable + - name: chart_name + value: stable/envoy + - name: release_version + value: v1.0.0 + - name: release_name + value: helm-repo-sample + - name: overwrite_values + value: autoscaling.enabled=true,autoscaling.maxReplicas=3 \ No newline at end of file diff --git a/task/helm-upgrade-from-repo/0.4/tests/pre-apply-task-hook.sh b/task/helm-upgrade-from-repo/0.4/tests/pre-apply-task-hook.sh new file mode 100755 index 0000000000..4bb7ad3104 --- /dev/null +++ b/task/helm-upgrade-from-repo/0.4/tests/pre-apply-task-hook.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +# Add service account +kubectl -n ${tns} create serviceaccount helm-pipeline-run-sa + +# Add edit role to service account +kubectl -n ${tns} create rolebinding helm-pipeline-run-sa-edit --clusterrole edit --serviceaccount ${tns}:helm-pipeline-run-sa -o yaml --dry-run=client | kubectl apply -f - diff --git a/task/helm-upgrade-from-repo/0.4/tests/run.yaml b/task/helm-upgrade-from-repo/0.4/tests/run.yaml new file mode 100644 index 0000000000..d728495b62 --- /dev/null +++ b/task/helm-upgrade-from-repo/0.4/tests/run.yaml @@ -0,0 +1,30 @@ +--- +apiVersion: tekton.dev/v1beta1 +kind: Pipeline +metadata: + name: helm-upgrade-test-pipeline +spec: + tasks: + - name: helm-upgrade-from-repo + taskRef: + name: helm-upgrade-from-repo + params: + - name: helm_repo + value: https://dunefro.github.io/sample-charts/ + - name: chart_name + value: sample-charts/sample-nginx + - name: release_version + value: v1.0.0 + - name: release_name + value: helm-repo-sample + - name: overwrite_values + value: autoscaling.enabled=false,autoscaling.maxReplicas=3 +--- +apiVersion: tekton.dev/v1beta1 +kind: PipelineRun +metadata: + name: helm-upgrade-test-pipeline-run +spec: + serviceAccountName: helm-pipeline-run-sa + pipelineRef: + name: helm-upgrade-test-pipeline From f4d1b93284db2718800e920ae4b66fd730c50cdc Mon Sep 17 00:00:00 2001 From: gferreir Date: Thu, 17 Sep 2026 10:57:14 -0300 Subject: [PATCH 16/19] chore(helm-upgrade-from-repo): bump apiVersion to tekton.dev/v1 Ref: tektoncd/catalog#1381 Signed-off-by: gferreir --- task/helm-upgrade-from-repo/0.4/README.md | 4 ++-- task/helm-upgrade-from-repo/0.4/helm-upgrade-from-repo.yaml | 6 +++--- .../0.4/samples/helm-upgrade-from-repo-task-run.yaml.tmpl | 2 +- task/helm-upgrade-from-repo/0.4/tests/run.yaml | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/task/helm-upgrade-from-repo/0.4/README.md b/task/helm-upgrade-from-repo/0.4/README.md index 91efd3ec54..7a6559e6c4 100644 --- a/task/helm-upgrade-from-repo/0.4/README.md +++ b/task/helm-upgrade-from-repo/0.4/README.md @@ -11,7 +11,7 @@ These tasks will install / upgrade a helm chart into your Kubernetes / OpenShift ### helm install / upgrade from repo ``` -kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/helm-upgrade-from-repo/0.3/helm-upgrade-from-repo.yaml +kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/helm-upgrade-from-repo/0.4/helm-upgrade-from-repo.yaml ``` #### Parameters @@ -39,7 +39,7 @@ This `TaskRun` runs the task to retrieve a Git repo and then installs/updates th ```yaml # example upgrade from repo -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: TaskRun metadata: name: example-helm-upgrade-from-repo diff --git a/task/helm-upgrade-from-repo/0.4/helm-upgrade-from-repo.yaml b/task/helm-upgrade-from-repo/0.4/helm-upgrade-from-repo.yaml index 0343bbcb0a..4cfb7c958d 100644 --- a/task/helm-upgrade-from-repo/0.4/helm-upgrade-from-repo.yaml +++ b/task/helm-upgrade-from-repo/0.4/helm-upgrade-from-repo.yaml @@ -1,13 +1,13 @@ # This Task will do a helm upgrade based on the given helm repo and chart -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: Task metadata: name: helm-upgrade-from-repo labels: - app.kubernetes.io/version: "0.3" + app.kubernetes.io/version: "0.4" annotations: tekton.dev/categories: Deployment - tekton.dev/pipelines.minVersion: "0.12.1" + tekton.dev/pipelines.minVersion: "0.50.0" tekton.dev/tags: helm tekton.dev/platforms: "linux/amd64,linux/s390x,linux/ppc64le,linux/arm64" spec: diff --git a/task/helm-upgrade-from-repo/0.4/samples/helm-upgrade-from-repo-task-run.yaml.tmpl b/task/helm-upgrade-from-repo/0.4/samples/helm-upgrade-from-repo-task-run.yaml.tmpl index fc2824ec96..babe573b5d 100644 --- a/task/helm-upgrade-from-repo/0.4/samples/helm-upgrade-from-repo-task-run.yaml.tmpl +++ b/task/helm-upgrade-from-repo/0.4/samples/helm-upgrade-from-repo-task-run.yaml.tmpl @@ -1,4 +1,4 @@ -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: TaskRun metadata: name: example-helm-upgrade-from-repo diff --git a/task/helm-upgrade-from-repo/0.4/tests/run.yaml b/task/helm-upgrade-from-repo/0.4/tests/run.yaml index d728495b62..3a8506869f 100644 --- a/task/helm-upgrade-from-repo/0.4/tests/run.yaml +++ b/task/helm-upgrade-from-repo/0.4/tests/run.yaml @@ -1,5 +1,5 @@ --- -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: Pipeline metadata: name: helm-upgrade-test-pipeline @@ -20,7 +20,7 @@ spec: - name: overwrite_values value: autoscaling.enabled=false,autoscaling.maxReplicas=3 --- -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: PipelineRun metadata: name: helm-upgrade-test-pipeline-run From 3dced597eef887440ca40534acd55f9bc24f1f7f Mon Sep 17 00:00:00 2001 From: gferreir Date: Thu, 17 Sep 2026 10:57:14 -0300 Subject: [PATCH 17/19] chore(istio-canary-release): copy task from 0.1 to 0.2 Signed-off-by: gferreir --- task/istio-canary-release/0.2/README.md | 64 ++++++++++++++++ .../0.2/istio-canary-release.yaml | 74 +++++++++++++++++++ .../0.2/samples/application/app-gateway.yaml | 48 ++++++++++++ .../0.2/samples/application/myapp.yaml | 59 +++++++++++++++ .../istio-canary-release/0.2/samples/run.yaml | 49 ++++++++++++ .../0.2/samples/taskrun.yaml | 17 +++++ .../0.2/support/clusterrolebinding.yaml | 12 +++ 7 files changed, 323 insertions(+) create mode 100644 task/istio-canary-release/0.2/README.md create mode 100644 task/istio-canary-release/0.2/istio-canary-release.yaml create mode 100644 task/istio-canary-release/0.2/samples/application/app-gateway.yaml create mode 100644 task/istio-canary-release/0.2/samples/application/myapp.yaml create mode 100644 task/istio-canary-release/0.2/samples/run.yaml create mode 100644 task/istio-canary-release/0.2/samples/taskrun.yaml create mode 100644 task/istio-canary-release/0.2/support/clusterrolebinding.yaml diff --git a/task/istio-canary-release/0.2/README.md b/task/istio-canary-release/0.2/README.md new file mode 100644 index 0000000000..63e2e9a0a1 --- /dev/null +++ b/task/istio-canary-release/0.2/README.md @@ -0,0 +1,64 @@ +# Canary Release using Istio + +The following task can be used to do canary deployment by doing a canary traffic routing to the deployed versions. + +When the new version of application is deployed, you can start routing a few selected users to it. As you gain more confidence in the new version, you can start releasing it to more servers in your infrastructure and routing more users to it. + +For more details about canary release please refer [here](https://martinfowler.com/bliki/CanaryRelease.html) + +### **PRE-REQUISITE**: Istio should already be installed in the same cluster. + +## Installing the tasks + +1. For Application Manifests deployment we can use the existing `kubenetes-actions` task from the catalog + +```bash +kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/kubernetes-actions/0.1/kubernetes-actions.yaml +``` + +2. For Istio Services + +```bash +kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/istio-canary-release/0.1/istio-canary-release.yaml +``` + +## Installing the ClusterRoleBinding + +```bash +kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/istio-canary-release/0.1/support/clusterrolebinding.yaml +``` + +## Workspaces + +- **deployment-manifest-dir**: The workspace in which `ConfigMap` containing all the deployment manifests will be mounted. +- **istio-manifest-dir**: The workspace in which `ConfigMap` containing the istio related manifests will be mounted. + +## Params for Canary-Istio-Deploy + +- **VS_NAME**: The name of the `VirtualService` +- **V1_WEIGHT**: The traffic weight to be diverted to existing version v1 +- **V2_WEIGHT**: The traffic weight to be diverted to new version v2 + +**Note**: The above parameters are used in case we need to do traffic splitting using virtual service and for creating a `VirtualService` then use the `ConfigMap` as shown below. + +## Platforms + +The Task can be run on `linux/amd64` platform. + +# Usage + +1. Create `ConfigMap` for `Istio` manifests + +```bash +kubectl create configmap istio --from-file="./samples/application/app-gateway.yaml" +``` + +2. Create `ConfigMap` for `Deployment` manifests + +```bash +kubectl create configmap deployment --from-file="isto-canary-release/samples/application/myapp.yaml" +``` + +In case of app deployment and configuring Istio follow [this](./samples/run.yaml) example. + +In case of just re-configuring the Istio follow [this](./samples/taskrun.yaml) example. diff --git a/task/istio-canary-release/0.2/istio-canary-release.yaml b/task/istio-canary-release/0.2/istio-canary-release.yaml new file mode 100644 index 0000000000..1bd23aad81 --- /dev/null +++ b/task/istio-canary-release/0.2/istio-canary-release.yaml @@ -0,0 +1,74 @@ +apiVersion: tekton.dev/v1beta1 +kind: Task +metadata: + name: istio-canary-release + labels: + app.kubernetes.io/version: "0.1" + annotations: + tekton.dev/pipelines.minVersion: "0.12.1" + tekton.dev/categories: Deployment + tekton.dev/tags: canary deployment, istio + tekton.dev/displayName: "istio canary release" + tekton.dev/platforms: "linux/amd64" +spec: + description: >- + This task can be used to perform deployment of an application + using canary release strategy. + + Using this task we can route the traffic to the deployments + with the help of virtual service by specifying the weights to + individual deployment. + + workspaces: + - name: istio-manifest-dir + description: >- + The workspace consisting of Istio manifests such as Gateway, + DestinationRule and VirtualService in case applying for the + first time. + params: + - name: VS_NAME + description: The virtual service name to be patched + type: string + default: "" + - name: V1_WEIGHT + description: The traffic percentage to be sent to version v1 + type: string + default: "" + - name: V2_WEIGHT + description: The traffic percentage to be sent to version v2 + type: string + default: "" + steps: + - name: canary-deploy + image: quay.io/openshift/origin-cli:4.6 + workingDir: $(workspaces.istio-manifest-dir.path) + script: | + #!/usr/bin/env bash + + cat </tmp/patch.yaml + apiVersion: networking.istio.io/v1alpha3 + kind: VirtualService + metadata: + name: $(params.VS_NAME) + spec: + hosts: + - "*" + gateways: + - app-gateway + http: + - route: + - destination: + host: myapp + subset: v1 + weight: $(params.V1_WEIGHT) + - destination: + host: myapp + subset: v2 + weight: $(params.V2_WEIGHT) + EOF + + if [ -n "$(params.V1_WEIGHT)" -a -n "$(params.V2_WEIGHT)" ]; then + kubectl replace -f /tmp/patch.yaml + else + kubectl apply -f ./ + fi diff --git a/task/istio-canary-release/0.2/samples/application/app-gateway.yaml b/task/istio-canary-release/0.2/samples/application/app-gateway.yaml new file mode 100644 index 0000000000..496cfd2469 --- /dev/null +++ b/task/istio-canary-release/0.2/samples/application/app-gateway.yaml @@ -0,0 +1,48 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: app-gateway +spec: + selector: + istio: ingressgateway + servers: + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - "*" +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: myapp +spec: + host: myapp + subsets: + - name: v1 + labels: + version: v1 + - name: v2 + labels: + version: v2 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: myapp +spec: + hosts: + - "*" + gateways: + - app-gateway + http: + - route: + - destination: + host: myapp + subset: v1 + weight: 20 + - destination: + host: myapp + subset: v2 + weight: 80 diff --git a/task/istio-canary-release/0.2/samples/application/myapp.yaml b/task/istio-canary-release/0.2/samples/application/myapp.yaml new file mode 100644 index 0000000000..860c85842c --- /dev/null +++ b/task/istio-canary-release/0.2/samples/application/myapp.yaml @@ -0,0 +1,59 @@ +apiVersion: v1 +kind: Service +metadata: + name: myapp + labels: + app: myapp +spec: + type: ClusterIP + ports: + - port: 80 + name: http + selector: + app: myapp +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myapp-v1 +spec: + replicas: 1 + selector: + matchLabels: + app: myapp + version: v1 + template: + metadata: + labels: + app: myapp + version: v1 + spec: + containers: + - name: myapp + image: janakiramm/myapp:v1 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 80 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myapp-v2 +spec: + replicas: 1 + selector: + matchLabels: + app: myapp + version: v2 + template: + metadata: + labels: + app: myapp + version: v2 + spec: + containers: + - name: myapp + image: janakiramm/myapp:v2 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 80 diff --git a/task/istio-canary-release/0.2/samples/run.yaml b/task/istio-canary-release/0.2/samples/run.yaml new file mode 100644 index 0000000000..1a8e398cfb --- /dev/null +++ b/task/istio-canary-release/0.2/samples/run.yaml @@ -0,0 +1,49 @@ +apiVersion: tekton.dev/v1beta1 +kind: Pipeline +metadata: + name: canary-deployment +spec: + workspaces: + - name: deployment-manifest-dir + - name: istio-manifest-dir + - name: kubeconfig-dir + tasks: + - name: app-deploy + taskRef: + name: kubernetes-actions + params: + - name: args + value: + - apply + - -f + - "." + workspaces: + - name: manifest-dir + workspace: deployment-manifest-dir + - name: kubeconfig-dir + workspace: kubeconfig-dir + - name: deploy-istio-service + taskRef: + name: istio-canary-release + runAfter: + - app-deploy + workspaces: + - name: istio-manifest-dir + workspace: istio-manifest-dir +--- +apiVersion: tekton.dev/v1beta1 +kind: PipelineRun +metadata: + name: canary-deployment-run +spec: + pipelineRef: + name: canary-deployment + workspaces: + - name: deployment-manifest-dir + configMap: + name: deployment + - name: istio-manifest-dir + configMap: + name: istio + - name: kubeconfig-dir + emptyDir: {} diff --git a/task/istio-canary-release/0.2/samples/taskrun.yaml b/task/istio-canary-release/0.2/samples/taskrun.yaml new file mode 100644 index 0000000000..3e9c451460 --- /dev/null +++ b/task/istio-canary-release/0.2/samples/taskrun.yaml @@ -0,0 +1,17 @@ +apiVersion: tekton.dev/v1beta1 +kind: TaskRun +metadata: istio-run +spec: + taskRef: + name: istio-canary-release + params: + - name: VS_NAME + value: myapp + - name: V1_WEIGHT + value: "50" + - name: V2_WEIGHT + value: "50" + workspaces: + - name: istio-manifest-dir + configMap: + name: istio diff --git a/task/istio-canary-release/0.2/support/clusterrolebinding.yaml b/task/istio-canary-release/0.2/support/clusterrolebinding.yaml new file mode 100644 index 0000000000..e82b23ce3b --- /dev/null +++ b/task/istio-canary-release/0.2/support/clusterrolebinding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: default-canary +subjects: + - kind: ServiceAccount + name: default + namespace: default +roleRef: + kind: ClusterRole + name: cluster-admin + apiGroup: rbac.authorization.k8s.io From 3d7c1f2329f3a2872bbe745f079c55fcd7f8dff6 Mon Sep 17 00:00:00 2001 From: gferreir Date: Thu, 17 Sep 2026 10:57:14 -0300 Subject: [PATCH 18/19] chore(istio-canary-release): bump apiVersion to tekton.dev/v1 Ref: tektoncd/catalog#1381 Signed-off-by: gferreir --- task/istio-canary-release/0.2/README.md | 4 ++-- task/istio-canary-release/0.2/istio-canary-release.yaml | 8 ++++---- task/istio-canary-release/0.2/samples/run.yaml | 4 ++-- task/istio-canary-release/0.2/samples/taskrun.yaml | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/task/istio-canary-release/0.2/README.md b/task/istio-canary-release/0.2/README.md index 63e2e9a0a1..61d8b73fe2 100644 --- a/task/istio-canary-release/0.2/README.md +++ b/task/istio-canary-release/0.2/README.md @@ -19,13 +19,13 @@ kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/ku 2. For Istio Services ```bash -kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/istio-canary-release/0.1/istio-canary-release.yaml +kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/istio-canary-release/0.2/istio-canary-release.yaml ``` ## Installing the ClusterRoleBinding ```bash -kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/istio-canary-release/0.1/support/clusterrolebinding.yaml +kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/istio-canary-release/0.2/support/clusterrolebinding.yaml ``` ## Workspaces diff --git a/task/istio-canary-release/0.2/istio-canary-release.yaml b/task/istio-canary-release/0.2/istio-canary-release.yaml index 1bd23aad81..588e38d03e 100644 --- a/task/istio-canary-release/0.2/istio-canary-release.yaml +++ b/task/istio-canary-release/0.2/istio-canary-release.yaml @@ -1,11 +1,11 @@ -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: Task metadata: name: istio-canary-release labels: - app.kubernetes.io/version: "0.1" + app.kubernetes.io/version: "0.2" annotations: - tekton.dev/pipelines.minVersion: "0.12.1" + tekton.dev/pipelines.minVersion: "0.50.0" tekton.dev/categories: Deployment tekton.dev/tags: canary deployment, istio tekton.dev/displayName: "istio canary release" @@ -40,7 +40,7 @@ spec: default: "" steps: - name: canary-deploy - image: quay.io/openshift/origin-cli:4.6 + image: quay.io/openshift/origin-cli:4.6@sha256:6722d5041b472ac61a294647f7fa02fb432a948835bb780cc73cd221a9291a2c workingDir: $(workspaces.istio-manifest-dir.path) script: | #!/usr/bin/env bash diff --git a/task/istio-canary-release/0.2/samples/run.yaml b/task/istio-canary-release/0.2/samples/run.yaml index 1a8e398cfb..6b847b4e1e 100644 --- a/task/istio-canary-release/0.2/samples/run.yaml +++ b/task/istio-canary-release/0.2/samples/run.yaml @@ -1,4 +1,4 @@ -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: Pipeline metadata: name: canary-deployment @@ -31,7 +31,7 @@ spec: - name: istio-manifest-dir workspace: istio-manifest-dir --- -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: PipelineRun metadata: name: canary-deployment-run diff --git a/task/istio-canary-release/0.2/samples/taskrun.yaml b/task/istio-canary-release/0.2/samples/taskrun.yaml index 3e9c451460..f39f57313b 100644 --- a/task/istio-canary-release/0.2/samples/taskrun.yaml +++ b/task/istio-canary-release/0.2/samples/taskrun.yaml @@ -1,4 +1,4 @@ -apiVersion: tekton.dev/v1beta1 +apiVersion: tekton.dev/v1 kind: TaskRun metadata: istio-run spec: From 303c653796d4e1bd10e8e6a412337d174c0fbd1f Mon Sep 17 00:00:00 2001 From: gferreir Date: Fri, 18 Sep 2026 11:37:19 -0300 Subject: [PATCH 19/19] fix(helm): use taskRunTemplate.serviceAccountName in PipelineRun v1 PipelineRun v1 removed spec.serviceAccountName in favor of spec.taskRunTemplate.serviceAccountName. The old field causes strict decoding errors on Tekton >= 0.50.0. Affected tests: - helm-upgrade-from-repo/0.4/tests/run.yaml - helm-upgrade-from-source/0.5/tests/run.yaml Ref: tektoncd/catalog#1381 Signed-off-by: gferreir --- task/helm-upgrade-from-repo/0.4/tests/run.yaml | 3 ++- task/helm-upgrade-from-source/0.5/tests/run.yaml | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/task/helm-upgrade-from-repo/0.4/tests/run.yaml b/task/helm-upgrade-from-repo/0.4/tests/run.yaml index 3a8506869f..147efd0cfe 100644 --- a/task/helm-upgrade-from-repo/0.4/tests/run.yaml +++ b/task/helm-upgrade-from-repo/0.4/tests/run.yaml @@ -25,6 +25,7 @@ kind: PipelineRun metadata: name: helm-upgrade-test-pipeline-run spec: - serviceAccountName: helm-pipeline-run-sa + taskRunTemplate: + serviceAccountName: helm-pipeline-run-sa pipelineRef: name: helm-upgrade-test-pipeline diff --git a/task/helm-upgrade-from-source/0.5/tests/run.yaml b/task/helm-upgrade-from-source/0.5/tests/run.yaml index d3ed76174c..b7b5f541e5 100644 --- a/task/helm-upgrade-from-source/0.5/tests/run.yaml +++ b/task/helm-upgrade-from-source/0.5/tests/run.yaml @@ -45,7 +45,8 @@ kind: PipelineRun metadata: name: helm-upgrade-test-pipeline-run spec: - serviceAccountName: helm-pipeline-run-sa + taskRunTemplate: + serviceAccountName: helm-pipeline-run-sa pipelineRef: name: helm-upgrade-test-pipeline workspaces: