From eab7905e0c6d1df611349c4039db6cde0bc9e501 Mon Sep 17 00:00:00 2001 From: Priyanka Saggu Date: Wed, 7 Aug 2024 11:45:46 +0530 Subject: [PATCH 01/17] update template files for repo specific info --- CONTRIBUTING.md | 8 ++------ OWNERS | 8 +++++--- OWNERS_ALIASES | 14 -------------- README.md | 20 ++++---------------- SECURITY_CONTACTS | 6 +++++- 5 files changed, 16 insertions(+), 40 deletions(-) delete mode 100644 OWNERS_ALIASES diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6a35a74..a5b17cd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,11 +20,7 @@ If your repo has certain guidelines for contribution, put them here ahead of the - [Mentoring Initiatives](https://k8s.dev/community/mentoring) - We have a diverse set of mentorship programs available that are always looking for volunteers! - +- [Slack channel](https://kubernetes.slack.com/messages/wg-etcd-operator) +- [Mailing list](https://groups.google.com/a/kubernetes.io/g/wg-etcd-operator) diff --git a/OWNERS b/OWNERS index 218b769..160a810 100644 --- a/OWNERS +++ b/OWNERS @@ -1,6 +1,8 @@ # See the OWNERS docs at https://go.k8s.io/owners approvers: - # TODO: in your repo created from this template, you should replace the - # github-admin-team with a list of project owners, see the doc linked above. - - github-admin-team + - ahrtr + - jmhbnz + - hakman + - jberkus + - justinsb diff --git a/OWNERS_ALIASES b/OWNERS_ALIASES deleted file mode 100644 index 5acaaad..0000000 --- a/OWNERS_ALIASES +++ /dev/null @@ -1,14 +0,0 @@ -# See the OWNERS docs at https://go.k8s.io/owners#owners_aliases - -aliases: - # TODO: remove this alias, it will go stale in your repo, and in your repo - # you should have your own set of approvers (see OWNERS) - # in the original template repo, we must maintain this list to approve changes - # to the template itself - github-admin-team: - - cblecker - - fejta - - idvoretskyi - - mrbobbytables - - nikhita - - spiffxp diff --git a/README.md b/README.md index 5bf9c1f..10e1011 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,7 @@ -# Kubernetes Template Project +# etcd-operator -The Kubernetes Template Project is a template for starting new projects in the GitHub organizations owned by Kubernetes. All Kubernetes projects, at minimum, must have the following files: +The official Kubernetes operator for etcd. -- a `README.md` outlining the project goals, sponsoring sig, and community contact information -- an `OWNERS` with the project leads listed as approvers ([docs on `OWNERS` files][owners]) -- a `CONTRIBUTING.md` outlining how to contribute to the project -- an unmodified copy of `code-of-conduct.md` from this repo, which outlines community behavior and the consequences of breaking the code -- a `LICENSE` which must be Apache 2.0 for code projects, or [Creative Commons 4.0] for documentation repositories, without any custom content -- a `SECURITY_CONTACTS` with the contact points for the Product Security Team - to reach out to for triaging and handling of incoming issues. They must agree to abide by the - [Embargo Policy](https://git.k8s.io/security/private-distributors-list.md#embargo-policy) - and will be removed and replaced if they violate that agreement. ## Community, discussion, contribution, and support @@ -18,12 +9,9 @@ Learn how to engage with the Kubernetes community on the [community page](http:/ You can reach the maintainers of this project at: -- [Slack](https://slack.k8s.io/) -- [Mailing List](https://groups.google.com/a/kubernetes.io/g/dev) +- [Slack channel](https://kubernetes.slack.com/messages/wg-etcd-operator) +- [Mailing list](https://groups.google.com/a/kubernetes.io/g/wg-etcd-operator) ### Code of conduct Participation in the Kubernetes community is governed by the [Kubernetes Code of Conduct](code-of-conduct.md). - -[owners]: https://git.k8s.io/community/contributors/guide/owners.md -[Creative Commons 4.0]: https://git.k8s.io/website/LICENSE diff --git a/SECURITY_CONTACTS b/SECURITY_CONTACTS index 0bd6f4b..e974c08 100644 --- a/SECURITY_CONTACTS +++ b/SECURITY_CONTACTS @@ -10,4 +10,8 @@ # DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE # INSTRUCTIONS AT https://kubernetes.io/security/ -github-usernames-go-here +ahrtr +jmhbnz +hakman +jberkus +justinsb From 2477660fb3c4af86643e977cf6d7565880033a8f Mon Sep 17 00:00:00 2001 From: Benjamin Wang Date: Thu, 29 Aug 2024 13:35:15 +0100 Subject: [PATCH 02/17] add an initial roadmap Signed-off-by: Benjamin Wang --- docs/roadmap.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 docs/roadmap.md diff --git a/docs/roadmap.md b/docs/roadmap.md new file mode 100644 index 0000000..afbb6ab --- /dev/null +++ b/docs/roadmap.md @@ -0,0 +1,27 @@ +# Roadmap + +The list is based on the survey results and the discussion in wg-etcd-operator. It is not set in stone and may be adjusted as needed. + +## v0.1.0 +- Create a new etcd cluster, e.g 3 or 5 members cluster + - Users should be able to set at least the etcd version and cluster size +- Understand health of a cluster +- Enabling TLS communication + - Should also support certificate renewal + +## v0.2.0 +- Upgrade across patches or one minor version +- Scale in and out, e.g 1 -> 3 -> 5 members and vise versa +- Support customizing etcd options (via flags or env vars) + +## v0.3.0 +- Recover a single failed cluster member (still have quorum) +- Recover from multiple failed cluster members (quorum loss) + +## v0.4.0 +- Create on-demand backup of a cluster +- Create periodic backup of a cluster +- Create a new cluster from a backup + +## Future versions +It makes no sense to plan too far ahead because plans can't keep up with changes. \ No newline at end of file From 0c1749ec08ca2f1418b677946ac5aefb21ea021e Mon Sep 17 00:00:00 2001 From: Frederiko Costa Date: Mon, 2 Sep 2024 13:06:29 -0700 Subject: [PATCH 03/17] Fix Typo Signed-off-by: Frederiko Costa --- docs/roadmap.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/roadmap.md b/docs/roadmap.md index afbb6ab..0a1d87a 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -11,7 +11,7 @@ The list is based on the survey results and the discussion in wg-etcd-operator. ## v0.2.0 - Upgrade across patches or one minor version -- Scale in and out, e.g 1 -> 3 -> 5 members and vise versa +- Scale in and out, e.g 1 -> 3 -> 5 members and vice versa - Support customizing etcd options (via flags or env vars) ## v0.3.0 @@ -24,4 +24,4 @@ The list is based on the survey results and the discussion in wg-etcd-operator. - Create a new cluster from a backup ## Future versions -It makes no sense to plan too far ahead because plans can't keep up with changes. \ No newline at end of file +It makes no sense to plan too far ahead because plans can't keep up with changes. From 8dcf226e14175df93282ebc3cf6144d40cf41f8d Mon Sep 17 00:00:00 2001 From: Josh Berkus Date: Thu, 5 Sep 2024 19:15:45 -0500 Subject: [PATCH 04/17] Add user survey summary to repo. Signed-off-by: Josh Berkus --- wg/survey/2024-operator-survey.md | 106 ++++++++++++++++++++++++++++++ wg/survey/hard_part.png | Bin 0 -> 14567 bytes wg/survey/manage.png | Bin 0 -> 24183 bytes wg/survey/no_clusters.png | Bin 0 -> 18447 bytes wg/survey/run_method.png | Bin 0 -> 12237 bytes wg/survey/where_use.png | Bin 0 -> 12361 bytes 6 files changed, 106 insertions(+) create mode 100644 wg/survey/2024-operator-survey.md create mode 100644 wg/survey/hard_part.png create mode 100644 wg/survey/manage.png create mode 100644 wg/survey/no_clusters.png create mode 100644 wg/survey/run_method.png create mode 100644 wg/survey/where_use.png diff --git a/wg/survey/2024-operator-survey.md b/wg/survey/2024-operator-survey.md new file mode 100644 index 0000000..5631e1f --- /dev/null +++ b/wg/survey/2024-operator-survey.md @@ -0,0 +1,106 @@ +# Etcd Operator Survey Results + +# Survey Responses and Data Cleaning + +We received 52 survey responses to the Etcd Operator Survey. + +Of these 52, 10 were removed from the aggregate results below: + +* One did not complete the survey +* Two said they would not use an official operator +* Eight responses came from a single organization, and as such were condensed into a single response before computing it. + +[Detailed summary result sheet](https://docs.google.com/spreadsheets/d/1Wria1k3I4nrV2OgorDjvr4-aucoBc\_oszrdmWCPrW1c/edit?gid=0\#gid=0) has the full anonymized data. + +# Survey Population + +Almost everyone uses Etcd at work. A few use it at school or for personal projects, but most of those also use it at work. + +![bar chart showing where respondees use etcd](where_use.png) + +Folks generally run Etcd as Kubernetes pods. Only about ⅓ of those use static pods. + +![bar chart showing methods of running etcd](run_method.png) + +Our surveyees divide into thirds; one-third runs fewer than ten etcd clusters, one-third runs more than 100, and one-third is in between. + +![pie chart showing number of clusters that users run](no_clusters.png) + +Our respondees largely already use older or custom operators: + +![pie chart showing how users manage their etcd clusters](manage.png) + +# Feature Priorities + +Required features fall naturally into four clusters: + +## Universal Features: + +These features were required by more than 78% of respondees. Interestingly, no required feature, even cluster creation, was 100% universal. + +* Creation of a 3 or 5 node etcd cluster +* Understanding health of a cluster + +## Popular Features: + +These features were required by more than 52% of respondees: + +* Upgrading a cluster by one minor version +* Understanding performance of a cluster +* Upgrading a cluster between patch versions +* Enabling TLS communication +* Creating on-demand backups of a cluster +* Recovering a single failed cluster node (still have quorum) +* Creating a new cluster from a backup +* Creating periodic backups of a cluster + +## Common Features + +These features were required by 33-52% of respondees: + +* Recovering from multiple failed cluster nodes (quorum loss) +* Growing a one node cluster to a 3 node cluster +* Growing a 3 node cluster to a 5 node cluster +* Creation of a single node etcd cluster +* Upgrading a cluster by multiple minor versions +* “Rolling back” a cluster to a backup +* Creation of a cluster with learners +* Shrinking a 5 node cluster to a 3 node cluster +* Shrinking a 3 node cluster to a 1 node cluster +* Expanding size of backing cloud volumes + +## Uncommon Features + +These features were required by less than ⅓ of respondees: + +* 1:1 exchange of one node with another node (e.g. to change cloud zones) +* Downgrading a cluster by one minor version +* Downgrading a cluster between patch versions +* Moving a cluster node between cloud zones +* Shrinking size of backing cloud volumes +* Downgrading a cluster by multiple minor version +* Moving cloud volumes between types (e.g. HDD \-\> SSD) +* Enabling unencrypted communication +* Moving cloud volumes between zones + +## Suggested Features + +These features were not part of our list, but were suggested requirements by various respondees: + +* Automatic TLS certificate renewal +* Ability to customize etcd configuration parameters +* Multi-cluster support (X2) +* Automated database compaction +* Ability to customize etcd pod spec + +## Big User vs. Small User Features + +Since our surveyees divide neatly into thirds, I wanted to see if there was any required features which were notably different between Big (\>100) and Small (\< 10) users. As it turned out, there wasn’t much difference that didn’t look more like individual user differences. + +Big Users did find recovering from quorum loss to be more important, and small users found growing clusters by numbers of nodes more important. However, at 14 respondees per group, these preference differences may not be significant. + +## Hardest Part of Etcd + +We asked users what the hardest parts of etcd were, which gives suggestions for pain we could automate away. We sorted these into several categories, with some respondees naming more than one category. + +![bar chart showing the hardest parts of running etcd](hard_part.png) diff --git a/wg/survey/hard_part.png b/wg/survey/hard_part.png new file mode 100644 index 0000000000000000000000000000000000000000..9d4d4d741d0aaefee291bdd543c94274afe86f19 GIT binary patch literal 14567 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 G?f(OdPnlH! literal 0 HcmV?d00001 diff --git a/wg/survey/manage.png b/wg/survey/manage.png new file mode 100644 index 0000000000000000000000000000000000000000..27bc704ab1716edb8c5638291a88914aef5b86ca GIT binary patch literal 24183 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 literal 0 HcmV?d00001 diff --git a/wg/survey/no_clusters.png b/wg/survey/no_clusters.png new file mode 100644 index 0000000000000000000000000000000000000000..ecacfa22ca990cb108d42a3705f046b85f41b414 GIT binary patch literal 18447 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 )D6-$q4T+Roo zgMn~p7WncX5)8?ii!zZ+g@If7`#7MG5n<0qc;?K_Vo7M8G3E2h#hKH8X1z8}3u^;n z0{2x~9ClpQ_s2!74@t@im_5xoa)S*s+R=(RZ@aLWaWLOtbdQ$}86nN5~HDv>~D z?q*wlOnK@)5+AT~`TNPgi|;NAw7@5a(-Du2xFGEQZ4-C%GRrzBonb*>+I>USwqrYE z-sik@RtDadYKShJbvO=e3Vo?j9FH@^diSG~`#ZRj6nn?|i|h$(TaPZ~jCaOdLf{r) zYKpp%w-rJifczSbcdlW$(irP$E_d|Kc~voDq4yzg%_htJ)H@OOvIH>g;t##JinD^Z z>kJhO{>w(y*+mk;=I%M&K7AtN6z2hj1x(u7nT&J38+Fa|4QlC^73{uN=W&Vu9-?$|claAjP>~)SIoBi*^?whV1MQ8E+93aA1mnhu@@YyF zj!%<&uPEp>U*R%I1&m?H^PFYM9Kn9b6ax2qesdi0cpmy!Jh4bpR0T8Vef2l>oOjG^ z7OstrVZDkZ$da%?rXd=zurE~F;aX&DO_&1=-@on)0H#)*ye4Y`Z6z_;7k4_b_RiNi zc~LF9E->G3%3M$Cck)=hauB?e8Y%0(5q%!nzEYf=wx+CAl~6Jfj&AtQM03 zi~it;nbJGVKOGi*=CkkE$@n9|eaMW^<YV+J zgG_Ob=2%ia6gtSaiU8iT?|;A{jpPadlg6)GcEyOH1$#@O_i+t*RTb^(%K^o?PAj=E z^I$11NLPEdiWrs3iGVeMg_3?cg_gOuB0?Pivm4DWp2Bc{Oq`g9-^ZYglh?MZ-!cs5 zxOTA>wc;0;UIZn+AXO;!-Yb&$(rb~flxGe(0D9`&^Da*PGsmg$Vf?mE;pLv16Y|_AhU%R z#}hpxcsmJ|Cku0zHWo8`Me0=?Zn`zm3?%=ka{&V#Wa3xd?O6BBDg%~Q$V}CTRkAs* zvji~JU>Mi0&VFMX@_4%ICsj~B+CVx-0e_rEFkJactPeo9Xj^jGZv3lK7l)v*u)xY) z9jXFa5HBg=wV))vozm_i#hVYT@8Rl1gPSH)=bBx_(euEvk5;ZM)NhjZM-eOR!;keE4bwl7g@I<=@lm<)e;XjsJzuz+ zBXzJF=7Mo_cRIF{kStLBHH@s&-T(|wA9WaQVdQs0s(Lq6*47*)S?Xx!RdMbMgR6>1 zi!6ct19o%}6@YPA^ZP6?jwPgoCEmmkN-eM|h|U*l&$f0GZSsdUBlr_#2PuwLr~~HPtgkZzJTVwN;2OsI~726X&gp)E7AJ zM7fGuZ(xXj0Ak!3R<5EA(9G_x4vH93I__$T*tIW2{?l+dl-cv5m_54nw`Xzk!gNS; zk(9&FM&MCCY~_LvI2BeA%u5?+C04{%P0Ld$5!(V6M99>&Jd#RT9>03yj+~ZnVVT_* z7hQy5*b=|Mw0`kBjxa7HT-cJjHcX@~v_oG5QvM@{J}*pRu=g4c`Jd+aw5Y?%yJtLZ znDIjYwzJ;3Qv~?$>UXv^lmemZSg<5bZW4ICdZ(yN7;c%w`cXgJ`TB44jf?!k%PTif zPYj-01J~6WZv1^VHgf;9Z=l$*qoVnt&*^e^6NYo7z*I+**r319cz!Ny191H%D)j9Z zzZrn!&Qw@@Q}5w86kgm=a5FR|Wl~D~uRQwLIEKO8yM0JU9&2{}yBZPVzISyy;DcNa z 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 Y=I!=e%i@18{|Zv&>FVdQ&MBb@0NYz8$^ZZW literal 0 HcmV?d00001 diff --git a/wg/survey/run_method.png b/wg/survey/run_method.png new file mode 100644 index 0000000000000000000000000000000000000000..8008dd3fb543123bb61e1459ee0f8ace1b4e475e GIT binary patch literal 12237 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 G-S}T06h)K( literal 0 HcmV?d00001 diff --git a/wg/survey/where_use.png b/wg/survey/where_use.png new file mode 100644 index 0000000000000000000000000000000000000000..82955121dd9795f12f08fbd26453825f91deae71 GIT binary patch literal 12361 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 Date: Thu, 5 Sep 2024 19:22:03 -0500 Subject: [PATCH 05/17] Fix labels in Hard Part chart. Signed-off-by: Josh Berkus --- wg/survey/hard_part.png | Bin 14567 -> 16909 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/wg/survey/hard_part.png b/wg/survey/hard_part.png index 9d4d4d741d0aaefee291bdd543c94274afe86f19..e771b6b5591978462570db07157963d9e31c6860 100644 GIT binary patch literal 16909 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 G?f(OdPnlH! From 4044eaa41a4b0c32b569281931e79bf99fbfe5ac Mon Sep 17 00:00:00 2001 From: Benjamin Wang Date: Wed, 9 Oct 2024 21:05:52 +0100 Subject: [PATCH 06/17] Move wg/survey into docs Signed-off-by: Benjamin Wang --- {wg => docs/wg}/survey/2024-operator-survey.md | 0 {wg => docs/wg}/survey/hard_part.png | Bin {wg => docs/wg}/survey/manage.png | Bin {wg => docs/wg}/survey/no_clusters.png | Bin {wg => docs/wg}/survey/run_method.png | Bin {wg => docs/wg}/survey/where_use.png | Bin 6 files changed, 0 insertions(+), 0 deletions(-) rename {wg => docs/wg}/survey/2024-operator-survey.md (100%) rename {wg => docs/wg}/survey/hard_part.png (100%) rename {wg => docs/wg}/survey/manage.png (100%) rename {wg => docs/wg}/survey/no_clusters.png (100%) rename {wg => docs/wg}/survey/run_method.png (100%) rename {wg => docs/wg}/survey/where_use.png (100%) diff --git a/wg/survey/2024-operator-survey.md b/docs/wg/survey/2024-operator-survey.md similarity index 100% rename from wg/survey/2024-operator-survey.md rename to docs/wg/survey/2024-operator-survey.md diff --git a/wg/survey/hard_part.png b/docs/wg/survey/hard_part.png similarity index 100% rename from wg/survey/hard_part.png rename to docs/wg/survey/hard_part.png diff --git a/wg/survey/manage.png b/docs/wg/survey/manage.png similarity index 100% rename from wg/survey/manage.png rename to docs/wg/survey/manage.png diff --git a/wg/survey/no_clusters.png b/docs/wg/survey/no_clusters.png similarity index 100% rename from wg/survey/no_clusters.png rename to docs/wg/survey/no_clusters.png diff --git a/wg/survey/run_method.png b/docs/wg/survey/run_method.png similarity index 100% rename from wg/survey/run_method.png rename to docs/wg/survey/run_method.png diff --git a/wg/survey/where_use.png b/docs/wg/survey/where_use.png similarity index 100% rename from wg/survey/where_use.png rename to docs/wg/survey/where_use.png From 82cd0f584ed3327fb79cc54e0679748ba096fcc0 Mon Sep 17 00:00:00 2001 From: James Blair Date: Wed, 16 Oct 2024 07:36:47 +1300 Subject: [PATCH 07/17] Add operator evaluation pdf to repo. Signed-off-by: James Blair --- docs/wg/evaluation/evaluation.pdf | Bin 0 -> 167558 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/wg/evaluation/evaluation.pdf diff --git a/docs/wg/evaluation/evaluation.pdf b/docs/wg/evaluation/evaluation.pdf new file mode 100644 index 0000000000000000000000000000000000000000..9821ea9db6ee1f8529bee05c9596f89023720524 GIT binary patch literal 167558 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 z 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
oQt&!`MYPG=ACjeAha1;S+Z>pW6TOt}CUTHs_q} ziy!am?EJkzuD-PCGPjj!h^EY^;@{CG>qnp20fk(&4WF85&mwU?)8n&pmA$y1!vKd? z-5|Hgac>aikZ?Flm?f?dR*GW0aDY%98X=sloSIt~9$7G|aI(;- zH07Sw=gJ&gjFF4=ZGn!&btIu9g*p=B-L7TUkhqQ{bfl2cdKAO@SQ7=bKq!n4v{%MP z#_P(aN2bN5#uu3vSQpyPa?SCbZ@$2Kf&F6joPrhcD}?ptE3ND8*Qjd>E{oq_z1e=V zJ1?uSN}~y9FcB~&ibw*WDBu*!`zK%ya;UZR{NR;A8jO3arFn&M5|=y@<0@^6npbMf z%kv0)$RyD~Z^n?lG!v#x$_{F0FjX2auvyJg6b-weL6Jp)$|PQpk8!e;7c32=7>iwp z9D2|LrQF2jYFi}{GJ&*^rDOwotivs0QZvRF3D2Q^u4E6v?;E4JM&+OFM-`PEHc1~fV#NU6`>0E*|k3GQV zD{9ts)}=?*epWl1lLr_$%z6Q>X*Qi@)0ak64$aGYIA?m^aCMtgl}FK})<#1?A$Q&| z?~NyGbGuz$kLcxd9~mW5qUkZ~jK5sGm$}?fIFuDGxs|LtLug+omKVH=mj zh@>10lV~1NANW6XFt*bbTO*nu;W0TvXc_aI5%MVEGKsrdxm+@2h0@o$arvPxoqp7% zQI}@auo4a1Z|!MkBDHWLd7$|dm3zfCtGtK93@3~OqVA}J=5*zX>$`%I_2Gw){tLPP zl+0&hNE`}%po(rzl^CtYV!t&|Tx2aSMkB{v6&zfAa&fb@xp;wfesN2`_0}tjZu8t8 zc);rJqfZPA**o|dcAx*jKHL3|_j%gCr_U?y_xcz{dI_O!S(UmGJ)%4X%Nn3F6XEnvee zD-!>~eCddZjIIUDtPGA;|sxO6Dv(xI$i zm%K-&VYybOvWv4fcLvLv2*Y2%k0TPLL$mpUICuW}@Ukvi4wS@_@t1-5~n2%QQh-&4nxzDO{E?=NBxCGr7Q} zMioB?R2DM1p%f0KT#R_!ZkNX!O9--JL+#7v@0dxbnZ0AdBTtN8F=oKRx95_Ix^4^B{x-ux#*-ZP(G(p0{9{=B;qxtC2H_0XDetH-%))<8krbav@Ujmvz? zuBuPXJf-h>hkjUd(jf9)pOD&TY}uHW)5o85F0(eTz|jNz#gY-qMN*qc3P1Qr+;S?Af$_M9E)2)|`{ z+xxcv!<>J3|Ka~AcYin&_D7^Ldzq`BRBKO3r`jh-XGw48ej^@LEvnll$`pbjSs^BO z$Y%EG)`3sg9?a90igV^J*lQ-LIc07!x0*%GvtZ^U#_Y>Z6_0QkWM*b6qq3P5!gv#r z{hT*hOlmTty?G^ZP*#(Jvx}nwoP2PId^~WTXE=_b3V}17z!^}8Q`$jLHIMjM+X#0H5`W(4s%}eI zXRGBkW7W>AGY++z+S!|189U-1cf~QDL*2C;mPKPYYexlzmYfQ){6Ycs)3K$5()+h9 z-*V<7%Tirm|M7{1v~ue8tA2m)Ijepz?d<&Ky7AY&u%hd$t~Y*1Zr(NZs@*T{eRem~ zI}oA26tlh6Yt7-11o6A{XYg40*77`AP$Qj|CoHN`_5z!M%jNta*NBI8srqGVHRq)Q zb23Z_5JFP6Bx>9g;~OJ^673Rt1-wi0oS}d`wuzTa!kjdMoe9Pn0a@X>+6Az z>N2(Y0RC}<2w6#A!6IHJzi^7>WL8hN(ZhI3sM(VH)gRvO`gZx}S3dl1_!0l5)7L$C z&*clQC2PEo?IF3u^m{^AKXPYq;i9KredEbrq0AYDytGgA-IHCZi%e9s#;ujskydGd zYe48UI>j`}H90hw&X(pFXSrHJ9pTrc*K^+Uf1LBN>nrcy{U3AL;t7Y70Va^@157$8 zeQANUuV*kFV6CTh)={pLL#LUhS?5|mmOu3zC5LS)aSJxHYDbx4RvdsrN9ZMVzI%)d zoeDbW$-8tmYoj?ppweW$o(#g5O$?5Cl+~6!w_*6;Z>)N}NJ<2{Mqlk<@ z#w&u7$Hx!XdrF=*t~k$dLqZ8~p7G~ZPUspGhZx}*uI#pD`xKF@uG z9`UK*A$F_RJHgZ9S?UoyA^Qe(lS)-p42Db!?4%E}QKC!sjua=AiUazl925&)%^%X+ z{jE*>y(yf-zRN9PtL8qD8S(`uv6U5NEG(`}TZuIg#=EWYL?ydE#>}8F3454sXkrC< zDl}o5^^tQvPz#h)L2;!{Yi-nP5+Krp?jcThO;&_B#XX$*NcY|vra3vblPi{SD)PXQ zWj$O22XUs9Jiz5bb4};6n(UHqcCCk5Hp_Lfp!r{1N|Y~HlW2k)H^Lb^OTOIkdDmCO z_3rD$Mt=Ov)V5~U)tztCiIzdruDs|0GR=GUHWEf1Y9W2P-tYQejXbh*9=Yj?5%cb2 zIwuF&p;dYnyrd|V=Q0wzzs%pypYkvD-){M>^#Q9PVC`c~`#b!ipLJ_05U$KMSOtqc zWFl^wbmfTbcdItKh%1xB`!FXZW*1<1XL>D~i7A3WZy;>kcWmuHsFGb%$xyg*0}y|T zjb4AsilY}?eAd&4&wBFNc!rYfeCO+|H^!Cq#(crmJa=0&EzkTjk8!K~ZlC`NvJ;|k zgqXmWOdjbu;FwGEFwTbfs5_WE*vzIyHOvivu-Z}0*DPGBLpCb10qtJZ=nR5Gwg*X) zB#T$CCP^HR%PSnQ0Tlx(tJw4u;K<8^V)9I?#cY;bCFZ#6RCAq6Hs<l-U692y&1cxvH>l1(Mb!05oD+LBS`QPH}hDbXoK^OafA zSw$@+ttD?4eir>Q_En+7>yh2kGFGKZRcau9$>s;&*z(mLab&xm(6xAo9+H&$;v1b&&hGehUv1bBSY;e zp}C0W!}kc=S9X96*#qoalXaCY^RmS$K9?xOfl4(g?Hy3z;C_lk&)p_xJz_2&vGU?| zJ{wt;e&^8Hf4%033+|iq&Za+oaqE2-U$pt*3(niz5SSP*pFO=QeHE#B?-oL?zNPiY z1>fyC?;)Z1uN}Kydg|Gy*r;6#Ah7>#?;}xp<&_+A+>OdV;T~;kGQ9U6w=aaBl|CSLd}kKs9k{a>6Ftl(Laf5M_F>UNH z?lT@TDqsv7ml|7*8?#aSjTxgUY()EA5vgF51xDdgUh5?UWJwlHvJ#g-+$e4m(_)9X zUz9t+#@lIPtRRjv{FDin^Ubh~ z)XARvV4Iis^j7vh_~tC6_quJ{wuyh=v*!o5nE2ssHcFA2!gokbGktcuwvycKtTpI} z$P`~+t}eo7W2(07wE>Me zGw(z*7Z7INMdmnA9!Ys5<&iW_2-+33Fdl~#l0DU*iw3^p4cub@oI{vT0!0Cz;sKv) zg5P5OAUgW2o{9k#z*seFE-;t(vLnppjgz|UrfIfr!q-}QYDT{i^A8j|X#HEeI49luP zmHb*cK)d$quU)l0^Bt);s!6*PmNrWJByl`~Ly{1dmP)NsMiNo4n5dws8deflIc~J` zHUjB@L+r;ZkLjK7j_IA;9(qS(E6qYRWX)6EJ)gUGDbh#0XbQbqV`xP)ewh{ws_L2ji4xwk3EgcUcJf)-X)PXMmF)r+4T-e3pWG@ir zTBBiLB2VBVFZX96kNfArleLL{)MrnJQ!Z{CX)I~eq+mh3ot(EdI=Z)ota(bgG2Fv{ z+T3#=BfIY$S2t(mC(D)tn^>VPMd_)sjde_+>ZX&$m6LE;96{o=x^>e@pYtA1(IV@+ z`HG;IZ|dfj6`y?dw6X3izi+{+--IuD;f@El#+rsMy>VN^>{C|{785s(n{j5t&PTR) z7Si7>nlbpMdpdtZ+s-?0!fn@gzLmA8Kf#gYAzM;8k|5{M&1$>)k??8GA>l}lEHXWr zk1Th-N^Vj2`u6)WJ~3i&*<2ncTGT}LSWWCV(R8M@=_AgTU42EYz{jmwYA~b(fi&>t=#~=5anIwn~^??K|Y7 zOMRPsX=w3PG^b5JF{d3p%xN(z-8xdvpPJ|6 zyy}sj%eg2mHM`k_~ z3z70x@RMEJ-9Gj{Ioh`^{0orJQgayQ=Lt^5z(zUI$x92WSpcnJDWX|e2b;U#@Xs(=VH%n-?_wXlqKuw!W3zW>2%8?VU9G%w8&!e zhD61Ig36_Hj7#@|y4d6?hfjtIf_#o0X=}nz+Gs-OVhp@fc^pID&q>Uxfds>%aYA#W;OTb4}FIc z^NBJ`#yDA;Y&=ss(EJi08t;U$w96;EuMnSF~+i zv$l=qkiu(Mb$!se`|rOZdBpnCi!c54nHOKc#;)y}FGi6ooRCLuPOY@4rRqs)y(-p5 z(h(Yt6j@@qk4X0b0yv)62R9xG-wM#;9cXx*%1r$(N zupq%bxCM82NN^{(Td?5n?(Xiv-QB-hIp?gk_SyUFcJBA%-rH!^T2;+ivuX_9F@N+v z-lt1tjNw-vDQgUQFgB0hc=T<3idGb4sI;;fc~c7N+JtCpCeCN>D&UJ>pVl6-5%X$9 z>`S+x%s!Nvn_RDQ+&4U^a$3~^m3tEyy{@Sfm#%`IZ9 z-fCkD!svqY`qkkB_lbt%s_<=@W<{=f>s8-1290(acp6GcO1T|vc2PR{nlil3uW@u- zV$_t(fQ*B$_T$vms z+FlSm;f{EZ$$n#of}UO_;ir=p+M~6~<}LXk7OdC=^AmjTwwo)q0Av#WEkxDy#CrRM z#Ex5>h*C?n)qDKf29C?5awzw_jIa0#_UC535gA?l+zHqR;zD8@+zOc#0HT4psGkuc z^F`W&Eok?pPaVCAVH5~?+hYT5{VpZv7e0^R=uuaNa{QJz8Ff0I0|eT1;`s`N@fa~> z1LI#TSb<3?@1Pn&@^oC}z7l={se_Rm4G+K(%o^ z&)NxRti>)*pAt_&#y26H?pFcNr8=j?>ew$GDf1|xxT8IF)V!h8yy?`urIV5-PxDh< zXQq(+Z9^pxMbND#mN_}wQ!DOY&|71-%dR7D$Id=%tZgP7zm$WKa2Yy?k7bvNuOv~B z%l(laag^Ko3(B?1pQ+q!Po$JO`MdV!4=$80W-w-Uep2RGE1vw&OeU~n_)(kS_bA3c z;Ypg2V~0x+oYlHx^YtD4QvsolA;{eW;nn4cvr}i|>*A;EYEhLS_(%M8Gwi6>t-Bkjh8MBdHF4?6?diVkTGolxza}KT zhkMbZTQf_)es?K5dvyQkAoi`z+i4}wbzwd|V>`24hFFtdX00?@ipijelMiv#*TNE~ ztOh3Ge1zU&wfCmIBD7YEs!0RtI7vy*R9ng}j*_rYaYP;pw1yAoQxSzd67Va3Jy;qb`zG3U@ z6w%Y+&a~5=8LORLAGpb}%W$+zc^*Vy=C&4inj2f?_L|S!IHb{e0weOP4SSwKv0Zo# zJBFN}jTWDbnO85dL3GtN_o-1dJs#&5F{+USo?aO?cEkSmo-xVP$~{62pgf-tJshC) zn#@87S_R~#bCw={;e59t3}p;{I+hWw*YHyD>nU-}{{Vo?Q0Uii24doLZ3- zIv1yPGEn-~<-U5h$a5x8EB-thnfW{dfu$3>QbO{V+*c+f3-}z!q_6!PDdj+TnNOiq zO@VJ=}iK zDYqj16jjXgV1W^tF{;rhDE8d&Q^cG=e^=Cj_Kri4j!8Q_51v0stBqO2O@+(mr|TVu zYPbJlsP>1=lk-B?lm*+H?%+A(g_|Wy1MEnWa-Y@lhU?^)Y#NzXE25H@b;}#slQ%hi z-+#!MLO&7(l~rlrTdqiQHeipu4y4j8Ka!e`y0;=o?yYk?3N100+1=9&E%0@VIWmvR zAKRlz^KxIm6L$6?HzpF$VS|BFDJV(3lnpQh9B#dw&o3v`O<4^*WFsH0o?7_m4=@3V zXXj9n&9(W&yg1g`R;1IPgWrmYNRAHr-(LHN-qsN>A=f~rTHr;aXjq=+rq=lDEE!cO zl(4gP5u%00k5`Q3m4J=ZLEIhjbN3iwQeDBzpnh-yY%%srLqU(=PZM;ayy7zP7*ymN z(^sqO@RbAeCt*6?$|lT6xD8UftWeC*kJN4UwSui!dIqrEvlkdTpu| zkhaYt9;Xe~eLl(8;=ami&EXS>+4k*L)I~0&rL8Q~crqtkcJ!z+9jG~?+mk8Rexs+P zwj+(TvqYg466_EVffo#xdW%lAL6+myA@leRMf|&mgwRu%uZV~|rl6@J5ErQYU0&Fh z0S|6KguLK1F{!00?bGtg=*iLXi#7XW%Ii~x{kQZA1>UST(shhWzy_GNg!pP~2F~zE zCA!NN@ykHnl8V*lnHD1JSqg)c1?#n5jz^9AviTK{ahG`yztgE(0@&OWr>EvQyyci6G2_O&9N+Xhk+XI`Pefcj8M{dy11PzmV;cU;jn$a~E3UXqmYyH(3>2eUxCGxR*&f5|Q z(MqP@6B8`a+tN4CqF8DqD!yXt>U(*X#2%VBg&uZwgl<`!@Qv z&ejX@syr39uS)WeMd?wtcp>WoZLH0pe;cnmxRmIb#!VSDbs^ESufNCGm5uEvmXe+9 z3!9*Zjn5@bII+YzWj&O1Ut6_^$9^laW5!w{5fz9LW(!ApE;z?Y&quZ0tU|(Cf|L(; zCjOIJNDP9~?EE$B#BEEXuJw3DDKly=?XU29g07c`{rzl$n$_(5)z6PH!JF3=Q)1qC z1+`}9kqOV>>#|V=RM|=BX;4uaQ{x4`&rsk`H*qh#ki2QUX>^@`hUAIi%FY1r>tly5 zGMEy6wq!pp@jpD?T{o{)+i4pw6rE`uBMPAS(w#1%I0||cz8zcr_!NB2`5=3W(5YcC z?F4bF799dEJE_SyF)5g!w?f}bC#k3^KUKK1V;oOAzJFChI%td=FGuZ6OvI%766RK$ zn1NPPv5A&OCfZ!}tJuH!ZMhJ{`>;JVc+-xKtW8~gHCzg<{`&~XeuzL11ioKeaF5|u zL}0aOSW5K4=^0cb+GQD)(gh>uCE##_?Jd6FUgPfyBE+5=a6Lt^*3&keV?sgLPcH%r z>bTE7LiF#jIrS^)MoL!1Q0V$LWCfQ1I2Y6^4851quxQrgJM?3&W3;ejWw3He-d<{9 zF$}7xpB2!juGB*nQ@c;G^};qbf)@N!jzr1I`s=7E}B>=J)Lx%lsUHy_76LYaz!f) zW$tsV3OLy~cI@obcwuVj>?-uIG|DgYy$hI|jU_N>#vmR$J88MR!Q87{hl@>z!5AJx zL%AtUqgX>j(o_!*N-Tdiw6BMd|B)OgL9|ktre%bDd{=T;hy?!xiyX} zpgy~0ut>1R5@!wT$ZRS9H23l8dHtn!Z6e`W^}eV>avc_=-*%XGli&3k&D>?Z_v6-b zzW*f?YUQSV)QH`Q$NigLytC5>Qk?$`GggNRZ)Epq_>NUpj#EL#Gg4MIIYA)H>U80vx z983*XN5~&ymVR zQG88$$e|9Nuko>S)y-4CQhUu^&-r*>n60ZTgVzC3XT@GGk_%>H%lfr-cl1$q`2#N- z+j}Sd)b~>_9|ld%f(_N@6d@oyVDQgqVE>sc$qD?6-}x6g^K*_k+5IKep6|D?o%`LtX>5F6J&QeyvrRQ?@W$?>no z`X5}`zeY^@drJO+68ql={wH?x|7}1l3m6CsWYHr1gV_pXX997tu!F&{0Px!Y5DS>b z`4I7vA;IG8{nRse{Ujf<2GMEWO& zmX!S;KFakcC6n=wH7H3>^L2ApUy) zuV<`(k#WI*Ta7}>N`pMwK;IaHUD}Or;JeI#M4u+bNva_(0 zaf2ZJb{#9B3j(^I=2K+nyR4aNc!j}}a_mm&1?<7lJ-aG|2 zX4VP=<&nnx_Rae+tr#r0Nnh(W7R9A660uMGJ1K7h$_pcF4j2(WjL_nj7azv4vxIX} zeAW83SVX!bbD_o{E=h{|ox2EK8tI~vGghWYDQIaV4O6}1pDpP~Dai2Cf$#Fexb z_1fA`J>Wpg#eWo3V}(l_x|%(>b%MbDVW}lqx4Ptd%sUozS^Uj*E76HU6fVXJDp5s? zjFz19lS=9`Eu`GV+CzY5g3MDjbT%6f(Z|#TarYmDbo``L8b2r|RuxlKBV1I7zB|#O z%`_XYG1jDO@aTnb<f$(l-$f22kW#!Rw7$3T~*v=XOukIziZ3muas7))wq zBBR|H%?=yQu(TcA$7gK}2s?81`hbb#DXXsvY$mTx|?Vng5BJ``;J({}!10$BpH`0dxPTh`--^xc;h; z{{rR$04zW-J^SAk43LE#@b`*2<}$UxGrxpF23HqLVlfN~E?dhqD0J24UIvsudQUxjp5CpxueqPPKVL(<`Rd?tMmjq;d*8rn zMF(+@(p_3;ZE0GTHeZjk4uoA(SzA?G**@-v_$5QOyfmq;$uWWT!s%B=N@#I9KR&@( zwGQ%2pjaj%h6}g#wqAtMT?{%Caar@LudO)a^IH?STk5FDiju`iKZds9NB;isOU}dt zkyTL0(_h>f5s3u%iL3I3|LYdcn_(1-NIz(isqHE8{7Z&f3i90cMtr?gl+e0JsUsaz z&J~pMb{O45B4VUK(GQE4+yb3~nz{qxCa;P2#gNAoE&a?V$l)R({74o8_!l-C^LuxG zHE+fI$Z!Y>uC0#*@FQ^rlD){% zh61L(LoKx<5^`nY5`SDKC~*EkNguAYxT&-&&6H}*1F}bsOKncRI!?HWk=g{}e9Fhg zXuf2=eYxRWQkZ+?rL*AGzV`=j)>H*PiDU?e$ELWt*?w$L! z%e+y8`}b{$Pn!h8Ws??qH#YC_8+Bk0U12L%zu^*7VG6^Nv%KTcO9bh%lgG zmwucHKkl7BOrU~9m-ohQx#yUMTr_Mh8~5UnO!??R9nmH*Yky{ZhFZJ3j$3=lwFoKO z`F!?Pf7KUFj)l{?!}APRs-wy#y4Z(=bjP&Y8?I09gK7INrvB)U)Pw~vZvmcI5O3@U zBGxV+3Nx#OBCSq>=p)Sc3(U#9UwG3G=*w`oon5q^D1_gd?#7P#H)AKEuw%hTUZ4-@hYlgY`BJGc8_Y?A4|g|eBx_$}$fnP)C!)J3FYixVy*ao{MP z=qOXS7+MviUL(Sw9$snTyT=BQzDGQ625_tf{~)RgDx;`Pcu4d0k=6V=Yk+)kuO(K6 zTU@z@A9A-yd0P@=370XZ6FL8|k>%GGipr+wppaOJS#S&EKDyDw-oZ5P!c_u7!1H0P6j?XlBv2l?YNX=}Zr~ z?4183jjNRf*EIC#7iA}ntL>#dU!#fP6mQxY5lyD&9!!lGC*t1`%}u6I2nU&);AdkR zITs~0(H*!KD6thIb&NS->ErD@xIfn4! zA^mgc6vIr**bhH}S_vV+56Or6&hN6*O&()5Sh#a>iCs@Row|559KOg7m_=Xr@$4A%vS{kuLRwZ2__Lzy)^Yf8V# zZOKZLZx`55#)W|`l`$rjH$Yd@wZv;VvzR>NH%lCsDz|ccwZF7nqAv4ud|?G62+c0T z<7rExzsO2Owg!et7j3jC-hfcG3WT~TeLFC-`3tISjwgbTK%xB*SpE>BIrY`&C_Q_G z;<`Ya$eqyz12Ks}v(H~(R9ferQ`2-l{t2a8!h*R&xe|Iw$KcVT)OJDCyxS?!eOskz z#;WEu?#7;Xu9#}Ko+%>T)dIkqj+qb_TU%yhSh|fJZNKIrEL%e70#VYVm;r~b1F)6X z_q|??oYC{@FjG3?dRFkI#}B@$Uo=wPaPH}j<3-{oAkC0WqJ zH|pCSHikGg^1pOgNl+LjsM73OF0}29e>eRlLdl&j zxJ;P<`$a-;iuGI$i1#$cke>j=c{vG0X-L1nB>C`obQz%ayccMJs++|;U|J#ILjg!O z5cwG<8uXEdfo&=mjCj$Hy1-$>F*NYd9OAOts_;%rrsK%qZ#)#zdDJ1~Bcb=%P>A^yKfC0%+uPi1EOmSA22K<#rXB9#gd1}BlC1C3ne(v=M=>*e z7}&*NR91$9DyQXHYHP=5{HC;me+D9nvF$z3EEjbmmTdMo(?XtEH%1720Fab_l+!WO_R8dXZg98l@10fqn zgwFQc1XDQ1Iw{X4Tfq^NXUE12+uJasPBpc4&JNXMM!fdacI3?2`O9-^zd$%?+-sIq zDZ~tR&X{c%_Aww&Qxz5Mg9WkGmp*5N1(+6n9!_jnDZ9X1Tuhb5tn_z#h zrCfc{3#S;W!3EoiRUKVXtM*^av<3+J2-My@k1rH8&(AfES*UBy*QTwJ&5f-^_FVy^ zrPql|vg-+(peqwF6G_@AI2Vrf}P@o|GeyJ7PqF4g2#55idEgtASk(S%pin`cIi zQ=(MQ*Gr%3o~DznKJNz|_EA4L-?#Dhy({Xr3VvyTar>~8)Gg$n?ktz2JvLic7W}@mwtJ{y-Ws55Q+#$A+ zrR>&zg#DMfIXN`OM%)ThjPm998rSG55e~yX{hA7smgFU$8!CCH;`Tpv9Rt*AOX{y2 z=GtTUP*M?|VwFZ(m+mA)56UVpIG*`C zwcWIOg5znTkN}+@lRpFOlI2XFrVL$)oLlWe9&L;~ zUX^z3V+gV3Sb2ii`7M>?nfO8~=8Arb)K9H>oy86CsEXW6+MGv%`k%8xc_7VAtrtZY zZeL$RUm@D$Ofz6wj9{)VK77-LCh21~Z?5Naz|rzfDl*L*)yd0uoOgf-iMrYIt{bT< z)tD zP;@mpoy_yIL)ZW}U41HtNN+UW>(a_*nX{~4|sK{DvQ?i-IfR}hbp-nL( za`e$3wTfngrQ+xJpYixJgWt_URh2wbAWL^@1++@0wxiRcC9eybn<7@T-ca$1eV2bX z+Sx$+qe07Tb(skDFqV{pJa3a*JYTifv{!uFjQefjTIe{?hR=6Xw+m^j7gR}EI9^B# z31DeJJGJkHB}goXiiqA36)6@A-l&FrI7haQ$_oY@ zApg|2k+Tx8`n62|SR>m7Z`#I>T&VvUQ#n-Qz#55`DefIr{+l|eaRbUNCCzBb*lp8e zeWvYrP1;c3gG3P-i-`OF;F}YOLWLd-qHhR<>t;SPb{2riw^QUl`2)6T0+~YNuIJr)`|+G7lIGO)Xu-#sdw#Oa9Bo5 zb1&$y6b|uK(1wioIvDieuie>ycVv_?lJHA%BN`M2^-)V;SQb{`?YD#&aaP-2IU@pL z*%*q7cNzA{5@u{%k)$*|M8TWmc7smgq|^D#&GueUX)EB9A-1b%?3AX8ewH)!T3&p* zG;INWohS;8l3pdvRnd8n}M5$g9vG7@t8Tn(N&iPa^ zth`l!h%L2q*qK!&@@&@Hdx=7=5T&AE1;^A%;@Lw?gxt@$W^rHkwaa1-x>JcheLm&5fpmLkBggNkE>HXz*a5<=6>6ZUj2R~%%-oCPHC zze7`Am5=57*(}Ha-t%CAhIu0{C)jD}*~e6Avbk&>#+tf(@7gUVNMaux->sx^ZUk6~ zAd=73a1{g>8u010Oj6Duk;1eHLl(lZjZz`^yA2936cKoT57z9W)R#)K>8Wr-CWrQe zc)@hsbF*h^4H{`6-XArV!oCt}99bb!YAs&oa zCz*Qcd-hw@2|rlCcw|G^+h;*TrcE3C(_nK2XZJFUV5&HWOtVqxglu9{EZ<68L~?BB z$RWByqobY<0Qf8{Ar$aujOV)+Mc&erhCFq5E7@tKYHBw_ZxxiY*ejhokmWIB{SaE*vvj{`+X+ue>m> zjA!11AkNyEgY>@gwV$fSwSWQ>H4OpFG=qvt666~fWu_+dV2AS@q(hjow;$7toj8BE zdnPK&aBCX@yuln2p4} z@F{^U;~kf1_BDvwsI(P=Fq?iNv)un3(pP7(`Q)p)Eb$>4VoV|Qmb9tGl#RaSKwW57EPOJgaBK>V__(hMMfg zd-SIqPPrAQ9v=C=;*_ahXV*<9^n*RH~o9 zHXIDh6%No1k3P+OZ=%2RZCbm2Q)GNz#Mgy^q4$Qo2RU>7`p*qx1o^U)e5PraIpLGB zToc3H(gzLefb_@a+LTcR3-46c6f|kzw+R#A#eAzqoCJzo3~?#7Ou}-`TrhQGK9+xc z?ffieqi_tbX^^bgRN;6(eb=X}5kdCcxWZZhBBX7TS^>yyemPj&hV=9!Ukygoo`5+M zwFw{(Ip2DRyFG1_=yUT!c^J+jsYG*tLa?E3+Q)pZR+C*EL5tg?m4dv*lt|CvZX0|0V~H_Og9 zczXMtkX#MY{3?=c;BK_t8R8VV*j8oWP76@tna*&S8`71)yGj&7%RTu$CusjJD~s6p z1ZaZZwXU(e0jS@DkJ#LqzW;eGkvh2?A(N@|<>pgoGgGDbu0dRK!11IP z&UFv_l?2RLy&OfskNMD#Xgb$ZHtwaxw0EDBDIb6{SmPP7;(1w=3F#<%YSg0{388Cd zbL7!>rW^iwHJ1%nU8dTn6ZNYS(~@F?sT-!ajRoq-b~$3QyiXN1Qjo3TR4b^f274-Q zaaK>7A{&-UEqW;aigt$7P)OXuNDs_gwJclztVx2U>Ob?+{?a7>av%P~jgZl^1k01Z z?G`}>SsOzuMLjF~-|2kd-+!FeECE0 z{F?v@R?+{(!2j8N`D1?m!F>7Gv+$>e`~QIj!@NX z?JNK%IQHGy5q+X7)|=c_^Wn8|9+Nxq>@% z#x$A4{734(h!UpAW7vMX5-U(DQlu$tKiE`EX=l3Qy5#A0TO+$CeJ})OcD1UOa`9YG zO|wi_{z>-g*(hE!6@h=kra#jpoWmt0Bh5mo=NghnF^c}5mo?yT^8R1T`rla%|GKRI zmxjad#q^Jc!|(s`-`CsUA_M=+aNq*4fD=6bT?Mdn0@?pw0yU~|HkhhzFHQNolOS|) zQqdpo)5Ex|8_@#dU(ZR&$YkJ%T-0F`C-&YVP(s_{TYL-eIHtf2GcZ7GI=4)9jI20! z*(^pW0y5(z)z99S_&*)y7GJwpc9pT0EfbntJs)l#&2kDo`j8h0E*lpckh?xj0>O+k|< zyvZnnhH*kk!ud(~Bpmi3@ran0!;Yrcogeb`E!-9zw*nYby(pK2Rjx6Rn|vtY%>rAVC!D*Y*e+wX z;TS04iiB4uef}sfHs&XjubEOP#!pAgr7tw@uN$MX+THURE@Q6T-x`1Q)LW}@ypK*1 z;(}5SQp|)-eOuB)Cr1I?TnJFiT%sH7Q?pfFcetoGrbMQEl-QScS`+-F<7^xq`*Jrf zqfmcCU{6je`~G6!NlkR4wKR+W4fpN!4bnQ51wqIyLeCk!-*5vdRWxmEnCl2D4Sci> zdPJMyl!zX_quOi^O}p(6X!;zKZy7bK8-Yqp=?`vReUWkD;SBPs@W&N)Ck@p65K#!4 zroNY~MXHmEi=vRRIefeqw(1{Dg!4>aE*>t;*&ZK1 z#CvTvoNA<5&+o2XUNYz= zX8+}i8hbfz9~{XqO0y5Q=K{@*80H?Ky_1YA)Rr6GBKz%<=nQ#ss{8?dMHpprbG$V) zV4v&ggT&aRUSlM2CL7@k@zHU9)84zZfDy>=`psflr>=9#eS*f&(i}zIml3=2#;T$* zj506Y8DrL-?Ok23a}|?qClPc`0ax+F{k1 zCg|EvTR?cP+PB?F0fD3`#pp6(LeiauJfec&8&(XW{9MU&XN+KR(AH-}c&AF&CzYRAu~yC2J6agMh~rM<7#`DhpY`r> zf1%N{$Cwjz_ODdqHtlHct@Tpf$kFIaoDs4eK#Xd;%uDm}G7IAZ5*}wpEY+}$KMwm! zqEr)&->3iw-3z5$e;)j3Zn_W#shJKo(K8SFhDy2WX3?D%&y%12WZ8a!!rA7*PQ19W zQ(WaJQ$0yB9&EXcwi|2aZg6jlNq*-<=M50+O(GjapcRda_|0VHjJRNPFJLJ z9_HAVHq_XiW`L&TDRz&0E#3Gi@8{ zT}$W_tUFr$BLZ(~XUHt-eFAopoxn*PmPuS_KDLuohWh&iDZuuIkm5}O&Ol0@3Kr8M zd$^z?u994J@wi0>`-e70>((+xolDb&Z8ghLy8=eZm}<>^t9^!nDD$0a!+7KBh9ND> zP8GAE30C%m8-qDjrl{&SjRc2J4ACBxE<=2l5q1?L*}>|iE_HWtd+ojW!Cd~;Hj^eu zWfDyzJHUWC(-^W;79YkVyoGVAdKuj5*;cw_bicqF0~9_HDxi5-4C91qg<8V237vfL z3aYe3L|{$w3TB=SS2KY%GAkuvZNaQ!q7Az6J>MV!jk<6bwj;S4MhFYMCJodV`bTV# zg%{m(|2;+Yz%4WuC|Wy%Q)2zX=DzuUNYcLBXW-r+YdbC!UX!WDA)wwy&}%y^{ zSR8C@DW`^IANqF})4ch~Fp=0yu)&OFo`7jL{j{@w_qkE+$2+R^ejRV8{T|8Dp~daM zfb=kF0z6b6u~8o84C4Fqg1|9C{WUoW5gv(yOuC>t+URZPhW^7LDH*CdLpBl)%TTCq zo#*|+WZ3ty3JE+cVwg+B9^Q}Qd7F>SH=f1@LsO8uZCs6~#*u_P84RVU@ka^V$j?tw zr*SAk9f}>36tB;2pKN$tHr#i)$Ew@;ortr>?&-LlnJyR&xilpJka=As6&@7z65H=p za5d{Q6-?YqEoY;tsyb(86uPV@6?|=+^k#kx4t`WdSQyp|MCWLnztx>R43hfgwlfk* z!PnWln*kFzR9{NIs$pXE<&*6|SSGuvLVKtQ z5P9DuP;76w_eJC~hx5|4<{xWKrgO7i#801nxqe7Wsk2(K5F=#_bcWiB+}di49!(AV z;*~yUJ|e395h`!%5ZRWwd&v9cg)J~r(<^pC`SCP{d-Y{NJooPAnTG#iy>E7oZDj|QSspZ>To*B8BxN0 zHBfv?7Dr67aY8=N=nNs(~U(&+g(<9_PebgIa} zBo@@Cj5#2x$@{*}o%cNheQl6ZZEvs7gH>i$eY=jLLKThrOLO`uQ}_y_W4)H~O1ghA z%%Z4v3_gE-jXT|Y+MR@rkH#%EPIebn2=E>a_ob8#$G`ZC`!~(=-G$!l79ij-7Sh6E zzPq5t3309Bc#w44U3;-vYRETh^xK|WUFD9Av8CjBomCVQ@$9PxSaBblpy+a5bG#c*gF!i3t8*S3 zKiMkn_?E`=a5~>wQdXDW#4v#uX}MC_V4&E9-QsDWVLlX)*L!_9TdLMlsAu>rwUDsR zh@p^#S7T=B+5Du=~0;x=vvAD zIpN~oY;LcH_RBOFSf{j%72@w$wDmcwptXlqQOrhJs3cNQq^Gi@20o`-l*-7Vw-W+O zr$u|LkbE?!fQ5?NhfWY4e#ivxVrP(*b@~LKLa_vIb6K=bjSy$Eegn#+Lz4QM597XE=s9%*(+=?&RTu8AjZMTsC1M?eaPUR325+QwEP ziH|vQylBREArP}IR#nqj4ApQH2be2C-53DzX;V#H2DEN&V5tMy5G+oTx%`5$E)T)f zBJoUB<1`Z%UWCXMSLY1_+(?-@T)J&opgDWfFlaUHXos>ANFsIh>zm;Oo+1z9Ta7f% zNjGcCD*-cdX|0jr^Sbu62eX<|1oWc_XFOyjO@aN%;^-{uRZg$`?<|7i9jSKPjn)IS z)bqHgnvE0ge2bg`vsF9+#UmAFJ>P|jFMhl+Xjog#@HK2||Le*pt zfYEM4KAId8IztRwBq;YI?WZAaapZnBR-m4O$#8T9n@8HGYNaf!ydF}7K3ppW{bcme zZy_@nXAA)t*10sJA)z%Z)C}p=S6lqAb==g#H+x$=Ux7 zkgh{!AjVa*Ktz~-W=?7W=U%VkGD`?d7X7&V^tPPAB1o~Y{YwYJ$Q}uL25mgAu?^NF zfuQpJf=LgmM)u9s*?G~t-0Pm7T9?4OWrAhsH+gS1MsLP!CNIPDAp&+@L8)r84w%qm zqxCSHH@aMw;kGu;B@hr@vHJEdqyT~_pA}wea~`G7kKKVnnuc{BEL*4ii18E`N=%2F z0}1pg>djUZh9|f6hf{JpYrkkE9jW&SCyI~$N=SJec2N-@J;bm!M$ukKLYRjs!o%LS zbyr?IEM2m`GF@jfj~zPs1+63Qv&gpU0^!ns+-viafuq0PYiyKbPD z$QoH{S-j(y>*~PN;@TDwE98ziYNN$2I>H`1dp74{Qv@TQb>AbbqH4B|tBw=~FG+aS zMfQfZ`0BWKcWG$V2g^oF*(C?dII|ElRXos9Zca-KbW_^7YMc(98ZE&5)x)HNMAq7g zA_IK9c=XCMr1$q}<+utS;&b}xW2l-?rOYyLC*K)=eR->IQ&DOhapOJvvevBwa~>%< zc|`!%t2Yd@!~M8JI2Jx_AyaD%az7dgy0Pp331l^2xJ6h>X)cD?(e*-UGruK#0RhMW zson7#A_q$G?zbkAxUi8CL?ap~I+Hi^1V2kAx-u)JT85m^h1-|#;LDfB6#7ak@JV2o zNE!ndj)=DpA_A}s30kYnpgb(~vX^^n>HQ_#g_;NU?|v;{M_%%GdmH3!XcQ)S5^bUg zT+?+bsGB__7TkD4-$2meY8{l#p6Nt!cq(=@-dPHR?;xRpcJfKc+0=)})8g<(O&%9{F|GSPd?ydhS$H#QW)u z{BdMca6%U%r|MTI44iH|n0&9~yG##S3e;4<*qfp=oAb|;ek-4A2&05*En9@G`%cLd zr;=QkNCI{-%{37Sxkm^eNOqWe$o^S*gwfCIqE1OVF`T7Ps6XaG3?Oh8sPcChNs$w3OXSXhCqOzgkK zbg)vY0b&I*asC$EIl%Hf_!?m8odZ1AKo0Pe--0>|7ZV5QKecxt2l%5vHUR0LC;tmU z{cl|}|4vS2#ungnCA(hN~4hl&>#M| z+G;dxmF3g9I}ADim@e+lnxG6c5f}y%yIIC|nWm)P0P2FpQ{D-kscbX zr$4IrH{J~Ko4j!IwJ(v88xDs|$vN+8TawlR?T0_I-lG<(2_HGK9Y06K&-Vqb;Va`xm zb)9l*&q%RRaCXNY4{bCM(emuYz^S^(EUk?yBtr9_mo&KRAyRLz-vv(TG`6f!1{|JDY#YSAJ^L7nuq>NPX|{Fi1ptK>fnB*e<*=tkhueZwdi|>?}wuVtc!o_olSeg z;)mu{*6M0HAue;J3~_?y*EPaOpw2xV5(m3Wv5ZC(glL}~;0o&(0`6GeRjl|`V63cd`IS&$^7Sq5+_jTfqaTUK z4dvu((AA{22&K2KEAjdzEb|c&?n;}H|3`@aP5I_FZ(98O5gd{}IcL1DxfZ0A-t!(4 z=fYdoVqUf^tm7?5_s8KsHAF~;0s=)vXAtE4t{&+;xmNi+EH+x#AQOGX+aTT{>b_y1 z^i@;VLmr=3BO~Bhz@4A=VXsE`%3d;2-uTPbrc;LHEe!H!_+7av9(!UTX(a;l16Q+4 zCZuh~d}{5E`?ja;``~Sf-J~8oq#DIAEf^4sAi(J@K?TOVUzz})(_88Buv-<_jkH1B zU(Y32%!bFQRXc6%MtU1!Wo>WkNG57E#BhX*83vker`0+WL#ngj@(VVkacC| z)d`uco)xR|9^YFh#6Jv(!ZD97`e_o{P#W8DSj-Zx4;btntsQVh3MxzGWiO7CHMici?}wv&L9vB4LvwLIdU!qGo(t&;ki5d?L@+egKm9sL!H+U z^sSwZ3Am0mpimtI%pIYZ$4;W0#IPP z)Xvan#sDvwWw_toH%~garVpN9F08N%Q?Hznu#sY9lg-8=bA)BZXnO#!g`N@1#`Z7c z6q~R4-wfJiF)}4@oU(M-UHWg2@>Bv@aFz=^aDA$6GN9cQ|_P#pyib-G#xYPF==y$RN3CRg8XoOWu3+kiK3Sz*8mv0GkZ^quL{%I;jaDu_52(g5AUuk;8dHW2rwGm zFRuX|QUf!6Pt`I)sx_09wcTz?$r>X$`ReqV{^Eu7*@%6 zMw;*oKSLFEPGnTM@Lc7q(2vLHX_nkg6N(h44$V^uA?P=ryK33xAE0VH$B-T`mlH{Y|&5Fu;&WO^IC3dxY}9p!c>JUpO?uHF^hy=FNQi>hLrVG zqv)>~L*ZJ6l*nq|GhMwe!fZrP&MGmpCRi}u zDuPwJ>kMmoUx+#w2`8u%SU%#cGJl}xKkKfPWoR2X-h5X%Ui}#hA153RDO4$oI78z? zNv}#3i^EkZYm|+8+U-ebL`eB(yiykZZ6#{Ivj5;RvR?LMvD~_fzukI3xu6_Wn~mCM z=E6>H0ClleCcL?wlAfcJ=I6K)c!sJ&f2^0oT%yj44Yw?tB-zi+Kea!{t|!l>@2Zo# zO!(0lzBJ$XUm`%6rju@sDniwvVu(!Be=!Cv;e0Vf03{WEKURWLo#54TS4pz(xw&_U zl@P%!rHJ5j&*R`>eIzo61Lcy!3v&!|rVu zhxtThjkv}IO+#}Mt~?eJLzpxHytFQQJ9te0epQmLAK%LV(&1Ti@?CWr0$Sz}u5qtk zjBBIqC#(^6Hz~85g{X{$Vos7$y>xLf@$pgGR2j89)E?^g?MOmOnYcS&*Bc zf~4Thb_B7)7M@5isZ>Y7CuyX9My6&nb$y43E+R-TF1I&GvU1UEH^O%a%1?&F*BVyJ z_cO-36ARkST77t#F*vqhOtDtJnZ8 z_1ls(9^5tmR)=2Wh`U8s($pE%xT%!jMfuu-0YVdzvP81H8O`cu!xw=ms0Q+b^l`VM zB7h~MQ6bk%6k^q3rweRovVT>GvojA?A8_Qu6)db34<31ySBj!e+l@rW-nfQmhP@Tx z-ER8efZrT29R;f7z=`XhOW@7furuSa&Clqj2(+1gH2Rv(L0S4!hn^cS8 z!N@PL%x6tUijBa_L~1&cO1frR?N0Yvn*)ii*D<@U^h_!W4L<@ps=PA?P#X>DduoF( zEZE(^6TLBcsV42VKx9B!&YfNtj(qJX$EIqmel%AUD=L_Ij0jh=ub@KFfUryn!^X*c zflNS82(akZCfD;|ZF)er$7N|oNS8aAtue7TD?B@s`^(QGp3ico47Qw?g_|5HY!BDn z#)2i6i#G53yqrgGf92|R`&%MYmS0P~d$O`j0}2YetRB`?E2vXqIc%~TVe`BC7l#E@ zamne{`FD?p;xcWNr2}aLXD#EJQq_@W-7V#8pX~3y+}37bd#%OV?s-atE%};gy=SK? zc^a#aga)2o9yPw~&*qwKa444LW7%4s7daJX2J#R4MEzBw!^yTTFg<4)`9OnC@9R_WU|qY()L)j;e6B&CE9*kPP&m;`ZHg; zS#pGvNzXw$8q;n=7kKe;@!pQUhBp(I423^koq80%9AeFMmr<>`R_X0`CBXsoWm)3i zyF|;;+H&ktnwIEF*JGRi@^*dfC%9c2a73^sp`}!h-mymeIGPPL36FO(aOb)N-5TW-d!Db#aa*(Q0^JvLt*v#EW_ zu8IS3L~0QrX)>U_$-I`X@UEG>S>{~Sdo`VXl-exQJzM0sy}rrf_&hJqghX?*J3spg zK5e;N_k4PJJVizWT;SkfVDGou%d6QI=QdC-A_HBV&rP>BQK78YR##`&m*u*R?uy%1 z(@)EK2z&LUN68>F8U@OZn`lQu0vCb>*Wx|%Qz?;|1SubQ5%`n>F58NA4@6SdaO}mc z2db~LCESJE_K%4P0x9L7jQ$8~)hjM7qasrs(0}Xh4_L(tQlw|@s z0!n&LxrSL148;|5eR#h-UP-{S(kp*=;*}DJpFK%fm#@KcLqe@-*XToGuak`q zRSm)%umgA8McE*YLh_nNRRq||{>5zdyCXke;)W%e^|r!R2K*(bB#oJ0flu6kf|R7i zv4+wIhyh62Nt)52qRN-*D4O?0w6GJ&i0$(kcF4%m*ZfT-5M&!bs_g^IAyPsRf5o9< zqy4^Nq86=176*#^DJS}E)3Qe$yuy46U>y9*ElAHEUa!j@bt27|?NqRr8SG#h+%XR? z&t7G$35CH1 z!I$`F^@=#79f_O?l3+|itx)_H%Oo?)Nv6TDxSfFl`+a8Jgk0cbLs+xSRBj{9b2^S3 zUptW~hn3_l71BCt4s+IG)NjqsQIM70Uk2t1)7z!U43#K84zahvTB&!b8(1m(bLWTw z^39S^B(rk|JEMX9fBulE{G0AxQb=mEMs`vDKXmuk^Fl@Z=>O8)m;Y9DEJs)7?B~S} zkM_mRRYS;I-_EBi+&@C*iNKGsu>7zDDTIvcw(^}l9mV{7`+u? z*g5KqGY#y++Gx2l$|AN}M^7jCLopi8hX_L?Y81+_CnIE7gpANmKlL1rwi>{;j+&)csvtPM z;YLR5OqLJcYP?&hZXV48=`q?UZ-iz)O*LDDPQSOVuOcRiVXEu2_hm%Llq#gDP^{@( zksTNcOW@0=7PbNVDB}m@9>ib{s$NCjkz%YpU3qR#@jhHNxLP#J$51*tMa zRe^3tj~X?-Yna~}5~?l~+AA||q=*hNmVgnW-{CSE&v@J}O_HoQ>tDMC^ZuZD<+OCUaL(&+ zfy*?uVh_n!da?cp||HpN?@L0IL1@V!5_h%nDs$s!c*z~68*#xX&<&VYbCa6Mq-5tWYVg9u1#{x zt|GE9!Amh}2l=!4eT^Uw2YR=Z;itlG)(M@7zhNKe=PCPtsBtw- zgGBL|>(XRQI3aB#Wh@xM4y#y!unQ>ul+=U;I{7|1)^nIu3&thOa+3=YySEN5xM04Qr~)NqdnpTTP5?2G@?kbuSW~ ztYk}Pa!ek2&?>!Zw@#VGx^*&>C++l)Q2kSDFN(EdX25j`Hexl%89Xls$l zinEljUakb5ooz^YfZO?X$#rTCp8 zF-;<=EJBpj1}_a;$E#QMl)VbY%I!p?+WmrJJbIKeQT4%@G)4nx*+O!8@*MM$xl?}f zrI}iB5lt;o(4|~E8_JE@@v4NQebFV!;Gwr;kzaZf{Xfe4v{J6sIycLIl=mz&jaFig zxok_Cm}sAaN=Yx3b{4<+yDM>Nrkv_%D~*nLbs$8)H+mciKb;rZ%Dt9(cfsk|X(Nkt zTNb%A#kca_OoAu~5fJ^Yyf+ex(4O(zQ6Jbn5mrG+Rv`&pDQ80eR^F?Tj5UqC%8q?y z{P5Ndk%Sm=Axso(!EIR_aVb%~1duW{bd8QE$cE212Q&)QDox-0@?s;I0U_^s;JNS8 zc38I47tuuzw;o7arpENRGZaU^l^&HDtPHU-(|Uxpl)Q%5H!IvMu|W*lo;!A$8xs~B zs+hsXyFCHl5Oj2kp?4DX%wG;Us(|t@q4E6lIP;J4o<>`F-;n$IUYM`~wstC&np=`( zW{$xdNDMZv!jENjD7MhYWSh(P31q27IrzF=U-QGuS&T{vyKDc(JWhBfE}U3Rsvi#K z0R30BOaeOW)-GxFq_BxCG+W7_XlJv7y%rOgpLd+vn5Ob;65EU4L&MeCFk#XVB@1ll ztT$WK0K22uKgxRoiu~p1f0XxoH5^>TW6u&vB(E%uEPppB;v)O&EZuo?P0}bnGcDhh zGs0?2<^U0q)miMF&Ni!7 zE$jX%VPe|cLnj~d%y=Aq_36C&d4f+c&5ZW~o|Mn1&n6#@y-9&NsZ>76FNfC@vv;}^ zANB5{Xm&?WoGhlhT(!BfbS)K@v@dcSQYl8~*(-6z%sWUN4oXH{VYelctHL z71lN5HOmaEdaM8O!FubVnQ-CB$Mysa`+qNCekaTPHzmyfpHhi`rJwNf{&N-nff3*K zfd6Lg|2viVS3(LDoq(Q$(LdM%pYH#*iu<31-~TVg{@;uGFI3`xmHz*8nB^Ph{L2dP zO(__@DaF4-hJVE!eFrYF(6X|AJ1PDfO7RUb{^R6t?!fSE4`BV56M*?Y$;7w8p|w->ee1#>VnFyhpKtyVh#A8wcMyIr$Yv|G z78P^)+U-zkFd?_%sxcnbpN;7TjOJb*GT^QOJ$iZvA0|EM_LUlIXd?fCE&4BYUuKHU&_gD?>a?o$a_XKT|DIF?=<%>Vv?GyZeC{~Pr7pIi0+eMa#w zL(P9>6#p{I{EsJ(B0v)2Akn}FdvOYFZGKQ1~TT@{5F`8>-m7d^Hv z9o=Qy5@cNPaUcwV5DCrjftc&)NK?gr3OPfTx8Um`f2ZqUKiPq#*tr}Bh5|VaM;=H1 z>T8(@h5FkPMHoq!pTGYptK=ex`0(}8vGvBg#k9rrRP60kb~^8UI$zob!~X*x=64`a z0adw3oXUvxkJG{BreZKTIYa1t3OIGM z>#vMehldPb2atj;nXAt3(NLU7U=JqdhFuim3ezNeiZw*W+mgA6gZSCt zM?}#9kf8~>jJt||eMWzBfOA1dkjY7vEk}Z z!)3>6U!{wMC+Zc_41%fl$3=?C)~Ef5Yo?5wi^FyUA7tccFrWgJqVZ)k^>?d*NY?}9 z?!7fAHJXNS&;_CnE~1uss~O@t6D7*V`~@88%L)H%dPF9Y5mO(~3|iyp@0496&W5?x znrlY!T?I63jf{z++nEG7An=Y_5<@OGNTVlweqF=<=4d}5+cNni)8UkCQGCz3Z&{~o zrnEWce1JQ_V+@Y^qOWGHZnCV=Hs};-T={j8Q+NU1G+a`jhG56j?`bMN3nFT76kn|C z*D9{w!*P{RIAG0<=o&}$drS-ndMGU;q`n1yun+m%1t~a1Z(LtjUdNxx03W*NzLwjV zfjVSN?q@pvg=Qis>)Rc@H*D}*9+!qX{6RD1o(ld(Xf2PR$qVl9Nr4JI{I1`Yy_(vO zF&0=OMiprWM1y4N%Q;J}^lDq&6?(MAG?I&5kx#}XyOzgvUxoCaw;{Yx{bm&B0#9Ri ziG7n_DoLMoyt|C-a2t&+LZrETP+Crm-XLuc`*byaAwaD7UXAbM6|%)Db&eu?sTKYA zQ0FGFgIY8fKjAp5@8Mkm5SP5UUjCN~hb|LyyhbPEC0~GXoNosuJ@@a!UZfhVPpN2w zDl2yLi)$6zJmn6osz8kzR*ZwMYFnJiGvdTuiIyPO2IqN+r+ntEUmkH!KU<)j{SsOl zr*vT|khF(1&w8L&$O(|-)UAn+EU4tpuo0_+d;gly`5DjVFPO5Kv01?NT zDoS;1eFQTH`2D@1^$npv8rsKlN9nQ%L<9U;h0uID+g`G4*l}~saTN!`kS(6+a%AWf zRSi#P%Bdb)Y00h%;HtR~AeL~JL)su)r{g8{rZaKGS)^tsLU^XRobVwuJ~xY{Ch8`% ziGw>4;|%yr_Qqc)GX-}di>n(jr>@nhfOMxR( zG7Wm4O0S|y$W0a9<5Jfm)uG;|+@}56P+n{yyR_BTH3QXXp+`8{uWtEKX$$vgNp>F4 ze8U5R2OowW2D*hmLZ~o;@~kavP5cxWGD1{{W3eL3i=Pu$J-oE<5k49}Ixkvp%GyQH zmZ&XZljkz$^?X^PGkpb;5=$c#gqWxK7X{UzeDPPtjhDQu&VBfs5X?}kT$}VNArCbV z>4zF8ZAPNb3IEe5+*8gZmsicNHde=t#f8O%s?M0VFmR($IG_eY()>$vp^r`|tK_YM z%x)Pec4zH)(cri{J455x7eh$3AR;%I)`<7)<`1}i4D6!r1cPN`riVM$rxFrJ5S*AR z;f65Uyo{5HhO91OS;%l*kr9<{J|5nKX{Ba2xH$1J5AIgZ3&uN{NG!N<=H z0omESK2>>X(tb})`akLC@OZ-2nx3%H;ZwR>+5_<_Bc%2yJfs=9QS@0*`)+!^=qTF3 zz{1nh)%rHB!Sx{3U}R@0nK`vTqv6FL0S8j=Z;YXsxNG1$xY66w-sH^5z28|VB z-mox&gD}GM?dr{2t3UUY6|(vo7lJIWz8nIbadHA`NJw;{GwoN!{rbA%?!CAEGn>-pvDr)SD!jrX2LSm) znHXwo^3~}Ts1NR{eYPMg3-(6o088*6AEWUYU?wowtA1djkL>S9{?&62j}|Ss>EI?M z92Lt{u-v1^r9DaMt_uhjm@tRu!RAf%HCR*CQ1_o=}Qx02c~tg zhN1{r>^1lmITp*$meeICD~_g}!w@9yJ6k)I3^~Oy`6w@>DYG=z5UKkUmr z08UtX%c5XLYAds6i4w)|>`7_F2j)Z;A$ZdZ|H^Kck|#Quq^ji(BBS*`lR4yNZ{!`z zQMy4xMu(Tf7$B-z43EABrExawQKLOg8cVV=X`^0X;I0y_7q}Hi{bWUN9zCU)W3y(y z7Zdy=spx7wD;O3+!J^h1XO|jI#T4m-qkaT`Xzq1`4!a^Y=zE(IDgov}{~GT|!z;!4 zb`T>V+-$e^SI%~RFgPj-M}2HuP7cOuUHnVxtE0BHjDUn4XSM3g>*f#J{I2Q*iBStV zd88>!91N0%fnopt2@98!?{+W+i&f%u91M}Uh68=2u?al>paDgMQ5-eAA<$paf=BrcR6jG_ zZu#dN^|{E1YNRenaV7t!a(yjY&ixj-#t^QMaubGEtYbc`VtpyvmQRUgr*_FwfHs*w z?3hS=iWO6a$IVFmd}Y3ldQ)~%C7(i51=2%ovHBe+KO?+h(1_^@Xv(v9{6La za8OSfQ953)r-gYBy^nE&M)eA1Aq?s|B(G@=N9Ez`?`B>YpIAoaWhg_+N+>ntxc9xf z3#IV)t>522Y$%&w3BNJLOcbwL>ef@`Qu0Fk{aIKe7(05&AzzE8TUIby>ox7K>j(0o z<4wrRKs~O6_dc{MEGgo`=h5Jr8yq9)o<`txs*MoZpOiG{H@w+BgspN@Ly6 zg+mP)0sSD#)An4vq-uQ1|417;b8_np1+&E|Tcl9ZKpGBzGK4$bsD{y`7ooWlY<3U>IkD|uE0 z>P{7y#fOef0C=?)6EuL2#ZI z)9d=E^;K|VxlG#=2sw`_2F-g$L28ru5Xv(+!4UU-|e}cgOnvN1>1KuEY)R-R0j2WO7X$IS{b{uk( zkg{#u&p7`F!TC(trwp&&Mnum%kR64Lpa17VPc^DjbpKPV7m zLH;vjv5XaE_H}+1cj$BYT%Fm1Fl2Yf_5tMbKKFI7RfdIr%7 z{_izeJHAch2$Ie9KjZd2;qyQ!zv3e2mh*ov1=X>A21l@D`Uzg?m6l7?&d?E*Q({Y4 z@q}x+(gnWq{)asHF_7iznN@(~FBf}4^;qJcJH$J;B#`a(H340Vk6Jp3e<3EBCFbV@ zSfK+53EFA6>8A-=)<%y&Igdlu0%m#^cYu$v;6+7iNo;f{Z1~|fKpbI?(`QD+I)mml zrv0s%+A5ECkL5<;l^lP+BDSeacY*>>4@^t*mlV9M)uh9=RnssM(yxo_6#4W9;pKXq z=(K)8dHKE3%^kIV5x%A!cMIv5jzRa>5)}h~_X}2;q3dxB`!w^2=E;R=p4nh`1_Jza zL^&QT$ndj9;!L|NUa_hNcBbApbA^$bcweE`?FnnMUrw^~zf=B@tw{rJAP2&arp57?L3LNJ?aVI5U zp>ul!LBclAO4=pT4*Y3D7Cn)NKPfs7x)NG!+G;vD*a_W0iFlm&)o@NoGZmXGUUf%Ss|c;lh+%$X5%Ww@sZi(`@ymsR-B>^er>3kMZe?iUUlk&9h=Q zbS^;zEYGa(8M>$1uq-TkFErJ5s%qfslcLMsAx*{f@6Y!xf13bo%Cj|*e3%PZwTB^S z3Ys`Sv7CEb6Fh~ZRg^A?zx1`OCS>%`U&_o8BhZ4C78jLWV$Cw){P%T+zk4^*O_uaW zrQQ6NOG(>qr|Lx;d>>Bf=icwH7fHPfdT^g4LmXUcqb@0{V<8K&!*j7Y_9_T|}u%3SFrJ2rU4nkBZr}^_vw0K`?Yn0M?Kom;j5x{~2aq0HPLdAOA53 zLLYaCeBYdm0Phw5ac>##7XBB0IQx%R0$8DUOsG6QeFS8D)czkAAc?lvAixOVf(X0t z9==zgxaL+0pVuDptb(LsM!8PJF9xFba}e;B}%^|h|1(1-0AvcuUy zDO!l?QAP@94&MAk4^ai)YoyCXCB>H!<%UA*6DmB@Wz^@9`rQ$_2c25x1q(wDQ;R^$ zpBeTnn+n<(TCc~ckE9vu$}n%1(~BMLkcVrBt6As;b(aTp0*Z|$K(tGk8g`S?Lk$?f z&d_UmgrxQ(1r*VP+hGhH(5t+mEB9~%lIZbnWY&{2|OT8$oZ#4*2 zLLIou2IDZHSN&18D7(@%V0K6q!t0T)=-x2h0v#AtBJVJo1vvg1?3++$@HPPtq0RkZ zQk}pz@avFE1e>5(jRDshEx0$fXW(-8*RYTHt#db?uRYYF7P!L zV5^^Iwf!1@y{r=$uGcCQuKyx5#?}-0lHU{hQpgkAJK`B+h_7cObZy%u)UE}*7Ukwg zLoX`eq6VcF=W=c{m~6-U0(861YjD7kZpI_(xgY!P-E>(eB%SU1uLgoolqL(Co`~t_XGHF>XU21W zPta_E^E)#9e_%)lr3Zoh!gEy6C4tzH6vf-U-uhb!I9hggZvD--8O0^Z4ejE|oTpS?&4-9_FU-#bRuC&AJQ-skrT zJx;IS8;-Bwn*TX{tXrS$A@2sF8l4`)l{!m3kjJS}ZwRO?J^(Q_KDl#U`O!{cz+_28 zEEC_MS@FbA9LYg>2?732c_v0zz#-PgjNNIR`-1^Fx`*TT4^@HFIf=U2kh!kHy%91s zigx(LJt;`|=vFfhbki4T&2tO6Z9rvemr}*!{sONL_ed&{v8R{21MX-N&)o zeftN%ACxiLYH}UAhnU4`~kH6OMreA3X!K}Fu*?_ zq%Ob2zLh)?Nez&UmWx?(PIcGGxp|88AX&2yMV+&JUR3nVX3LN1%+KG9#6>WFx$)L7 zxQr35{;V)V2iuQhM(@R*T+McN$8Bt*t>d7rUFs(Hs;i^6+3NOi_}cMu=;j6k%$i<( z;gNFJyeT?<;>Fn@yA~zlW=@O909Sx}&%J6Aa&*G$!Tt8yk^HHRr&W|-=xj=+&zc~f zZQjh3CAlCx>n1?sOX%#-O&2?R3dnld6_HU05S z3`$(NRW*s`(nzZ@gmdjNf)sEaZFnH#sfX<++MX``^HL|o`G z<9EZTtjTp@PQRV&X@^M{y@MHx>wuD!7PZ~B;UD%_+Eo&N1CSuhKjO(H|MIyLCaHR- z?}*~eg|Ygum6s>s~dn>`e{+HI(B(p;5ZDYYrvWKD{}PPd8YFA3u^#lq9AUuZR!| zZi*j!L3bN-%?8d2zF*g1Z_@hYdGxaBuGQH(sD9Nk%%#&j&AsFvc86$VvTZd7v;;H- zZl=@Hb?upI$DRwy{kybBeH$HLN!4KXWf5|AVAe0PdO)E}T)H`w5j00fIh0_-hM_IZ zvQFHQiNWA56rfT|k9L{)A(D@2FbHN4@dp~PJdXJi&d|m&0g@@rj5yR9im65*#Tv&x zZj>+pAgym@qa|Yw#`Fo`2nRT!3DV@)fCUpAp`hP zioX}e&)GoRWeuUBfFacfiN=#(7ay7xhP#t5s*09o>7YzzfooUagaBS1?aC+$XS~)E zc1hUU;8_u#KeQK}YnXjWQ7MIeGc`yYGlJcVT|-P|NL2?zNjYA4LK#@+02&ezrYO#U z#5sGF_gGZP)JzlRSUZ>jg{fSDMm-d45`iBzYZ&B0VTasYi|(a5%XOF?cg&c`V4LXgk?Fx-(!oRnDx>bKXcUb_)vyIIeN#oY zy=45=50QZjv?xG))$y_~g=Y^k5*EF%5peN!P~%e+n(9|{naAm`G%WTWG^|RtIA0&b zRk5Z0hLNh^2CyZY6Puv+ak#&5uF{4PxlfyrBqs)7ZtwbWO>D6J}Yt*A`o1(le-6ilVrSMxTR2`@}t5WK{ z*jY;*iMt{z59$&PBEcYl1jNP>aTt;SsUUIadxQb#;9+)Qp>}rY{XsorLED->oM_FC zwC*RGTSZ6b3S#`Fa)0&pR*-?mimx}qqBbCSokM}W20T(>z6%ADlr67CBRREKAbs9l zF{P5SLKwHdMU0H8Xyndfw($~(8~BswO~xYj!Wiv(d6Ov3zhfjRm0~KUZa#-4Evrg;5u#|=*H6v?`Voc|zL3e}^!s{jn9s=`tl12+D>q(=w_&^S zht?yaDveA({`oOv`NkA8vLe0-h9{Tg8AJz`O2!!b%(Lzu`U&o#_qg}4J7f;MKjLk= z3}wpm93lf?e;osHC63lgT4pKq?_L%ZJW=~uEyD9k;P>qbAj(g@vHn;wXarOa1iOcc zTMKZloJ)}`KRb`#CrTUJTkoxo4ocA1xizRQbL&4#R^?lUjUozF_|X*}IMc#7^LBr~ zKVl0X)K}IeZjACC#O6~FCdAx?=NjHV^gr>CFx6JIjN1wd+}Nkx7^2D^7n|8OM?@R- z*^9JZ58EgGnm#doi3`l9FuANKQh^gKS9;R+n1b2b>JEayB7-eSRw(%Uk(Baz-{+_DSc6lF=~5^)&wN6T z^90ZYx-OY373fr~&M~({L=}s8kQUM6WRi#%bRuRA`-9;f-1^vDq!68;ZI|0Q&NR)p z&b!F9&Nridl(uivKzGafsxneOD?6KDjgkp4cWxzR$I6_L={;$-R&Fj+R1(hF%I%?j zCD$OKnApVFQz+W??_z;j@Q<)!Ugz%}*>6HY+_JA9L}4oMnx7Qe95+sG936+|V!bt1 zPUK~)X169aw)r8r)*q*T$Tu*a`va1FWm9el${v*@v2@f#>%czuki0gtV|QMYOxa5S z7^HooJ!i^8K;`)*lI!Jsuj6T5@3g=`_AbgOGn~=Z9x?(eV_ik2;J`lcEa>%iPI5FM zn1ku1)l4v%TDlYzB^;{vP_8c1@>E z{8(r%)@(`Z1tRURtvd_E7LFy3R|~woOCey*d4i-_o6G((KnhXBQ5yL(EIt;}ZU03z zV1}IIHcD^kWsowYV(Qv(AB!mZU9QwFc8`0He2BSdkbTK@^xCPd$cLQIMb%XG@})K7 zuKAEEpbqSzav0ADJ4tE5MPf0r>n>4Et^SpDzj+^T_=EXuY`Ru6V~nE2WqR?E_meru z2F4s7>^dqBG-mbf27T_g%8=s7RWoK;-3Ms^QzyBmp_nu;*>mu)vNdf6oZ#}s<`rQX z)uFj!Gw-gH@yTW7A!pj%lJJ(LwQq|tg=W1m**o;I#puXdr#SH3dp z6qIxZRZf=P%^gu1aokd`UvFsHr>NX+0bRw|!k$Gf`ohsCbPRDfmNre@OEYj_--g&^ zMGFNhZ3?3z9yif@vDaW-wzq3F*cUgZVq>c@Jo?NvME9~5HKqBfJIAH*^*qIer|EUj zFRR&gx`TNIu-!R73D{doxP7|B-w)cKei?F;!sGmF~f*0=Br^$UKn8^<;J#{Qz6JX_i zuy3>SdQ-}x`jXq|((et#8k?d0I6Zs?zvSf!*lhm{A7QKH{a`i^fjR#w?{h=pCx9E^ zp6_X+vrXin#7?Ws;(RBCpb!pS*Ed0CvFFMu82_^qnkHK!)eb^X1TpT(ncPc03J3dB zG_9a7ju_Rl&R9f@!hcC~ko*Im^?mOl<3Z!W&a31z_OnGB$culg!e+)sTm)y)!d;L* z=CP1a{x{t(%iy;g^=d+V$vV^6q#BT2RJ(F?G_HaE{B;UkG>XvQc6`A?40iXq6^Hxx z5uUHYz~wrQH796DOK_RTyJf-6b3H=8u}jWqKqSXx_ZUqSa1J~IqPA9JUyCI3`JS$+ za5Ar8E-o&1kKP`=a%e@m_&jX;NI%3K9!n zz{q41O3pybU%Cqu>T=m?amOIXq8K+a@$V@Fbf5Ss$Jmux=J_w|>1oQ*%elHXvNbA9 zG`L@#!$b{lLYG<4i6ZieM*|)Tgej<>nC8)GQIyePA@D{=0~jGk5J)Phl0uHD#`h)~ z^(!?C=1)~3Qp8g96B--?YAnW4ut@Kfq?(^6zUF7sDmDtc1^WNUgz0<+@&pj;DyU)RIAN*zAci|DL- z8T7#DTK1V5`mzp;n0_o5xDNA2_2MXSfkDQdM=X>Ko5-YFEc zs>}X-wE!t|$*>yuOPM^MZyQxn9)@xMf>GqIB_hHhbJ5!rDSy9d`pdqWr96?X5LH@% zS&rakk5}!?a*WbwtaxIiBf!eMH1pbZ7|^L~KoEiWM{a$jAjfHftR2pIqg`b6p`VF(v+?%c60@b_ zOd#>2+ztrZI6X2lDy{vj7PpPc_^h(j-IUDvVo3q*VVcj@KQT;14iX}awe;45<^wVoe z^!JJMiD7J;V{h!{#jjIPg2a=QxwM@Uc#i#tzri1RbsQZmQvI|kONg76M67XmCL8bM zV^<+Bc8k5FvxA9$BczL?ZUrmD@XTK(YH0Mz9@$spUsa1U@GRFgv07Ve+WIrR07F#Q zS*1PS@3j^vSmixKmB@JAAJ+^<0}~`UVM+&*S^{sXFkZf>L9RChRp$blD?xpReDKZ- zg1|kB**!|ygE5M@-E?3kv!t(iJQUev`mom6Btol50XJXK|-w|gX#fB2G9_O!!S6?noiT%k^qw?FvJHP1CEm6NVNoXy$ntyTe$+-a+bnOui2aZapRVa?9hp!itm?M(F( zL&%m<0*08?aSJj?mrf6d?;P9o8^^T|sqIus7aq+`lGVuFNJ3bKP;W% zyy6_1-sIz}Qb_KC`jE}ScLe4H^2E&-OX`MVw)+v{!{Z}te1 z*GC#4aCHz_?erNlkaSI7!*Oxw)~T+1jtoTT*!kx~pz&ps6@^w~*xI*->p4krQ(On| zT+gP85yIZr0duPaJeZJX*tAIIKeVi5M@1G}hs5N&8?v!j^3BO6lb)GKFg*~iHM9s9 z!-_!qIePyHxCE~m1+Vh>#M$lGy*q<*!r549`dn?gI9qI#sh`QPBffV`y(U<926VGuE<2V?}a zF{-3paWA=bsc!@obE;(7bXohEWw#AC_AFs|Zro(Q@m!syiDHW~!htvDG7*a`n7W6l z7DppaDU_7sVem~I%SW+BY~RpAYVp4~g^Ns9rVK@#;qY-UzNSL*|)7UX%fB@N{(J>Zta`4Y!6$(@`_xqzy6 zo8^x1Uv!wP`he*O>@@xTO%j7q+)*5@nVS21tmQ+f3xzxsQDfg}Oi2e4R<3B=XfJvB z^bA5m3c^f6dwC&pVZ)Np3S2>7O__gKT z`Q5OxY)}2N!!QvTcLw+T9km2M=hv19XUx~*($nd{`b?xgHuqF)Mb4oN# z`U0;@M%3fE7@v;9Ql2}9CHpZ7WIHhiW>S$tK0XFLk{uk`s_E@5u|{-y68(EJ_!5&{wtA}AfTQDinMXo?_`h=LF$Xh1+&N)+eSb0=-3~9F9=33omLwHjTH$Ui_2{!u zV*a-E*}+fKj#!ulTe$~$E39Sy)6qYI-qt#~QOuo&4xto!k z@>$|W-R=bs7qyN}(O;N6bdTrJ=zpBI_WLR$vtUtoebeX=*AA-%r9LCZ_cYpvY2_9i zndJ4Ia!#nrDRtS&KKZbZ?Df=3jjz`%4%)S9g+;)og^Ckhzx^0QczsP}E9^|}r~Trk z`1M@O^I-4X&99zM56eHH>aJ?Mlp9#3n*DU{@!{WZP(HNW_+V7(i@arJt!5tgUBeu2 zd|+y^wK?}rT&K28(HgvHUP@4TUG#i|(r6dzRq>U^)ux{$Hr|`sJo}imR@-!3rFL?? ztRUW;Zdmbo%#8Z?Wj^bs9m<*;QC9i!%vBb{4&0PWv^ck&73;6gbHP^KmESOWGOap( zdUoX32a+4kb-0bT|F-<3+}&ouWB=4~E6rnj52a=09Zr!MX0suWX7}~z8p@ia+I{>C z#fx|>wbH%BbbZV{w`&2e$~#?kMtfG7wQRXw7}*@qmeG3SU`XHSrcl1RLT+o@6mc*~ zzg4QX-?9JvUi(AxJh=wIZ!+HPJ5NV>H>=WOAzmQ&vbNs6y! z=mm4V3E5rV$`OmacE)H5MHm}Pm^bR*rKVq+$&dqO{->#=O>7nZ7nNNTCcfLVb zW0Go=vb8WWqIN<;Rdk?fdE<->g*TIZS#4jry~ZISZ*`s`^T~uN=_aL1>6!A6?Y*6o zsup(+>#*t#@0I19b=r8ko74+zQ{KP&?6ha(j@K3KsXp`ab?!yAcX0cp&$f5jXFdyW zj;nO-iW*-$K4I3{Ti(tWh8hartY|CaM&Vsxt8);X{BX5a_LF4)6th;~WBjeZVq^fl$*Q zqD=pVK$8AL6zH9zOrRD-1GgL}nL`qkDT}e707PII269aBWKbX?IRSNKKQwF*btFGX z9_DSVB9LZ(N(9uAXy5~YxBmk+lcljY5=E%OY_ShL_L) zn#45}krEb{u%Nv3_BSXv5d;C!Of1g=GLs+lQ^Ngut_IsVu;uMHkZSsK1xPiquyx?M z1B>3UN7C3JK_-3>Y3aL=c?3rb;F-=#f&iYW>Y1=JajM;iLzn8lcW{B-qiEad?L)Hk z*3Ft+5fDT zirp5czPUSvbugQz3d1`8^+I*M$0K}9&$NV|u@k*w3I6g=ioaC_aXvhZu=y}*G~tN@RSa;=$j7+cF`m)@skYL zaG;#jd?Z0{Y$Q!ns13t#5@4Q!brj2M`deUQFrI{4Ca}R?2C^csF&x1F`=!7JbBjgK z1F~8Tuv@T>V?kpMvGFX0`iEmYMNELCbH3*>I&A8G|md1NmRgA_yjgK0t$XkIWDcxQ#r=$|^GI5;q)>o@}D4&pNd^FnCD87Mix zdIhlo7@R=!f-{T;gN&@>DAZ>XAm`{_0(cxnHqfd=&m$P|-2jW`b_;e6ND@NDiZsx?vOpLWRgWis3~$0GvE@knlVTE-#vU(CEX_^Jty{nM2`T z2BSs3FgPZI@XkZl zk%XvMS!e}x9fuJ>sVv;9DF^BcXvvA{#^E%H-YbrQzar>)AUTQFh=aPJx#u`sbcc9o zL9~`U^aq+#p2bA<;6YOni5Du#!M`X$yfCkDG&ZnNqPYS8wb1&)aOO$G7ZA(DStK^F zv1lAH6JaVMzK|?Mp+1u=!=pY!&xqn6Ina_5LuwyH$=mP?h?4o xSM#bhTM--_Dj^|x8bQ$|L4Ls!NNzuW`sPqsNNE2{8Rjj`^E!rxwoZ0BzXPKZuO0vZ literal 0 HcmV?d00001 From 9832e253d09247f3dd4a4e16a5f248fe42d062d8 Mon Sep 17 00:00:00 2001 From: Benjamin Wang Date: Thu, 31 Oct 2024 20:00:34 +0000 Subject: [PATCH 08/17] Init etcd-operator using kubebuilder The command is: kubebuilder init --domain etcd.io --repo go.etcd.io/etcd-operator But the generated readme.md file is removed for now, and it will be merged to the existing readme.md in next commit. Signed-off-by: Benjamin Wang --- .devcontainer/devcontainer.json | 25 ++ .devcontainer/post-install.sh | 23 ++ .dockerignore | 3 + .github/workflows/lint.yml | 23 ++ .github/workflows/test-e2e.yml | 35 ++ .github/workflows/test.yml | 23 ++ .gitignore | 27 ++ .golangci.yml | 47 +++ Dockerfile | 33 ++ Makefile | 212 ++++++++++++ PROJECT | 10 + cmd/main.go | 159 +++++++++ config/default/kustomization.yaml | 177 ++++++++++ config/default/manager_metrics_patch.yaml | 4 + config/default/metrics_service.yaml | 17 + config/manager/kustomization.yaml | 2 + config/manager/manager.yaml | 95 ++++++ .../network-policy/allow-metrics-traffic.yaml | 26 ++ config/network-policy/kustomization.yaml | 2 + config/prometheus/kustomization.yaml | 2 + config/prometheus/monitor.yaml | 30 ++ config/rbac/kustomization.yaml | 20 ++ config/rbac/leader_election_role.yaml | 40 +++ config/rbac/leader_election_role_binding.yaml | 15 + config/rbac/metrics_auth_role.yaml | 17 + config/rbac/metrics_auth_role_binding.yaml | 12 + config/rbac/metrics_reader_role.yaml | 9 + config/rbac/role.yaml | 11 + config/rbac/role_binding.yaml | 15 + config/rbac/service_account.yaml | 8 + go.mod | 98 ++++++ go.sum | 251 ++++++++++++++ hack/boilerplate.go.txt | 15 + test/e2e/e2e_suite_test.go | 120 +++++++ test/e2e/e2e_test.go | 307 ++++++++++++++++++ test/utils/utils.go | 251 ++++++++++++++ 36 files changed, 2164 insertions(+) create mode 100644 .devcontainer/devcontainer.json create mode 100644 .devcontainer/post-install.sh create mode 100644 .dockerignore create mode 100644 .github/workflows/lint.yml create mode 100644 .github/workflows/test-e2e.yml create mode 100644 .github/workflows/test.yml create mode 100644 .gitignore create mode 100644 .golangci.yml create mode 100644 Dockerfile create mode 100644 Makefile create mode 100644 PROJECT create mode 100644 cmd/main.go create mode 100644 config/default/kustomization.yaml create mode 100644 config/default/manager_metrics_patch.yaml create mode 100644 config/default/metrics_service.yaml create mode 100644 config/manager/kustomization.yaml create mode 100644 config/manager/manager.yaml create mode 100644 config/network-policy/allow-metrics-traffic.yaml create mode 100644 config/network-policy/kustomization.yaml create mode 100644 config/prometheus/kustomization.yaml create mode 100644 config/prometheus/monitor.yaml create mode 100644 config/rbac/kustomization.yaml create mode 100644 config/rbac/leader_election_role.yaml create mode 100644 config/rbac/leader_election_role_binding.yaml create mode 100644 config/rbac/metrics_auth_role.yaml create mode 100644 config/rbac/metrics_auth_role_binding.yaml create mode 100644 config/rbac/metrics_reader_role.yaml create mode 100644 config/rbac/role.yaml create mode 100644 config/rbac/role_binding.yaml create mode 100644 config/rbac/service_account.yaml create mode 100644 go.mod create mode 100644 go.sum create mode 100644 hack/boilerplate.go.txt create mode 100644 test/e2e/e2e_suite_test.go create mode 100644 test/e2e/e2e_test.go create mode 100644 test/utils/utils.go diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..e2cdc09 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,25 @@ +{ + "name": "Kubebuilder DevContainer", + "image": "golang:1.22", + "features": { + "ghcr.io/devcontainers/features/docker-in-docker:2": {}, + "ghcr.io/devcontainers/features/git:1": {} + }, + + "runArgs": ["--network=host"], + + "customizations": { + "vscode": { + "settings": { + "terminal.integrated.shell.linux": "/bin/bash" + }, + "extensions": [ + "ms-kubernetes-tools.vscode-kubernetes-tools", + "ms-azuretools.vscode-docker" + ] + } + }, + + "onCreateCommand": "bash .devcontainer/post-install.sh" +} + diff --git a/.devcontainer/post-install.sh b/.devcontainer/post-install.sh new file mode 100644 index 0000000..265c43e --- /dev/null +++ b/.devcontainer/post-install.sh @@ -0,0 +1,23 @@ +#!/bin/bash +set -x + +curl -Lo ./kind https://kind.sigs.k8s.io/dl/latest/kind-linux-amd64 +chmod +x ./kind +mv ./kind /usr/local/bin/kind + +curl -L -o kubebuilder https://go.kubebuilder.io/dl/latest/linux/amd64 +chmod +x kubebuilder +mv kubebuilder /usr/local/bin/ + +KUBECTL_VERSION=$(curl -L -s https://dl.k8s.io/release/stable.txt) +curl -LO "https://dl.k8s.io/release/$KUBECTL_VERSION/bin/linux/amd64/kubectl" +chmod +x kubectl +mv kubectl /usr/local/bin/kubectl + +docker network create -d=bridge --subnet=172.19.0.0/24 kind + +kind version +kubebuilder version +docker --version +go version +kubectl version --client diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..a3aab7a --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +# More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file +# Ignore build and test binaries. +bin/ diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..b6967b3 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,23 @@ +name: Lint + +on: + push: + pull_request: + +jobs: + lint: + name: Run on Ubuntu + runs-on: ubuntu-latest + steps: + - name: Clone the code + uses: actions/checkout@v4 + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: '~1.22' + + - name: Run linter + uses: golangci/golangci-lint-action@v6 + with: + version: v1.59 diff --git a/.github/workflows/test-e2e.yml b/.github/workflows/test-e2e.yml new file mode 100644 index 0000000..8780644 --- /dev/null +++ b/.github/workflows/test-e2e.yml @@ -0,0 +1,35 @@ +name: E2E Tests + +on: + push: + pull_request: + +jobs: + test-e2e: + name: Run on Ubuntu + runs-on: ubuntu-latest + steps: + - name: Clone the code + uses: actions/checkout@v4 + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: '~1.22' + + - name: Install the latest version of kind + run: | + curl -Lo ./kind https://kind.sigs.k8s.io/dl/latest/kind-linux-amd64 + chmod +x ./kind + sudo mv ./kind /usr/local/bin/kind + + - name: Verify kind installation + run: kind version + + - name: Create kind cluster + run: kind create cluster + + - name: Running Test e2e + run: | + go mod tidy + make test-e2e diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..7baf657 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,23 @@ +name: Tests + +on: + push: + pull_request: + +jobs: + test: + name: Run on Ubuntu + runs-on: ubuntu-latest + steps: + - name: Clone the code + uses: actions/checkout@v4 + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: '~1.22' + + - name: Running Tests + run: | + go mod tidy + make test diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ada68ff --- /dev/null +++ b/.gitignore @@ -0,0 +1,27 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib +bin/* +Dockerfile.cross + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Go workspace file +go.work + +# Kubernetes Generated files - skip generated files, except for vendored files +!vendor/**/zz_generated.* + +# editor and IDE paraphernalia +.idea +.vscode +*.swp +*.swo +*~ diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..aac8a13 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,47 @@ +run: + timeout: 5m + allow-parallel-runners: true + +issues: + # don't skip warning about doc comments + # don't exclude the default set of lint + exclude-use-default: false + # restore some of the defaults + # (fill in the rest as needed) + exclude-rules: + - path: "api/*" + linters: + - lll + - path: "internal/*" + linters: + - dupl + - lll +linters: + disable-all: true + enable: + - dupl + - errcheck + - exportloopref + - ginkgolinter + - goconst + - gocyclo + - gofmt + - goimports + - gosimple + - govet + - ineffassign + - lll + - misspell + - nakedret + - prealloc + - revive + - staticcheck + - typecheck + - unconvert + - unparam + - unused + +linters-settings: + revive: + rules: + - name: comment-spacings diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..4ba18b6 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,33 @@ +# Build the manager binary +FROM golang:1.22 AS builder +ARG TARGETOS +ARG TARGETARCH + +WORKDIR /workspace +# Copy the Go Modules manifests +COPY go.mod go.mod +COPY go.sum go.sum +# cache deps before building and copying source so that we don't need to re-download as much +# and so that source changes don't invalidate our downloaded layer +RUN go mod download + +# Copy the go source +COPY cmd/main.go cmd/main.go +COPY api/ api/ +COPY internal/ internal/ + +# Build +# the GOARCH has not a default value to allow the binary be built according to the host where the command +# was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO +# the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore, +# by leaving it empty we can ensure that the container and binary shipped on it will have the same platform. +RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager cmd/main.go + +# Use distroless as minimal base image to package the manager binary +# Refer to https://github.com/GoogleContainerTools/distroless for more details +FROM gcr.io/distroless/static:nonroot +WORKDIR / +COPY --from=builder /workspace/manager . +USER 65532:65532 + +ENTRYPOINT ["/manager"] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5b0e996 --- /dev/null +++ b/Makefile @@ -0,0 +1,212 @@ +# Image URL to use all building/pushing image targets +IMG ?= controller:latest +# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary. +ENVTEST_K8S_VERSION = 1.31.0 + +# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) +ifeq (,$(shell go env GOBIN)) +GOBIN=$(shell go env GOPATH)/bin +else +GOBIN=$(shell go env GOBIN) +endif + +# CONTAINER_TOOL defines the container tool to be used for building images. +# Be aware that the target commands are only tested with Docker which is +# scaffolded by default. However, you might want to replace it to use other +# tools. (i.e. podman) +CONTAINER_TOOL ?= docker + +# Setting SHELL to bash allows bash commands to be executed by recipes. +# Options are set to exit when a recipe line exits non-zero or a piped command fails. +SHELL = /usr/bin/env bash -o pipefail +.SHELLFLAGS = -ec + +.PHONY: all +all: build + +##@ General + +# The help target prints out all targets with their descriptions organized +# beneath their categories. The categories are represented by '##@' and the +# target descriptions by '##'. The awk command is responsible for reading the +# entire set of makefiles included in this invocation, looking for lines of the +# file as xyz: ## something, and then pretty-format the target and help. Then, +# if there's a line with ##@ something, that gets pretty-printed as a category. +# More info on the usage of ANSI control characters for terminal formatting: +# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters +# More info on the awk command: +# http://linuxcommand.org/lc3_adv_awk.php + +.PHONY: help +help: ## Display this help. + @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) + +##@ Development + +.PHONY: manifests +manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects. + $(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases + +.PHONY: generate +generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations. + $(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..." + +.PHONY: fmt +fmt: ## Run go fmt against code. + go fmt ./... + +.PHONY: vet +vet: ## Run go vet against code. + go vet ./... + +.PHONY: test +test: manifests generate fmt vet envtest ## Run tests. + KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test $$(go list ./... | grep -v /e2e) -coverprofile cover.out + +# TODO(user): To use a different vendor for e2e tests, modify the setup under 'tests/e2e'. +# The default setup assumes Kind is pre-installed and builds/loads the Manager Docker image locally. +# Prometheus and CertManager are installed by default; skip with: +# - PROMETHEUS_INSTALL_SKIP=true +# - CERT_MANAGER_INSTALL_SKIP=true +.PHONY: test-e2e +test-e2e: manifests generate fmt vet ## Run the e2e tests. Expected an isolated environment using Kind. + @command -v kind >/dev/null 2>&1 || { \ + echo "Kind is not installed. Please install Kind manually."; \ + exit 1; \ + } + @kind get clusters | grep -q 'kind' || { \ + echo "No Kind cluster is running. Please start a Kind cluster before running the e2e tests."; \ + exit 1; \ + } + go test ./test/e2e/ -v -ginkgo.v + +.PHONY: lint +lint: golangci-lint ## Run golangci-lint linter + $(GOLANGCI_LINT) run + +.PHONY: lint-fix +lint-fix: golangci-lint ## Run golangci-lint linter and perform fixes + $(GOLANGCI_LINT) run --fix + +##@ Build + +.PHONY: build +build: manifests generate fmt vet ## Build manager binary. + go build -o bin/manager cmd/main.go + +.PHONY: run +run: manifests generate fmt vet ## Run a controller from your host. + go run ./cmd/main.go + +# If you wish to build the manager image targeting other platforms you can use the --platform flag. +# (i.e. docker build --platform linux/arm64). However, you must enable docker buildKit for it. +# More info: https://docs.docker.com/develop/develop-images/build_enhancements/ +.PHONY: docker-build +docker-build: ## Build docker image with the manager. + $(CONTAINER_TOOL) build -t ${IMG} . + +.PHONY: docker-push +docker-push: ## Push docker image with the manager. + $(CONTAINER_TOOL) push ${IMG} + +# PLATFORMS defines the target platforms for the manager image be built to provide support to multiple +# architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to: +# - be able to use docker buildx. More info: https://docs.docker.com/build/buildx/ +# - have enabled BuildKit. More info: https://docs.docker.com/develop/develop-images/build_enhancements/ +# - be able to push the image to your registry (i.e. if you do not set a valid value via IMG=> then the export will fail) +# To adequately provide solutions that are compatible with multiple platforms, you should consider using this option. +PLATFORMS ?= linux/arm64,linux/amd64,linux/s390x,linux/ppc64le +.PHONY: docker-buildx +docker-buildx: ## Build and push docker image for the manager for cross-platform support + # copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross, and preserve the original Dockerfile + sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross + - $(CONTAINER_TOOL) buildx create --name etcd-operator-builder + $(CONTAINER_TOOL) buildx use etcd-operator-builder + - $(CONTAINER_TOOL) buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross . + - $(CONTAINER_TOOL) buildx rm etcd-operator-builder + rm Dockerfile.cross + +.PHONY: build-installer +build-installer: manifests generate kustomize ## Generate a consolidated YAML with CRDs and deployment. + mkdir -p dist + cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG} + $(KUSTOMIZE) build config/default > dist/install.yaml + +##@ Deployment + +ifndef ignore-not-found + ignore-not-found = false +endif + +.PHONY: install +install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config. + $(KUSTOMIZE) build config/crd | $(KUBECTL) apply -f - + +.PHONY: uninstall +uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. + $(KUSTOMIZE) build config/crd | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f - + +.PHONY: deploy +deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config. + cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG} + $(KUSTOMIZE) build config/default | $(KUBECTL) apply -f - + +.PHONY: undeploy +undeploy: kustomize ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. + $(KUSTOMIZE) build config/default | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f - + +##@ Dependencies + +## Location to install dependencies to +LOCALBIN ?= $(shell pwd)/bin +$(LOCALBIN): + mkdir -p $(LOCALBIN) + +## Tool Binaries +KUBECTL ?= kubectl +KUSTOMIZE ?= $(LOCALBIN)/kustomize +CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen +ENVTEST ?= $(LOCALBIN)/setup-envtest +GOLANGCI_LINT = $(LOCALBIN)/golangci-lint + +## Tool Versions +KUSTOMIZE_VERSION ?= v5.4.3 +CONTROLLER_TOOLS_VERSION ?= v0.16.4 +ENVTEST_VERSION ?= release-0.19 +GOLANGCI_LINT_VERSION ?= v1.59.1 + +.PHONY: kustomize +kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary. +$(KUSTOMIZE): $(LOCALBIN) + $(call go-install-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v5,$(KUSTOMIZE_VERSION)) + +.PHONY: controller-gen +controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary. +$(CONTROLLER_GEN): $(LOCALBIN) + $(call go-install-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen,$(CONTROLLER_TOOLS_VERSION)) + +.PHONY: envtest +envtest: $(ENVTEST) ## Download setup-envtest locally if necessary. +$(ENVTEST): $(LOCALBIN) + $(call go-install-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest,$(ENVTEST_VERSION)) + +.PHONY: golangci-lint +golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary. +$(GOLANGCI_LINT): $(LOCALBIN) + $(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION)) + +# go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist +# $1 - target path with name of binary +# $2 - package url which can be installed +# $3 - specific version of package +define go-install-tool +@[ -f "$(1)-$(3)" ] || { \ +set -e; \ +package=$(2)@$(3) ;\ +echo "Downloading $${package}" ;\ +rm -f $(1) || true ;\ +GOBIN=$(LOCALBIN) go install $${package} ;\ +mv $(1) $(1)-$(3) ;\ +} ;\ +ln -sf $(1)-$(3) $(1) +endef diff --git a/PROJECT b/PROJECT new file mode 100644 index 0000000..0b8dab6 --- /dev/null +++ b/PROJECT @@ -0,0 +1,10 @@ +# Code generated by tool. DO NOT EDIT. +# This file is used to track the info used to scaffold your project +# and allow the plugins properly work. +# More info: https://book.kubebuilder.io/reference/project-config.html +domain: etcd.io +layout: +- go.kubebuilder.io/v4 +projectName: etcd-operator +repo: go.etcd.io/etcd-operator +version: "3" diff --git a/cmd/main.go b/cmd/main.go new file mode 100644 index 0000000..62165f4 --- /dev/null +++ b/cmd/main.go @@ -0,0 +1,159 @@ +/* +Copyright 2024. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "crypto/tls" + "flag" + "os" + + // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) + // to ensure that exec-entrypoint and run can make use of them. + _ "k8s.io/client-go/plugin/pkg/client/auth" + + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/healthz" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + "sigs.k8s.io/controller-runtime/pkg/metrics/filters" + metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" + "sigs.k8s.io/controller-runtime/pkg/webhook" + // +kubebuilder:scaffold:imports +) + +var ( + scheme = runtime.NewScheme() + setupLog = ctrl.Log.WithName("setup") +) + +func init() { + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + + // +kubebuilder:scaffold:scheme +} + +func main() { + var metricsAddr string + var enableLeaderElection bool + var probeAddr string + var secureMetrics bool + var enableHTTP2 bool + var tlsOpts []func(*tls.Config) + flag.StringVar(&metricsAddr, "metrics-bind-address", "0", "The address the metrics endpoint binds to. "+ + "Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service.") + flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") + flag.BoolVar(&enableLeaderElection, "leader-elect", false, + "Enable leader election for controller manager. "+ + "Enabling this will ensure there is only one active controller manager.") + flag.BoolVar(&secureMetrics, "metrics-secure", true, + "If set, the metrics endpoint is served securely via HTTPS. Use --metrics-secure=false to use HTTP instead.") + flag.BoolVar(&enableHTTP2, "enable-http2", false, + "If set, HTTP/2 will be enabled for the metrics and webhook servers") + opts := zap.Options{ + Development: true, + } + opts.BindFlags(flag.CommandLine) + flag.Parse() + + ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) + + // if the enable-http2 flag is false (the default), http/2 should be disabled + // due to its vulnerabilities. More specifically, disabling http/2 will + // prevent from being vulnerable to the HTTP/2 Stream Cancellation and + // Rapid Reset CVEs. For more information see: + // - https://github.com/advisories/GHSA-qppj-fm5r-hxr3 + // - https://github.com/advisories/GHSA-4374-p667-p6c8 + disableHTTP2 := func(c *tls.Config) { + setupLog.Info("disabling http/2") + c.NextProtos = []string{"http/1.1"} + } + + if !enableHTTP2 { + tlsOpts = append(tlsOpts, disableHTTP2) + } + + webhookServer := webhook.NewServer(webhook.Options{ + TLSOpts: tlsOpts, + }) + + // Metrics endpoint is enabled in 'config/default/kustomization.yaml'. The Metrics options configure the server. + // More info: + // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.0/pkg/metrics/server + // - https://book.kubebuilder.io/reference/metrics.html + metricsServerOptions := metricsserver.Options{ + BindAddress: metricsAddr, + SecureServing: secureMetrics, + // TODO(user): TLSOpts is used to allow configuring the TLS config used for the server. If certificates are + // not provided, self-signed certificates will be generated by default. This option is not recommended for + // production environments as self-signed certificates do not offer the same level of trust and security + // as certificates issued by a trusted Certificate Authority (CA). The primary risk is potentially allowing + // unauthorized access to sensitive metrics data. Consider replacing with CertDir, CertName, and KeyName + // to provide certificates, ensuring the server communicates using trusted and secure certificates. + TLSOpts: tlsOpts, + } + + if secureMetrics { + // FilterProvider is used to protect the metrics endpoint with authn/authz. + // These configurations ensure that only authorized users and service accounts + // can access the metrics endpoint. The RBAC are configured in 'config/rbac/kustomization.yaml'. More info: + // https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.0/pkg/metrics/filters#WithAuthenticationAndAuthorization + metricsServerOptions.FilterProvider = filters.WithAuthenticationAndAuthorization + } + + mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ + Scheme: scheme, + Metrics: metricsServerOptions, + WebhookServer: webhookServer, + HealthProbeBindAddress: probeAddr, + LeaderElection: enableLeaderElection, + LeaderElectionID: "cc4a0f4b.etcd.io", + // LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily + // when the Manager ends. This requires the binary to immediately end when the + // Manager is stopped, otherwise, this setting is unsafe. Setting this significantly + // speeds up voluntary leader transitions as the new leader don't have to wait + // LeaseDuration time first. + // + // In the default scaffold provided, the program ends immediately after + // the manager stops, so would be fine to enable this option. However, + // if you are doing or is intended to do any operation such as perform cleanups + // after the manager stops then its usage might be unsafe. + // LeaderElectionReleaseOnCancel: true, + }) + if err != nil { + setupLog.Error(err, "unable to start manager") + os.Exit(1) + } + + // +kubebuilder:scaffold:builder + + if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { + setupLog.Error(err, "unable to set up health check") + os.Exit(1) + } + if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil { + setupLog.Error(err, "unable to set up ready check") + os.Exit(1) + } + + setupLog.Info("starting manager") + if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { + setupLog.Error(err, "problem running manager") + os.Exit(1) + } +} diff --git a/config/default/kustomization.yaml b/config/default/kustomization.yaml new file mode 100644 index 0000000..512fb7f --- /dev/null +++ b/config/default/kustomization.yaml @@ -0,0 +1,177 @@ +# Adds namespace to all resources. +namespace: etcd-operator-system + +# Value of this field is prepended to the +# names of all resources, e.g. a deployment named +# "wordpress" becomes "alices-wordpress". +# Note that it should also match with the prefix (text before '-') of the namespace +# field above. +namePrefix: etcd-operator- + +# Labels to add to all resources and selectors. +#labels: +#- includeSelectors: true +# pairs: +# someName: someValue + +resources: +#- ../crd +- ../rbac +- ../manager +# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in +# crd/kustomization.yaml +#- ../webhook +# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required. +#- ../certmanager +# [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'. +#- ../prometheus +# [METRICS] Expose the controller manager metrics service. +- metrics_service.yaml +# [NETWORK POLICY] Protect the /metrics endpoint and Webhook Server with NetworkPolicy. +# Only Pod(s) running a namespace labeled with 'metrics: enabled' will be able to gather the metrics. +# Only CR(s) which requires webhooks and are applied on namespaces labeled with 'webhooks: enabled' will +# be able to communicate with the Webhook Server. +#- ../network-policy + +# Uncomment the patches line if you enable Metrics, and/or are using webhooks and cert-manager +patches: +# [METRICS] The following patch will enable the metrics endpoint using HTTPS and the port :8443. +# More info: https://book.kubebuilder.io/reference/metrics +- path: manager_metrics_patch.yaml + target: + kind: Deployment + +# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in +# crd/kustomization.yaml +#- path: manager_webhook_patch.yaml + +# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix. +# Uncomment the following replacements to add the cert-manager CA injection annotations +#replacements: +# - source: # Uncomment the following block if you have a ValidatingWebhook (--programmatic-validation) +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: serving-cert # This name should match the one in certificate.yaml +# fieldPath: .metadata.namespace # Namespace of the certificate CR +# targets: +# - select: +# kind: ValidatingWebhookConfiguration +# fieldPaths: +# - .metadata.annotations.[cert-manager.io/inject-ca-from] +# options: +# delimiter: '/' +# index: 0 +# create: true +# - source: +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: serving-cert # This name should match the one in certificate.yaml +# fieldPath: .metadata.name +# targets: +# - select: +# kind: ValidatingWebhookConfiguration +# fieldPaths: +# - .metadata.annotations.[cert-manager.io/inject-ca-from] +# options: +# delimiter: '/' +# index: 1 +# create: true +# +# - source: # Uncomment the following block if you have a DefaultingWebhook (--defaulting ) +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: serving-cert # This name should match the one in certificate.yaml +# fieldPath: .metadata.namespace # Namespace of the certificate CR +# targets: +# - select: +# kind: MutatingWebhookConfiguration +# fieldPaths: +# - .metadata.annotations.[cert-manager.io/inject-ca-from] +# options: +# delimiter: '/' +# index: 0 +# create: true +# - source: +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: serving-cert # This name should match the one in certificate.yaml +# fieldPath: .metadata.name +# targets: +# - select: +# kind: MutatingWebhookConfiguration +# fieldPaths: +# - .metadata.annotations.[cert-manager.io/inject-ca-from] +# options: +# delimiter: '/' +# index: 1 +# create: true +# +# - source: # Uncomment the following block if you have a ConversionWebhook (--conversion) +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: serving-cert # This name should match the one in certificate.yaml +# fieldPath: .metadata.namespace # Namespace of the certificate CR +# targets: +# - select: +# kind: CustomResourceDefinition +# fieldPaths: +# - .metadata.annotations.[cert-manager.io/inject-ca-from] +# options: +# delimiter: '/' +# index: 0 +# create: true +# - source: +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: serving-cert # This name should match the one in certificate.yaml +# fieldPath: .metadata.name +# targets: +# - select: +# kind: CustomResourceDefinition +# fieldPaths: +# - .metadata.annotations.[cert-manager.io/inject-ca-from] +# options: +# delimiter: '/' +# index: 1 +# create: true +# +# - source: # Uncomment the following block if you enable cert-manager +# kind: Service +# version: v1 +# name: webhook-service +# fieldPath: .metadata.name # Name of the service +# targets: +# - select: +# kind: Certificate +# group: cert-manager.io +# version: v1 +# fieldPaths: +# - .spec.dnsNames.0 +# - .spec.dnsNames.1 +# options: +# delimiter: '.' +# index: 0 +# create: true +# - source: +# kind: Service +# version: v1 +# name: webhook-service +# fieldPath: .metadata.namespace # Namespace of the service +# targets: +# - select: +# kind: Certificate +# group: cert-manager.io +# version: v1 +# fieldPaths: +# - .spec.dnsNames.0 +# - .spec.dnsNames.1 +# options: +# delimiter: '.' +# index: 1 +# create: true diff --git a/config/default/manager_metrics_patch.yaml b/config/default/manager_metrics_patch.yaml new file mode 100644 index 0000000..2aaef65 --- /dev/null +++ b/config/default/manager_metrics_patch.yaml @@ -0,0 +1,4 @@ +# This patch adds the args to allow exposing the metrics endpoint using HTTPS +- op: add + path: /spec/template/spec/containers/0/args/0 + value: --metrics-bind-address=:8443 diff --git a/config/default/metrics_service.yaml b/config/default/metrics_service.yaml new file mode 100644 index 0000000..07ffb27 --- /dev/null +++ b/config/default/metrics_service.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + control-plane: controller-manager + app.kubernetes.io/name: etcd-operator + app.kubernetes.io/managed-by: kustomize + name: controller-manager-metrics-service + namespace: system +spec: + ports: + - name: https + port: 8443 + protocol: TCP + targetPort: 8443 + selector: + control-plane: controller-manager diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml new file mode 100644 index 0000000..5c5f0b8 --- /dev/null +++ b/config/manager/kustomization.yaml @@ -0,0 +1,2 @@ +resources: +- manager.yaml diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml new file mode 100644 index 0000000..c3164c4 --- /dev/null +++ b/config/manager/manager.yaml @@ -0,0 +1,95 @@ +apiVersion: v1 +kind: Namespace +metadata: + labels: + control-plane: controller-manager + app.kubernetes.io/name: etcd-operator + app.kubernetes.io/managed-by: kustomize + name: system +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: controller-manager + namespace: system + labels: + control-plane: controller-manager + app.kubernetes.io/name: etcd-operator + app.kubernetes.io/managed-by: kustomize +spec: + selector: + matchLabels: + control-plane: controller-manager + replicas: 1 + template: + metadata: + annotations: + kubectl.kubernetes.io/default-container: manager + labels: + control-plane: controller-manager + spec: + # TODO(user): Uncomment the following code to configure the nodeAffinity expression + # according to the platforms which are supported by your solution. + # It is considered best practice to support multiple architectures. You can + # build your manager image using the makefile target docker-buildx. + # affinity: + # nodeAffinity: + # requiredDuringSchedulingIgnoredDuringExecution: + # nodeSelectorTerms: + # - matchExpressions: + # - key: kubernetes.io/arch + # operator: In + # values: + # - amd64 + # - arm64 + # - ppc64le + # - s390x + # - key: kubernetes.io/os + # operator: In + # values: + # - linux + securityContext: + runAsNonRoot: true + # TODO(user): For common cases that do not require escalating privileges + # it is recommended to ensure that all your Pods/Containers are restrictive. + # More info: https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted + # Please uncomment the following code if your project does NOT have to work on old Kubernetes + # versions < 1.19 or on vendors versions which do NOT support this field by default (i.e. Openshift < 4.11 ). + # seccompProfile: + # type: RuntimeDefault + containers: + - command: + - /manager + args: + - --leader-elect + - --health-probe-bind-address=:8081 + image: controller:latest + name: manager + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - "ALL" + livenessProbe: + httpGet: + path: /healthz + port: 8081 + initialDelaySeconds: 15 + periodSeconds: 20 + readinessProbe: + httpGet: + path: /readyz + port: 8081 + initialDelaySeconds: 5 + periodSeconds: 10 + # TODO(user): Configure the resources accordingly based on the project requirements. + # More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 10m + memory: 64Mi + serviceAccountName: controller-manager + terminationGracePeriodSeconds: 10 diff --git a/config/network-policy/allow-metrics-traffic.yaml b/config/network-policy/allow-metrics-traffic.yaml new file mode 100644 index 0000000..9f83870 --- /dev/null +++ b/config/network-policy/allow-metrics-traffic.yaml @@ -0,0 +1,26 @@ +# This NetworkPolicy allows ingress traffic +# with Pods running on namespaces labeled with 'metrics: enabled'. Only Pods on those +# namespaces are able to gathering data from the metrics endpoint. +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + labels: + app.kubernetes.io/name: etcd-operator + app.kubernetes.io/managed-by: kustomize + name: allow-metrics-traffic + namespace: system +spec: + podSelector: + matchLabels: + control-plane: controller-manager + policyTypes: + - Ingress + ingress: + # This allows ingress traffic from any namespace with the label metrics: enabled + - from: + - namespaceSelector: + matchLabels: + metrics: enabled # Only from namespaces with this label + ports: + - port: 8443 + protocol: TCP diff --git a/config/network-policy/kustomization.yaml b/config/network-policy/kustomization.yaml new file mode 100644 index 0000000..ec0fb5e --- /dev/null +++ b/config/network-policy/kustomization.yaml @@ -0,0 +1,2 @@ +resources: +- allow-metrics-traffic.yaml diff --git a/config/prometheus/kustomization.yaml b/config/prometheus/kustomization.yaml new file mode 100644 index 0000000..ed13716 --- /dev/null +++ b/config/prometheus/kustomization.yaml @@ -0,0 +1,2 @@ +resources: +- monitor.yaml diff --git a/config/prometheus/monitor.yaml b/config/prometheus/monitor.yaml new file mode 100644 index 0000000..b6cad92 --- /dev/null +++ b/config/prometheus/monitor.yaml @@ -0,0 +1,30 @@ +# Prometheus Monitor Service (Metrics) +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + labels: + control-plane: controller-manager + app.kubernetes.io/name: etcd-operator + app.kubernetes.io/managed-by: kustomize + name: controller-manager-metrics-monitor + namespace: system +spec: + endpoints: + - path: /metrics + port: https # Ensure this is the name of the port that exposes HTTPS metrics + scheme: https + bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token + tlsConfig: + # TODO(user): The option insecureSkipVerify: true is not recommended for production since it disables + # certificate verification. This poses a significant security risk by making the system vulnerable to + # man-in-the-middle attacks, where an attacker could intercept and manipulate the communication between + # Prometheus and the monitored services. This could lead to unauthorized access to sensitive metrics data, + # compromising the integrity and confidentiality of the information. + # Please use the following options for secure configurations: + # caFile: /etc/metrics-certs/ca.crt + # certFile: /etc/metrics-certs/tls.crt + # keyFile: /etc/metrics-certs/tls.key + insecureSkipVerify: true + selector: + matchLabels: + control-plane: controller-manager diff --git a/config/rbac/kustomization.yaml b/config/rbac/kustomization.yaml new file mode 100644 index 0000000..5619aa0 --- /dev/null +++ b/config/rbac/kustomization.yaml @@ -0,0 +1,20 @@ +resources: +# All RBAC will be applied under this service account in +# the deployment namespace. You may comment out this resource +# if your manager will use a service account that exists at +# runtime. Be sure to update RoleBinding and ClusterRoleBinding +# subjects if changing service account names. +- service_account.yaml +- role.yaml +- role_binding.yaml +- leader_election_role.yaml +- leader_election_role_binding.yaml +# The following RBAC configurations are used to protect +# the metrics endpoint with authn/authz. These configurations +# ensure that only authorized users and service accounts +# can access the metrics endpoint. Comment the following +# permissions if you want to disable this protection. +# More info: https://book.kubebuilder.io/reference/metrics.html +- metrics_auth_role.yaml +- metrics_auth_role_binding.yaml +- metrics_reader_role.yaml diff --git a/config/rbac/leader_election_role.yaml b/config/rbac/leader_election_role.yaml new file mode 100644 index 0000000..ef5189e --- /dev/null +++ b/config/rbac/leader_election_role.yaml @@ -0,0 +1,40 @@ +# permissions to do leader election. +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + labels: + app.kubernetes.io/name: etcd-operator + app.kubernetes.io/managed-by: kustomize + name: leader-election-role +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch diff --git a/config/rbac/leader_election_role_binding.yaml b/config/rbac/leader_election_role_binding.yaml new file mode 100644 index 0000000..f7cf464 --- /dev/null +++ b/config/rbac/leader_election_role_binding.yaml @@ -0,0 +1,15 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + labels: + app.kubernetes.io/name: etcd-operator + app.kubernetes.io/managed-by: kustomize + name: leader-election-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: leader-election-role +subjects: +- kind: ServiceAccount + name: controller-manager + namespace: system diff --git a/config/rbac/metrics_auth_role.yaml b/config/rbac/metrics_auth_role.yaml new file mode 100644 index 0000000..32d2e4e --- /dev/null +++ b/config/rbac/metrics_auth_role.yaml @@ -0,0 +1,17 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: metrics-auth-role +rules: +- apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create +- apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create diff --git a/config/rbac/metrics_auth_role_binding.yaml b/config/rbac/metrics_auth_role_binding.yaml new file mode 100644 index 0000000..e775d67 --- /dev/null +++ b/config/rbac/metrics_auth_role_binding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: metrics-auth-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: metrics-auth-role +subjects: +- kind: ServiceAccount + name: controller-manager + namespace: system diff --git a/config/rbac/metrics_reader_role.yaml b/config/rbac/metrics_reader_role.yaml new file mode 100644 index 0000000..51a75db --- /dev/null +++ b/config/rbac/metrics_reader_role.yaml @@ -0,0 +1,9 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: metrics-reader +rules: +- nonResourceURLs: + - "/metrics" + verbs: + - get diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml new file mode 100644 index 0000000..f8f8aed --- /dev/null +++ b/config/rbac/role.yaml @@ -0,0 +1,11 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: etcd-operator + app.kubernetes.io/managed-by: kustomize + name: manager-role +rules: +- apiGroups: [""] + resources: ["pods"] + verbs: ["get", "list", "watch"] diff --git a/config/rbac/role_binding.yaml b/config/rbac/role_binding.yaml new file mode 100644 index 0000000..4d24efd --- /dev/null +++ b/config/rbac/role_binding.yaml @@ -0,0 +1,15 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/name: etcd-operator + app.kubernetes.io/managed-by: kustomize + name: manager-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: manager-role +subjects: +- kind: ServiceAccount + name: controller-manager + namespace: system diff --git a/config/rbac/service_account.yaml b/config/rbac/service_account.yaml new file mode 100644 index 0000000..fa4a570 --- /dev/null +++ b/config/rbac/service_account.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + app.kubernetes.io/name: etcd-operator + app.kubernetes.io/managed-by: kustomize + name: controller-manager + namespace: system diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..6b61fa7 --- /dev/null +++ b/go.mod @@ -0,0 +1,98 @@ +module go.etcd.io/etcd-operator + +go 1.22.0 + +require ( + github.com/onsi/ginkgo/v2 v2.19.0 + github.com/onsi/gomega v1.33.1 + k8s.io/apimachinery v0.31.0 + k8s.io/client-go v0.31.0 + sigs.k8s.io/controller-runtime v0.19.0 +) + +require ( + github.com/antlr4-go/antlr/v4 v4.13.0 // indirect + github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/blang/semver/v4 v4.0.0 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/evanphx/json-patch/v5 v5.9.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/fxamacker/cbor/v2 v2.7.0 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-logr/zapr v1.3.0 // indirect + github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/swag v0.22.4 // indirect + github.com/go-task/slim-sprig/v3 v3.0.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/google/cel-go v0.20.1 // indirect + github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/go-cmp v0.6.0 // indirect + github.com/google/gofuzz v1.2.0 // indirect + github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect + github.com/imdario/mergo v0.3.6 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/prometheus/client_golang v1.19.1 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect + github.com/spf13/cobra v1.8.1 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/stoewer/go-strcase v1.2.0 // indirect + github.com/x448/float16 v0.8.4 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect + go.opentelemetry.io/otel v1.28.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 // indirect + go.opentelemetry.io/otel/metric v1.28.0 // indirect + go.opentelemetry.io/otel/sdk v1.28.0 // indirect + go.opentelemetry.io/otel/trace v1.28.0 // indirect + go.opentelemetry.io/proto/otlp v1.3.1 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.26.0 // indirect + golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc // indirect + golang.org/x/net v0.26.0 // indirect + golang.org/x/oauth2 v0.21.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.21.0 // indirect + golang.org/x/term v0.21.0 // indirect + golang.org/x/text v0.16.0 // indirect + golang.org/x/time v0.3.0 // indirect + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect + google.golang.org/grpc v1.65.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/api v0.31.0 // indirect + k8s.io/apiextensions-apiserver v0.31.0 // indirect + k8s.io/apiserver v0.31.0 // indirect + k8s.io/component-base v0.31.0 // indirect + k8s.io/klog/v2 v2.130.1 // indirect + k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect + k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect + sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect + sigs.k8s.io/yaml v1.4.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..a8ec01d --- /dev/null +++ b/go.sum @@ -0,0 +1,251 @@ +github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= +github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/evanphx/json-patch v0.5.2 h1:xVCHIVMUu1wtM/VkR9jVZ45N3FhZfYMMYGorLCR8P3k= +github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= +github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= +github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= +github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= +github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= +github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/cel-go v0.20.1 h1:nDx9r8S3L4pE61eDdt8igGj8rf5kjYR3ILxWIpWNi84= +github.com/google/cel-go v0.20.1/go.mod h1:kWcIzTsPX0zmQ+H3TirHstLLf9ep5QTsZBN9u4dOYLg= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM= +github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= +github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= +github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= +github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= +github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= +github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= +github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= +github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= +go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= +go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 h1:qFffATk0X+HD+f1Z8lswGiOQYKHRlzfmdJm0wEaVrFA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0/go.mod h1:MOiCmryaYtc+V0Ei+Tx9o5S1ZjA7kzLucuVuyzBZloQ= +go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= +go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= +go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= +go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= +go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= +go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= +go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= +go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc h1:mCRnTeVUjcrhlRmO0VK8a6k6Rrf6TF9htwo2pJVSjIU= +golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= +golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= +golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= +gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= +google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 h1:7whR9kGa5LUwFtpLm2ArCEejtnxlGeLbAyjFY8sGNFw= +google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= +google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= +google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= +gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +k8s.io/api v0.31.0 h1:b9LiSjR2ym/SzTOlfMHm1tr7/21aD7fSkqgD/CVJBCo= +k8s.io/api v0.31.0/go.mod h1:0YiFF+JfFxMM6+1hQei8FY8M7s1Mth+z/q7eF1aJkTE= +k8s.io/apiextensions-apiserver v0.31.0 h1:fZgCVhGwsclj3qCw1buVXCV6khjRzKC5eCFt24kyLSk= +k8s.io/apiextensions-apiserver v0.31.0/go.mod h1:b9aMDEYaEe5sdK+1T0KU78ApR/5ZVp4i56VacZYEHxk= +k8s.io/apimachinery v0.31.0 h1:m9jOiSr3FoSSL5WO9bjm1n6B9KROYYgNZOb4tyZ1lBc= +k8s.io/apimachinery v0.31.0/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= +k8s.io/apiserver v0.31.0 h1:p+2dgJjy+bk+B1Csz+mc2wl5gHwvNkC9QJV+w55LVrY= +k8s.io/apiserver v0.31.0/go.mod h1:KI9ox5Yu902iBnnyMmy7ajonhKnkeZYJhTZ/YI+WEMk= +k8s.io/client-go v0.31.0 h1:QqEJzNjbN2Yv1H79SsS+SWnXkBgVu4Pj3CJQgbx0gI8= +k8s.io/client-go v0.31.0/go.mod h1:Y9wvC76g4fLjmU0BA+rV+h2cncoadjvjjkkIGoTLcGU= +k8s.io/component-base v0.31.0 h1:/KIzGM5EvPNQcYgwq5NwoQBaOlVFrghoVGr8lG6vNRs= +k8s.io/component-base v0.31.0/go.mod h1:TYVuzI1QmN4L5ItVdMSXKvH7/DtvIuas5/mm8YT3rTo= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= +k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 h1:2770sDpzrjjsAtVhSeUFseziht227YAWYHLGNM8QPwY= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= +sigs.k8s.io/controller-runtime v0.19.0 h1:nWVM7aq+Il2ABxwiCizrVDSlmDcshi9llbaFbC0ji/Q= +sigs.k8s.io/controller-runtime v0.19.0/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/hack/boilerplate.go.txt b/hack/boilerplate.go.txt new file mode 100644 index 0000000..ff72ff2 --- /dev/null +++ b/hack/boilerplate.go.txt @@ -0,0 +1,15 @@ +/* +Copyright 2024. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ \ No newline at end of file diff --git a/test/e2e/e2e_suite_test.go b/test/e2e/e2e_suite_test.go new file mode 100644 index 0000000..78e2ddf --- /dev/null +++ b/test/e2e/e2e_suite_test.go @@ -0,0 +1,120 @@ +/* +Copyright 2024. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package e2e + +import ( + "fmt" + "os" + "os/exec" + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "go.etcd.io/etcd-operator/test/utils" +) + +var ( + // Optional Environment Variables: + // - PROMETHEUS_INSTALL_SKIP=true: Skips Prometheus Operator installation during test setup. + // - CERT_MANAGER_INSTALL_SKIP=true: Skips CertManager installation during test setup. + // These variables are useful if Prometheus or CertManager is already installed, avoiding + // re-installation and conflicts. + skipPrometheusInstall = os.Getenv("PROMETHEUS_INSTALL_SKIP") == "true" + skipCertManagerInstall = os.Getenv("CERT_MANAGER_INSTALL_SKIP") == "true" + // isPrometheusOperatorAlreadyInstalled will be set true when prometheus CRDs be found on the cluster + isPrometheusOperatorAlreadyInstalled = false + // isCertManagerAlreadyInstalled will be set true when CertManager CRDs be found on the cluster + isCertManagerAlreadyInstalled = false + + // projectImage is the name of the image which will be build and loaded + // with the code source changes to be tested. + projectImage = "example.com/etcd-operator:v0.0.1" +) + +// TestE2E runs the end-to-end (e2e) test suite for the project. These tests execute in an isolated, +// temporary environment to validate project changes with the the purposed to be used in CI jobs. +// The default setup requires Kind, builds/loads the Manager Docker image locally, and installs +// CertManager and Prometheus. +func TestE2E(t *testing.T) { + RegisterFailHandler(Fail) + _, _ = fmt.Fprintf(GinkgoWriter, "Starting etcd-operator integration test suite\n") + RunSpecs(t, "e2e suite") +} + +var _ = BeforeSuite(func() { + By("Ensure that Prometheus is enabled") + _ = utils.UncommentCode("config/default/kustomization.yaml", "#- ../prometheus", "#") + + By("generating files") + cmd := exec.Command("make", "generate") + _, err := utils.Run(cmd) + ExpectWithOffset(1, err).NotTo(HaveOccurred(), "Failed to run make generate") + + By("generating manifests") + cmd = exec.Command("make", "manifests") + _, err = utils.Run(cmd) + ExpectWithOffset(1, err).NotTo(HaveOccurred(), "Failed to run make manifests") + + By("building the manager(Operator) image") + cmd = exec.Command("make", "docker-build", fmt.Sprintf("IMG=%s", projectImage)) + _, err = utils.Run(cmd) + ExpectWithOffset(1, err).NotTo(HaveOccurred(), "Failed to build the manager(Operator) image") + + // TODO(user): If you want to change the e2e test vendor from Kind, ensure the image is + // built and available before running the tests. Also, remove the following block. + By("loading the manager(Operator) image on Kind") + err = utils.LoadImageToKindClusterWithName(projectImage) + ExpectWithOffset(1, err).NotTo(HaveOccurred(), "Failed to load the manager(Operator) image into Kind") + + // The tests-e2e are intended to run on a temporary cluster that is created and destroyed for testing. + // To prevent errors when tests run in environments with Prometheus or CertManager already installed, + // we check for their presence before execution. + // Setup Prometheus and CertManager before the suite if not skipped and if not already installed + if !skipPrometheusInstall { + By("checking if prometheus is installed already") + isPrometheusOperatorAlreadyInstalled = utils.IsPrometheusCRDsInstalled() + if !isPrometheusOperatorAlreadyInstalled { + _, _ = fmt.Fprintf(GinkgoWriter, "Installing Prometheus Operator...\n") + Expect(utils.InstallPrometheusOperator()).To(Succeed(), "Failed to install Prometheus Operator") + } else { + _, _ = fmt.Fprintf(GinkgoWriter, "WARNING: Prometheus Operator is already installed. Skipping installation...\n") + } + } + if !skipCertManagerInstall { + By("checking if cert manager is installed already") + isCertManagerAlreadyInstalled = utils.IsCertManagerCRDsInstalled() + if !isCertManagerAlreadyInstalled { + _, _ = fmt.Fprintf(GinkgoWriter, "Installing CertManager...\n") + Expect(utils.InstallCertManager()).To(Succeed(), "Failed to install CertManager") + } else { + _, _ = fmt.Fprintf(GinkgoWriter, "WARNING: CertManager is already installed. Skipping installation...\n") + } + } +}) + +var _ = AfterSuite(func() { + // Teardown Prometheus and CertManager after the suite if not skipped and if they were not already installed + if !skipPrometheusInstall && !isPrometheusOperatorAlreadyInstalled { + _, _ = fmt.Fprintf(GinkgoWriter, "Uninstalling Prometheus Operator...\n") + utils.UninstallPrometheusOperator() + } + if !skipCertManagerInstall && !isCertManagerAlreadyInstalled { + _, _ = fmt.Fprintf(GinkgoWriter, "Uninstalling CertManager...\n") + utils.UninstallCertManager() + } +}) diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go new file mode 100644 index 0000000..61cddb3 --- /dev/null +++ b/test/e2e/e2e_test.go @@ -0,0 +1,307 @@ +/* +Copyright 2024. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package e2e + +import ( + "encoding/json" + "fmt" + "os" + "os/exec" + "path/filepath" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "go.etcd.io/etcd-operator/test/utils" +) + +// namespace where the project is deployed in +const namespace = "etcd-operator-system" + +// serviceAccountName created for the project +const serviceAccountName = "etcd-operator-controller-manager" + +// metricsServiceName is the name of the metrics service of the project +const metricsServiceName = "etcd-operator-controller-manager-metrics-service" + +// metricsRoleBindingName is the name of the RBAC that will be created to allow get the metrics data +const metricsRoleBindingName = "etcd-operator-metrics-binding" + +var _ = Describe("Manager", Ordered, func() { + var controllerPodName string + + // Before running the tests, set up the environment by creating the namespace, + // installing CRDs, and deploying the controller. + BeforeAll(func() { + By("creating manager namespace") + cmd := exec.Command("kubectl", "create", "ns", namespace) + _, err := utils.Run(cmd) + Expect(err).NotTo(HaveOccurred(), "Failed to create namespace") + + By("installing CRDs") + cmd = exec.Command("make", "install") + _, err = utils.Run(cmd) + Expect(err).NotTo(HaveOccurred(), "Failed to install CRDs") + + By("deploying the controller-manager") + cmd = exec.Command("make", "deploy", fmt.Sprintf("IMG=%s", projectImage)) + _, err = utils.Run(cmd) + Expect(err).NotTo(HaveOccurred(), "Failed to deploy the controller-manager") + }) + + // After all tests have been executed, clean up by undeploying the controller, uninstalling CRDs, + // and deleting the namespace. + AfterAll(func() { + By("cleaning up the curl pod for metrics") + cmd := exec.Command("kubectl", "delete", "pod", "curl-metrics", "-n", namespace) + _, _ = utils.Run(cmd) + + By("undeploying the controller-manager") + cmd = exec.Command("make", "undeploy") + _, _ = utils.Run(cmd) + + By("uninstalling CRDs") + cmd = exec.Command("make", "uninstall") + _, _ = utils.Run(cmd) + + By("removing manager namespace") + cmd = exec.Command("kubectl", "delete", "ns", namespace) + _, _ = utils.Run(cmd) + }) + + // After each test, check for failures and collect logs, events, + // and pod descriptions for debugging. + AfterEach(func() { + specReport := CurrentSpecReport() + if specReport.Failed() { + By("Fetching controller manager pod logs") + cmd := exec.Command("kubectl", "logs", controllerPodName, "-n", namespace) + controllerLogs, err := utils.Run(cmd) + if err == nil { + _, _ = fmt.Fprintf(GinkgoWriter, fmt.Sprintf("Controller logs:\n %s", controllerLogs)) + } else { + _, _ = fmt.Fprintf(GinkgoWriter, fmt.Sprintf("Failed to get Controller logs: %s", err)) + } + + By("Fetching Kubernetes events") + cmd = exec.Command("kubectl", "get", "events", "-n", namespace, "--sort-by=.lastTimestamp") + eventsOutput, err := utils.Run(cmd) + if err == nil { + _, _ = fmt.Fprintf(GinkgoWriter, fmt.Sprintf("Kubernetes events:\n%s", eventsOutput)) + } else { + _, _ = fmt.Fprintf(GinkgoWriter, fmt.Sprintf("Failed to get Kubernetes events: %s", err)) + } + + By("Fetching curl-metrics logs") + cmd = exec.Command("kubectl", "logs", "curl-metrics", "-n", namespace) + metricsOutput, err := utils.Run(cmd) + if err == nil { + _, _ = fmt.Fprintf(GinkgoWriter, fmt.Sprintf("Metrics logs:\n %s", metricsOutput)) + } else { + _, _ = fmt.Fprintf(GinkgoWriter, fmt.Sprintf("Failed to get curl-metrics logs: %s", err)) + } + + By("Fetching controller manager pod description") + cmd = exec.Command("kubectl", "describe", "pod", controllerPodName, "-n", namespace) + podDescription, err := utils.Run(cmd) + if err == nil { + fmt.Println("Pod description:\n", podDescription) + } else { + fmt.Println("Failed to describe controller pod") + } + } + }) + + SetDefaultEventuallyTimeout(2 * time.Minute) + SetDefaultEventuallyPollingInterval(time.Second) + + Context("Manager", func() { + It("should run successfully", func() { + By("validating that the controller-manager pod is running as expected") + verifyControllerUp := func(g Gomega) { + // Get the name of the controller-manager pod + cmd := exec.Command("kubectl", "get", + "pods", "-l", "control-plane=controller-manager", + "-o", "go-template={{ range .items }}"+ + "{{ if not .metadata.deletionTimestamp }}"+ + "{{ .metadata.name }}"+ + "{{ \"\\n\" }}{{ end }}{{ end }}", + "-n", namespace, + ) + + podOutput, err := utils.Run(cmd) + g.Expect(err).NotTo(HaveOccurred(), "Failed to retrieve controller-manager pod information") + podNames := utils.GetNonEmptyLines(podOutput) + g.Expect(podNames).To(HaveLen(1), "expected 1 controller pod running") + controllerPodName = podNames[0] + g.Expect(controllerPodName).To(ContainSubstring("controller-manager")) + + // Validate the pod's status + cmd = exec.Command("kubectl", "get", + "pods", controllerPodName, "-o", "jsonpath={.status.phase}", + "-n", namespace, + ) + output, err := utils.Run(cmd) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(output).To(Equal("Running"), "Incorrect controller-manager pod status") + } + Eventually(verifyControllerUp).Should(Succeed()) + }) + + It("should ensure the metrics endpoint is serving metrics", func() { + By("creating a ClusterRoleBinding for the service account to allow access to metrics") + cmd := exec.Command("kubectl", "create", "clusterrolebinding", metricsRoleBindingName, + "--clusterrole=etcd-operator-metrics-reader", + fmt.Sprintf("--serviceaccount=%s:%s", namespace, serviceAccountName), + ) + _, err := utils.Run(cmd) + Expect(err).NotTo(HaveOccurred(), "Failed to create ClusterRoleBinding") + + By("validating that the metrics service is available") + cmd = exec.Command("kubectl", "get", "service", metricsServiceName, "-n", namespace) + _, err = utils.Run(cmd) + Expect(err).NotTo(HaveOccurred(), "Metrics service should exist") + + By("validating that the ServiceMonitor for Prometheus is applied in the namespace") + cmd = exec.Command("kubectl", "get", "ServiceMonitor", "-n", namespace) + _, err = utils.Run(cmd) + Expect(err).NotTo(HaveOccurred(), "ServiceMonitor should exist") + + By("getting the service account token") + token, err := serviceAccountToken() + Expect(err).NotTo(HaveOccurred()) + Expect(token).NotTo(BeEmpty()) + + By("waiting for the metrics endpoint to be ready") + verifyMetricsEndpointReady := func(g Gomega) { + cmd := exec.Command("kubectl", "get", "endpoints", metricsServiceName, "-n", namespace) + output, err := utils.Run(cmd) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(output).To(ContainSubstring("8443"), "Metrics endpoint is not ready") + } + Eventually(verifyMetricsEndpointReady).Should(Succeed()) + + By("verifying that the controller manager is serving the metrics server") + verifyMetricsServerStarted := func(g Gomega) { + cmd := exec.Command("kubectl", "logs", controllerPodName, "-n", namespace) + output, err := utils.Run(cmd) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(output).To(ContainSubstring("controller-runtime.metrics\tServing metrics server"), + "Metrics server not yet started") + } + Eventually(verifyMetricsServerStarted).Should(Succeed()) + + By("creating the curl-metrics pod to access the metrics endpoint") + cmd = exec.Command("kubectl", "run", "curl-metrics", "--restart=Never", + "--namespace", namespace, + "--image=curlimages/curl:7.78.0", + "--", "/bin/sh", "-c", fmt.Sprintf( + "curl -v -k -H 'Authorization: Bearer %s' https://%s.%s.svc.cluster.local:8443/metrics", + token, metricsServiceName, namespace)) + _, err = utils.Run(cmd) + Expect(err).NotTo(HaveOccurred(), "Failed to create curl-metrics pod") + + By("waiting for the curl-metrics pod to complete.") + verifyCurlUp := func(g Gomega) { + cmd := exec.Command("kubectl", "get", "pods", "curl-metrics", + "-o", "jsonpath={.status.phase}", + "-n", namespace) + output, err := utils.Run(cmd) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(output).To(Equal("Succeeded"), "curl pod in wrong status") + } + Eventually(verifyCurlUp, 5*time.Minute).Should(Succeed()) + + By("getting the metrics by checking curl-metrics logs") + metricsOutput := getMetricsOutput() + Expect(metricsOutput).To(ContainSubstring( + "controller_runtime_reconcile_total", + )) + }) + + // +kubebuilder:scaffold:e2e-webhooks-checks + + // TODO: Customize the e2e test suite with scenarios specific to your project. + // Consider applying sample/CR(s) and check their status and/or verifying + // the reconciliation by using the metrics, i.e.: + // metricsOutput := getMetricsOutput() + // Expect(metricsOutput).To(ContainSubstring( + // fmt.Sprintf(`controller_runtime_reconcile_total{controller="%s",result="success"} 1`, + // strings.ToLower(), + // )) + }) +}) + +// serviceAccountToken returns a token for the specified service account in the given namespace. +// It uses the Kubernetes TokenRequest API to generate a token by directly sending a request +// and parsing the resulting token from the API response. +func serviceAccountToken() (string, error) { + const tokenRequestRawString = `{ + "apiVersion": "authentication.k8s.io/v1", + "kind": "TokenRequest" + }` + + // Temporary file to store the token request + secretName := fmt.Sprintf("%s-token-request", serviceAccountName) + tokenRequestFile := filepath.Join("/tmp", secretName) + err := os.WriteFile(tokenRequestFile, []byte(tokenRequestRawString), os.FileMode(0o644)) + if err != nil { + return "", err + } + + var out string + verifyTokenCreation := func(g Gomega) { + // Execute kubectl command to create the token + cmd := exec.Command("kubectl", "create", "--raw", fmt.Sprintf( + "/api/v1/namespaces/%s/serviceaccounts/%s/token", + namespace, + serviceAccountName, + ), "-f", tokenRequestFile) + + output, err := cmd.CombinedOutput() + g.Expect(err).NotTo(HaveOccurred()) + + // Parse the JSON output to extract the token + var token tokenRequest + err = json.Unmarshal([]byte(output), &token) + g.Expect(err).NotTo(HaveOccurred()) + + out = token.Status.Token + } + Eventually(verifyTokenCreation).Should(Succeed()) + + return out, err +} + +// getMetricsOutput retrieves and returns the logs from the curl pod used to access the metrics endpoint. +func getMetricsOutput() string { + By("getting the curl-metrics logs") + cmd := exec.Command("kubectl", "logs", "curl-metrics", "-n", namespace) + metricsOutput, err := utils.Run(cmd) + Expect(err).NotTo(HaveOccurred(), "Failed to retrieve logs from curl pod") + Expect(metricsOutput).To(ContainSubstring("< HTTP/1.1 200 OK")) + return metricsOutput +} + +// tokenRequest is a simplified representation of the Kubernetes TokenRequest API response, +// containing only the token field that we need to extract. +type tokenRequest struct { + Status struct { + Token string `json:"token"` + } `json:"status"` +} diff --git a/test/utils/utils.go b/test/utils/utils.go new file mode 100644 index 0000000..c3d51ce --- /dev/null +++ b/test/utils/utils.go @@ -0,0 +1,251 @@ +/* +Copyright 2024. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package utils + +import ( + "bufio" + "bytes" + "fmt" + "os" + "os/exec" + "strings" + + . "github.com/onsi/ginkgo/v2" //nolint:golint,revive +) + +const ( + prometheusOperatorVersion = "v0.77.1" + prometheusOperatorURL = "https://github.com/prometheus-operator/prometheus-operator/" + + "releases/download/%s/bundle.yaml" + + certmanagerVersion = "v1.16.0" + certmanagerURLTmpl = "https://github.com/jetstack/cert-manager/releases/download/%s/cert-manager.yaml" +) + +func warnError(err error) { + _, _ = fmt.Fprintf(GinkgoWriter, "warning: %v\n", err) +} + +// Run executes the provided command within this context +func Run(cmd *exec.Cmd) (string, error) { + dir, _ := GetProjectDir() + cmd.Dir = dir + + if err := os.Chdir(cmd.Dir); err != nil { + _, _ = fmt.Fprintf(GinkgoWriter, "chdir dir: %s\n", err) + } + + cmd.Env = append(os.Environ(), "GO111MODULE=on") + command := strings.Join(cmd.Args, " ") + _, _ = fmt.Fprintf(GinkgoWriter, "running: %s\n", command) + output, err := cmd.CombinedOutput() + if err != nil { + return string(output), fmt.Errorf("%s failed with error: (%v) %s", command, err, string(output)) + } + + return string(output), nil +} + +// InstallPrometheusOperator installs the prometheus Operator to be used to export the enabled metrics. +func InstallPrometheusOperator() error { + url := fmt.Sprintf(prometheusOperatorURL, prometheusOperatorVersion) + cmd := exec.Command("kubectl", "create", "-f", url) + _, err := Run(cmd) + return err +} + +// UninstallPrometheusOperator uninstalls the prometheus +func UninstallPrometheusOperator() { + url := fmt.Sprintf(prometheusOperatorURL, prometheusOperatorVersion) + cmd := exec.Command("kubectl", "delete", "-f", url) + if _, err := Run(cmd); err != nil { + warnError(err) + } +} + +// IsPrometheusCRDsInstalled checks if any Prometheus CRDs are installed +// by verifying the existence of key CRDs related to Prometheus. +func IsPrometheusCRDsInstalled() bool { + // List of common Prometheus CRDs + prometheusCRDs := []string{ + "prometheuses.monitoring.coreos.com", + "prometheusrules.monitoring.coreos.com", + "prometheusagents.monitoring.coreos.com", + } + + cmd := exec.Command("kubectl", "get", "crds", "-o", "custom-columns=NAME:.metadata.name") + output, err := Run(cmd) + if err != nil { + return false + } + crdList := GetNonEmptyLines(string(output)) + for _, crd := range prometheusCRDs { + for _, line := range crdList { + if strings.Contains(line, crd) { + return true + } + } + } + + return false +} + +// UninstallCertManager uninstalls the cert manager +func UninstallCertManager() { + url := fmt.Sprintf(certmanagerURLTmpl, certmanagerVersion) + cmd := exec.Command("kubectl", "delete", "-f", url) + if _, err := Run(cmd); err != nil { + warnError(err) + } +} + +// InstallCertManager installs the cert manager bundle. +func InstallCertManager() error { + url := fmt.Sprintf(certmanagerURLTmpl, certmanagerVersion) + cmd := exec.Command("kubectl", "apply", "-f", url) + if _, err := Run(cmd); err != nil { + return err + } + // Wait for cert-manager-webhook to be ready, which can take time if cert-manager + // was re-installed after uninstalling on a cluster. + cmd = exec.Command("kubectl", "wait", "deployment.apps/cert-manager-webhook", + "--for", "condition=Available", + "--namespace", "cert-manager", + "--timeout", "5m", + ) + + _, err := Run(cmd) + return err +} + +// IsCertManagerCRDsInstalled checks if any Cert Manager CRDs are installed +// by verifying the existence of key CRDs related to Cert Manager. +func IsCertManagerCRDsInstalled() bool { + // List of common Cert Manager CRDs + certManagerCRDs := []string{ + "certificates.cert-manager.io", + "issuers.cert-manager.io", + "clusterissuers.cert-manager.io", + "certificaterequests.cert-manager.io", + "orders.acme.cert-manager.io", + "challenges.acme.cert-manager.io", + } + + // Execute the kubectl command to get all CRDs + cmd := exec.Command("kubectl", "get", "crds") + output, err := Run(cmd) + if err != nil { + return false + } + + // Check if any of the Cert Manager CRDs are present + crdList := GetNonEmptyLines(string(output)) + for _, crd := range certManagerCRDs { + for _, line := range crdList { + if strings.Contains(line, crd) { + return true + } + } + } + + return false +} + +// LoadImageToKindClusterWithName loads a local docker image to the kind cluster +func LoadImageToKindClusterWithName(name string) error { + cluster := "kind" + if v, ok := os.LookupEnv("KIND_CLUSTER"); ok { + cluster = v + } + kindOptions := []string{"load", "docker-image", name, "--name", cluster} + cmd := exec.Command("kind", kindOptions...) + _, err := Run(cmd) + return err +} + +// GetNonEmptyLines converts given command output string into individual objects +// according to line breakers, and ignores the empty elements in it. +func GetNonEmptyLines(output string) []string { + var res []string + elements := strings.Split(output, "\n") + for _, element := range elements { + if element != "" { + res = append(res, element) + } + } + + return res +} + +// GetProjectDir will return the directory where the project is +func GetProjectDir() (string, error) { + wd, err := os.Getwd() + if err != nil { + return wd, err + } + wd = strings.Replace(wd, "/test/e2e", "", -1) + return wd, nil +} + +// UncommentCode searches for target in the file and remove the comment prefix +// of the target content. The target content may span multiple lines. +func UncommentCode(filename, target, prefix string) error { + // false positive + // nolint:gosec + content, err := os.ReadFile(filename) + if err != nil { + return err + } + strContent := string(content) + + idx := strings.Index(strContent, target) + if idx < 0 { + return fmt.Errorf("unable to find the code %s to be uncomment", target) + } + + out := new(bytes.Buffer) + _, err = out.Write(content[:idx]) + if err != nil { + return err + } + + scanner := bufio.NewScanner(bytes.NewBufferString(target)) + if !scanner.Scan() { + return nil + } + for { + _, err := out.WriteString(strings.TrimPrefix(scanner.Text(), prefix)) + if err != nil { + return err + } + // Avoid writing a newline in case the previous line was the last in target. + if !scanner.Scan() { + break + } + if _, err := out.WriteString("\n"); err != nil { + return err + } + } + + _, err = out.Write(content[idx+len(target):]) + if err != nil { + return err + } + // false positive + // nolint:gosec + return os.WriteFile(filename, out.Bytes(), 0644) +} From 0aff78a665adcdb0d64e0bd06982ed40da610679 Mon Sep 17 00:00:00 2001 From: Benjamin Wang Date: Thu, 31 Oct 2024 20:06:38 +0000 Subject: [PATCH 09/17] Merge the kubebuilder generated README.md into the existing one Signed-off-by: Benjamin Wang --- README.md | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/README.md b/README.md index 10e1011..4284f37 100644 --- a/README.md +++ b/README.md @@ -15,3 +15,95 @@ You can reach the maintainers of this project at: ### Code of conduct Participation in the Kubernetes community is governed by the [Kubernetes Code of Conduct](code-of-conduct.md). + +## Getting Started + +### Prerequisites +- go version v1.22.0+ +- docker version 17.03+. +- kubectl version v1.11.3+. +- Access to a Kubernetes v1.11.3+ cluster. + +### To Deploy on the cluster +**Build and push your image to the location specified by `IMG`:** + +```sh +make docker-build docker-push IMG=/etcd-operator:tag +``` + +**NOTE:** This image ought to be published in the personal registry you specified. +And it is required to have access to pull the image from the working environment. +Make sure you have the proper permission to the registry if the above commands don’t work. + +**Install the CRDs into the cluster:** + +```sh +make install +``` + +**Deploy the Manager to the cluster with the image specified by `IMG`:** + +```sh +make deploy IMG=/etcd-operator:tag +``` + +> **NOTE**: If you encounter RBAC errors, you may need to grant yourself cluster-admin +privileges or be logged in as admin. + +**Create instances of your solution** +You can apply the samples (examples) from the config/sample: + +```sh +kubectl apply -k config/samples/ +``` + +>**NOTE**: Ensure that the samples has default values to test it out. + +### To Uninstall +**Delete the instances (CRs) from the cluster:** + +```sh +kubectl delete -k config/samples/ +``` + +**Delete the APIs(CRDs) from the cluster:** + +```sh +make uninstall +``` + +**UnDeploy the controller from the cluster:** + +```sh +make undeploy +``` + +## Project Distribution + +Following are the steps to build the installer and distribute this project to users. + +1. Build the installer for the image built and published in the registry: + +```sh +make build-installer IMG=/etcd-operator:tag +``` + +NOTE: The makefile target mentioned above generates an 'install.yaml' +file in the dist directory. This file contains all the resources built +with Kustomize, which are necessary to install this project without +its dependencies. + +2. Using the installer + +Users can just run kubectl apply -f to install the project, i.e.: + +```sh +kubectl apply -f https://raw.githubusercontent.com//etcd-operator//dist/install.yaml +``` + +## Contributing +// TODO(user): Add detailed information on how you would like others to contribute to this project + +**NOTE:** Run `make help` for more information on all potential `make` targets + +More information can be found via the [Kubebuilder Documentation](https://book.kubebuilder.io/introduction.html) From ea5c566ed97ea614eba24daa1b5c1dfea6c3509f Mon Sep 17 00:00:00 2001 From: Benjamin Wang Date: Thu, 31 Oct 2024 20:09:06 +0000 Subject: [PATCH 10/17] Create new API as etcd.io.groups/v1alpha1 and new Kind EtcdCluster The command is: kubebuilder create api --group clusters --version v1alpha1 --kind EtcdCluster and input two "y" Signed-off-by: Benjamin Wang --- PROJECT | 10 ++ api/v1alpha1/etcdcluster_types.go | 64 ++++++++++ api/v1alpha1/groupversion_info.go | 36 ++++++ api/v1alpha1/zz_generated.deepcopy.go | 114 ++++++++++++++++++ cmd/main.go | 11 ++ config/crd/kustomization.yaml | 22 ++++ config/crd/kustomizeconfig.yaml | 19 +++ config/default/kustomization.yaml | 2 +- config/rbac/etcdcluster_editor_role.yaml | 27 +++++ config/rbac/etcdcluster_viewer_role.yaml | 23 ++++ config/rbac/kustomization.yaml | 7 ++ .../clusters_v1alpha1_etcdcluster.yaml | 9 ++ config/samples/kustomization.yaml | 4 + internal/controller/etcdcluster_controller.go | 63 ++++++++++ .../controller/etcdcluster_controller_test.go | 84 +++++++++++++ internal/controller/suite_test.go | 96 +++++++++++++++ 16 files changed, 590 insertions(+), 1 deletion(-) create mode 100644 api/v1alpha1/etcdcluster_types.go create mode 100644 api/v1alpha1/groupversion_info.go create mode 100644 api/v1alpha1/zz_generated.deepcopy.go create mode 100644 config/crd/kustomization.yaml create mode 100644 config/crd/kustomizeconfig.yaml create mode 100644 config/rbac/etcdcluster_editor_role.yaml create mode 100644 config/rbac/etcdcluster_viewer_role.yaml create mode 100644 config/samples/clusters_v1alpha1_etcdcluster.yaml create mode 100644 config/samples/kustomization.yaml create mode 100644 internal/controller/etcdcluster_controller.go create mode 100644 internal/controller/etcdcluster_controller_test.go create mode 100644 internal/controller/suite_test.go diff --git a/PROJECT b/PROJECT index 0b8dab6..40c7c87 100644 --- a/PROJECT +++ b/PROJECT @@ -7,4 +7,14 @@ layout: - go.kubebuilder.io/v4 projectName: etcd-operator repo: go.etcd.io/etcd-operator +resources: +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: etcd.io + group: clusters + kind: EtcdCluster + path: go.etcd.io/etcd-operator/api/v1alpha1 + version: v1alpha1 version: "3" diff --git a/api/v1alpha1/etcdcluster_types.go b/api/v1alpha1/etcdcluster_types.go new file mode 100644 index 0000000..9c2ac69 --- /dev/null +++ b/api/v1alpha1/etcdcluster_types.go @@ -0,0 +1,64 @@ +/* +Copyright 2024. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// EtcdClusterSpec defines the desired state of EtcdCluster. +type EtcdClusterSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file + + // Foo is an example field of EtcdCluster. Edit etcdcluster_types.go to remove/update + Foo string `json:"foo,omitempty"` +} + +// EtcdClusterStatus defines the observed state of EtcdCluster. +type EtcdClusterStatus struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "make" to regenerate code after modifying this file +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status + +// EtcdCluster is the Schema for the etcdclusters API. +type EtcdCluster struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec EtcdClusterSpec `json:"spec,omitempty"` + Status EtcdClusterStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// EtcdClusterList contains a list of EtcdCluster. +type EtcdClusterList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []EtcdCluster `json:"items"` +} + +func init() { + SchemeBuilder.Register(&EtcdCluster{}, &EtcdClusterList{}) +} diff --git a/api/v1alpha1/groupversion_info.go b/api/v1alpha1/groupversion_info.go new file mode 100644 index 0000000..e845835 --- /dev/null +++ b/api/v1alpha1/groupversion_info.go @@ -0,0 +1,36 @@ +/* +Copyright 2024. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package v1alpha1 contains API Schema definitions for the clusters v1alpha1 API group. +// +kubebuilder:object:generate=true +// +groupName=clusters.etcd.io +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +var ( + // GroupVersion is group version used to register these objects. + GroupVersion = schema.GroupVersion{Group: "clusters.etcd.io", Version: "v1alpha1"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme. + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 0000000..2a890c6 --- /dev/null +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,114 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2024. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EtcdCluster) DeepCopyInto(out *EtcdCluster) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EtcdCluster. +func (in *EtcdCluster) DeepCopy() *EtcdCluster { + if in == nil { + return nil + } + out := new(EtcdCluster) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *EtcdCluster) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EtcdClusterList) DeepCopyInto(out *EtcdClusterList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]EtcdCluster, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EtcdClusterList. +func (in *EtcdClusterList) DeepCopy() *EtcdClusterList { + if in == nil { + return nil + } + out := new(EtcdClusterList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *EtcdClusterList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EtcdClusterSpec) DeepCopyInto(out *EtcdClusterSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EtcdClusterSpec. +func (in *EtcdClusterSpec) DeepCopy() *EtcdClusterSpec { + if in == nil { + return nil + } + out := new(EtcdClusterSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EtcdClusterStatus) DeepCopyInto(out *EtcdClusterStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EtcdClusterStatus. +func (in *EtcdClusterStatus) DeepCopy() *EtcdClusterStatus { + if in == nil { + return nil + } + out := new(EtcdClusterStatus) + in.DeepCopyInto(out) + return out +} diff --git a/cmd/main.go b/cmd/main.go index 62165f4..3ec11e1 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -34,6 +34,9 @@ import ( "sigs.k8s.io/controller-runtime/pkg/metrics/filters" metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" "sigs.k8s.io/controller-runtime/pkg/webhook" + + clustersv1alpha1 "go.etcd.io/etcd-operator/api/v1alpha1" + "go.etcd.io/etcd-operator/internal/controller" // +kubebuilder:scaffold:imports ) @@ -45,6 +48,7 @@ var ( func init() { utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + utilruntime.Must(clustersv1alpha1.AddToScheme(scheme)) // +kubebuilder:scaffold:scheme } @@ -140,6 +144,13 @@ func main() { os.Exit(1) } + if err = (&controller.EtcdClusterReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "EtcdCluster") + os.Exit(1) + } // +kubebuilder:scaffold:builder if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml new file mode 100644 index 0000000..3948730 --- /dev/null +++ b/config/crd/kustomization.yaml @@ -0,0 +1,22 @@ +# This kustomization.yaml is not intended to be run by itself, +# since it depends on service name and namespace that are out of this kustomize package. +# It should be run by config/default +resources: +- bases/clusters.etcd.io_etcdclusters.yaml +# +kubebuilder:scaffold:crdkustomizeresource + +patches: +# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. +# patches here are for enabling the conversion webhook for each CRD +# +kubebuilder:scaffold:crdkustomizewebhookpatch + +# [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix. +# patches here are for enabling the CA injection for each CRD +#- path: patches/cainjection_in_etcdclusters.yaml +# +kubebuilder:scaffold:crdkustomizecainjectionpatch + +# [WEBHOOK] To enable webhook, uncomment the following section +# the following config is for teaching kustomize how to do kustomization for CRDs. + +#configurations: +#- kustomizeconfig.yaml diff --git a/config/crd/kustomizeconfig.yaml b/config/crd/kustomizeconfig.yaml new file mode 100644 index 0000000..ec5c150 --- /dev/null +++ b/config/crd/kustomizeconfig.yaml @@ -0,0 +1,19 @@ +# This file is for teaching kustomize how to substitute name and namespace reference in CRD +nameReference: +- kind: Service + version: v1 + fieldSpecs: + - kind: CustomResourceDefinition + version: v1 + group: apiextensions.k8s.io + path: spec/conversion/webhook/clientConfig/service/name + +namespace: +- kind: CustomResourceDefinition + version: v1 + group: apiextensions.k8s.io + path: spec/conversion/webhook/clientConfig/service/namespace + create: false + +varReference: +- path: metadata/annotations diff --git a/config/default/kustomization.yaml b/config/default/kustomization.yaml index 512fb7f..2fbe4d5 100644 --- a/config/default/kustomization.yaml +++ b/config/default/kustomization.yaml @@ -15,7 +15,7 @@ namePrefix: etcd-operator- # someName: someValue resources: -#- ../crd +- ../crd - ../rbac - ../manager # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in diff --git a/config/rbac/etcdcluster_editor_role.yaml b/config/rbac/etcdcluster_editor_role.yaml new file mode 100644 index 0000000..e3fe9f3 --- /dev/null +++ b/config/rbac/etcdcluster_editor_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to edit etcdclusters. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: etcd-operator + app.kubernetes.io/managed-by: kustomize + name: etcdcluster-editor-role +rules: +- apiGroups: + - clusters.etcd.io + resources: + - etcdclusters + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - clusters.etcd.io + resources: + - etcdclusters/status + verbs: + - get diff --git a/config/rbac/etcdcluster_viewer_role.yaml b/config/rbac/etcdcluster_viewer_role.yaml new file mode 100644 index 0000000..455491a --- /dev/null +++ b/config/rbac/etcdcluster_viewer_role.yaml @@ -0,0 +1,23 @@ +# permissions for end users to view etcdclusters. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: etcd-operator + app.kubernetes.io/managed-by: kustomize + name: etcdcluster-viewer-role +rules: +- apiGroups: + - clusters.etcd.io + resources: + - etcdclusters + verbs: + - get + - list + - watch +- apiGroups: + - clusters.etcd.io + resources: + - etcdclusters/status + verbs: + - get diff --git a/config/rbac/kustomization.yaml b/config/rbac/kustomization.yaml index 5619aa0..ae91bf7 100644 --- a/config/rbac/kustomization.yaml +++ b/config/rbac/kustomization.yaml @@ -18,3 +18,10 @@ resources: - metrics_auth_role.yaml - metrics_auth_role_binding.yaml - metrics_reader_role.yaml +# For each CRD, "Editor" and "Viewer" roles are scaffolded by +# default, aiding admins in cluster management. Those roles are +# not used by the Project itself. You can comment the following lines +# if you do not want those helpers be installed with your Project. +- etcdcluster_editor_role.yaml +- etcdcluster_viewer_role.yaml + diff --git a/config/samples/clusters_v1alpha1_etcdcluster.yaml b/config/samples/clusters_v1alpha1_etcdcluster.yaml new file mode 100644 index 0000000..a2a37a4 --- /dev/null +++ b/config/samples/clusters_v1alpha1_etcdcluster.yaml @@ -0,0 +1,9 @@ +apiVersion: clusters.etcd.io/v1alpha1 +kind: EtcdCluster +metadata: + labels: + app.kubernetes.io/name: etcd-operator + app.kubernetes.io/managed-by: kustomize + name: etcdcluster-sample +spec: + # TODO(user): Add fields here diff --git a/config/samples/kustomization.yaml b/config/samples/kustomization.yaml new file mode 100644 index 0000000..0e248f6 --- /dev/null +++ b/config/samples/kustomization.yaml @@ -0,0 +1,4 @@ +## Append samples of your project ## +resources: +- clusters_v1alpha1_etcdcluster.yaml +# +kubebuilder:scaffold:manifestskustomizesamples diff --git a/internal/controller/etcdcluster_controller.go b/internal/controller/etcdcluster_controller.go new file mode 100644 index 0000000..af98093 --- /dev/null +++ b/internal/controller/etcdcluster_controller.go @@ -0,0 +1,63 @@ +/* +Copyright 2024. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controller + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + + clustersv1alpha1 "go.etcd.io/etcd-operator/api/v1alpha1" +) + +// EtcdClusterReconciler reconciles a EtcdCluster object +type EtcdClusterReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +// +kubebuilder:rbac:groups=clusters.etcd.io,resources=etcdclusters,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=clusters.etcd.io,resources=etcdclusters/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=clusters.etcd.io,resources=etcdclusters/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the EtcdCluster object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.0/pkg/reconcile +func (r *EtcdClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + _ = log.FromContext(ctx) + + // TODO(user): your logic here + + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *EtcdClusterReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&clustersv1alpha1.EtcdCluster{}). + Named("etcdcluster"). + Complete(r) +} diff --git a/internal/controller/etcdcluster_controller_test.go b/internal/controller/etcdcluster_controller_test.go new file mode 100644 index 0000000..2537586 --- /dev/null +++ b/internal/controller/etcdcluster_controller_test.go @@ -0,0 +1,84 @@ +/* +Copyright 2024. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controller + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + clustersv1alpha1 "go.etcd.io/etcd-operator/api/v1alpha1" +) + +var _ = Describe("EtcdCluster Controller", func() { + Context("When reconciling a resource", func() { + const resourceName = "test-resource" + + ctx := context.Background() + + typeNamespacedName := types.NamespacedName{ + Name: resourceName, + Namespace: "default", // TODO(user):Modify as needed + } + etcdcluster := &clustersv1alpha1.EtcdCluster{} + + BeforeEach(func() { + By("creating the custom resource for the Kind EtcdCluster") + err := k8sClient.Get(ctx, typeNamespacedName, etcdcluster) + if err != nil && errors.IsNotFound(err) { + resource := &clustersv1alpha1.EtcdCluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: resourceName, + Namespace: "default", + }, + // TODO(user): Specify other spec details if needed. + } + Expect(k8sClient.Create(ctx, resource)).To(Succeed()) + } + }) + + AfterEach(func() { + // TODO(user): Cleanup logic after each test, like removing the resource instance. + resource := &clustersv1alpha1.EtcdCluster{} + err := k8sClient.Get(ctx, typeNamespacedName, resource) + Expect(err).NotTo(HaveOccurred()) + + By("Cleanup the specific resource instance EtcdCluster") + Expect(k8sClient.Delete(ctx, resource)).To(Succeed()) + }) + It("should successfully reconcile the resource", func() { + By("Reconciling the created resource") + controllerReconciler := &EtcdClusterReconciler{ + Client: k8sClient, + Scheme: k8sClient.Scheme(), + } + + _, err := controllerReconciler.Reconcile(ctx, reconcile.Request{ + NamespacedName: typeNamespacedName, + }) + Expect(err).NotTo(HaveOccurred()) + // TODO(user): Add more specific assertions depending on your controller's reconciliation logic. + // Example: If you expect a certain status condition after reconciliation, verify it here. + }) + }) +}) diff --git a/internal/controller/suite_test.go b/internal/controller/suite_test.go new file mode 100644 index 0000000..aa2b0ac --- /dev/null +++ b/internal/controller/suite_test.go @@ -0,0 +1,96 @@ +/* +Copyright 2024. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controller + +import ( + "context" + "fmt" + "path/filepath" + "runtime" + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + + clustersv1alpha1 "go.etcd.io/etcd-operator/api/v1alpha1" + // +kubebuilder:scaffold:imports +) + +// These tests use Ginkgo (BDD-style Go testing framework). Refer to +// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. + +var cfg *rest.Config +var k8sClient client.Client +var testEnv *envtest.Environment +var ctx context.Context +var cancel context.CancelFunc + +func TestControllers(t *testing.T) { + RegisterFailHandler(Fail) + + RunSpecs(t, "Controller Suite") +} + +var _ = BeforeSuite(func() { + logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) + + ctx, cancel = context.WithCancel(context.TODO()) + + By("bootstrapping test environment") + testEnv = &envtest.Environment{ + CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")}, + ErrorIfCRDPathMissing: true, + + // The BinaryAssetsDirectory is only required if you want to run the tests directly + // without call the makefile target test. If not informed it will look for the + // default path defined in controller-runtime which is /usr/local/kubebuilder/. + // Note that you must have the required binaries setup under the bin directory to perform + // the tests directly. When we run make test it will be setup and used automatically. + BinaryAssetsDirectory: filepath.Join("..", "..", "bin", "k8s", + fmt.Sprintf("1.31.0-%s-%s", runtime.GOOS, runtime.GOARCH)), + } + + var err error + // cfg is defined in this file globally. + cfg, err = testEnv.Start() + Expect(err).NotTo(HaveOccurred()) + Expect(cfg).NotTo(BeNil()) + + err = clustersv1alpha1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + + // +kubebuilder:scaffold:scheme + + k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) + Expect(err).NotTo(HaveOccurred()) + Expect(k8sClient).NotTo(BeNil()) + +}) + +var _ = AfterSuite(func() { + By("tearing down the test environment") + cancel() + err := testEnv.Stop() + Expect(err).NotTo(HaveOccurred()) +}) From 62b7e81a5476c4d0ddf14508632aa3f76eccf8b3 Mon Sep 17 00:00:00 2001 From: Benjamin Wang Date: Thu, 31 Oct 2024 20:14:29 +0000 Subject: [PATCH 11/17] Edit EtcdClusterSpec to add two new fields: Size and Version Signed-off-by: Benjamin Wang --- api/v1alpha1/etcdcluster_types.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/api/v1alpha1/etcdcluster_types.go b/api/v1alpha1/etcdcluster_types.go index 9c2ac69..310f793 100644 --- a/api/v1alpha1/etcdcluster_types.go +++ b/api/v1alpha1/etcdcluster_types.go @@ -28,8 +28,10 @@ type EtcdClusterSpec struct { // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster // Important: Run "make" to regenerate code after modifying this file - // Foo is an example field of EtcdCluster. Edit etcdcluster_types.go to remove/update - Foo string `json:"foo,omitempty"` + // Size is the expected size of the etcd cluster. + Size int `json:"size"` + // Version is the expected version of the etcd container image. + Version string `json:"version"` } // EtcdClusterStatus defines the observed state of EtcdCluster. From 61d05c4a8e78c57ad7c6ed2a6dda461af2ce0ed4 Mon Sep 17 00:00:00 2001 From: Benjamin Wang Date: Thu, 31 Oct 2024 20:14:58 +0000 Subject: [PATCH 12/17] Re-generate the manifest The command is: make manifests Signed-off-by: Benjamin Wang --- .../bases/clusters.etcd.io_etcdclusters.yaml | 60 +++++++++++++++++++ config/rbac/role.yaml | 33 ++++++++-- 2 files changed, 87 insertions(+), 6 deletions(-) create mode 100644 config/crd/bases/clusters.etcd.io_etcdclusters.yaml diff --git a/config/crd/bases/clusters.etcd.io_etcdclusters.yaml b/config/crd/bases/clusters.etcd.io_etcdclusters.yaml new file mode 100644 index 0000000..fdae794 --- /dev/null +++ b/config/crd/bases/clusters.etcd.io_etcdclusters.yaml @@ -0,0 +1,60 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: etcdclusters.clusters.etcd.io +spec: + group: clusters.etcd.io + names: + kind: EtcdCluster + listKind: EtcdClusterList + plural: etcdclusters + singular: etcdcluster + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: EtcdCluster is the Schema for the etcdclusters API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: EtcdClusterSpec defines the desired state of EtcdCluster. + properties: + size: + description: Size is the expected size of the etcd cluster. + type: integer + version: + description: Version is the expected version of the etcd container + image. + type: string + required: + - size + - version + type: object + status: + description: EtcdClusterStatus defines the observed state of EtcdCluster. + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index f8f8aed..859ff1e 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -1,11 +1,32 @@ +--- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - labels: - app.kubernetes.io/name: etcd-operator - app.kubernetes.io/managed-by: kustomize name: manager-role rules: -- apiGroups: [""] - resources: ["pods"] - verbs: ["get", "list", "watch"] +- apiGroups: + - clusters.etcd.io + resources: + - etcdclusters + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - clusters.etcd.io + resources: + - etcdclusters/finalizers + verbs: + - update +- apiGroups: + - clusters.etcd.io + resources: + - etcdclusters/status + verbs: + - get + - patch + - update From 732247c4bc6e5f3690278b833dad94281bbf071e Mon Sep 17 00:00:00 2001 From: Benjamin Wang Date: Thu, 31 Oct 2024 20:32:09 +0000 Subject: [PATCH 13/17] Remove lint.yaml workflow for now Signed-off-by: Benjamin Wang --- .github/workflows/lint.yml | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 .github/workflows/lint.yml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml deleted file mode 100644 index b6967b3..0000000 --- a/.github/workflows/lint.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: Lint - -on: - push: - pull_request: - -jobs: - lint: - name: Run on Ubuntu - runs-on: ubuntu-latest - steps: - - name: Clone the code - uses: actions/checkout@v4 - - - name: Setup Go - uses: actions/setup-go@v5 - with: - go-version: '~1.22' - - - name: Run linter - uses: golangci/golangci-lint-action@v6 - with: - version: v1.59 From 83bbf0126daea7cc14d4298b81f8ca463497e19b Mon Sep 17 00:00:00 2001 From: Benjamin Wang Date: Fri, 22 Nov 2024 15:44:07 +0000 Subject: [PATCH 14/17] Change the api group from clusters.etcd.io to operator.etcd.io Signed-off-by: Benjamin Wang --- Makefile | 4 +- PROJECT | 2 +- api/v1alpha1/groupversion_info.go | 6 +- cmd/main.go | 20 +++--- ...aml => operator.etcd.io_etcdclusters.yaml} | 4 +- config/crd/kustomization.yaml | 4 +- config/default/kustomization.yaml | 70 +++++++++---------- config/rbac/etcdcluster_editor_role.yaml | 4 +- config/rbac/etcdcluster_viewer_role.yaml | 4 +- config/rbac/role.yaml | 6 +- config/samples/kustomization.yaml | 2 +- ...aml => operator_v1alpha1_etcdcluster.yaml} | 2 +- go.mod | 2 +- go.sum | 4 +- internal/controller/etcdcluster_controller.go | 12 ++-- .../controller/etcdcluster_controller_test.go | 8 +-- internal/controller/suite_test.go | 4 +- 17 files changed, 77 insertions(+), 81 deletions(-) rename config/crd/bases/{clusters.etcd.io_etcdclusters.yaml => operator.etcd.io_etcdclusters.yaml} (96%) rename config/samples/{clusters_v1alpha1_etcdcluster.yaml => operator_v1alpha1_etcdcluster.yaml} (83%) diff --git a/Makefile b/Makefile index 5b0e996..336f532 100644 --- a/Makefile +++ b/Makefile @@ -170,10 +170,10 @@ ENVTEST ?= $(LOCALBIN)/setup-envtest GOLANGCI_LINT = $(LOCALBIN)/golangci-lint ## Tool Versions -KUSTOMIZE_VERSION ?= v5.4.3 +KUSTOMIZE_VERSION ?= v5.5.0 CONTROLLER_TOOLS_VERSION ?= v0.16.4 ENVTEST_VERSION ?= release-0.19 -GOLANGCI_LINT_VERSION ?= v1.59.1 +GOLANGCI_LINT_VERSION ?= v1.61.0 .PHONY: kustomize kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary. diff --git a/PROJECT b/PROJECT index 40c7c87..f70bcb6 100644 --- a/PROJECT +++ b/PROJECT @@ -13,7 +13,7 @@ resources: namespaced: true controller: true domain: etcd.io - group: clusters + group: operator kind: EtcdCluster path: go.etcd.io/etcd-operator/api/v1alpha1 version: v1alpha1 diff --git a/api/v1alpha1/groupversion_info.go b/api/v1alpha1/groupversion_info.go index e845835..9acf45f 100644 --- a/api/v1alpha1/groupversion_info.go +++ b/api/v1alpha1/groupversion_info.go @@ -14,9 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -// Package v1alpha1 contains API Schema definitions for the clusters v1alpha1 API group. +// Package v1alpha1 contains API Schema definitions for the operator v1alpha1 API group. // +kubebuilder:object:generate=true -// +groupName=clusters.etcd.io +// +groupName=operator.etcd.io package v1alpha1 import ( @@ -26,7 +26,7 @@ import ( var ( // GroupVersion is group version used to register these objects. - GroupVersion = schema.GroupVersion{Group: "clusters.etcd.io", Version: "v1alpha1"} + GroupVersion = schema.GroupVersion{Group: "operator.etcd.io", Version: "v1alpha1"} // SchemeBuilder is used to add go types to the GroupVersionKind scheme. SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} diff --git a/cmd/main.go b/cmd/main.go index 3ec11e1..7a1c99a 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -35,7 +35,7 @@ import ( metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" "sigs.k8s.io/controller-runtime/pkg/webhook" - clustersv1alpha1 "go.etcd.io/etcd-operator/api/v1alpha1" + operatorv1alpha1 "go.etcd.io/etcd-operator/api/v1alpha1" "go.etcd.io/etcd-operator/internal/controller" // +kubebuilder:scaffold:imports ) @@ -48,7 +48,7 @@ var ( func init() { utilruntime.Must(clientgoscheme.AddToScheme(scheme)) - utilruntime.Must(clustersv1alpha1.AddToScheme(scheme)) + utilruntime.Must(operatorv1alpha1.AddToScheme(scheme)) // +kubebuilder:scaffold:scheme } @@ -98,26 +98,24 @@ func main() { // Metrics endpoint is enabled in 'config/default/kustomization.yaml'. The Metrics options configure the server. // More info: - // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.0/pkg/metrics/server + // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.1/pkg/metrics/server // - https://book.kubebuilder.io/reference/metrics.html metricsServerOptions := metricsserver.Options{ BindAddress: metricsAddr, SecureServing: secureMetrics, - // TODO(user): TLSOpts is used to allow configuring the TLS config used for the server. If certificates are - // not provided, self-signed certificates will be generated by default. This option is not recommended for - // production environments as self-signed certificates do not offer the same level of trust and security - // as certificates issued by a trusted Certificate Authority (CA). The primary risk is potentially allowing - // unauthorized access to sensitive metrics data. Consider replacing with CertDir, CertName, and KeyName - // to provide certificates, ensuring the server communicates using trusted and secure certificates. - TLSOpts: tlsOpts, + TLSOpts: tlsOpts, } if secureMetrics { // FilterProvider is used to protect the metrics endpoint with authn/authz. // These configurations ensure that only authorized users and service accounts // can access the metrics endpoint. The RBAC are configured in 'config/rbac/kustomization.yaml'. More info: - // https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.0/pkg/metrics/filters#WithAuthenticationAndAuthorization + // https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.1/pkg/metrics/filters#WithAuthenticationAndAuthorization metricsServerOptions.FilterProvider = filters.WithAuthenticationAndAuthorization + + // TODO(user): If CertDir, CertName, and KeyName are not specified, controller-runtime will automatically + // generate self-signed certificates for the metrics server. While convenient for development and testing, + // this setup is not recommended for production. } mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ diff --git a/config/crd/bases/clusters.etcd.io_etcdclusters.yaml b/config/crd/bases/operator.etcd.io_etcdclusters.yaml similarity index 96% rename from config/crd/bases/clusters.etcd.io_etcdclusters.yaml rename to config/crd/bases/operator.etcd.io_etcdclusters.yaml index fdae794..0cb092a 100644 --- a/config/crd/bases/clusters.etcd.io_etcdclusters.yaml +++ b/config/crd/bases/operator.etcd.io_etcdclusters.yaml @@ -4,9 +4,9 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.16.4 - name: etcdclusters.clusters.etcd.io + name: etcdclusters.operator.etcd.io spec: - group: clusters.etcd.io + group: operator.etcd.io names: kind: EtcdCluster listKind: EtcdClusterList diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 3948730..ca614b9 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -2,7 +2,7 @@ # since it depends on service name and namespace that are out of this kustomize package. # It should be run by config/default resources: -- bases/clusters.etcd.io_etcdclusters.yaml +- bases/operator.etcd.io_etcdclusters.yaml # +kubebuilder:scaffold:crdkustomizeresource patches: @@ -12,11 +12,9 @@ patches: # [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix. # patches here are for enabling the CA injection for each CRD -#- path: patches/cainjection_in_etcdclusters.yaml # +kubebuilder:scaffold:crdkustomizecainjectionpatch # [WEBHOOK] To enable webhook, uncomment the following section # the following config is for teaching kustomize how to do kustomization for CRDs. - #configurations: #- kustomizeconfig.yaml diff --git a/config/default/kustomization.yaml b/config/default/kustomization.yaml index 2fbe4d5..792ef45 100644 --- a/config/default/kustomization.yaml +++ b/config/default/kustomization.yaml @@ -48,6 +48,41 @@ patches: # [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix. # Uncomment the following replacements to add the cert-manager CA injection annotations #replacements: +# - source: # Uncomment the following block if you have any webhook +# kind: Service +# version: v1 +# name: webhook-service +# fieldPath: .metadata.name # Name of the service +# targets: +# - select: +# kind: Certificate +# group: cert-manager.io +# version: v1 +# fieldPaths: +# - .spec.dnsNames.0 +# - .spec.dnsNames.1 +# options: +# delimiter: '.' +# index: 0 +# create: true +# - source: +# kind: Service +# version: v1 +# name: webhook-service +# fieldPath: .metadata.namespace # Namespace of the service +# targets: +# - select: +# kind: Certificate +# group: cert-manager.io +# version: v1 +# fieldPaths: +# - .spec.dnsNames.0 +# - .spec.dnsNames.1 +# options: +# delimiter: '.' +# index: 1 +# create: true +# # - source: # Uncomment the following block if you have a ValidatingWebhook (--programmatic-validation) # kind: Certificate # group: cert-manager.io @@ -140,38 +175,3 @@ patches: # delimiter: '/' # index: 1 # create: true -# -# - source: # Uncomment the following block if you enable cert-manager -# kind: Service -# version: v1 -# name: webhook-service -# fieldPath: .metadata.name # Name of the service -# targets: -# - select: -# kind: Certificate -# group: cert-manager.io -# version: v1 -# fieldPaths: -# - .spec.dnsNames.0 -# - .spec.dnsNames.1 -# options: -# delimiter: '.' -# index: 0 -# create: true -# - source: -# kind: Service -# version: v1 -# name: webhook-service -# fieldPath: .metadata.namespace # Namespace of the service -# targets: -# - select: -# kind: Certificate -# group: cert-manager.io -# version: v1 -# fieldPaths: -# - .spec.dnsNames.0 -# - .spec.dnsNames.1 -# options: -# delimiter: '.' -# index: 1 -# create: true diff --git a/config/rbac/etcdcluster_editor_role.yaml b/config/rbac/etcdcluster_editor_role.yaml index e3fe9f3..2bbfd5a 100644 --- a/config/rbac/etcdcluster_editor_role.yaml +++ b/config/rbac/etcdcluster_editor_role.yaml @@ -8,7 +8,7 @@ metadata: name: etcdcluster-editor-role rules: - apiGroups: - - clusters.etcd.io + - operator.etcd.io resources: - etcdclusters verbs: @@ -20,7 +20,7 @@ rules: - update - watch - apiGroups: - - clusters.etcd.io + - operator.etcd.io resources: - etcdclusters/status verbs: diff --git a/config/rbac/etcdcluster_viewer_role.yaml b/config/rbac/etcdcluster_viewer_role.yaml index 455491a..56a0c9a 100644 --- a/config/rbac/etcdcluster_viewer_role.yaml +++ b/config/rbac/etcdcluster_viewer_role.yaml @@ -8,7 +8,7 @@ metadata: name: etcdcluster-viewer-role rules: - apiGroups: - - clusters.etcd.io + - operator.etcd.io resources: - etcdclusters verbs: @@ -16,7 +16,7 @@ rules: - list - watch - apiGroups: - - clusters.etcd.io + - operator.etcd.io resources: - etcdclusters/status verbs: diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 859ff1e..0f57b69 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -5,7 +5,7 @@ metadata: name: manager-role rules: - apiGroups: - - clusters.etcd.io + - operator.etcd.io resources: - etcdclusters verbs: @@ -17,13 +17,13 @@ rules: - update - watch - apiGroups: - - clusters.etcd.io + - operator.etcd.io resources: - etcdclusters/finalizers verbs: - update - apiGroups: - - clusters.etcd.io + - operator.etcd.io resources: - etcdclusters/status verbs: diff --git a/config/samples/kustomization.yaml b/config/samples/kustomization.yaml index 0e248f6..f3c97ab 100644 --- a/config/samples/kustomization.yaml +++ b/config/samples/kustomization.yaml @@ -1,4 +1,4 @@ ## Append samples of your project ## resources: -- clusters_v1alpha1_etcdcluster.yaml +- operator_v1alpha1_etcdcluster.yaml # +kubebuilder:scaffold:manifestskustomizesamples diff --git a/config/samples/clusters_v1alpha1_etcdcluster.yaml b/config/samples/operator_v1alpha1_etcdcluster.yaml similarity index 83% rename from config/samples/clusters_v1alpha1_etcdcluster.yaml rename to config/samples/operator_v1alpha1_etcdcluster.yaml index a2a37a4..ea4d3bf 100644 --- a/config/samples/clusters_v1alpha1_etcdcluster.yaml +++ b/config/samples/operator_v1alpha1_etcdcluster.yaml @@ -1,4 +1,4 @@ -apiVersion: clusters.etcd.io/v1alpha1 +apiVersion: operator.etcd.io/v1alpha1 kind: EtcdCluster metadata: labels: diff --git a/go.mod b/go.mod index 6b61fa7..7fcf649 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/onsi/gomega v1.33.1 k8s.io/apimachinery v0.31.0 k8s.io/client-go v0.31.0 - sigs.k8s.io/controller-runtime v0.19.0 + sigs.k8s.io/controller-runtime v0.19.1 ) require ( diff --git a/go.sum b/go.sum index a8ec01d..0958667 100644 --- a/go.sum +++ b/go.sum @@ -241,8 +241,8 @@ k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1 k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 h1:2770sDpzrjjsAtVhSeUFseziht227YAWYHLGNM8QPwY= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= -sigs.k8s.io/controller-runtime v0.19.0 h1:nWVM7aq+Il2ABxwiCizrVDSlmDcshi9llbaFbC0ji/Q= -sigs.k8s.io/controller-runtime v0.19.0/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= +sigs.k8s.io/controller-runtime v0.19.1 h1:Son+Q40+Be3QWb+niBXAg2vFiYWolDjjRfO8hn/cxOk= +sigs.k8s.io/controller-runtime v0.19.1/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= diff --git a/internal/controller/etcdcluster_controller.go b/internal/controller/etcdcluster_controller.go index af98093..065f6c6 100644 --- a/internal/controller/etcdcluster_controller.go +++ b/internal/controller/etcdcluster_controller.go @@ -24,7 +24,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/log" - clustersv1alpha1 "go.etcd.io/etcd-operator/api/v1alpha1" + operatorv1alpha1 "go.etcd.io/etcd-operator/api/v1alpha1" ) // EtcdClusterReconciler reconciles a EtcdCluster object @@ -33,9 +33,9 @@ type EtcdClusterReconciler struct { Scheme *runtime.Scheme } -// +kubebuilder:rbac:groups=clusters.etcd.io,resources=etcdclusters,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=clusters.etcd.io,resources=etcdclusters/status,verbs=get;update;patch -// +kubebuilder:rbac:groups=clusters.etcd.io,resources=etcdclusters/finalizers,verbs=update +// +kubebuilder:rbac:groups=operator.etcd.io,resources=etcdclusters,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=operator.etcd.io,resources=etcdclusters/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=operator.etcd.io,resources=etcdclusters/finalizers,verbs=update // Reconcile is part of the main kubernetes reconciliation loop which aims to // move the current state of the cluster closer to the desired state. @@ -45,7 +45,7 @@ type EtcdClusterReconciler struct { // the user. // // For more details, check Reconcile and its Result here: -// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.0/pkg/reconcile +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.1/pkg/reconcile func (r *EtcdClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { _ = log.FromContext(ctx) @@ -57,7 +57,7 @@ func (r *EtcdClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) // SetupWithManager sets up the controller with the Manager. func (r *EtcdClusterReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). - For(&clustersv1alpha1.EtcdCluster{}). + For(&operatorv1alpha1.EtcdCluster{}). Named("etcdcluster"). Complete(r) } diff --git a/internal/controller/etcdcluster_controller_test.go b/internal/controller/etcdcluster_controller_test.go index 2537586..93e059c 100644 --- a/internal/controller/etcdcluster_controller_test.go +++ b/internal/controller/etcdcluster_controller_test.go @@ -27,7 +27,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - clustersv1alpha1 "go.etcd.io/etcd-operator/api/v1alpha1" + operatorv1alpha1 "go.etcd.io/etcd-operator/api/v1alpha1" ) var _ = Describe("EtcdCluster Controller", func() { @@ -40,13 +40,13 @@ var _ = Describe("EtcdCluster Controller", func() { Name: resourceName, Namespace: "default", // TODO(user):Modify as needed } - etcdcluster := &clustersv1alpha1.EtcdCluster{} + etcdcluster := &operatorv1alpha1.EtcdCluster{} BeforeEach(func() { By("creating the custom resource for the Kind EtcdCluster") err := k8sClient.Get(ctx, typeNamespacedName, etcdcluster) if err != nil && errors.IsNotFound(err) { - resource := &clustersv1alpha1.EtcdCluster{ + resource := &operatorv1alpha1.EtcdCluster{ ObjectMeta: metav1.ObjectMeta{ Name: resourceName, Namespace: "default", @@ -59,7 +59,7 @@ var _ = Describe("EtcdCluster Controller", func() { AfterEach(func() { // TODO(user): Cleanup logic after each test, like removing the resource instance. - resource := &clustersv1alpha1.EtcdCluster{} + resource := &operatorv1alpha1.EtcdCluster{} err := k8sClient.Get(ctx, typeNamespacedName, resource) Expect(err).NotTo(HaveOccurred()) diff --git a/internal/controller/suite_test.go b/internal/controller/suite_test.go index aa2b0ac..0c9ba00 100644 --- a/internal/controller/suite_test.go +++ b/internal/controller/suite_test.go @@ -33,7 +33,7 @@ import ( logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" - clustersv1alpha1 "go.etcd.io/etcd-operator/api/v1alpha1" + operatorv1alpha1 "go.etcd.io/etcd-operator/api/v1alpha1" // +kubebuilder:scaffold:imports ) @@ -77,7 +77,7 @@ var _ = BeforeSuite(func() { Expect(err).NotTo(HaveOccurred()) Expect(cfg).NotTo(BeNil()) - err = clustersv1alpha1.AddToScheme(scheme.Scheme) + err = operatorv1alpha1.AddToScheme(scheme.Scheme) Expect(err).NotTo(HaveOccurred()) // +kubebuilder:scaffold:scheme From bf6c14247cba274a689befa75c15e488c64b1aa0 Mon Sep 17 00:00:00 2001 From: James Blair Date: Thu, 5 Dec 2024 10:33:16 +1300 Subject: [PATCH 15/17] Use go version from go.mod in actions workflows. Signed-off-by: James Blair --- .github/workflows/test-e2e.yml | 2 +- .github/workflows/test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-e2e.yml b/.github/workflows/test-e2e.yml index 8780644..b3b66dc 100644 --- a/.github/workflows/test-e2e.yml +++ b/.github/workflows/test-e2e.yml @@ -15,7 +15,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: '~1.22' + go-version-file: 'go.mod' - name: Install the latest version of kind run: | diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7baf657..07fbf7c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,7 +15,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: '~1.22' + go-version-file: 'go.mod' - name: Running Tests run: | From cc45964f3aba9fb4daf250b9303354d392b501b0 Mon Sep 17 00:00:00 2001 From: James Blair Date: Thu, 5 Dec 2024 10:35:45 +1300 Subject: [PATCH 16/17] Update to go 1.23. Signed-off-by: James Blair --- Dockerfile | 2 +- README.md | 6 +++++- go.mod | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 4ba18b6..5c73c7f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build the manager binary -FROM golang:1.22 AS builder +FROM golang:1.23 AS builder ARG TARGETOS ARG TARGETARCH diff --git a/README.md b/README.md index 4284f37..318f408 100644 --- a/README.md +++ b/README.md @@ -19,12 +19,14 @@ Participation in the Kubernetes community is governed by the [Kubernetes Code of ## Getting Started ### Prerequisites -- go version v1.22.0+ + +- go version v1.23.0+ - docker version 17.03+. - kubectl version v1.11.3+. - Access to a Kubernetes v1.11.3+ cluster. ### To Deploy on the cluster + **Build and push your image to the location specified by `IMG`:** ```sh @@ -60,6 +62,7 @@ kubectl apply -k config/samples/ >**NOTE**: Ensure that the samples has default values to test it out. ### To Uninstall + **Delete the instances (CRs) from the cluster:** ```sh @@ -102,6 +105,7 @@ kubectl apply -f https://raw.githubusercontent.com//etcd-operator/ Date: Thu, 5 Dec 2024 10:47:17 +1300 Subject: [PATCH 17/17] Align devcontainer with etcd-io/etcd. Signed-off-by: James Blair --- .devcontainer/devcontainer.json | 7 ++++--- .devcontainer/post-install.sh | 9 ++------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index e2cdc09..0c3da07 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,9 +1,11 @@ { "name": "Kubebuilder DevContainer", - "image": "golang:1.22", + "image": "mcr.microsoft.com/devcontainers/go:1.23-bookworm", "features": { "ghcr.io/devcontainers/features/docker-in-docker:2": {}, - "ghcr.io/devcontainers/features/git:1": {} + "ghcr.io/devcontainers/features/git:1": {}, + "ghcr.io/devcontainers/features/github-cli:1": {}, + "ghcr.io/devcontainers/features/kubectl-helm-minikube:1": {} }, "runArgs": ["--network=host"], @@ -22,4 +24,3 @@ "onCreateCommand": "bash .devcontainer/post-install.sh" } - diff --git a/.devcontainer/post-install.sh b/.devcontainer/post-install.sh index 265c43e..b2960d5 100644 --- a/.devcontainer/post-install.sh +++ b/.devcontainer/post-install.sh @@ -3,16 +3,11 @@ set -x curl -Lo ./kind https://kind.sigs.k8s.io/dl/latest/kind-linux-amd64 chmod +x ./kind -mv ./kind /usr/local/bin/kind +sudo mv ./kind /usr/local/bin/kind curl -L -o kubebuilder https://go.kubebuilder.io/dl/latest/linux/amd64 chmod +x kubebuilder -mv kubebuilder /usr/local/bin/ - -KUBECTL_VERSION=$(curl -L -s https://dl.k8s.io/release/stable.txt) -curl -LO "https://dl.k8s.io/release/$KUBECTL_VERSION/bin/linux/amd64/kubectl" -chmod +x kubectl -mv kubectl /usr/local/bin/kubectl +sudo mv kubebuilder /usr/local/bin/ docker network create -d=bridge --subnet=172.19.0.0/24 kind