diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 151f7bca297..9e2365db37a 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,30 +1,30 @@ diff --git a/.github/workflows/spaces.yml b/.github/workflows/spaces.yml new file mode 100644 index 00000000000..99742b0fc3b --- /dev/null +++ b/.github/workflows/spaces.yml @@ -0,0 +1,22 @@ +name: Trailing + +# Trigger the workflow on pull requests and direct pushes to any branch +on: + push: + paths: + - '**/*.md' + pull_request: + paths: + - '**/*.md' + +jobs: + lint: + name: "Check Trailing" + runs-on: ubuntu-latest + # Pull requests from the same repository won't trigger this checks as they were already triggered by the push + if: (github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository) + steps: + - name: Clone the code + uses: actions/checkout@v4 + - name: Run check + run: make test-spaces diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4eccdf9ccfa..05eafedaaa3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,209 +1,209 @@ -# Contributing guidelines +#Contributingguidelines -This document describes how to contribute to the project. +Thisdocumentdescribeshowtocontributetotheproject. -## Sign the CLA +##SigntheCLA -Kubernetes projects require that you sign a Contributor License Agreement (CLA) before we can accept your pull requests. +KubernetesprojectsrequirethatyousignaContributorLicenseAgreement(CLA)beforewecanacceptyourpullrequests. -Please see https://git.k8s.io/community/CLA.md for more info. +Pleaseseehttps://git.k8s.io/community/CLA.mdformoreinfo. -## Prerequisites +##Prerequisites -- [go](https://golang.org/dl/) version v1.21+. -- [docker](https://docs.docker.com/install/) version 17.03+. -- [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) version v1.11.3+. -- [kustomize](https://github.com/kubernetes-sigs/kustomize/blob/master/site/content/en/docs/Getting%20started/installation.md) v3.1.0+ -- Access to a Kubernetes v1.11.3+ cluster. +-[go](https://golang.org/dl/)versionv1.21+. +-[docker](https://docs.docker.com/install/)version17.03+. +-[kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/)versionv1.11.3+. +-[kustomize](https://github.com/kubernetes-sigs/kustomize/blob/master/site/content/en/docs/Getting%20started/installation.md)v3.1.0+ +-AccesstoaKubernetesv1.11.3+cluster. -## Contributing steps +##Contributingsteps -1. Submit an issue describing your proposed change to the repo in question. -1. The [repo owners](OWNERS) will respond to your issue promptly. -1. If your proposed change is accepted, and you haven't already done so, sign a Contributor License Agreement (see details above). -1. Fork the desired repo, develop and test your code changes. -1. Submit a pull request. +1.Submitanissuedescribingyourproposedchangetotherepoinquestion. +1.The[repoowners](OWNERS)willrespondtoyourissuepromptly. +1.Ifyourproposedchangeisaccepted,andyouhaven'talreadydoneso,signaContributorLicenseAgreement(seedetailsabove). +1.Forkthedesiredrepo,developandtestyourcodechanges. +1.Submitapullrequest. -In addition to the above steps, we adhere to the following best practices to maintain consistency and efficiency in our project: +Inadditiontotheabovesteps,weadheretothefollowingbestpracticestomaintainconsistencyandefficiencyinourproject: -- **Single Commit per PR:** Each Pull Request (PR) should contain only one commit. This approach simplifies tracking changes and makes the history more readable. -- **One Issue per PR:** Each PR should address a single specific issue or need. This helps in streamlining our workflow and makes it easier to identify and resolve problems such as revert the changes if required. +-**SingleCommitperPR:**EachPullRequest(PR)shouldcontainonlyonecommit.Thisapproachsimplifiestrackingchangesandmakesthehistorymorereadable. +-**OneIssueperPR:**EachPRshouldaddressasinglespecificissueorneed.Thishelpsinstreamliningourworkflowandmakesiteasiertoidentifyandresolveproblemssuchasrevertthechangesifrequired. -For more detailed guidelines, refer to the [Kubernetes Contributor Guide][k8s-contrubutiong-guide]. +Formoredetailedguidelines,refertothe[KubernetesContributorGuide][k8s-contrubutiong-guide]. -## How to build kubebuilder locally +##Howtobuildkubebuilderlocally -Note that, by building the kubebuilder from the source code we are allowed to test the changes made locally. +Notethat,bybuildingthekubebuilderfromthesourcecodeweareallowedtotestthechangesmadelocally. -1. Run the following command to clone your fork of the project locally in the dir /src/sigs.k8s.io/kubebuilder +1.Runthefollowingcommandtocloneyourforkoftheprojectlocallyinthedir/src/sigs.k8s.io/kubebuilder ``` -$ git clone git@github.com:/kubebuilder.git $GOPATH/src/sigs.k8s.io/kubebuilder +$gitclonegit@github.com:/kubebuilder.git$GOPATH/src/sigs.k8s.io/kubebuilder ``` -1. Ensure you activate module support before continue (`$ export GO111MODULE=on`) -1. Run the command `make install` to create a bin with the source code +1.Ensureyouactivatemodulesupportbeforecontinue(`$exportGO111MODULE=on`) +1.Runthecommand`makeinstall`tocreateabinwiththesourcecode -**NOTE** In order to check the local environment run `make test-unit`. +**NOTE**Inordertocheckthelocalenvironmentrun`maketest-unit`. -## What to do before submitting a pull request +##Whattodobeforesubmittingapullrequest -1. Run the script `make generate` to update/generate the mock data used in the e2e test in `$GOPATH/src/sigs.k8s.io/kubebuilder/testdata/` -1. Run `make test-unit test-e2e-local` +1.Runthescript`makegenerate`toupdate/generatethemockdatausedinthee2etestin`$GOPATH/src/sigs.k8s.io/kubebuilder/testdata/` +1.Run`maketest-unittest-e2e-local` -- e2e tests use [`kind`][kind] and [`setup-envtest`][setup-envtest]. If you want to bring your own binaries, place them in `$(go env GOPATH)/bin`. +-e2etestsuse[`kind`][kind]and[`setup-envtest`][setup-envtest].Ifyouwanttobringyourownbinaries,placethemin`$(goenvGOPATH)/bin`. -**IMPORTANT:** The `make generate` is very helpful. By using it, you can check if good part of the commands still working successfully after the changes. Also, note that its usage is a pre-requirement to submit a PR. +**IMPORTANT:**The`makegenerate`isveryhelpful.Byusingit,youcancheckifgoodpartofthecommandsstillworkingsuccessfullyafterthechanges.Also,notethatitsusageisapre-requirementtosubmitaPR. -Following the targets that can be used to test your changes locally. +Followingthetargetsthatcanbeusedtotestyourchangeslocally. -| Command | Description | Is called in the CI? | -| ------------------- | ------------------------------------------------------------- | -------------------- | -| make test-unit | Runs go tests | no | -| make test | Runs tests in shell (`./test.sh`) | yes | -| make lint | Run [golangci][golangci] lint checks | yes | -| make lint-fix | Run [golangci][golangci] to automatically perform fixes | no | -| make test-coverage | Run coveralls to check the % of code covered by tests | yes | -| make check-testdata | Checks if the testdata dir is updated with the latest changes | yes | -| make test-e2e-local | Runs the CI e2e tests locally | no | +|Command|Description|IscalledintheCI?| +|-------------------|-------------------------------------------------------------|--------------------| +|maketest-unit|Runsgotests|no| +|maketest|Runstestsinshell(`./test.sh`)|yes| +|makelint|Run[golangci][golangci]lintchecks|yes| +|makelint-fix|Run[golangci][golangci]toautomaticallyperformfixes|no| +|maketest-coverage|Runcoverallstocheckthe%ofcodecoveredbytests|yes| +|makecheck-testdata|Checksifthetestdatadirisupdatedwiththelatestchanges|yes| +|maketest-e2e-local|RunstheCIe2etestslocally|no| -**NOTE** To use the `make lint` is required to install `golangci-lint` locally. More info: https://github.com/golangci/golangci-lint#install +**NOTE**Tousethe`makelint`isrequiredtoinstall`golangci-lint`locally.Moreinfo:https://github.com/golangci/golangci-lint#install -### Test Plugin +###TestPlugin -If your intended PR creates a new plugin, make sure the PR also provides test cases. Testing should include: +IfyourintendedPRcreatesanewplugin,makesurethePRalsoprovidestestcases.Testingshouldinclude: -1. `e2e tests` to validate the behavior of the proposed plugin. -2. `sample projects` to verify the scaffolded output from the plugin. +1.`e2etests`tovalidatethebehavioroftheproposedplugin. +2.`sampleprojects`toverifythescaffoldedoutputfromtheplugin. -#### 1. Plugin E2E Tests +####1.PluginE2ETests -All the plugins provided by Kubebuilder should be validated through `e2e-tests` across multiple platforms. +AllthepluginsprovidedbyKubebuildershouldbevalidatedthrough`e2e-tests`acrossmultipleplatforms. -Current Kubebuilder provides the testing framework that includes testing code based on [ginkgo](https://github.com/onsi/ginkgo), [Github Actions](https://github.com/Kavinjsir/kubebuilder/blob/docs%2Ftest-plugin/.github/workflows/testdata.yml) for unit tests, and multiple env tests driven by [test-infra](https://github.com/kubernetes/test-infra/blob/master/config/jobs/kubernetes-sigs/kubebuilder/kubebuilder-presubmits.yaml). +CurrentKubebuilderprovidesthetestingframeworkthatincludestestingcodebasedon[ginkgo](https://github.com/onsi/ginkgo),[GithubActions](https://github.com/Kavinjsir/kubebuilder/blob/docs%2Ftest-plugin/.github/workflows/testdata.yml)forunittests,andmultipleenvtestsdrivenby[test-infra](https://github.com/kubernetes/test-infra/blob/master/config/jobs/kubernetes-sigs/kubebuilder/kubebuilder-presubmits.yaml). -To fully test the proposed plugin: +Tofullytesttheproposedplugin: -1. Create a new package(folder) under `test/e2e/`. -2. Create [e2e_suite_test.go](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/v4/e2e_suite_test.go), which imports the necessary testing framework. -3. Create `generate_test.go` ([ref](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/v4/generate_test.go)). That should: - - Introduce/Receive a `TextContext` instance - - Trigger the plugin's bound subcommands. See [Init](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/utils/test_context.go#L213), [CreateAPI](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.6.0/test/e2e/utils/test_context.go#L222) - - Use [PluginUtil](https://pkg.go.dev/sigs.k8s.io/kubebuilder/v3/pkg/plugin/util) to verify the scaffolded outputs. See [InsertCode](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/pkg/plugin/util/util.go#L67), [ReplaceInFile](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.6.0/pkg/plugin/util/util.go#L196), [UncommendCode](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.6.0/pkg/plugin/util/util.go#L86) -4. Create `plugin_cluster_test.go` ([ref](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/v4/plugin_cluster_test.go)). That should: +1.Createanewpackage(folder)under`test/e2e/`. +2.Create[e2e_suite_test.go](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/v4/e2e_suite_test.go),whichimportsthenecessarytestingframework. +3.Create`generate_test.go`([ref](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/v4/generate_test.go)).Thatshould: +-Introduce/Receivea`TextContext`instance +-Triggertheplugin'sboundsubcommands.See[Init](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/utils/test_context.go#L213),[CreateAPI](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.6.0/test/e2e/utils/test_context.go#L222) +-Use[PluginUtil](https://pkg.go.dev/sigs.k8s.io/kubebuilder/v3/pkg/plugin/util)toverifythescaffoldedoutputs.See[InsertCode](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/pkg/plugin/util/util.go#L67),[ReplaceInFile](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.6.0/pkg/plugin/util/util.go#L196),[UncommendCode](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.6.0/pkg/plugin/util/util.go#L86) +4.Create`plugin_cluster_test.go`([ref](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/v4/plugin_cluster_test.go)).Thatshould: - - 4.1. Setup testing environment, e.g: +-4.1.Setuptestingenvironment,e.g: - - Cleanup environment, create temp dir. See [Prepare](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/utils/test_context.go#L97) - - If your test will cover the provided features then, ensure that you install prerequisites CRDs: See [InstallCertManager](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/utils/test_context.go#L138), [InstallPrometheusManager](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.6.0/test/e2e/utils/test_context.go#L171) +-Cleanupenvironment,createtempdir.See[Prepare](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/utils/test_context.go#L97) +-Ifyourtestwillcovertheprovidedfeaturesthen,ensurethatyouinstallprerequisitesCRDs:See[InstallCertManager](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/utils/test_context.go#L138),[InstallPrometheusManager](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.6.0/test/e2e/utils/test_context.go#L171) - - 4.2. Run the function from `generate_test.go`. +-4.2.Runthefunctionfrom`generate_test.go`. - - 4.3. Further make sure the scaffolded output works, e.g: +-4.3.Furthermakesurethescaffoldedoutputworks,e.g: - - Execute commands in your `Makefile`. See [Make](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/utils/test_context.go#L240) - - Temporary load image of the testing controller. See [LoadImageToKindCluster](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/utils/test_context.go#L283) - - Call Kubectl to validate running resources. See [utils.Kubectl](https://pkg.go.dev/sigs.k8s.io/kubebuilder/v3/test/e2e/utils#Kubectl) +-Executecommandsinyour`Makefile`.See[Make](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/utils/test_context.go#L240) +-Temporaryloadimageofthetestingcontroller.See[LoadImageToKindCluster](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/utils/test_context.go#L283) +-CallKubectltovalidaterunningresources.See[utils.Kubectl](https://pkg.go.dev/sigs.k8s.io/kubebuilder/v3/test/e2e/utils#Kubectl) - - 4.4. Delete temporary resources after testing exited, e.g: - - Uninstall prerequisites CRDs: See [UninstallPrometheusOperManager](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/utils/test_context.go#L183) - - Delete temp dir. See [Destroy](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/utils/test_context.go#L255) +-4.4.Deletetemporaryresourcesaftertestingexited,e.g: +-UninstallprerequisitesCRDs:See[UninstallPrometheusOperManager](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/utils/test_context.go#L183) +-Deletetempdir.See[Destroy](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/utils/test_context.go#L255) -5. Add the command in [test/e2e/plugin](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/setup.sh#L65) to run your testing code: +5.Addthecommandin[test/e2e/plugin](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/setup.sh#L65)torunyourtestingcode: ```shell -go test $(dirname "$0")/ $flags -timeout 30m +gotest$(dirname"$0")/$flags-timeout30m ``` -#### 2. Sample Projects from the Plugin +####2.SampleProjectsfromthePlugin -It is also necessary to test consistency of the proposed plugin across different env and the integration with other plugins. +Itisalsonecessarytotestconsistencyoftheproposedpluginacrossdifferentenvandtheintegrationwithotherplugins. -This is performed by generating sample projects based on the plugins. The CI workflow defined in Github Action would validate the availability and the consistency. +Thisisperformedbygeneratingsampleprojectsbasedontheplugins.TheCIworkflowdefinedinGithubActionwouldvalidatetheavailabilityandtheconsistency. See: -- [test/testdata/generated.sh](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/testdata/generate.sh#L144) -- [make generate](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/Makefile#L70) +-[test/testdata/generated.sh](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/testdata/generate.sh#L144) +-[makegenerate](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/Makefile#L70) -## PR Process +##PRProcess -See [VERSIONING.md](VERSIONING.md) for a full description. TL;DR: +See[VERSIONING.md](VERSIONING.md)forafulldescription.TL;DR: -Every PR should be annotated with an icon indicating whether it's +EveryPRshouldbeannotatedwithaniconindicatingwhetherit's a: -- Breaking change: :warning: (`:warning:`) -- Non-breaking feature: :sparkles: (`:sparkles:`) -- Patch fix: :bug: (`:bug:`) -- Docs: :book: (`:book:`) -- Infra/Tests/Other: :seedling: (`:seedling:`) -- No release note: :ghost: (`:ghost:`) +-Breakingchange::warning:(`:warning:`) +-Non-breakingfeature::sparkles:(`:sparkles:`) +-Patchfix::bug:(`:bug:`) +-Docs::book:(`:book:`) +-Infra/Tests/Other::seedling:(`:seedling:`) +-Noreleasenote::ghost:(`:ghost:`) -Use :ghost: (no release note) only for the PRs that change or revert unreleased -changes, which don't deserve a release note. Please don't abuse it. +Use:ghost:(noreleasenote)onlyforthePRsthatchangeorrevertunreleased +changes,whichdon'tdeserveareleasenote.Pleasedon'tabuseit. -You can also use the equivalent emoji directly, since GitHub doesn't -render the `:xyz:` aliases in PR titles. +Youcanalsousetheequivalentemojidirectly,sinceGitHubdoesn't +renderthe`:xyz:`aliasesinPRtitles. -If the PR is "plugin" scoped, you may also append the responding plugin names in the prefix. -[For instance](https://github.com/kubernetes-sigs/kubebuilder/commit/0b36d0c4021bbf52f29d5a990157466761ec180c): +IfthePRis"plugin"scoped,youmayalsoappendtherespondingpluginnamesintheprefix. +[Forinstance](https://github.com/kubernetes-sigs/kubebuilder/commit/0b36d0c4021bbf52f29d5a990157466761ec180c): ``` -🐛 (kustomize/v2-alpha): Fix typo issue in the labels added to the manifests +🐛(kustomize/v2-alpha):Fixtypoissueinthelabelsaddedtothemanifests ``` -Individual commits should not be tagged separately, but will generally be -assumed to match the PR. For instance, if you have a bugfix in with -a breaking change, it's generally encouraged to submit the bugfix -separately, but if you must put them in one PR, mark the commit +Individualcommitsshouldnotbetaggedseparately,butwillgenerallybe +assumedtomatchthePR.Forinstance,ifyouhaveabugfixinwith +abreakingchange,it'sgenerallyencouragedtosubmitthebugfix +separately,butifyoumustputtheminonePR,markthecommit separately. -## Where the CI Tests are configured +##WheretheCITestsareconfigured -1. See the [action files](.github/workflows) to check its tests, and the scripts used on it. -2. Note that the prow tests used in the CI are configured in [kubernetes-sigs/kubebuilder/kubebuilder-presubmits.yaml](https://github.com/kubernetes/test-infra/blob/master/config/jobs/kubernetes-sigs/kubebuilder/kubebuilder-presubmits.yaml). -3. Check that all scripts used by the CI are defined in the project. -4. Notice that our policy to test the project is to run against k8s version N-2. So that the old version should be removed when there is a new k8s version available. +1.Seethe[actionfiles](.github/workflows)tocheckitstests,andthescriptsusedonit. +2.NotethattheprowtestsusedintheCIareconfiguredin[kubernetes-sigs/kubebuilder/kubebuilder-presubmits.yaml](https://github.com/kubernetes/test-infra/blob/master/config/jobs/kubernetes-sigs/kubebuilder/kubebuilder-presubmits.yaml). +3.CheckthatallscriptsusedbytheCIaredefinedintheproject. +4.Noticethatourpolicytotesttheprojectistorunagainstk8sversionN-2.Sothattheoldversionshouldberemovedwhenthereisanewk8sversionavailable. -## How to contribute to docs +##Howtocontributetodocs -The docs are published off of three branches: +Thedocsarepublishedoffofthreebranches: -- `book-v4`: [book.kubebuilder.io](https://book.kubebuilder.io) -- current docs -- `book-v3`: [book-v3.book.kubebuilder.io](https://book-v3.book.kubebuilder.io) -- legacy docs -- `book-v2`: [book-v2.book.kubebuilder.io](https://book-v2.book.kubebuilder.io) -- legacy docs -- `book-v1`: [book-v1.book.kubebuilder.io](https://book-v1.book.kubebuilder.io) -- legacy docs -- `master`: [master.book.kubebuilder.io](https://master.book.kubebuilder.io) -- "nightly" docs +-`book-v4`:[book.kubebuilder.io](https://book.kubebuilder.io)--currentdocs +-`book-v3`:[book-v3.book.kubebuilder.io](https://book-v3.book.kubebuilder.io)--legacydocs +-`book-v2`:[book-v2.book.kubebuilder.io](https://book-v2.book.kubebuilder.io)--legacydocs +-`book-v1`:[book-v1.book.kubebuilder.io](https://book-v1.book.kubebuilder.io)--legacydocs +-`master`:[master.book.kubebuilder.io](https://master.book.kubebuilder.io)--"nightly"docs -See [VERSIONING.md](VERSIONING.md#book-releases) for more information. +See[VERSIONING.md](VERSIONING.md#book-releases)formoreinformation. -There are certain writing style guidelines for Kubernetes documentation, checkout [style guide](https://kubernetes.io/docs/contribute/style/style-guide/) for more information. +TherearecertainwritingstyleguidelinesforKubernetesdocumentation,checkout[styleguide](https://kubernetes.io/docs/contribute/style/style-guide/)formoreinformation. -### How to preview the changes performed in the docs +###Howtopreviewthechangesperformedinthedocs -Check the CI job after to do the Pull Request and then, click on in the `Details` of `netlify/kubebuilder/deploy-preview` +ChecktheCIjobaftertodothePullRequestandthen,clickoninthe`Details`of`netlify/kubebuilder/deploy-preview` -## Community, discussion and support +##Community,discussionandsupport -Learn how to engage with the Kubernetes community on the [community page](http://kubernetes.io/community/). +LearnhowtoengagewiththeKubernetescommunityonthe[communitypage](http://kubernetes.io/community/). -You can reach the maintainers of this project at: +Youcanreachthemaintainersofthisprojectat: -- [Slack](http://slack.k8s.io/) -- [Mailing List](https://groups.google.com/forum/#!forum/kubebuilder) +-[Slack](http://slack.k8s.io/) +-[MailingList](https://groups.google.com/forum/#!forum/kubebuilder) -## Becoming a reviewer or approver +##Becomingareviewerorapprover -Contributors may eventually become official reviewers or approvers in -Kubebuilder and the related repositories. See -[CONTRIBUTING-ROLES.md](docs/CONTRIBUTING-ROLES.md) for more information. +Contributorsmayeventuallybecomeofficialreviewersorapproversin +Kubebuilderandtherelatedrepositories.See +[CONTRIBUTING-ROLES.md](docs/CONTRIBUTING-ROLES.md)formoreinformation. -## Code of conduct +##Codeofconduct -Participation in the Kubernetes community is governed by the [Kubernetes Code of Conduct](code-of-conduct.md). +ParticipationintheKubernetescommunityisgovernedbythe[KubernetesCodeofConduct](code-of-conduct.md). -[golangci]: https://github.com/golangci/golangci-lint -[kind]: https://kind.sigs.k8s.io/#installation-and-usage -[setup-envtest]: https://book.kubebuilder.io/reference/envtest -[k8s-contrubutiong-guide]: https://www.kubernetes.dev/docs/guide/contributing/ +[golangci]:https://github.com/golangci/golangci-lint +[kind]:https://kind.sigs.k8s.io/#installation-and-usage +[setup-envtest]:https://book.kubebuilder.io/reference/envtest +[k8s-contrubutiong-guide]:https://www.kubernetes.dev/docs/guide/contributing/ diff --git a/DESIGN.md b/DESIGN.md index d736a0fa8d0..9b73cff0bc7 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -1,117 +1,117 @@ -# Kubebuilder Design Principles - -This lays out some of the guiding design principles behind the Kubebuilder -project and its various components. - -## Overarching - -* **Libraries Over Code Generation**: Generated code is messy to maintain, - hard for humans to change and understand, and hard to update. Library - code is easy to update (just increase your dependency version), easier - to version using existing mechanisms, and more concise. - -* **Copy-pasting is bad**: Copy-pasted code suffers from similar problems - as code generation, except more acutely. Copy-pasted code is nearly - impossible to easy update, and frequently suffers from bugs and - misunderstandings. If something is being copy-pasted, it should - refactored into a library component or remote - [kustomize](https://sigs.k8s.io/kustomize) base. - -* **Common Cases Should Be Easy**: The 80-90% common cases should be - simple and easy for users to understand. - -* **Uncommon Cases Should Be Possible**: There shouldn't be situations - where it's downright impossible to do something within - controller-runtime or controller-tools. It may take extra digging or - coding, and it may involve interoperating with lower-level components, - but it should be possible without unreasonable friction. - -## Kubebuilder - -* **Kubebuilder Has Opinions**: Kubebuilder exists as an opinionated - project generator. It should strive to give users a reasonable project - layout that's simple enough to understand when getting started, but - provides room to grow. It might not match everyone's opinions, but it - should strive to be useful to most. - -* **Batteries Included**: Kubebuilder projects should contain enough - deployment information to reasonably develop and run the scaffolded - project. This includes testing, deployment files, and development - infrastructure to go from code to running containers. - -## controller-tools and controller-runtime - -* **Sufficient But Composable**: controller-tools and controller-runtime - should be sufficient for building a custom controller by hand. While - scaffolding and additional libraries may make life easier, building - without should be as painless as possible. That being said, they should - strive to be usable as building blocks for higher-level libraries as - well. - -* **Self-Sufficient Docs**: controller-tools and controller-runtime should - strive to have self-sufficient docs (i.e. documentation that doesn't - require reading other libraries' documentation for common use cases). - Examples should be plentiful. - -* **Contained Arcana**: Developers should not need to be experts in - Kubernetes API machinery to develop controllers, but those familiar with - Kubernetes API machinery should not feel out of place. Abstractions - should be intuitive to new users but feel familiar to experienced ones. - Abstractions should embrace the concepts of Kubernetes (e.g. declarative - idempotent reconcilers) while simplifying the details. - -## controller-runtime - -* **Abstractions Should Be Layered**: Abstractions should be built on top - of lower layers, such that advanced users can write custom logic while - still working within the existing model. For instance, the controller - builder is built on top of the event, source, and handler helpers, which - are in turn built for use with the event, source, and handler - interfaces. - -* **Repetitive Stress Injuries Are Bad**: - When possible, commonly used pieces should be exposed in a way that - enables clear, concise code. This includes aliasing groups of - functionality under "alias" or "prelude" packages to avoid having 40 - lines of imports, including common idioms as flexible helpers, and - infering resource information from the user's object types in client - code. - -* **A Little Bit of Magic Goes a Long Way**: In absence of generics, - reflection is acceptable, especially when it leads to clearer, conciser - code. However, when possible interfaces that use reflection should be - designed to avoid requiring the end-developer to use type assertions, - string splitting, which are error-prone and repetitive. These should be - dealt with inside controller-runtime internals. - -* **Defaults Over Constructors**: When not a huge performance impact, - favor auto-defaulting and `Options` structs over constructors. - Constructors quickly become unclear due to lack of names associated - with values, and don't work well with optional values. - -## Development - -* **Words Are Better Than Letters**: Don't abbreviate variable names - unless it's blindingly obvious what they are (e.g. `ctx` for `Context`). - Single- and double-letter method receivers are acceptable, but single- - and double-letter variables quickly become confusing the longer a code - block gets. - -* **Well-commented code**: Code should be commented and given Godocs, even - private methods and functions. It may *seem* obvious what they do at the - time and why, but you might forget, and others will certainly come along. - -* **Test Behaviors**: Test cases should be comprehensible as sets of - expected behaviors. Test cases read without code (e.g. just using `It`, - `Describe`, `Context`, and `By` lines) should still be able to explain - what's required of the tested interface. Testing behaviors makes - internal refactors easier, and makes reading tests easier. - -* **Real Components Over Mocks**: Avoid mocks and recording actions. Mocks - tend to be brittle and gradually become more complicated over time (e.g. - fake client implementations tend to grow into poorly-written, incomplete - API servers). Recording of actions tends to lead to brittle tests that - requires changes during refactors. Instead, test that the end desired - state is correct. Test the way the world should be, without caring how - it got there, and provide easy ways to set up the real components so - that mocks aren't required. +#KubebuilderDesignPrinciples + +ThislaysoutsomeoftheguidingdesignprinciplesbehindtheKubebuilder +projectanditsvariouscomponents. + +##Overarching + +***LibrariesOverCodeGeneration**:Generatedcodeismessytomaintain, +hardforhumanstochangeandunderstand,andhardtoupdate.Library +codeiseasytoupdate(justincreaseyourdependencyversion),easier +toversionusingexistingmechanisms,andmoreconcise. + +***Copy-pastingisbad**:Copy-pastedcodesuffersfromsimilarproblems +ascodegeneration,exceptmoreacutely.Copy-pastedcodeisnearly +impossibletoeasyupdate,andfrequentlysuffersfrombugsand +misunderstandings.Ifsomethingisbeingcopy-pasted,itshould +refactoredintoalibrarycomponentorremote +[kustomize](https://sigs.k8s.io/kustomize)base. + +***CommonCasesShouldBeEasy**:The80-90%commoncasesshouldbe +simpleandeasyforuserstounderstand. + +***UncommonCasesShouldBePossible**:Thereshouldn'tbesituations +whereit'sdownrightimpossibletodosomethingwithin +controller-runtimeorcontroller-tools.Itmaytakeextradiggingor +coding,anditmayinvolveinteroperatingwithlower-levelcomponents, +butitshouldbepossiblewithoutunreasonablefriction. + +##Kubebuilder + +***KubebuilderHasOpinions**:Kubebuilderexistsasanopinionated +projectgenerator.Itshouldstrivetogiveusersareasonableproject +layoutthat'ssimpleenoughtounderstandwhengettingstarted,but +providesroomtogrow.Itmightnotmatcheveryone'sopinions,butit +shouldstrivetobeusefultomost. + +***BatteriesIncluded**:Kubebuilderprojectsshouldcontainenough +deploymentinformationtoreasonablydevelopandrunthescaffolded +project.Thisincludestesting,deploymentfiles,anddevelopment +infrastructuretogofromcodetorunningcontainers. + +##controller-toolsandcontroller-runtime + +***SufficientButComposable**:controller-toolsandcontroller-runtime +shouldbesufficientforbuildingacustomcontrollerbyhand.While +scaffoldingandadditionallibrariesmaymakelifeeasier,building +withoutshouldbeaspainlessaspossible.Thatbeingsaid,theyshould +strivetobeusableasbuildingblocksforhigher-levellibrariesas +well. + +***Self-SufficientDocs**:controller-toolsandcontroller-runtimeshould +strivetohaveself-sufficientdocs(i.e.documentationthatdoesn't +requirereadingotherlibraries'documentationforcommonusecases). +Examplesshouldbeplentiful. + +***ContainedArcana**:Developersshouldnotneedtobeexpertsin +KubernetesAPImachinerytodevelopcontrollers,butthosefamiliarwith +KubernetesAPImachineryshouldnotfeeloutofplace.Abstractions +shouldbeintuitivetonewusersbutfeelfamiliartoexperiencedones. +AbstractionsshouldembracetheconceptsofKubernetes(e.g.declarative +idempotentreconcilers)whilesimplifyingthedetails. + +##controller-runtime + +***AbstractionsShouldBeLayered**:Abstractionsshouldbebuiltontop +oflowerlayers,suchthatadvanceduserscanwritecustomlogicwhile +stillworkingwithintheexistingmodel.Forinstance,thecontroller +builderisbuiltontopoftheevent,source,andhandlerhelpers,which +areinturnbuiltforusewiththeevent,source,andhandler +interfaces. + +***RepetitiveStressInjuriesAreBad**: +Whenpossible,commonlyusedpiecesshouldbeexposedinawaythat +enablesclear,concisecode.Thisincludesaliasinggroupsof +functionalityunder"alias"or"prelude"packagestoavoidhaving40 +linesofimports,includingcommonidiomsasflexiblehelpers,and +inferingresourceinformationfromtheuser'sobjecttypesinclient +code. + +***ALittleBitofMagicGoesaLongWay**:Inabsenceofgenerics, +reflectionisacceptable,especiallywhenitleadstoclearer,conciser +code.However,whenpossibleinterfacesthatusereflectionshouldbe +designedtoavoidrequiringtheend-developertousetypeassertions, +stringsplitting,whichareerror-proneandrepetitive.Theseshouldbe +dealtwithinsidecontroller-runtimeinternals. + +***DefaultsOverConstructors**:Whennotahugeperformanceimpact, +favorauto-defaultingand`Options`structsoverconstructors. +Constructorsquicklybecomeunclearduetolackofnamesassociated +withvalues,anddon'tworkwellwithoptionalvalues. + +##Development + +***WordsAreBetterThanLetters**:Don'tabbreviatevariablenames +unlessit'sblindinglyobviouswhattheyare(e.g.`ctx`for`Context`). +Single-anddouble-lettermethodreceiversareacceptable,butsingle- +anddouble-lettervariablesquicklybecomeconfusingthelongeracode +blockgets. + +***Well-commentedcode**:CodeshouldbecommentedandgivenGodocs,even +privatemethodsandfunctions.Itmay*seem*obviouswhattheydoatthe +timeandwhy,butyoumightforget,andotherswillcertainlycomealong. + +***TestBehaviors**:Testcasesshouldbecomprehensibleassetsof +expectedbehaviors.Testcasesreadwithoutcode(e.g.justusing`It`, +`Describe`,`Context`,and`By`lines)shouldstillbeabletoexplain +what'srequiredofthetestedinterface.Testingbehaviorsmakes +internalrefactorseasier,andmakesreadingtestseasier. + +***RealComponentsOverMocks**:Avoidmocksandrecordingactions.Mocks +tendtobebrittleandgraduallybecomemorecomplicatedovertime(e.g. +fakeclientimplementationstendtogrowintopoorly-written,incomplete +APIservers).Recordingofactionstendstoleadtobrittleteststhat +requireschangesduringrefactors.Instead,testthattheenddesired +stateiscorrect.Testthewaytheworldshouldbe,withoutcaringhow +itgotthere,andprovideeasywaystosetuptherealcomponentsso +thatmocksaren'trequired. diff --git a/Makefile b/Makefile index b2e33008d07..dda17f14f63 100644 --- a/Makefile +++ b/Makefile @@ -66,6 +66,8 @@ install: build ## Build and install the binary with the current source code. Use .PHONY: generate generate: generate-testdata generate-docs ## Update/generate all mock data. You should run this commands to update the mock data after your changes. go mod tidy + @echo "Removing trailing spaces" + find . -type f -name "*.md" -exec sed -i '' 's/[[:space:]]*//g' {} + .PHONY: generate-testdata generate-testdata: ## Update/generate the testdata in $GOPATH/src/sigs.k8s.io/kubebuilder @@ -160,3 +162,7 @@ test-book: ## Run the cronjob tutorial's unit tests to make sure we don't break .PHONY: test-license test-license: ## Run the license check ./test/check-license.sh + +.PHONY: test-spaces +test-spaces: ## Run the trailing spaces check + ./test/check_spaces.sh \ No newline at end of file diff --git a/README.md b/README.md index 7ab2727e630..17d75934ace 100644 --- a/README.md +++ b/README.md @@ -1,145 +1,145 @@ [![Lint](https://github.com/kubernetes-sigs/kubebuilder/actions/workflows/lint.yml/badge.svg)](https://github.com/kubernetes-sigs/kubebuilder/actions/workflows/lint.yml) -[![Unit tests](https://github.com/kubernetes-sigs/kubebuilder/actions/workflows/unit-tests.yml/badge.svg)](https://github.com/kubernetes-sigs/kubebuilder/actions/workflows/unit-tests.yml) -[![Go Report Card](https://goreportcard.com/badge/sigs.k8s.io/kubebuilder)](https://goreportcard.com/report/sigs.k8s.io/kubebuilder) -[![Coverage Status](https://coveralls.io/repos/github/kubernetes-sigs/kubebuilder/badge.svg?branch=master)](https://coveralls.io/github/kubernetes-sigs/kubebuilder?branch=master) -[![Latest release](https://badgen.net/github/release/kubernetes-sigs/kubebuilder)](https://github.com/kubernetes-sigs/kubebuilder/lreleases) +[![Unittests](https://github.com/kubernetes-sigs/kubebuilder/actions/workflows/unit-tests.yml/badge.svg)](https://github.com/kubernetes-sigs/kubebuilder/actions/workflows/unit-tests.yml) +[![GoReportCard](https://goreportcard.com/badge/sigs.k8s.io/kubebuilder)](https://goreportcard.com/report/sigs.k8s.io/kubebuilder) +[![CoverageStatus](https://coveralls.io/repos/github/kubernetes-sigs/kubebuilder/badge.svg?branch=master)](https://coveralls.io/github/kubernetes-sigs/kubebuilder?branch=master) +[![Latestrelease](https://badgen.net/github/release/kubernetes-sigs/kubebuilder)](https://github.com/kubernetes-sigs/kubebuilder/lreleases) -## Kubebuilder +##Kubebuilder -Kubebuilder is a framework for building Kubernetes APIs using [custom resource definitions (CRDs)](https://kubernetes.io/docs/tasks/access-kubernetes-api/extend-api-custom-resource-definitions). +KubebuilderisaframeworkforbuildingKubernetesAPIsusing[customresourcedefinitions(CRDs)](https://kubernetes.io/docs/tasks/access-kubernetes-api/extend-api-custom-resource-definitions). -Similar to web development frameworks such as *Ruby on Rails* and *SpringBoot*, -Kubebuilder increases velocity and reduces the complexity managed by -developers for rapidly building and publishing Kubernetes APIs in Go. -It builds on top of the canonical techniques used to build the core Kubernetes APIs to provide simple abstractions that reduce boilerplate and toil. +Similartowebdevelopmentframeworkssuchas*RubyonRails*and*SpringBoot*, +Kubebuilderincreasesvelocityandreducesthecomplexitymanagedby +developersforrapidlybuildingandpublishingKubernetesAPIsinGo. +ItbuildsontopofthecanonicaltechniquesusedtobuildthecoreKubernetesAPIstoprovidesimpleabstractionsthatreduceboilerplateandtoil. -Kubebuilder does **not** exist as an example to *copy-paste*, but instead provides powerful libraries and tools -to simplify building and publishing Kubernetes APIs from scratch. It -provides a plugin architecture allowing users to take advantage of optional helpers -and features. To learn more about this see the [Plugin section][plugin-section]. +Kubebuilderdoes**not**existasanexampleto*copy-paste*,butinsteadprovidespowerfullibrariesandtools +tosimplifybuildingandpublishingKubernetesAPIsfromscratch.It +providesapluginarchitectureallowinguserstotakeadvantageofoptionalhelpers +andfeatures.Tolearnmoreaboutthisseethe[Pluginsection][plugin-section]. -Kubebuilder is developed on top of the [controller-runtime][controller-runtime] and [controller-tools][controller-tools] libraries. +Kubebuilderisdevelopedontopofthe[controller-runtime][controller-runtime]and[controller-tools][controller-tools]libraries. -### Kubebuilder is also a library +###Kubebuilderisalsoalibrary -Kubebuilder is extensible and can be used as a library in other projects. -[Operator-SDK][operator-sdk] is a good example of a project that uses Kubebuilder as a library. -[Operator-SDK][operator-sdk] uses the plugin feature to include non-Go operators _e.g. operator-sdk's Ansible and Helm-based language Operators_. +Kubebuilderisextensibleandcanbeusedasalibraryinotherprojects. +[Operator-SDK][operator-sdk]isagoodexampleofaprojectthatusesKubebuilderasalibrary. +[Operator-SDK][operator-sdk]usesthepluginfeaturetoincludenon-Gooperators_e.g.operator-sdk'sAnsibleandHelm-basedlanguageOperators_. -To learn more see [how to create your own plugins][your-own-plugins]. +Tolearnmoresee[howtocreateyourownplugins][your-own-plugins]. -### Installation +###Installation -It is strongly recommended that you use a released version. Release binaries are available on the [releases](https://github.com/kubernetes-sigs/kubebuilder/releases) page. -Follow the [instructions](https://book.kubebuilder.io/quick-start.html#installation) to install Kubebuilder. +Itisstronglyrecommendedthatyouuseareleasedversion.Releasebinariesareavailableonthe[releases](https://github.com/kubernetes-sigs/kubebuilder/releases)page. +Followthe[instructions](https://book.kubebuilder.io/quick-start.html#installation)toinstallKubebuilder. -## Getting Started +##GettingStarted -See the [Getting Started](https://book.kubebuilder.io/quick-start.html) documentation. +Seethe[GettingStarted](https://book.kubebuilder.io/quick-start.html)documentation. -![Quick Start](docs/gif/kb-demo.v3.11.1.svg) +![QuickStart](docs/gif/kb-demo.v3.11.1.svg) -Also, ensure that you check out the [Deploy Image](https://book.kubebuilder.io/plugins/deploy-image-plugin-v1-alpha.html) -Plugin. This plugin allows users to scaffold API/Controllers to deploy and manage an -Operand (image) on the cluster following the guidelines and best practices. It abstracts the -complexities of achieving this goal while allowing users to customize the generated code. +Also,ensurethatyoucheckoutthe[DeployImage](https://book.kubebuilder.io/plugins/deploy-image-plugin-v1-alpha.html) +Plugin.ThispluginallowsuserstoscaffoldAPI/Controllerstodeployandmanagean +Operand(image)ontheclusterfollowingtheguidelinesandbestpractices.Itabstractsthe +complexitiesofachievingthisgoalwhileallowinguserstocustomizethegeneratedcode. -## Documentation +##Documentation -Check out the Kubebuilder [book](https://book.kubebuilder.io). +CheckouttheKubebuilder[book](https://book.kubebuilder.io). -## Resources +##Resources -- Kubebuilder Book: [book.kubebuilder.io](https://book.kubebuilder.io) -- GitHub Repo: [kubernetes-sigs/kubebuilder](https://github.com/kubernetes-sigs/kubebuilder) -- Slack channel: [#kubebuilder](https://kubernetes.slack.com/messages/#kubebuilder) -- Google Group: [kubebuilder@googlegroups.com](https://groups.google.com/forum/#!forum/kubebuilder) -- Design Documents: [designs](designs/) -- Plugin: [plugins][plugin-section] +-KubebuilderBook:[book.kubebuilder.io](https://book.kubebuilder.io) +-GitHubRepo:[kubernetes-sigs/kubebuilder](https://github.com/kubernetes-sigs/kubebuilder) +-Slackchannel:[#kubebuilder](https://kubernetes.slack.com/messages/#kubebuilder) +-GoogleGroup:[kubebuilder@googlegroups.com](https://groups.google.com/forum/#!forum/kubebuilder) +-DesignDocuments:[designs](designs/) +-Plugin:[plugins][plugin-section] -## Motivation +##Motivation -Building Kubernetes tools and APIs involves making a lot of decisions and writing a lot of boilerplate. +BuildingKubernetestoolsandAPIsinvolvesmakingalotofdecisionsandwritingalotofboilerplate. -In order to facilitate easily building Kubernetes APIs and tools using the canonical approach, this framework -provides a collection of Kubernetes development tools to minimize toil. +InordertofacilitateeasilybuildingKubernetesAPIsandtoolsusingthecanonicalapproach,thisframework +providesacollectionofKubernetesdevelopmenttoolstominimizetoil. -Kubebuilder attempts to facilitate the following developer workflow for building APIs +KubebuilderattemptstofacilitatethefollowingdeveloperworkflowforbuildingAPIs -1. Create a new project directory -2. Create one or more resource APIs as CRDs and then add fields to the resources -3. Implement reconcile loops in controllers and watch additional resources -4. Test by running against a cluster (self-installs CRDs and starts controllers automatically) -5. Update bootstrapped integration tests to test new fields and business logic -6. Build and publish a container from the provided Dockerfile +1.Createanewprojectdirectory +2.CreateoneormoreresourceAPIsasCRDsandthenaddfieldstotheresources +3.Implementreconcileloopsincontrollersandwatchadditionalresources +4.Testbyrunningagainstacluster(self-installsCRDsandstartscontrollersautomatically) +5.Updatebootstrappedintegrationteststotestnewfieldsandbusinesslogic +6.BuildandpublishacontainerfromtheprovidedDockerfile -## Scope +##Scope -Building APIs using CRDs, Controllers and Admission Webhooks. +BuildingAPIsusingCRDs,ControllersandAdmissionWebhooks. -## Philosophy +##Philosophy -See [DESIGN.md](DESIGN.md) for the guiding principles of the various Kubebuilder projects. +See[DESIGN.md](DESIGN.md)fortheguidingprinciplesofthevariousKubebuilderprojects. TL;DR: -Provide clean library abstractions with clear and well exampled godocs. +Providecleanlibraryabstractionswithclearandwellexampledgodocs. -- Prefer using go *interfaces* and *libraries* over relying on *code generation* -- Prefer using *code generation* over *1 time init* of stubs -- Prefer *1 time init* of stubs over forked and modified boilerplate -- Never fork and modify boilerplate +-Preferusinggo*interfaces*and*libraries*overrelyingon*codegeneration* +-Preferusing*codegeneration*over*1timeinit*ofstubs +-Prefer*1timeinit*ofstubsoverforkedandmodifiedboilerplate +-Neverforkandmodifyboilerplate -## Techniques +##Techniques -- Provide higher level libraries on top of low level client libraries - - Protect developers from breaking changes in low level libraries - - Start minimal and provide progressive discovery of functionality - - Provide sane defaults and allow users to override when they exist -- Provide code generators to maintain common boilerplate that can't be addressed by interfaces - - Driven off of `//+` comments -- Provide bootstrapping commands to initialize new packages +-Providehigherlevellibrariesontopoflowlevelclientlibraries +-Protectdevelopersfrombreakingchangesinlowlevellibraries +-Startminimalandprovideprogressivediscoveryoffunctionality +-Providesanedefaultsandallowuserstooverridewhentheyexist +-Providecodegeneratorstomaintaincommonboilerplatethatcan'tbeaddressedbyinterfaces +-Drivenoffof`//+`comments +-Providebootstrappingcommandstoinitializenewpackages -## Versioning and Releasing +##VersioningandReleasing -See [VERSIONING.md](VERSIONING.md). +See[VERSIONING.md](VERSIONING.md). -## Troubleshooting +##Troubleshooting -- ### Bugs and Feature Requests: - If you have what looks like a bug, or you would like to make a feature request, please use the [Github issue tracking system.](https://github.com/kubernetes-sigs/kubebuilder/issues) -Before you file an issue, please search existing issues to see if your issue is already covered. +-###BugsandFeatureRequests: +Ifyouhavewhatlookslikeabug,oryouwouldliketomakeafeaturerequest,pleaseusethe[Githubissuetrackingsystem.](https://github.com/kubernetes-sigs/kubebuilder/issues) +Beforeyoufileanissue,pleasesearchexistingissuestoseeifyourissueisalreadycovered. -- ### Slack - For realtime discussion, you can join the [#kubebuilder](https://slack.k8s.io/#kubebuilder) slack channel. Slack requires registration, but the Kubernetes team is open invitation to anyone to register here. Feel free to come and ask any questions. +-###Slack +Forrealtimediscussion,youcanjointhe[#kubebuilder](https://slack.k8s.io/#kubebuilder)slackchannel.Slackrequiresregistration,buttheKubernetesteamisopeninvitationtoanyonetoregisterhere.Feelfreetocomeandaskanyquestions. -## Contributing +##Contributing -Contributions are greatly appreciated. The maintainers actively manage the issues list, and try to highlight issues suitable for newcomers. -The project follows the typical GitHub pull request model. See [CONTRIBUTING.md](CONTRIBUTING.md) for more details. -Before starting any work, please either comment on an existing issue, or file a new one. +Contributionsaregreatlyappreciated.Themaintainersactivelymanagetheissueslist,andtrytohighlightissuessuitablefornewcomers. +TheprojectfollowsthetypicalGitHubpullrequestmodel.See[CONTRIBUTING.md](CONTRIBUTING.md)formoredetails. +Beforestartinganywork,pleaseeithercommentonanexistingissue,orfileanewone. -## Supportability +##Supportability -Currently, Kubebuilder officially supports OSX and Linux platforms. -So, if you are using a Windows OS you may find issues. Contributions towards -supporting Windows are welcome. +Currently,KubebuilderofficiallysupportsOSXandLinuxplatforms. +So,ifyouareusingaWindowsOSyoumayfindissues.Contributionstowards +supportingWindowsarewelcome. -### Apple Silicon +###AppleSilicon -Apple Silicon (`darwin/arm64`) support begins with the `go/v4` plugin. +AppleSilicon(`darwin/arm64`)supportbeginswiththe`go/v4`plugin. -## Community Meetings - -The following meetings happen biweekly: - -- Kubebuilder Meeting +##CommunityMeetings -You are more than welcome to attend. For further info join to [kubebuilder@googlegroups.com](https://groups.google.com/g/kubebuilder). -Every month, our team meets on the first Thursday at 11:00 PT (Pacific Time) to discuss our progress and plan for the upcoming weeks. +Thefollowingmeetingshappenbiweekly: -[operator-sdk]: https://github.com/operator-framework/operator-sdk -[plugin-section]: https://book.kubebuilder.io/plugins/plugins.html -[controller-runtime]: https://github.com/kubernetes-sigs/controller-runtime -[your-own-plugins]: https://book.kubebuilder.io/plugins/creating-plugins.html -[controller-tools]: https://github.com/kubernetes-sigs/controller-tools +-KubebuilderMeeting + +Youaremorethanwelcometoattend.Forfurtherinfojointo[kubebuilder@googlegroups.com](https://groups.google.com/g/kubebuilder). +Everymonth,ourteammeetsonthefirstThursdayat11:00PT(PacificTime)todiscussourprogressandplanfortheupcomingweeks. + +[operator-sdk]:https://github.com/operator-framework/operator-sdk +[plugin-section]:https://book.kubebuilder.io/plugins/plugins.html +[controller-runtime]:https://github.com/kubernetes-sigs/controller-runtime +[your-own-plugins]:https://book.kubebuilder.io/plugins/creating-plugins.html +[controller-tools]:https://github.com/kubernetes-sigs/controller-tools diff --git a/RELEASE.md b/RELEASE.md index f1329419e9d..77aac56ac1b 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,125 +1,125 @@ -# Release Process +#ReleaseProcess -The Kubebuilder Project is released on an as-needed basis. The process is as follows: +TheKubebuilderProjectisreleasedonanas-neededbasis.Theprocessisasfollows: -**Note:** Releases are done from the `release-MAJOR.MINOR` branches. For PATCH releases it is not required -to create a new branch. Instead, you will just need to ensure that all major fixes are cherry-picked into the respective -`release-MAJOR.MINOR` branch. To know more about versioning check https://semver.org/. +**Note:**Releasesaredonefromthe`release-MAJOR.MINOR`branches.ForPATCHreleasesitisnotrequired +tocreateanewbranch.Instead,youwilljustneedtoensurethatallmajorfixesarecherry-pickedintotherespective +`release-MAJOR.MINOR`branch.Toknowmoreaboutversioningcheckhttps://semver.org/. -**Note:** Before `3.5.*` release this project was released based on `MAJOR`. A change to the -process was done to ensure that we have an aligned process under the org (similar to `controller-runtime` and -`controller-tools`) and to make it easier to produce patch releases. +**Note:**Before`3.5.*`releasethisprojectwasreleasedbasedon`MAJOR`.Achangetothe +processwasdonetoensurethatwehaveanalignedprocessundertheorg(similarto`controller-runtime`and +`controller-tools`)andtomakeiteasiertoproducepatchreleases. -## How to do a release +##Howtodoarelease -### Create the new branch and the release tag +###Createthenewbranchandthereleasetag -1. Create a new branch `git checkout -b release-` from master -2. Push the new branch to the remote repository +1.Createanewbranch`gitcheckout-brelease-`frommaster +2.Pushthenewbranchtotheremoterepository -### Now, let's generate the changelog +###Now,let'sgeneratethechangelog -1. Create the changelog from the new branch `release-` (`git checkout release-`). - You will need to use the [kubebuilder-release-tools][kubebuilder-release-tools] to generate release notes. See [here][release-notes-generation] +1.Createthechangelogfromthenewbranch`release-`(`gitcheckoutrelease-`). +Youwillneedtousethe[kubebuilder-release-tools][kubebuilder-release-tools]togeneratereleasenotes.See[here][release-notes-generation] -> **Note** -> - You will need to have checkout locally from the remote repository the previous branch -> - Also, ensure that you fetch all tags from the remote `git fetch --all --tags` -> - Also, if you face issues to generate the release notes you might want to able to sort it out by running i.e.: -> `go run sigs.k8s.io/kubebuilder-release-tools/notes --use-upstream=false --from=v3.11.0 --branch=release-X` +>**Note** +>-Youwillneedtohavecheckoutlocallyfromtheremoterepositorythepreviousbranch +>-Also,ensurethatyoufetchalltagsfromtheremote`gitfetch--all--tags` +>-Also,ifyoufaceissuestogeneratethereleasenotesyoumightwanttoabletosortitoutbyrunningi.e.: +>`gorunsigs.k8s.io/kubebuilder-release-tools/notes--use-upstream=false--from=v3.11.0--branch=release-X` -### Draft a new release from GitHub +###DraftanewreleasefromGitHub -1. Create a new tag with the correct version from the new `release-` branch -2. Verify the Release Github Action. It should build the assets and publish in the draft release -3. You also need to manually add the changelog generated above on the release page and publish it. Now, the code source is released ! +1.Createanewtagwiththecorrectversionfromthenew`release-`branch +2.VerifytheReleaseGithubAction.Itshouldbuildtheassetsandpublishinthedraftrelease +3.Youalsoneedtomanuallyaddthechangeloggeneratedaboveonthereleasepageandpublishit.Now,thecodesourceisreleased! -### Update the website docs (https://book.kubebuilder.io/quick-start.html) +###Updatethewebsitedocs(https://book.kubebuilder.io/quick-start.html) -1. Push a PR to update the `book-v3` branch with the changes of the latest release branch created (`release-`) -2. Ping in the [Kubebuilder Slack channel](https://kubernetes.slack.com/archives/CAR30FCJZ) and ask for reviews. +1.PushaPRtoupdatethe`book-v3`branchwiththechangesofthelatestreleasebranchcreated(`release-`) +2.Pinginthe[KubebuilderSlackchannel](https://kubernetes.slack.com/archives/CAR30FCJZ)andaskforreviews. -### When the release be done and the website update: Announce the new release: +###Whenthereleasebedoneandthewebsiteupdate:Announcethenewrelease: -1. Announce the new release on the Slack channel, i.e: +1.AnnouncethenewreleaseontheSlackchannel,i.e: ```` -:announce: Kubebuilder v3.5.0 has been released! -This release includes a Kubernetes dependency bump to v1.24. -For more info, see the release page: https://github.com/kubernetes-sigs/kubebuilder/releases/tag/v3.5.0 - :tada: Thanks to all our contributors! +:announce:Kubebuilderv3.5.0hasbeenreleased! +ThisreleaseincludesaKubernetesdependencybumptov1.24. +Formoreinfo,seethereleasepage:https://github.com/kubernetes-sigs/kubebuilder/releases/tag/v3.5.0 +:tada:Thankstoallourcontributors! ```` -2. Announce the new release via email is sent to `kubebuilder@googlegroups.com` with the subject `[ANNOUNCE] Kubebuilder $VERSION is released` +2.Announcethenewreleaseviaemailissentto`kubebuilder@googlegroups.com`withthesubject`[ANNOUNCE]Kubebuilder$VERSIONisreleased` -## HEAD releases +##HEADreleases -The binaries releases for HEAD are available here: +ThebinariesreleasesforHEADareavailablehere: -- [kubebuilder-release-master-head-darwin-amd64.tar.gz](https://storage.googleapis.com/kubebuilder-release/kubebuilder-release-master-head-darwin-amd64.tar.gz) -- [kubebuilder-release-master-head-linux-amd64.tar.gz](https://storage.googleapis.com/kubebuilder-release/kubebuilder-release-master-head-linux-amd64.tar.gz) +-[kubebuilder-release-master-head-darwin-amd64.tar.gz](https://storage.googleapis.com/kubebuilder-release/kubebuilder-release-master-head-darwin-amd64.tar.gz) +-[kubebuilder-release-master-head-linux-amd64.tar.gz](https://storage.googleapis.com/kubebuilder-release/kubebuilder-release-master-head-linux-amd64.tar.gz) -## How the releases are configured +##Howthereleasesareconfigured -The releases occur in an account in the Google Cloud (See [here](https://console.cloud.google.com/cloud-build/builds?project=kubebuilder)) using Cloud Build. +ThereleasesoccurinanaccountintheGoogleCloud(See[here](https://console.cloud.google.com/cloud-build/builds?project=kubebuilder))usingCloudBuild. -### To build the Kubebuilder CLI binaries: +###TobuildtheKubebuilderCLIbinaries: -A trigger GitHub action [release](.github/workflows/release.yml) is trigged when a new tag is pushed. -This action will caall the job [./build/.goreleaser.yml](./build/.goreleaser.yml). +AtriggerGitHubaction[release](.github/workflows/release.yml)istriggedwhenanewtagispushed. +Thisactionwillcaallthejob[./build/.goreleaser.yml](./build/.goreleaser.yml). -### To build the Kubebuilder-tools: (Artifacts required to use ENV TEST) +###TobuildtheKubebuilder-tools:(ArtifactsrequiredtouseENVTEST) -Kubebuilder projects requires artifacts which are used to do test with ENV TEST (when we call `make test` target) -These artifacts can be checked in the service page: https://storage.googleapis.com/kubebuilder-tools +KubebuilderprojectsrequiresartifactswhichareusedtodotestwithENVTEST(whenwecall`maketest`target) +Theseartifactscanbecheckedintheservicepage:https://storage.googleapis.com/kubebuilder-tools -The build is made from the branch [tools-releases](https://github.com/kubernetes-sigs/kubebuilder/tree/tools-releases) and the trigger will call the `build/cloudbuild_tools.yaml` passing -as argument the architecture and the SO that should be used, e.g: +Thebuildismadefromthebranch[tools-releases](https://github.com/kubernetes-sigs/kubebuilder/tree/tools-releases)andthetriggerwillcallthe`build/cloudbuild_tools.yaml`passing +asargumentthearchitectureandtheSOthatshouldbeused,e.g: -Screenshot 2022-04-30 at 10 15 41 + -For further information see the [README](https://github.com/kubernetes-sigs/kubebuilder/blob/tools-releases/README.md). +Forfurtherinformationseethe[README](https://github.com/kubernetes-sigs/kubebuilder/blob/tools-releases/README.md). -### To build the `kube-rbac-proxy` images: +###Tobuildthe`kube-rbac-proxy`images: -These images are built from the project [brancz/kube-rbac-proxy](https://github.com/brancz/kube-rbac-proxy). -The projects built with Kubebuilder creates a side container with `kube-rbac-proxy` to protect the Manager. +Theseimagesarebuiltfromtheproject[brancz/kube-rbac-proxy](https://github.com/brancz/kube-rbac-proxy). +TheprojectsbuiltwithKubebuildercreatesasidecontainerwith`kube-rbac-proxy`toprotecttheManager. -These images are can be checked in the consolse, see [here](https://console.cloud.google.com/gcr/images/kubebuilder/GLOBAL/kube-rbac-proxy). +Theseimagesarecanbecheckedintheconsolse,see[here](https://console.cloud.google.com/gcr/images/kubebuilder/GLOBAL/kube-rbac-proxy). -The project `kube-rbac-proxy` is in the process to be donated to the k8s org. However, it is going on for a long time and then, -we have no ETA for that to occur. When that occurs we can automate this process. But until there we need to generate these images -by bumping the versions/tags released by `kube-rbac-proxy` on the branch +Theproject`kube-rbac-proxy`isintheprocesstobedonatedtothek8sorg.However,itisgoingonforalongtimeandthen, +wehavenoETAforthattooccur.Whenthatoccurswecanautomatethisprocess.Butuntilthereweneedtogeneratetheseimages +bybumpingtheversions/tagsreleasedby`kube-rbac-proxy`onthebranch [kube-rbac-proxy-releases](https://github.com/kubernetes-sigs/kubebuilder/tree/kube-rbac-proxy-releases) -then the `build/cloudbuild_kube-rbac-proxy.yaml` will generate the images. +thenthe`build/cloudbuild_kube-rbac-proxy.yaml`willgeneratetheimages. -To check an example, see the pull request [#2578](https://github.com/kubernetes-sigs/kubebuilder/pull/2578). +Tocheckanexample,seethepullrequest[#2578](https://github.com/kubernetes-sigs/kubebuilder/pull/2578). -**Note**: we cannot use the images produced by the project `kube-rbac-proxy` because we need to ensure -to Kubebuilder users that these images will be available. +**Note**:wecannotusetheimagesproducedbytheproject`kube-rbac-proxy`becauseweneedtoensure +toKubebuilderusersthattheseimageswillbeavailable. -### To build the `gcr.io/kubebuilder/pr-verifier` images: +###Tobuildthe`gcr.io/kubebuilder/pr-verifier`images: -These images are used to verify the PR title and description. They are built from [kubernetes-sigs/kubebuilder-release-tools](https://github.com/kubernetes-sigs/kubebuilder-release-tools/). -In Kubebuilder, we have been using this project via the GitHub action [.github/workflows/verify.yml](.github/workflows/verify.yml) -and not the image, see: +TheseimagesareusedtoverifythePRtitleanddescription.Theyarebuiltfrom[kubernetes-sigs/kubebuilder-release-tools](https://github.com/kubernetes-sigs/kubebuilder-release-tools/). +InKubebuilder,wehavebeenusingthisprojectviatheGitHubaction[.github/workflows/verify.yml](.github/workflows/verify.yml) +andnottheimage,see: ```yaml - verify: - name: Verify PR contents - runs-on: ubuntu-latest - steps: - - name: Verifier action - id: verifier - uses: kubernetes-sigs/kubebuilder-release-tools@v0.1.1 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} +verify: +name:VerifyPRcontents +runs-on:ubuntu-latest +steps: +-name:Verifieraction +id:verifier +uses:kubernetes-sigs/kubebuilder-release-tools@v0.1.1 +with: +github_token:${{secrets.GITHUB_TOKEN}} ``` -However, the image should still be built and maintained since other projects under the org might be using them. +However,theimageshouldstillbebuiltandmaintainedsinceotherprojectsundertheorgmightbeusingthem. -[kubebuilder-release-tools]: https://github.com/kubernetes-sigs/kubebuilder-release-tools -[release-notes-generation]: https://github.com/kubernetes-sigs/kubebuilder-release-tools/blob/master/README.md#release-notes-generation -[release-process]: https://github.com/kubernetes-sigs/kubebuilder/blob/master/VERSIONING.md#releasing +[kubebuilder-release-tools]:https://github.com/kubernetes-sigs/kubebuilder-release-tools +[release-notes-generation]:https://github.com/kubernetes-sigs/kubebuilder-release-tools/blob/master/README.md#release-notes-generation +[release-process]:https://github.com/kubernetes-sigs/kubebuilder/blob/master/VERSIONING.md#releasing diff --git a/VERSIONING.md b/VERSIONING.md index d26a8552434..0d561a4f1ff 100644 --- a/VERSIONING.md +++ b/VERSIONING.md @@ -1,62 +1,62 @@ -# Versioning and Releasing for Kubebuilder +#VersioningandReleasingforKubebuilder -We (mostly) follow the [common Kubebuilder versioning -guidelines][guidelines], and use the corresponding tooling and PR process -described there. +We(mostly)followthe[commonKubebuilderversioning +guidelines][guidelines],andusethecorrespondingtoolingandPRprocess +describedthere. -For the purposes of the aforementioned guidelines, Kubebuilder counts as -a "CLI project". +Forthepurposesoftheaforementionedguidelines,Kubebuildercountsas +a"CLIproject". -[guidelines]: https://sigs.k8s.io/kubebuilder-release-tools/VERSIONING.md +[guidelines]:https://sigs.k8s.io/kubebuilder-release-tools/VERSIONING.md -## Compatibility +##Compatibility -Note that we generally do not support older release branches, except in -extreme circumstances. +Notethatwegenerallydonotsupportolderreleasebranches,exceptin +extremecircumstances. -Bear in mind that changes to scaffolding generally constitute breaking -changes -- see [below](#understanding-the-versions) for more details. +Bearinmindthatchangestoscaffoldinggenerallyconstitutebreaking +changes--see[below](#understanding-the-versions)formoredetails. -## Releasing +##Releasing -When releasing, you'll need to: +Whenreleasing,you'llneedto: -- to update references in [the build directory](build/) to the latest - version of the [envtest tools](#tools-releases) **before tagging the - release.** +-toupdatereferencesin[thebuilddirectory](build/)tothelatest +versionofthe[envtesttools](#tools-releases)**beforetaggingthe +release.** -- reset the book branch: see [below](#book-releases) +-resetthebookbranch:see[below](#book-releases) -You may also want to check that the book is generating the marker docs off -the latest controller-tools release. That info is stored in +Youmayalsowanttocheckthatthebookisgeneratingthemarkerdocsoff +thelatestcontroller-toolsrelease.Thatinfoisstoredin [docs/book/install-and-build.sh](/docs/book/install-and-build.sh). -## Book Releases +##BookReleases -The book's main version (https://book.kubebuilder.io) is published off of -the [book-v3][book-branch] (a version built off the main branch can be -found at https://master.book.kubebuilder.io). +Thebook'smainversion(https://book.kubebuilder.io)ispublishedoffof +the[book-v3][book-branch](aversionbuiltoffthemainbranchcanbe +foundathttps://master.book.kubebuilder.io). -Docs changes that aren't specific to a new feature should be -cherry-picked to the aforementioned branch to get them to be published. -The cherry-picks will automatically be published to the book once their PR +Docschangesthataren'tspecifictoanewfeatureshouldbe +cherry-pickedtotheaforementionedbranchtogetthemtobepublished. +Thecherry-pickswillautomaticallybepublishedtothebookoncetheirPR merges. -**When you publish a Kubebuilder release**, be sure to also submit a PR -that merges the main branch into [book-v3][book-branch], so that it -describes the latest changes in the new release. +**WhenyoupublishaKubebuilderrelease**,besuretoalsosubmitaPR +thatmergesthemainbranchinto[book-v3][book-branch],sothatit +describesthelatestchangesinthenewrelease. -[book-branch]: https://github.com/kubernetes-sigs/kubebuilder/tree/tools-releases +[book-branch]:https://github.com/kubernetes-sigs/kubebuilder/tree/tools-releases -## Tools Releases +##ToolsReleases -In order to update the [envtest tools][envtest-ref], you'll need to do an -update to the [tools-releases branch][tools-branch]. Simply submit a PR -against that branch that changes all references to the current version to -the desired next version. Once the PR is merged, Google Cloud Build will -take care of building and publishing the artifacts. +Inordertoupdatethe[envtesttools][envtest-ref],you'llneedtodoan +updatetothe[tools-releasesbranch][tools-branch].SimplysubmitaPR +againstthatbranchthatchangesallreferencestothecurrentversionto +thedesirednextversion.OncethePRismerged,GoogleCloudBuildwill +takecareofbuildingandpublishingtheartifacts. -[envtest-ref]: https://book.kubebuilder.io/reference/artifacts.html -[tools-branch]: https://github.com/kubernetes-sigs/kubebuilder/tree/tools-releases +[envtest-ref]:https://book.kubebuilder.io/reference/artifacts.html +[tools-branch]:https://github.com/kubernetes-sigs/kubebuilder/tree/tools-releases [kb-releases]:https://github.com/kubernetes-sigs/kubebuilder/releases [cli-plugins-versioning]:docs/book/src/plugins/extending-cli.md#plugin-versioning diff --git a/code-of-conduct.md b/code-of-conduct.md index 3cd88b27d82..6d78a9f93ce 100644 --- a/code-of-conduct.md +++ b/code-of-conduct.md @@ -1,3 +1,3 @@ -# Kubernetes Community Code of Conduct +#KubernetesCommunityCodeofConduct -Please refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/community/code-of-conduct.md) \ No newline at end of file +Pleaserefertoour[KubernetesCommunityCodeofConduct](https://git.k8s.io/community/code-of-conduct.md) \ No newline at end of file diff --git a/designs/README.md b/designs/README.md index 13750b3ca9d..e9bb320ee46 100644 --- a/designs/README.md +++ b/designs/README.md @@ -1,37 +1,37 @@ Designs ======= -These are design documents for changes to Kubebuilder (and -cross-repository changes for related projects, like controller-runtime and -controller-tools). They exist to help document the design processes that -go into writing Kubebuilder, but may not be up-to-date (more below). +ThesearedesigndocumentsforchangestoKubebuilder(and +cross-repositorychangesforrelatedprojects,likecontroller-runtimeand +controller-tools).Theyexisttohelpdocumentthedesignprocessesthat +gointowritingKubebuilder,butmaynotbeup-to-date(morebelow). -Not all changes to Kubebuilder need a design document -- only major ones. -Use your best judgement. +NotallchangestoKubebuilderneedadesigndocument--onlymajorones. +Useyourbestjudgement. -When submitting a design document, we encourage having written -a proof-of-concept, and it's perfectly acceptable to submit the -proof-of-concept PR simultaneously with the design document, as the -proof-of-concept process can help iron out wrinkles and can help with the -`Example` section of the template. +Whensubmittingadesigndocument,weencouragehavingwritten +aproof-of-concept,andit'sperfectlyacceptabletosubmitthe +proof-of-conceptPRsimultaneouslywiththedesigndocument,asthe +proof-of-conceptprocesscanhelpironoutwrinklesandcanhelpwiththe +`Example`sectionofthetemplate. -## Out-of-Date Designs +##Out-of-DateDesigns -**Kubebuilder documentation (the [book](https://book.kubebuilder.io) and -the [GoDoc](https://pkg.go.dev/sigs.k8s.io/controller-runtime?tab=doc)) should be -considered the canonical, update-to-date reference and architectural -documentation** for Kubebuilder. +**Kubebuilderdocumentation(the[book](https://book.kubebuilder.io)and +the[GoDoc](https://pkg.go.dev/sigs.k8s.io/controller-runtime?tab=doc))shouldbe +consideredthecanonical,update-to-datereferenceandarchitectural +documentation**forKubebuilder. -However, if you see an out-of-date design document, feel free to submit -a PR marking it as such, and add an addendum linking to issues documenting -why things changed. For example: +However,ifyouseeanout-of-datedesigndocument,feelfreetosubmit +aPRmarkingitassuch,andaddanaddendumlinkingtoissuesdocumenting +whythingschanged.Forexample: ```markdown -# Out of Date +#OutofDate -This change is out of date. It turns out curly braces a frustrating to -type, so we had to abandon functions entirely, and have users specify -custom functionality using strings of Common LISP instead. See #000 for -more information. +Thischangeisoutofdate.Itturnsoutcurlybracesafrustratingto +type,sowehadtoabandonfunctionsentirely,andhaveusersspecify +customfunctionalityusingstringsofCommonLISPinstead.See#000for +moreinformation. ``` diff --git a/designs/code-generate-image-plugin.md b/designs/code-generate-image-plugin.md index 719eba97eac..50466ffb815 100644 --- a/designs/code-generate-image-plugin.md +++ b/designs/code-generate-image-plugin.md @@ -1,300 +1,300 @@ -| Authors | Creation Date | Status | Extra | +|Authors|CreationDate|Status|Extra| |---------------|---------------|-------------|---| -| @camilamacedo86 | 2021-02-14 | Implemented | [deploy-image-plugin-v1-alpha](https://book.kubebuilder.io/plugins/deploy-image-plugin-v1-alpha.html) | +|@camilamacedo86|2021-02-14|Implemented|[deploy-image-plugin-v1-alpha](https://book.kubebuilder.io/plugins/deploy-image-plugin-v1-alpha.html)| -# New Plugin (`deploy-image.go.kubebuilder.io/v1beta1`) to generate code +#NewPlugin(`deploy-image.go.kubebuilder.io/v1beta1`)togeneratecode -## Summary +##Summary -This proposal defines a new plugin which allow users get the scaffold with the - required code to have a project that will deploy and manage an image on the cluster following the guidelines and what have been considered as good practices. - -## Motivation +Thisproposaldefinesanewpluginwhichallowusersgetthescaffoldwiththe +requiredcodetohaveaprojectthatwilldeployandmanageanimageontheclusterfollowingtheguidelinesandwhathavebeenconsideredasgoodpractices. -The biggest part of the Kubebuilder users looking for to create a project that will at the end only deploy an image. In this way, one of the mainly motivations of this proposal is to abstract the complexities to achieve this goal and still giving the possibility of users improve and customize their projects according to their requirements. +##Motivation -**Note:** This plugin will address requests that has been raised for a while and for many users in the community. Check [here](https://github.com/operator-framework/operator-sdk/pull/2158), for example, a request done in the past for the SDK project which is integrated with Kubebuidler to address the same need. +ThebiggestpartoftheKubebuilderuserslookingfortocreateaprojectthatwillattheendonlydeployanimage.Inthisway,oneofthemainlymotivationsofthisproposalistoabstractthecomplexitiestoachievethisgoalandstillgivingthepossibilityofusersimproveandcustomizetheirprojectsaccordingtotheirrequirements. -### Goals +**Note:**Thispluginwilladdressrequeststhathasbeenraisedforawhileandformanyusersinthecommunity.Check[here](https://github.com/operator-framework/operator-sdk/pull/2158),forexample,arequestdoneinthepastfortheSDKprojectwhichisintegratedwithKubebuidlertoaddressthesameneed. -- Add a new plugin to generate the code required to deploy and manage an image on the cluster -- Promote the best practices as give example of common implementations -- Make the process to develop operators projects easier and more agil. -- Give flexibility to the users and allow them to change the code according to their needs -- Provide examples of code implementations and of the most common features usage and reduce the learning curve - -### Non-Goals +###Goals -The idea of this proposal is provide a facility for the users. This plugin can be improved -in the future, however, this proposal just covers the basic requirements. In this way, is a non-goal -allow extra configurations such as; scaffold the project using webhooks and the controller covered by tests. +-Addanewplugintogeneratethecoderequiredtodeployandmanageanimageonthecluster +-Promotethebestpracticesasgiveexampleofcommonimplementations +-Maketheprocesstodevelopoperatorsprojectseasierandmoreagil. +-Giveflexibilitytotheusersandallowthemtochangethecodeaccordingtotheirneeds +-Provideexamplesofcodeimplementationsandofthemostcommonfeaturesusageandreducethelearningcurve -## Proposal +###Non-Goals -Add the new plugin code generate which will scaffold code implementation to deploy the image informed which would like such as; `kubebuilder create api --group=crew --version=v1 --image=myexample:0.0.1 --kind=App --plugins=deploy-image.go.kubebuilder.io/v1beta1` which will: +Theideaofthisproposalisprovideafacilityfortheusers.Thisplugincanbeimproved +inthefuture,however,thisproposaljustcoversthebasicrequirements.Inthisway,isanon-goal +allowextraconfigurationssuchas;scaffoldtheprojectusingwebhooksandthecontrollercoveredbytests. -- Add a code implementation which will do the Custom Resource reconciliation and create a Deployment resource for the `--image`; +##Proposal -- Add an EnvVar on the manager manifest (`config/manager/manager.yaml`) which will store the image informed and shows its possibility to users: +Addthenewplugincodegeneratewhichwillscaffoldcodeimplementationtodeploytheimageinformedwhichwouldlikesuchas;`kubebuildercreateapi--group=crew--version=v1--image=myexample:0.0.1--kind=App--plugins=deploy-image.go.kubebuilder.io/v1beta1`whichwill: + +-AddacodeimplementationwhichwilldotheCustomResourcereconciliationandcreateaDeploymentresourceforthe`--image`; + +-AddanEnvVaronthemanagermanifest(`config/manager/manager.yaml`)whichwillstoretheimageinformedandshowsitspossibilitytousers: ```yaml - .. - spec: - containers: - - name: manager - env: - - name: {{ resource}}-IMAGE - value: {{image:tag}} - image: controller:latest - ... +.. +spec: +containers: +-name:manager +env: +-name:{{resource}}-IMAGE +value:{{image:tag}} +image:controller:latest +... ``` -- Add a check into reconcile to ensure that the replicas of the deployment on cluster are equals the size defined in the CR: +-AddacheckintoreconciletoensurethatthereplicasofthedeploymentonclusterareequalsthesizedefinedintheCR: ```go - // Ensure the deployment size is the same as the spec - size := {{ resource }}.Spec.Size - if *found.Spec.Replicas != size { - found.Spec.Replicas = &size - err = r.Update(ctx, found) - if err != nil { - log.Error(err, "Failed to update Deployment", "Deployment.Namespace", found.Namespace, "Deployment.Name", found.Name) - return ctrl.Result{}, err - } - // Spec updated - return and requeue - return ctrl.Result{Requeue: true}, nil - } +//Ensurethedeploymentsizeisthesameasthespec +size:={{resource}}.Spec.Size +if*found.Spec.Replicas!=size{ +found.Spec.Replicas=&size +err=r.Update(ctx,found) +iferr!=nil{ +log.Error(err,"FailedtoupdateDeployment","Deployment.Namespace",found.Namespace,"Deployment.Name",found.Name) +returnctrl.Result{},err +} +//Specupdated-returnandrequeue +returnctrl.Result{Requeue:true},nil +} ``` -- Add the watch feature for the Deployment managed by the controller: +-AddthewatchfeaturefortheDeploymentmanagedbythecontroller: -```go -func (r *{{ resource }}Reconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&cachev1alpha1.{{ resource }}{}). - Owns(&appsv1.Deployment{}). - Complete(r) +```go +func(r*{{resource}}Reconciler)SetupWithManager(mgrctrl.Manager)error{ +returnctrl.NewControllerManagedBy(mgr). +For(&cachev1alpha1.{{resource}}{}). +Owns(&appsv1.Deployment{}). +Complete(r) } ``` -- Add the RBAC permissions required for the scenario such as: +-AddtheRBACpermissionsrequiredforthescenariosuchas: ```go -// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete ``` -- A status [conditions][conditions] to allow users check that if the deployment occurred successfully or its errors +-Astatus[conditions][conditions]toallowuserscheckthatifthedeploymentoccurredsuccessfullyoritserrors -- Add a [marker][markers] in the spec definition to demonstrate how to use OpenAPI schemas validation such as `+kubebuilder:validation:Minimum=1` +-Adda[marker][markers]inthespecdefinitiontodemonstratehowtouseOpenAPIschemasvalidationsuchas`+kubebuilder:validation:Minimum=1` -- Add the specs on the `_types.go` to generate the CRD/CR sample with default values for `ImagePullPolicy` (`Always`), `ContainerPort` (`80`) and the `Replicas Size` (`3`) +-Addthespecsonthe`_types.go`togeneratetheCRD/CRsamplewithdefaultvaluesfor`ImagePullPolicy`(`Always`),`ContainerPort`(`80`)andthe`ReplicasSize`(`3`) -- Add a finalizer implementation with TODO for the CR managed by the controller such as described in the SDK doc [Handle Cleanup on Deletion](https://sdk.operatorframework.io/docs/building-operators/golang/advanced-topics/#handle-cleanup-on-deletion) - -### User Stories +-AddafinalizerimplementationwithTODOfortheCRmanagedbythecontrollersuchasdescribedintheSDKdoc[HandleCleanuponDeletion](https://sdk.operatorframework.io/docs/building-operators/golang/advanced-topics/#handle-cleanup-on-deletion) -- I am as user, would like to use a command to scaffold my common need which is deploy an image of my application, so that I do not need to know exactly how to implement it +###UserStories -- I am as user, would like to have a good example code base which uses the common features, so that I can easily learn its concepts and have a good start point to address my needs. +-Iamasuser,wouldliketouseacommandtoscaffoldmycommonneedwhichisdeployanimageofmyapplication,sothatIdonotneedtoknowexactlyhowtoimplementit -- I am as maintainer, would like to have a good example to address the common questions, so that I can easily describe how to implement the projects and/or use the common features. - -### Implementation Details/Notes/Constraints +-Iamasuser,wouldliketohaveagoodexamplecodebasewhichusesthecommonfeatures,sothatIcaneasilylearnitsconceptsandhaveagoodstartpointtoaddressmyneeds. -**Example of the controller template** +-Iamasmaintainer,wouldliketohaveagoodexampletoaddressthecommonquestions,sothatIcaneasilydescribehowtoimplementtheprojectsand/orusethecommonfeatures. + +###ImplementationDetails/Notes/Constraints + +**Exampleofthecontrollertemplate** ```go -// +kubebuilder:rbac:groups=cache.example.com,resources={{ resource.plural }},verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=cache.example.com,resources={{ resource.plural }}/status,verbs=get;update;patch -// +kubebuilder:rbac:groups=cache.example.com,resources={{ resource.plural }}/finalizers,verbs=update -// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete - -func (r *{{ resource }}.Reconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { - ctx := context.Background() - log := r.Log.WithValues("{{ resource }}", req.NamespacedName) - - // Fetch the {{ resource }} instance - {{ resource }} := &{{ apiimportalias }}.{{ resource }}{} - err := r.Get(ctx, req.NamespacedName, {{ resource }}) - if err != nil { - if errors.IsNotFound(err) { - // Request object not found, could have been deleted after reconcile request. - // Owned objects are automatically garbage collected. For additional cleanup logic use finalizers. - // Return and don't requeue - log.Info("{{ resource }} resource not found. Ignoring since object must be deleted") - return ctrl.Result{}, nil - } - // Error reading the object - requeue the request. - log.Error(err, "Failed to get {{ resource }}") - return ctrl.Result{}, err - } - - // Check if the deployment already exists, if not create a new one - found := &appsv1.Deployment{} - err = r.Get(ctx, types.NamespacedName{Name: {{ resource }}.Name, Namespace: {{ resource }}.Namespace}, found) - if err != nil && errors.IsNotFound(err) { - // Define a new deployment - dep := r.deploymentFor{{ resource }}({{ resource }}) - log.Info("Creating a new Deployment", "Deployment.Namespace", dep.Namespace, "Deployment.Name", dep.Name) - err = r.Create(ctx, dep) - if err != nil { - log.Error(err, "Failed to create new Deployment", "Deployment.Namespace", dep.Namespace, "Deployment.Name", dep.Name) - return ctrl.Result{}, err - } - // Deployment created successfully - return and requeue - return ctrl.Result{Requeue: true}, nil - } else if err != nil { - log.Error(err, "Failed to get Deployment") - return ctrl.Result{}, err - } - - // Ensure the deployment size is the same as the spec - size := {{ resource }}.Spec.Size - if *found.Spec.Replicas != size { - found.Spec.Replicas = &size - err = r.Update(ctx, found) - if err != nil { - log.Error(err, "Failed to update Deployment", "Deployment.Namespace", found.Namespace, "Deployment.Name", found.Name) - return ctrl.Result{}, err - } - // Spec updated - return and requeue - return ctrl.Result{Requeue: true}, nil - } - - // TODO: add here code implementation to update/manage the status - - return ctrl.Result{}, nil +//+kubebuilder:rbac:groups=cache.example.com,resources={{resource.plural}},verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=cache.example.com,resources={{resource.plural}}/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=cache.example.com,resources={{resource.plural}}/finalizers,verbs=update +//+kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete + +func(r*{{resource}}.Reconciler)Reconcile(reqctrl.Request)(ctrl.Result,error){ +ctx:=context.Background() +log:=r.Log.WithValues("{{resource}}",req.NamespacedName) + +//Fetchthe{{resource}}instance +{{resource}}:=&{{apiimportalias}}.{{resource}}{} +err:=r.Get(ctx,req.NamespacedName,{{resource}}) +iferr!=nil{ +iferrors.IsNotFound(err){ +//Requestobjectnotfound,couldhavebeendeletedafterreconcilerequest. +//Ownedobjectsareautomaticallygarbagecollected.Foradditionalcleanuplogicusefinalizers. +//Returnanddon'trequeue +log.Info("{{resource}}resourcenotfound.Ignoringsinceobjectmustbedeleted") +returnctrl.Result{},nil +} +//Errorreadingtheobject-requeuetherequest. +log.Error(err,"Failedtoget{{resource}}") +returnctrl.Result{},err +} + +//Checkifthedeploymentalreadyexists,ifnotcreateanewone +found:=&appsv1.Deployment{} +err=r.Get(ctx,types.NamespacedName{Name:{{resource}}.Name,Namespace:{{resource}}.Namespace},found) +iferr!=nil&&errors.IsNotFound(err){ +//Defineanewdeployment +dep:=r.deploymentFor{{resource}}({{resource}}) +log.Info("CreatinganewDeployment","Deployment.Namespace",dep.Namespace,"Deployment.Name",dep.Name) +err=r.Create(ctx,dep) +iferr!=nil{ +log.Error(err,"FailedtocreatenewDeployment","Deployment.Namespace",dep.Namespace,"Deployment.Name",dep.Name) +returnctrl.Result{},err } +//Deploymentcreatedsuccessfully-returnandrequeue +returnctrl.Result{Requeue:true},nil +}elseiferr!=nil{ +log.Error(err,"FailedtogetDeployment") +returnctrl.Result{},err +} + +//Ensurethedeploymentsizeisthesameasthespec +size:={{resource}}.Spec.Size +if*found.Spec.Replicas!=size{ +found.Spec.Replicas=&size +err=r.Update(ctx,found) +iferr!=nil{ +log.Error(err,"FailedtoupdateDeployment","Deployment.Namespace",found.Namespace,"Deployment.Name",found.Name) +returnctrl.Result{},err +} +//Specupdated-returnandrequeue +returnctrl.Result{Requeue:true},nil +} + +//TODO:addherecodeimplementationtoupdate/managethestatus -// deploymentFor{{ resource }} returns a {{ resource }} Deployment object -func (r *{{ resource }}Reconciler) deploymentFor{{ resource }}(m *{{ apiimportalias }}.{{ resource }}) *appsv1.Deployment { - ls := labelsFor{{ resource }}(m.Name) - replicas := m.Spec.Size - - dep := &appsv1.Deployment{ - ObjectMeta: metav1.ObjectMeta{ - Name: m.Name, - Namespace: m.Namespace, - }, - Spec: appsv1.DeploymentSpec{ - Replicas: &replicas, - Selector: &metav1.LabelSelector{ - MatchLabels: ls, - }, - Template: corev1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: ls, - }, - Spec: corev1.PodSpec{ - Containers: []corev1.Container{{ - Image: imageFor{{ resource }}(m.Name), - Name: {{ resource }}, - ImagePullPolicy: {{ resource }}.Spec.ContainerImagePullPolicy, - Command: []string{"{{ resource }}"}, - Ports: []corev1.ContainerPort{{ - ContainerPort: {{ resource }}.Spec.ContainerPort, - Name: "{{ resource }}", - }}, - }}, - }, - }, - }, - } - // Set {{ resource }} instance as the owner and controller - ctrl.SetControllerReference(m, dep, r.Scheme) - return dep +returnctrl.Result{},nil } -// labelsFor{{ resource }} returns the labels for selecting the resources -// belonging to the given {{ resource }} CR name. -func labelsFor{{ resource }}(name string) map[string]string { - return map[string]string{"type": "{{ resource }}", "{{ resource }}_cr": name} +//deploymentFor{{resource}}returnsa{{resource}}Deploymentobject +func(r*{{resource}}Reconciler)deploymentFor{{resource}}(m*{{apiimportalias}}.{{resource}})*appsv1.Deployment{ +ls:=labelsFor{{resource}}(m.Name) +replicas:=m.Spec.Size + +dep:=&appsv1.Deployment{ +ObjectMeta:metav1.ObjectMeta{ +Name:m.Name, +Namespace:m.Namespace, +}, +Spec:appsv1.DeploymentSpec{ +Replicas:&replicas, +Selector:&metav1.LabelSelector{ +MatchLabels:ls, +}, +Template:corev1.PodTemplateSpec{ +ObjectMeta:metav1.ObjectMeta{ +Labels:ls, +}, +Spec:corev1.PodSpec{ +Containers:[]corev1.Container{{ +Image:imageFor{{resource}}(m.Name), +Name:{{resource}}, +ImagePullPolicy:{{resource}}.Spec.ContainerImagePullPolicy, +Command:[]string{"{{resource}}"}, +Ports:[]corev1.ContainerPort{{ +ContainerPort:{{resource}}.Spec.ContainerPort, +Name:"{{resource}}", +}}, +}}, +}, +}, +}, +} +//Set{{resource}}instanceastheownerandcontroller +ctrl.SetControllerReference(m,dep,r.Scheme) +returndep } -// imageFor{{ resource }} returns the image for the resources -// belonging to the given {{ resource }} CR name. -func imageFor{{ resource }}(name string) string { - // TODO: this method will return the value of the envvar create to store the image:tag informed +//labelsFor{{resource}}returnsthelabelsforselectingtheresources +//belongingtothegiven{{resource}}CRname. +funclabelsFor{{resource}}(namestring)map[string]string{ +returnmap[string]string{"type":"{{resource}}","{{resource}}_cr":name} } -func (r *{{ resource }}Reconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&cachev1alpha1.{{ resource }}{}). - Owns(&appsv1.Deployment{}). - Complete(r) +//imageFor{{resource}}returnstheimagefortheresources +//belongingtothegiven{{resource}}CRname. +funcimageFor{{resource}}(namestring)string{ +//TODO:thismethodwillreturnthevalueoftheenvvarcreatetostoretheimage:taginformed } -``` +func(r*{{resource}}Reconciler)SetupWithManager(mgrctrl.Manager)error{ +returnctrl.NewControllerManagedBy(mgr). +For(&cachev1alpha1.{{resource}}{}). +Owns(&appsv1.Deployment{}). +Complete(r) +} -**Example of the spec for the _types.go template** +``` + +**Exampleofthespecforthe_types.gotemplate** ```go -// {{ resource }}Spec defines the desired state of {{ resource }} -type {{ resource }}Spec struct { - // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - // Important: Run "make" to regenerate code after modifying this file +//{{resource}}Specdefinesthedesiredstateof{{resource}} +type{{resource}}Specstruct{ +//INSERTADDITIONALSPECFIELDS-desiredstateofcluster +//Important:Run"make"toregeneratecodeaftermodifyingthisfile - // +kubebuilder:validation:Minimum=1 - // Size defines the number of {{ resource }} instances - Size int32 `json:"size,omitempty"` +//+kubebuilder:validation:Minimum=1 +//Sizedefinesthenumberof{{resource}}instances +Sizeint32`json:"size,omitempty"` - // ImagePullPolicy defines the policy to pull the container images - ImagePullPolicy string `json:"image-pull-policy,omitempty"` +//ImagePullPolicydefinesthepolicytopullthecontainerimages +ImagePullPolicystring`json:"image-pull-policy,omitempty"` - // ContainerPort specifies the port which will be used by the image container - ContainerPort int `json:"container-port,omitempty"` +//ContainerPortspecifiestheportwhichwillbeusedbytheimagecontainer +ContainerPortint`json:"container-port,omitempty"` } ``` -## Design Details +##DesignDetails -### Test Plan +###TestPlan -To ensure this implementation a new project example should be generated in the [testdata](../testdata/) directory of the project. See the [test/testadata/generate.sh](../test/testadata/generate.sh). Also, we should use this scaffold in the [integration tests](../test/e2e/) to ensure that the data scaffolded with works on the cluster as expected. +Toensurethisimplementationanewprojectexampleshouldbegeneratedinthe[testdata](../testdata/)directoryoftheproject.Seethe[test/testadata/generate.sh](../test/testadata/generate.sh).Also,weshouldusethisscaffoldinthe[integrationtests](../test/e2e/)toensurethatthedatascaffoldedwithworksontheclusterasexpected. -### Graduation Criteria +###GraduationCriteria -- The new plugin will only be support `project-version=3` -- The attribute image with the value informed should be added to the resources model in the PROJECT file to let the tool know that the Resource get done with the common basic code implementation: +-Thenewpluginwillonlybesupport`project-version=3` +-TheattributeimagewiththevalueinformedshouldbeaddedtotheresourcesmodelinthePROJECTfiletoletthetoolknowthattheResourcegetdonewiththecommonbasiccodeimplementation: ```yaml plugins: - deploy-image.go.kubebuilder.io/v1beta1: - resources: - - domain: example.io - group: crew - kind: Captain - version: v1 - image: "/: -``` +deploy-image.go.kubebuilder.io/v1beta1: +resources: +-domain:example.io +group:crew +kind:Captain +version:v1 +image:"/: +``` -For further information check the definition agreement register in the comment https://github.com/kubernetes-sigs/kubebuilder/issues/1941#issuecomment-778649947. +Forfurtherinformationcheckthedefinitionagreementregisterinthecommenthttps://github.com/kubernetes-sigs/kubebuilder/issues/1941#issuecomment-778649947. -## Open Questions +##OpenQuestions -1. Should we allow to scaffold the code for an API that is already created for the project? -No, at least in the first moment to keep the simplicity. +1.ShouldweallowtoscaffoldthecodeforanAPIthatisalreadycreatedfortheproject? +No,atleastinthefirstmomenttokeepthesimplicity. -2. Should we support StatefulSet and Deployments? -The idea is we start it by using a Deployment. However, we can improve the feature in follow-ups to support more default types of scaffolds which could be like `kubebuilder create api --group=crew --version=v1 --image=myexample:0.0.1 --kind=App --plugins=deploy-image.go.kubebuilder.io/v1beta1 --type=[deployment|statefulset|webhook]` +2.ShouldwesupportStatefulSetandDeployments? +TheideaiswestartitbyusingaDeployment.However,wecanimprovethefeatureinfollow-upstosupportmoredefaulttypesofscaffoldswhichcouldbelike`kubebuildercreateapi--group=crew--version=v1--image=myexample:0.0.1--kind=App--plugins=deploy-image.go.kubebuilder.io/v1beta1--type=[deployment|statefulset|webhook]` -3. Could this feature be useful to other languages or is it just valid to Go based operators? +3.CouldthisfeaturebeusefultootherlanguagesorisitjustvalidtoGobasedoperators? -This plugin would is reponsable to scaffold content and files for Go-based operators. In a future, if other language-based operators starts to be supported (either officially or by the community) this plugin could be used as reference to create an equivalent one for their languages. Therefore, it should probably not to be a `subdomain` of `go.kubebuilder.io.` +ThispluginwouldisreponsabletoscaffoldcontentandfilesforGo-basedoperators.Inafuture,ifotherlanguage-basedoperatorsstartstobesupported(eitherofficiallyorbythecommunity)thisplugincouldbeusedasreferencetocreateanequivalentonefortheirlanguages.Therefore,itshouldprobablynottobea`subdomain`of`go.kubebuilder.io.` -For its integration with SDK, it might be valid for the Ansible-based operators where a new `playbook/role` could be generated as well. However, for example, for the Helm plugin it might to be useless. E.g `deploy-image.ansible.sdk.operatorframework.io/v1beta1` +ForitsintegrationwithSDK,itmightbevalidfortheAnsible-basedoperatorswhereanew`playbook/role`couldbegeneratedaswell.However,forexample,fortheHelmpluginitmighttobeuseless.E.g`deploy-image.ansible.sdk.operatorframework.io/v1beta1` -4. Should we consider create a separate repo for plugins? +4.Shouldweconsidercreateaseparaterepoforplugins? -In the long term yes. However, see that currently, Kubebuilder has not too many plugins yet. And then, and the preliminary support for plugins did not indeed release. For more info see the [Extensible CLI and Scaffolding Plugins][plugins-phase1-design-doc]. +Inthelongtermyes.However,seethatcurrently,Kubebuilderhasnottoomanypluginsyet.Andthen,andthepreliminarysupportforpluginsdidnotindeedrelease.Formoreinfoseethe[ExtensibleCLIandScaffoldingPlugins][plugins-phase1-design-doc]. -In this way, at this moment, it shows to be a little Premature Optimization. Note that the issue [#2016](https://github.com/kubernetes-sigs/kubebuilder/issues/1378) will check the possibility of the plugins be as separate binaries that can be discovered by the Kubebuilder CLI binary via user-specified plugin file paths. Then, the discussion over the best approach to dealing with many plugins and if they should or not leave in the Kubebuilder repository would be better addressed after that. +Inthisway,atthismoment,itshowstobealittlePrematureOptimization.Notethattheissue[#2016](https://github.com/kubernetes-sigs/kubebuilder/issues/1378)willcheckthepossibilityofthepluginsbeasseparatebinariesthatcanbediscoveredbytheKubebuilderCLIbinaryviauser-specifiedpluginfilepaths.Then,thediscussionoverthebestapproachtodealingwithmanypluginsandiftheyshouldornotleaveintheKubebuilderrepositorywouldbebetteraddressedafterthat. -5. Is Kubebuilder prepared to receive this implementation already? +5.IsKubebuilderpreparedtoreceivethisimplementationalready? -The [Extensible CLI and Scaffolding Plugins - Phase 1.5](extensible-cli-and-scaffolding-plugins-phase-1-5.md) and the issue #1941 requires to be implemented before this proposal. Also, to have a better idea over the proposed solutions made so for the Plugin Ecosystem see the meta issue [#2016](https://github.com/kubernetes-sigs/kubebuilder/issues/2016) +The[ExtensibleCLIandScaffoldingPlugins-Phase1.5](extensible-cli-and-scaffolding-plugins-phase-1-5.md)andtheissue#1941requirestobeimplementedbeforethisproposal.Also,tohaveabetterideaovertheproposedsolutionsmadesoforthePluginEcosystemseethemetaissue[#2016](https://github.com/kubernetes-sigs/kubebuilder/issues/2016) -[markers]: ../docs/book/src/reference/markers.md -[conditions]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties -[plugins-phase1-design-doc]: https://github.com/kubernetes-sigs/kubebuilder/blob/master/designs/extensible-cli-and-scaffolding-plugins-phase-1.md \ No newline at end of file +[markers]:../docs/book/src/reference/markers.md +[conditions]:https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties +[plugins-phase1-design-doc]:https://github.com/kubernetes-sigs/kubebuilder/blob/master/designs/extensible-cli-and-scaffolding-plugins-phase-1.md \ No newline at end of file diff --git a/designs/crd_version_conversion.md b/designs/crd_version_conversion.md index e5358a0460d..4ffba166a19 100644 --- a/designs/crd_version_conversion.md +++ b/designs/crd_version_conversion.md @@ -1,269 +1,269 @@ -| Authors | Creation Date | Status | Extra | +|Authors|CreationDate|Status|Extra| |---------------|---------------|-------------|-------| -| @droot | 01/30/2019| implementable | - | +|@droot|01/30/2019|implementable|-| -# API Versioning in Kubebuilder +#APIVersioninginKubebuilder -This document describes high level design and workflow for supporting multiple versions in an API built using Kubebuilder. Multi-version support was added as an alpha feature in kubernetes project in 1.13 release. Here are links to some recommended reading material. +ThisdocumentdescribeshighleveldesignandworkflowforsupportingmultipleversionsinanAPIbuiltusingKubebuilder.Multi-versionsupportwasaddedasanalphafeatureinkubernetesprojectin1.13release.Herearelinkstosomerecommendedreadingmaterial. -* [CRD version Conversion Design Doc](https://github.com/kubernetes/community/blob/3f8bf88a06a114b3984417d6867bb16506c9c71e/contributors/design-proposals/api-machinery/customresource-conversion-webhook.md) +*[CRDversionConversionDesignDoc](https://github.com/kubernetes/community/blob/3f8bf88a06a114b3984417d6867bb16506c9c71e/contributors/design-proposals/api-machinery/customresource-conversion-webhook.md) -* [CRD Webhook Conversion API changes PR](https://github.com/kubernetes/kubernetes/pull/67795/files) +*[CRDWebhookConversionAPIchangesPR](https://github.com/kubernetes/kubernetes/pull/67795/files) -* [CRD Webhook Conversion PR](https://github.com/kubernetes/kubernetes/pull/67006) +*[CRDWebhookConversionPR](https://github.com/kubernetes/kubernetes/pull/67006) -* [Kubecon talk](https://www.youtube.com/watch?v=HsYtMvvzDyI&t=0s&index=100&list=PLj6h78yzYM2PZf9eA7bhWnIh_mK1vyOfU) +*[Kubecontalk](https://www.youtube.com/watch?v=HsYtMvvzDyI&t=0s&index=100&list=PLj6h78yzYM2PZf9eA7bhWnIh_mK1vyOfU) -* [CRD version conversion POC](https://github.com/droot/crd-conversion-example) +*[CRDversionconversionPOC](https://github.com/droot/crd-conversion-example) -# Design +#Design -## Hub and Spoke +##HubandSpoke -The basic concept is that all versions of an object share the storage. So say if you have versions v1, v2 and v3 of a Kind Toy, kubernetes will use one of the versions to persist the object in stable storage i.e. Etcd. User can specify the version to be used for storage in the Custom Resource definition for that API. +Thebasicconceptisthatallversionsofanobjectsharethestorage.Sosayifyouhaveversionsv1,v2andv3ofaKindToy,kuberneteswilluseoneoftheversionstopersisttheobjectinstablestoragei.e.Etcd.UsercanspecifytheversiontobeusedforstorageintheCustomResourcedefinitionforthatAPI. -One can think storage version as the hub and other versions as spoke to visualize the relationship between storage and other versions (as shown below in the diagram). The key thing to note is that conversion between storage and other version should be lossless (round trippable). As shown in the diagram below, v3 is the storage/hub version and v1, v2 and v4 are spoke version. The document uses storage version and hub interchangeably. +Onecanthinkstorageversionasthehubandotherversionsasspoketovisualizetherelationshipbetweenstorageandotherversions(asshownbelowinthediagram).Thekeythingtonoteisthatconversionbetweenstorageandotherversionshouldbelossless(roundtrippable).Asshowninthediagrambelow,v3isthestorage/hubversionandv1,v2andv4arespokeversion.Thedocumentusesstorageversionandhubinterchangeably. -![hub and spoke version diagram][version-diagram] +![hubandspokeversiondiagram][version-diagram] -So if each spoke version (v1, v2 and v4 in this case) defines conversion function from/to the hub version, then conversion function between the spoke versions (v1, v2, v4) can be derived. For example, for converting an object from v1 to v4, we can convert v1 to v3 (the hub version) and v3 to v4. +Soifeachspokeversion(v1,v2andv4inthiscase)definesconversionfunctionfrom/tothehubversion,thenconversionfunctionbetweenthespokeversions(v1,v2,v4)canbederived.Forexample,forconvertinganobjectfromv1tov4,wecanconvertv1tov3(thehubversion)andv3tov4. -We will introduce two interfaces in controller-runtime to express the above relationship. +Wewillintroducetwointerfacesincontroller-runtimetoexpresstheaboverelationship. ```Go -// Hub defines capability to indicate whether a versioned type is a Hub or not. +//HubdefinescapabilitytoindicatewhetheraversionedtypeisaHubornot. -type Hub interface { - runtime.Object - Hub() +typeHubinterface{ +runtime.Object +Hub() } -// A versioned type is convertible if it can be converted to/from a hub type. +//Aversionedtypeisconvertibleifitcanbeconvertedto/fromahubtype. -type Convertible interface { - runtime.Object - ConvertTo(dst Hub) error - ConvertFrom(src Hub) error +typeConvertibleinterface{ +runtime.Object +ConvertTo(dstHub)error +ConvertFrom(srcHub)error } ``` -A spoke type needs to implement Convertible interface. Kubebuilder can scaffold the skeleton for a type when it is created. An example of Convertible implementation: +AspoketypeneedstoimplementConvertibleinterface.Kubebuildercanscaffoldtheskeletonforatypewhenitiscreated.AnexampleofConvertibleimplementation: ```Go -package v1 - -func (ej *ExternalJob) ConvertTo(dst conversion.Hub) error { - switch t := dst.(type) { - case *v3.ExternalJob: - jobv3 := dst.(*v3.ExternalJob) - jobv3.ObjectMeta = ej.ObjectMeta - // conversion implementation - // - return nil - default: - return fmt.Errorf("unsupported type %v", t) - } +packagev1 + +func(ej*ExternalJob)ConvertTo(dstconversion.Hub)error{ +switcht:=dst.(type){ +case*v3.ExternalJob: +jobv3:=dst.(*v3.ExternalJob) +jobv3.ObjectMeta=ej.ObjectMeta +//conversionimplementation +// +returnnil +default: +returnfmt.Errorf("unsupportedtype%v",t) +} } -func (ej *ExternalJob) ConvertFrom(src conversion.Hub) error { - switch t := src.(type) { - case *v3.ExternalJob: - jobv3 := src.(*v3.ExternalJob) - ej.ObjectMeta = jobv3.ObjectMeta - // conversion implementation - return nil - default: - return fmt.Errorf("unsupported type %v", t) - } +func(ej*ExternalJob)ConvertFrom(srcconversion.Hub)error{ +switcht:=src.(type){ +case*v3.ExternalJob: +jobv3:=src.(*v3.ExternalJob) +ej.ObjectMeta=jobv3.ObjectMeta +//conversionimplementation +returnnil +default: +returnfmt.Errorf("unsupportedtype%v",t) +} } ``` -The storage type v3 needs to implement the Hub interface: +Thestoragetypev3needstoimplementtheHubinterface: ```Go -package v3 -func (ej *ExternalJob) Hub() {} +packagev3 +func(ej*ExternalJob)Hub(){} ``` -## Conversion Webhook Handler +##ConversionWebhookHandler -Controller-runtime will implement a default conversion handler that can handle conversion requests for any API type. Code snippets below captures high level implementation details of the handler. This handler will be registered with the webhook server by default. +Controller-runtimewillimplementadefaultconversionhandlerthatcanhandleconversionrequestsforanyAPItype.Codesnippetsbelowcaptureshighlevelimplementationdetailsofthehandler.Thishandlerwillberegisteredwiththewebhookserverbydefault. ```Go -type conversionHandler struct { - // scheme which has Go types for the APIs are registered. This will be injected by controller manager. - Scheme runtime.Scheme - // decoder which will be injected by the webhook server - // decoder knows how to decode a conversion request and API objects. - Decoder decoder.Decoder +typeconversionHandlerstruct{ +//schemewhichhasGotypesfortheAPIsareregistered.Thiswillbeinjectedbycontrollermanager. +Schemeruntime.Scheme +//decoderwhichwillbeinjectedbythewebhookserver +//decoderknowshowtodecodeaconversionrequestandAPIobjects. +Decoderdecoder.Decoder +} + +//Thisisthedefaulthandlerwhichwillbemountedonthewebhookserver. +func(ch*conversionHandler)Handle(r*http.Request,whttp.Response){ +//decodetherequesttoconverReviewrequestobject +convertReq:=ch.Decode(r.Body) +for_,obj:=rangeconvertReq.Objects{ +//decodetheincomingobject +src,gvk,_:=ch.Decoder.Decode(obj.raw) + +//gettargetobjectinstanceforconvertReq.DesiredAPIVersionandgvk.Kind +dst,_:=getTargetObject(convertReq.DesiredAPIVersion,gvk.Kind) + +//thisiswhereconversionbetweenobjectshappens + +ch.ConvertObject(src,dst) + +//appenddsttoconvertedobjectlist } -// This is the default handler which will be mounted on the webhook server. -func (ch *conversionHandler) Handle(r *http.Request, w http.Response) { - // decode the request to converReview request object - convertReq := ch.Decode(r.Body) - for _, obj := range convertReq.Objects { - // decode the incoming object - src, gvk, _ := ch.Decoder.Decode(obj.raw) +//createaconversionresponsewithconvertedobjects +} + +func(ch*conversionHandler)convertObject(src,dstruntime.Object)error{ +//checkifsrcanddstareofsametype,thenmaybereturnwitherrorbecauseAPIserverwillneverinvokethishandlerforsameversion. +srcIsHub,dstIsHub:=isHub(src),isHub(dst) +srcIsConvertible,dstIsConvertible:=isConvertible(src),isConvertable(dst) +ifsrcIsHub{ +ifdstIsConvertible{ +returndst.(conversion.Convertable).ConvertFrom(src.(conversion.Hub)) +}else{ +//thisiserrorcase,thiscanbeflaggedatsetuptime? +returnfmt.Errorf("%Tisnotconvertibleto",src) +} +} - // get target object instance for convertReq.DesiredAPIVersion and gvk.Kind - dst, _ := getTargetObject(convertReq.DesiredAPIVersion, gvk.Kind) +ifdstIsHub{ +ifsrcIsConvertible{ +returnsrc.(conversion.Convertable).ConvertTo(dst.(conversion.Hub)) +}else{ +//thisiserrorcase. +returnfmt.Errorf("%Tisnotconvertible",src) +} +} - // this is where conversion between objects happens +//neithersrcordstareHub,meansbothofthemarespoke,soletsgetthehub +//versiontype. - ch.ConvertObject(src, dst) +hub,err:=getHub(scheme,src) +iferr!=nil{ +returnerr +} - // append dst to converted object list +//shallwegetHubfordsttypeaswellandensurehubsaresame? +//srcanddstneedstobeconvertibleforittowork +if!srcIsConvertable||!dstIsConvertable{ +returnfmt.Errorf("%Tand%Tneedstobebothconvertible",src,dst) } - // create a conversion response with converted objects +err=src.(conversion.Convertible).ConvertTo(hub) +iferr!=nil{ +returnfmt.Errorf("%Tfailedtoconverttohubversion%T:%v",src,hub,err) } -func (ch *conversionHandler) convertObject(src, dst runtime.Object) error { - // check if src and dst are of same type, then may be return with error because API server will never invoke this handler for same version. - srcIsHub, dstIsHub := isHub(src), isHub(dst) - srcIsConvertible, dstIsConvertible := isConvertible(src), isConvertable(dst) - if srcIsHub { - if dstIsConvertible { - return dst.(conversion.Convertable).ConvertFrom(src.(conversion.Hub)) - } else { - // this is error case, this can be flagged at setup time ? - return fmt.Errorf("%T is not convertible to", src) - } - } - - if dstIsHub { - if srcIsConvertible { - return src.(conversion.Convertable).ConvertTo(dst.(conversion.Hub)) - } else { - // this is error case. - return fmt.Errorf("%T is not convertible", src) - } - } - - // neither src or dst are Hub, means both of them are spoke, so lets get the hub - // version type. - - hub, err := getHub(scheme, src) - if err != nil { - return err - } - - // shall we get Hub for dst type as well and ensure hubs are same ? - // src and dst needs to be convertible for it to work - if !srcIsConvertable || !dstIsConvertable { - return fmt.Errorf("%T and %T needs to be both convertible", src, dst) - } - - err = src.(conversion.Convertible).ConvertTo(hub) - if err != nil { - return fmt.Errorf("%T failed to convert to hub version %T : %v", src, hub, err) - } - - err = dst.(conversion.Convertible).ConvertFrom(hub) - if err != nil { - return fmt.Errorf("%T failed to convert from hub version %T : %v", dst, hub, err) - } - return nil +err=dst.(conversion.Convertible).ConvertFrom(hub) +iferr!=nil{ +returnfmt.Errorf("%Tfailedtoconvertfromhubversion%T:%v",dst,hub,err) +} +returnnil } ``` -Handler Registration flow will perform following at the startup: +HandlerRegistrationflowwillperformfollowingatthestartup: -* For APIs with hub defined, it can examine if spoke versions implement convertible or not and can abort with error. +*ForAPIswithhubdefined,itcanexamineifspokeversionsimplementconvertibleornotandcanabortwitherror. -* It will also be nice if we can detect an API with multiple versions but with no hub defined, but that requires distinguishing between APIs defined in the project vs external. +*ItwillalsobeniceifwecandetectanAPIwithmultipleversionsbutwithnohubdefined,butthatrequiresdistinguishingbetweenAPIsdefinedintheprojectvsexternal. -# CRD Generation +#CRDGeneration -The tool that generates the CRD manifests lives under controller-tools repo. Currently it generates the manifests for each discovered under ‘pkg/…’ directory in the project by examining the comments (aka annotations) in Go source files. Following annotations will be added to support multi version: +ThetoolthatgeneratestheCRDmanifestslivesundercontroller-toolsrepo.Currentlyitgeneratesthemanifestsforeachdiscoveredunder‘pkg/…’directoryintheprojectbyexaminingthecomments(akaannotations)inGosourcefiles.Followingannotationswillbeaddedtosupportmultiversion: -## Storage/Serve annotations: +##Storage/Serveannotations: -The resource annotation will be extended to indicate storage/serve attributes as shown below. +Theresourceannotationwillbeextendedtoindicatestorage/serveattributesasshownbelow. ```Go -// ... -// +kubebuilder:resource:storage=true,serve=true -// … -type APIName struct { - ... +//... +//+kubebuilder:resource:storage=true,serve=true +//… +typeAPINamestruct{ +... } ``` -The default value of *serve* attribute is true. The default value of *storage* attribute will be *true* for single version and *false* for multiple versions to ensure backward compatibility. +Thedefaultvalueof*serve*attributeistrue.Thedefaultvalueof*storage*attributewillbe*true*forsingleversionand*false*formultipleversionstoensurebackwardcompatibility. -CRD generation will be extended to support the following: +CRDgenerationwillbeextendedtosupportthefollowing: -* If multiple versions are detected for an API: +*IfmultipleversionsaredetectedforanAPI: - * Ensure only one version is marked as storage version. Assume default value of *storage* to be *false* for this case. +*Ensureonlyoneversionismarkedasstorageversion.Assumedefaultvalueof*storage*tobe*false*forthiscase. - * Ensure version specific fields such as *OpenAPIValidationSchema, SubResources and AdditionalPrinterColumn* are added per version and omitted from the top level CRD definition. +*Ensureversionspecificfieldssuchas*OpenAPIValidationSchema,SubResourcesandAdditionalPrinterColumn*areaddedperversionandomittedfromthetoplevelCRDdefinition. -* In case of single version, +*Incaseofsingleversion, - * Do not use version specific field in CRD spec because users are most likely running with k8s version < 1.13 which doesn’t support version specific specs for *OpenAPIValidationSchema, SubResources and AdditionalPrinterColumn. *This is critical to maintain backward compatibility. +*DonotuseversionspecificfieldinCRDspecbecauseusersaremostlikelyrunningwithk8sversion<1.13whichdoesn’tsupportversionspecificspecsfor*OpenAPIValidationSchema,SubResourcesandAdditionalPrinterColumn.*Thisiscriticaltomaintainbackwardcompatibility. - * Assume default value for storage attribute to be *true* for this case. +*Assumedefaultvalueforstorageattributetobe*true*forthiscase. -The above two requirements will require CRD generation logic to be divided in two phases. In first phase, parse and store CRD information in an internal structure for all versions and then generate the CRD manifest on the basis of multi-version/single-version scenario. +TheabovetworequirementswillrequireCRDgenerationlogictobedividedintwophases.Infirstphase,parseandstoreCRDinformationinaninternalstructureforallversionsandthengeneratetheCRDmanifestonthebasisofmulti-version/single-versionscenario. -## Conversion Webhook annotations: +##ConversionWebhookannotations: -Webhook annotations will be extended to support conversion webhook fields. +Webhookannotationswillbeextendedtosupportconversionwebhookfields. ```Go -// ... -// +kubebuilder:webhook:conversion:.... -// ... +//... +//+kubebuilder:webhook:conversion:.... +//... ``` -These annotations would be placed just above the API type definition to associate conversion webhook with an API type. +TheseannotationswouldbeplacedjustabovetheAPItypedefinitiontoassociateconversionwebhookwithanAPItype. -The exact syntax for annotation is yet to be defined, but goal is CRD generation tool to be able to extract information from these annotation to populate the `CustomResourceConversion` struct in CRD definition. The CA bits for webhook configuration will be populated by using annotations on the CRD as per the [design](https://docs.google.com/document/d/1ipTvFBRoe7fuDiz27Csm5Zb6rH0z6LJTuKM8xY3jaUg/edit?ts=5c49094e#heading=h.u7ei2s2van5b). +Theexactsyntaxforannotationisyettobedefined,butgoalisCRDgenerationtooltobeabletoextractinformationfromtheseannotationtopopulatethe`CustomResourceConversion`structinCRDdefinition.TheCAbitsforwebhookconfigurationwillbepopulatedbyusingannotationsontheCRDasperthe[design](https://docs.google.com/document/d/1ipTvFBRoe7fuDiz27Csm5Zb6rH0z6LJTuKM8xY3jaUg/edit?ts=5c49094e#heading=h.u7ei2s2van5b). -# Kubebuilder CLI: +#KubebuilderCLI: -kubebuilder create api --group g1 --version v2 --Kind k1 [--storage] +kubebuildercreateapi--groupg1--versionv2--Kindk1[--storage] -Fields marked in yellow are proposed new fields to the command and reasoning is stated below. +Fieldsmarkedinyellowareproposednewfieldstothecommandandreasoningisstatedbelow. -* *--storage* flag gives an option to mark a version as storage/hub version. +**--storage*flaggivesanoptiontomarkaversionasstorage/hubversion. -Generally users have one controller per group/kind, we will avoid scaffolding code for controller if we detect that a controller already exists for an API group/kind. +Generallyusershaveonecontrollerpergroup/kind,wewillavoidscaffoldingcodeforcontrollerifwedetectthatacontrolleralreadyexistsforanAPIgroup/kind. -# TODO: +#TODO: -## There is more exploration/work is required in the following areas related to API versioning: +##Thereismoreexploration/workisrequiredinthefollowingareasrelatedtoAPIversioning: -* Making it easy to write the conversion function itself. +*Makingiteasytowritetheconversionfunctionitself. -* Making it easy to generate tests for conversion functions using fuzzer. +*Makingiteasytogeneratetestsforconversionfunctionsusingfuzzer. -* Best practices around rolling out different versions of the API +*BestpracticesaroundrollingoutdifferentversionsoftheAPI -Version History +VersionHistory - - - - - - - - + + + + + + + - - - - - - - + + + + + + +
VersionUpdated onDescription
Draft01/30/2019 +
VersionUpdatedonDescription
Draft01/30/2019 Initial version
1.002/27/2019Updated the design as per POC implementation
Initialversion
1.002/27/2019UpdatedthedesignasperPOCimplementation
-[version-diaiagram]: assets/version_diagram.png +[version-diaiagram]:assets/version_diagram.png diff --git a/designs/extensible-cli-and-scaffolding-plugins-phase-1-5.md b/designs/extensible-cli-and-scaffolding-plugins-phase-1-5.md index 463cecf3848..22207e1c234 100644 --- a/designs/extensible-cli-and-scaffolding-plugins-phase-1-5.md +++ b/designs/extensible-cli-and-scaffolding-plugins-phase-1-5.md @@ -1,339 +1,339 @@ -| Authors | Creation Date | Status | Extra | +|Authors|CreationDate|Status|Extra| |---------------|---------------|-------------|-----------------------------------------------------------------| -| @adirio | Mar 9, 2021 | Implemented | [Plugins doc](https://book.kubebuilder.io/plugins/plugins.html) | - -# Extensible CLI and Scaffolding Plugins - Phase 1.5 - -Continuation of [Extensible CLI and Scaffolding Plugins](./extensible-cli-and-scaffolding-plugins-phase-1.md). - -## Goal - -The goal of this phase is to achieve one of the goals proposed for Phase 2: chaining plugins. -Phase 2 includes several other challenging goals, but being able to chain plugins will be beneficial -for third-party developers that are using kubebuilder as a library. - -The other main goal of phase 2, discovering and using external plugins, is out of the scope of this phase, -and will be tackled when phase 2 is implemented. - -## Table of contents -- [Goal](#goal) -- [Motivation](#motivation) -- [Proposal](#proposal) -- [Implementation](#implementation) - -## Motivation - -There are several cases of plugins that want to maintain most of the go plugin functionality and add -certain features on top of it, both inside and outside kubebuilder repository: -- [Addon pattern](../plugins/addon) -- [Operator SDK](https://github.com/operator-framework/operator-sdk/tree/master/internal/plugins/golang) - -This behavior fits perfectly under Phase 1.5, where plugins could be chained. However, as this feature is -not available, the adopted temporal solution is to wrap the base go plugin and perform additional actions -after its `Run` method has been executed. This solution faces several issues: - -- Wrapper plugins are unable to access the data of the wrapped plugins, as they weren't designed for this - purpose, and therefore, most of its internal data is non-exported. An example of this inaccessible data - would be the `Resource` objects created inside the `create api` and `create webhook` commands. -- Wrapper plugins are dependent on their wrapped plugins, and therefore can't be used for other plugins. -- Under the hood, subcommands implement a second hidden interface: `RunOptions`, which further accentuates - these issues. - -Plugin chaining solves the aforementioned problems but the current plugin API, and more specifically the -`Subcommand` interface, does not support plugin chaining. - -- The `RunOptions` interface implemented under the hood is not part of the plugin API, and therefore - the cli is not able to run post-scaffold logic (implemented in `RunOptions.PostScaffold` method) after - all the plugins have scaffolded their part. -- `Resource`-related commands can't bind flags like `--group`, `--version` or `--kind` in each plugin, - it must be created outside the plugins and then injected into them similar to the approach followed - currently for `Config` objects. - -## Proposal - -Design a Plugin API that combines the current [`Subcommand`](../pkg/plugin/interfaces.go) and -[`RunOptions`](../pkg/plugins/internal/cmdutil/cmdutil.go) interfaces and enables plugin-chaining. -The new `Subcommand` hooks can be split in two different categories: -- Initialization hooks -- Execution hooks - -Initialization hooks are run during the dynamic creation of the CLI, which means that they are able to -modify the CLI, e.g. providing descriptions and examples for subcommands or binding flags. -Execution hooks are run after the CLI is created, and therefore cannot modify the CLI. On the other hand, -as they are run during the CLI execution, they have access to user-provided flag values, project configuration, -the new API resource or the filesystem abstraction, as opposed to the initialization hooks. - -Additionally, some of these hooks may be optional, in which case a non-implemented hook will be skipped -when it should be called and consider it succeeded. This also allows to create some hooks specific for -a certain subcommand call (e.g.: `Resource`-related hooks for the `edit` subcommand are not needed). - -Different ordering guarantees can be considered: -- Hook order guarantee: a hook for a plugin will be called after its previous hooks succeeded. -- Steps order guarantee: hooks will be called when all plugins have finished the previous hook. -- Plugin order guarantee: same hook for each plugin will be called in the order specified - by the plugin position at the plugin chain. - -All of the hooks will offer plugin order guarantee, as they all modify/update some item so the order -of plugins is important. Execution hooks need to guarantee step order, as the items that are being modified -in each step (config, resource, and filesystem) are also needed in the following steps. This is not true for -initialization hooks that modify items (metadata and flagset) that are only used in their own methods, -so they only need to guarantee hook order. - -Execution hooks will be able to return an error. A specific error can be returned to specify that -no further hooks of this plugin should be called, but that the scaffold process should be continued. -This enables plugins to exit early, e.g., a plugin that scaffolds some files only for cluster-scoped -resources can detect if the resource is cluster-scoped at one of the first execution steps, and -therefore, use this error to tell the CLI that no further execution step should be called for itself. - -### Initialization hooks - -#### Update metadata -This hook will be used for two purposes. It provides CLI-related metadata to the Subcommand (e.g., -command name) and update the subcommands metadata such as the description or examples. - -- Required/optional - - [ ] Required - - [x] Optional -- Subcommands - - [x] Init - - [x] Edit - - [x] Create API - - [x] Create webhook - -#### Bind flags -This hook will allow subcommands to define specific flags. - -- Required/optional - - [ ] Required - - [x] Optional -- Subcommands - - [x] Init - - [x] Edit - - [x] Create API - - [x] Create webhook - -### Execution methods - -#### Inject configuration -This hook will be used to inject the `Config` object that the plugin can modify at will. -The CLI will create/load/save this configuration object. - -- Required/optional - - [ ] Required - - [x] Optional -- Subcommands - - [x] Init - - [x] Edit - - [x] Create API - - [x] Create webhook - -#### Inject resource -This hook will be used to inject the `Resource` object created by the CLI. - -- Required/optional - - [x] Required - - [ ] Optional -- Subcommands - - [ ] Init - - [ ] Edit - - [x] Create API - - [x] Create webhook - -#### Pre-scaffold -This hook will be used to take actions before the main scaffolding is performed, e.g. validations. - -NOTE: a filesystem abstraction will be passed to this hook, but it should not be used for scaffolding. - -- Required/optional - - [ ] Required - - [x] Optional -- Subcommands - - [x] Init - - [x] Edit - - [x] Create API - - [x] Create webhook - -#### Scaffold -This hook will be used to perform the main scaffolding. - -NOTE: a filesystem abstraction will be passed to this hook that must be used for scaffolding. - -- Required/optional - - [x] Required - - [ ] Optional -- Subcommands - - [x] Init - - [x] Edit - - [x] Create API - - [x] Create webhook - -#### Post-scaffold -This hook will be used to take actions after the main scaffolding is performed, e.g. cleanup. - -NOTE: a filesystem abstraction will **NOT** be passed to this hook, as post-scaffold task do not require it. -In case some post-scaffold task requires a filesystem abstraction, it could be added. - -NOTE 2: the project configuration is saved by the CLI before calling this hook, so changes done to the -configuration at this hook will not be persisted. - -- Required/optional - - [ ] Required - - [x] Optional -- Subcommands - - [x] Init - - [x] Edit - - [x] Create API - - [x] Create webhook - -### Override plugins for single subcommand calls - -Defining plugins at initialization and using them for every command call will solve most of the cases. -However, there are some cases where a plugin may be wanted just for a certain subcommand call. For -example, a project with multiple controllers may want to follow the declarative pattern in only one of -their controllers. The other case is also relevant, a project where most of the controllers follow the -declarative pattern may need a single controller not to follow it. - -In order to achieve this, the `--plugins` flag will be allowed in every command call, overriding the -value used in its corresponging project initialization call. - -### Plugin chain persistence - -Currently, the project configuration v3 offers two mechanisms for storing plugin-related information. - -- A layout field (`string`) that is used for plugin resolution on initialized projects. -- A plugin field (`map[string]interface{}`) that is used for plugin configuration raw storage. - -Plugin resolution uses the `layout` field to resolve plugins. In this phase, it has to store a plugin -chain and not a single plugin. As this value is stored as a string, comma-separated representation can -be used to represent a chain of plugins instead. - -NOTE: commas are not allowed in the plugin key. - -While the `plugin` field may seem like a better fit to store the plugin chain, as it can already -contain multiple values, there are several issues with this alternative approach: -- A map does not provide any order guarantee, and the plugin chain order is relevant. -- Some plugins do not store plugin-specific configuration information, e.g. the `go`-plugins. So - the absence of a plugin key doesn't mean that the plugin is not part of the plugin chain. -- The desire of running a different set of plugins for a single subcommand call has already been - mentioned. Some of these out-of-chain plugins may need to store plugin-specific configuration, - so the presence of a plugin doesn't mean that is part of the plugin chain. - -The next project configuration version could consider this new requirements to define the -names/types of these two fields. - -### Plugin bundle - -As a side-effect of plugin chaining, the user experience may suffer if they need to provide -several plugin keys for the `--plugins` flag. Additionally, this would also mean a user-facing -important breaking change. - -In order to solve this issue, a plugin bundle concept will be introduced. A plugin bundle -behaves as a plugin: -- It has a name: provided at creation. -- It has a version: provided at creation. -- It has a list of supported project versions: computed from the common supported project - versions of all the plugins in the bundled. - -Instead of implementing the optional getter methods that return a subcommand, it offers a way -to retrieve the list of bundled plugins. This process will be done after plugin resolution. - -This way, CLIs will be able to define bundles, which will be used in the user-facing API and -the plugin resolution process, but later they will be treated as separate plugins offering -the maintainability and separation of concerns advantages that smaller plugins have in -comparison with bigger monolithic plugins. - -## Implementation - -The following types are used as input/output values of the described hooks: +|@adirio|Mar9,2021|Implemented|[Pluginsdoc](https://book.kubebuilder.io/plugins/plugins.html)| + +#ExtensibleCLIandScaffoldingPlugins-Phase1.5 + +Continuationof[ExtensibleCLIandScaffoldingPlugins](./extensible-cli-and-scaffolding-plugins-phase-1.md). + +##Goal + +ThegoalofthisphaseistoachieveoneofthegoalsproposedforPhase2:chainingplugins. +Phase2includesseveralotherchallenginggoals,butbeingabletochainpluginswillbebeneficial +forthird-partydevelopersthatareusingkubebuilderasalibrary. + +Theothermaingoalofphase2,discoveringandusingexternalplugins,isoutofthescopeofthisphase, +andwillbetackledwhenphase2isimplemented. + +##Tableofcontents +-[Goal](#goal) +-[Motivation](#motivation) +-[Proposal](#proposal) +-[Implementation](#implementation) + +##Motivation + +Thereareseveralcasesofpluginsthatwanttomaintainmostofthegopluginfunctionalityandadd +certainfeaturesontopofit,bothinsideandoutsidekubebuilderrepository: +-[Addonpattern](../plugins/addon) +-[OperatorSDK](https://github.com/operator-framework/operator-sdk/tree/master/internal/plugins/golang) + +ThisbehaviorfitsperfectlyunderPhase1.5,wherepluginscouldbechained.However,asthisfeatureis +notavailable,theadoptedtemporalsolutionistowrapthebasegopluginandperformadditionalactions +afterits`Run`methodhasbeenexecuted.Thissolutionfacesseveralissues: + +-Wrapperpluginsareunabletoaccessthedataofthewrappedplugins,astheyweren'tdesignedforthis +purpose,andtherefore,mostofitsinternaldataisnon-exported.Anexampleofthisinaccessibledata +wouldbethe`Resource`objectscreatedinsidethe`createapi`and`createwebhook`commands. +-Wrapperpluginsaredependentontheirwrappedplugins,andthereforecan'tbeusedforotherplugins. +-Underthehood,subcommandsimplementasecondhiddeninterface:`RunOptions`,whichfurtheraccentuates +theseissues. + +PluginchainingsolvestheaforementionedproblemsbutthecurrentpluginAPI,andmorespecificallythe +`Subcommand`interface,doesnotsupportpluginchaining. + +-The`RunOptions`interfaceimplementedunderthehoodisnotpartofthepluginAPI,andtherefore +thecliisnotabletorunpost-scaffoldlogic(implementedin`RunOptions.PostScaffold`method)after +allthepluginshavescaffoldedtheirpart. +-`Resource`-relatedcommandscan'tbindflagslike`--group`,`--version`or`--kind`ineachplugin, +itmustbecreatedoutsidethepluginsandtheninjectedintothemsimilartotheapproachfollowed +currentlyfor`Config`objects. + +##Proposal + +DesignaPluginAPIthatcombinesthecurrent[`Subcommand`](../pkg/plugin/interfaces.go)and +[`RunOptions`](../pkg/plugins/internal/cmdutil/cmdutil.go)interfacesandenablesplugin-chaining. +Thenew`Subcommand`hookscanbesplitintwodifferentcategories: +-Initializationhooks +-Executionhooks + +InitializationhooksarerunduringthedynamiccreationoftheCLI,whichmeansthattheyareableto +modifytheCLI,e.g.providingdescriptionsandexamplesforsubcommandsorbindingflags. +ExecutionhooksarerunaftertheCLIiscreated,andthereforecannotmodifytheCLI.Ontheotherhand, +astheyarerunduringtheCLIexecution,theyhaveaccesstouser-providedflagvalues,projectconfiguration, +thenewAPIresourceorthefilesystemabstraction,asopposedtotheinitializationhooks. + +Additionally,someofthesehooksmaybeoptional,inwhichcaseanon-implementedhookwillbeskipped +whenitshouldbecalledandconsideritsucceeded.Thisalsoallowstocreatesomehooksspecificfor +acertainsubcommandcall(e.g.:`Resource`-relatedhooksforthe`edit`subcommandarenotneeded). + +Differentorderingguaranteescanbeconsidered: +-Hookorderguarantee:ahookforapluginwillbecalledafteritsprevioushookssucceeded. +-Stepsorderguarantee:hookswillbecalledwhenallpluginshavefinishedtheprevioushook. +-Pluginorderguarantee:samehookforeachpluginwillbecalledintheorderspecified +bythepluginpositionatthepluginchain. + +Allofthehookswillofferpluginorderguarantee,astheyallmodify/updatesomeitemsotheorder +ofpluginsisimportant.Executionhooksneedtoguaranteesteporder,astheitemsthatarebeingmodified +ineachstep(config,resource,andfilesystem)arealsoneededinthefollowingsteps.Thisisnottruefor +initializationhooksthatmodifyitems(metadataandflagset)thatareonlyusedintheirownmethods, +sotheyonlyneedtoguaranteehookorder. + +Executionhookswillbeabletoreturnanerror.Aspecificerrorcanbereturnedtospecifythat +nofurtherhooksofthispluginshouldbecalled,butthatthescaffoldprocessshouldbecontinued. +Thisenablespluginstoexitearly,e.g.,apluginthatscaffoldssomefilesonlyforcluster-scoped +resourcescandetectiftheresourceiscluster-scopedatoneofthefirstexecutionsteps,and +therefore,usethiserrortotelltheCLIthatnofurtherexecutionstepshouldbecalledforitself. + +###Initializationhooks + +####Updatemetadata +Thishookwillbeusedfortwopurposes.ItprovidesCLI-relatedmetadatatotheSubcommand(e.g., +commandname)andupdatethesubcommandsmetadatasuchasthedescriptionorexamples. + +-Required/optional +-[]Required +-[x]Optional +-Subcommands +-[x]Init +-[x]Edit +-[x]CreateAPI +-[x]Createwebhook + +####Bindflags +Thishookwillallowsubcommandstodefinespecificflags. + +-Required/optional +-[]Required +-[x]Optional +-Subcommands +-[x]Init +-[x]Edit +-[x]CreateAPI +-[x]Createwebhook + +###Executionmethods + +####Injectconfiguration +Thishookwillbeusedtoinjectthe`Config`objectthattheplugincanmodifyatwill. +TheCLIwillcreate/load/savethisconfigurationobject. + +-Required/optional +-[]Required +-[x]Optional +-Subcommands +-[x]Init +-[x]Edit +-[x]CreateAPI +-[x]Createwebhook + +####Injectresource +Thishookwillbeusedtoinjectthe`Resource`objectcreatedbytheCLI. + +-Required/optional +-[x]Required +-[]Optional +-Subcommands +-[]Init +-[]Edit +-[x]CreateAPI +-[x]Createwebhook + +####Pre-scaffold +Thishookwillbeusedtotakeactionsbeforethemainscaffoldingisperformed,e.g.validations. + +NOTE:afilesystemabstractionwillbepassedtothishook,butitshouldnotbeusedforscaffolding. + +-Required/optional +-[]Required +-[x]Optional +-Subcommands +-[x]Init +-[x]Edit +-[x]CreateAPI +-[x]Createwebhook + +####Scaffold +Thishookwillbeusedtoperformthemainscaffolding. + +NOTE:afilesystemabstractionwillbepassedtothishookthatmustbeusedforscaffolding. + +-Required/optional +-[x]Required +-[]Optional +-Subcommands +-[x]Init +-[x]Edit +-[x]CreateAPI +-[x]Createwebhook + +####Post-scaffold +Thishookwillbeusedtotakeactionsafterthemainscaffoldingisperformed,e.g.cleanup. + +NOTE:afilesystemabstractionwill**NOT**bepassedtothishook,aspost-scaffoldtaskdonotrequireit. +Incasesomepost-scaffoldtaskrequiresafilesystemabstraction,itcouldbeadded. + +NOTE2:theprojectconfigurationissavedbytheCLIbeforecallingthishook,sochangesdonetothe +configurationatthishookwillnotbepersisted. + +-Required/optional +-[]Required +-[x]Optional +-Subcommands +-[x]Init +-[x]Edit +-[x]CreateAPI +-[x]Createwebhook + +###Overridepluginsforsinglesubcommandcalls + +Definingpluginsatinitializationandusingthemforeverycommandcallwillsolvemostofthecases. +However,therearesomecaseswhereapluginmaybewantedjustforacertainsubcommandcall.For +example,aprojectwithmultiplecontrollersmaywanttofollowthedeclarativepatterninonlyoneof +theircontrollers.Theothercaseisalsorelevant,aprojectwheremostofthecontrollersfollowthe +declarativepatternmayneedasinglecontrollernottofollowit. + +Inordertoachievethis,the`--plugins`flagwillbeallowedineverycommandcall,overridingthe +valueusedinitscorrespongingprojectinitializationcall. + +###Pluginchainpersistence + +Currently,theprojectconfigurationv3offerstwomechanismsforstoringplugin-relatedinformation. + +-Alayoutfield(`string`)thatisusedforpluginresolutiononinitializedprojects. +-Apluginfield(`map[string]interface{}`)thatisusedforpluginconfigurationrawstorage. + +Pluginresolutionusesthe`layout`fieldtoresolveplugins.Inthisphase,ithastostoreaplugin +chainandnotasingleplugin.Asthisvalueisstoredasastring,comma-separatedrepresentationcan +beusedtorepresentachainofpluginsinstead. + +NOTE:commasarenotallowedinthepluginkey. + +Whilethe`plugin`fieldmayseemlikeabetterfittostorethepluginchain,asitcanalready +containmultiplevalues,thereareseveralissueswiththisalternativeapproach: +-Amapdoesnotprovideanyorderguarantee,andthepluginchainorderisrelevant. +-Somepluginsdonotstoreplugin-specificconfigurationinformation,e.g.the`go`-plugins.So +theabsenceofapluginkeydoesn'tmeanthatthepluginisnotpartofthepluginchain. +-Thedesireofrunningadifferentsetofpluginsforasinglesubcommandcallhasalreadybeen +mentioned.Someoftheseout-of-chainpluginsmayneedtostoreplugin-specificconfiguration, +sothepresenceofaplugindoesn'tmeanthatispartofthepluginchain. + +Thenextprojectconfigurationversioncouldconsiderthisnewrequirementstodefinethe +names/typesofthesetwofields. + +###Pluginbundle + +Asaside-effectofpluginchaining,theuserexperiencemaysufferiftheyneedtoprovide +severalpluginkeysforthe`--plugins`flag.Additionally,thiswouldalsomeanauser-facing +importantbreakingchange. + +Inordertosolvethisissue,apluginbundleconceptwillbeintroduced.Apluginbundle +behavesasaplugin: +-Ithasaname:providedatcreation. +-Ithasaversion:providedatcreation. +-Ithasalistofsupportedprojectversions:computedfromthecommonsupportedproject +versionsofallthepluginsinthebundled. + +Insteadofimplementingtheoptionalgettermethodsthatreturnasubcommand,itoffersaway +toretrievethelistofbundledplugins.Thisprocesswillbedoneafterpluginresolution. + +Thisway,CLIswillbeabletodefinebundles,whichwillbeusedintheuser-facingAPIand +thepluginresolutionprocess,butlatertheywillbetreatedasseparatepluginsoffering +themaintainabilityandseparationofconcernsadvantagesthatsmallerpluginshavein +comparisonwithbiggermonolithicplugins. + +##Implementation + +Thefollowingtypesareusedasinput/outputvaluesofthedescribedhooks: ```go -// CLIMetadata is the runtime meta-data of the CLI -type CLIMetadata struct { - // CommandName is the root command name. - CommandName string +//CLIMetadataistheruntimemeta-dataoftheCLI +typeCLIMetadatastruct{ +//CommandNameistherootcommandname. +CommandNamestring } -// SubcommandMetadata is the runtime meta-data for a subcommand -type SubcommandMetadata struct { - // Description is a description of what this subcommand does. It is used to display help. - Description string - // Examples are one or more examples of the command-line usage of this subcommand. It is used to display help. - Examples string +//SubcommandMetadataistheruntimemeta-dataforasubcommand +typeSubcommandMetadatastruct{ +//Descriptionisadescriptionofwhatthissubcommanddoes.Itisusedtodisplayhelp. +Descriptionstring +//Examplesareoneormoreexamplesofthecommand-lineusageofthissubcommand.Itisusedtodisplayhelp. +Examplesstring } -type ExitError struct { - Plugin string - Reason string +typeExitErrorstruct{ +Pluginstring +Reasonstring } -func (e ExitError) Error() string { - return fmt.Sprintf("plugin %s exit early: %s", e.Plugin, e.Reason) +func(eExitError)Error()string{ +returnfmt.Sprintf("plugin%sexitearly:%s",e.Plugin,e.Reason) } ``` -The described hooks are implemented through the use of the following interfaces. +Thedescribedhooksareimplementedthroughtheuseofthefollowinginterfaces. ```go -type RequiresCLIMetadata interface { - InjectCLIMetadata(CLIMetadata) +typeRequiresCLIMetadatainterface{ +InjectCLIMetadata(CLIMetadata) } -type UpdatesSubcommandMetadata interface { - UpdateSubcommandMetadata(*SubcommandMetadata) +typeUpdatesSubcommandMetadatainterface{ +UpdateSubcommandMetadata(*SubcommandMetadata) } -type HasFlags interface { - BindFlags(*pflag.FlagSet) +typeHasFlagsinterface{ +BindFlags(*pflag.FlagSet) } -type RequiresConfig interface { - InjectConfig(config.Config) error +typeRequiresConfiginterface{ +InjectConfig(config.Config)error } -type RequiresResource interface { - InjectResource(*resource.Resource) error +typeRequiresResourceinterface{ +InjectResource(*resource.Resource)error } -type HasPreScaffold interface { - PreScaffold(machinery.Filesystem) error +typeHasPreScaffoldinterface{ +PreScaffold(machinery.Filesystem)error } -type Scaffolder interface { - Scaffold(machinery.Filesystem) error +typeScaffolderinterface{ +Scaffold(machinery.Filesystem)error } -type HasPostScaffold interface { - PostScaffold() error +typeHasPostScaffoldinterface{ +PostScaffold()error } ``` -Additional interfaces define the required method for each type of plugin: +Additionalinterfacesdefinetherequiredmethodforeachtypeofplugin: ```go -// InitSubcommand is the specific interface for subcommands returned by init plugins. -type InitSubcommand interface { - Scaffolder +//InitSubcommandisthespecificinterfaceforsubcommandsreturnedbyinitplugins. +typeInitSubcommandinterface{ +Scaffolder } -// EditSubcommand is the specific interface for subcommands returned by edit plugins. -type EditSubcommand interface { - Scaffolder +//EditSubcommandisthespecificinterfaceforsubcommandsreturnedbyeditplugins. +typeEditSubcommandinterface{ +Scaffolder } -// CreateAPISubcommand is the specific interface for subcommands returned by create API plugins. -type CreateAPISubcommand interface { - RequiresResource - Scaffolder +//CreateAPISubcommandisthespecificinterfaceforsubcommandsreturnedbycreateAPIplugins. +typeCreateAPISubcommandinterface{ +RequiresResource +Scaffolder } -// CreateWebhookSubcommand is the specific interface for subcommands returned by create webhook plugins. -type CreateWebhookSubcommand interface { - RequiresResource - Scaffolder +//CreateWebhookSubcommandisthespecificinterfaceforsubcommandsreturnedbycreatewebhookplugins. +typeCreateWebhookSubcommandinterface{ +RequiresResource +Scaffolder } ``` -An additional interface defines the bundle method to return the wrapped plugins: +Anadditionalinterfacedefinesthebundlemethodtoreturnthewrappedplugins: ```go -type Bundle interface { - Plugin - Plugins() []Plugin +typeBundleinterface{ +Plugin +Plugins()[]Plugin } ``` diff --git a/designs/extensible-cli-and-scaffolding-plugins-phase-1.md b/designs/extensible-cli-and-scaffolding-plugins-phase-1.md index 0b1f679a3cf..cee77148950 100644 --- a/designs/extensible-cli-and-scaffolding-plugins-phase-1.md +++ b/designs/extensible-cli-and-scaffolding-plugins-phase-1.md @@ -1,223 +1,223 @@ -| Authors | Creation Date | Status | Extra | +|Authors|CreationDate|Status|Extra| |---------------|---------------|-------------|-----------------------------------------------------------------| -| @estroz,@joelanford | Dec 10, 2019 | Implemented | [Plugins doc](https://book.kubebuilder.io/plugins/plugins.html) | +|@estroz,@joelanford|Dec10,2019|Implemented|[Pluginsdoc](https://book.kubebuilder.io/plugins/plugins.html)| -# Extensible CLI and Scaffolding Plugins +#ExtensibleCLIandScaffoldingPlugins -## Overview +##Overview -I would like for Kubebuilder to become more extensible, such that it could be imported and used as a library in other projects. Specifically, I'm looking for a way to use Kubebuilder's existing CLI and scaffolding for Go projects, but to also be able to augment the Kubebuilder project structure with other custom project types so that I can support the Kubebuilder workflow with non-Go operators (e.g. operator-sdk's Ansible and Helm-based operators). +IwouldlikeforKubebuildertobecomemoreextensible,suchthatitcouldbeimportedandusedasalibraryinotherprojects.Specifically,I'mlookingforawaytouseKubebuilder'sexistingCLIandscaffoldingforGoprojects,buttoalsobeabletoaugmenttheKubebuilderprojectstructurewithothercustomprojecttypessothatIcansupporttheKubebuilderworkflowwithnon-Gooperators(e.g.operator-sdk'sAnsibleandHelm-basedoperators). -The idea is for Kubebuilder to define one or more plugin interfaces that can be used to drive what the `init`, `create api` and `create webhooks` subcommands do and to add a new `cli` package that other projects can use to integrate out-of-tree plugins with the Kubebuilder CLI in their own projects. +TheideaisforKubebuildertodefineoneormoreplugininterfacesthatcanbeusedtodrivewhatthe`init`,`createapi`and`createwebhooks`subcommandsdoandtoaddanew`cli`packagethatotherprojectscanusetointegrateout-of-treepluginswiththeKubebuilderCLIintheirownprojects. -## Related issues and PRs +##RelatedissuesandPRs -* [#1148](https://github.com/kubernetes-sigs/kubebuilder/pull/1148) -* [#1171](https://github.com/kubernetes-sigs/kubebuilder/pull/1171) -* Possibly [#1218](https://github.com/kubernetes-sigs/kubebuilder/issues/1218) +*[#1148](https://github.com/kubernetes-sigs/kubebuilder/pull/1148) +*[#1171](https://github.com/kubernetes-sigs/kubebuilder/pull/1171) +*Possibly[#1218](https://github.com/kubernetes-sigs/kubebuilder/issues/1218) -## Prototype implementation +##Prototypeimplementation -Barebones plugin refactor: https://github.com/joelanford/kubebuilder-exp -Kubebuilder feature branch: https://github.com/kubernetes-sigs/kubebuilder/tree/feature/plugins-part-2-electric-boogaloo +Barebonespluginrefactor:https://github.com/joelanford/kubebuilder-exp +Kubebuilderfeaturebranch:https://github.com/kubernetes-sigs/kubebuilder/tree/feature/plugins-part-2-electric-boogaloo -## Plugin interfaces +##Plugininterfaces -### Required +###Required -Each plugin would minimally be required to implement the `Plugin` interface. +Eachpluginwouldminimallyberequiredtoimplementthe`Plugin`interface. ```go -type Plugin interface { - // Version returns the plugin's semantic version, ex. "v1.2.3". - // - // Note: this version is different from config version. - Version() string - // Name returns a DNS1123 label string defining the plugin type. - // For example, Kubebuilder's main plugin would return "go". - // - // Plugin names can be fully-qualified, and non-fully-qualified names are - // prepended to ".kubebuilder.io" to prevent conflicts. - Name() string - // SupportedProjectVersions lists all project configuration versions this - // plugin supports, ex. []string{"2", "3"}. The returned slice cannot be empty. - SupportedProjectVersions() []string +typePlugininterface{ +//Versionreturnstheplugin'ssemanticversion,ex."v1.2.3". +// +//Note:thisversionisdifferentfromconfigversion. +Version()string +//NamereturnsaDNS1123labelstringdefiningtheplugintype. +//Forexample,Kubebuilder'smainpluginwouldreturn"go". +// +//Pluginnamescanbefully-qualified,andnon-fully-qualifiednamesare +//prependedto".kubebuilder.io"topreventconflicts. +Name()string +//SupportedProjectVersionslistsallprojectconfigurationversionsthis +//pluginsupports,ex.[]string{"2","3"}.Thereturnedslicecannotbeempty. +SupportedProjectVersions()[]string } ``` -#### Plugin naming +####Pluginnaming -Plugin names (returned by `Name()`) must be DNS1123 labels. The returned name -may be fully qualified (fq), ex. `go.kubebuilder.io`, or not but internally will -always be fq by either appending `.kubebuilder.io` to the name or using an -existing qualifier defined by the plugin. FQ names prevent conflicts between -plugin names; the plugin runner will ask the user to add a name qualifier to -a conflicting plugin. +Pluginnames(returnedby`Name()`)mustbeDNS1123labels.Thereturnedname +maybefullyqualified(fq),ex.`go.kubebuilder.io`,ornotbutinternallywill +alwaysbefqbyeitherappending`.kubebuilder.io`tothenameorusingan +existingqualifierdefinedbytheplugin.FQnamespreventconflictsbetween +pluginnames;thepluginrunnerwillasktheusertoaddanamequalifierto +aconflictingplugin. -### Optional +###Optional -Next, a plugin could optionally implement further interfaces to declare its support for specific Kubebuilder subcommands. For example: -* `InitPlugin` - to initialize new projects -* `CreateAPIPlugin` - to create APIs (and possibly controllers) for existing projects -* `CreateWebhookPlugin` - to create webhooks for existing projects +Next,aplugincouldoptionallyimplementfurtherinterfacestodeclareitssupportforspecificKubebuildersubcommands.Forexample: +*`InitPlugin`-toinitializenewprojects +*`CreateAPIPlugin`-tocreateAPIs(andpossiblycontrollers)forexistingprojects +*`CreateWebhookPlugin`-tocreatewebhooksforexistingprojects -Each of these interfaces would follow the same pattern (see the `InitPlugin` interface example below). +Eachoftheseinterfaceswouldfollowthesamepattern(seethe`InitPlugin`interfaceexamplebelow). ```go -type InitPluginGetter interface { - Plugin - // GetInitPlugin returns the underlying InitPlugin interface. - GetInitPlugin() InitPlugin +typeInitPluginGetterinterface{ +Plugin +//GetInitPluginreturnstheunderlyingInitPlugininterface. +GetInitPlugin()InitPlugin } -type InitPlugin interface { - GenericSubcommand +typeInitPlugininterface{ +GenericSubcommand } ``` -Each specialized plugin interface can leverage a generic subcommand interface, which prevents duplication of methods while permitting type checking and interface flexibility. A plugin context can be used to preserve default help text in case a plugin does not implement its own. +Eachspecializedplugininterfacecanleverageagenericsubcommandinterface,whichpreventsduplicationofmethodswhilepermittingtypecheckingandinterfaceflexibility.Aplugincontextcanbeusedtopreservedefaulthelptextincaseaplugindoesnotimplementitsown. ```go -type GenericSubcommand interface { - // UpdateContext updates a PluginContext with command-specific help text, like description and examples. - // Can be a no-op if default help text is desired. - UpdateContext(*PluginContext) - // BindFlags binds the plugin's flags to the CLI. This allows each plugin to define its own - // command line flags for the kubebuilder subcommand. - BindFlags(*pflag.FlagSet) - // Run runs the subcommand. - Run() error - // InjectConfig passes a config to a plugin. The plugin may modify the - // config. Initializing, loading, and saving the config is managed by the - // cli package. - InjectConfig(*config.Config) +typeGenericSubcommandinterface{ +//UpdateContextupdatesaPluginContextwithcommand-specifichelptext,likedescriptionandexamples. +//Canbeano-opifdefaulthelptextisdesired. +UpdateContext(*PluginContext) +//BindFlagsbindstheplugin'sflagstotheCLI.Thisallowseachplugintodefineitsown +//commandlineflagsforthekubebuildersubcommand. +BindFlags(*pflag.FlagSet) +//Runrunsthesubcommand. +Run()error +//InjectConfigpassesaconfigtoaplugin.Thepluginmaymodifythe +//config.Initializing,loading,andsavingtheconfigismanagedbythe +//clipackage. +InjectConfig(*config.Config) } -type PluginContext struct { - // Description is a description of what this subcommand does. It is used to display help. - Description string - // Examples are one or more examples of the command-line usage - // of this plugin's project subcommand support. It is used to display help. - Examples string +typePluginContextstruct{ +//Descriptionisadescriptionofwhatthissubcommanddoes.Itisusedtodisplayhelp. +Descriptionstring +//Examplesareoneormoreexamplesofthecommand-lineusage +//ofthisplugin'sprojectsubcommandsupport.Itisusedtodisplayhelp. +Examplesstring } ``` -#### Deprecated Plugins +####DeprecatedPlugins -To generically support deprecated project versions, we could also add a `Deprecated` interface that the CLI could use to decide when to print deprecation warnings: +Togenericallysupportdeprecatedprojectversions,wecouldalsoadda`Deprecated`interfacethattheCLIcouldusetodecidewhentoprintdeprecationwarnings: ```go -// Deprecated is an interface that, if implemented, informs the CLI -// that the plugin is deprecated. The CLI uses this to print deprecation -// warnings when the plugin is in use. -type Deprecated interface { - // DeprecationWarning returns a deprecation message that callers - // can use to warn users of deprecations - DeprecationWarning() string +//Deprecatedisaninterfacethat,ifimplemented,informstheCLI +//thatthepluginisdeprecated.TheCLIusesthistoprintdeprecation +//warningswhenthepluginisinuse. +typeDeprecatedinterface{ +//DeprecationWarningreturnsadeprecationmessagethatcallers +//canusetowarnusersofdeprecations +DeprecationWarning()string } ``` -## Configuration +##Configuration -### Config version `3-alpha` +###Configversion`3-alpha` -Any changes that break `PROJECT` file backwards-compatibility require a version -bump. This new version will be `3-alpha`, which will eventually be bumped to -`3` once the below config changes have stabilized. +Anychangesthatbreak`PROJECT`filebackwards-compatibilityrequireaversion +bump.Thisnewversionwillbe`3-alpha`,whichwilleventuallybebumpedto +`3`oncethebelowconfigchangeshavestabilized. -### Project file plugin `layout` +###Projectfileplugin`layout` -The `PROJECT` file will specify what base plugin generated the project under -a `layout` key. `layout` will have the format: `Plugin.Name() + "/" + Plugin.Version()`. -`version` and `layout` have versions with different meanings: `version` is the -project config version, while `layout`'s version is the plugin semantic version. -The value in `version` will determine that in `layout` by a plugin's supported -project versions (via `SupportedProjectVersions()`). +The`PROJECT`filewillspecifywhatbaseplugingeneratedtheprojectunder +a`layout`key.`layout`willhavetheformat:`Plugin.Name()+"/"+Plugin.Version()`. +`version`and`layout`haveversionswithdifferentmeanings:`version`isthe +projectconfigversion,while`layout`'sversionisthepluginsemanticversion. +Thevaluein`version`willdeterminethatin`layout`byaplugin'ssupported +projectversions(via`SupportedProjectVersions()`). -Example `PROJECT` file: +Example`PROJECT`file: ```yaml -version: "3-alpha" -layout: go/v1.0.0 -domain: testproject.org -repo: github.com/test-inc/testproject +version:"3-alpha" +layout:go/v1.0.0 +domain:testproject.org +repo:github.com/test-inc/testproject resources: -- group: crew - kind: Captain - version: v1 +-group:crew +kind:Captain +version:v1 ``` -## CLI +##CLI -To make the above plugin system extensible and usable by other projects, we could add a new CLI package that Kubebuilder (and other projects) could use as their entrypoint. +Tomaketheabovepluginsystemextensibleandusablebyotherprojects,wecouldaddanewCLIpackagethatKubebuilder(andotherprojects)coulduseastheirentrypoint. -Example Kubebuilder main.go: +ExampleKubebuildermain.go: ```go -func main() { - c, err := cli.New( - cli.WithPlugins( - &golangv1.Plugin{}, - &golangv2.Plugin{}, - ), - ) - if err != nil { - log.Fatal(err) - } - if err := c.Run(); err != nil { - log.Fatal(err) - } +funcmain(){ +c,err:=cli.New( +cli.WithPlugins( +&golangv1.Plugin{}, +&golangv2.Plugin{}, +), +) +iferr!=nil{ +log.Fatal(err) +} +iferr:=c.Run();err!=nil{ +log.Fatal(err) +} } ``` -Example Operator SDK main.go: +ExampleOperatorSDKmain.go: ```go -func main() { - c, err := cli.New( - cli.WithCommandName("operator-sdk"), - cli.WithDefaultProjectVersion("2"), - cli.WithExtraCommands(newCustomCobraCmd()), - cli.WithPlugins( - &golangv1.Plugin{}, - &golangv2.Plugin{}, - &helmv1.Plugin{}, - &ansiblev1.Plugin{}, - ), - ) - if err != nil { - log.Fatal(err) - } - if err := c.Run(); err != nil { - log.Fatal(err) - } +funcmain(){ +c,err:=cli.New( +cli.WithCommandName("operator-sdk"), +cli.WithDefaultProjectVersion("2"), +cli.WithExtraCommands(newCustomCobraCmd()), +cli.WithPlugins( +&golangv1.Plugin{}, +&golangv2.Plugin{}, +&helmv1.Plugin{}, +&ansiblev1.Plugin{}, +), +) +iferr!=nil{ +log.Fatal(err) +} +iferr:=c.Run();err!=nil{ +log.Fatal(err) +} } ``` -## Comments & Questions +##Comments&Questions -### Cobra Commands +###CobraCommands -**RESOLUTION:** `cobra` will be used directly in Phase 1 since it is a widely used, feature-rich CLI package. This, however unlikely, may change in future phases. +**RESOLUTION:**`cobra`willbeuseddirectlyinPhase1sinceitisawidelyused,feature-richCLIpackage.This,howeverunlikely,maychangeinfuturephases. -As discussed earlier as part of [#1148](https://github.com/kubernetes-sigs/kubebuilder/pull/1148), one goal is to eliminate the use of `cobra.Command` in the exported API of Kubebuilder since that is considered an internal implementation detail. +Asdiscussedearlieraspartof[#1148](https://github.com/kubernetes-sigs/kubebuilder/pull/1148),onegoalistoeliminatetheuseof`cobra.Command`intheexportedAPIofKubebuildersincethatisconsideredaninternalimplementationdetail. -However, at some point, projects that make use of this extensibility will likely want to integrate their own subcommands. In this proposal, `cli.WithExtraCommands()` _DOES_ expose `cobra.Command` to allow callers to pass their own subcommands to the CLI. +However,atsomepoint,projectsthatmakeuseofthisextensibilitywilllikelywanttointegratetheirownsubcommands.Inthisproposal,`cli.WithExtraCommands()`_DOES_expose`cobra.Command`toallowcallerstopasstheirownsubcommandstotheCLI. -In [#1148](https://github.com/kubernetes-sigs/kubebuilder/pull/1148), callers would use Kubebuilder's cobra commands to build their CLI. Here, control of the CLI is retained by Kubebuilder, and callers pass their subcommands to Kubebuilder. This has several benefits: -1. Kubebuilder's CLI subcommands are never exposed except via the explicit plugin interface. This allows the Kubebuilder project to re-implement its subcommand internals without worrying about backwards compatibility of consumers of Kubebuilder's CLI. -2. If desired, Kubebuilder could ensure that extra subcommands do not overwrite/reuse the existing Kubebuilder subcommand names. For example, only Kubebuilder gets to define the `init` subcommand -3. The overall binary's help handling is self-contained in Kubebuilder's CLI. Callers don't have to figure out how to have a cohesive help output between the Kubebuilder CLI and their own custom subcommands. +In[#1148](https://github.com/kubernetes-sigs/kubebuilder/pull/1148),callerswoulduseKubebuilder'scobracommandstobuildtheirCLI.Here,controloftheCLIisretainedbyKubebuilder,andcallerspasstheirsubcommandstoKubebuilder.Thishasseveralbenefits: +1.Kubebuilder'sCLIsubcommandsareneverexposedexceptviatheexplicitplugininterface.ThisallowstheKubebuilderprojecttore-implementitssubcommandinternalswithoutworryingaboutbackwardscompatibilityofconsumersofKubebuilder'sCLI. +2.Ifdesired,Kubebuildercouldensurethatextrasubcommandsdonotoverwrite/reusetheexistingKubebuildersubcommandnames.Forexample,onlyKubebuildergetstodefinethe`init`subcommand +3.Theoverallbinary'shelphandlingisself-containedinKubebuilder'sCLI.Callersdon'thavetofigureouthowtohaveacohesivehelpoutputbetweentheKubebuilderCLIandtheirowncustomsubcommands. -With all of that said, even this exposure of `cobra.Command` could be problematic. If Kubebuilder decides in the future to transition to a different CLI framework (or to roll its own) it has to either continue maintaining support for these extra cobra commands passed into it, or it was to break the CLI API. +Withallofthatsaid,eventhisexposureof`cobra.Command`couldbeproblematic.IfKubebuilderdecidesinthefuturetotransitiontoadifferentCLIframework(ortorollitsown)ithastoeithercontinuemaintainingsupportfortheseextracobracommandspassedintoit,oritwastobreaktheCLIAPI. -Are there other ideas for how to handle the following requirements? -* Eliminate use of cobra in CLI interface -* Allow other projects to have custom subcommands -* Support cohesive help output +Arethereotherideasforhowtohandlethefollowingrequirements? +*EliminateuseofcobrainCLIinterface +*Allowotherprojectstohavecustomsubcommands +*Supportcohesivehelpoutput -### Other -1. ~Should the `InitPlugin` interface methods be required of all plugins?~ No -2. ~Any other approaches or ideas?~ -3. ~Anything I didn't cover that could use more explanation?~ +###Other +1.~Shouldthe`InitPlugin`interfacemethodsberequiredofallplugins?~No +2.~Anyotherapproachesorideas?~ +3.~AnythingIdidn'tcoverthatcouldusemoreexplanation?~ diff --git a/designs/extensible-cli-and-scaffolding-plugins-phase-2.md b/designs/extensible-cli-and-scaffolding-plugins-phase-2.md index 13da9089211..28c60e1b5ec 100644 --- a/designs/extensible-cli-and-scaffolding-plugins-phase-2.md +++ b/designs/extensible-cli-and-scaffolding-plugins-phase-2.md @@ -1,360 +1,360 @@ -| Authors | Creation Date | Status | Extra | +|Authors|CreationDate|Status|Extra| |---------------|---------------|-------------|-----------------------------------------------------------------| -| @rashmigottipati | Mar 9, 2021 | partial implemented | [Plugins doc](https://book.kubebuilder.io/plugins/plugins.html) | +|@rashmigottipati|Mar9,2021|partialimplemented|[Pluginsdoc](https://book.kubebuilder.io/plugins/plugins.html)| -# Extensible CLI and Scaffolding Plugins - Phase 2 +#ExtensibleCLIandScaffoldingPlugins-Phase2 -## Overview +##Overview -Plugin [Phase 1.5](https://github.com/kubernetes-sigs/kubebuilder/blob/master/designs/extensible-cli-and-scaffolding-plugins-phase-1-5.md) was designed and implemented to allow chaining of plugins. The purpose of Phase 2 plugins is to discover and use external plugins, also referred to as out-of-tree plugins (which can be implemented in any language). Phase 2 achieves both chaining and discovery of external plugins/source code not compiled with the `kubebuilder` CLI binary. By achieving this goal, we could (for example) externalize the optional [declarative plugin](https://github.com/kubernetes-sigs/kubebuilder/tree/master/pkg/plugins/golang/declarative/v1) which means that the CLI would still be able to use it, however, its source code would no longer be required to be inside of the Kubebuilder repository. +Plugin[Phase1.5](https://github.com/kubernetes-sigs/kubebuilder/blob/master/designs/extensible-cli-and-scaffolding-plugins-phase-1-5.md)wasdesignedandimplementedtoallowchainingofplugins.ThepurposeofPhase2pluginsistodiscoveranduseexternalplugins,alsoreferredtoasout-of-treeplugins(whichcanbeimplementedinanylanguage).Phase2achievesbothchaininganddiscoveryofexternalplugins/sourcecodenotcompiledwiththe`kubebuilder`CLIbinary.Byachievingthisgoal,wecould(forexample)externalizetheoptional[declarativeplugin](https://github.com/kubernetes-sigs/kubebuilder/tree/master/pkg/plugins/golang/declarative/v1)whichmeansthattheCLIwouldstillbeabletouseit,however,itssourcecodewouldnolongerberequiredtobeinsideoftheKubebuilderrepository. -### Related issues and PRs +###RelatedissuesandPRs -* [Feature Request: Plugins Phase 2](https://github.com/kubernetes-sigs/kubebuilder/issues/1378) -* [Extensible CLI and Scaffolding Plugins - Phase 1.5](https://github.com/kubernetes-sigs/kubebuilder/blob/master/designs/extensible-cli-and-scaffolding-plugins-phase-1-5.md) -* [Phase 1.5 Implementation PR](https://github.com/kubernetes-sigs/kubebuilder/pull/2060) -* [Plugin Resolution Enhancement Proposal](https://github.com/kubernetes-sigs/kubebuilder/pull/1942) +*[FeatureRequest:PluginsPhase2](https://github.com/kubernetes-sigs/kubebuilder/issues/1378) +*[ExtensibleCLIandScaffoldingPlugins-Phase1.5](https://github.com/kubernetes-sigs/kubebuilder/blob/master/designs/extensible-cli-and-scaffolding-plugins-phase-1-5.md) +*[Phase1.5ImplementationPR](https://github.com/kubernetes-sigs/kubebuilder/pull/2060) +*[PluginResolutionEnhancementProposal](https://github.com/kubernetes-sigs/kubebuilder/pull/1942) -### Prototype implementation +###Prototypeimplementation -[POC](https://github.com/rashmigottipati/POC-Phase2-Plugins) - Invoke an external python program that simulates a plugin from a go main and pass messages from `kubebuilder` to the plugin and vice-versa using `stdin/stdout/stderr`. +[POC](https://github.com/rashmigottipati/POC-Phase2-Plugins)-Invokeanexternalpythonprogramthatsimulatesapluginfromagomainandpassmessagesfrom`kubebuilder`tothepluginandvice-versausing`stdin/stdout/stderr`. -### User Stories +###UserStories -* As a plugin developer, I would like to be able to provide external plugins path for the CLI to perform the scaffolds, so that I could take advantage of external initiatives which are implemented using Kubebuilder as a lib and following its standards but are not shipped with its CLI binaries. +*Asaplugindeveloper,IwouldliketobeabletoprovideexternalpluginspathfortheCLItoperformthescaffolds,sothatIcouldtakeadvantageofexternalinitiativeswhichareimplementedusingKubebuilderasalibandfollowingitsstandardsbutarenotshippedwithitsCLIbinaries. -* As a Kubebuilder maintainer, I would like to support external plugins not maintained by the core project. - * For example, once the Phase 2 plugin implementation is completed, some internal plugins can be re-implemented as external plugins removing the necessity to build those plugins in the `kubebuilder` binary. +*AsaKubebuildermaintainer,Iwouldliketosupportexternalpluginsnotmaintainedbythecoreproject. +*Forexample,oncethePhase2pluginimplementationiscompleted,someinternalpluginscanbere-implementedasexternalpluginsremovingthenecessitytobuildthosepluginsinthe`kubebuilder`binary. -### Goals +###Goals -* `kubebuilder` is able to discover plugin binaries and run those plugins using the CLI. +*`kubebuilder`isabletodiscoverpluginbinariesandrunthosepluginsusingtheCLI. -* Kubebuilder can use the external plugins as well as its own internal ones to do scaffolding. +*Kubebuildercanusetheexternalpluginsaswellasitsowninternalonestodoscaffolding. -* `kubebuilder` should be able to show plugin specific information via the `--help` flag. +*`kubebuilder`shouldbeabletoshowpluginspecificinformationviathe`--help`flag. -* Support for standard streams i.e. `stdin/stdout/stderr` as the only IPC method between `kubebuilder` and plugins. +*Supportforstandardstreamsi.e.`stdin/stdout/stderr`astheonlyIPCmethodbetween`kubebuilder`andplugins. -* Kubebuilder library consumers can support chaining and discovery of out-of-tree plugins. +*Kubebuilderlibraryconsumerscansupportchaininganddiscoveryofout-of-treeplugins. -### Non-Goals +###Non-Goals -* Addition of new arbitrary subcommands other than the subcommands that we already support i.e `init`, `create api`, and `create webhook`. +*Additionofnewarbitrarysubcommandsotherthanthesubcommandsthatwealreadysupporti.e`init`,`createapi`,and`createwebhook`. -* Discovering plugin binaries that are not locally present on the machine (i.e. binary exists in a remote repository). +*Discoveringpluginbinariesthatarenotlocallypresentonthemachine(i.e.binaryexistsinaremoterepository). -* Providing other options (other than standard streams such as `stdin/stdout/stderr`) for inter-process communication between `kubebuilder` and external plugins. - * Other IPC methods may be allowed in the future, although EPs are required for those methods. +*Providingotheroptions(otherthanstandardstreamssuchas`stdin/stdout/stderr`)forinter-processcommunicationbetween`kubebuilder`andexternalplugins. +*OtherIPCmethodsmaybeallowedinthefuture,althoughEPsarerequiredforthosemethods. -### Examples +###Examples -* `kubebuilder create api --plugins=myexternalplugin/v1` - * should scaffold files using the external plugin as defined in its implementation of the `create api` method. +*`kubebuildercreateapi--plugins=myexternalplugin/v1` +*shouldscaffoldfilesusingtheexternalpluginasdefinedinitsimplementationofthe`createapi`method. -* `kubebuilder create api --plugins=myexternalplugin/v1,myotherexternalplugin/v2` - * should scaffold files using the external plugin as defined in their implementation of the `create api` method (by respecting the plugin chaining order, i.e. in the order of `create api` of v1 and then `create api` of v2 as specified in the layout field in the configuration). +*`kubebuildercreateapi--plugins=myexternalplugin/v1,myotherexternalplugin/v2` +*shouldscaffoldfilesusingtheexternalpluginasdefinedintheirimplementationofthe`createapi`method(byrespectingthepluginchainingorder,i.e.intheorderof`createapi`ofv1andthen`createapi`ofv2asspecifiedinthelayoutfieldintheconfiguration). -* `kubebuilder create api --plugins=myexternalplugin/v1 --help` - * should display help information of the plugin which is not shipped in the binary (myexternalplugin/v1 is present outside of the `kubebuilder` binary). +*`kubebuildercreateapi--plugins=myexternalplugin/v1--help` +*shoulddisplayhelpinformationofthepluginwhichisnotshippedinthebinary(myexternalplugin/v1ispresentoutsideofthe`kubebuilder`binary). -* `kubebuilder create api --plugins=go/v3,myexternalplugin/v2` - * should create files using the `go/v3` plugin, then pass those files to `myexternalplugin/v2` as defined in its implementation of the `create api` method by respecting the plugin chaining order. +*`kubebuildercreateapi--plugins=go/v3,myexternalplugin/v2` +*shouldcreatefilesusingthe`go/v3`plugin,thenpassthosefilesto`myexternalplugin/v2`asdefinedinitsimplementationofthe`createapi`methodbyrespectingthepluginchainingorder. -## Proposal +##Proposal -### Discovery of plugin binaries +###Discoveryofpluginbinaries -The method [kustomize](https://kubectl.docs.kubernetes.io/guides/extending_kustomize/) uses to discover plugins, by following a GVK path scheme, is the most natural for this use case since plugins must have a group-like name and version. +Themethod[kustomize](https://kubectl.docs.kubernetes.io/guides/extending_kustomize/)usestodiscoverplugins,byfollowingaGVKpathscheme,isthemostnaturalforthisusecasesincepluginsmusthaveagroup-likenameandversion. -Every plugin gets its own directory constructed using the plugin name and plugin version for the executable to be placed in and `kubebuilder` will search for a plugin binary with the name of the plugin in the `${name}/${version}` directory of the plugin. This information (plugin name and plugin version) is obtained by `kubebuilder` via the value passed to the `--plugins` CLI flag. Once `kubebuilder` successfully locates the plugin, it will run the plugin using the CLI. +Everyplugingetsitsowndirectoryconstructedusingthepluginnameandpluginversionfortheexecutabletobeplacedinand`kubebuilder`willsearchforapluginbinarywiththenameoftheplugininthe`${name}/${version}`directoryoftheplugin.Thisinformation(pluginnameandpluginversion)isobtainedby`kubebuilder`viathevaluepassedtothe`--plugins`CLIflag.Once`kubebuilder`successfullylocatestheplugin,itwillrunthepluginusingtheCLI. -Every plugin gets its own directory as below. +Everyplugingetsitsowndirectoryasbelow. -On Linux: +OnLinux: ```shell - $XDG_CONFIG_HOME/kubebuilder/plugins/${name}/${version} +$XDG_CONFIG_HOME/kubebuilder/plugins/${name}/${version} ``` -The default value of XDG_CONFIG_HOME is `$HOME/.config`. +ThedefaultvalueofXDG_CONFIG_HOMEis`$HOME/.config`. -On OSX: +OnOSX: ```shell - ~/Library/Application Support/kubebuilder/plugins/${name}/${version} +~/Library/ApplicationSupport/kubebuilder/plugins/${name}/${version} ``` -Based on the above directory scheme, let's say that if the value passed to the `--plugins` CLI flag is `myexternalplugin/v1`: +Basedontheabovedirectoryscheme,let'ssaythatifthevaluepassedtothe`--plugins`CLIflagis`myexternalplugin/v1`: -* On Linux: - * `kubebuilder` will search for the `myexternalplugin` binary in `$XDG_CONFIG_HOME/kubebuilder/plugins/myexternalplugin/v1`, where the base of this path in is the binary name. -* On OSX: - * Kubebuilder will search for the `myexternalplugin` binary in `$HOME/Library/Application Support/kubebuilder/plugins/myexternalplugin/v1`. +*OnLinux: +*`kubebuilder`willsearchforthe`myexternalplugin`binaryin`$XDG_CONFIG_HOME/kubebuilder/plugins/myexternalplugin/v1`,wherethebaseofthispathinisthebinaryname. +*OnOSX: +*Kubebuilderwillsearchforthe`myexternalplugin`binaryin`$HOME/Library/ApplicationSupport/kubebuilder/plugins/myexternalplugin/v1`. -Note: If the name is ambiguous, then the qualified name `myexternalplugin.my.domain` would be used, so the path would be `$XDG_CONFIG_HOME/kubebuilder/plugins/my/domain/myexternalplugin/v1` on Linux and `$HOME/Library/Application Support/kubebuilder/plugins/my/domain/myexternalplugin/v1` on OSX. +Note:Ifthenameisambiguous,thenthequalifiedname`myexternalplugin.my.domain`wouldbeused,sothepathwouldbe`$XDG_CONFIG_HOME/kubebuilder/plugins/my/domain/myexternalplugin/v1`onLinuxand`$HOME/Library/ApplicationSupport/kubebuilder/plugins/my/domain/myexternalplugin/v1`onOSX. -* Pros - * `kustomize` which is popular and robust tool, follows this approach in which `apiVersion` and `kind` fields are used to locate the plugin. +*Pros +*`kustomize`whichispopularandrobusttool,followsthisapproachinwhich`apiVersion`and`kind`fieldsareusedtolocatetheplugin. - * This approach enforces naming constraints as the permitted character set must be directory name-compatible following naming rules for both Linux and OSX systems. +*Thisapproachenforcesnamingconstraintsasthepermittedcharactersetmustbedirectoryname-compatiblefollowingnamingrulesforbothLinuxandOSXsystems. - * The one-plugin-per-directory requirement eases creation of a plugin bundle for sharing. +*Theone-plugin-per-directoryrequirementeasescreationofapluginbundleforsharing. -### What Plugin system should we use +###WhatPluginsystemshouldweuse -I propose we use our own plugin system that passes JSON blobs back and forth across `stdin/stdout/stderr` and make this the only option for now as it’s a language-agnostic medium and it is easy to work with in most languages. +IproposeweuseourownpluginsystemthatpassesJSONblobsbackandforthacross`stdin/stdout/stderr`andmakethistheonlyoptionfornowasit’salanguage-agnosticmediumanditiseasytoworkwithinmostlanguages. -We came to the conclusion that a kubebuilder-specific plugin library should be written after evaluating plugin libraries such as the [built-in go-plugin library](https://golang.org/pkg/plugin/) and [Hashicorp’s plugin library](https://github.com/hashicorp/go-plugin): +Wecametotheconclusionthatakubebuilder-specificpluginlibraryshouldbewrittenafterevaluatingpluginlibrariessuchasthe[built-ingo-pluginlibrary](https://golang.org/pkg/plugin/)and[Hashicorp’spluginlibrary](https://github.com/hashicorp/go-plugin): -* The built-in plugin library seems to be more suitable for in-tree plugins rather than out-of-tree plugins and it doesn’t offer cross-language support, thereby making it a non-starter. -* Hashicorp’s go plugin system is more suitable than the built-in go-plugin library as it enables cross language/platform support. However, it is more suited for long running plugins as opposed to short lived plugins and the usage of protobuf could be overkill as we will not be handling 10s of 1000s of deserializations. +*Thebuilt-inpluginlibraryseemstobemoresuitableforin-treepluginsratherthanout-of-treepluginsanditdoesn’toffercross-languagesupport,therebymakingitanon-starter. +*Hashicorp’sgopluginsystemismoresuitablethanthebuilt-ingo-pluginlibraryasitenablescrosslanguage/platformsupport.However,itismoresuitedforlongrunningpluginsasopposedtoshortlivedpluginsandtheusageofprotobufcouldbeoverkillaswewillnotbehandling10sof1000sofdeserializations. -In the future, if a need arises (for example, users are hitting performance issues), we can then explore the possibility of using the Hashicorp’s go plugin library. From a design standpoint, to leave it architecturally open, I propose using a `type` field in the PROJECT file to potentially allow other plugin libraries in the future and make this a seperate field in the PROJECT file per plugin; and this field determines how the `universe` will be passed for a given plugin. However, for the sake of simplicity in initial design and not to introduce any breaking changes as Project version 3 would suffice for our needs, this option is out of scope in this proposal. +Inthefuture,ifaneedarises(forexample,usersarehittingperformanceissues),wecanthenexplorethepossibilityofusingtheHashicorp’sgopluginlibrary.Fromadesignstandpoint,toleaveitarchitecturallyopen,Iproposeusinga`type`fieldinthePROJECTfiletopotentiallyallowotherpluginlibrariesinthefutureandmakethisaseperatefieldinthePROJECTfileperplugin;andthisfielddetermineshowthe`universe`willbepassedforagivenplugin.However,forthesakeofsimplicityininitialdesignandnottointroduceanybreakingchangesasProjectversion3wouldsufficeforourneeds,thisoptionisoutofscopeinthisproposal. -### Project configuration +###Projectconfiguration -Currently, the project configuration has two fields to store plugin specific information. +Currently,theprojectconfigurationhastwofieldstostorepluginspecificinformation. -* `Layout` field (of type []string) is used for plugin chain resolution on initialized projects. This will be the default if no plugins are specified for a subcommand. -* `Plugins` field (of type map[string]interface{}) is used for option plugin configuration that stores configuration information of any plugin. +*`Layout`field(oftype[]string)isusedforpluginchainresolutiononinitializedprojects.Thiswillbethedefaultifnopluginsarespecifiedforasubcommand. +*`Plugins`field(oftypemap[string]interface{})isusedforoptionpluginconfigurationthatstoresconfigurationinformationofanyplugin. -* So, where should external plugins be defined in the configuration? +*So,whereshouldexternalpluginsbedefinedintheconfiguration? - * I propose that the external plugin should get encoded in the project configuration as a part of the `layout` field. - * For example, external plugin `myexternalplugin/v2` can be specified through the `--plugins` flag for every subcommand and also be defined in the project configuration in the `layout` field for plugin resolution. +*Iproposethattheexternalpluginshouldgetencodedintheprojectconfigurationasapartofthe`layout`field. +*Forexample,externalplugin`myexternalplugin/v2`canbespecifiedthroughthe`--plugins`flagforeverysubcommandandalsobedefinedintheprojectconfigurationinthe`layout`fieldforpluginresolution. -Example `PROJECT` file: +Example`PROJECT`file: ```yaml -version: "3" -domain: testproject.org -layout: -- go.kubebuilder.io/v3 -- myexternalplugin/v2 +version:"3" +domain:testproject.org +layout: +-go.kubebuilder.io/v3 +-myexternalplugin/v2 plugins: - myexternalplugin/v2: - resources: - - domain: testproject.org - group: crew - kind: Captain - version: v2 - declarative.go.kubebuilder.io/v1: - resources: - - domain: testproject.org - group: crew - kind: FirstMate - version: v1 -repo: github.com/test-inc/testproject +myexternalplugin/v2: resources: -- group: crew - kind: Captain - version: v1 +-domain:testproject.org +group:crew +kind:Captain +version:v2 +declarative.go.kubebuilder.io/v1: +resources: +-domain:testproject.org +group:crew +kind:FirstMate +version:v1 +repo:github.com/test-inc/testproject +resources: +-group:crew +kind:Captain +version:v1 ``` -### Communication between `kubebuilder` and external plugins +###Communicationbetween`kubebuilder`andexternalplugins -* Why do we need communication between `kubebuilder` and external plugins? +*Whydoweneedcommunicationbetween`kubebuilder`andexternalplugins? - * The in-tree plugins do not need any inter-process communication as they are the same process, and hence, direct calls are made to the respective functions (also referred as hooks) based on the supported subcommands for an in-tree plugin. As Phase 2 plugins is tackling out-of-tree or external plugins, there's a need for inter-process communication between `kubebuilder` and the external plugin as they are two separate processes/binaries. `kubebuilder` needs to communicate the subcommand that the external plugin should run, and all the arguments received in the CLI request by the user. These arguments contain flags which will have to be directly passed to all plugins in the chain. Additionally, it's important to have context of all the files that were scaffolded until that point especially if there is more than one external plugin in the chain. `kubebuilder` attaches that information in the request, along with the command and arguments. For the external plugin, it would need to communicate the subcommand it ran and the updated file contents information that the external plugin scaffolded to `kubebuilder`. The external plugin would also need to provide its help text if requested by `kubebuilder`. As discussed earlier, standard streams seems to be a desirable IPC method of communication for the use-cases that Phase 2 is trying to solve that involves discovery and chaining of external plugins. +*Thein-treepluginsdonotneedanyinter-processcommunicationastheyarethesameprocess,andhence,directcallsaremadetotherespectivefunctions(alsoreferredashooks)basedonthesupportedsubcommandsforanin-treeplugin.AsPhase2pluginsistacklingout-of-treeorexternalplugins,there'saneedforinter-processcommunicationbetween`kubebuilder`andtheexternalpluginastheyaretwoseparateprocesses/binaries.`kubebuilder`needstocommunicatethesubcommandthattheexternalpluginshouldrun,andalltheargumentsreceivedintheCLIrequestbytheuser.Theseargumentscontainflagswhichwillhavetobedirectlypassedtoallpluginsinthechain.Additionally,it'simportanttohavecontextofallthefilesthatwerescaffoldeduntilthatpointespeciallyifthereismorethanoneexternalplugininthechain.`kubebuilder`attachesthatinformationintherequest,alongwiththecommandandarguments.Fortheexternalplugin,itwouldneedtocommunicatethesubcommanditranandtheupdatedfilecontentsinformationthattheexternalpluginscaffoldedto`kubebuilder`.Theexternalpluginwouldalsoneedtoprovideitshelptextifrequestedby`kubebuilder`.Asdiscussedearlier,standardstreamsseemstobeadesirableIPCmethodofcommunicationfortheuse-casesthatPhase2istryingtosolvethatinvolvesdiscoveryandchainingofexternalplugins. -* How does `kubebuilder` communicate to external plugins? +*Howdoes`kubebuilder`communicatetoexternalplugins? - * Standard streams have three I/O connections: standard input (`stdin`), standard output (`stdout`) and standard error (`stderr`) and they work well with chaining applications, meaning that output stream of one program can be redirected to the input stream of another. - * Let's say there are two external plugins in the plugin chain. Below is the sequence of how `kubebuilder` communicates to the plugins `myfirstexternalplugin/v1` and `mysecondexternalplugin/v1`. +*StandardstreamshavethreeI/Oconnections:standardinput(`stdin`),standardoutput(`stdout`)andstandarderror(`stderr`)andtheyworkwellwithchainingapplications,meaningthatoutputstreamofoneprogramcanberedirectedtotheinputstreamofanother. +*Let'ssaytherearetwoexternalpluginsinthepluginchain.Belowisthesequenceofhow`kubebuilder`communicatestotheplugins`myfirstexternalplugin/v1`and`mysecondexternalplugin/v1`. -![Kubebuilder to external plugins sequence diagram](https://github.com/rashmigottipati/POC-Phase2-Plugins/blob/main/docs/externalplugins-sequence-diagram.png) +![Kubebuildertoexternalpluginssequencediagram](https://github.com/rashmigottipati/POC-Phase2-Plugins/blob/main/docs/externalplugins-sequence-diagram.png) -* What to pass between `kubebuilder` and an external plugin? +*Whattopassbetween`kubebuilder`andanexternalplugin? -Message passing between `kubebuilder` and the external plugin will occur through a request / response mechanism. The `PluginRequest` will contain information that `kubebuilder` sends *to* the external plugin. The `PluginResponse` will contain information that `kubebuilder` receives *from* the external plugin. +Messagepassingbetween`kubebuilder`andtheexternalpluginwilloccurthrougharequest/responsemechanism.The`PluginRequest`willcontaininformationthat`kubebuilder`sends*to*theexternalplugin.The`PluginResponse`willcontaininformationthat`kubebuilder`receives*from*theexternalplugin. -The following scenarios shows what `kubebuilder` will send/receive to the external plugin: +Thefollowingscenariosshowswhat`kubebuilder`willsend/receivetotheexternalplugin: -* `kubebuilder` to external plugin: - * `kubebuilder` constructs a `PluginRequest` that contains the `Command` (such as `init`, `create api`, or `create webhook`), `Args` containing all the raw flags from the CLI request and license boilerplate without comment delimiters, and an empty `Universe` that contains the current virtual state of file contents that is not written to the disk yet. `kubebuilder` writes the `PluginRequest` through `stdin`. +*`kubebuilder`toexternalplugin: +*`kubebuilder`constructsa`PluginRequest`thatcontainsthe`Command`(suchas`init`,`createapi`,or`createwebhook`),`Args`containingalltherawflagsfromtheCLIrequestandlicenseboilerplatewithoutcommentdelimiters,andanempty`Universe`thatcontainsthecurrentvirtualstateoffilecontentsthatisnotwrittentothediskyet.`kubebuilder`writesthe`PluginRequest`through`stdin`. -* External plugin to `kubebuilder`: - * The plugin reads the `PluginRequest` through its `stdin` and processes the request based on the `Command` that was sent. If the `Command` doesn't match what the plugin supports, it writes back an error immediately without any further processing. If the `Command` matches what the plugin supports, it constructs a `PluginResponse` containing the `Command` that was executed by the plugin, and modified `Universe` based on the new files that were scaffolded by the external plugin, `Error` and `ErrorMsg` that add any error information, and writes the `PluginResponse` back to `kubebuilder` through `stdout`. +*Externalpluginto`kubebuilder`: +*Thepluginreadsthe`PluginRequest`throughits`stdin`andprocessestherequestbasedonthe`Command`thatwassent.Ifthe`Command`doesn'tmatchwhatthepluginsupports,itwritesbackanerrorimmediatelywithoutanyfurtherprocessing.Ifthe`Command`matcheswhatthepluginsupports,itconstructsa`PluginResponse`containingthe`Command`thatwasexecutedbytheplugin,andmodified`Universe`basedonthenewfilesthatwerescaffoldedbytheexternalplugin,`Error`and`ErrorMsg`thataddanyerrorinformation,andwritesthe`PluginResponse`backto`kubebuilder`through`stdout`. -* Note: If `--help` flag is being passed from `kubebuilder` to the external plugin through `PluginRequest`, the plugin attaches its help text information in the `Metadata` field of the `PluginResponse`. Both `PluginRequest` and `PluginResponse` also contain `APIVersion` field to have compatible versioned schemas. +*Note:If`--help`flagisbeingpassedfrom`kubebuilder`totheexternalpluginthrough`PluginRequest`,thepluginattachesitshelptextinformationinthe`Metadata`fieldofthe`PluginResponse`.Both`PluginRequest`and`PluginResponse`alsocontain`APIVersion`fieldtohavecompatibleversionedschemas. -* Handling plugin failures across the chain: +*Handlingpluginfailuresacrossthechain: - * If any plugin in the chain fails, the plugin reports errors back through `PluginResponse` to `kubebuilder` and plugin chain execution will be halted, as one plugin may be dependent on the success of another. All the files that were scaffolded already until that point will not be written to disk to prevent a half committed state. +*Ifanyplugininthechainfails,thepluginreportserrorsbackthrough`PluginResponse`to`kubebuilder`andpluginchainexecutionwillbehalted,asonepluginmaybedependentonthesuccessofanother.Allthefilesthatwerescaffoldedalreadyuntilthatpointwillnotbewrittentodisktopreventahalfcommittedstate. -## Implementation Details/Notes/Constraints +##ImplementationDetails/Notes/Constraints -`PluginRequest` holds all the information `kubebuilder` receives from the CLI and the plugins that were executed before it and the `PluginRequest` will be marshaled into a JSON and sent over `stdin` to the external plugin. `PluginResponse` is what the plugin constructs with the updated universe and sent back to `kubebuilder`. The following structs would be defined on the Kubebuilder side. +`PluginRequest`holdsalltheinformation`kubebuilder`receivesfromtheCLIandthepluginsthatwereexecutedbeforeitandthe`PluginRequest`willbemarshaledintoaJSONandsentover`stdin`totheexternalplugin.`PluginResponse`iswhatthepluginconstructswiththeupdateduniverseandsentbackto`kubebuilder`.ThefollowingstructswouldbedefinedontheKubebuilderside. ```go -// PluginRequest contains all information kubebuilder received from the CLI -// and plugins executed before it. -type PluginRequest struct { - // Command contains the command to be executed by the plugin such as init, create api, etc. - Command string `json:"command"` - - // APIVersion defines the versioned schema of the PluginRequest that is encoded and sent from Kubebuilder to plugin. - // Initially, this will be marked as alpha (v1alpha1). - APIVersion string `json:"apiVersion"` - - // Args holds the plugin specific arguments that are received from the CLI which are to be passed down to the plugin. - Args []string `json:"args"` - - // Universe represents the modified file contents that gets updated over a series of plugin runs - // across the plugin chain. Initially, it starts out as empty. - Universe map[string]string `json:"universe"` +//PluginRequestcontainsallinformationkubebuilderreceivedfromtheCLI +//andpluginsexecutedbeforeit. +typePluginRequeststruct{ +//Commandcontainsthecommandtobeexecutedbythepluginsuchasinit,createapi,etc. +Commandstring`json:"command"` + +//APIVersiondefinestheversionedschemaofthePluginRequestthatisencodedandsentfromKubebuildertoplugin. +//Initially,thiswillbemarkedasalpha(v1alpha1). +APIVersionstring`json:"apiVersion"` + +//ArgsholdsthepluginspecificargumentsthatarereceivedfromtheCLIwhicharetobepasseddowntotheplugin. +Args[]string`json:"args"` + +//Universerepresentsthemodifiedfilecontentsthatgetsupdatedoveraseriesofpluginruns +//acrossthepluginchain.Initially,itstartsoutasempty. +Universemap[string]string`json:"universe"` } -// PluginResponse is returned to kubebuilder by the plugin and contains all files -// written by the plugin following a certain command. -type PluginResponse struct { - // Command holds the command that gets executed by the plugin such as init, create api, etc. - Command string `json:"command"` +//PluginResponseisreturnedtokubebuilderbythepluginandcontainsallfiles +//writtenbythepluginfollowingacertaincommand. +typePluginResponsestruct{ +//Commandholdsthecommandthatgetsexecutedbythepluginsuchasinit,createapi,etc. +Commandstring`json:"command"` - // Metadata contains the plugin specific help text that the plugin returns to Kubebuilder when it receives - // `--help` flag from Kubebuilder. - Metadata plugin.SubcommandMetadata `json:"metadata"` +//MetadatacontainsthepluginspecifichelptextthatthepluginreturnstoKubebuilderwhenitreceives +//`--help`flagfromKubebuilder. +Metadataplugin.SubcommandMetadata`json:"metadata"` - // APIVersion defines the versioned schema of the PluginResponse that will be written back to kubebuilder. - // Initially, this will be marked as alpha (v1alpha1). - APIVersion string `json:"apiVersion"` +//APIVersiondefinestheversionedschemaofthePluginResponsethatwillbewrittenbacktokubebuilder. +//Initially,thiswillbemarkedasalpha(v1alpha1). +APIVersionstring`json:"apiVersion"` - // Universe in the PluginResponse represents the updated file contents that was written by the plugin. - Universe map[string]string `json:"universe"` +//UniverseinthePluginResponserepresentstheupdatedfilecontentsthatwaswrittenbytheplugin. +Universemap[string]string`json:"universe"` - // Error is a boolean type that indicates whether there were any errors due to plugin failures. - Error bool `json:"error,omitempty"` +//Errorisabooleantypethatindicateswhethertherewereanyerrorsduetopluginfailures. +Errorbool`json:"error,omitempty"` - // ErrorMsg holds the specific error message of plugin failures. - ErrorMsg string `json:"error_msg,omitempty"` +//ErrorMsgholdsthespecificerrormessageofpluginfailures. +ErrorMsgstring`json:"error_msg,omitempty"` } ``` -The following function handles construction of the `PluginRequest` based on the information `kubebuilder` receives from the CLI and the request is marshaled into JSON. The command to run the external plugin by providing the plugin path will be invoked and `kubebuilder` will send the marshaled `PluginRequest` JSON to the plugin over `stdin`. +Thefollowingfunctionhandlesconstructionofthe`PluginRequest`basedontheinformation`kubebuilder`receivesfromtheCLIandtherequestismarshaledintoJSON.Thecommandtoruntheexternalpluginbyprovidingthepluginpathwillbeinvokedand`kubebuilder`willsendthemarshaled`PluginRequest`JSONtothepluginover`stdin`. ```go -func (p *ExternalPlugin) runExternalProgram(req PluginRequest) (res PluginResponse, err error) { - pluginReq, err := json.Marshal(req) - if err != nil { - return res, err - } - - cmd := exec.Command(p.Path) - cmd.Dir = p.DirContext - cmd.Stdin = bytes.NewBuffer(pluginReq) - cmd.Stderr = os.Stderr - - out, err := cmd.Output() - if err != nil { - fmt.Fprint(os.Stdout, string(out)) - return res, err - } - - if json.Unmarshal(out, &res); err != nil { - return res, err - } - return res, nil +func(p*ExternalPlugin)runExternalProgram(reqPluginRequest)(resPluginResponse,errerror){ +pluginReq,err:=json.Marshal(req) +iferr!=nil{ +returnres,err +} + +cmd:=exec.Command(p.Path) +cmd.Dir=p.DirContext +cmd.Stdin=bytes.NewBuffer(pluginReq) +cmd.Stderr=os.Stderr + +out,err:=cmd.Output() +iferr!=nil{ +fmt.Fprint(os.Stdout,string(out)) +returnres,err +} + +ifjson.Unmarshal(out,&res);err!=nil{ +returnres,err +} +returnres,nil } ``` -On the plugin side, the request JSON will be decoded and depending on what the `Command` in the `PluginRequest` is, the corresponding function to handle `init` or `create api` will be invoked thereby modifying the universe by writing the updated files to it. After `init` or `create api` functions execute successfully, the plugin will write back `PluginResponse` with updated universe and errors (if any) in JSON format through `stdout` to `kubebuilder`. `PluginResponse` also contains error fields `Error` and `ErrorMsg` that the plugin can utilize to add error context if any errors occur. -`kubebuilder` receives the command output and decodes into `PluginResponse` struct. This is how message passing will occur between `kubebuilder` and the external plugin. Refer to [POC](https://github.com/rashmigottipati/POC-Phase2-Plugins) for specifics. +Onthepluginside,therequestJSONwillbedecodedanddependingonwhatthe`Command`inthe`PluginRequest`is,thecorrespondingfunctiontohandle`init`or`createapi`willbeinvokedtherebymodifyingtheuniversebywritingtheupdatedfilestoit.After`init`or`createapi`functionsexecutesuccessfully,thepluginwillwriteback`PluginResponse`withupdateduniverseanderrors(ifany)inJSONformatthrough`stdout`to`kubebuilder`.`PluginResponse`alsocontainserrorfields`Error`and`ErrorMsg`thattheplugincanutilizetoadderrorcontextifanyerrorsoccur. +`kubebuilder`receivesthecommandoutputanddecodesinto`PluginResponse`struct.Thisishowmessagepassingwilloccurbetween`kubebuilder`andtheexternalplugin.Referto[POC](https://github.com/rashmigottipati/POC-Phase2-Plugins)forspecifics. -### Simple Example +###SimpleExample ```shell -kubebuilder init --plugins=myexternalplugin/v1 --domain example.com +kubebuilderinit--plugins=myexternalplugin/v1--domainexample.com ``` -What happens when the above is invoked? +Whathappenswhentheaboveisinvoked? -![Kubebuilder to external plugins](https://github.com/rashmigottipati/POC-Phase2-Plugins/blob/main/docs/externalplugins-sequence-diagram-2.png) +![Kubebuildertoexternalplugins](https://github.com/rashmigottipati/POC-Phase2-Plugins/blob/main/docs/externalplugins-sequence-diagram-2.png) -* `kubebuilder` discovers `myexternalplugin/v1` plugin binary and runs the plugin from the discovered path. +*`kubebuilder`discovers`myexternalplugin/v1`pluginbinaryandrunsthepluginfromthediscoveredpath. -* Send `PluginRequest` as a JSON over `stdin` to `myexternalplugin` plugin. +*Send`PluginRequest`asaJSONover`stdin`to`myexternalplugin`plugin. -`PluginRequest JSON`: +`PluginRequestJSON`: ```JSON -{ - "command":"init", - "args":["--domain","example.com"], - "universe":{} +{ +"command":"init", +"args":["--domain","example.com"], +"universe":{} } ``` -* `myexternalplugin` plugin parses the `PluginRequest` and based on the `Command` specified in the request i.e `init`, performs the necessary scaffolding. +*`myexternalplugin`pluginparsesthe`PluginRequest`andbasedonthe`Command`specifiedintherequesti.e`init`,performsthenecessaryscaffolding. -* `myexternalplugin` plugin constructs `PluginResponse` with modified `Universe` that contains the updated file contents and errors if any. +*`myexternalplugin`pluginconstructs`PluginResponse`withmodified`Universe`thatcontainstheupdatedfilecontentsanderrorsifany. -* Plugin writes `PluginResponse` to stdout in a JSON format back to `kubebuilder`. +*Pluginwrites`PluginResponse`tostdoutinaJSONformatbackto`kubebuilder`. -* `kubebuilder` receives the command output containing the `PluginResponse` JSON which will be decoded into the `PluginResponse` struct. +*`kubebuilder`receivesthecommandoutputcontainingthe`PluginResponse`JSONwhichwillbedecodedintothe`PluginResponse`struct. -* `kubebuilder` writes the files in the universe to disk. +*`kubebuilder`writesthefilesintheuniversetodisk. -`PluginResponse JSON`: +`PluginResponseJSON`: ```JSON { - "command": "init", - "universe": { - "LICENSE": "Apache 2.0 License\n", - "main.py": "..." - } +"command":"init", +"universe":{ +"LICENSE":"Apache2.0License\n", +"main.py":"..." +} } ``` -## Alternatives +##Alternatives -### Plugin discovery +###Plugindiscovery -#### User specified file paths +####Userspecifiedfilepaths -A user will provide a list of file paths for `kubebuilder` to discover the plugins in. We will define a variable `KUBEBUILDER_PLUGINS_DIRS` that will take a list of file paths to search for the plugin name. It will also have a default value to search in, in case no file paths are provided. It will search for the plugin name that was provided to the `--plugins` flag in the CLI. `kubebuilder` will recursively search for all file paths until the plugin name is found and returns the successful match, and if it doesn’t exist, it returns an error message that the plugin is not found in the provided file paths. Also use the host system mechanism for PATH separation. +Auserwillprovidealistoffilepathsfor`kubebuilder`todiscoverthepluginsin.Wewilldefineavariable`KUBEBUILDER_PLUGINS_DIRS`thatwilltakealistoffilepathstosearchforthepluginname.Itwillalsohaveadefaultvaluetosearchin,incasenofilepathsareprovided.Itwillsearchforthepluginnamethatwasprovidedtothe`--plugins`flagintheCLI.`kubebuilder`willrecursivelysearchforallfilepathsuntilthepluginnameisfoundandreturnsthesuccessfulmatch,andifitdoesn’texist,itreturnsanerrormessagethatthepluginisnotfoundintheprovidedfilepaths.AlsousethehostsystemmechanismforPATHseparation. -* Alternatively, this could be handled in a way that [helm kustomize plugin](https://helm.sh/docs/topics/advanced/#post-rendering) discovers the plugin based on the non-existence of a separator in the path provided, in which case `kubebuilder` will search in `$PATH`, otherwise resolve any relative paths to a fully qualified path. +*Alternatively,thiscouldbehandledinawaythat[helmkustomizeplugin](https://helm.sh/docs/topics/advanced/#post-rendering)discoversthepluginbasedonthenon-existenceofaseparatorinthepathprovided,inwhichcase`kubebuilder`willsearchin`$PATH`,otherwiseresolveanyrelativepathstoafullyqualifiedpath. -* Pros - * This provides flexibility for the user to specify the file paths that the plugin would be placed in and `kubebuilder` could discover the binaries in those user specified file paths. +*Pros +*Thisprovidesflexibilityfortheusertospecifythefilepathsthatthepluginwouldbeplacedinand`kubebuilder`coulddiscoverthebinariesinthoseuserspecifiedfilepaths. - * No constraints on plugin binary naming or directory placements from the Kubebuilder side. +*NoconstraintsonpluginbinarynamingordirectoryplacementsfromtheKubebuilderside. - * Provides a default value for the plugin directory in case user wants to use that to drop their plugins. +*Providesadefaultvaluefortheplugindirectoryincaseuserwantstousethattodroptheirplugins. -#### Prefixed plugin executable names in $PATH +####Prefixedpluginexecutablenamesin$PATH -Another approach is adding plugin executables with a prefix `kubebuilder-` followed by the plugin name to the PATH variable. This will enable `kubebuilder` to traverse through the PATH looking for the plugin executables starting with the prefix `kubebuilder-` and matching by the plugin name that was provided in the CLI. Furthermore, a check should be added to verify that the match is an executable or not and return an error if it's not an executable. This approach provides a lot of flexibility in terms of plugin discovery as all the user needs to do is to add the plugin executable to the PATH and `kubebuilder` will discover it. +Anotherapproachisaddingpluginexecutableswithaprefix`kubebuilder-`followedbythepluginnametothePATHvariable.Thiswillenable`kubebuilder`totraversethroughthePATHlookingforthepluginexecutablesstartingwiththeprefix`kubebuilder-`andmatchingbythepluginnamethatwasprovidedintheCLI.Furthermore,acheckshouldbeaddedtoverifythatthematchisanexecutableornotandreturnanerrorifit'snotanexecutable.ThisapproachprovidesalotofflexibilityintermsofplugindiscoveryasalltheuserneedstodoistoaddthepluginexecutabletothePATHand`kubebuilder`willdiscoverit. -* Pros - * `kubectl` and `git` follow the same approach for discovering plugins, so there’s prior art. +*Pros +*`kubectl`and`git`followthesameapproachfordiscoveringplugins,sothere’spriorart. - * There’s a lot of flexibility in just dropping plugin binaries to PATH variable and enabling the discovery without having to enforce any other constraints on the placements of the plugins. +*There’salotofflexibilityinjustdroppingpluginbinariestoPATHvariableandenablingthediscoverywithouthavingtoenforceanyotherconstraintsontheplacementsoftheplugins. -* Cons - * Enumerating the list of all available plugins might be a bit tough compared to having a single folder with the list of available plugins and having to enumerate those. +*Cons +*Enumeratingthelistofallavailablepluginsmightbeabittoughcomparedtohavingasinglefolderwiththelistofavailablepluginsandhavingtoenumeratethose. - * These plugin binaries cannot be run in a standalone manner outside of Kubebuilder, so may not be very ideal to add them to the PATH var. +*ThesepluginbinariescannotberuninastandalonemanneroutsideofKubebuilder,somaynotbeveryidealtoaddthemtothePATHvar. -## Open questions +##Openquestions -* Do we want to support the addition of new arbitrary subcommands other than the subcommands (init, create api, create webhook) that we already support? - * Not for the EP or initial implementation, but can revisit later. +*Dowewanttosupporttheadditionofnewarbitrarysubcommandsotherthanthesubcommands(init,createapi,createwebhook)thatwealreadysupport? +*NotfortheEPorinitialimplementation,butcanrevisitlater. -* Do we need to discover flags by calling the plugin binary or should we have users define them in the project configuration? - * Flags will be passed directly to the external plugins as a string. Flag parse errors will be passed back via `PluginResponse`. +*Doweneedtodiscoverflagsbycallingthepluginbinaryorshouldwehaveusersdefinethemintheprojectconfiguration? +*Flagswillbepasseddirectlytotheexternalpluginsasastring.Flagparseerrorswillbepassedbackvia`PluginResponse`. -* What alternatives to stdin/stdout exist and why shouldn't we use them? - * Other alternatives exist such as named pipe and sockets, but stdin/stdout seems to be more suitable for our needs. +*Whatalternativestostdin/stdoutexistandwhyshouldn'tweusethem? +*Otheralternativesexistsuchasnamedpipeandsockets,butstdin/stdoutseemstobemoresuitableforourneeds. -* What happens when two plugins bind the same flag name? Will there be any conflicts? - * As mentioned in the implementation details section, flags are passed directly as a string to plugins and the same string will be passed to each plugin in the chain, so all plugins get the same flag set. Errors should not be returned if an unrecognized flag is parsed. +*Whathappenswhentwopluginsbindthesameflagname?Willtherebeanyconflicts? +*Asmentionedintheimplementationdetailssection,flagsarepasseddirectlyasastringtopluginsandthesamestringwillbepassedtoeachplugininthechain,soallpluginsgetthesameflagset.Errorsshouldnotbereturnedifanunrecognizedflagisparsed. -* How should we handle environment variables? - * We would pass the entire CLI environment to the plugin to permit simple external plugin configuration without jumping through hoops. +*Howshouldwehandleenvironmentvariables? +*WewouldpasstheentireCLIenvironmenttotheplugintopermitsimpleexternalpluginconfigurationwithoutjumpingthroughhoops. -* Should the API version be a part of the plugin request spec? - * It would be nice to encode APIVersion for `PluginRequest` and `PluginResponse` so the initial schemas can be marked as `v1alpha1`. +*ShouldtheAPIversionbeapartofthepluginrequestspec? +*ItwouldbenicetoencodeAPIVersionfor`PluginRequest`and`PluginResponse`sotheinitialschemascanbemarkedas`v1alpha1`. diff --git a/designs/helper_to_upgrade_projects_by_rescaffolding.md b/designs/helper_to_upgrade_projects_by_rescaffolding.md index 3ec6c329e5b..929e465ad47 100644 --- a/designs/helper_to_upgrade_projects_by_rescaffolding.md +++ b/designs/helper_to_upgrade_projects_by_rescaffolding.md @@ -1,212 +1,212 @@ -| Authors | Creation Date | Status | Extra | +|Authors|CreationDate|Status|Extra| |------------------------------------|---------------|-------------|---| -| @camilamacedo86,@Kavinjsir,@varshaprasad96 | Feb, 2023 | Implementable | - | +|@camilamacedo86,@Kavinjsir,@varshaprasad96|Feb,2023|Implementable|-| -Experimental Helper to upgrade projects by re-scaffolding +ExperimentalHelpertoupgradeprojectsbyre-scaffolding =================== -This proposal aims to provide a new alpha command with a helper which -would be able to re-scaffold the project from the scratch based on -the [PROJECT config][project-config]. +Thisproposalaimstoprovideanewalphacommandwithahelperwhich +wouldbeabletore-scaffoldtheprojectfromthescratchbasedon +the[PROJECTconfig][project-config]. -## Example +##Example -By running a command like following, users would be able to re-scaffold the whole project from the scratch using the -current version of KubeBuilder binary available. +Byrunningacommandlikefollowing,userswouldbeabletore-scaffoldthewholeprojectfromthescratchusingthe +currentversionofKubeBuilderbinaryavailable. ```shell -kubebuilder alpha generate [OPTIONS] +kubebuilderalphagenerate[OPTIONS] ``` -### Workflows +###Workflows -Following some examples of the workflows +Followingsomeexamplesoftheworkflows -**To update the project with minor changes provided** +**Toupdatetheprojectwithminorchangesprovided** -See that for each KubeBuilder release the plugins versions used to scaffold -the projects might have bug fixes and new incremental features added to the -templates which will result in changes to the files that are generated by -the tool for new projects. +SeethatforeachKubeBuilderreleasethepluginsversionsusedtoscaffold +theprojectsmighthavebugfixesandnewincrementalfeaturesaddedtothe +templateswhichwillresultinchangestothefilesthataregeneratedby +thetoolfornewprojects. -In this case, you used previously the tool to generate the project -and now would like to update your project with the latest changes -provided for the same plugin version. Therefore, you will need to: +Inthiscase,youusedpreviouslythetooltogeneratetheproject +andnowwouldliketoupdateyourprojectwiththelatestchanges +providedforthesamepluginversion.Therefore,youwillneedto: -- Download and install KubeBuilder binary ( latest / upper release ) -- You will run the command in the root directory of your project: `kubebuilder alpha generate` -- Then, the command will remove the content of your local directory and re-scaffold the project from the scratch -- It will allow you to compare your local branch with the remote branch of your project to re-add the code on top OR - if you do not use the flag `--no-backup` then you can compare the local directory with the copy of your project - copied to the path `.backup/project-name/` before the re-scaffold be done. -- Therefore, you can run make all and test the final result. You will have after all your project updated. +-DownloadandinstallKubeBuilderbinary(latest/upperrelease) +-Youwillrunthecommandintherootdirectoryofyourproject:`kubebuilderalphagenerate` +-Then,thecommandwillremovethecontentofyourlocaldirectoryandre-scaffoldtheprojectfromthescratch +-Itwillallowyoutocompareyourlocalbranchwiththeremotebranchofyourprojecttore-addthecodeontopOR +ifyoudonotusetheflag`--no-backup`thenyoucancomparethelocaldirectorywiththecopyofyourproject +copiedtothepath`.backup/project-name/`beforethere-scaffoldbedone. +-Therefore,youcanrunmakeallandtestthefinalresult.Youwillhaveafterallyourprojectupdated. -**To update the project with major changes provided** +**Toupdatetheprojectwithmajorchangesprovided** -In this case, you are looking for to migrate the project from, for example, -`go/v3` to `go/v4`. The steps are very similar to the above ones. However, -in this case you need to inform the plugin that you want to use to do the scaffold -from scratch `kubebuilder alpha generate --plugins=go/v4`. +Inthiscase,youarelookingfortomigratetheprojectfrom,forexample, +`go/v3`to`go/v4`.Thestepsareverysimilartotheaboveones.However, +inthiscaseyouneedtoinformthepluginthatyouwanttousetodothescaffold +fromscratch`kubebuilderalphagenerate--plugins=go/v4`. -## Open Questions +##OpenQuestions N/A -## Summary +##Summary -Therefore, a new command can be designed to load user configs from the [PROJECT config][project-config] file, and run the corresponding kubebuilder subcommands to generate the project based on the new kubebuilder version. Thus, it makes it easier for the users to migrate their operator projects to the new scaffolding. +Therefore,anewcommandcanbedesignedtoloaduserconfigsfromthe[PROJECTconfig][project-config]file,andrunthecorrespondingkubebuildersubcommandstogeneratetheprojectbasedonthenewkubebuilderversion.Thus,itmakesiteasierfortheuserstomigratetheiroperatorprojectstothenewscaffolding. -## Motivation +##Motivation -A common scenario is to upgrade the project based on the newer Kubebuilder. The recommended (straightforward) steps are: +AcommonscenarioistoupgradetheprojectbasedonthenewerKubebuilder.Therecommended(straightforward)stepsare: -- a) re-scaffold all files from scratch using the upper version/plugins -- b) copy user-defined source code to the new layout +-a)re-scaffoldallfilesfromscratchusingtheupperversion/plugins +-b)copyuser-definedsourcecodetothenewlayout -The proposed command will automate the process at maximum, therefore helping operator authors with minimizing the manual effort. +Theproposedcommandwillautomatetheprocessatmaximum,thereforehelpingoperatorauthorswithminimizingthemanualeffort. -The main motivation of this proposal is to provide a helper for upgrades and -make less painful this process. Examples: +Themainmotivationofthisproposalistoprovideahelperforupgradesand +makelesspainfulthisprocess.Examples: -- See the discussion [How to regenerate scaffolding?](https://github.com/kubernetes-sigs/kubebuilder/discussions/2864) -- From [slack channel By Paul Laffitte](https://kubernetes.slack.com/archives/CAR30FCJZ/p1675166014762669) +-Seethediscussion[Howtoregeneratescaffolding?](https://github.com/kubernetes-sigs/kubebuilder/discussions/2864) +-From[slackchannelByPaulLaffitte](https://kubernetes.slack.com/archives/CAR30FCJZ/p1675166014762669) -### Goals +###Goals -- Help users upgrade their project with the latest changes -- Help users to re-scaffold projects from scratch based on what was done previously with the tool -- Make less painful the process to upgrade +-Helpusersupgradetheirprojectwiththelatestchanges +-Helpuserstore-scaffoldprojectsfromscratchbasedonwhatwasdonepreviouslywiththetool +-Makelesspainfultheprocesstoupgrade -### Non-Goals +###Non-Goals -- Change the default layout or how the KubeBuilder CLI works -- Deal with customizations or deviations from the proposed layout -- Be able to perform the project upgrade to the latest changes without human interactions -- Deal and support external plugins -- Provides support to [declarative](https://book.kubebuilder.io/plugins/declarative-v1.html) plugin - since it is desired and planned to decouple this solution and donate this plugin to its own authors [More info](https://github.com/kubernetes-sigs/kubebuilder/issues/3186) -- Provide support to older version before having the Project config (Kubebuilder < 3x) and the go/v2 layout which exists to ensure a backwards compatibility with legacy layout provided by Kubebuilder 2x +-ChangethedefaultlayoutorhowtheKubeBuilderCLIworks +-Dealwithcustomizationsordeviationsfromtheproposedlayout +-Beabletoperformtheprojectupgradetothelatestchangeswithouthumaninteractions +-Dealandsupportexternalplugins +-Providessupportto[declarative](https://book.kubebuilder.io/plugins/declarative-v1.html)plugin +sinceitisdesiredandplannedtodecouplethissolutionanddonatethisplugintoitsownauthors[Moreinfo](https://github.com/kubernetes-sigs/kubebuilder/issues/3186) +-ProvidesupporttoolderversionbeforehavingtheProjectconfig(Kubebuilder<3x)andthego/v2layoutwhichexiststoensureabackwardscompatibilitywithlegacylayoutprovidedbyKubebuilder2x -## Proposal +##Proposal -The proposed solution to achieve this goal is to create an alpha command as described -in the example section above, see: +Theproposedsolutiontoachievethisgoalistocreateanalphacommandasdescribed +intheexamplesectionabove,see: ```shell -kubebuilder alpha generate \ - --input-dir= - --output-dir= - --no-backup - --backup-path= - --plugins= +kubebuilderalphagenerate\ +--input-dir= +--output-dir= +--no-backup +--backup-path= +--plugins= ``` **Where**: -- input-dir: [Optional] If not informed, then, by default, it is the current directory (project directory). If the `PROJECT` file does not exist, it will fail. -- output-dir: [Optional] If not informed then, it should be the current repository. -- no-backup: [Optional] If not informed then, the current directory should be copied to the path `.backup/project-name` -- backup: [Optional] If not informed then, the backup will be copied to the path `.backup/project-name` -- plugins: [Optional] If not informed then, it is the same plugin chain available in the layout field -- binary: [Optional] If not informed then, the command will use KubeBuilder binary installed globaly. +-input-dir:[Optional]Ifnotinformed,then,bydefault,itisthecurrentdirectory(projectdirectory).Ifthe`PROJECT`filedoesnotexist,itwillfail. +-output-dir:[Optional]Ifnotinformedthen,itshouldbethecurrentrepository. +-no-backup:[Optional]Ifnotinformedthen,thecurrentdirectoryshouldbecopiedtothepath`.backup/project-name` +-backup:[Optional]Ifnotinformedthen,thebackupwillbecopiedtothepath`.backup/project-name` +-plugins:[Optional]Ifnotinformedthen,itisthesamepluginchainavailableinthelayoutfield +-binary:[Optional]Ifnotinformedthen,thecommandwilluseKubeBuilderbinaryinstalledglobaly. -> Note that the backup created in the current directory must be prefixed with `.`. Otherwise the tool -will not able to perform the scaffold to create a new project from the scratch. +>Notethatthebackupcreatedinthecurrentdirectorymustbeprefixedwith`.`.Otherwisethetool +willnotabletoperformthescaffoldtocreateanewprojectfromthescratch. -This command would mainly perform the following operations: +Thiscommandwouldmainlyperformthefollowingoperations: -- 1. Check the flags -- 2. If the backup flag be used, then check if is a valid path and make a backup of the current project -- 3. Copy the whole current directory to `.backup/project-name` -- 4. Ensure that the output path is clean. By default it is the current directory project where the project was scaffolded previously and it should be cleaned up before to do the re-scaffold. -Only the content under `.backup/project-name` should be kept. -- 4. Read the [PROJECT config][project-config] -- 5. Re-run all commands using the KubeBuilder binary to recreate the project in the output directory +-1.Checktheflags +-2.Ifthebackupflagbeused,thencheckifisavalidpathandmakeabackupofthecurrentproject +-3.Copythewholecurrentdirectoryto`.backup/project-name` +-4.Ensurethattheoutputpathisclean.Bydefaultitisthecurrentdirectoryprojectwheretheprojectwasscaffoldedpreviouslyanditshouldbecleanedupbeforetodothere-scaffold. +Onlythecontentunder`.backup/project-name`shouldbekept. +-4.Readthe[PROJECTconfig][project-config] +-5.Re-runallcommandsusingtheKubeBuilderbinarytorecreatetheprojectintheoutputdirectory -The command should also provide a comprensive help with examples of the proposed workflows. So that, users -are able to understand how to use it when run `--help`. +Thecommandshouldalsoprovideacomprensivehelpwithexamplesoftheproposedworkflows.Sothat,users +areabletounderstandhowtouseitwhenrun`--help`. -### User Stories +###UserStories -**As an Operator author:** +**AsanOperatorauthor:** -- I can re-generate my project from scratch based on the proposed helper, which executes all the -commands according to my previous input to the project. That way, I can easily migrate my project to the new layout -using the newer CLI/plugin versions, which support the latest changes, bug fixes, and features. -- I can regenerate my project from the scratch based on all commands that I used the tool to build -my project previously but informing a new init plugin chain, so that I could upgrade my current project to new -layout versions and experiment alpha ones. -- I would like to re-generate the project from the scratch using the same config provide in the PROJECT file and inform -a path to do a backup of my current directory so that I can also use the backup to compare with the new scaffold and add my custom code -on top again without the need to compare my local directory and new scaffold with any outside source. +-Icanre-generatemyprojectfromscratchbasedontheproposedhelper,whichexecutesallthe +commandsaccordingtomypreviousinputtotheproject.Thatway,Icaneasilymigratemyprojecttothenewlayout +usingthenewerCLI/pluginversions,whichsupportthelatestchanges,bugfixes,andfeatures. +-IcanregeneratemyprojectfromthescratchbasedonallcommandsthatIusedthetooltobuild +myprojectpreviouslybutinforminganewinitpluginchain,sothatIcouldupgrademycurrentprojecttonew +layoutversionsandexperimentalphaones. +-Iwouldliketore-generatetheprojectfromthescratchusingthesameconfigprovideinthePROJECTfileandinform +apathtodoabackupofmycurrentdirectorysothatIcanalsousethebackuptocomparewiththenewscaffoldandaddmycustomcode +ontopagainwithouttheneedtocomparemylocaldirectoryandnewscaffoldwithanyoutsidesource. -**As a Kubebuiler maintainer:** +**AsaKubebuilermaintainer:** -- I can leverage this helper to easily migrate tutorial projects of the Kubebuilder book. -- I can leverage on this helper to encourage its users to migrate to upper versions more often, making it easier to maintain the project. +-IcanleveragethishelpertoeasilymigratetutorialprojectsoftheKubebuilderbook. +-Icanleverageonthishelpertoencourageitsuserstomigratetoupperversionsmoreoften,makingiteasiertomaintaintheproject. -### Implementation Details/Notes/Constraints +###ImplementationDetails/Notes/Constraints -Note that in the [e2e tests](https://github.com/kubernetes-sigs/kubebuilder/tree/master/test/e2e) the binary is used to do the scaffolds. -Also, very similar to the implementation that exist in the integration test KubeBuilder has -a code implementation to re-generate the samples used in the docs and add customizations on top, -for further information check the [hack/docs](https://github.com/kubernetes-sigs/kubebuilder/tree/master/hack/docs). +Notethatinthe[e2etests](https://github.com/kubernetes-sigs/kubebuilder/tree/master/test/e2e)thebinaryisusedtodothescaffolds. +Also,verysimilartotheimplementationthatexistintheintegrationtestKubeBuilderhas +acodeimplementationtore-generatethesamplesusedinthedocsandaddcustomizationsontop, +forfurtherinformationcheckthe[hack/docs](https://github.com/kubernetes-sigs/kubebuilder/tree/master/hack/docs). -This subcommand could have a similar implementation that could be used by the tests and this plugin. -Note that to run the commands using the binaries we are mainly using the following golang implementation: +Thissubcommandcouldhaveasimilarimplementationthatcouldbeusedbythetestsandthisplugin. +Notethattorunthecommandsusingthebinarieswearemainlyusingthefollowinggolangimplementation: ```go -cmd := exec.Command(t.BinaryName, Options) -_, err := t.Run(cmd) +cmd:=exec.Command(t.BinaryName,Options) +_,err:=t.Run(cmd) ``` -### Risks and Mitigations +###RisksandMitigations -**Hard to keep the command maintained** +**Hardtokeepthecommandmaintained** -A risk to consider is that it would be hard to keep this command maintained -because we need to develop specific code operations for each plugin. The mitigation for -this problem could be developing a design more generic that could work with all plugins. +Arisktoconsideristhatitwouldbehardtokeepthiscommandmaintained +becauseweneedtodevelopspecificcodeoperationsforeachplugin.Themitigationfor +thisproblemcouldbedevelopingadesignmoregenericthatcouldworkwithallplugins. -However, initially a more generic design implementation does not appear to be achievable and -would be considered out of the scope of this proposal (no goal). It should to be considered -as a second phase of this implementation. +However,initiallyamoregenericdesignimplementationdoesnotappeartobeachievableand +wouldbeconsideredoutofthescopeofthisproposal(nogoal).Itshouldtobeconsidered +asasecondphaseofthisimplementation. -Therefore, the current achievable mitigation in place is that KubeBuilder's policy of not providing official -support of maintaining and distributing many plugins. +Therefore,thecurrentachievablemitigationinplaceisthatKubeBuilder'spolicyofnotprovidingofficial +supportofmaintaininganddistributingmanyplugins. -### Proof of Concept +###ProofofConcept -All input data is tracked. Also, as described above we have examples of code implementation -that uses the binary to scaffold the projects. Therefore, the goal of this project seems -very reasonable and achievable. An initial work to try to address this requirement can -be checked in this [pull request](https://github.com/kubernetes-sigs/kubebuilder/pull/3022) +Allinputdataistracked.Also,asdescribedabovewehaveexamplesofcodeimplementation +thatusesthebinarytoscaffoldtheprojects.Therefore,thegoalofthisprojectseems +veryreasonableandachievable.Aninitialworktotrytoaddressthisrequirementcan +becheckedinthis[pullrequest](https://github.com/kubernetes-sigs/kubebuilder/pull/3022) -## Drawbacks +##Drawbacks -- If the value that feature provides does not pay off the effort to keep it - maintained, then we would need to deprecate and remove the feature in the long term. +-Ifthevaluethatfeatureprovidesdoesnotpayofftheefforttokeepit +maintained,thenwewouldneedtodeprecateandremovethefeatureinthelongterm. -## Alternatives +##Alternatives N/A -## Implementation History +##ImplementationHistory -The idea of automate the re-scaffold of the project is what motivates -us track all input data in to the [project config][project-config] -in the past. We also tracked the [issue](https://github.com/kubernetes-sigs/kubebuilder/issues/2068) -based on discussion that we have to indeed try to add further -specific implementations to do operations per major bumps. For example: +Theideaofautomatethere-scaffoldoftheprojectiswhatmotivates +ustrackallinputdataintothe[projectconfig][project-config] +inthepast.Wealsotrackedthe[issue](https://github.com/kubernetes-sigs/kubebuilder/issues/2068) +basedondiscussionthatwehavetoindeedtrytoaddfurther +specificimplementationstodooperationspermajorbumps.Forexample: -To upgrade from go/v3 to go/v4 we know exactly what are the changes in the layout -then, we could automate these specific operations as well. However, this first idea is harder yet -to be addressed and maintained. +Toupgradefromgo/v3togo/v4weknowexactlywhatarethechangesinthelayout +then,wecouldautomatethesespecificoperationsaswell.However,thisfirstideaisharderyet +tobeaddressedandmaintained. -## Future Vision +##FutureVision -We could use it to do cool future features such as creating a GitHub action which would push-pull requests against the project repositories to help users be updated with, for example, minor changes. By using this command, we might able to git clone the project and to do a new scaffold and then use some [git strategy merge](https://www.geeksforgeeks.org/merge-strategies-in-git/) to result in a PR to purpose the required changes. +WecoulduseittodocoolfuturefeaturessuchascreatingaGitHubactionwhichwouldpush-pullrequestsagainsttheprojectrepositoriestohelpusersbeupdatedwith,forexample,minorchanges.Byusingthiscommand,wemightabletogitclonetheprojectandtodoanewscaffoldandthenusesome[gitstrategymerge](https://www.geeksforgeeks.org/merge-strategies-in-git/)toresultinaPRtopurposetherequiredchanges. -We probably need to store the CLI tool tag release used to do the scaffold to persuade this idea. So that we can know if the project requires updates or not. +WeprobablyneedtostoretheCLItooltagreleaseusedtodothescaffoldtopersuadethisidea.Sothatwecanknowiftheprojectrequiresupdatesornot. -[project-config]: https://book.kubebuilder.io/reference/project-config.html +[project-config]:https://book.kubebuilder.io/reference/project-config.html diff --git a/designs/integrating-kubebuilder-and-osdk.md b/designs/integrating-kubebuilder-and-osdk.md index df4ec362cc8..51a2c343d43 100644 --- a/designs/integrating-kubebuilder-and-osdk.md +++ b/designs/integrating-kubebuilder-and-osdk.md @@ -1,47 +1,47 @@ -| Authors | Creation Date | Status | Extra | +|Authors|CreationDate|Status|Extra| |---------------|---------------|-------------|-------| -| @joelanford | Sep 6, 2019 | implemented | - | +|@joelanford|Sep6,2019|implemented|-| -Integrating Kubebuilder and Operator SDK +IntegratingKubebuilderandOperatorSDK ======================================== -## Goal +##Goal -To unite Kubebuilder and Operator SDK around Kubebuilder’s project scaffolding, to move Operator SDK’s Go operator features upstream, where appropriate, and to join forces on maintaining Kubebuilder so that both Kubebuilder and Operator SDK support the same project structure and command line interface for Go-based operators. +TouniteKubebuilderandOperatorSDKaroundKubebuilder’sprojectscaffolding,tomoveOperatorSDK’sGooperatorfeaturesupstream,whereappropriate,andtojoinforcesonmaintainingKubebuildersothatbothKubebuilderandOperatorSDKsupportthesameprojectstructureandcommandlineinterfaceforGo-basedoperators. -## Background +##Background -Kubebuilder and [Operator SDK][operator-sdk] are similar projects meant to simplify the process of building a Kubernetes operator (or controller). Both projects make extensive use of the upstream controller-runtime and controller-tools projects, and therefore scaffold similar Go source files and package structures. +Kubebuilderand[OperatorSDK][operator-sdk]aresimilarprojectsmeanttosimplifytheprocessofbuildingaKubernetesoperator(orcontroller).Bothprojectsmakeextensiveuseoftheupstreamcontroller-runtimeandcontroller-toolsprojects,andthereforescaffoldsimilarGosourcefilesandpackagestructures. -## Motivation +##Motivation -The Operator SDK and Kubebuilder contributors collaborate on improvements to their shared upstream dependencies, but there is significant overlap between Operator SDK and Kubebuilder related to scaffolding Go operators. Both projects have commands to initialize a new project and add boilerplate implementations of new APIs and controllers. +TheOperatorSDKandKubebuildercontributorscollaborateonimprovementstotheirsharedupstreamdependencies,butthereissignificantoverlapbetweenOperatorSDKandKubebuilderrelatedtoscaffoldingGooperators.BothprojectshavecommandstoinitializeanewprojectandaddboilerplateimplementationsofnewAPIsandcontrollers. -The motivation for integrating Kubebuilder and Operator SDK is that rather than duplicating work related to project scaffolding of Go operators, the projects could work together on one implementation, which would speed up progress and likely result in a more general solution. +ThemotivationforintegratingKubebuilderandOperatorSDKisthatratherthanduplicatingworkrelatedtoprojectscaffoldingofGooperators,theprojectscouldworktogetherononeimplementation,whichwouldspeedupprogressandlikelyresultinamoregeneralsolution. -## Integration Plan +##IntegrationPlan -The Kubebuilder and Operator SDK contributors created a [GitHub project][kb-osdk-github-project] to track the work necessary to align the projects. There are three main themes. +TheKubebuilderandOperatorSDKcontributorscreateda[GitHubproject][kb-osdk-github-project]totracktheworknecessarytoaligntheprojects.Therearethreemainthemes. -### Upstream code from Operator SDK +###UpstreamcodefromOperatorSDK -The Operator SDK project contains various features that can be used by Go operator developers regardless of whether the project is based on Kubebuilder or Operator SDK. These features will be upstreamed into `kubebuilder`, `controller-runtime`, and `controller-tools`, where appropriate. These include: -* a `DynamicRESTMapper` that enables an operator to dynamically and automatically discover new CRDs added to the cluster after the operator has started -* a `GenerationChangedPredicate` that can trigger reconciliation events when a resource's `metadata.generation` field has changed. -* flags and helpers that can be used to provide more fine-grained configuration when constructing the default `zap`-based logger. +TheOperatorSDKprojectcontainsvariousfeaturesthatcanbeusedbyGooperatordevelopersregardlessofwhethertheprojectisbasedonKubebuilderorOperatorSDK.Thesefeatureswillbeupstreamedinto`kubebuilder`,`controller-runtime`,and`controller-tools`,whereappropriate.Theseinclude: +*a`DynamicRESTMapper`thatenablesanoperatortodynamicallyandautomaticallydiscovernewCRDsaddedtotheclusteraftertheoperatorhasstarted +*a`GenerationChangedPredicate`thatcantriggerreconciliationeventswhenaresource's`metadata.generation`fieldhaschanged. +*flagsandhelpersthatcanbeusedtoprovidemorefine-grainedconfigurationwhenconstructingthedefault`zap`-basedlogger. -The Operator SDK contributors plan to begin conducting all development of Go operator related code in upstream Kubebuilder (and related projects) and to spend more time helping the Kubebuilder contributors maintain these projects. +TheOperatorSDKcontributorsplantobeginconductingalldevelopmentofGooperatorrelatedcodeinupstreamKubebuilder(andrelatedprojects)andtospendmoretimehelpingtheKubebuildercontributorsmaintaintheseprojects. -### Prototypes +###Prototypes -To make Kubebuilder more extensible, the community has been discussing a proposal to add extension points to Kubebuilder to support different operator patterns. One example of an operator pattern is the [addon pattern][addon-pattern-pr] that uses an existing library to instantiate an opinionated API and controller. +TomakeKubebuildermoreextensible,thecommunityhasbeendiscussingaproposaltoaddextensionpointstoKubebuildertosupportdifferentoperatorpatterns.Oneexampleofanoperatorpatternisthe[addonpattern][addon-pattern-pr]thatusesanexistinglibrarytoinstantiateanopinionatedAPIandcontroller. -More broadly, the idea is to add support for executable plugin-based extensions that can modify Kubebuilder’s base scaffolding before files are written to disk so that the project (e.g. Go code, kustomize templates, the project Makefile and Dockerfile) can have customized content provided by an extension. +Morebroadly,theideaistoaddsupportforexecutableplugin-basedextensionsthatcanmodifyKubebuilder’sbasescaffoldingbeforefilesarewrittentodisksothattheproject(e.g.Gocode,kustomizetemplates,theprojectMakefileandDockerfile)canhavecustomizedcontentprovidedbyanextension. -### Documentation +###Documentation -Operator SDK and Kubebuilder currently maintain separate documentation even though a significant chunk of it overlaps. By combining efforts, the SDK contributors will migrate and integrate their Go-based operator documentation upstream into the Kubebuilder documentation and join the Kubebuilder contributors in keeping it up-to-date. +OperatorSDKandKubebuildercurrentlymaintainseparatedocumentationeventhoughasignificantchunkofitoverlaps.Bycombiningefforts,theSDKcontributorswillmigrateandintegratetheirGo-basedoperatordocumentationupstreamintotheKubebuilderdocumentationandjointheKubebuildercontributorsinkeepingitup-to-date. -[operator-sdk]: https://github.com/operator-framework/operator-sdk -[kb-osdk-github-project]: https://github.com/kubernetes-sigs/kubebuilder/projects/7 -[addon-pattern-pr]: https://github.com/kubernetes-sigs/kubebuilder/pull/943 +[operator-sdk]:https://github.com/operator-framework/operator-sdk +[kb-osdk-github-project]:https://github.com/kubernetes-sigs/kubebuilder/projects/7 +[addon-pattern-pr]:https://github.com/kubernetes-sigs/kubebuilder/pull/943 diff --git a/designs/simplified-scaffolding.md b/designs/simplified-scaffolding.md index bdbacaa8d8f..2a9fa5eb20d 100644 --- a/designs/simplified-scaffolding.md +++ b/designs/simplified-scaffolding.md @@ -1,393 +1,393 @@ -| Authors | Creation Date | Status | Extra | +|Authors|CreationDate|Status|Extra| |---------------|---------------|-------------|---| -| @DirectXMan12 | Mar 6, 2019 | Implemented | - | +|@DirectXMan12|Mar6,2019|Implemented|-| -Simplified Builder-Based Scaffolding +SimplifiedBuilder-BasedScaffolding ==================================== -## Background +##Background -The current scaffolding in kubebuilder produces a directory structure that -looks something like this (compiled artifacts like config omitted for +Thecurrentscaffoldinginkubebuilderproducesadirectorystructurethat +lookssomethinglikethis(compiledartifactslikeconfigomittedfor brevity):
-`tree -d ./test/project` +`tree-d./test/project` ```shell -$ tree -d ./test/project +$tree-d./test/project ./test/project -├── cmd -│   └── manager -├── pkg -│   ├── apis -│   │   ├── creatures -│   │   │   └── v2alpha1 -│   │   ├── crew -│   │   │   └── v1 -│   │   ├── policy -│   │   │   └── v1beta1 -│   │   └── ship -│   │   └── v1beta1 -│   ├── controller -│   │   ├── firstmate -│   │   ├── frigate -│   │   ├── healthcheckpolicy -│   │   ├── kraken -│   │   └── namespace -│   └── webhook -│   └── default_server -│   ├── firstmate -│   │   └── mutating -│   ├── frigate -│   │   └── validating -│   ├── kraken -│   │   └── validating -│   └── namespace -│   └── mutating -└── vendor +├──cmd +│└──manager +├──pkg +│├──apis +││├──creatures +│││└──v2alpha1 +││├──crew +│││└──v1 +││├──policy +│││└──v1beta1 +││└──ship +││└──v1beta1 +│├──controller +││├──firstmate +││├──frigate +││├──healthcheckpolicy +││├──kraken +││└──namespace +│└──webhook +│└──default_server +│├──firstmate +││└──mutating +│├──frigate +││└──validating +│├──kraken +││└──validating +│└──namespace +│└──mutating +└──vendor ```
-API packages have a separate file for each API group that creates a SchemeBuilder, -a separate file to aggregate those scheme builders together, plus files for types, -and the per-group-version scheme builders as well: +APIpackageshaveaseparatefileforeachAPIgroupthatcreatesaSchemeBuilder, +aseparatefiletoaggregatethoseschemebuilderstogether,plusfilesfortypes, +andtheper-group-versionschemebuildersaswell:
-`tree ./test/project/pkg/apis` +`tree./test/project/pkg/apis` ```shell -$ ./test/project/pkg/apis -├── addtoscheme_creatures_v2alpha1.go -├── apis.go -├── creatures -│   ├── group.go -│   └── v2alpha1 -│   ├── doc.go -│   ├── kraken_types.go -│   ├── kraken_types_test.go -│   ├── register.go -│   ├── v2alpha1_suite_test.go -│   └── zz_generated.deepcopy.go +$./test/project/pkg/apis +├──addtoscheme_creatures_v2alpha1.go +├──apis.go +├──creatures +│├──group.go +│└──v2alpha1 +│├──doc.go +│├──kraken_types.go +│├──kraken_types_test.go +│├──register.go +│├──v2alpha1_suite_test.go +│└──zz_generated.deepcopy.go ... ```
-Controller packages have a separate file that registers each controller with a global list -of controllers, a file that provides functionality to register that list with a manager, -as well as a file that constructs the individual controller itself: +Controllerpackageshaveaseparatefilethatregisterseachcontrollerwithagloballist +ofcontrollers,afilethatprovidesfunctionalitytoregisterthatlistwithamanager, +aswellasafilethatconstructstheindividualcontrolleritself:
-`tree ./test/project/pkg/controller` +`tree./test/project/pkg/controller` ```shell -$ tree ./test/project/pkg/controller +$tree./test/project/pkg/controller ./test/project/pkg/controller -├── add_firstmate.go -├── controller.go -├── firstmate -│   ├── firstmate_controller.go -│   ├── firstmate_controller_suite_test.go -│   └── firstmate_controller_test.go +├──add_firstmate.go +├──controller.go +├──firstmate +│├──firstmate_controller.go +│├──firstmate_controller_suite_test.go +│└──firstmate_controller_test.go ... ```
-## Motivation - -The current scaffolding in Kubebuilder has two main problems: -comprehensibility and dependency passing. - -### Complicated Initial Structure - -While the structure of Kubebuilder projects will likely feel at home for -existing Kubernetes contributors (since it matches the structure of -Kubernetes itself quite closely), it provides a fairly convoluted -experience out of the box. - -Even for a single controller and API type (without a webhook), it -generates 8 API-related files and 5 controller-related files. Of those -files, 6 are Kubebuilder-specific glue code, 4 are test setup, and -1 contains standard Kubernetes glue code, leaving only 2 with actual -user-edited code. - -This proliferation of files makes it difficult for users to understand how -their code relates to the library, posing some barrier for initial adoption -and moving beyond a basic knowledge of functionality to actual -understanding of the structure. A common line of questioning amongst -newcomers to Kubebuilder includes "where should I put my code that adds -new types to a scheme" (and similar questions), which indicates that it's -not immediately obvious to these users why the project is structured the -way it is. - -Additionally, we scaffold out API "tests" that test that the API server is -able to receive create requests for the objects, but don't encourage -modification beyond that. An informal survey seems to indicate that most -users don't actually modify these tests (many repositories continue to -look like +##Motivation + +ThecurrentscaffoldinginKubebuilderhastwomainproblems: +comprehensibilityanddependencypassing. + +###ComplicatedInitialStructure + +WhilethestructureofKubebuilderprojectswilllikelyfeelathomefor +existingKubernetescontributors(sinceitmatchesthestructureof +Kubernetesitselfquiteclosely),itprovidesafairlyconvoluted +experienceoutofthebox. + +EvenforasinglecontrollerandAPItype(withoutawebhook),it +generates8API-relatedfilesand5controller-relatedfiles.Ofthose +files,6areKubebuilder-specificgluecode,4aretestsetup,and +1containsstandardKubernetesgluecode,leavingonly2withactual +user-editedcode. + +Thisproliferationoffilesmakesitdifficultforuserstounderstandhow +theircoderelatestothelibrary,posingsomebarrierforinitialadoption +andmovingbeyondabasicknowledgeoffunctionalitytoactual +understandingofthestructure.Acommonlineofquestioningamongst +newcomerstoKubebuilderincludes"whereshouldIputmycodethatadds +newtypestoascheme"(andsimilarquestions),whichindicatesthatit's +notimmediatelyobvioustotheseuserswhytheprojectisstructuredthe +wayitis. + +Additionally,wescaffoldoutAPI"tests"thattestthattheAPIserveris +abletoreceivecreaterequestsfortheobjects,butdon'tencourage +modificationbeyondthat.Aninformalsurveyseemstoindicatethatmost +usersdon'tactuallymodifythesetests(manyrepositoriescontinueto +looklike [this](https://github.com/replicatedhq/gatekeeper/blob/3bfe0f7213b6d41abf2df2a6746f3351e709e6ff/pkg/apis/policies/v1alpha2/admissionpolicy_types_test.go)). -If we want to help users test that their object's structure is the way -they think it is, we're probably better served coming up with a standard -"can I create this example YAML file". +Ifwewanttohelpuserstestthattheirobject'sstructureistheway +theythinkitis,we'reprobablybetterservedcomingupwithastandard +"canIcreatethisexampleYAMLfile". -Furthermore, since the structure is quite convoluted, it makes it more -difficult to write examples, since the actual code we care about ends up -scattered deep in a folder structure. +Furthermore,sincethestructureisquiteconvoluted,itmakesitmore +difficulttowriteexamples,sincetheactualcodewecareaboutendsup +scattereddeepinafolderstructure. -### Lack of Builder +###LackofBuilder -We introduced the builder pattern for controller construction in +Weintroducedthebuilderpatternforcontrollerconstructionin controller-runtime ([GoDoc](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/builder?tab=doc#ControllerManagedBy)) -as a way to simplify construction of controllers and reduce boilerplate -for the common cases of controller construction. Informal feedback from -this has been positive, and it enables fairly rapid, clear, and concise -construction of controllers (e.g. this [one file +asawaytosimplifyconstructionofcontrollersandreduceboilerplate +forthecommoncasesofcontrollerconstruction.Informalfeedbackfrom +thishasbeenpositive,anditenablesfairlyrapid,clear,andconcise +constructionofcontrollers(e.g.this[onefile controller](https://github.com/DirectXMan12/sample-controller/blob/workshop/main.go) -used as a getting started example for a workshop). +usedasagettingstartedexampleforaworkshop). -Current Kubebuilder scaffolding does not take advantage of the builder, -leaving generated code using the lower-level constructs which require more -understanding of the internals of controller-runtime to comprehend. +CurrentKubebuilderscaffoldingdoesnottakeadvantageofthebuilder, +leavinggeneratedcodeusingthelower-levelconstructswhichrequiremore +understandingoftheinternalsofcontroller-runtimetocomprehend. -### Dependency Passing Woes +###DependencyPassingWoes -Another common line of questioning amongst Kubebuilder users is "how to -I pass dependencies to my controllers?". This ranges from "how to I pass -custom clients for the software I'm running" to "how to I pass -configuration from files and flags down to my controllers" (e.g. +AnothercommonlineofquestioningamongstKubebuilderusersis"howto +Ipassdependenciestomycontrollers?".Thisrangesfrom"howtoIpass +customclientsforthesoftwareI'mrunning"to"howtoIpass +configurationfromfilesandflagsdowntomycontrollers"(e.g. [kubernete-sigs/kubebuilder#611](https://github.com/kubernetes-sigs/kubebuilder/issues/611) -Since reconciler implementations are initialized in `Add` methods with -standard signatures, dependencies cannot be passed directly to -reconcilers. This has lead to requests for dependency injection in -controller-runtime (e.g. +Sincereconcilerimplementationsareinitializedin`Add`methodswith +standardsignatures,dependenciescannotbepasseddirectlyto +reconcilers.Thishasleadtorequestsfordependencyinjectionin +controller-runtime(e.g. [kubernetes-sigs/controller-runtime#102](https://github.com/kubernetes-sigs/controller-runtime/issues/102)), -but in most cases, a structure more amicable to passing in the -dependencies directly would solve the issue (as noted in +butinmostcases,astructuremoreamicabletopassinginthe +dependenciesdirectlywouldsolvetheissue(asnotedin [kubernetes-sigs/controller-runtime#182](https://github.com/kubernetes-sigs/controller-runtime/pull/182#issuecomment-442615175)). -## Revised Structure +##RevisedStructure -In the revised structure, we use the builder pattern to focus on the -"code-refactor-code-refactor" cycle: start out with a simple structure, -refactor out as your project becomes more complicated. +Intherevisedstructure,weusethebuilderpatterntofocusonthe +"code-refactor-code-refactor"cycle:startoutwithasimplestructure, +refactoroutasyourprojectbecomesmorecomplicated. -Users receive a simply scaffolded structure to start. Simple projects can -remain relatively simple, and complicated projects can decide to adopt -a different structure as they grow. +Usersreceiveasimplyscaffoldedstructuretostart.Simpleprojectscan +remainrelativelysimple,andcomplicatedprojectscandecidetoadopt +adifferentstructureastheygrow. -The new scaffold project structure looks something like this (compiled -artifacts like config omitted for brevity): +Thenewscaffoldprojectstructurelookssomethinglikethis(compiled +artifactslikeconfigomittedforbrevity): ```shell -$ tree ./test/project +$tree./test/project ./test/project -├── main.go -├── controller -│   ├── mykind_controller.go -│   ├── mykind_controller_test.go -│   └── controllers_suite_test.go -├── api -│ └── v1 -│   └── mykind_types.go -│   └── groupversion_info.go -└── vendor +├──main.go +├──controller +│├──mykind_controller.go +│├──mykind_controller_test.go +│└──controllers_suite_test.go +├──api +│└──v1 +│└──mykind_types.go +│└──groupversion_info.go +└──vendor ``` -In this new layout, `main.go` constructs the reconciler: +Inthisnewlayout,`main.go`constructsthereconciler: ```go -// ... -func main() { - // ... - err := (&controllers.MyReconciler{ - MySuperSpecialAppClient: doSomeThingsWithFlags(), - }).SetupWithManager(mgr) - // ... +//... +funcmain(){ +//... +err:=(&controllers.MyReconciler{ +MySuperSpecialAppClient:doSomeThingsWithFlags(), +}).SetupWithManager(mgr) +//... } ``` -while `mykind_controller.go` actually sets up the controller using the +while`mykind_controller.go`actuallysetsupthecontrollerusingthe reconciler: ```go -func (r *MyReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&api.MyAppType{}). - Owns(&corev1.Pod{}). - Complete(r) +func(r*MyReconciler)SetupWithManager(mgrctrl.Manager)error{ +returnctrl.NewControllerManagedBy(mgr). +For(&api.MyAppType{}). +Owns(&corev1.Pod{}). +Complete(r) } ``` -This makes it abundantly clear where to start looking at the code -(`main.go` is the defacto standard entry-point for many go programs), and -simplifies the levels of hierarchy. Furthermore, since `main.go` actually -instantiates an instance of the reconciler, users are able to add custom -logic having to do with flags. +Thismakesitabundantlyclearwheretostartlookingatthecode +(`main.go`isthedefactostandardentry-pointformanygoprograms),and +simplifiesthelevelsofhierarchy.Furthermore,since`main.go`actually +instantiatesaninstanceofthereconciler,usersareabletoaddcustom +logichavingtodowithflags. -Notice that we explicitly construct the reconciler in `main.go`, but put -the setup logic for the controller details in `mykind_controller.go`. This -makes testing easier (see -[below](#put-the-controller-setup-code-in-main-go)), but still allows us -to pass in dependencies from `main`. +Noticethatweexplicitlyconstructthereconcilerin`main.go`,butput +thesetuplogicforthecontrollerdetailsin`mykind_controller.go`.This +makestestingeasier(see +[below](#put-the-controller-setup-code-in-main-go)),butstillallowsus +topassindependenciesfrom`main`. -### Why don't we... +###Whydon'twe... -#### Put the controller setup code in main.go +####Putthecontrollersetupcodeinmain.go -While this is an attractive pattern from a prototyping perspective, it -makes it harder to write integration tests, since you can't easily say -"run this controller with all its setup in processes". With a separate -`SetupWithManager` method associated with reconcile, it becomes fairly -easy to setup with a manager. +Whilethisisanattractivepatternfromaprototypingperspective,it +makesithardertowriteintegrationtests,sinceyoucan'teasilysay +"runthiscontrollerwithallitssetupinprocesses".Withaseparate +`SetupWithManager`methodassociatedwithreconcile,itbecomesfairly +easytosetupwithamanager. -#### Put the types directly under api/, or not have groupversion_info.go +####Putthetypesdirectlyunderapi/,ornothavegroupversion_info.go -These suggestions make it much harder to scaffold out additional versions -and kinds. You need to have each version in a separate package, so that -type names don't conflict. While we could put scheme registration in with -`kind_types.go`, if a project has multiple "significant" Kinds in an API -group, it's not immediately clear which file has the scheme registration. +Thesesuggestionsmakeitmuchhardertoscaffoldoutadditionalversions +andkinds.Youneedtohaveeachversioninaseparatepackage,sothat +typenamesdon'tconflict.Whilewecouldputschemeregistrationinwith +`kind_types.go`,ifaprojecthasmultiple"significant"KindsinanAPI +group,it'snotimmediatelyclearwhichfilehastheschemeregistration. -#### Use a single types.go file +####Useasingletypes.gofile -This works fine when you have a single "major" Kind, but quickly grows -unwieldy when you have multiple major kinds and end up with -a hundreds-of-lines-long `types.go` file (e.g. the `appsv1` API group in -core Kubernetes). Splitting out by "major" Kind (`Deployment`, -`ReplicaSet`, etc) makes the code organization clearer. +Thisworksfinewhenyouhaveasingle"major"Kind,butquicklygrows +unwieldywhenyouhavemultiplemajorkindsandendupwith +ahundreds-of-lines-long`types.go`file(e.g.the`appsv1`APIgroupin +coreKubernetes).Splittingoutby"major"Kind(`Deployment`, +`ReplicaSet`,etc)makesthecodeorganizationclearer. -#### Change the current scaffold to just make Add a method on the reconciler +####ChangethecurrentscaffoldtojustmakeAddamethodonthereconciler -While this solves the dependency issues (mostly, since you might want to -further pass configuration to the setup logic and not just the runtime -logic), it does not solve the underlying pedagogical issues around the -initial structure burying key logic amidst a sprawl of generated files and +Whilethissolvesthedependencyissues(mostly,sinceyoumightwantto +furtherpassconfigurationtothesetuplogicandnotjusttheruntime +logic),itdoesnotsolvetheunderlyingpedagogicalissuesaroundthe +initialstructureburyingkeylogicamidstasprawlofgeneratedfilesand directories. -### Making this work with multiple controllers, API versions, API groups, etc +###Makingthisworkwithmultiplecontrollers,APIversions,APIgroups,etc -#### Versions +####Versions -Most projects will eventually grow multiple API versions. The only -wrinkle here is making sure API versions get added to a scheme. This can -be solved by adding a specially-marked init function that registration -functions get added to (see the example). +MostprojectswilleventuallygrowmultipleAPIversions.Theonly +wrinklehereismakingsureAPIversionsgetaddedtoascheme.Thiscan +besolvedbyaddingaspecially-markedinitfunctionthatregistration +functionsgetaddedto(seetheexample). -#### Groups +####Groups -Some projects eventually grow multiple API groups. Presumably, in the -case of multiple API groups, the desired hierarchy is: +SomeprojectseventuallygrowmultipleAPIgroups.Presumably,inthe +caseofmultipleAPIgroups,thedesiredhierarchyis: ```shell -$ tree ./test/project/api +$tree./test/project/api ./test/project/api -├── groupa -│   └── v1 -│   └── types.go -└── groupb -    └── v1 -    └── types.go +├──groupa +│└──v1 +│└──types.go +└──groupb +└──v1 +└──types.go ``` -There are three options here: +Therearethreeoptionshere: -1. Scaffold with the more complex API structure (this looks pretty close - to what we do today). It doesn't add a ton of complexity, but does - bury types deeper in a directory structure. +1.ScaffoldwiththemorecomplexAPIstructure(thislooksprettyclose +towhatwedotoday).Itdoesn'taddatonofcomplexity,butdoes +burytypesdeeperinadirectorystructure. -2. Try to move things and rename references. This takes a lot more effort - on the Kubebuilder maintainers' part if we try to rename references - across the codebase. Not so much if we force the user to, but that's - a poorer experience. +2.Trytomovethingsandrenamereferences.Thistakesalotmoreeffort +ontheKubebuildermaintainers'partifwetrytorenamereferences +acrossthecodebase.Notsomuchifweforcetheuserto,butthat's +apoorerexperience. -3. Tell users to move things, and scaffold out with the new structure. - This is fairly messy for the user. +3.Telluserstomovethings,andscaffoldoutwiththenewstructure. +Thisisfairlymessyfortheuser. -Since growing to multiple API groups seems to be fairly uncommon, it's -mostly like safe to take a hybrid approach here -- allow manually -specifying the output path, and, when not specified, asking the user to -first restructure before running the command. +SincegrowingtomultipleAPIgroupsseemstobefairlyuncommon,it's +mostlylikesafetotakeahybridapproachhere--allowmanually +specifyingtheoutputpath,and,whennotspecified,askingtheuserto +firstrestructurebeforerunningthecommand. -#### Controllers +####Controllers -Multiple controllers don't need their own package, but we'd want to -scaffold out the builder. We have two options here: +Multiplecontrollersdon'tneedtheirownpackage,butwe'dwantto +scaffoldoutthebuilder.Wehavetwooptionshere: -1. Looking for a particular code comment, and appending a new builder - after it. This is a bit more complicated for us, but perhaps provides - a nicer UX. +1.Lookingforaparticularcodecomment,andappendinganewbuilder +afterit.Thisisabitmorecomplicatedforus,butperhapsprovides +anicerUX. -2. Simply adding a new controller, and reminding the user to add the - builder themselves. This is easier for the maintainers, but perhaps - a slightly poorer UX for the users. However, writing out a builder by - hand is significantly less complex than adding a controller by hand in - the current structure. +2.Simplyaddinganewcontroller,andremindingtheusertoaddthe +builderthemselves.Thisiseasierforthemaintainers,butperhaps +aslightlypoorerUXfortheusers.However,writingoutabuilderby +handissignificantlylesscomplexthanaddingacontrollerbyhandin +thecurrentstructure. -Option 1 should be fairly simple, since the logic is already needed for -registering types to the scheme, and we can always fall back to emitting -code for the user to place in manually if we can't find the correct +Option1shouldbefairlysimple,sincethelogicisalreadyneededfor +registeringtypestothescheme,andwecanalwaysfallbacktoemitting +codefortheusertoplaceinmanuallyifwecan'tfindthecorrect comment. -### Making this work with Existing Kubebuilder Installations +###MakingthisworkwithExistingKubebuilderInstallations -Kubebuilder projects currently have a `PROJECT` file that can be used to -store information about project settings. We can make use of this to -store a "scaffolding version", where we increment versions when making -incompatible changes to how the scaffolding works. +Kubebuilderprojectscurrentlyhavea`PROJECT`filethatcanbeusedto +storeinformationaboutprojectsettings.Wecanmakeuseofthisto +storea"scaffoldingversion",whereweincrementversionswhenmaking +incompatiblechangestohowthescaffoldingworks. -A missing scaffolding version field implies the version `1`, which uses -our current scaffolding semantics. Version `2` uses the semantics -proposed here. New projects are scaffolded with `2`, and existing -projects check the scaffold version before attempting to add addition API -versions, controllers, etc +Amissingscaffoldingversionfieldimpliestheversion`1`,whichuses +ourcurrentscaffoldingsemantics.Version`2`usesthesemantics +proposedhere.Newprojectsarescaffoldedwith`2`,andexisting +projectscheckthescaffoldversionbeforeattemptingtoaddadditionAPI +versions,controllers,etc -### Teaching more complicated project structures +###Teachingmorecomplicatedprojectstructures -Some controllers may eventually want more complicated project structures. -We should have a section of the book recommending options for when you -project gets very complicated. +Somecontrollersmayeventuallywantmorecomplicatedprojectstructures. +Weshouldhaveasectionofthebookrecommendingoptionsforwhenyou +projectgetsverycomplicated. -### Additional Tooling Work +###AdditionalToolingWork -* Currently the `api/` package will need a `doc.go` file to make - `deepcopy-gen` happy. We should fix this. +*Currentlythe`api/`packagewillneeda`doc.go`filetomake +`deepcopy-gen`happy.Weshouldfixthis. -* Currently, `controller-gen crd` needs the `api` directory to be - `pkg/apis//`. We should fix this. +*Currently,`controller-gencrd`needsthe`api`directorytobe +`pkg/apis//`.Weshouldfixthis. -## Example +##Example -See #000 for an example with multiple stages of code generation -(representing the examples is this form is rather complicated, since it -involves multiple files). +See#000foranexamplewithmultiplestagesofcodegeneration +(representingtheexamplesisthisformisrathercomplicated,sinceit +involvesmultiplefiles). ```shell -$ kubebuilder init --domain test.k8s.io -$ kubebuilder create api --group mygroup --version v1beta1 --kind MyKind -$ kubebuilder create api --group mygroup --version v2beta1 --kind MyKind -$ tree . +$kubebuilderinit--domaintest.k8s.io +$kubebuildercreateapi--groupmygroup--versionv1beta1--kindMyKind +$kubebuildercreateapi--groupmygroup--versionv2beta1--kindMyKind +$tree. . -├── main.go -├── controller -│   ├── mykind_controller.go -│   ├── controller_test.go -│   └── controllers_suite_test.go -├── api -│ ├── v1beta1 -│   │ ├── mykind_types.go -│   │ └── groupversion_info.go -│ └── v1 -│   ├── mykind_types.go -│   └── groupversion_info.go -└── vendor +├──main.go +├──controller +│├──mykind_controller.go +│├──controller_test.go +│└──controllers_suite_test.go +├──api +│├──v1beta1 +││├──mykind_types.go +││└──groupversion_info.go +│└──v1 +│├──mykind_types.go +│└──groupversion_info.go +└──vendor ```
@@ -395,56 +395,56 @@ $ tree . main.go ```go -package main +packagemain -import ( - "os" +import( +"os" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/log/zap" - "k8s.io/apimachinery/pkg/runtime" +ctrl"sigs.k8s.io/controller-runtime" +"sigs.k8s.io/controller-runtime/pkg/log/zap" +"k8s.io/apimachinery/pkg/runtime" - "my.repo/api/v1beta1" - "my.repo/api/v1" - "my.repo/controllers" +"my.repo/api/v1beta1" +"my.repo/api/v1" +"my.repo/controllers" ) -var ( - scheme = runtime.NewScheme() - setupLog = ctrl.Log.WithName("setup") +var( +scheme=runtime.NewScheme() +setupLog=ctrl.Log.WithName("setup") ) -func init() { - v1beta1.AddToScheme(scheme) - v1.AddToScheme(scheme) - // +kubebuilder:scaffold:scheme +funcinit(){ +v1beta1.AddToScheme(scheme) +v1.AddToScheme(scheme) +//+kubebuilder:scaffold:scheme } -func main() { - ctrl.SetLogger(zap.New(zap.UseDevMode(true))) - - mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{Scheme: scheme}) - if err != nil { - setupLog.Error(err, "unable to start manager") - os.Exit(1) - } - - err = (&controllers.MyKindReconciler{ - Client: mgr.GetClient(), - log: ctrl.Log.WithName("mykind-controller"), - }).SetupWithManager(mgr) - if err != nil { - setupLog.Error(err, "unable to create controller", "controller", "mykind") - os.Exit(1) - } - - // +kubebuilder:scaffold:builder - - setupLog.Info("starting manager") - if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { - setupLog.Error(err, "problem running manager") - os.Exit(1) - } +funcmain(){ +ctrl.SetLogger(zap.New(zap.UseDevMode(true))) + +mgr,err:=ctrl.NewManager(ctrl.GetConfigOrDie(),ctrl.Options{Scheme:scheme}) +iferr!=nil{ +setupLog.Error(err,"unabletostartmanager") +os.Exit(1) +} + +err=(&controllers.MyKindReconciler{ +Client:mgr.GetClient(), +log:ctrl.Log.WithName("mykind-controller"), +}).SetupWithManager(mgr) +iferr!=nil{ +setupLog.Error(err,"unabletocreatecontroller","controller","mykind") +os.Exit(1) +} + +//+kubebuilder:scaffold:builder + +setupLog.Info("startingmanager") +iferr:=mgr.Start(ctrl.SetupSignalHandler());err!=nil{ +setupLog.Error(err,"problemrunningmanager") +os.Exit(1) +} } ``` @@ -455,63 +455,63 @@ func main() { mykind_controller.go ```go -package controllers +packagecontrollers -import ( - "context" +import( +"context" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/go-logr/logr" +ctrl"sigs.k8s.io/controller-runtime" +"sigs.k8s.io/controller-runtime/pkg/client" +"github.com/go-logr/logr" - "my.repo/api/v1" +"my.repo/api/v1" ) -type MyKindReconciler struct { - client.Client - log logr.Logger +typeMyKindReconcilerstruct{ +client.Client +loglogr.Logger } -func (r *MyKindReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { - ctx := context.Background() - log := r.log.WithValues("mykind", req.NamespacedName) +func(r*MyKindReconciler)Reconcile(reqctrl.Request)(ctrl.Result,error){ +ctx:=context.Background() +log:=r.log.WithValues("mykind",req.NamespacedName) - // your logic here +//yourlogichere - return req.Result{}, nil +returnreq.Result{},nil } -func (r *MyKindReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(v1.MyKind{}). - Complete(r) +func(r*MyKindReconciler)SetupWithManager(mgrctrl.Manager)error{ +returnctrl.NewControllerManagedBy(mgr). +For(v1.MyKind{}). +Complete(r) } ```
-`*_types.go` looks nearly identical to the current standard. +`*_types.go`looksnearlyidenticaltothecurrentstandard.
groupversion_info.go ```go -package v1 +packagev1 -import ( - "sigs.k8s.io/controller-runtime/pkg/scheme" - "k8s.io/apimachinery/pkg/runtime/schema" +import( +"sigs.k8s.io/controller-runtime/pkg/scheme" +"k8s.io/apimachinery/pkg/runtime/schema" ) -var ( - GroupVersion = schema.GroupVersion{Group: "mygroup.test.k8s.io", Version: "v1"} +var( +GroupVersion=schema.GroupVersion{Group:"mygroup.test.k8s.io",Version:"v1"} - // SchemeBuilder is used to add go types to the GroupVersionKind scheme - SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} +//SchemeBuilderisusedtoaddgotypestotheGroupVersionKindscheme +SchemeBuilder=&scheme.Builder{GroupVersion:GroupVersion} - // AddToScheme adds the types in this group-version to the given scheme. - AddToScheme = SchemeBuilder.AddToScheme +//AddToSchemeaddsthetypesinthisgroup-versiontothegivenscheme. +AddToScheme=SchemeBuilder.AddToScheme ) ``` diff --git a/designs/template.md b/designs/template.md index 52ae3ddab85..57f9b4af325 100644 --- a/designs/template.md +++ b/designs/template.md @@ -1,114 +1,114 @@ -| Authors | Creation Date | Status | Extra | +|Authors|CreationDate|Status|Extra| |---------------|---------------|-------------|---| -| @name | date | Implementeble | - | +|@name|date|Implementeble|-| -Title of the Design/Proposal +TitleoftheDesign/Proposal =================== - -## Example +##Example - +Thisisalsoagoodopportunitytostopandwriteaproof-of-concept,if +youhaven'talready,whichshouldhelpcatchpracticalnitswiththe +design.--> -## Open Questions [optional] +##OpenQuestions[optional] - -## Summary +##Summary - +Agoodsummaryisprobablyatleastaparagraphinlength.--> -## Motivation +##Motivation - + -### Goals +###Goals - + -### Non-Goals +###Non-Goals - + -## Proposal +##Proposal - + -### User Stories +###UserStories - +-AsaIcan,sothat--> -### Implementation Details/Notes/Constraints [optional] +###ImplementationDetails/Notes/Constraints[optional] - + -### Risks and Mitigations +###RisksandMitigations - +Considerincludingfolksthatalsoworkoutsideyourimmediatesub-project.--> -### Proof of Concept [optional] +###ProofofConcept[optional] - +Besuretoinclude: +-Anembeddedrecordingoftheprototypeinaction. +-Alinktotherepositoryhostingthechangesthattheprototypeintroduces.--> -## Drawbacks +##Drawbacks - + -## Alternatives +##Alternatives - + diff --git a/docs/CONTRIBUTING-ROLES.md b/docs/CONTRIBUTING-ROLES.md index d7536b03924..243226c79c0 100644 --- a/docs/CONTRIBUTING-ROLES.md +++ b/docs/CONTRIBUTING-ROLES.md @@ -1,152 +1,152 @@ -Contributing Roles +ContributingRoles ================== -## Direct Code-Related Roles +##DirectCode-RelatedRoles -While anyone (who's signed the [CLA and follows the code of -conduct](../CONTRIBUTING.md)) is welcome to contribute to the Kubebuilder -project, we've got two "formal" roles that carry additional privileges and -responsibilities: *reviewer* and *approver*. +Whileanyone(who'ssignedthe[CLAandfollowsthecodeof +conduct](../CONTRIBUTING.md))iswelcometocontributetotheKubebuilder +project,we'vegottwo"formal"rolesthatcarryadditionalprivilegesand +responsibilities:*reviewer*and*approver*. -In a nutshell, reviewers and approvers are officially recognized to make -day-to-day and overarching technical decisions within parts of the -project, or the project as a whole. We follow a similar set of -definitions to the [main Kubernetes project itself][kube-ladder], with -slightly looser requirements. +Inanutshell,reviewersandapproversareofficiallyrecognizedtomake +day-to-dayandoverarchingtechnicaldecisionswithinpartsofthe +project,ortheprojectasawhole.Wefollowasimilarsetof +definitionstothe[mainKubernetesprojectitself][kube-ladder],with +slightlylooserrequirements. -As much as possible, we want people to help take on responsibility in the -project -- these guidelines are attempts to make it *easier* for this to -happen, *not harder*. If you've got any questions, just reach out on -Slack to one of the [subproject leads][kb-leads] (called -kubebuilder-admins in the `OWNERS_ALIASES` file). +Asmuchaspossible,wewantpeopletohelptakeonresponsibilityinthe +project--theseguidelinesareattemptstomakeit*easier*forthisto +happen,*notharder*.Ifyou'vegotanyquestions,justreachouton +Slacktooneofthe[subprojectleads][kb-leads](called +kubebuilder-adminsinthe`OWNERS_ALIASES`file). -## Prerequisite: Member +##Prerequisite:Member -Anyone who wants to become a reviewer or approver must first be a [member -of the Kubernetes project][kube-member]. The aforementioned doc has more -details, but the gist is that you must have made a couple contributions to -some part of the Kubernetes project -- *this includes Kubebuilder and -related repos*. Then, you need two existing members to sponsor you. +Anyonewhowantstobecomeareviewerorapprovermustfirstbea[member +oftheKubernetesproject][kube-member].Theaforementioneddochasmore +details,butthegististhatyoumusthavemadeacouplecontributionsto +somepartoftheKubernetesproject--*thisincludesKubebuilderand +relatedrepos*.Then,youneedtwoexistingmemberstosponsoryou. -**If you've contributed a few times to Kubebuilder, we'll be happy to -sponsor you, just ping us on Slack :-)** +**Ifyou'vecontributedafewtimestoKubebuilder,we'llbehappyto +sponsoryou,justpingusonSlack:-)** -## Reviewers +##Reviewers -Reviewers are recongized as able to provide code reviews for parts of the -codebase, and are entered into the `reviewers` section of one or more -`OWNERS` files. You'll get auto-assigned reviews for your area of the -codebase, and are generally expected to review for both correctness, -testing, general code organization, etc. Reviewers may review for design -as well, but approvers have the final say on that. +Reviewersarerecongizedasabletoprovidecodereviewsforpartsofthe +codebase,andareenteredintothe`reviewers`sectionofoneormore +`OWNERS`files.You'llgetauto-assignedreviewsforyourareaofthe +codebase,andaregenerallyexpectedtoreviewforbothcorrectness, +testing,generalcodeorganization,etc.Reviewersmayreviewfordesign +aswell,butapprovershavethefinalsayonthat. -Things to look for: +Thingstolookfor: -- does this code work, and is it written performantly and idomatically? -- is it tested? -- is it organized nicely? Is it maintainable? -- is it documented? -- does it need to be threadsafe? Is it? -- Take a glance at the stuff for approvers, if you can. +-doesthiscodework,andisitwrittenperformantlyandidomatically? +-isittested? +-isitorganizednicely?Isitmaintainable? +-isitdocumented? +-doesitneedtobethreadsafe?Isit? +-Takeaglanceatthestuffforapprovers,ifyoucan. -Reviewers' `/lgtm` marks are generally trusted by approvers to mean that -the code is ready for one last look-over before merging. +Reviewers'`/lgtm`marksaregenerallytrustedbyapproverstomeanthat +thecodeisreadyforonelastlook-overbeforemerging. -### Becoming a Reviewer +###BecomingaReviewer -The criteria for becoming a reviewer are: +Thecriteriaforbecomingareviewerare: -- Give 5-10 reviews on PRs -- Contribute or review 3-5 PRs substantially (i.e. take on the role of the - defacto "main" reviewer for the PR, contribute a bugfix or feature, etc) +-Give5-10reviewsonPRs +-Contributeorreview3-5PRssubstantially(i.e.takeontheroleofthe +defacto"main"reviewerforthePR,contributeabugfixorfeature,etc) -Usually, this will need to occur within a single repository, but if you've -worked on a cross-cutting feature, it's ok to count PRs across +Usually,thiswillneedtooccurwithinasinglerepository,butifyou've +workedonacross-cuttingfeature,it'soktocountPRsacross repositories. -Once you meet those criteria, submit yourself as a reviewer in the -`OWNERS` file or files that you feel represent your areas of knowlege via -a PR to the relevant repository. +Onceyoumeetthosecriteria,submityourselfasareviewerinthe +`OWNERS`fileorfilesthatyoufeelrepresentyourareasofknowlegevia +aPRtotherelevantrepository. -## Approvers +##Approvers -Approvers provide the final say as to whether a piece of code is merged. -Once approvals (`/approve`) are given for each piece of the affected code -(and a reviewer or approver has added `/lgtm`), the code will merge. +Approversprovidethefinalsayastowhetherapieceofcodeismerged. +Onceapprovals(`/approve`)aregivenforeachpieceoftheaffectedcode +(andareviewerorapproverhasadded`/lgtm`),thecodewillmerge. -Approvers are responsible for giving the code a final once-over before -merge, and doing an overall design/API review. +Approversareresponsibleforgivingthecodeafinalonce-overbefore +merge,anddoinganoveralldesign/APIreview. -Things to look for: +Thingstolookfor: -- Does the API exposed to the user make sense, and is it easy to use? -- Is it backwards compatible? -- Will it accommodate new changes in the future? -- Is it extesnible/layerable (see [DESIGN.md](../DESIGN.md))? -- Does it expose a new type from `k8s.io/XYZ`, and, if so, is it worth it? - Is that piece well-designed? +-DoestheAPIexposedtotheusermakesense,andisiteasytouse? +-Isitbackwardscompatible? +-Willitaccommodatenewchangesinthefuture? +-Isitextesnible/layerable(see[DESIGN.md](../DESIGN.md))? +-Doesitexposeanewtypefrom`k8s.io/XYZ`,and,ifso,isitworthit? +Isthatpiecewell-designed? -**For large changes, approvers are responsible for getting reasonble -consensus**. With the power to approve such changes comes the -responsibility of ensuring that the project as a whole has time to discuss +**Forlargechanges,approversareresponsibleforgettingreasonble +consensus**.Withthepowertoapprovesuchchangescomesthe +responsibilityofensuringthattheprojectasawholehastimetodiscuss them. -### Becoming an Approver +###BecominganApprover -All approvers need to start out as reviewers. The criteria for becoming -an approver are: +Allapproversneedtostartoutasreviewers.Thecriteriaforbecoming +anapproverare: -- Be a reviewer in the area for a couple months -- Be the "main" reviewer or contributor for 5-10 substantial (bugfixes, - features, etc) PRs where approvers did not need to leave substantial - additional comments (i.e. where you were acting as a defacto approver). +-Beareviewerintheareaforacouplemonths +-Bethe"main"reviewerorcontributorfor5-10substantial(bugfixes, +features,etc)PRswhereapproversdidnotneedtoleavesubstantial +additionalcomments(i.e.whereyouwereactingasadefactoapprover). -Once you've met those criteria, you can submit yourself as an approver -using a PR that edits the revelant `OWNERS` files appropriately. The -existing approvers will then approve the change with lazy consensus. If -you feel more comfortable asking before submitting the PR, feel free to -ping one of the [subproject leads][kb-leads] (called kubebuilder-admins in -the `OWNERS_ALIASES` file) on Slack. +Onceyou'vemetthosecriteria,youcansubmityourselfasanapprover +usingaPRthateditstherevelant`OWNERS`filesappropriately.The +existingapproverswillthenapprovethechangewithlazyconsensus.If +youfeelmorecomfortableaskingbeforesubmittingthePR,feelfreeto +pingoneofthe[subprojectleads][kb-leads](calledkubebuilder-adminsin +the`OWNERS_ALIASES`file)onSlack. -## Indirectly Code-Related/Non-Code Roles +##IndirectlyCode-Related/Non-CodeRoles -We're always looking help with other areas of the project as well, such +We'realwayslookinghelpwithotherareasoftheprojectaswell,such as: -### Docs +###Docs -Docs contributors are always welcome. Docs folks can also become -reviewers/approvers for the book by following the same process above. +Docscontributorsarealwayswelcome.Docsfolkscanalsobecome +reviewers/approversforthebookbyfollowingthesameprocessabove. -### Triage +###Triage -Help triaging our issues is also welcome. Folks doing triage are -responsible for using the following commands to mark PRs and issues with -one or more labels, and should also feel free to help answer questions: +Helptriagingourissuesisalsowelcome.Folksdoingtriageare +responsibleforusingthefollowingcommandstomarkPRsandissueswith +oneormorelabels,andshouldalsofeelfreetohelpanswerquestions: -- `/kind {bug|feature|documentation}`: things that are broken/new - things/things with lots of words, repsectively +-`/kind{bug|feature|documentation}`:thingsthatarebroken/new +things/thingswithlotsofwords,repsectively -- `/triage support`: questions, and things that might be bugs but might - just be confusion of how to use something +-`/triagesupport`:questions,andthingsthatmightbebugsbutmight +justbeconfusionofhowtousesomething -- `/priority {backlog|important-longterm|important-soon|critical-urgent}`: - how soon we need to deal with the thing (if someone wants - to/eventually/pretty soon/RIGHT NOW OMG THINGS ARE ON FIRE, - respectively) +-`/priority{backlog|important-longterm|important-soon|critical-urgent}`: +howsoonweneedtodealwiththething(ifsomeonewants +to/eventually/prettysoon/RIGHTNOWOMGTHINGSAREONFIRE, +respectively) -- `/good-first-issue`: this is pretty straightforward to implement, has - a clear plan, and clear criteria for being complete +-`/good-first-issue`:thisisprettystraightforwardtoimplement,has +aclearplan,andclearcriteriaforbeingcomplete -- `/help`: this could feasibly still be picked up by someone new-ish, but - has some wrinkles or nitty-gritty details that might not make it a good - first issue +-`/help`:thiscouldfeasiblystillbepickedupbysomeonenew-ish,but +hassomewrinklesornitty-grittydetailsthatmightnotmakeitagood +firstissue -See the [Prow reference](https://prow.k8s.io/command-help) for more +Seethe[Prowreference](https://prow.k8s.io/command-help)formore details. -[kube-ladder]: https://github.com/kubernetes/community/blob/master/community-membership.md "Kubernetes Community Membership" +[kube-ladder]:https://github.com/kubernetes/community/blob/master/community-membership.md"KubernetesCommunityMembership" -[kube-member]: https://github.com/kubernetes/community/blob/master/community-membership.md#member "Kubernetes Project Member" +[kube-member]:https://github.com/kubernetes/community/blob/master/community-membership.md#member"KubernetesProjectMember" -[kb-leads]: ../OWNERS_ALIASES "Root OWNERS file -- kubebuilder-admins" +[kb-leads]:../OWNERS_ALIASES"RootOWNERSfile--kubebuilder-admins" diff --git a/docs/README.md b/docs/README.md index ec9980fda5a..a12b667a11f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,18 +1,18 @@ -# Running mdBook +#RunningmdBook -The kubebuilder book is served using [mdBook](https://github.com/rust-lang-nursery/mdBook). If you want to test changes to the book locally, follow these directions: +Thekubebuilderbookisservedusing[mdBook](https://github.com/rust-lang-nursery/mdBook).Ifyouwanttotestchangestothebooklocally,followthesedirections: -1. Follow the instructions at [https://github.com/rust-lang-nursery/mdBook#installation](https://github.com/rust-lang-nursery/mdBook#installation) to - install mdBook. -2. Make sure [controller-gen](https://pkg.go.dev/sigs.k8s.io/controller-tools/cmd/controller-gen) is installed in `$GOPATH`. -3. cd into the `docs/book` directory -4. Run `mdbook serve` -5. Visit [http://localhost:3000](http://localhost:3000) +1.Followtheinstructionsat[https://github.com/rust-lang-nursery/mdBook#installation](https://github.com/rust-lang-nursery/mdBook#installation)to +installmdBook. +2.Makesure[controller-gen](https://pkg.go.dev/sigs.k8s.io/controller-tools/cmd/controller-gen)isinstalledin`$GOPATH`. +3.cdintothe`docs/book`directory +4.Run`mdbookserve` +5.Visit[http://localhost:3000](http://localhost:3000) -# Steps to deploy +#Stepstodeploy -There are no manual steps needed to deploy the website. +Therearenomanualstepsneededtodeploythewebsite. -Kubebuilder book website is deployed on Netlify. -There is a preview of the website for each PR. -As soon as the PR is merged, the website will be built and deployed on Netlify. +KubebuilderbookwebsiteisdeployedonNetlify. +ThereisapreviewofthewebsiteforeachPR. +AssoonasthePRismerged,thewebsitewillbebuiltanddeployedonNetlify. diff --git a/docs/book/src/SUMMARY.md b/docs/book/src/SUMMARY.md index cb389867449..36d2f4fcad0 100644 --- a/docs/book/src/SUMMARY.md +++ b/docs/book/src/SUMMARY.md @@ -1,150 +1,150 @@ -# Summary +#Summary [Introduction](./introduction.md) [Architecture](./architecture.md) -[Quick Start](./quick-start.md) +[QuickStart](./quick-start.md) -[Getting Started](./getting-started.md) +[GettingStarted](./getting-started.md) --- -- [Tutorial: Building CronJob](cronjob-tutorial/cronjob-tutorial.md) +-[Tutorial:BuildingCronJob](cronjob-tutorial/cronjob-tutorial.md) - - [What's in a basic project?](./cronjob-tutorial/basic-project.md) - - [Every journey needs a start, every program a main](./cronjob-tutorial/empty-main.md) - - [Groups and Versions and Kinds, oh my!](./cronjob-tutorial/gvks.md) - - [Adding a new API](./cronjob-tutorial/new-api.md) - - [Designing an API](./cronjob-tutorial/api-design.md) +-[What'sinabasicproject?](./cronjob-tutorial/basic-project.md) +-[Everyjourneyneedsastart,everyprogramamain](./cronjob-tutorial/empty-main.md) +-[GroupsandVersionsandKinds,ohmy!](./cronjob-tutorial/gvks.md) +-[AddinganewAPI](./cronjob-tutorial/new-api.md) +-[DesigninganAPI](./cronjob-tutorial/api-design.md) - - [A Brief Aside: What's the rest of this stuff?](./cronjob-tutorial/other-api-files.md) +-[ABriefAside:What'stherestofthisstuff?](./cronjob-tutorial/other-api-files.md) - - [What's in a controller?](./cronjob-tutorial/controller-overview.md) - - [Implementing a controller](./cronjob-tutorial/controller-implementation.md) +-[What'sinacontroller?](./cronjob-tutorial/controller-overview.md) +-[Implementingacontroller](./cronjob-tutorial/controller-implementation.md) - - [You said something about main?](./cronjob-tutorial/main-revisited.md) +-[Yousaidsomethingaboutmain?](./cronjob-tutorial/main-revisited.md) - - [Implementing defaulting/validating webhooks](./cronjob-tutorial/webhook-implementation.md) - - [Running and deploying the controller](./cronjob-tutorial/running.md) +-[Implementingdefaulting/validatingwebhooks](./cronjob-tutorial/webhook-implementation.md) +-[Runninganddeployingthecontroller](./cronjob-tutorial/running.md) - - [Deploying cert-manager](./cronjob-tutorial/cert-manager.md) - - [Deploying webhooks](./cronjob-tutorial/running-webhook.md) +-[Deployingcert-manager](./cronjob-tutorial/cert-manager.md) +-[Deployingwebhooks](./cronjob-tutorial/running-webhook.md) - - [Writing tests](./cronjob-tutorial/writing-tests.md) +-[Writingtests](./cronjob-tutorial/writing-tests.md) - - [Epilogue](./cronjob-tutorial/epilogue.md) +-[Epilogue](./cronjob-tutorial/epilogue.md) -- [Tutorial: Multi-Version API](./multiversion-tutorial/tutorial.md) +-[Tutorial:Multi-VersionAPI](./multiversion-tutorial/tutorial.md) - - [Changing things up](./multiversion-tutorial/api-changes.md) - - [Hubs, spokes, and other wheel metaphors](./multiversion-tutorial/conversion-concepts.md) - - [Implementing conversion](./multiversion-tutorial/conversion.md) +-[Changingthingsup](./multiversion-tutorial/api-changes.md) +-[Hubs,spokes,andotherwheelmetaphors](./multiversion-tutorial/conversion-concepts.md) +-[Implementingconversion](./multiversion-tutorial/conversion.md) - - [and setting up the webhooks](./multiversion-tutorial/webhooks.md) +-[andsettingupthewebhooks](./multiversion-tutorial/webhooks.md) - - [Deployment and Testing](./multiversion-tutorial/deployment.md) +-[DeploymentandTesting](./multiversion-tutorial/deployment.md) -- [Tutorial: Component Config](./component-config-tutorial/tutorial.md) +-[Tutorial:ComponentConfig](./component-config-tutorial/tutorial.md) - - [Changing things up](./component-config-tutorial/api-changes.md) - - [Defining your Config](./component-config-tutorial/define-config.md) +-[Changingthingsup](./component-config-tutorial/api-changes.md) +-[DefiningyourConfig](./component-config-tutorial/define-config.md) - - [Using a custom type](./component-config-tutorial/custom-type.md) +-[Usingacustomtype](./component-config-tutorial/custom-type.md) - - [Adding a new Config Type](./component-config-tutorial/config-type.md) - - [Updating main](./component-config-tutorial/updating-main.md) - - [Defining your Custom Config](./component-config-tutorial/define-custom-config.md) +-[AddinganewConfigType](./component-config-tutorial/config-type.md) +-[Updatingmain](./component-config-tutorial/updating-main.md) +-[DefiningyourCustomConfig](./component-config-tutorial/define-custom-config.md) --- -- [Migrations](./migrations.md) +-[Migrations](./migrations.md) - - [Legacy (before <= v3.0.0)](./migration/legacy.md) - - [Kubebuilder v1 vs v2](migration/legacy/v1vsv2.md) +-[Legacy(before<=v3.0.0)](./migration/legacy.md) +-[Kubebuilderv1vsv2](migration/legacy/v1vsv2.md) - - [Migration Guide](./migration/legacy/migration_guide_v1tov2.md) +-[MigrationGuide](./migration/legacy/migration_guide_v1tov2.md) - - [Kubebuilder v2 vs v3](migration/legacy/v2vsv3.md) +-[Kubebuilderv2vsv3](migration/legacy/v2vsv3.md) - - [Migration Guide](migration/legacy/migration_guide_v2tov3.md) - - [Migration by updating the files](migration/legacy/manually_migration_guide_v2_v3.md) - - [From v3.0.0 with plugins](./migration/v3-plugins.md) - - [go/v3 vs go/v4](migration/v3vsv4.md) - - - [Migration Guide](migration/migration_guide_gov3_to_gov4.md) - - [Migration by updating the files](migration/manually_migration_guide_gov3_to_gov4.md) - - [Single Group to Multi-Group](./migration/multi-group.md) +-[MigrationGuide](migration/legacy/migration_guide_v2tov3.md) +-[Migrationbyupdatingthefiles](migration/legacy/manually_migration_guide_v2_v3.md) +-[Fromv3.0.0withplugins](./migration/v3-plugins.md) +-[go/v3vsgo/v4](migration/v3vsv4.md) -- [Project Upgrade Assistant](./reference/rescaffold.md) +-[MigrationGuide](migration/migration_guide_gov3_to_gov4.md) +-[Migrationbyupdatingthefiles](migration/manually_migration_guide_gov3_to_gov4.md) +-[SingleGrouptoMulti-Group](./migration/multi-group.md) + +-[ProjectUpgradeAssistant](./reference/rescaffold.md) --- -- [Reference](./reference/reference.md) +-[Reference](./reference/reference.md) - - [Generating CRDs](./reference/generating-crd.md) - - [Using Finalizers](./reference/using-finalizers.md) - - [Good Practices](./reference/good-practices.md) - - [Raising Events](./reference/raising-events.md) - - [Watching Resources](./reference/watching-resources.md) - - [Resources Managed by the Operator](./reference/watching-resources/operator-managed.md) - - [Externally Managed Resources](./reference/watching-resources/externally-managed.md) - - [Kind cluster](reference/kind.md) - - [What's a webhook?](reference/webhook-overview.md) - - [Admission webhook](reference/admission-webhook.md) - - [Webhooks for Core Types](reference/webhook-for-core-types.md) - - [Markers for Config/Code Generation](./reference/markers.md) +-[GeneratingCRDs](./reference/generating-crd.md) +-[UsingFinalizers](./reference/using-finalizers.md) +-[GoodPractices](./reference/good-practices.md) +-[RaisingEvents](./reference/raising-events.md) +-[WatchingResources](./reference/watching-resources.md) +-[ResourcesManagedbytheOperator](./reference/watching-resources/operator-managed.md) +-[ExternallyManagedResources](./reference/watching-resources/externally-managed.md) +-[Kindcluster](reference/kind.md) +-[What'sawebhook?](reference/webhook-overview.md) +-[Admissionwebhook](reference/admission-webhook.md) +-[WebhooksforCoreTypes](reference/webhook-for-core-types.md) +-[MarkersforConfig/CodeGeneration](./reference/markers.md) - - [CRD Generation](./reference/markers/crd.md) - - [CRD Validation](./reference/markers/crd-validation.md) - - [CRD Processing](./reference/markers/crd-processing.md) - - [Webhook](./reference/markers/webhook.md) - - [Object/DeepCopy](./reference/markers/object.md) - - [RBAC](./reference/markers/rbac.md) +-[CRDGeneration](./reference/markers/crd.md) +-[CRDValidation](./reference/markers/crd-validation.md) +-[CRDProcessing](./reference/markers/crd-processing.md) +-[Webhook](./reference/markers/webhook.md) +-[Object/DeepCopy](./reference/markers/object.md) +-[RBAC](./reference/markers/rbac.md) - - [controller-gen CLI](./reference/controller-gen.md) - - [completion](./reference/completion.md) - - [Artifacts](./reference/artifacts.md) - - [Platform Support](./reference/platform.md) +-[controller-genCLI](./reference/controller-gen.md) +-[completion](./reference/completion.md) +-[Artifacts](./reference/artifacts.md) +-[PlatformSupport](./reference/platform.md) - - [Sub-Module Layouts](./reference/submodule-layouts.md) - - [Using an external Type / API](./reference/using_an_external_type.md) +-[Sub-ModuleLayouts](./reference/submodule-layouts.md) +-[UsinganexternalType/API](./reference/using_an_external_type.md) - - [Configuring EnvTest](./reference/envtest.md) +-[ConfiguringEnvTest](./reference/envtest.md) - - [Metrics](./reference/metrics.md) +-[Metrics](./reference/metrics.md) - - [Reference](./reference/metrics-reference.md) +-[Reference](./reference/metrics-reference.md) - - [Makefile Helpers](./reference/makefile-helpers.md) - - [Project config](./reference/project-config.md) +-[MakefileHelpers](./reference/makefile-helpers.md) +-[Projectconfig](./reference/project-config.md) --- -- [Plugins][plugins] - - - [Available Plugins](./plugins/available-plugins.md) - - [To scaffold a project](./plugins/to-scaffold-project.md) - - [go/v2 (Deprecated)](./plugins/go-v2-plugin.md) - - [go/v3 (Deprecated)](./plugins/go-v3-plugin.md) - - [go/v4 (Default init scaffold)](./plugins/go-v4-plugin.md) - - [To add optional features](./plugins/to-add-optional-features.md) - - [declarative/v1 (Deprecated)](./plugins/declarative-v1.md) - - [grafana/v1-alpha](./plugins/grafana-v1-alpha.md) - - [deploy-image/v1-alpha](./plugins/deploy-image-plugin-v1-alpha.md) - - [To be extended for others tools](./plugins/to-be-extended.md) - - [kustomize/v1 (Deprecated)](./plugins/kustomize-v1.md) - - [kustomize/v2](./plugins/kustomize-v2.md) - - [Extending the CLI](./plugins/extending-cli.md) - - [Creating your own plugins](./plugins/creating-plugins.md) - - [Testing your own plugins](./plugins/testing-plugins.md) - - [Plugins Versioning](./plugins/plugins-versioning.md) - - [Creating external plugins](./plugins/external-plugins.md) +-[Plugins][plugins] + +-[AvailablePlugins](./plugins/available-plugins.md) +-[Toscaffoldaproject](./plugins/to-scaffold-project.md) +-[go/v2(Deprecated)](./plugins/go-v2-plugin.md) +-[go/v3(Deprecated)](./plugins/go-v3-plugin.md) +-[go/v4(Defaultinitscaffold)](./plugins/go-v4-plugin.md) +-[Toaddoptionalfeatures](./plugins/to-add-optional-features.md) +-[declarative/v1(Deprecated)](./plugins/declarative-v1.md) +-[grafana/v1-alpha](./plugins/grafana-v1-alpha.md) +-[deploy-image/v1-alpha](./plugins/deploy-image-plugin-v1-alpha.md) +-[Tobeextendedforotherstools](./plugins/to-be-extended.md) +-[kustomize/v1(Deprecated)](./plugins/kustomize-v1.md) +-[kustomize/v2](./plugins/kustomize-v2.md) +-[ExtendingtheCLI](./plugins/extending-cli.md) +-[Creatingyourownplugins](./plugins/creating-plugins.md) +-[Testingyourownplugins](./plugins/testing-plugins.md) +-[PluginsVersioning](./plugins/plugins-versioning.md) +-[Creatingexternalplugins](./plugins/external-plugins.md) --- [FAQ](./faq.md) -[Appendix: The TODO Landing Page](./TODO.md) +[Appendix:TheTODOLandingPage](./TODO.md) -[plugins]: ./plugins/plugins.md +[plugins]:./plugins/plugins.md diff --git a/docs/book/src/TODO.md b/docs/book/src/TODO.md index 37a00404fe5..41d78ab8f05 100644 --- a/docs/book/src/TODO.md +++ b/docs/book/src/TODO.md @@ -1,8 +1,8 @@ -# TODO +#TODO -If you're seeing this page, it's probably because something's not done in -the book yet, or you stumbled upon an old link. Go [see if anyone else -has found +Ifyou'reseeingthispage,it'sprobablybecausesomething'snotdonein +thebookyet,oryoustumbleduponanoldlink.Go[seeifanyoneelse +hasfound this](https://github.com/kubernetes-sigs/kubebuilder/issues?q=is%3Aopen+is%3Aissue+label%3Akind%2Fdocumentation) -or [bug the +or[bugthe maintainers](https://github.com/kubernetes-sigs/kubebuilder/issues/new?assignees=&labels=kind%2Fdocumentation). diff --git a/docs/book/src/architecture.md b/docs/book/src/architecture.md index ef12bd22fa2..890bd393d57 100644 --- a/docs/book/src/architecture.md +++ b/docs/book/src/architecture.md @@ -1,6 +1,6 @@ -# Architecture Concept Diagram +#ArchitectureConceptDiagram -The following diagram will help you get a better idea over the Kubebuilder concepts and architecture. +ThefollowingdiagramwillhelpyougetabetterideaovertheKubebuilderconceptsandarchitecture. - -{{#include ./kb_concept_diagram.svg}} + +{{#include./kb_concept_diagram.svg}} diff --git a/docs/book/src/component-config-tutorial/api-changes.md b/docs/book/src/component-config-tutorial/api-changes.md index edd39223edd..727d8637714 100644 --- a/docs/book/src/component-config-tutorial/api-changes.md +++ b/docs/book/src/component-config-tutorial/api-changes.md @@ -1,148 +1,148 @@ -# Changing things up +#Changingthingsup - -This tutorial will show you how to create a custom configuration file for your -project by modifying a project generated with the `--component-config` flag -passed to the `init` command. The full tutorial's source can be found -[here][tutorial-source]. Make sure you've gone through the [installation -steps](/quick-start.md#installation) before continuing. +Thistutorialwillshowyouhowtocreateacustomconfigurationfileforyour +projectbymodifyingaprojectgeneratedwiththe`--component-config`flag +passedtothe`init`command.Thefulltutorial'ssourcecanbefound +[here][tutorial-source].Makesureyou'vegonethroughthe[installation +steps](/quick-start.md#installation)beforecontinuing. -## New project: +##Newproject: ```bash -# we'll use a domain of tutorial.kubebuilder.io, -# so all API groups will be .tutorial.kubebuilder.io. -kubebuilder init --domain tutorial.kubebuilder.io --component-config +#we'lluseadomainoftutorial.kubebuilder.io, +#soallAPIgroupswillbe.tutorial.kubebuilder.io. +kubebuilderinit--domaintutorial.kubebuilder.io--component-config ``` -## Setting up an existing project +##Settingupanexistingproject -If you've previously generated a project we can add support for parsing the -config file by making the following changes to `main.go`. +Ifyou'vepreviouslygeneratedaprojectwecanaddsupportforparsingthe +configfilebymakingthefollowingchangesto`main.go`. -First, add a new `flag` to specify the path that the component config file -should be loaded from. +First,addanew`flag`tospecifythepaththatthecomponentconfigfile +shouldbeloadedfrom. ```go -var configFile string -flag.StringVar(&configFile, "config", "", - "The controller will load its initial configuration from this file. "+ - "Omit this flag to use the default configuration values. "+ - "Command-line flags override configuration from this file.") +varconfigFilestring +flag.StringVar(&configFile,"config","", +"Thecontrollerwillloaditsinitialconfigurationfromthisfile."+ +"Omitthisflagtousethedefaultconfigurationvalues."+ +"Command-lineflagsoverrideconfigurationfromthisfile.") ``` -Now, we can setup the `Options` struct and check if the `configFile` is set, -this allows backwards compatibility, if it's set we'll then use the `AndFrom` -function on `Options` to parse and populate the `Options` from the config. +Now,wecansetupthe`Options`structandcheckifthe`configFile`isset, +thisallowsbackwardscompatibility,ifit'ssetwe'llthenusethe`AndFrom` +functionon`Options`toparseandpopulatethe`Options`fromtheconfig. ```go -var err error -options := ctrl.Options{Scheme: scheme} -if configFile != "" { - options, err = options.AndFrom(ctrl.ConfigFile().AtPath(configFile)) - if err != nil { - setupLog.Error(err, "unable to load the config file") - os.Exit(1) - } +varerrerror +options:=ctrl.Options{Scheme:scheme} +ifconfigFile!=""{ +options,err=options.AndFrom(ctrl.ConfigFile().AtPath(configFile)) +iferr!=nil{ +setupLog.Error(err,"unabletoloadtheconfigfile") +os.Exit(1) +} } ``` - -Lastly, we'll change the `NewManager` call to use the `options` variable we -defined above. +Lastly,we'llchangethe`NewManager`calltousethe`options`variablewe +definedabove. ```go -mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), options) +mgr,err:=ctrl.NewManager(ctrl.GetConfigOrDie(),options) ``` -With that out of the way, we can get on to defining our new config! +Withthatoutoftheway,wecangetontodefiningournewconfig! -[tutorial-source]: https://github.com/kubernetes-sigs/kubebuilder/tree/master/docs/book/src/component-config-tutorial/testdata/project +[tutorial-source]:https://github.com/kubernetes-sigs/kubebuilder/tree/master/docs/book/src/component-config-tutorial/testdata/project -Create the file `/config/manager/controller_manager_config.yaml` with the following content: +Createthefile`/config/manager/controller_manager_config.yaml`withthefollowingcontent: ```yaml -apiVersion: controller-runtime.sigs.k8s.io/v1alpha1 -kind: ControllerManagerConfig +apiVersion:controller-runtime.sigs.k8s.io/v1alpha1 +kind:ControllerManagerConfig health: - healthProbeBindAddress: :8081 +healthProbeBindAddress::8081 metrics: - bindAddress: 127.0.0.1:8080 +bindAddress:127.0.0.1:8080 webhook: - port: 9443 +port:9443 leaderElection: - leaderElect: true - resourceName: ecaf1259.tutorial.kubebuilder.io -# leaderElectionReleaseOnCancel defines if the leader should step down volume -# 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 +leaderElect:true +resourceName:ecaf1259.tutorial.kubebuilder.io +#leaderElectionReleaseOnCanceldefinesiftheleadershouldstepdownvolume +#whentheManagerends.Thisrequiresthebinarytoimmediatelyendwhenthe +#Managerisstopped,otherwise,thissettingisunsafe.Settingthissignificantly +#speedsupvoluntaryleadertransitionsasthenewleaderdon'thavetowait +#LeaseDurationtimefirst. +#Inthedefaultscaffoldprovided,theprogramendsimmediatelyafter +#themanagerstops,sowouldbefinetoenablethisoption.However, +#ifyouaredoingorisintendedtodoanyoperationsuchasperformcleanups +#afterthemanagerstopsthenitsusagemightbeunsafe. +#leaderElectionReleaseOnCancel:true ``` -Update the file `/config/manager/kustomization.yaml` by adding at the bottom the following content: +Updatethefile`/config/manager/kustomization.yaml`byaddingatthebottomthefollowingcontent: ```yaml generatorOptions: - disableNameSuffixHash: true +disableNameSuffixHash:true configMapGenerator: -- name: manager-config - files: - - controller_manager_config.yaml +-name:manager-config +files: +-controller_manager_config.yaml ``` -Update the file `default/kustomization.yaml` by adding under the [`patchesStrategicMerge:` key](https://kubectl.docs.kubernetes.io/references/kustomize/builtins/#_patchesstrategicmerge_) the following patch: +Updatethefile`default/kustomization.yaml`byaddingunderthe[`patchesStrategicMerge:`key](https://kubectl.docs.kubernetes.io/references/kustomize/builtins/#_patchesstrategicmerge_)thefollowingpatch: ```yaml patchesStrategicMerge: -# Mount the controller config file for loading manager configurations -# through a ComponentConfig type -- manager_config_patch.yaml +#Mountthecontrollerconfigfileforloadingmanagerconfigurations +#throughaComponentConfigtype +-manager_config_patch.yaml ``` -Update the file `default/manager_config_patch.yaml` by adding under the `spec:` key the following patch: +Updatethefile`default/manager_config_patch.yaml`byaddingunderthe`spec:`keythefollowingpatch: ```yaml spec: - template: - spec: - containers: - - name: manager - args: - - "--config=controller_manager_config.yaml" - volumeMounts: - - name: manager-config - mountPath: /controller_manager_config.yaml - subPath: controller_manager_config.yaml - volumes: - - name: manager-config - configMap: - name: manager-config +template: +spec: +containers: +-name:manager +args: +-"--config=controller_manager_config.yaml" +volumeMounts: +-name:manager-config +mountPath:/controller_manager_config.yaml +subPath:controller_manager_config.yaml +volumes: +-name:manager-config +configMap: +name:manager-config ``` diff --git a/docs/book/src/component-config-tutorial/config-type.md b/docs/book/src/component-config-tutorial/config-type.md index 518f360ed81..d0d9f592730 100644 --- a/docs/book/src/component-config-tutorial/config-type.md +++ b/docs/book/src/component-config-tutorial/config-type.md @@ -1,39 +1,39 @@ -# Adding a new Config Type +#AddinganewConfigType - -To scaffold out a new config Kind, we can use `kubebuilder create api`. +ToscaffoldoutanewconfigKind,wecanuse`kubebuildercreateapi`. ```bash -kubebuilder create api --group config --version v2 --kind ProjectConfig --resource --controller=false --make=false +kubebuildercreateapi--groupconfig--versionv2--kindProjectConfig--resource--controller=false--make=false ``` -Then, run `make build` to implement the interface for your API type, which would generate the file `zz_generated.deepcopy.go`. +Then,run`makebuild`toimplementtheinterfaceforyourAPItype,whichwouldgeneratethefile`zz_generated.deepcopy.go`. - -This will create a new type file in `api/config/v2/` for the `ProjectConfig` -kind. We'll need to change this file to embed the +Thiswillcreateanewtypefilein`api/config/v2/`forthe`ProjectConfig` +kind.We'llneedtochangethisfiletoembedthe [v1alpha1.ControllerManagerConfigurationSpec](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/#ControllerManagerConfigurationSpec) -{{#literatego ./testdata/projectconfig_types.go}} +{{#literatego./testdata/projectconfig_types.go}} -Lastly, we'll change the `main.go` to reference this type for parsing the file. +Lastly,we'llchangethe`main.go`toreferencethistypeforparsingthefile. diff --git a/docs/book/src/component-config-tutorial/custom-type.md b/docs/book/src/component-config-tutorial/custom-type.md index 55910168e48..d9b6a70d0f4 100644 --- a/docs/book/src/component-config-tutorial/custom-type.md +++ b/docs/book/src/component-config-tutorial/custom-type.md @@ -1,31 +1,31 @@ -# Using a Custom Type +#UsingaCustomType - - -If your project needs to accept additional non-controller runtime specific -configurations, e.g. `ClusterName`, `Region` or anything serializable into -`yaml` you can do this by using `kubebuilder` to create a new type and then -updating your `main.go` to setup the new type for parsing. +Ifyourprojectneedstoacceptadditionalnon-controllerruntimespecific +configurations,e.g.`ClusterName`,`Region`oranythingserializableinto +`yaml`youcandothisbyusing`kubebuilder`tocreateanewtypeandthen +updatingyour`main.go`tosetupthenewtypeforparsing. -The rest of this tutorial will walk through implementing a custom component -config type. \ No newline at end of file +Therestofthistutorialwillwalkthroughimplementingacustomcomponent +configtype. \ No newline at end of file diff --git a/docs/book/src/component-config-tutorial/define-config.md b/docs/book/src/component-config-tutorial/define-config.md index aad23970c08..b1eec23ba8a 100644 --- a/docs/book/src/component-config-tutorial/define-config.md +++ b/docs/book/src/component-config-tutorial/define-config.md @@ -1,24 +1,24 @@ -# Defining your Config +#DefiningyourConfig - -Now that you have a component config base project we need to customize the -values that are passed into the controller, to do this we can take a look at +Nowthatyouhaveacomponentconfigbaseprojectweneedtocustomizethe +valuesthatarepassedintothecontroller,todothiswecantakealookat `config/manager/controller_manager_config.yaml`. -{{#literatego ./testdata/controller_manager_config.yaml}} +{{#literatego./testdata/controller_manager_config.yaml}} -To see all the available fields you can look at the `v1alpha` Controller -Runtime config [ControllerManagerConfiguration][configtype] +Toseealltheavailablefieldsyoucanlookatthe`v1alpha`Controller +Runtimeconfig[ControllerManagerConfiguration][configtype] -[configtype]: https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1#ControllerManagerConfigurationSpec \ No newline at end of file +[configtype]:https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1#ControllerManagerConfigurationSpec \ No newline at end of file diff --git a/docs/book/src/component-config-tutorial/define-custom-config.md b/docs/book/src/component-config-tutorial/define-custom-config.md index 454b45b3c6a..21b0037f995 100644 --- a/docs/book/src/component-config-tutorial/define-custom-config.md +++ b/docs/book/src/component-config-tutorial/define-custom-config.md @@ -1,23 +1,23 @@ -# Defining your Custom Config +#DefiningyourCustomConfig - -Now that you have a custom component config we change the -`config/manager/controller_manager_config.yaml` to use the new GVK you defined. +Nowthatyouhaveacustomcomponentconfigwechangethe +`config/manager/controller_manager_config.yaml`tousethenewGVKyoudefined. -{{#literatego ./testdata/project/config/manager/controller_manager_config.yaml}} +{{#literatego./testdata/project/config/manager/controller_manager_config.yaml}} -This type uses the new `ProjectConfig` kind under the GVK -`config.tutorial.kubebuilder.io/v2`, with these custom configs we can add any -`yaml` serializable fields that your controller needs and begin to reduce the -reliance on `flags` to configure your project. \ No newline at end of file +Thistypeusesthenew`ProjectConfig`kindundertheGVK +`config.tutorial.kubebuilder.io/v2`,withthesecustomconfigswecanaddany +`yaml`serializablefieldsthatyourcontrollerneedsandbegintoreducethe +relianceon`flags`toconfigureyourproject. \ No newline at end of file diff --git a/docs/book/src/component-config-tutorial/testdata/project/README.md b/docs/book/src/component-config-tutorial/testdata/project/README.md index 3fca7276d17..71917a215b4 100644 --- a/docs/book/src/component-config-tutorial/testdata/project/README.md +++ b/docs/book/src/component-config-tutorial/testdata/project/README.md @@ -1,114 +1,114 @@ -# project -// TODO(user): Add simple overview of use/purpose +#project +//TODO(user):Addsimpleoverviewofuse/purpose -## Description -// TODO(user): An in-depth paragraph about your project and overview of use +##Description +//TODO(user):Anin-depthparagraphaboutyourprojectandoverviewofuse -## Getting Started +##GettingStarted -### Prerequisites -- go version v1.21.0+ -- docker version 17.03+. -- kubectl version v1.11.3+. -- Access to a Kubernetes v1.11.3+ cluster. +###Prerequisites +-goversionv1.21.0+ +-dockerversion17.03+. +-kubectlversionv1.11.3+. +-AccesstoaKubernetesv1.11.3+cluster. -### To Deploy on the cluster -**Build and push your image to the location specified by `IMG`:** +###ToDeployonthecluster +**Buildandpushyourimagetothelocationspecifiedby`IMG`:** ```sh -make docker-build docker-push IMG=/project:tag +makedocker-builddocker-pushIMG=/project: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. +**NOTE:**Thisimageoughttobepublishedinthepersonalregistryyouspecified. +Anditisrequiredtohaveaccesstopulltheimagefromtheworkingenvironment. +Makesureyouhavetheproperpermissiontotheregistryiftheabovecommandsdon’twork. -**Install the CRDs into the cluster:** +**InstalltheCRDsintothecluster:** ```sh -make install +makeinstall ``` -**Deploy the Manager to the cluster with the image specified by `IMG`:** +**DeploytheManagertotheclusterwiththeimagespecifiedby`IMG`:** ```sh -make deploy IMG=/project:tag +makedeployIMG=/project:tag ``` -> **NOTE**: If you encounter RBAC errors, you may need to grant yourself cluster-admin -privileges or be logged in as admin. +>**NOTE**:IfyouencounterRBACerrors,youmayneedtograntyourselfcluster-admin +privilegesorbeloggedinasadmin. -**Create instances of your solution** -You can apply the samples (examples) from the config/sample: +**Createinstancesofyoursolution** +Youcanapplythesamples(examples)fromtheconfig/sample: ```sh -kubectl apply -k config/samples/ +kubectlapply-kconfig/samples/ ``` ->**NOTE**: Ensure that the samples has default values to test it out. +>**NOTE**:Ensurethatthesampleshasdefaultvaluestotestitout. -### To Uninstall -**Delete the instances (CRs) from the cluster:** +###ToUninstall +**Deletetheinstances(CRs)fromthecluster:** ```sh -kubectl delete -k config/samples/ +kubectldelete-kconfig/samples/ ``` -**Delete the APIs(CRDs) from the cluster:** +**DeletetheAPIs(CRDs)fromthecluster:** ```sh -make uninstall +makeuninstall ``` -**UnDeploy the controller from the cluster:** +**UnDeploythecontrollerfromthecluster:** ```sh -make undeploy +makeundeploy ``` -## Project Distribution +##ProjectDistribution -Following are the steps to build the installer and distribute this project to users. +Followingarethestepstobuildtheinstalleranddistributethisprojecttousers. -1. Build the installer for the image built and published in the registry: +1.Buildtheinstallerfortheimagebuiltandpublishedintheregistry: ```sh -make build-installer IMG=/project:tag +makebuild-installerIMG=/project: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. +NOTE:Themakefiletargetmentionedabovegeneratesan'install.yaml' +fileinthedistdirectory.Thisfilecontainsalltheresourcesbuilt +withKustomize,whicharenecessarytoinstallthisprojectwithout +itsdependencies. -2. Using the installer +2.Usingtheinstaller -Users can just run kubectl apply -f to install the project, i.e.: +Userscanjustrunkubectlapply-ftoinstalltheproject,i.e.: ```sh -kubectl apply -f https://raw.githubusercontent.com//project//dist/install.yaml +kubectlapply-fhttps://raw.githubusercontent.com//project//dist/install.yaml ``` -## Contributing -// TODO(user): Add detailed information on how you would like others to contribute to this project +##Contributing +//TODO(user):Adddetailedinformationonhowyouwouldlikeotherstocontributetothisproject -**NOTE:** Run `make help` for more information on all potential `make` targets +**NOTE:**Run`makehelp`formoreinformationonallpotential`make`targets -More information can be found via the [Kubebuilder Documentation](https://book.kubebuilder.io/introduction.html) +Moreinformationcanbefoundviathe[KubebuilderDocumentation](https://book.kubebuilder.io/introduction.html) -## License +##License -Copyright 2024 The Kubernetes authors. +Copyright2024TheKubernetesauthors. -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 +LicensedundertheApacheLicense,Version2.0(the"License"); +youmaynotusethisfileexceptincompliancewiththeLicense. +YoumayobtainacopyoftheLicenseat - http://www.apache.org/licenses/LICENSE-2.0 +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. +Unlessrequiredbyapplicablelaworagreedtoinwriting,software +distributedundertheLicenseisdistributedonan"ASIS"BASIS, +WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied. +SeetheLicenseforthespecificlanguagegoverningpermissionsand +limitationsundertheLicense. diff --git a/docs/book/src/component-config-tutorial/tutorial.md b/docs/book/src/component-config-tutorial/tutorial.md index 4482f686bb2..e1daa55ea8b 100644 --- a/docs/book/src/component-config-tutorial/tutorial.md +++ b/docs/book/src/component-config-tutorial/tutorial.md @@ -1,47 +1,47 @@ -# Tutorial: ComponentConfig +#Tutorial:ComponentConfig - -Nearly every project that is built for Kubernetes will eventually need to -support passing in additional configurations into the controller. These could -be to enable better logging, turn on/off specific feature gates, set the sync -period, or a myriad of other controls. Previously this was commonly done using -cli `flags` that your `main.go` would parse to make them accessible within your -program. While this _works_ it's not a future forward design and the Kubernetes -community has been migrating the core components away from this and toward -using versioned config files, referred to as "component configs". +NearlyeveryprojectthatisbuiltforKuberneteswilleventuallyneedto +supportpassinginadditionalconfigurationsintothecontroller.Thesecould +betoenablebetterlogging,turnon/offspecificfeaturegates,setthesync +period,oramyriadofothercontrols.Previouslythiswascommonlydoneusing +cli`flags`thatyour`main.go`wouldparsetomakethemaccessiblewithinyour +program.Whilethis_works_it'snotafutureforwarddesignandtheKubernetes +communityhasbeenmigratingthecorecomponentsawayfromthisandtoward +usingversionedconfigfiles,referredtoas"componentconfigs". -The rest of this tutorial will show you how to configure your kubebuilder -project with the component config type then moves on to implementing a custom -type so that you can extend this capability. +Therestofthistutorialwillshowyouhowtoconfigureyourkubebuilder +projectwiththecomponentconfigtypethenmovesontoimplementingacustom +typesothatyoucanextendthiscapability. - -## Resources +##Resources -* [Versioned Component Configuration File Design](https://github.com/kubernetes/community/blob/master/archive/wg-component-standard/component-config/README.md) +*[VersionedComponentConfigurationFileDesign](https://github.com/kubernetes/community/blob/master/archive/wg-component-standard/component-config/README.md) -* [Config v1alpha1 Go Docs](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/) +*[Configv1alpha1GoDocs](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/) diff --git a/docs/book/src/component-config-tutorial/updating-main.md b/docs/book/src/component-config-tutorial/updating-main.md index 64518b1f0ac..aa8a52fc5ac 100644 --- a/docs/book/src/component-config-tutorial/updating-main.md +++ b/docs/book/src/component-config-tutorial/updating-main.md @@ -1,56 +1,56 @@ -# Updating main +#Updatingmain - -Once you have defined your new custom component config type we need to make -sure our new config type has been imported and the types are registered with -the scheme. _If you used `kubebuilder create api` this should have been +Onceyouhavedefinedyournewcustomcomponentconfigtypeweneedtomake +sureournewconfigtypehasbeenimportedandthetypesareregisteredwith +thescheme._Ifyouused`kubebuildercreateapi`thisshouldhavebeen automated._ ```go -import ( - // ... other imports - configv2 "tutorial.kubebuilder.io/project/apis/config/v2" - // +kubebuilder:scaffold:imports +import( +//...otherimports +configv2"tutorial.kubebuilder.io/project/apis/config/v2" +//+kubebuilder:scaffold:imports ) ``` -With the package imported we can confirm the types have been added. +Withthepackageimportedwecanconfirmthetypeshavebeenadded. ```go -func init() { - // ... other scheme registrations - utilruntime.Must(configv2.AddToScheme(scheme)) - // +kubebuilder:scaffold:scheme +funcinit(){ +//...otherschemeregistrations +utilruntime.Must(configv2.AddToScheme(scheme)) +//+kubebuilder:scaffold:scheme } ``` -Lastly, we need to change the options parsing in -`main.go` to use this new type. To do this we'll chain `OfKind` onto -`ctrl.ConfigFile()` and pass in a pointer to the config kind. +Lastly,weneedtochangetheoptionsparsingin +`main.go`tousethisnewtype.Todothiswe'llchain`OfKind`onto +`ctrl.ConfigFile()`andpassinapointertotheconfigkind. ```go -var err error -ctrlConfig := configv2.ProjectConfig{} -options := ctrl.Options{Scheme: scheme} -if configFile != "" { - options, err = options.AndFrom(ctrl.ConfigFile().AtPath(configFile).OfKind(&ctrlConfig)) - if err != nil { - setupLog.Error(err, "unable to load the config file") - os.Exit(1) - } +varerrerror +ctrlConfig:=configv2.ProjectConfig{} +options:=ctrl.Options{Scheme:scheme} +ifconfigFile!=""{ +options,err=options.AndFrom(ctrl.ConfigFile().AtPath(configFile).OfKind(&ctrlConfig)) +iferr!=nil{ +setupLog.Error(err,"unabletoloadtheconfigfile") +os.Exit(1) +} } ``` -Now if you need to use the `.clusterName` field we defined in our custom kind -you can call `ctrlConfig.ClusterName` which will be populated from the config -file supplied. \ No newline at end of file +Nowifyouneedtousethe`.clusterName`fieldwedefinedinourcustomkind +youcancall`ctrlConfig.ClusterName`whichwillbepopulatedfromtheconfig +filesupplied. \ No newline at end of file diff --git a/docs/book/src/cronjob-tutorial/api-design.md b/docs/book/src/cronjob-tutorial/api-design.md index 46c53a5ccec..c651790922b 100644 --- a/docs/book/src/cronjob-tutorial/api-design.md +++ b/docs/book/src/cronjob-tutorial/api-design.md @@ -1,47 +1,47 @@ -# Designing an API - -In Kubernetes, we have a few rules for how we design APIs. Namely, all -serialized fields *must* be `camelCase`, so we use JSON struct tags to -specify this. We can also use the `omitempty` struct tag to mark that -a field should be omitted from serialization when empty. - -Fields may use most of the primitive types. Numbers are the exception: -for API compatibility purposes, we accept three forms of numbers: `int32` -and `int64` for integers, and `resource.Quantity` for decimals. - -
Hold up, what's a Quantity? - -Quantities are a special notation for decimal numbers that have an -explicitly fixed representation that makes them more portable across -machines. You've probably noticed them when specifying resources requests -and limits on pods in Kubernetes. - -They conceptually work similar to floating point numbers: they have -a significant, base, and exponent. Their serializable and human readable format -uses whole numbers and suffixes to specify values much the way we describe -computer storage. - -For instance, the value `2m` means `0.002` in decimal notation. `2Ki` -means `2048` in decimal, while `2K` means `2000` in decimal. If we want -to specify fractions, we switch to a suffix that lets us use a whole -number: `2.5` is `2500m`. - -There are two supported bases: 10 and 2 (called decimal and binary, -respectively). Decimal base is indicated with "normal" SI suffixes (e.g. -`M` and `K`), while Binary base is specified in "mebi" notation (e.g. `Mi` -and `Ki`). Think [megabytes vs +#DesigninganAPI + +InKubernetes,wehaveafewrulesforhowwedesignAPIs.Namely,all +serializedfields*must*be`camelCase`,soweuseJSONstructtagsto +specifythis.Wecanalsousethe`omitempty`structtagtomarkthat +afieldshouldbeomittedfromserializationwhenempty. + +Fieldsmayusemostoftheprimitivetypes.Numbersaretheexception: +forAPIcompatibilitypurposes,weacceptthreeformsofnumbers:`int32` +and`int64`forintegers,and`resource.Quantity`fordecimals. + +
Holdup,what'saQuantity? + +Quantitiesareaspecialnotationfordecimalnumbersthathavean +explicitlyfixedrepresentationthatmakesthemmoreportableacross +machines.You'veprobablynoticedthemwhenspecifyingresourcesrequests +andlimitsonpodsinKubernetes. + +Theyconceptuallyworksimilartofloatingpointnumbers:theyhave +asignificant,base,andexponent.Theirserializableandhumanreadableformat +useswholenumbersandsuffixestospecifyvaluesmuchthewaywedescribe +computerstorage. + +Forinstance,thevalue`2m`means`0.002`indecimalnotation.`2Ki` +means`2048`indecimal,while`2K`means`2000`indecimal.Ifwewant +tospecifyfractions,weswitchtoasuffixthatletsususeawhole +number:`2.5`is`2500m`. + +Therearetwosupportedbases:10and2(calleddecimalandbinary, +respectively).Decimalbaseisindicatedwith"normal"SIsuffixes(e.g. +`M`and`K`),whileBinarybaseisspecifiedin"mebi"notation(e.g.`Mi` +and`Ki`).Think[megabytesvs mebibytes](https://en.wikipedia.org/wiki/Binary_prefix).
-There's one other special type that we use: `metav1.Time`. This functions -identically to `time.Time`, except that it has a fixed, portable -serialization format. +There'soneotherspecialtypethatweuse:`metav1.Time`.Thisfunctions +identicallyto`time.Time`,exceptthatithasafixed,portable +serializationformat. -With that out of the way, let's take a look at what our CronJob object -looks like! +Withthatoutoftheway,let'stakealookatwhatourCronJobobject +lookslike! -{{#literatego ./testdata/project/api/v1/cronjob_types.go}} +{{#literatego./testdata/project/api/v1/cronjob_types.go}} -Now that we have an API, we'll need to write a controller to actually -implement the functionality. +NowthatwehaveanAPI,we'llneedtowriteacontrollertoactually +implementthefunctionality. diff --git a/docs/book/src/cronjob-tutorial/basic-project.md b/docs/book/src/cronjob-tutorial/basic-project.md index d333cecc3fd..e13dfe579f2 100644 --- a/docs/book/src/cronjob-tutorial/basic-project.md +++ b/docs/book/src/cronjob-tutorial/basic-project.md @@ -1,57 +1,57 @@ -# What's in a basic project? +#What'sinabasicproject? -When scaffolding out a new project, Kubebuilder provides us with a few -basic pieces of boilerplate. +Whenscaffoldingoutanewproject,Kubebuilderprovidesuswithafew +basicpiecesofboilerplate. -## Build Infrastructure +##BuildInfrastructure -First up, basic infrastructure for building your project: +Firstup,basicinfrastructureforbuildingyourproject: -
go.mod: A new Go module matching our project, with -basic dependencies +
go.mod:AnewGomodulematchingourproject,with +basicdependencies ```go -{{#include ./testdata/project/go.mod}} +{{#include./testdata/project/go.mod}} ```
-
Makefile: Make targets for building and deploying your controller +
Makefile:Maketargetsforbuildinganddeployingyourcontroller ```makefile -{{#include ./testdata/project/Makefile}} +{{#include./testdata/project/Makefile}} ```
-
PROJECT: Kubebuilder metadata for scaffolding new components +
PROJECT:Kubebuildermetadataforscaffoldingnewcomponents ```yaml -{{#include ./testdata/project/PROJECT}} +{{#include./testdata/project/PROJECT}} ```
-## Launch Configuration +##LaunchConfiguration -We also get launch configurations under the +Wealsogetlaunchconfigurationsunderthe [`config/`](https://github.com/kubernetes-sigs/kubebuilder/tree/master/docs/book/src/cronjob-tutorial/testdata/project/config) -directory. Right now, it just contains -[Kustomize](https://sigs.k8s.io/kustomize) YAML definitions required to -launch our controller on a cluster, but once we get started writing our -controller, it'll also hold our CustomResourceDefinitions, RBAC -configuration, and WebhookConfigurations. +directory.Rightnow,itjustcontains +[Kustomize](https://sigs.k8s.io/kustomize)YAMLdefinitionsrequiredto +launchourcontrolleronacluster,butoncewegetstartedwritingour +controller,it'llalsoholdourCustomResourceDefinitions,RBAC +configuration,andWebhookConfigurations. -[`config/default`](https://github.com/kubernetes-sigs/kubebuilder/tree/master/docs/book/src/cronjob-tutorial/testdata/project/config/default) contains a [Kustomize base](https://github.com/kubernetes-sigs/kubebuilder/blob/master/docs/book/src/cronjob-tutorial/testdata/project/config/default/kustomization.yaml) for launching -the controller in a standard configuration. +[`config/default`](https://github.com/kubernetes-sigs/kubebuilder/tree/master/docs/book/src/cronjob-tutorial/testdata/project/config/default)containsa[Kustomizebase](https://github.com/kubernetes-sigs/kubebuilder/blob/master/docs/book/src/cronjob-tutorial/testdata/project/config/default/kustomization.yaml)forlaunching +thecontrollerinastandardconfiguration. -Each other directory contains a different piece of configuration, -refactored out into its own base: +Eachotherdirectorycontainsadifferentpieceofconfiguration, +refactoredoutintoitsownbase: -- [`config/manager`](https://github.com/kubernetes-sigs/kubebuilder/tree/master/docs/book/src/cronjob-tutorial/testdata/project/config/manager): launch your controllers as pods in the - cluster +-[`config/manager`](https://github.com/kubernetes-sigs/kubebuilder/tree/master/docs/book/src/cronjob-tutorial/testdata/project/config/manager):launchyourcontrollersaspodsinthe +cluster -- [`config/rbac`](https://github.com/kubernetes-sigs/kubebuilder/tree/master/docs/book/src/cronjob-tutorial/testdata/project/config/rbac): permissions required to run your - controllers under their own service account +-[`config/rbac`](https://github.com/kubernetes-sigs/kubebuilder/tree/master/docs/book/src/cronjob-tutorial/testdata/project/config/rbac):permissionsrequiredtorunyour +controllersundertheirownserviceaccount -## The Entrypoint +##TheEntrypoint -Last, but certainly not least, Kubebuilder scaffolds out the basic -entrypoint of our project: `main.go`. Let's take a look at that next... +Last,butcertainlynotleast,Kubebuilderscaffoldsoutthebasic +entrypointofourproject:`main.go`.Let'stakealookatthatnext... diff --git a/docs/book/src/cronjob-tutorial/cert-manager.md b/docs/book/src/cronjob-tutorial/cert-manager.md index c2596deb8f8..b3b14e9f3b5 100644 --- a/docs/book/src/cronjob-tutorial/cert-manager.md +++ b/docs/book/src/cronjob-tutorial/cert-manager.md @@ -1,29 +1,29 @@ -# Deploying cert-manager +#Deployingcert-manager -We suggest using [cert-manager](https://github.com/cert-manager/cert-manager) for -provisioning the certificates for the webhook server. Other solutions should -also work as long as they put the certificates in the desired location. +Wesuggestusing[cert-manager](https://github.com/cert-manager/cert-manager)for +provisioningthecertificatesforthewebhookserver.Othersolutionsshould +alsoworkaslongastheyputthecertificatesinthedesiredlocation. -You can follow -[the cert-manager documentation](https://cert-manager.io/docs/installation/) -to install it. +Youcanfollow +[thecert-managerdocumentation](https://cert-manager.io/docs/installation/) +toinstallit. -cert-manager also has a component called [CA -Injector](https://cert-manager.io/docs/concepts/ca-injector/), which is responsible for -injecting the CA bundle into the [`MutatingWebhookConfiguration`](https://pkg.go.dev/k8s.io/api/admissionregistration/v1#MutatingWebhookConfiguration) -/ [`ValidatingWebhookConfiguration`](https://pkg.go.dev/k8s.io/api/admissionregistration/v1#ValidatingWebhookConfiguration). +cert-manageralsohasacomponentcalled[CA +Injector](https://cert-manager.io/docs/concepts/ca-injector/),whichisresponsiblefor +injectingtheCAbundleintothe[`MutatingWebhookConfiguration`](https://pkg.go.dev/k8s.io/api/admissionregistration/v1#MutatingWebhookConfiguration) +/[`ValidatingWebhookConfiguration`](https://pkg.go.dev/k8s.io/api/admissionregistration/v1#ValidatingWebhookConfiguration). -To accomplish that, you need to use an annotation with key +Toaccomplishthat,youneedtouseanannotationwithkey `cert-manager.io/inject-ca-from` -in the [`MutatingWebhookConfiguration`](https://pkg.go.dev/k8s.io/api/admissionregistration/v1#MutatingWebhookConfiguration) -/ [`ValidatingWebhookConfiguration`](https://pkg.go.dev/k8s.io/api/admissionregistration/v1#ValidatingWebhookConfiguration) objects. -The value of the annotation should point to an existing [certificate request instance](https://cert-manager.io/docs/concepts/certificaterequest/) -in the format of `/`. +inthe[`MutatingWebhookConfiguration`](https://pkg.go.dev/k8s.io/api/admissionregistration/v1#MutatingWebhookConfiguration) +/[`ValidatingWebhookConfiguration`](https://pkg.go.dev/k8s.io/api/admissionregistration/v1#ValidatingWebhookConfiguration)objects. +Thevalueoftheannotationshouldpointtoanexisting[certificaterequestinstance](https://cert-manager.io/docs/concepts/certificaterequest/) +intheformatof`/`. -This is the [kustomize](https://github.com/kubernetes-sigs/kustomize) patch we -used for annotating the [`MutatingWebhookConfiguration`](https://pkg.go.dev/k8s.io/api/admissionregistration/v1#MutatingWebhookConfiguration) -/ [`ValidatingWebhookConfiguration`](https://pkg.go.dev/k8s.io/api/admissionregistration/v1#ValidatingWebhookConfiguration) objects. +Thisisthe[kustomize](https://github.com/kubernetes-sigs/kustomize)patchwe +usedforannotatingthe[`MutatingWebhookConfiguration`](https://pkg.go.dev/k8s.io/api/admissionregistration/v1#MutatingWebhookConfiguration) +/[`ValidatingWebhookConfiguration`](https://pkg.go.dev/k8s.io/api/admissionregistration/v1#ValidatingWebhookConfiguration)objects. ```yaml -{{#include ./testdata/project/config/default/webhookcainjection_patch.yaml}} +{{#include./testdata/project/config/default/webhookcainjection_patch.yaml}} ``` diff --git a/docs/book/src/cronjob-tutorial/controller-implementation.md b/docs/book/src/cronjob-tutorial/controller-implementation.md index be548e069a1..f8784c13793 100644 --- a/docs/book/src/cronjob-tutorial/controller-implementation.md +++ b/docs/book/src/cronjob-tutorial/controller-implementation.md @@ -1,24 +1,24 @@ -# Implementing a controller +#Implementingacontroller -The basic logic of our CronJob controller is this: +ThebasiclogicofourCronJobcontrolleristhis: -1. Load the named CronJob +1.LoadthenamedCronJob -2. List all active jobs, and update the status +2.Listallactivejobs,andupdatethestatus -3. Clean up old jobs according to the history limits +3.Cleanupoldjobsaccordingtothehistorylimits -4. Check if we're suspended (and don't do anything else if we are) +4.Checkifwe'resuspended(anddon'tdoanythingelseifweare) -5. Get the next scheduled run +5.Getthenextscheduledrun -6. Run a new job if it's on schedule, not past the deadline, and not - blocked by our concurrency policy +6.Runanewjobifit'sonschedule,notpastthedeadline,andnot +blockedbyourconcurrencypolicy -7. Requeue when we either see a running job (done automatically) or it's - time for the next scheduled run. +7.Requeuewhenweeitherseearunningjob(doneautomatically)orit's +timeforthenextscheduledrun. -{{#literatego ./testdata/project/internal/controller/cronjob_controller.go}} +{{#literatego./testdata/project/internal/controller/cronjob_controller.go}} -That was a doozy, but now we've got a working controller. Let's test -against the cluster, then, if we don't have any issues, deploy it! +Thatwasadoozy,butnowwe'vegotaworkingcontroller.Let'stest +againstthecluster,then,ifwedon'thaveanyissues,deployit! diff --git a/docs/book/src/cronjob-tutorial/controller-overview.md b/docs/book/src/cronjob-tutorial/controller-overview.md index 779ec9f0994..c851efba7a6 100644 --- a/docs/book/src/cronjob-tutorial/controller-overview.md +++ b/docs/book/src/cronjob-tutorial/controller-overview.md @@ -1,22 +1,22 @@ -# What's in a controller? +#What'sinacontroller? -Controllers are the core of Kubernetes, and of any operator. +ControllersarethecoreofKubernetes,andofanyoperator. -It's a controller's job to ensure that, for any given object, the actual -state of the world (both the cluster state, and potentially external state -like running containers for Kubelet or loadbalancers for a cloud provider) -matches the desired state in the object. Each controller focuses on one -*root* Kind, but may interact with other Kinds. +It'sacontroller'sjobtoensurethat,foranygivenobject,theactual +stateoftheworld(boththeclusterstate,andpotentiallyexternalstate +likerunningcontainersforKubeletorloadbalancersforacloudprovider) +matchesthedesiredstateintheobject.Eachcontrollerfocusesonone +*root*Kind,butmayinteractwithotherKinds. -We call this process *reconciling*. +Wecallthisprocess*reconciling*. -In controller-runtime, the logic that implements the reconciling for -a specific kind is called a [*Reconciler*](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/reconcile?tab=doc). A reconciler -takes the name of an object, and returns whether or not we need to try -again (e.g. in case of errors or periodic controllers, like the +Incontroller-runtime,thelogicthatimplementsthereconcilingfor +aspecifickindiscalleda[*Reconciler*](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/reconcile?tab=doc).Areconciler +takesthenameofanobject,andreturnswhetherornotweneedtotry +again(e.g.incaseoferrorsorperiodiccontrollers,likethe HorizontalPodAutoscaler). -{{#literatego ./testdata/emptycontroller.go}} +{{#literatego./testdata/emptycontroller.go}} -Now that we've seen the basic structure of a reconciler, let's fill out -the logic for `CronJob`s. +Nowthatwe'veseenthebasicstructureofareconciler,let'sfillout +thelogicfor`CronJob`s. diff --git a/docs/book/src/cronjob-tutorial/cronjob-tutorial.md b/docs/book/src/cronjob-tutorial/cronjob-tutorial.md index f87ae89d94c..b4b2cfad4f5 100644 --- a/docs/book/src/cronjob-tutorial/cronjob-tutorial.md +++ b/docs/book/src/cronjob-tutorial/cronjob-tutorial.md @@ -1,77 +1,77 @@ -# Tutorial: Building CronJob +#Tutorial:BuildingCronJob -Too many tutorials start out with some really contrived setup, or some toy -application that gets the basics across, and then stalls out on the more -complicated stuff. Instead, this tutorial should take you through (almost) -the full gamut of complexity with Kubebuilder, starting off simple and -building up to something pretty full-featured. +Toomanytutorialsstartoutwithsomereallycontrivedsetup,orsometoy +applicationthatgetsthebasicsacross,andthenstallsoutonthemore +complicatedstuff.Instead,thistutorialshouldtakeyouthrough(almost) +thefullgamutofcomplexitywithKubebuilder,startingoffsimpleand +buildinguptosomethingprettyfull-featured. -Let's pretend (and sure, this is a teensy bit contrived) that we've -finally gotten tired of the maintenance burden of the non-Kubebuilder -implementation of the CronJob controller in Kubernetes, and we'd like to -rewrite it using Kubebuilder. +Let'spretend(andsure,thisisateensybitcontrived)thatwe've +finallygottentiredofthemaintenanceburdenofthenon-Kubebuilder +implementationoftheCronJobcontrollerinKubernetes,andwe'dliketo +rewriteitusingKubebuilder. -The job (no pun intended) of the *CronJob* controller is to run one-off -tasks on the Kubernetes cluster at regular intervals. It does this by -building on top of the *Job* controller, whose task is to run one-off tasks -once, seeing them to completion. +Thejob(nopunintended)ofthe*CronJob*controlleristorunone-off +tasksontheKubernetesclusteratregularintervals.Itdoesthisby +buildingontopofthe*Job*controller,whosetaskistorunone-offtasks +once,seeingthemtocompletion. -Instead of trying to tackle rewriting the Job controller as well, we'll -use this as an opportunity to see how to interact with external types. +InsteadoftryingtotacklerewritingtheJobcontrolleraswell,we'll +usethisasanopportunitytoseehowtointeractwithexternaltypes. - -## Scaffolding Out Our Project +##ScaffoldingOutOurProject -As covered in the [quick start](../quick-start.md), we'll need to scaffold -out a new project. Make sure you've [installed -Kubebuilder](../quick-start.md#installation), then scaffold out a new +Ascoveredinthe[quickstart](../quick-start.md),we'llneedtoscaffold +outanewproject.Makesureyou've[installed +Kubebuilder](../quick-start.md#installation),thenscaffoldoutanew project: ```bash -# create a project directory, and then run the init command. -mkdir project -cd project -# we'll use a domain of tutorial.kubebuilder.io, -# so all API groups will be .tutorial.kubebuilder.io. -kubebuilder init --domain tutorial.kubebuilder.io --repo tutorial.kubebuilder.io/project +#createaprojectdirectory,andthenruntheinitcommand. +mkdirproject +cdproject +#we'lluseadomainoftutorial.kubebuilder.io, +#soallAPIgroupswillbe.tutorial.kubebuilder.io. +kubebuilderinit--domaintutorial.kubebuilder.io--repotutorial.kubebuilder.io/project ``` - -Now that we've got a project in place, let's take a look at what -Kubebuilder has scaffolded for us so far... +Nowthatwe'vegotaprojectinplace,let'stakealookatwhat +Kubebuilderhasscaffoldedforussofar... - -[GOPATH-golang-docs]: https://golang.org/doc/code.html#GOPATH -[go-modules-blogpost]: https://blog.golang.org/using-go-modules \ No newline at end of file +[GOPATH-golang-docs]:https://golang.org/doc/code.html#GOPATH +[go-modules-blogpost]:https://blog.golang.org/using-go-modules \ No newline at end of file diff --git a/docs/book/src/cronjob-tutorial/empty-main.md b/docs/book/src/cronjob-tutorial/empty-main.md index 27af11c5ef9..8ecb04e11e3 100644 --- a/docs/book/src/cronjob-tutorial/empty-main.md +++ b/docs/book/src/cronjob-tutorial/empty-main.md @@ -1,5 +1,5 @@ -# Every journey needs a start, every program needs a main +#Everyjourneyneedsastart,everyprogramneedsamain -{{#literatego ./testdata/emptymain.go}} +{{#literatego./testdata/emptymain.go}} -With that out of the way, we can get on to scaffolding our API! +Withthatoutoftheway,wecangetontoscaffoldingourAPI! diff --git a/docs/book/src/cronjob-tutorial/epilogue.md b/docs/book/src/cronjob-tutorial/epilogue.md index f72386ac9ca..aa170f957a8 100644 --- a/docs/book/src/cronjob-tutorial/epilogue.md +++ b/docs/book/src/cronjob-tutorial/epilogue.md @@ -1,16 +1,16 @@ -# Epilogue +#Epilogue -By this point, we've got a pretty full-featured implementation of the -CronJob controller, made use of most of the features of -Kubebuilder, and written tests for the controller using envtest. +Bythispoint,we'vegotaprettyfull-featuredimplementationofthe +CronJobcontroller,madeuseofmostofthefeaturesof +Kubebuilder,andwrittentestsforthecontrollerusingenvtest. -If you want more, head over to the [Multi-Version -Tutorial](/multiversion-tutorial/tutorial.md) to learn how to add new API -versions to a project. +Ifyouwantmore,headovertothe[Multi-Version +Tutorial](/multiversion-tutorial/tutorial.md)tolearnhowtoaddnewAPI +versionstoaproject. -Additionally, you can try the following steps on your own -- we'll have -a tutorial section on them Soon™: +Additionally,youcantrythefollowingstepsonyourown--we'llhave +atutorialsectiononthemSoon™: -- adding [additional printer columns][printer-columns] `kubectl get` +-adding[additionalprintercolumns][printer-columns]`kubectlget` -[printer-columns]: /reference/generating-crd.md#additional-printer-columns +[printer-columns]:/reference/generating-crd.md#additional-printer-columns diff --git a/docs/book/src/cronjob-tutorial/gvks.md b/docs/book/src/cronjob-tutorial/gvks.md index 0526c0e5169..05c91878ee7 100644 --- a/docs/book/src/cronjob-tutorial/gvks.md +++ b/docs/book/src/cronjob-tutorial/gvks.md @@ -1,94 +1,94 @@ -# Groups and Versions and Kinds, oh my! +#GroupsandVersionsandKinds,ohmy! -Actually, before we get started with our API, we should talk terminology -a bit. +Actually,beforewegetstartedwithourAPI,weshouldtalkterminology +abit. -When we talk about APIs in Kubernetes, we often use 4 terms: *groups*, -*versions*, *kinds*, and *resources*. +WhenwetalkaboutAPIsinKubernetes,weoftenuse4terms:*groups*, +*versions*,*kinds*,and*resources*. -## Groups and Versions +##GroupsandVersions -An *API Group* in Kubernetes is simply a collection of related -functionality. Each group has one or more *versions*, which, as the name -suggests, allow us to change how an API works over time. +An*APIGroup*inKubernetesissimplyacollectionofrelated +functionality.Eachgrouphasoneormore*versions*,which,asthename +suggests,allowustochangehowanAPIworksovertime. -## Kinds and Resources +##KindsandResources -Each API group-version contains one or more API types, which we call -*Kinds*. While a Kind may change forms between versions, each form must -be able to store all the data of the other forms, somehow (we can store -the data in fields, or in annotations). This means that using an older -API version won't cause newer data to be lost or corrupted. See the -[Kubernetes API +EachAPIgroup-versioncontainsoneormoreAPItypes,whichwecall +*Kinds*.WhileaKindmaychangeformsbetweenversions,eachformmust +beabletostoreallthedataoftheotherforms,somehow(wecanstore +thedatainfields,orinannotations).Thismeansthatusinganolder +APIversionwon'tcausenewerdatatobelostorcorrupted.Seethe +[KubernetesAPI guidelines](https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md) -for more information. +formoreinformation. -You'll also hear mention of *resources* on occasion. A resource is simply -a use of a Kind in the API. Often, there's a one-to-one mapping between -Kinds and resources. For instance, the `pods` resource corresponds to the -`Pod` Kind. However, sometimes, the same Kind may be returned by multiple -resources. For instance, the `Scale` Kind is returned by all scale -subresources, like `deployments/scale` or `replicasets/scale`. This is -what allows the Kubernetes HorizontalPodAutoscaler to interact with -different resources. With CRDs, however, each Kind will correspond to -a single resource. +You'llalsohearmentionof*resources*onoccasion.Aresourceissimply +auseofaKindintheAPI.Often,there'saone-to-onemappingbetween +Kindsandresources.Forinstance,the`pods`resourcecorrespondstothe +`Pod`Kind.However,sometimes,thesameKindmaybereturnedbymultiple +resources.Forinstance,the`Scale`Kindisreturnedbyallscale +subresources,like`deployments/scale`or`replicasets/scale`.Thisis +whatallowstheKubernetesHorizontalPodAutoscalertointeractwith +differentresources.WithCRDs,however,eachKindwillcorrespondto +asingleresource. -Notice that resources are always lowercase, and by convention are the -lowercase form of the Kind. +Noticethatresourcesarealwayslowercase,andbyconventionarethe +lowercaseformoftheKind. -## So, how does that correspond to Go? +##So,howdoesthatcorrespondtoGo? -When we refer to a kind in a particular group-version, we'll call it -a *GroupVersionKind*, or GVK for short. Same with resources and GVR. As -we'll see shortly, each GVK corresponds to a given root Go type in -a package. +Whenwerefertoakindinaparticulargroup-version,we'llcallit +a*GroupVersionKind*,orGVKforshort.SamewithresourcesandGVR.As +we'llseeshortly,eachGVKcorrespondstoagivenrootGotypein +apackage. -Now that we have our terminology straight, we can *actually* create our +Nowthatwehaveourterminologystraight,wecan*actually*createour API! -## So, how can we create our API? +##So,howcanwecreateourAPI? -In the next section, [Adding a new API](../cronjob-tutorial/new-api.html), we will check how the tool helps us to -create our own APIs with the command `kubebuilder create api`. +Inthenextsection,[AddinganewAPI](../cronjob-tutorial/new-api.html),wewillcheckhowthetoolhelpsusto +createourownAPIswiththecommand`kubebuildercreateapi`. -The goal of this command is to create Custom Resource (CR) and Custom Resource Definition (CRD) for our Kind(s). To check it further see; [Extend the Kubernetes API with CustomResourceDefinitions][kubernetes-extend-api]. +ThegoalofthiscommandistocreateCustomResource(CR)andCustomResourceDefinition(CRD)forourKind(s).Tocheckitfurthersee;[ExtendtheKubernetesAPIwithCustomResourceDefinitions][kubernetes-extend-api]. -## But, why create APIs at all? +##But,whycreateAPIsatall? -New APIs are how we teach Kubernetes about our custom objects. The Go structs are used to generate a CRD which includes the schema for our data as well as tracking data like what our new type is called. We can then create instances of our custom objects which will be managed by our [controllers][controllers]. +NewAPIsarehowweteachKubernetesaboutourcustomobjects.TheGostructsareusedtogenerateaCRDwhichincludestheschemaforourdataaswellastrackingdatalikewhatournewtypeiscalled.Wecanthencreateinstancesofourcustomobjectswhichwillbemanagedbyour[controllers][controllers]. -Our APIs and resources represent our solutions on the clusters. Basically, the CRDs are a definition of our customized Objects, and the CRs are an instance of it. +OurAPIsandresourcesrepresentoursolutionsontheclusters.Basically,theCRDsareadefinitionofourcustomizedObjects,andtheCRsareaninstanceofit. -## Ah, do you have an example? +##Ah,doyouhaveanexample? -Let’s think about the classic scenario where the goal is to have an application and its database running on the platform with Kubernetes. Then, one CRD could represent the App, and another one could represent the DB. By having one CRD to describe the App and another one for the DB, we will not be hurting concepts such as encapsulation, the single responsibility principle, and cohesion. Damaging these concepts could cause unexpected side effects, such as difficulty in extending, reuse, or maintenance, just to mention a few. +Let’sthinkabouttheclassicscenariowherethegoalistohaveanapplicationanditsdatabaserunningontheplatformwithKubernetes.Then,oneCRDcouldrepresenttheApp,andanotheronecouldrepresenttheDB.ByhavingoneCRDtodescribetheAppandanotheronefortheDB,wewillnotbehurtingconceptssuchasencapsulation,thesingleresponsibilityprinciple,andcohesion.Damagingtheseconceptscouldcauseunexpectedsideeffects,suchasdifficultyinextending,reuse,ormaintenance,justtomentionafew. -In this way, we can create the App CRD which will have its controller and which would be responsible for things like creating Deployments that contain the App and creating Services to access it and etc. Similarly, we could create a CRD to represent the DB, and deploy a controller that would manage DB instances. +Inthisway,wecancreatetheAppCRDwhichwillhaveitscontrollerandwhichwouldberesponsibleforthingslikecreatingDeploymentsthatcontaintheAppandcreatingServicestoaccessitandetc.Similarly,wecouldcreateaCRDtorepresenttheDB,anddeployacontrollerthatwouldmanageDBinstances. -## Err, but what's that Scheme thing? +##Err,butwhat'sthatSchemething? -The `Scheme` we saw before is simply a way to keep track of what Go type -corresponds to a given GVK (don't be overwhelmed by its +The`Scheme`wesawbeforeissimplyawaytokeeptrackofwhatGotype +correspondstoagivenGVK(don'tbeoverwhelmedbyits [godocs](https://pkg.go.dev/k8s.io/apimachinery/pkg/runtime?tab=doc#Scheme)). -For instance, suppose we mark the -`"tutorial.kubebuilder.io/api/v1".CronJob{}` type as being in the -`batch.tutorial.kubebuilder.io/v1` API group (implicitly saying it has the -Kind `CronJob`). +Forinstance,supposewemarkthe +`"tutorial.kubebuilder.io/api/v1".CronJob{}`typeasbeinginthe +`batch.tutorial.kubebuilder.io/v1`APIgroup(implicitlysayingithasthe +Kind`CronJob`). -Then, we can later construct a new `&CronJob{}` given some JSON from the -API server that says +Then,wecanlaterconstructanew`&CronJob{}`givensomeJSONfromthe +APIserverthatsays ```json { - "kind": "CronJob", - "apiVersion": "batch.tutorial.kubebuilder.io/v1", - ... +"kind":"CronJob", +"apiVersion":"batch.tutorial.kubebuilder.io/v1", +... } ``` -or properly look up the group-version when we go to submit a `&CronJob{}` -in an update. +orproperlylookupthegroup-versionwhenwegotosubmita`&CronJob{}` +inanupdate. -[kubernetes-extend-api]: https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/ -[controllers]: ../cronjob-tutorial/controller-overview.md +[kubernetes-extend-api]:https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/ +[controllers]:../cronjob-tutorial/controller-overview.md diff --git a/docs/book/src/cronjob-tutorial/main-revisited.md b/docs/book/src/cronjob-tutorial/main-revisited.md index 4a8c0fd33dc..ed4f7067850 100644 --- a/docs/book/src/cronjob-tutorial/main-revisited.md +++ b/docs/book/src/cronjob-tutorial/main-revisited.md @@ -1,9 +1,9 @@ -# You said something about main? +#Yousaidsomethingaboutmain? -But first, remember how we said we'd [come back to `main.go` -again](/cronjob-tutorial/empty-main.md)? Let's take a look and see what's -changed, and what we need to add. +Butfirst,rememberhowwesaidwe'd[comebackto`main.go` +again](/cronjob-tutorial/empty-main.md)?Let'stakealookandseewhat's +changed,andwhatweneedtoadd. -{{#literatego ./testdata/project/cmd/main.go}} +{{#literatego./testdata/project/cmd/main.go}} -*Now* we can implement our controller. +*Now*wecanimplementourcontroller. diff --git a/docs/book/src/cronjob-tutorial/new-api.md b/docs/book/src/cronjob-tutorial/new-api.md index 9240754e773..3e4a9b65aa8 100644 --- a/docs/book/src/cronjob-tutorial/new-api.md +++ b/docs/book/src/cronjob-tutorial/new-api.md @@ -1,46 +1,46 @@ -# Adding a new API +#AddinganewAPI -To scaffold out a new Kind (you were paying attention to the [last -chapter](./gvks.md#kinds-and-resources), right?) and corresponding -controller, we can use `kubebuilder create api`: +ToscaffoldoutanewKind(youwerepayingattentiontothe[last +chapter](./gvks.md#kinds-and-resources),right?)andcorresponding +controller,wecanuse`kubebuildercreateapi`: ```bash -kubebuilder create api --group batch --version v1 --kind CronJob +kubebuildercreateapi--groupbatch--versionv1--kindCronJob ``` -Press `y` for "Create Resource" and "Create Controller". +Press`y`for"CreateResource"and"CreateController". -The first time we call this command for each group-version, it will create -a directory for the new group-version. +Thefirsttimewecallthiscommandforeachgroup-version,itwillcreate +adirectoryforthenewgroup-version. - -In this case, the +Inthiscase,the [`api/v1/`](https://sigs.k8s.io/kubebuilder/docs/book/src/cronjob-tutorial/testdata/project/api/v1) -directory is created, corresponding to the -`batch.tutorial.kubebuilder.io/v1` (remember our [`--domain` -setting](cronjob-tutorial.md#scaffolding-out-our-project) from the +directoryiscreated,correspondingtothe +`batch.tutorial.kubebuilder.io/v1`(rememberour[`--domain` +setting](cronjob-tutorial.md#scaffolding-out-our-project)fromthe beginning?). -It has also added a file for our `CronJob` Kind, -`api/v1/cronjob_types.go`. Each time we call the command with a different -kind, it'll add a corresponding new file. +Ithasalsoaddedafileforour`CronJob`Kind, +`api/v1/cronjob_types.go`.Eachtimewecallthecommandwithadifferent +kind,it'lladdacorrespondingnewfile. -Let's take a look at what we've been given out of the box, then we can -move on to filling it out. +Let'stakealookatwhatwe'vebeengivenoutofthebox,thenwecan +moveontofillingitout. -{{#literatego ./testdata/emptyapi.go}} +{{#literatego./testdata/emptyapi.go}} -Now that we've seen the basic structure, let's fill it out! +Nowthatwe'veseenthebasicstructure,let'sfillitout! diff --git a/docs/book/src/cronjob-tutorial/other-api-files.md b/docs/book/src/cronjob-tutorial/other-api-files.md index 82c6362db92..71c734d7345 100644 --- a/docs/book/src/cronjob-tutorial/other-api-files.md +++ b/docs/book/src/cronjob-tutorial/other-api-files.md @@ -1,28 +1,28 @@ -# A Brief Aside: What's the rest of this stuff? +#ABriefAside:What'stherestofthisstuff? -If you've taken a peek at the rest of the files in the +Ifyou'vetakenapeekattherestofthefilesinthe [`api/v1/`](https://sigs.k8s.io/kubebuilder/docs/book/src/cronjob-tutorial/testdata/project/api/v1) -directory, you might have noticed two additional files beyond -`cronjob_types.go`: `groupversion_info.go` and `zz_generated.deepcopy.go`. +directory,youmighthavenoticedtwoadditionalfilesbeyond +`cronjob_types.go`:`groupversion_info.go`and`zz_generated.deepcopy.go`. -Neither of these files ever needs to be edited (the former stays the same -and the latter is autogenerated), but it's useful to know what's in them. +Neitherofthesefileseverneedstobeedited(theformerstaysthesame +andthelatterisautogenerated),butit'susefultoknowwhat'sinthem. -## `groupversion_info.go` +##`groupversion_info.go` -`groupversion_info.go` contains common metadata about the group-version: +`groupversion_info.go`containscommonmetadataaboutthegroup-version: -{{#literatego ./testdata/project/api/v1/groupversion_info.go}} +{{#literatego./testdata/project/api/v1/groupversion_info.go}} -## `zz_generated.deepcopy.go` +##`zz_generated.deepcopy.go` -`zz_generated.deepcopy.go` contains the autogenerated implementation of -the aforementioned `runtime.Object` interface, which marks all of our root -types as representing Kinds. +`zz_generated.deepcopy.go`containstheautogeneratedimplementationof +theaforementioned`runtime.Object`interface,whichmarksallofourroot +typesasrepresentingKinds. -The core of the `runtime.Object` interface is a deep-copy method, +Thecoreofthe`runtime.Object`interfaceisadeep-copymethod, `DeepCopyObject`. -The `object` generator in controller-tools also generates two other handy -methods for each root type and all its sub-types: `DeepCopy` and +The`object`generatorincontroller-toolsalsogeneratestwootherhandy +methodsforeachroottypeandallitssub-types:`DeepCopy`and `DeepCopyInto`. diff --git a/docs/book/src/cronjob-tutorial/running-webhook.md b/docs/book/src/cronjob-tutorial/running-webhook.md index 222b8d645d8..b87e3f9d814 100644 --- a/docs/book/src/cronjob-tutorial/running-webhook.md +++ b/docs/book/src/cronjob-tutorial/running-webhook.md @@ -1,81 +1,81 @@ -# Deploying Admission Webhooks +#DeployingAdmissionWebhooks -## Kind Cluster +##KindCluster -It is recommended to develop your webhook with a -[kind](../reference/kind.md) cluster for faster iteration. +Itisrecommendedtodevelopyourwebhookwitha +[kind](../reference/kind.md)clusterforfasteriteration. Why? -- You can bring up a multi-node cluster locally within 1 minute. -- You can tear it down in seconds. -- You don't need to push your images to remote registry. +-Youcanbringupamulti-nodeclusterlocallywithin1minute. +-Youcantearitdowninseconds. +-Youdon'tneedtopushyourimagestoremoteregistry. -## cert-manager +##cert-manager -You need to follow [this](./cert-manager.md) to install the cert-manager bundle. +Youneedtofollow[this](./cert-manager.md)toinstallthecert-managerbundle. -## Build your image +##Buildyourimage -Run the following command to build your image locally. +Runthefollowingcommandtobuildyourimagelocally. ```bash -make docker-build docker-push IMG=/:tag +makedocker-builddocker-pushIMG=/:tag ``` -You don't need to push the image to a remote container registry if you are using -a kind cluster. You can directly load your local image to your specified kind cluster: +Youdon'tneedtopushtheimagetoaremotecontainerregistryifyouareusing +akindcluster.Youcandirectlyloadyourlocalimagetoyourspecifiedkindcluster: ```bash -kind load docker-image :tag --name +kindloaddocker-image:tag--name ``` -## Deploy Webhooks +##DeployWebhooks -You need to enable the webhook and cert manager configuration through kustomize. -`config/default/kustomization.yaml` should now look like the following: +Youneedtoenablethewebhookandcertmanagerconfigurationthroughkustomize. +`config/default/kustomization.yaml`shouldnowlooklikethefollowing: ```yaml -{{#include ./testdata/project/config/default/kustomization.yaml}} +{{#include./testdata/project/config/default/kustomization.yaml}} ``` -And `config/crd/kustomization.yaml` should now look like the following: +And`config/crd/kustomization.yaml`shouldnowlooklikethefollowing: ```yaml -{{#include ./testdata/project/config/crd/kustomization.yaml}} +{{#include./testdata/project/config/crd/kustomization.yaml}} ``` -Now you can deploy it to your cluster by +Nowyoucandeployittoyourclusterby ```bash -make deploy IMG=/:tag +makedeployIMG=/:tag ``` -Wait a while till the webhook pod comes up and the certificates are provisioned. -It usually completes within 1 minute. +Waitawhiletillthewebhookpodcomesupandthecertificatesareprovisioned. +Itusuallycompleteswithin1minute. -Now you can create a valid CronJob to test your webhooks. The creation should -successfully go through. +NowyoucancreateavalidCronJobtotestyourwebhooks.Thecreationshould +successfullygothrough. ```bash -kubectl create -f config/samples/batch_v1_cronjob.yaml +kubectlcreate-fconfig/samples/batch_v1_cronjob.yaml ``` -You can also try to create an invalid CronJob (e.g. use an ill-formatted -schedule field). You should see a creation failure with a validation error. +YoucanalsotrytocreateaninvalidCronJob(e.g.useanill-formatted +schedulefield).Youshouldseeacreationfailurewithavalidationerror. - -[namespaceSelector]: https://github.com/kubernetes/api/blob/kubernetes-1.14.5/admissionregistration/v1beta1/types.go#L189-L233 -[objectSelector]: https://github.com/kubernetes/api/blob/kubernetes-1.15.2/admissionregistration/v1beta1/types.go#L262-L274 +[namespaceSelector]:https://github.com/kubernetes/api/blob/kubernetes-1.14.5/admissionregistration/v1beta1/types.go#L189-L233 +[objectSelector]:https://github.com/kubernetes/api/blob/kubernetes-1.15.2/admissionregistration/v1beta1/types.go#L262-L274 diff --git a/docs/book/src/cronjob-tutorial/running.md b/docs/book/src/cronjob-tutorial/running.md index 15713044c2c..2a296b863eb 100644 --- a/docs/book/src/cronjob-tutorial/running.md +++ b/docs/book/src/cronjob-tutorial/running.md @@ -1,85 +1,85 @@ -# Running and deploying the controller +#Runninganddeployingthecontroller -### Optional -If opting to make any changes to the API definitions, then before proceeding, -generate the manifests like CRs or CRDs with +###Optional +IfoptingtomakeanychangestotheAPIdefinitions,thenbeforeproceeding, +generatethemanifestslikeCRsorCRDswith ```bash -make manifests +makemanifests ``` -To test out the controller, we can run it locally against the cluster. -Before we do so, though, we'll need to install our CRDs, as per the [quick -start](/quick-start.md). This will automatically update the YAML -manifests using controller-tools, if needed: +Totestoutthecontroller,wecanrunitlocallyagainstthecluster. +Beforewedoso,though,we'llneedtoinstallourCRDs,asperthe[quick +start](/quick-start.md).ThiswillautomaticallyupdatetheYAML +manifestsusingcontroller-tools,ifneeded: ```bash -make install +makeinstall ``` -Now that we've installed our CRDs, we can run the controller against our -cluster. This will use whatever credentials that we connect to the -cluster with, so we don't need to worry about RBAC just yet. +Nowthatwe'veinstalledourCRDs,wecanrunthecontrolleragainstour +cluster.Thiswillusewhatevercredentialsthatweconnecttothe +clusterwith,sowedon'tneedtoworryaboutRBACjustyet. - -In a separate terminal, run +Inaseparateterminal,run ```bash -export ENABLE_WEBHOOKS=false -make run +exportENABLE_WEBHOOKS=false +makerun ``` -You should see logs from the controller about starting up, but it won't do -anything just yet. +Youshouldseelogsfromthecontrolleraboutstartingup,butitwon'tdo +anythingjustyet. -At this point, we need a CronJob to test with. Let's write a sample to -`config/samples/batch_v1_cronjob.yaml`, and use that: +Atthispoint,weneedaCronJobtotestwith.Let'swriteasampleto +`config/samples/batch_v1_cronjob.yaml`,andusethat: ```yaml -{{#include ./testdata/project/config/samples/batch_v1_cronjob.yaml}} +{{#include./testdata/project/config/samples/batch_v1_cronjob.yaml}} ``` ```bash -kubectl create -f config/samples/batch_v1_cronjob.yaml +kubectlcreate-fconfig/samples/batch_v1_cronjob.yaml ``` -At this point, you should see a flurry of activity. If you watch the -changes, you should see your cronjob running, and updating status: +Atthispoint,youshouldseeaflurryofactivity.Ifyouwatchthe +changes,youshouldseeyourcronjobrunning,andupdatingstatus: ```bash -kubectl get cronjob.batch.tutorial.kubebuilder.io -o yaml -kubectl get job +kubectlgetcronjob.batch.tutorial.kubebuilder.io-oyaml +kubectlgetjob ``` -Now that we know it's working, we can run it in the cluster. Stop the -`make run` invocation, and run +Nowthatweknowit'sworking,wecanrunitinthecluster.Stopthe +`makerun`invocation,andrun ```bash -make docker-build docker-push IMG=/:tag -make deploy IMG=/:tag +makedocker-builddocker-pushIMG=/:tag +makedeployIMG=/:tag ``` - -If we list cronjobs again like we did before, we should see the controller -functioning again! +Ifwelistcronjobsagainlikewedidbefore,weshouldseethecontroller +functioningagain! diff --git a/docs/book/src/cronjob-tutorial/testdata/project/README.md b/docs/book/src/cronjob-tutorial/testdata/project/README.md index 3fca7276d17..71917a215b4 100644 --- a/docs/book/src/cronjob-tutorial/testdata/project/README.md +++ b/docs/book/src/cronjob-tutorial/testdata/project/README.md @@ -1,114 +1,114 @@ -# project -// TODO(user): Add simple overview of use/purpose +#project +//TODO(user):Addsimpleoverviewofuse/purpose -## Description -// TODO(user): An in-depth paragraph about your project and overview of use +##Description +//TODO(user):Anin-depthparagraphaboutyourprojectandoverviewofuse -## Getting Started +##GettingStarted -### Prerequisites -- go version v1.21.0+ -- docker version 17.03+. -- kubectl version v1.11.3+. -- Access to a Kubernetes v1.11.3+ cluster. +###Prerequisites +-goversionv1.21.0+ +-dockerversion17.03+. +-kubectlversionv1.11.3+. +-AccesstoaKubernetesv1.11.3+cluster. -### To Deploy on the cluster -**Build and push your image to the location specified by `IMG`:** +###ToDeployonthecluster +**Buildandpushyourimagetothelocationspecifiedby`IMG`:** ```sh -make docker-build docker-push IMG=/project:tag +makedocker-builddocker-pushIMG=/project: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. +**NOTE:**Thisimageoughttobepublishedinthepersonalregistryyouspecified. +Anditisrequiredtohaveaccesstopulltheimagefromtheworkingenvironment. +Makesureyouhavetheproperpermissiontotheregistryiftheabovecommandsdon’twork. -**Install the CRDs into the cluster:** +**InstalltheCRDsintothecluster:** ```sh -make install +makeinstall ``` -**Deploy the Manager to the cluster with the image specified by `IMG`:** +**DeploytheManagertotheclusterwiththeimagespecifiedby`IMG`:** ```sh -make deploy IMG=/project:tag +makedeployIMG=/project:tag ``` -> **NOTE**: If you encounter RBAC errors, you may need to grant yourself cluster-admin -privileges or be logged in as admin. +>**NOTE**:IfyouencounterRBACerrors,youmayneedtograntyourselfcluster-admin +privilegesorbeloggedinasadmin. -**Create instances of your solution** -You can apply the samples (examples) from the config/sample: +**Createinstancesofyoursolution** +Youcanapplythesamples(examples)fromtheconfig/sample: ```sh -kubectl apply -k config/samples/ +kubectlapply-kconfig/samples/ ``` ->**NOTE**: Ensure that the samples has default values to test it out. +>**NOTE**:Ensurethatthesampleshasdefaultvaluestotestitout. -### To Uninstall -**Delete the instances (CRs) from the cluster:** +###ToUninstall +**Deletetheinstances(CRs)fromthecluster:** ```sh -kubectl delete -k config/samples/ +kubectldelete-kconfig/samples/ ``` -**Delete the APIs(CRDs) from the cluster:** +**DeletetheAPIs(CRDs)fromthecluster:** ```sh -make uninstall +makeuninstall ``` -**UnDeploy the controller from the cluster:** +**UnDeploythecontrollerfromthecluster:** ```sh -make undeploy +makeundeploy ``` -## Project Distribution +##ProjectDistribution -Following are the steps to build the installer and distribute this project to users. +Followingarethestepstobuildtheinstalleranddistributethisprojecttousers. -1. Build the installer for the image built and published in the registry: +1.Buildtheinstallerfortheimagebuiltandpublishedintheregistry: ```sh -make build-installer IMG=/project:tag +makebuild-installerIMG=/project: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. +NOTE:Themakefiletargetmentionedabovegeneratesan'install.yaml' +fileinthedistdirectory.Thisfilecontainsalltheresourcesbuilt +withKustomize,whicharenecessarytoinstallthisprojectwithout +itsdependencies. -2. Using the installer +2.Usingtheinstaller -Users can just run kubectl apply -f to install the project, i.e.: +Userscanjustrunkubectlapply-ftoinstalltheproject,i.e.: ```sh -kubectl apply -f https://raw.githubusercontent.com//project//dist/install.yaml +kubectlapply-fhttps://raw.githubusercontent.com//project//dist/install.yaml ``` -## Contributing -// TODO(user): Add detailed information on how you would like others to contribute to this project +##Contributing +//TODO(user):Adddetailedinformationonhowyouwouldlikeotherstocontributetothisproject -**NOTE:** Run `make help` for more information on all potential `make` targets +**NOTE:**Run`makehelp`formoreinformationonallpotential`make`targets -More information can be found via the [Kubebuilder Documentation](https://book.kubebuilder.io/introduction.html) +Moreinformationcanbefoundviathe[KubebuilderDocumentation](https://book.kubebuilder.io/introduction.html) -## License +##License -Copyright 2024 The Kubernetes authors. +Copyright2024TheKubernetesauthors. -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 +LicensedundertheApacheLicense,Version2.0(the"License"); +youmaynotusethisfileexceptincompliancewiththeLicense. +YoumayobtainacopyoftheLicenseat - http://www.apache.org/licenses/LICENSE-2.0 +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. +Unlessrequiredbyapplicablelaworagreedtoinwriting,software +distributedundertheLicenseisdistributedonan"ASIS"BASIS, +WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied. +SeetheLicenseforthespecificlanguagegoverningpermissionsand +limitationsundertheLicense. diff --git a/docs/book/src/cronjob-tutorial/webhook-implementation.md b/docs/book/src/cronjob-tutorial/webhook-implementation.md index 756bbb1474b..19b9a36de56 100644 --- a/docs/book/src/cronjob-tutorial/webhook-implementation.md +++ b/docs/book/src/cronjob-tutorial/webhook-implementation.md @@ -1,35 +1,35 @@ -# Implementing defaulting/validating webhooks +#Implementingdefaulting/validatingwebhooks -If you want to implement [admission webhooks](../reference/admission-webhook.md) -for your CRD, the only thing you need to do is to implement the `Defaulter` -and (or) the `Validator` interface. +Ifyouwanttoimplement[admissionwebhooks](../reference/admission-webhook.md) +foryourCRD,theonlythingyouneedtodoistoimplementthe`Defaulter` +and(or)the`Validator`interface. -Kubebuilder takes care of the rest for you, such as +Kubebuildertakescareoftherestforyou,suchas -1. Creating the webhook server. -1. Ensuring the server has been added in the manager. -1. Creating handlers for your webhooks. -1. Registering each handler with a path in your server. +1.Creatingthewebhookserver. +1.Ensuringtheserverhasbeenaddedinthemanager. +1.Creatinghandlersforyourwebhooks. +1.Registeringeachhandlerwithapathinyourserver. -First, let's scaffold the webhooks for our CRD (CronJob). We’ll need to run the following command with the `--defaulting` and `--programmatic-validation` flags (since our test project will use defaulting and validating webhooks): +First,let'sscaffoldthewebhooksforourCRD(CronJob).We’llneedtorunthefollowingcommandwiththe`--defaulting`and`--programmatic-validation`flags(sinceourtestprojectwillusedefaultingandvalidatingwebhooks): ```bash -kubebuilder create webhook --group batch --version v1 --kind CronJob --defaulting --programmatic-validation +kubebuildercreatewebhook--groupbatch--versionv1--kindCronJob--defaulting--programmatic-validation ``` -This will scaffold the webhook functions and register your webhook with the manager in your `main.go` for you. +Thiswillscaffoldthewebhookfunctionsandregisteryourwebhookwiththemanagerinyour`main.go`foryou. - -{{#literatego ./testdata/project/api/v1/cronjob_webhook.go}} +{{#literatego./testdata/project/api/v1/cronjob_webhook.go}} diff --git a/docs/book/src/cronjob-tutorial/writing-tests.md b/docs/book/src/cronjob-tutorial/writing-tests.md index f31d87fc1c6..b3affd07a76 100644 --- a/docs/book/src/cronjob-tutorial/writing-tests.md +++ b/docs/book/src/cronjob-tutorial/writing-tests.md @@ -1,33 +1,33 @@ -# Writing controller tests +#Writingcontrollertests -Testing Kubernetes controllers is a big subject, and the boilerplate testing -files generated for you by kubebuilder are fairly minimal. +TestingKubernetescontrollersisabigsubject,andtheboilerplatetesting +filesgeneratedforyoubykubebuilderarefairlyminimal. -To walk you through integration testing patterns for Kubebuilder-generated controllers, we will revisit the CronJob we built in our first tutorial and write a simple test for it. +TowalkyouthroughintegrationtestingpatternsforKubebuilder-generatedcontrollers,wewillrevisittheCronJobwebuiltinourfirsttutorialandwriteasimpletestforit. -The basic approach is that, in your generated `suite_test.go` file, you will use envtest to create a local Kubernetes API server, instantiate and run your controllers, and then write additional `*_test.go` files to test it using [Ginkgo](http://onsi.github.io/ginkgo). +Thebasicapproachisthat,inyourgenerated`suite_test.go`file,youwilluseenvtesttocreatealocalKubernetesAPIserver,instantiateandrunyourcontrollers,andthenwriteadditional`*_test.go`filestotestitusing[Ginkgo](http://onsi.github.io/ginkgo). -If you want to tinker with how your envtest cluster is configured, see section [Configuring envtest for integration tests](../reference/envtest.md) as well as the [`envtest docs`](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/envtest?tab=doc). +Ifyouwanttotinkerwithhowyourenvtestclusterisconfigured,seesection[Configuringenvtestforintegrationtests](../reference/envtest.md)aswellasthe[`envtestdocs`](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/envtest?tab=doc). -## Test Environment Setup +##TestEnvironmentSetup -{{#literatego ../cronjob-tutorial/testdata/project/internal/controller/suite_test.go}} +{{#literatego../cronjob-tutorial/testdata/project/internal/controller/suite_test.go}} -## Testing your Controller's Behavior +##TestingyourController'sBehavior -{{#literatego ../cronjob-tutorial/testdata/project/internal/controller/cronjob_controller_test.go}} +{{#literatego../cronjob-tutorial/testdata/project/internal/controller/cronjob_controller_test.go}} -This Status update example above demonstrates a general testing strategy for a custom Kind with downstream objects. By this point, you hopefully have learned the following methods for testing your controller behavior: +ThisStatusupdateexampleabovedemonstratesageneraltestingstrategyforacustomKindwithdownstreamobjects.Bythispoint,youhopefullyhavelearnedthefollowingmethodsfortestingyourcontrollerbehavior: -* Setting up your controller to run on an envtest cluster -* Writing stubs for creating test objects -* Isolating changes to an object to test specific controller behavior +*Settingupyourcontrollertorunonanenvtestcluster +*Writingstubsforcreatingtestobjects +*Isolatingchangestoanobjecttotestspecificcontrollerbehavior -## Advanced Examples +##AdvancedExamples -There are more involved examples of using envtest to rigorously test controller behavior. Examples include: +Therearemoreinvolvedexamplesofusingenvtesttorigorouslytestcontrollerbehavior.Examplesinclude: -* Azure Databricks Operator: see their fully fleshed-out - [`suite_test.go`](https://github.com/microsoft/azure-databricks-operator/blob/0f722a710fea06b86ecdccd9455336ca712bf775/controllers/suite_test.go) - as well as any `*_test.go` file in that directory [like this - one](https://github.com/microsoft/azure-databricks-operator/blob/0f722a710fea06b86ecdccd9455336ca712bf775/controllers/secretscope_controller_test.go). +*AzureDatabricksOperator:seetheirfullyfleshed-out +[`suite_test.go`](https://github.com/microsoft/azure-databricks-operator/blob/0f722a710fea06b86ecdccd9455336ca712bf775/controllers/suite_test.go) +aswellasany`*_test.go`fileinthatdirectory[likethis +one](https://github.com/microsoft/azure-databricks-operator/blob/0f722a710fea06b86ecdccd9455336ca712bf775/controllers/secretscope_controller_test.go). diff --git a/docs/book/src/faq.md b/docs/book/src/faq.md index ba72cbc08b2..7e34ae5450c 100644 --- a/docs/book/src/faq.md +++ b/docs/book/src/faq.md @@ -1,132 +1,132 @@ -# FAQ +#FAQ -## How does the value informed via the domain flag (i.e. `kubebuilder init --domain example.com`) when we init a project? +##Howdoesthevalueinformedviathedomainflag(i.e.`kubebuilderinit--domainexample.com`)whenweinitaproject? -After creating a project, usually you will want to extend the Kubernetes APIs and define new APIs which will be owned by your project. Therefore, the domain value is tracked in the [PROJECT][project-file-def] file which defines the config of your project and will be used as a domain to create the endpoints of your API(s). Please, ensure that you understand the [Groups and Versions and Kinds, oh my!][gvk]. +Aftercreatingaproject,usuallyyouwillwanttoextendtheKubernetesAPIsanddefinenewAPIswhichwillbeownedbyyourproject.Therefore,thedomainvalueistrackedinthe[PROJECT][project-file-def]filewhichdefinestheconfigofyourprojectandwillbeusedasadomaintocreatetheendpointsofyourAPI(s).Please,ensurethatyouunderstandthe[GroupsandVersionsandKinds,ohmy!][gvk]. -The domain is for the group suffix, to explicitly show the resource group category. -For example, if set `--domain=example.com`: +Thedomainisforthegroupsuffix,toexplicitlyshowtheresourcegroupcategory. +Forexample,ifset`--domain=example.com`: ``` -kubebuilder init --domain example.com --repo xxx --plugins=go/v4 -kubebuilder create api --group mygroup --version v1beta1 --kind Mykind +kubebuilderinit--domainexample.com--repoxxx--plugins=go/v4 +kubebuildercreateapi--groupmygroup--versionv1beta1--kindMykind ``` -Then the result resource group will be `mygroup.example.com`. +Thentheresultresourcegroupwillbe`mygroup.example.com`. -> If domain field not set, the default value is `my.domain`. +>Ifdomainfieldnotset,thedefaultvalueis`my.domain`. -## I'd like to customize my project to use [klog][klog] instead of the [zap][zap] provided by controller-runtime. How to use `klog` or other loggers as the project logger? +##I'dliketocustomizemyprojecttouse[klog][klog]insteadofthe[zap][zap]providedbycontroller-runtime.Howtouse`klog`orotherloggersastheprojectlogger? -In the `main.go` you can replace: +Inthe`main.go`youcanreplace: ```go - opts := zap.Options{ - Development: true, - } - opts.BindFlags(flag.CommandLine) - flag.Parse() - - ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) +opts:=zap.Options{ +Development:true, +} +opts.BindFlags(flag.CommandLine) +flag.Parse() + +ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) ``` with: ```go - flag.Parse() - ctrl.SetLogger(klog.NewKlogr()) +flag.Parse() +ctrl.SetLogger(klog.NewKlogr()) ``` -## After `make run`, I see errors like "unable to find leader election namespace: not running in-cluster..." +##After`makerun`,Iseeerrorslike"unabletofindleaderelectionnamespace:notrunningin-cluster..." -You can enable the leader election. However, if you are testing the project locally using the `make run` -target which will run the manager outside of the cluster then, you might also need to set the -namespace the leader election resource will be created, as follows: +Youcanenabletheleaderelection.However,ifyouaretestingtheprojectlocallyusingthe`makerun` +targetwhichwillrunthemanageroutsideoftheclusterthen,youmightalsoneedtosetthe +namespacetheleaderelectionresourcewillbecreated,asfollows: ```go -mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ - Scheme: scheme, - MetricsBindAddress: metricsAddr, - Port: 9443, - HealthProbeBindAddress: probeAddr, - LeaderElection: enableLeaderElection, - LeaderElectionID: "14be1926.testproject.org", - LeaderElectionNamespace: "-system", +mgr,err:=ctrl.NewManager(ctrl.GetConfigOrDie(),ctrl.Options{ +Scheme:scheme, +MetricsBindAddress:metricsAddr, +Port:9443, +HealthProbeBindAddress:probeAddr, +LeaderElection:enableLeaderElection, +LeaderElectionID:"14be1926.testproject.org", +LeaderElectionNamespace:"-system", ``` -If you are running the project on the cluster with `make deploy` target -then, you might not want to add this option. So, you might want to customize this behaviour using -environment variables to only add this option for development purposes, such as: +Ifyouarerunningtheprojectontheclusterwith`makedeploy`target +then,youmightnotwanttoaddthisoption.So,youmightwanttocustomizethisbehaviourusing +environmentvariablestoonlyaddthisoptionfordevelopmentpurposes,suchas: ```go - leaderElectionNS := "" - if os.Getenv("ENABLE_LEADER_ELECTION_NAMESPACE") != "false" { - leaderElectionNS = "-system" - } - - mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ - Scheme: scheme, - MetricsBindAddress: metricsAddr, - Port: 9443, - HealthProbeBindAddress: probeAddr, - LeaderElection: enableLeaderElection, - LeaderElectionNamespace: leaderElectionNS, - LeaderElectionID: "14be1926.testproject.org", - ... +leaderElectionNS:="" +ifos.Getenv("ENABLE_LEADER_ELECTION_NAMESPACE")!="false"{ +leaderElectionNS="-system" +} + +mgr,err:=ctrl.NewManager(ctrl.GetConfigOrDie(),ctrl.Options{ +Scheme:scheme, +MetricsBindAddress:metricsAddr, +Port:9443, +HealthProbeBindAddress:probeAddr, +LeaderElection:enableLeaderElection, +LeaderElectionNamespace:leaderElectionNS, +LeaderElectionID:"14be1926.testproject.org", +... ``` -## I am facing the error "open /var/run/secrets/kubernetes.io/serviceaccount/token: permission denied" when I deploy my project against Kubernetes old versions. How to sort it out? +##Iamfacingtheerror"open/var/run/secrets/kubernetes.io/serviceaccount/token:permissiondenied"whenIdeploymyprojectagainstKubernetesoldversions.Howtosortitout? -If you are facing the error: +Ifyouarefacingtheerror: ``` -1.6656687258729894e+09 ERROR controller-runtime.client.config unable to get kubeconfig {"error": "open /var/run/secrets/kubernetes.io/serviceaccount/token: permission denied"} +1.6656687258729894e+09ERRORcontroller-runtime.client.configunabletogetkubeconfig{"error":"open/var/run/secrets/kubernetes.io/serviceaccount/token:permissiondenied"} sigs.k8s.io/controller-runtime/pkg/client/config.GetConfigOrDie - /go/pkg/mod/sigs.k8s.io/controller-runtime@v0.13.0/pkg/client/config/config.go:153 +/go/pkg/mod/sigs.k8s.io/controller-runtime@v0.13.0/pkg/client/config/config.go:153 main.main - /workspace/main.go:68 +/workspace/main.go:68 runtime.main - /usr/local/go/src/runtime/proc.go:250 +/usr/local/go/src/runtime/proc.go:250 ``` -when you are running the project against a Kubernetes old version (maybe <= 1.21) , it might be caused by the [issue][permission-issue] , the reason is the mounted token file set to `0600`, see [solution][permission-PR] here. Then, the workaround is: +whenyouarerunningtheprojectagainstaKubernetesoldversion(maybe<=1.21),itmightbecausedbythe[issue][permission-issue],thereasonisthemountedtokenfilesetto`0600`,see[solution][permission-PR]here.Then,theworkaroundis: -Add `fsGroup` in the manager.yaml +Add`fsGroup`inthemanager.yaml ```yaml securityContext: - runAsNonRoot: true - fsGroup: 65532 # add this fsGroup to make the token file readable +runAsNonRoot:true +fsGroup:65532#addthisfsGrouptomakethetokenfilereadable ``` -However, note that this problem is fixed and will not occur if you deploy the project in high versions (maybe >= 1.22). +However,notethatthisproblemisfixedandwillnotoccurifyoudeploytheprojectinhighversions(maybe>=1.22). -## The error `Too long: must have at most 262144 bytes` is faced when I run `make install` to apply the CRD manifests. How to solve it? Why this error is faced? +##Theerror`Toolong:musthaveatmost262144bytes`isfacedwhenIrun`makeinstall`toapplytheCRDmanifests.Howtosolveit?Whythiserrorisfaced? -When attempting to run `make install` to apply the CRD manifests, the error `Too long: must have at most 262144 bytes may be encountered.` This error arises due to a size limit enforced by the Kubernetes API. Note that the `make install` target will apply the CRD manifest under `config/crd` using `kubectl apply -f -`. Therefore, when the apply command is used, the API annotates the object with the `last-applied-configuration` which contains the entire previous configuration. If this configuration is too large, it will exceed the allowed byte size. ([More info][k8s-obj-creation]) +Whenattemptingtorun`makeinstall`toapplytheCRDmanifests,theerror`Toolong:musthaveatmost262144bytesmaybeencountered.`ThiserrorarisesduetoasizelimitenforcedbytheKubernetesAPI.Notethatthe`makeinstall`targetwillapplytheCRDmanifestunder`config/crd`using`kubectlapply-f-`.Therefore,whentheapplycommandisused,theAPIannotatestheobjectwiththe`last-applied-configuration`whichcontainstheentirepreviousconfiguration.Ifthisconfigurationistoolarge,itwillexceedtheallowedbytesize.([Moreinfo][k8s-obj-creation]) -In ideal approach might use client-side apply might seem like the perfect solution since with the entire object configuration doesn't have to be stored as an annotation (last-applied-configuration) on the server. However, it's worth noting that as of now, it isn't supported by controller-gen or kubebuilder. For more on this, refer to: [Controller-tool-discussion][controller-tool-pr]. +Inidealapproachmightuseclient-sideapplymightseemliketheperfectsolutionsincewiththeentireobjectconfigurationdoesn'thavetobestoredasanannotation(last-applied-configuration)ontheserver.However,it'sworthnotingthatasofnow,itisn'tsupportedbycontroller-genorkubebuilder.Formoreonthis,referto:[Controller-tool-discussion][controller-tool-pr]. -Therefore, you have a few options to workround this scenario such as: +Therefore,youhaveafewoptionstoworkroundthisscenariosuchas: -**By removing the descriptions from CRDs:** +**ByremovingthedescriptionsfromCRDs:** -Your CRDs are generated using [controller-gen][controller-gen]. By using the option `maxDescLen=0` to remove the description, you may reduce the size, potentially resolving the issue. To do it you can update the Makefile as the following example and then, call the target `make manifest` to regenerate your CRDs without description, see: +YourCRDsaregeneratedusing[controller-gen][controller-gen].Byusingtheoption`maxDescLen=0`toremovethedescription,youmayreducethesize,potentiallyresolvingtheissue.TodoityoucanupdatetheMakefileasthefollowingexampleandthen,callthetarget`makemanifest`toregenerateyourCRDswithoutdescription,see: ```shell - .PHONY: manifests - manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects. - # Note that the option maxDescLen=0 was added in the default scaffold in order to sort out the issue - # Too long: must have at most 262144 bytes. By using kubectl apply to create / update resources an annotation - # is created by K8s API to store the latest version of the resource ( kubectl.kubernetes.io/last-applied-configuration). - # However, it has a size limit and if the CRD is too big with so many long descriptions as this one it will cause the failure. - $(CONTROLLER_GEN) rbac:roleName=manager-role crd:maxDescLen=0 webhook paths="./..." output:crd:artifacts:config=config/crd/bases +.PHONY:manifests +manifests:controller-gen##GenerateWebhookConfiguration,ClusterRoleandCustomResourceDefinitionobjects. +#NotethattheoptionmaxDescLen=0wasaddedinthedefaultscaffoldinordertosortouttheissue +#Toolong:musthaveatmost262144bytes.Byusingkubectlapplytocreate/updateresourcesanannotation +#iscreatedbyK8sAPItostorethelatestversionoftheresource(kubectl.kubernetes.io/last-applied-configuration). +#However,ithasasizelimitandiftheCRDistoobigwithsomanylongdescriptionsasthisoneitwillcausethefailure. +$(CONTROLLER_GEN)rbac:roleName=manager-rolecrd:maxDescLen=0webhookpaths="./..."output:crd:artifacts:config=config/crd/bases ``` -**By re-design your APIs:** +**Byre-designyourAPIs:** -You can review the design of your APIs and see if it has not more specs than should be by hurting single responsibility principle for example. So that you might to re-design them. +YoucanreviewthedesignofyourAPIsandseeifithasnotmorespecsthanshouldbebyhurtingsingleresponsibilityprincipleforexample.Sothatyoumighttore-designthem. -[k8s-obj-creation]: https://kubernetes.io/docs/tasks/manage-kubernetes-objects/declarative-config/#how-to-create-objects -[gvk]: ./cronjob-tutorial/gvks.md -[project-file-def]: ./reference/project-config.md -[klog]: https://github.com/kubernetes/klog -[zap]: https://github.com/uber-go/zap -[permission-issue]: https://github.com/kubernetes/kubernetes/issues/82573 -[permission-PR]: https://github.com/kubernetes/kubernetes/pull/89193 -[controller-gen]: ./reference/controller-gen.html -[controller-tool-pr]: https://github.com/kubernetes-sigs/controller-tools/pull/536 \ No newline at end of file +[k8s-obj-creation]:https://kubernetes.io/docs/tasks/manage-kubernetes-objects/declarative-config/#how-to-create-objects +[gvk]:./cronjob-tutorial/gvks.md +[project-file-def]:./reference/project-config.md +[klog]:https://github.com/kubernetes/klog +[zap]:https://github.com/uber-go/zap +[permission-issue]:https://github.com/kubernetes/kubernetes/issues/82573 +[permission-PR]:https://github.com/kubernetes/kubernetes/pull/89193 +[controller-gen]:./reference/controller-gen.html +[controller-tool-pr]:https://github.com/kubernetes-sigs/controller-tools/pull/536 \ No newline at end of file diff --git a/docs/book/src/getting-started.md b/docs/book/src/getting-started.md index 22bfcec5cbc..aacb33a5e8d 100644 --- a/docs/book/src/getting-started.md +++ b/docs/book/src/getting-started.md @@ -1,452 +1,452 @@ -# Getting Started +#GettingStarted -## Overview +##Overview -By following the [Operator Pattern][k8s-operator-pattern], it’s possible not only to provide all expected resources -but also to manage them dynamically, programmatically, and at execution time. To illustrate this idea, imagine if -someone accidentally changed a configuration or removed a resource by mistake; in this case, the operator could fix it -without any human intervention. +Byfollowingthe[OperatorPattern][k8s-operator-pattern],it’spossiblenotonlytoprovideallexpectedresources +butalsotomanagethemdynamically,programmatically,andatexecutiontime.Toillustratethisidea,imagineif +someoneaccidentallychangedaconfigurationorremovedaresourcebymistake;inthiscase,theoperatorcouldfixit +withoutanyhumanintervention. -## Sample Project +##SampleProject -We will create a sample project to let you know how it works. This sample will: +Wewillcreateasampleprojecttoletyouknowhowitworks.Thissamplewill: -- Reconcile a Memcached CR - which represents an instance of a Memcached deployed/managed on cluster -- Create a Deployment with the Memcached image -- Not allow more instances than the size defined in the CR which will be applied -- Update the Memcached CR status +-ReconcileaMemcachedCR-whichrepresentsaninstanceofaMemcacheddeployed/managedoncluster +-CreateaDeploymentwiththeMemcachedimage +-NotallowmoreinstancesthanthesizedefinedintheCRwhichwillbeapplied +-UpdatetheMemcachedCRstatus -Use the following steps. +Usethefollowingsteps. -## Create a project +##Createaproject -First, create and navigate into a directory for your project. Then, initialize it using `kubebuilder`: +First,createandnavigateintoadirectoryforyourproject.Then,initializeitusing`kubebuilder`: ```shell -mkdir $GOPATH/memcached-operator -cd $GOPATH/memcached-operator -kubebuilder init --domain=example.com +mkdir$GOPATH/memcached-operator +cd$GOPATH/memcached-operator +kubebuilderinit--domain=example.com ``` -## Create the Memcached API (CRD): +##CreatetheMemcachedAPI(CRD): -Next, we'll create a new API responsible for deploying and managing our Memcached solution. In this instance, we will utilize the [Deploy Image Plugin][deploy-image] to get a comprehensive code implementation for our solution. +Next,we'llcreateanewAPIresponsiblefordeployingandmanagingourMemcachedsolution.Inthisinstance,wewillutilizethe[DeployImagePlugin][deploy-image]togetacomprehensivecodeimplementationforoursolution. ``` -kubebuilder create api --group cache --version v1alpha1 --kind Memcached --image=memcached:1.4.36-alpine --image-container-command="memcached,-m=64,-o,modern,-v" --image-container-port="11211" --run-as-user="1001" --plugins="deploy-image/v1-alpha" --make=false +kubebuildercreateapi--groupcache--versionv1alpha1--kindMemcached--image=memcached:1.4.36-alpine--image-container-command="memcached,-m=64,-o,modern,-v"--image-container-port="11211"--run-as-user="1001"--plugins="deploy-image/v1-alpha"--make=false ``` -### Understanding APIs +###UnderstandingAPIs -This command's primary aim is to produce the Custom Resource (CR) and Custom Resource Definition (CRD) for the Memcached Kind. It creates the API with the group `cache.example.com` and version `v1alpha1`, uniquely identifying the new CRD of the Memcached Kind. By leveraging the Kubebuilder tool, we can define our APIs and objects representing our solutions for these platforms. While we've added only one Kind of resource in this example, you can have as many `Groups` and `Kinds` as necessary. Simply put, think of CRDs as the definition of our custom Objects, while CRs are instances of them. +Thiscommand'sprimaryaimistoproducetheCustomResource(CR)andCustomResourceDefinition(CRD)fortheMemcachedKind.ItcreatestheAPIwiththegroup`cache.example.com`andversion`v1alpha1`,uniquelyidentifyingthenewCRDoftheMemcachedKind.ByleveragingtheKubebuildertool,wecandefineourAPIsandobjectsrepresentingoursolutionsfortheseplatforms.Whilewe'veaddedonlyoneKindofresourceinthisexample,youcanhaveasmany`Groups`and`Kinds`asnecessary.Simplyput,thinkofCRDsasthedefinitionofourcustomObjects,whileCRsareinstancesofthem. - -### Define your API +###DefineyourAPI -In this example, observe that the Memcached Kind (CRD) possesses certain specifications. These were scaffolded by the Deploy Image plugin, building upon the default scaffold for management purposes: +Inthisexample,observethattheMemcachedKind(CRD)possessescertainspecifications.ThesewerescaffoldedbytheDeployImageplugin,buildinguponthedefaultscaffoldformanagementpurposes: -#### Status and Specs +####StatusandSpecs -The `MemcachedSpec` section is where we encapsulate all the available specifications and configurations for our Custom Resource (CR). Furthermore, it's worth noting that we employ Status Conditions. This ensures proficient management of the Memcached CR. When any change transpires, these conditions equip us with the necessary data to discern the current status of this resource within the Kubernetes cluster. This is akin to the status insights we obtain for a Deployment resource. +The`MemcachedSpec`sectioniswhereweencapsulatealltheavailablespecificationsandconfigurationsforourCustomResource(CR).Furthermore,it'sworthnotingthatweemployStatusConditions.ThisensuresproficientmanagementoftheMemcachedCR.Whenanychangetranspires,theseconditionsequipuswiththenecessarydatatodiscernthecurrentstatusofthisresourcewithintheKubernetescluster.ThisisakintothestatusinsightsweobtainforaDeploymentresource. -From: `api/v1alpha1/memcached_types.go` +From:`api/v1alpha1/memcached_types.go` ```go -// MemcachedSpec defines the desired state of Memcached -type MemcachedSpec struct { - // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - // Important: Run "make" to regenerate code after modifying this file - - // Size defines the number of Memcached instances - // The following markers will use OpenAPI v3 schema to validate the value - // More info: https://book.kubebuilder.io/reference/markers/crd-validation.html - // +kubebuilder:validation:Minimum=1 - // +kubebuilder:validation:Maximum=3 - // +kubebuilder:validation:ExclusiveMaximum=false - Size int32 `json:"size,omitempty"` - - // Port defines the port that will be used to init the container with the image - ContainerPort int32 `json:"containerPort,omitempty"` -} - -// MemcachedStatus defines the observed state of Memcached -type MemcachedStatus struct { - // Represents the observations of a Memcached's current state. - // Memcached.status.conditions.type are: "Available", "Progressing", and "Degraded" - // Memcached.status.conditions.status are one of True, False, Unknown. - // Memcached.status.conditions.reason the value should be a CamelCase string and producers of specific - // condition types may define expected values and meanings for this field, and whether the values - // are considered a guaranteed API. - // Memcached.status.conditions.Message is a human readable message indicating details about the transition. - // For further information see: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties - - Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,1,rep,name=conditions"` +//MemcachedSpecdefinesthedesiredstateofMemcached +typeMemcachedSpecstruct{ +//INSERTADDITIONALSPECFIELDS-desiredstateofcluster +//Important:Run"make"toregeneratecodeaftermodifyingthisfile + +//SizedefinesthenumberofMemcachedinstances +//ThefollowingmarkerswilluseOpenAPIv3schematovalidatethevalue +//Moreinfo:https://book.kubebuilder.io/reference/markers/crd-validation.html +//+kubebuilder:validation:Minimum=1 +//+kubebuilder:validation:Maximum=3 +//+kubebuilder:validation:ExclusiveMaximum=false +Sizeint32`json:"size,omitempty"` + +//Portdefinestheportthatwillbeusedtoinitthecontainerwiththeimage +ContainerPortint32`json:"containerPort,omitempty"` +} + +//MemcachedStatusdefinestheobservedstateofMemcached +typeMemcachedStatusstruct{ +//RepresentstheobservationsofaMemcached'scurrentstate. +//Memcached.status.conditions.typeare:"Available","Progressing",and"Degraded" +//Memcached.status.conditions.statusareoneofTrue,False,Unknown. +//Memcached.status.conditions.reasonthevalueshouldbeaCamelCasestringandproducersofspecific +//conditiontypesmaydefineexpectedvaluesandmeaningsforthisfield,andwhetherthevalues +//areconsideredaguaranteedAPI. +//Memcached.status.conditions.Messageisahumanreadablemessageindicatingdetailsaboutthetransition. +//Forfurtherinformationsee:https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties + +Conditions[]metav1.Condition`json:"conditions,omitempty"patchStrategy:"merge"patchMergeKey:"type"protobuf:"bytes,1,rep,name=conditions"` } ``` -Thus, when we introduce new specifications to this file and execute the `make generate` command, we utilize [controller-gen][controller-gen] to generate the CRD manifest, which is located under the `config/crd/bases` directory. +Thus,whenweintroducenewspecificationstothisfileandexecutethe`makegenerate`command,weutilize[controller-gen][controller-gen]togeneratetheCRDmanifest,whichislocatedunderthe`config/crd/bases`directory. -#### Markers and validations +####Markersandvalidations -Moreover, it's important to note that we're employing `markers`, such as `+kubebuilder:validation:Minimum=1`. These markers help in defining validations and criteria, ensuring that data provided by users — when they create or edit a Custom Resource for the Memcached Kind — is properly validated. For a comprehensive list and details of available markers, refer [the Markers documentation][markers]. -Observe the validation schema within the CRD; this schema ensures that the Kubernetes API properly validates the Custom Resources (CRs) that are applied: +Moreover,it'simportanttonotethatwe'reemploying`markers`,suchas`+kubebuilder:validation:Minimum=1`.Thesemarkershelpindefiningvalidationsandcriteria,ensuringthatdataprovidedbyusers—whentheycreateoreditaCustomResourcefortheMemcachedKind—isproperlyvalidated.Foracomprehensivelistanddetailsofavailablemarkers,refer[theMarkersdocumentation][markers]. +ObservethevalidationschemawithintheCRD;thisschemaensuresthattheKubernetesAPIproperlyvalidatestheCustomResources(CRs)thatareapplied: -From: [config/crd/bases/cache.example.com_memcacheds.yaml](https://github.com/kubernetes-sigs/kubebuilder/tree/master/docs/book/src/getting-started/testdata/project/config/crd/bases/cache.example.com_memcacheds.yaml) +From:[config/crd/bases/cache.example.com_memcacheds.yaml](https://github.com/kubernetes-sigs/kubebuilder/tree/master/docs/book/src/getting-started/testdata/project/config/crd/bases/cache.example.com_memcacheds.yaml) ```yaml -description: MemcachedSpec defines the desired state of Memcached +description:MemcachedSpecdefinesthedesiredstateofMemcached properties: - containerPort: - description: Port defines the port that will be used to init the container - with the image - format: int32 - type: integer - size: - description: 'Size defines the number of Memcached instances The following - markers will use OpenAPI v3 schema to validate the value More info: - https://book.kubebuilder.io/reference/markers/crd-validation.html' - format: int32 - maximum: 3 ## Generated from the marker +kubebuilder:validation:Maximum=3 - minimum: 1 ## Generated from the marker +kubebuilder:validation:Minimum=1 - type: integer -type: object +containerPort: +description:Portdefinestheportthatwillbeusedtoinitthecontainer +withtheimage +format:int32 +type:integer +size: +description:'SizedefinesthenumberofMemcachedinstancesThefollowing +markerswilluseOpenAPIv3schematovalidatethevalueMoreinfo: +https://book.kubebuilder.io/reference/markers/crd-validation.html' +format:int32 +maximum:3##Generatedfromthemarker+kubebuilder:validation:Maximum=3 +minimum:1##Generatedfromthemarker+kubebuilder:validation:Minimum=1 +type:integer +type:object ``` -#### Sample of Custom Resources +####SampleofCustomResources -The manifests located under the "config/samples" directory serve as examples of Custom Resources that can be applied to the cluster. -In this particular example, by applying the given resource to the cluster, we would generate a Deployment with a single instance size (see `size: 1`). +Themanifestslocatedunderthe"config/samples"directoryserveasexamplesofCustomResourcesthatcanbeappliedtothecluster. +Inthisparticularexample,byapplyingthegivenresourcetothecluster,wewouldgenerateaDeploymentwithasingleinstancesize(see`size:1`). -From: [config/samples/cache_v1alpha1_memcached.yaml](https://github.com/kubernetes-sigs/kubebuilder/tree/master/docs/book/src/getting-started/testdata/project/config/samples/cache_v1alpha1_memcached.yaml) +From:[config/samples/cache_v1alpha1_memcached.yaml](https://github.com/kubernetes-sigs/kubebuilder/tree/master/docs/book/src/getting-started/testdata/project/config/samples/cache_v1alpha1_memcached.yaml) ```yaml -{{#include ./getting-started/testdata/project/config/samples/cache_v1alpha1_memcached.yaml}} +{{#include./getting-started/testdata/project/config/samples/cache_v1alpha1_memcached.yaml}} ``` -### Reconciliation Process +###ReconciliationProcess -The reconciliation function plays a pivotal role in ensuring synchronization between resources and their specifications based on the business logic embedded within them. Essentially, it operates like a loop, continuously checking conditions and performing actions until all conditions align with its implementation. Here's pseudo-code to illustrate this: +Thereconciliationfunctionplaysapivotalroleinensuringsynchronizationbetweenresourcesandtheirspecificationsbasedonthebusinesslogicembeddedwithinthem.Essentially,itoperateslikealoop,continuouslycheckingconditionsandperformingactionsuntilallconditionsalignwithitsimplementation.Here'spseudo-codetoillustratethis: ```go -reconcile App { - - // Check if a Deployment for the app exists, if not, create one - // If there's an error, then restart from the beginning of the reconcile - if err != nil { - return reconcile.Result{}, err - } - - // Check if a Service for the app exists, if not, create one - // If there's an error, then restart from the beginning of the reconcile - if err != nil { - return reconcile.Result{}, err - } - - // Look for Database CR/CRD - // Check the Database Deployment's replicas size - // If deployment.replicas size doesn't match cr.size, then update it - // Then, restart from the beginning of the reconcile. For example, by returning `reconcile.Result{Requeue: true}, nil`. - if err != nil { - return reconcile.Result{Requeue: true}, nil - } - ... - - // If at the end of the loop: - // Everything was executed successfully, and the reconcile can stop - return reconcile.Result{}, nil +reconcileApp{ + +//CheckifaDeploymentfortheappexists,ifnot,createone +//Ifthere'sanerror,thenrestartfromthebeginningofthereconcile +iferr!=nil{ +returnreconcile.Result{},err +} + +//CheckifaServicefortheappexists,ifnot,createone +//Ifthere'sanerror,thenrestartfromthebeginningofthereconcile +iferr!=nil{ +returnreconcile.Result{},err +} + +//LookforDatabaseCR/CRD +//ChecktheDatabaseDeployment'sreplicassize +//Ifdeployment.replicassizedoesn'tmatchcr.size,thenupdateit +//Then,restartfromthebeginningofthereconcile.Forexample,byreturning`reconcile.Result{Requeue:true},nil`. +iferr!=nil{ +returnreconcile.Result{Requeue:true},nil +} +... + +//Ifattheendoftheloop: +//Everythingwasexecutedsuccessfully,andthereconcilecanstop +returnreconcile.Result{},nil } ``` -#### Return Options +####ReturnOptions -The following are a few possible return options to restart the Reconcile: +ThefollowingareafewpossiblereturnoptionstorestarttheReconcile: -- With the error: +-Withtheerror: ```go -return ctrl.Result{}, err +returnctrl.Result{},err ``` -- Without an error: +-Withoutanerror: ```go -return ctrl.Result{Requeue: true}, nil -``` +returnctrl.Result{Requeue:true},nil +``` -- Therefore, to stop the Reconcile, use: +-Therefore,tostoptheReconcile,use: ```go -return ctrl.Result{}, nil +returnctrl.Result{},nil ``` -- Reconcile again after X time: +-ReconcileagainafterXtime: ```go -return ctrl.Result{RequeueAfter: nextRun.Sub(r.Now())}, nil +returnctrl.Result{RequeueAfter:nextRun.Sub(r.Now())},nil ``` -#### In the context of our example +####Inthecontextofourexample -When a Custom Resource is applied to the cluster, there's a designated controller to manage the Memcached Kind. You can check how its reconciliation is implemented: +WhenaCustomResourceisappliedtothecluster,there'sadesignatedcontrollertomanagetheMemcachedKind.Youcancheckhowitsreconciliationisimplemented: -From: [internal/controller/memcached_controller.go](https://github.com/kubernetes-sigs/kubebuilder/tree/master/docs/book/src/getting-started/testdata/project/internal/controller/memcached_controller.go) +From:[internal/controller/memcached_controller.go](https://github.com/kubernetes-sigs/kubebuilder/tree/master/docs/book/src/getting-started/testdata/project/internal/controller/memcached_controller.go) ```go -func (r *MemcachedReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - log := log.FromContext(ctx) - - // Fetch the Memcached instance - // The purpose is check if the Custom Resource for the Kind Memcached - // is applied on the cluster if not we return nil to stop the reconciliation - memcached := &examplecomv1alpha1.Memcached{} - err := r.Get(ctx, req.NamespacedName, memcached) - if err != nil { - if apierrors.IsNotFound(err) { - // If the custom resource is not found then it usually means that it was deleted or not created - // In this way, we will stop the reconciliation - log.Info("memcached resource not found. Ignoring since object must be deleted") - return ctrl.Result{}, nil - } - // Error reading the object - requeue the request. - log.Error(err, "Failed to get memcached") - return ctrl.Result{}, err - } - - // Let's just set the status as Unknown when no status is available - if memcached.Status.Conditions == nil || len(memcached.Status.Conditions) == 0 { - meta.SetStatusCondition(&memcached.Status.Conditions, metav1.Condition{Type: typeAvailableMemcached, Status: metav1.ConditionUnknown, Reason: "Reconciling", Message: "Starting reconciliation"}) - if err = r.Status().Update(ctx, memcached); err != nil { - log.Error(err, "Failed to update Memcached status") - return ctrl.Result{}, err - } - - // Let's re-fetch the memcached Custom Resource after updating the status - // so that we have the latest state of the resource on the cluster and we will avoid - // raising the error "the object has been modified, please apply - // your changes to the latest version and try again" which would re-trigger the reconciliation - // if we try to update it again in the following operations - if err := r.Get(ctx, req.NamespacedName, memcached); err != nil { - log.Error(err, "Failed to re-fetch memcached") - return ctrl.Result{}, err - } - } - - // Let's add a finalizer. Then, we can define some operations which should - // occur before the custom resource to be deleted. - // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/finalizers - if !controllerutil.ContainsFinalizer(memcached, memcachedFinalizer) { - log.Info("Adding Finalizer for Memcached") - if ok := controllerutil.AddFinalizer(memcached, memcachedFinalizer); !ok { - log.Error(err, "Failed to add finalizer into the custom resource") - return ctrl.Result{Requeue: true}, nil - } - - if err = r.Update(ctx, memcached); err != nil { - log.Error(err, "Failed to update custom resource to add finalizer") - return ctrl.Result{}, err - } - } - - // Check if the Memcached instance is marked to be deleted, which is - // indicated by the deletion timestamp being set. - isMemcachedMarkedToBeDeleted := memcached.GetDeletionTimestamp() != nil - if isMemcachedMarkedToBeDeleted { - if controllerutil.ContainsFinalizer(memcached, memcachedFinalizer) { - log.Info("Performing Finalizer Operations for Memcached before delete CR") - - // Let's add here a status "Downgrade" to reflect that this resource began its process to be terminated. - meta.SetStatusCondition(&memcached.Status.Conditions, metav1.Condition{Type: typeDegradedMemcached, - Status: metav1.ConditionUnknown, Reason: "Finalizing", - Message: fmt.Sprintf("Performing finalizer operations for the custom resource: %s ", memcached.Name)}) - - if err := r.Status().Update(ctx, memcached); err != nil { - log.Error(err, "Failed to update Memcached status") - return ctrl.Result{}, err - } - - // Perform all operations required before removing the finalizer and allow - // the Kubernetes API to remove the custom resource. - r.doFinalizerOperationsForMemcached(memcached) - - // TODO(user): If you add operations to the doFinalizerOperationsForMemcached method - // then you need to ensure that all worked fine before deleting and updating the Downgrade status - // otherwise, you should requeue here. - - // Re-fetch the memcached Custom Resource before updating the status - // so that we have the latest state of the resource on the cluster and we will avoid - // raising the error "the object has been modified, please apply - // your changes to the latest version and try again" which would re-trigger the reconciliation - if err := r.Get(ctx, req.NamespacedName, memcached); err != nil { - log.Error(err, "Failed to re-fetch memcached") - return ctrl.Result{}, err - } - - meta.SetStatusCondition(&memcached.Status.Conditions, metav1.Condition{Type: typeDegradedMemcached, - Status: metav1.ConditionTrue, Reason: "Finalizing", - Message: fmt.Sprintf("Finalizer operations for custom resource %s name were successfully accomplished", memcached.Name)}) - - if err := r.Status().Update(ctx, memcached); err != nil { - log.Error(err, "Failed to update Memcached status") - return ctrl.Result{}, err - } - - log.Info("Removing Finalizer for Memcached after successfully perform the operations") - if ok := controllerutil.RemoveFinalizer(memcached, memcachedFinalizer); !ok { - log.Error(err, "Failed to remove finalizer for Memcached") - return ctrl.Result{Requeue: true}, nil - } - - if err := r.Update(ctx, memcached); err != nil { - log.Error(err, "Failed to remove finalizer for Memcached") - return ctrl.Result{}, err - } - } - return ctrl.Result{}, nil - } - - // Check if the deployment already exists, if not create a new one - found := &appsv1.Deployment{} - err = r.Get(ctx, types.NamespacedName{Name: memcached.Name, Namespace: memcached.Namespace}, found) - if err != nil && apierrors.IsNotFound(err) { - // Define a new deployment - dep, err := r.deploymentForMemcached(memcached) - if err != nil { - log.Error(err, "Failed to define new Deployment resource for Memcached") - - // The following implementation will update the status - meta.SetStatusCondition(&memcached.Status.Conditions, metav1.Condition{Type: typeAvailableMemcached, - Status: metav1.ConditionFalse, Reason: "Reconciling", - Message: fmt.Sprintf("Failed to create Deployment for the custom resource (%s): (%s)", memcached.Name, err)}) - - if err := r.Status().Update(ctx, memcached); err != nil { - log.Error(err, "Failed to update Memcached status") - return ctrl.Result{}, err - } - - return ctrl.Result{}, err - } - - log.Info("Creating a new Deployment", - "Deployment.Namespace", dep.Namespace, "Deployment.Name", dep.Name) - if err = r.Create(ctx, dep); err != nil { - log.Error(err, "Failed to create new Deployment", - "Deployment.Namespace", dep.Namespace, "Deployment.Name", dep.Name) - return ctrl.Result{}, err - } - - // Deployment created successfully - // We will requeue the reconciliation so that we can ensure the state - // and move forward for the next operations - return ctrl.Result{RequeueAfter: time.Minute}, nil - } else if err != nil { - log.Error(err, "Failed to get Deployment") - // Let's return the error for the reconciliation be re-trigged again - return ctrl.Result{}, err - } - - // The CRD API is defining that the Memcached type, have a MemcachedSpec.Size field - // to set the quantity of Deployment instances is the desired state on the cluster. - // Therefore, the following code will ensure the Deployment size is the same as defined - // via the Size spec of the Custom Resource which we are reconciling. - size := memcached.Spec.Size - if *found.Spec.Replicas != size { - found.Spec.Replicas = &size - if err = r.Update(ctx, found); err != nil { - log.Error(err, "Failed to update Deployment", - "Deployment.Namespace", found.Namespace, "Deployment.Name", found.Name) - - // Re-fetch the memcached Custom Resource before updating the status - // so that we have the latest state of the resource on the cluster and we will avoid - // raising the error "the object has been modified, please apply - // your changes to the latest version and try again" which would re-trigger the reconciliation - if err := r.Get(ctx, req.NamespacedName, memcached); err != nil { - log.Error(err, "Failed to re-fetch memcached") - return ctrl.Result{}, err - } - - // The following implementation will update the status - meta.SetStatusCondition(&memcached.Status.Conditions, metav1.Condition{Type: typeAvailableMemcached, - Status: metav1.ConditionFalse, Reason: "Resizing", - Message: fmt.Sprintf("Failed to update the size for the custom resource (%s): (%s)", memcached.Name, err)}) - - if err := r.Status().Update(ctx, memcached); err != nil { - log.Error(err, "Failed to update Memcached status") - return ctrl.Result{}, err - } - - return ctrl.Result{}, err - } - - // Now, that we update the size we want to requeue the reconciliation - // so that we can ensure that we have the latest state of the resource before - // update. Also, it will help ensure the desired state on the cluster - return ctrl.Result{Requeue: true}, nil - } - - // The following implementation will update the status - meta.SetStatusCondition(&memcached.Status.Conditions, metav1.Condition{Type: typeAvailableMemcached, - Status: metav1.ConditionTrue, Reason: "Reconciling", - Message: fmt.Sprintf("Deployment for custom resource (%s) with %d replicas created successfully", memcached.Name, size)}) - - if err := r.Status().Update(ctx, memcached); err != nil { - log.Error(err, "Failed to update Memcached status") - return ctrl.Result{}, err - } - - return ctrl.Result{}, nil +func(r*MemcachedReconciler)Reconcile(ctxcontext.Context,reqctrl.Request)(ctrl.Result,error){ +log:=log.FromContext(ctx) + +//FetchtheMemcachedinstance +//ThepurposeischeckiftheCustomResourcefortheKindMemcached +//isappliedontheclusterifnotwereturnniltostopthereconciliation +memcached:=&examplecomv1alpha1.Memcached{} +err:=r.Get(ctx,req.NamespacedName,memcached) +iferr!=nil{ +ifapierrors.IsNotFound(err){ +//Ifthecustomresourceisnotfoundthenitusuallymeansthatitwasdeletedornotcreated +//Inthisway,wewillstopthereconciliation +log.Info("memcachedresourcenotfound.Ignoringsinceobjectmustbedeleted") +returnctrl.Result{},nil +} +//Errorreadingtheobject-requeuetherequest. +log.Error(err,"Failedtogetmemcached") +returnctrl.Result{},err +} + +//Let'sjustsetthestatusasUnknownwhennostatusisavailable +ifmemcached.Status.Conditions==nil||len(memcached.Status.Conditions)==0{ +meta.SetStatusCondition(&memcached.Status.Conditions,metav1.Condition{Type:typeAvailableMemcached,Status:metav1.ConditionUnknown,Reason:"Reconciling",Message:"Startingreconciliation"}) +iferr=r.Status().Update(ctx,memcached);err!=nil{ +log.Error(err,"FailedtoupdateMemcachedstatus") +returnctrl.Result{},err +} + +//Let'sre-fetchthememcachedCustomResourceafterupdatingthestatus +//sothatwehavethelateststateoftheresourceontheclusterandwewillavoid +//raisingtheerror"theobjecthasbeenmodified,pleaseapply +//yourchangestothelatestversionandtryagain"whichwouldre-triggerthereconciliation +//ifwetrytoupdateitagaininthefollowingoperations +iferr:=r.Get(ctx,req.NamespacedName,memcached);err!=nil{ +log.Error(err,"Failedtore-fetchmemcached") +returnctrl.Result{},err +} +} + +//Let'saddafinalizer.Then,wecandefinesomeoperationswhichshould +//occurbeforethecustomresourcetobedeleted. +//Moreinfo:https://kubernetes.io/docs/concepts/overview/working-with-objects/finalizers +if!controllerutil.ContainsFinalizer(memcached,memcachedFinalizer){ +log.Info("AddingFinalizerforMemcached") +ifok:=controllerutil.AddFinalizer(memcached,memcachedFinalizer);!ok{ +log.Error(err,"Failedtoaddfinalizerintothecustomresource") +returnctrl.Result{Requeue:true},nil +} + +iferr=r.Update(ctx,memcached);err!=nil{ +log.Error(err,"Failedtoupdatecustomresourcetoaddfinalizer") +returnctrl.Result{},err +} +} + +//CheckiftheMemcachedinstanceismarkedtobedeleted,whichis +//indicatedbythedeletiontimestampbeingset. +isMemcachedMarkedToBeDeleted:=memcached.GetDeletionTimestamp()!=nil +ifisMemcachedMarkedToBeDeleted{ +ifcontrollerutil.ContainsFinalizer(memcached,memcachedFinalizer){ +log.Info("PerformingFinalizerOperationsforMemcachedbeforedeleteCR") + +//Let'saddhereastatus"Downgrade"toreflectthatthisresourcebeganitsprocesstobeterminated. +meta.SetStatusCondition(&memcached.Status.Conditions,metav1.Condition{Type:typeDegradedMemcached, +Status:metav1.ConditionUnknown,Reason:"Finalizing", +Message:fmt.Sprintf("Performingfinalizeroperationsforthecustomresource:%s",memcached.Name)}) + +iferr:=r.Status().Update(ctx,memcached);err!=nil{ +log.Error(err,"FailedtoupdateMemcachedstatus") +returnctrl.Result{},err +} + +//Performalloperationsrequiredbeforeremovingthefinalizerandallow +//theKubernetesAPItoremovethecustomresource. +r.doFinalizerOperationsForMemcached(memcached) + +//TODO(user):IfyouaddoperationstothedoFinalizerOperationsForMemcachedmethod +//thenyouneedtoensurethatallworkedfinebeforedeletingandupdatingtheDowngradestatus +//otherwise,youshouldrequeuehere. + +//Re-fetchthememcachedCustomResourcebeforeupdatingthestatus +//sothatwehavethelateststateoftheresourceontheclusterandwewillavoid +//raisingtheerror"theobjecthasbeenmodified,pleaseapply +//yourchangestothelatestversionandtryagain"whichwouldre-triggerthereconciliation +iferr:=r.Get(ctx,req.NamespacedName,memcached);err!=nil{ +log.Error(err,"Failedtore-fetchmemcached") +returnctrl.Result{},err +} + +meta.SetStatusCondition(&memcached.Status.Conditions,metav1.Condition{Type:typeDegradedMemcached, +Status:metav1.ConditionTrue,Reason:"Finalizing", +Message:fmt.Sprintf("Finalizeroperationsforcustomresource%snameweresuccessfullyaccomplished",memcached.Name)}) + +iferr:=r.Status().Update(ctx,memcached);err!=nil{ +log.Error(err,"FailedtoupdateMemcachedstatus") +returnctrl.Result{},err +} + +log.Info("RemovingFinalizerforMemcachedaftersuccessfullyperformtheoperations") +ifok:=controllerutil.RemoveFinalizer(memcached,memcachedFinalizer);!ok{ +log.Error(err,"FailedtoremovefinalizerforMemcached") +returnctrl.Result{Requeue:true},nil +} + +iferr:=r.Update(ctx,memcached);err!=nil{ +log.Error(err,"FailedtoremovefinalizerforMemcached") +returnctrl.Result{},err +} +} +returnctrl.Result{},nil +} + +//Checkifthedeploymentalreadyexists,ifnotcreateanewone +found:=&appsv1.Deployment{} +err=r.Get(ctx,types.NamespacedName{Name:memcached.Name,Namespace:memcached.Namespace},found) +iferr!=nil&&apierrors.IsNotFound(err){ +//Defineanewdeployment +dep,err:=r.deploymentForMemcached(memcached) +iferr!=nil{ +log.Error(err,"FailedtodefinenewDeploymentresourceforMemcached") + +//Thefollowingimplementationwillupdatethestatus +meta.SetStatusCondition(&memcached.Status.Conditions,metav1.Condition{Type:typeAvailableMemcached, +Status:metav1.ConditionFalse,Reason:"Reconciling", +Message:fmt.Sprintf("FailedtocreateDeploymentforthecustomresource(%s):(%s)",memcached.Name,err)}) + +iferr:=r.Status().Update(ctx,memcached);err!=nil{ +log.Error(err,"FailedtoupdateMemcachedstatus") +returnctrl.Result{},err +} + +returnctrl.Result{},err +} + +log.Info("CreatinganewDeployment", +"Deployment.Namespace",dep.Namespace,"Deployment.Name",dep.Name) +iferr=r.Create(ctx,dep);err!=nil{ +log.Error(err,"FailedtocreatenewDeployment", +"Deployment.Namespace",dep.Namespace,"Deployment.Name",dep.Name) +returnctrl.Result{},err +} + +//Deploymentcreatedsuccessfully +//Wewillrequeuethereconciliationsothatwecanensurethestate +//andmoveforwardforthenextoperations +returnctrl.Result{RequeueAfter:time.Minute},nil +}elseiferr!=nil{ +log.Error(err,"FailedtogetDeployment") +//Let'sreturntheerrorforthereconciliationbere-triggedagain +returnctrl.Result{},err +} + +//TheCRDAPIisdefiningthattheMemcachedtype,haveaMemcachedSpec.Sizefield +//tosetthequantityofDeploymentinstancesisthedesiredstateonthecluster. +//Therefore,thefollowingcodewillensuretheDeploymentsizeisthesameasdefined +//viatheSizespecoftheCustomResourcewhichwearereconciling. +size:=memcached.Spec.Size +if*found.Spec.Replicas!=size{ +found.Spec.Replicas=&size +iferr=r.Update(ctx,found);err!=nil{ +log.Error(err,"FailedtoupdateDeployment", +"Deployment.Namespace",found.Namespace,"Deployment.Name",found.Name) + +//Re-fetchthememcachedCustomResourcebeforeupdatingthestatus +//sothatwehavethelateststateoftheresourceontheclusterandwewillavoid +//raisingtheerror"theobjecthasbeenmodified,pleaseapply +//yourchangestothelatestversionandtryagain"whichwouldre-triggerthereconciliation +iferr:=r.Get(ctx,req.NamespacedName,memcached);err!=nil{ +log.Error(err,"Failedtore-fetchmemcached") +returnctrl.Result{},err +} + +//Thefollowingimplementationwillupdatethestatus +meta.SetStatusCondition(&memcached.Status.Conditions,metav1.Condition{Type:typeAvailableMemcached, +Status:metav1.ConditionFalse,Reason:"Resizing", +Message:fmt.Sprintf("Failedtoupdatethesizeforthecustomresource(%s):(%s)",memcached.Name,err)}) + +iferr:=r.Status().Update(ctx,memcached);err!=nil{ +log.Error(err,"FailedtoupdateMemcachedstatus") +returnctrl.Result{},err +} + +returnctrl.Result{},err +} + +//Now,thatweupdatethesizewewanttorequeuethereconciliation +//sothatwecanensurethatwehavethelateststateoftheresourcebefore +//update.Also,itwillhelpensurethedesiredstateonthecluster +returnctrl.Result{Requeue:true},nil +} + +//Thefollowingimplementationwillupdatethestatus +meta.SetStatusCondition(&memcached.Status.Conditions,metav1.Condition{Type:typeAvailableMemcached, +Status:metav1.ConditionTrue,Reason:"Reconciling", +Message:fmt.Sprintf("Deploymentforcustomresource(%s)with%dreplicascreatedsuccessfully",memcached.Name,size)}) + +iferr:=r.Status().Update(ctx,memcached);err!=nil{ +log.Error(err,"FailedtoupdateMemcachedstatus") +returnctrl.Result{},err +} + +returnctrl.Result{},nil } ``` -#### Observing changes on cluster +####Observingchangesoncluster -This controller is persistently observant, monitoring any events associated with this Kind. As a result, pertinent changes -instantly set off the controller's reconciliation process. It's worth noting that we have implemented the `watches` feature. [(More info)][watches]. -This allows us to monitor events related to creating, updating, or deleting a Custom Resource of the Memcached kind, as well as the Deployment -which is orchestrated and owned by its respective controller. Observe: +Thiscontrollerispersistentlyobservant,monitoringanyeventsassociatedwiththisKind.Asaresult,pertinentchanges +instantlysetoffthecontroller'sreconciliationprocess.It'sworthnotingthatwehaveimplementedthe`watches`feature.[(Moreinfo)][watches]. +Thisallowsustomonitoreventsrelatedtocreating,updating,ordeletingaCustomResourceoftheMemcachedkind,aswellastheDeployment +whichisorchestratedandownedbyitsrespectivecontroller.Observe: ```go -// SetupWithManager sets up the controller with the Manager. -// Note that the Deployment will be also watched in order to ensure its -// desirable state on the cluster -func (r *MemcachedReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&examplecomv1alpha1.Memcached{}). ## Create watches for the Memcached Kind - Owns(&appsv1.Deployment{}). ## Create watches for the Deployment which has its controller owned reference - Complete(r) +//SetupWithManagersetsupthecontrollerwiththeManager. +//NotethattheDeploymentwillbealsowatchedinordertoensureits +//desirablestateonthecluster +func(r*MemcachedReconciler)SetupWithManager(mgrctrl.Manager)error{ +returnctrl.NewControllerManagedBy(mgr). +For(&examplecomv1alpha1.Memcached{}).##CreatewatchesfortheMemcachedKind +Owns(&appsv1.Deployment{}).##CreatewatchesfortheDeploymentwhichhasitscontrollerownedreference +Complete(r) } ``` - -### Setting the RBAC permissions +###SettingtheRBACpermissions -The [RBAC permissions][k8s-rbac] are now configured via [RBAC markers][rbac-markers], which are used to generate and update the -manifest files present in `config/rbac/`. These markers can be found (and should be defined) on the `Reconcile()` method of each controller, see -how it is implemented in our example: +The[RBACpermissions][k8s-rbac]arenowconfiguredvia[RBACmarkers][rbac-markers],whichareusedtogenerateandupdatethe +manifestfilespresentin`config/rbac/`.Thesemarkerscanbefound(andshouldbedefined)onthe`Reconcile()`methodofeachcontroller,see +howitisimplementedinourexample: ```go //+kubebuilder:rbac:groups=cache.example.com,resources=memcacheds,verbs=get;list;watch;create;update;patch;delete @@ -457,74 +457,74 @@ how it is implemented in our example: //+kubebuilder:rbac:groups=core,resources=pods,verbs=get;list;watch ``` -It's important to highlight that if you wish to add or modify RBAC rules, you can do so by updating or adding the respective markers in the controller. -After making the necessary changes, run the `make generate` command. This will prompt [controller-gen][controller-gen] to refresh the files located under `config/rbac`. +It'simportanttohighlightthatifyouwishtoaddormodifyRBACrules,youcandosobyupdatingoraddingtherespectivemarkersinthecontroller. +Aftermakingthenecessarychanges,runthe`makegenerate`command.Thiswillprompt[controller-gen][controller-gen]torefreshthefileslocatedunder`config/rbac`. - -### Manager (main.go) +###Manager(main.go) -The [Manager][manager] plays a crucial role in overseeing Controllers, which in turn enable operations on the cluster side. -If you inspect the `cmd/main.go` file, you'll come across the following: +The[Manager][manager]playsacrucialroleinoverseeingControllers,whichinturnenableoperationsontheclusterside. +Ifyouinspectthe`cmd/main.go`file,you'llcomeacrossthefollowing: ```go ... - mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ - Scheme: scheme, - Metrics: metricsserver.Options{BindAddress: metricsAddr}, - HealthProbeBindAddress: probeAddr, - LeaderElection: enableLeaderElection, - LeaderElectionID: "1836d577.testproject.org", - // 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 doesn't have to wait - // the LeaseDuration time first. - // - // In the default scaffold provided, the program ends immediately after - // the manager stops, so it would be fine to enable this option. However, - // if you are doing, or are intending 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) - } +mgr,err:=ctrl.NewManager(ctrl.GetConfigOrDie(),ctrl.Options{ +Scheme:scheme, +Metrics:metricsserver.Options{BindAddress:metricsAddr}, +HealthProbeBindAddress:probeAddr, +LeaderElection:enableLeaderElection, +LeaderElectionID:"1836d577.testproject.org", +//LeaderElectionReleaseOnCanceldefinesiftheleadershouldstepdownvoluntarily +//whentheManagerends.Thisrequiresthebinarytoimmediatelyendwhenthe +//Managerisstopped,otherwise,thissettingisunsafe.Settingthissignificantly +//speedsupvoluntaryleadertransitionsasthenewleaderdoesn'thavetowait +//theLeaseDurationtimefirst. +// +//Inthedefaultscaffoldprovided,theprogramendsimmediatelyafter +//themanagerstops,soitwouldbefinetoenablethisoption.However, +//ifyouaredoing,orareintendingtodo,anyoperationsuchasperformcleanups +//afterthemanagerstopsthenitsusagemightbeunsafe. +//LeaderElectionReleaseOnCancel:true, +}) +iferr!=nil{ +setupLog.Error(err,"unabletostartmanager") +os.Exit(1) +} ``` -The code snippet above outlines the configuration [options][options-manager] for the Manager. While we won't be altering this in our current example, -it's crucial to understand its location and the initialization process of your operator-based image. The Manager is responsible for overseeing the controllers -that are produced for your operator's APIs. - -### Checking the Project running in the cluster - -At this point, you can execute the commands highlighted in the [quick-start][quick-start]. -By executing `make build IMG=myregistry/example:1.0.0`, you'll build the image for your project. For testing purposes, it's recommended to publish this image to a -public registry. This ensures easy accessibility, eliminating the need for additional configurations. Once that's done, you can deploy the image -to the cluster using the `make deploy IMG=myregistry/example:1.0.0` command. - -## Next Steps - -- To delve deeper into developing your solution, consider going through the provided tutorials. -- For insights on optimizing your approach, refer to the [Best Practices][best-practices] documentation. - -[k8s-operator-pattern]: https://kubernetes.io/docs/concepts/extend-kubernetes/operator/ -[controller-runtime]: https://github.com/kubernetes-sigs/controller-runtime -[group-kind-oh-my]: ./cronjob-tutorial/gvks.md -[controller-gen]: ./reference/controller-gen.md -[markers]: ./reference/markers.md -[watches]: ./reference/watching-resources.md -[rbac-markers]: ./reference/markers/rbac.md -[k8s-rbac]: https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -[manager]: https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/manager -[options-manager]: https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/manager#Options -[quick-start]: ./quick-start.md -[best-practices]: ./reference/good-practices.md +Thecodesnippetaboveoutlinestheconfiguration[options][options-manager]fortheManager.Whilewewon'tbealteringthisinourcurrentexample, +it'scrucialtounderstanditslocationandtheinitializationprocessofyouroperator-basedimage.TheManagerisresponsibleforoverseeingthecontrollers +thatareproducedforyouroperator'sAPIs. + +###CheckingtheProjectrunninginthecluster + +Atthispoint,youcanexecutethecommandshighlightedinthe[quick-start][quick-start]. +Byexecuting`makebuildIMG=myregistry/example:1.0.0`,you'llbuildtheimageforyourproject.Fortestingpurposes,it'srecommendedtopublishthisimagetoa +publicregistry.Thisensureseasyaccessibility,eliminatingtheneedforadditionalconfigurations.Oncethat'sdone,youcandeploytheimage +totheclusterusingthe`makedeployIMG=myregistry/example:1.0.0`command. + +##NextSteps + +-Todelvedeeperintodevelopingyoursolution,considergoingthroughtheprovidedtutorials. +-Forinsightsonoptimizingyourapproach,refertothe[BestPractices][best-practices]documentation. + +[k8s-operator-pattern]:https://kubernetes.io/docs/concepts/extend-kubernetes/operator/ +[controller-runtime]:https://github.com/kubernetes-sigs/controller-runtime +[group-kind-oh-my]:./cronjob-tutorial/gvks.md +[controller-gen]:./reference/controller-gen.md +[markers]:./reference/markers.md +[watches]:./reference/watching-resources.md +[rbac-markers]:./reference/markers/rbac.md +[k8s-rbac]:https://kubernetes.io/docs/reference/access-authn-authz/rbac/ +[manager]:https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/manager +[options-manager]:https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/manager#Options +[quick-start]:./quick-start.md +[best-practices]:./reference/good-practices.md diff --git a/docs/book/src/getting-started/testdata/project/README.md b/docs/book/src/getting-started/testdata/project/README.md index 3fca7276d17..71917a215b4 100644 --- a/docs/book/src/getting-started/testdata/project/README.md +++ b/docs/book/src/getting-started/testdata/project/README.md @@ -1,114 +1,114 @@ -# project -// TODO(user): Add simple overview of use/purpose +#project +//TODO(user):Addsimpleoverviewofuse/purpose -## Description -// TODO(user): An in-depth paragraph about your project and overview of use +##Description +//TODO(user):Anin-depthparagraphaboutyourprojectandoverviewofuse -## Getting Started +##GettingStarted -### Prerequisites -- go version v1.21.0+ -- docker version 17.03+. -- kubectl version v1.11.3+. -- Access to a Kubernetes v1.11.3+ cluster. +###Prerequisites +-goversionv1.21.0+ +-dockerversion17.03+. +-kubectlversionv1.11.3+. +-AccesstoaKubernetesv1.11.3+cluster. -### To Deploy on the cluster -**Build and push your image to the location specified by `IMG`:** +###ToDeployonthecluster +**Buildandpushyourimagetothelocationspecifiedby`IMG`:** ```sh -make docker-build docker-push IMG=/project:tag +makedocker-builddocker-pushIMG=/project: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. +**NOTE:**Thisimageoughttobepublishedinthepersonalregistryyouspecified. +Anditisrequiredtohaveaccesstopulltheimagefromtheworkingenvironment. +Makesureyouhavetheproperpermissiontotheregistryiftheabovecommandsdon’twork. -**Install the CRDs into the cluster:** +**InstalltheCRDsintothecluster:** ```sh -make install +makeinstall ``` -**Deploy the Manager to the cluster with the image specified by `IMG`:** +**DeploytheManagertotheclusterwiththeimagespecifiedby`IMG`:** ```sh -make deploy IMG=/project:tag +makedeployIMG=/project:tag ``` -> **NOTE**: If you encounter RBAC errors, you may need to grant yourself cluster-admin -privileges or be logged in as admin. +>**NOTE**:IfyouencounterRBACerrors,youmayneedtograntyourselfcluster-admin +privilegesorbeloggedinasadmin. -**Create instances of your solution** -You can apply the samples (examples) from the config/sample: +**Createinstancesofyoursolution** +Youcanapplythesamples(examples)fromtheconfig/sample: ```sh -kubectl apply -k config/samples/ +kubectlapply-kconfig/samples/ ``` ->**NOTE**: Ensure that the samples has default values to test it out. +>**NOTE**:Ensurethatthesampleshasdefaultvaluestotestitout. -### To Uninstall -**Delete the instances (CRs) from the cluster:** +###ToUninstall +**Deletetheinstances(CRs)fromthecluster:** ```sh -kubectl delete -k config/samples/ +kubectldelete-kconfig/samples/ ``` -**Delete the APIs(CRDs) from the cluster:** +**DeletetheAPIs(CRDs)fromthecluster:** ```sh -make uninstall +makeuninstall ``` -**UnDeploy the controller from the cluster:** +**UnDeploythecontrollerfromthecluster:** ```sh -make undeploy +makeundeploy ``` -## Project Distribution +##ProjectDistribution -Following are the steps to build the installer and distribute this project to users. +Followingarethestepstobuildtheinstalleranddistributethisprojecttousers. -1. Build the installer for the image built and published in the registry: +1.Buildtheinstallerfortheimagebuiltandpublishedintheregistry: ```sh -make build-installer IMG=/project:tag +makebuild-installerIMG=/project: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. +NOTE:Themakefiletargetmentionedabovegeneratesan'install.yaml' +fileinthedistdirectory.Thisfilecontainsalltheresourcesbuilt +withKustomize,whicharenecessarytoinstallthisprojectwithout +itsdependencies. -2. Using the installer +2.Usingtheinstaller -Users can just run kubectl apply -f to install the project, i.e.: +Userscanjustrunkubectlapply-ftoinstalltheproject,i.e.: ```sh -kubectl apply -f https://raw.githubusercontent.com//project//dist/install.yaml +kubectlapply-fhttps://raw.githubusercontent.com//project//dist/install.yaml ``` -## Contributing -// TODO(user): Add detailed information on how you would like others to contribute to this project +##Contributing +//TODO(user):Adddetailedinformationonhowyouwouldlikeotherstocontributetothisproject -**NOTE:** Run `make help` for more information on all potential `make` targets +**NOTE:**Run`makehelp`formoreinformationonallpotential`make`targets -More information can be found via the [Kubebuilder Documentation](https://book.kubebuilder.io/introduction.html) +Moreinformationcanbefoundviathe[KubebuilderDocumentation](https://book.kubebuilder.io/introduction.html) -## License +##License -Copyright 2024 The Kubernetes authors. +Copyright2024TheKubernetesauthors. -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 +LicensedundertheApacheLicense,Version2.0(the"License"); +youmaynotusethisfileexceptincompliancewiththeLicense. +YoumayobtainacopyoftheLicenseat - http://www.apache.org/licenses/LICENSE-2.0 +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. +Unlessrequiredbyapplicablelaworagreedtoinwriting,software +distributedundertheLicenseisdistributedonan"ASIS"BASIS, +WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied. +SeetheLicenseforthespecificlanguagegoverningpermissionsand +limitationsundertheLicense. diff --git a/docs/book/src/introduction.md b/docs/book/src/introduction.md index b245e8fa1f1..d5cb36bbb99 100644 --- a/docs/book/src/introduction.md +++ b/docs/book/src/introduction.md @@ -1,76 +1,76 @@ -**Note:** Impatient readers may head straight to [Quick Start](quick-start.md). +**Note:**Impatientreadersmayheadstraightto[QuickStart](quick-start.md). -**Using Kubebuilder v1 or v2? Check the legacy documentation for [v1](https://book-v1.book.kubebuilder.io) or [v2](https://book-v2.book.kubebuilder.io)** +**UsingKubebuilderv1orv2?Checkthelegacydocumentationfor[v1](https://book-v1.book.kubebuilder.io)or[v2](https://book-v2.book.kubebuilder.io)** -## Who is this for +##Whoisthisfor -#### Users of Kubernetes +####UsersofKubernetes -Users of Kubernetes will develop a deeper understanding of Kubernetes through learning -the fundamental concepts behind how APIs are designed and implemented. This book -will teach readers how to develop their own Kubernetes APIs and the -principles from which the core Kubernetes APIs are designed. +UsersofKuberneteswilldevelopadeeperunderstandingofKubernetesthroughlearning +thefundamentalconceptsbehindhowAPIsaredesignedandimplemented.Thisbook +willteachreadershowtodeveloptheirownKubernetesAPIsandthe +principlesfromwhichthecoreKubernetesAPIsaredesigned. Including: -- The structure of Kubernetes APIs and Resources -- API versioning semantics -- Self-healing -- Garbage Collection and Finalizers -- Declarative vs Imperative APIs -- Level-Based vs Edge-Base APIs -- Resources vs Subresources +-ThestructureofKubernetesAPIsandResources +-APIversioningsemantics +-Self-healing +-GarbageCollectionandFinalizers +-DeclarativevsImperativeAPIs +-Level-BasedvsEdge-BaseAPIs +-ResourcesvsSubresources -#### Kubernetes API extension developers +####KubernetesAPIextensiondevelopers -API extension developers will learn the principles and concepts behind implementing canonical -Kubernetes APIs, as well as simple tools and libraries for rapid execution. This -book covers pitfalls and misconceptions that extension developers commonly encounter. +APIextensiondeveloperswilllearntheprinciplesandconceptsbehindimplementingcanonical +KubernetesAPIs,aswellassimpletoolsandlibrariesforrapidexecution.This +bookcoverspitfallsandmisconceptionsthatextensiondeveloperscommonlyencounter. Including: -- How to batch multiple events into a single reconciliation call -- How to configure periodic reconciliation -- *Forthcoming* - - When to use the lister cache vs live lookups - - Garbage Collection vs Finalizers - - How to use Declarative vs Webhook Validation - - How to implement API versioning +-Howtobatchmultipleeventsintoasinglereconciliationcall +-Howtoconfigureperiodicreconciliation +-*Forthcoming* +-Whentousethelistercachevslivelookups +-GarbageCollectionvsFinalizers +-HowtouseDeclarativevsWebhookValidation +-HowtoimplementAPIversioning -## Why Kubernetes APIs +##WhyKubernetesAPIs -Kubernetes APIs provide consistent and well defined endpoints for -objects adhering to a consistent and rich structure. +KubernetesAPIsprovideconsistentandwelldefinedendpointsfor +objectsadheringtoaconsistentandrichstructure. -This approach has fostered a rich ecosystem of tools and libraries for working -with Kubernetes APIs. +Thisapproachhasfosteredarichecosystemoftoolsandlibrariesforworking +withKubernetesAPIs. -Users work with the APIs through declaring objects as *yaml* or *json* config, and using -common tooling to manage the objects. +UsersworkwiththeAPIsthroughdeclaringobjectsas*yaml*or*json*config,andusing +commontoolingtomanagetheobjects. -Building services as Kubernetes APIs provides many advantages to plain old REST, including: +BuildingservicesasKubernetesAPIsprovidesmanyadvantagestoplainoldREST,including: -* Hosted API endpoints, storage, and validation. -* Rich tooling and CLIs such as `kubectl` and `kustomize`. -* Support for AuthN and granular AuthZ. -* Support for API evolution through API versioning and conversion. -* Facilitation of adaptive / self-healing APIs that continuously respond to changes - in the system state without user intervention. -* Kubernetes as a hosting environment +*HostedAPIendpoints,storage,andvalidation. +*RichtoolingandCLIssuchas`kubectl`and`kustomize`. +*SupportforAuthNandgranularAuthZ. +*SupportforAPIevolutionthroughAPIversioningandconversion. +*Facilitationofadaptive/self-healingAPIsthatcontinuouslyrespondtochanges +inthesystemstatewithoutuserintervention. +*Kubernetesasahostingenvironment -Developers may build and publish their own Kubernetes APIs for installation into -running Kubernetes clusters. +DevelopersmaybuildandpublishtheirownKubernetesAPIsforinstallationinto +runningKubernetesclusters. -## Contribution +##Contribution -If you like to contribute to either this book or the code, please be so kind -to read our [Contribution](https://github.com/kubernetes-sigs/kubebuilder/blob/master/CONTRIBUTING.md) guidelines first. +Ifyouliketocontributetoeitherthisbookorthecode,pleasebesokind +toreadour[Contribution](https://github.com/kubernetes-sigs/kubebuilder/blob/master/CONTRIBUTING.md)guidelinesfirst. -## Resources +##Resources -* Repository: [sigs.k8s.io/kubebuilder](https://sigs.k8s.io/kubebuilder) +*Repository:[sigs.k8s.io/kubebuilder](https://sigs.k8s.io/kubebuilder) -* Slack channel: [#kubebuilder](http://slack.k8s.io/#kubebuilder) +*Slackchannel:[#kubebuilder](http://slack.k8s.io/#kubebuilder) -* Google Group: - [kubebuilder@googlegroups.com](https://groups.google.com/forum/#!forum/kubebuilder) +*GoogleGroup: +[kubebuilder@googlegroups.com](https://groups.google.com/forum/#!forum/kubebuilder) diff --git a/docs/book/src/logos/README.md b/docs/book/src/logos/README.md index bbcd1373a96..a841ad559a6 100644 --- a/docs/book/src/logos/README.md +++ b/docs/book/src/logos/README.md @@ -1,12 +1,12 @@ -# Kubebuilder Logos +#KubebuilderLogos -The official location for the logos is in a [public GCS -bucket][kb-logos-gcs] (or if you like GCS XML listings, +Theofficiallocationforthelogosisina[publicGCS +bucket][kb-logos-gcs](orifyoulikeGCSXMLlistings, [here][kb-logos-gcs-direct]). -These logos are copies used in the book, resized to their appropriate -sizes. +Theselogosarecopiesusedinthebook,resizedtotheirappropriate +sizes. -[kb-logos-gcs]: https://console.cloud.google.com/storage/browser/kubebuilder-logos +[kb-logos-gcs]:https://console.cloud.google.com/storage/browser/kubebuilder-logos -[kb-logos-gcs-direct]: https://storage.googleapis.com/kubebuilder-logos +[kb-logos-gcs-direct]:https://storage.googleapis.com/kubebuilder-logos diff --git a/docs/book/src/migration/legacy.md b/docs/book/src/migration/legacy.md index da2ff198a66..6a036cecad3 100644 --- a/docs/book/src/migration/legacy.md +++ b/docs/book/src/migration/legacy.md @@ -1,18 +1,18 @@ -# Migration guides from Legacy versions < 3.0.0 +#MigrationguidesfromLegacyversions<3.0.0 -Follow the migration guides from the legacy Kubebuilder versions up the required latest v3x version. -Note that from v3, a new ecosystem using plugins is introduced for better maintainability, reusability and user -experience . +FollowthemigrationguidesfromthelegacyKubebuilderversionsuptherequiredlatestv3xversion. +Notethatfromv3,anewecosystemusingpluginsisintroducedforbettermaintainability,reusabilityanduser +experience. -For more info, see the design docs of: +Formoreinfo,seethedesigndocsof: -- [Extensible CLI and Scaffolding Plugins: phase 1][plugins-phase1-design-doc] -- [Extensible CLI and Scaffolding Plugins: phase 1.5][plugins-phase1-design-doc-1.5] -- [Extensible CLI and Scaffolding Plugins - Phase 2][plugins-phase2-design-doc] +-[ExtensibleCLIandScaffoldingPlugins:phase1][plugins-phase1-design-doc] +-[ExtensibleCLIandScaffoldingPlugins:phase1.5][plugins-phase1-design-doc-1.5] +-[ExtensibleCLIandScaffoldingPlugins-Phase2][plugins-phase2-design-doc] -Also, you can check the [Plugins section][plugins-section]. +Also,youcancheckthe[Pluginssection][plugins-section]. -[plugins-phase1-design-doc]: https://github.com/kubernetes-sigs/kubebuilder/blob/master/designs/extensible-cli-and-scaffolding-plugins-phase-1.md -[plugins-phase1-design-doc-1.5]: https://github.com/kubernetes-sigs/kubebuilder/blob/master/designs/extensible-cli-and-scaffolding-plugins-phase-1-5.md -[plugins-phase2-design-doc]: https://github.com/kubernetes-sigs/kubebuilder/blob/master/designs/extensible-cli-and-scaffolding-plugins-phase-2.md -[plugins-section]: ./../plugins/plugins.md +[plugins-phase1-design-doc]:https://github.com/kubernetes-sigs/kubebuilder/blob/master/designs/extensible-cli-and-scaffolding-plugins-phase-1.md +[plugins-phase1-design-doc-1.5]:https://github.com/kubernetes-sigs/kubebuilder/blob/master/designs/extensible-cli-and-scaffolding-plugins-phase-1-5.md +[plugins-phase2-design-doc]:https://github.com/kubernetes-sigs/kubebuilder/blob/master/designs/extensible-cli-and-scaffolding-plugins-phase-2.md +[plugins-section]:./../plugins/plugins.md diff --git a/docs/book/src/migration/legacy/manually_migration_guide_v2_v3.md b/docs/book/src/migration/legacy/manually_migration_guide_v2_v3.md index 2b69a7cd0dc..09afe40e905 100644 --- a/docs/book/src/migration/legacy/manually_migration_guide_v2_v3.md +++ b/docs/book/src/migration/legacy/manually_migration_guide_v2_v3.md @@ -1,602 +1,602 @@ -# Migration from v2 to v3 by updating the files manually +#Migrationfromv2tov3byupdatingthefilesmanually -Make sure you understand the [differences between Kubebuilder v2 and v3][migration-v2vsv3] -before continuing +Makesureyouunderstandthe[differencesbetweenKubebuilderv2andv3][migration-v2vsv3] +beforecontinuing -Please ensure you have followed the [installation guide](/quick-start.md#installation) -to install the required components. +Pleaseensureyouhavefollowedthe[installationguide](/quick-start.md#installation) +toinstalltherequiredcomponents. -The following guide describes the manual steps required to upgrade your config version and start using the plugin-enabled version. +Thefollowingguidedescribesthemanualstepsrequiredtoupgradeyourconfigversionandstartusingtheplugin-enabledversion. -This way is more complex, susceptible to errors, and success cannot be assured. Also, by following these steps you will not get the improvements and bug fixes in the default generated project files. +Thiswayismorecomplex,susceptibletoerrors,andsuccesscannotbeassured.Also,byfollowingthesestepsyouwillnotgettheimprovementsandbugfixesinthedefaultgeneratedprojectfiles. -Usually you will only try to do it manually if you customized your project and deviated too much from the proposed scaffold. Before continuing, ensure that you understand the note about [project customizations][project-customizations]. Note that you might need to spend more effort to do this process manually than organize your project customizations to follow up the proposed layout and keep your project maintainable and upgradable with less effort in the future. +Usuallyyouwillonlytrytodoitmanuallyifyoucustomizedyourprojectanddeviatedtoomuchfromtheproposedscaffold.Beforecontinuing,ensurethatyouunderstandthenoteabout[projectcustomizations][project-customizations].Notethatyoumightneedtospendmoreefforttodothisprocessmanuallythanorganizeyourprojectcustomizationstofollowuptheproposedlayoutandkeepyourprojectmaintainableandupgradablewithlesseffortinthefuture. -The recommended upgrade approach is to follow the [Migration Guide v2 to V3][migration-guide-v2-to-v3] instead. +Therecommendedupgradeapproachistofollowthe[MigrationGuidev2toV3][migration-guide-v2-to-v3]instead. -## Migration from project config version "2" to "3" +##Migrationfromprojectconfigversion"2"to"3" -Migrating between project configuration versions involves additions, removals, and/or changes -to fields in your project's `PROJECT` file, which is created by running the `init` command. +Migratingbetweenprojectconfigurationversionsinvolvesadditions,removals,and/orchanges +tofieldsinyourproject's`PROJECT`file,whichiscreatedbyrunningthe`init`command. -The `PROJECT` file now has a new layout. It stores more information about what resources are in use, to better enable plugins to make useful decisions when scaffolding. +The`PROJECT`filenowhasanewlayout.Itstoresmoreinformationaboutwhatresourcesareinuse,tobetterenablepluginstomakeusefuldecisionswhenscaffolding. -Furthermore, the `PROJECT` file itself is now versioned. The `version` field corresponds to the version of the `PROJECT` file itself, while the `layout` field indicates the scaffolding and the primary plugin version in use. +Furthermore,the`PROJECT`fileitselfisnowversioned.The`version`fieldcorrespondstotheversionofthe`PROJECT`fileitself,whilethe`layout`fieldindicatesthescaffoldingandtheprimarypluginversioninuse. -### Steps to migrate +###Stepstomigrate -The following steps describe the manual changes required to bring the project configuration file (`PROJECT`). These change will add the information that Kubebuilder would add when generating the file. This file can be found in the root directory. +Thefollowingstepsdescribethemanualchangesrequiredtobringtheprojectconfigurationfile(`PROJECT`).ThesechangewilladdtheinformationthatKubebuilderwouldaddwhengeneratingthefile.Thisfilecanbefoundintherootdirectory. -#### Add the `projectName` +####Addthe`projectName` -The project name is the name of the project directory in lowercase: +Theprojectnameisthenameoftheprojectdirectoryinlowercase: ```yaml ... -projectName: example +projectName:example ... ``` -#### Add the `layout` +####Addthe`layout` -The default plugin layout which is equivalent to the previous version is `go.kubebuilder.io/v2`: +Thedefaultpluginlayoutwhichisequivalenttothepreviousversionis`go.kubebuilder.io/v2`: ```yaml ... layout: -- go.kubebuilder.io/v2 +-go.kubebuilder.io/v2 ... ``` -#### Update the `version` +####Updatethe`version` -The `version` field represents the version of project's layout. Update this to `"3"`: +The`version`fieldrepresentstheversionofproject'slayout.Updatethisto`"3"`: ```yaml ... -version: "3" +version:"3" ... ``` -#### Add the resource data +####Addtheresourcedata -The attribute `resources` represents the list of resources scaffolded in your project. +Theattribute`resources`representsthelistofresourcesscaffoldedinyourproject. -You will need to add the following data for each resource added to the project. +Youwillneedtoaddthefollowingdataforeachresourceaddedtotheproject. -##### Add the Kubernetes API version by adding `resources[entry].api.crdVersion: v1beta1`: +#####AddtheKubernetesAPIversionbyadding`resources[entry].api.crdVersion:v1beta1`: ```yaml ... resources: -- api: - ... - crdVersion: v1beta1 - domain: my.domain - group: webapp - kind: Guestbook - ... +-api: +... +crdVersion:v1beta1 +domain:my.domain +group:webapp +kind:Guestbook +... ``` -##### Add the scope used do scaffold the CRDs by adding `resources[entry].api.namespaced: true` unless they were cluster-scoped: +#####AddthescopeuseddoscaffoldtheCRDsbyadding`resources[entry].api.namespaced:true`unlesstheywerecluster-scoped: ```yaml ... resources: -- api: - ... - namespaced: true - group: webapp - kind: Guestbook - ... +-api: +... +namespaced:true +group:webapp +kind:Guestbook +... ``` -##### If you have a controller scaffolded for the API then, add `resources[entry].controller: true`: +#####IfyouhaveacontrollerscaffoldedfortheAPIthen,add`resources[entry].controller:true`: ```yaml ... resources: -- api: - ... - controller: true - group: webapp - kind: Guestbook +-api: +... +controller:true +group:webapp +kind:Guestbook ``` -##### Add the resource domain such as `resources[entry].domain: testproject.org` which usually will be the project domain unless the API scaffold is a core type and/or an external type: +#####Addtheresourcedomainsuchas`resources[entry].domain:testproject.org`whichusuallywillbetheprojectdomainunlesstheAPIscaffoldisacoretypeand/oranexternaltype: ```yaml ... resources: -- api: - ... - domain: testproject.org - group: webapp - kind: Guestbook +-api: +... +domain:testproject.org +group:webapp +kind:Guestbook ``` - -Note that you will only need to add the `domain` if your project has a scaffold for a core type API which the `Domain` value is not empty in Kubernetes API group qualified scheme definition. (For example, see [here](https://github.com/kubernetes/api/blob/v0.19.7/apps/v1/register.go#L26) that for Kinds from the API `apps` it has not a domain when see [here](https://github.com/kubernetes/api/blob/v0.19.7/authentication/v1/register.go#L26) that for Kinds from the API `authentication` its domain is `k8s.io` ) +Notethatyouwillonlyneedtoaddthe`domain`ifyourprojecthasascaffoldforacoretypeAPIwhichthe`Domain`valueisnotemptyinKubernetesAPIgroupqualifiedschemedefinition.(Forexample,see[here](https://github.com/kubernetes/api/blob/v0.19.7/apps/v1/register.go#L26)thatforKindsfromtheAPI`apps`ithasnotadomainwhensee[here](https://github.com/kubernetes/api/blob/v0.19.7/authentication/v1/register.go#L26)thatforKindsfromtheAPI`authentication`itsdomainis`k8s.io`) - Check the following the list to know the core types supported and its domain: +Checkthefollowingthelisttoknowthecoretypessupportedanditsdomain: -| Core Type | Domain | +|CoreType|Domain| |----------|:-------------:| -| admission | "k8s.io" | -| admissionregistration | "k8s.io" | -| apps | empty | -| auditregistration | "k8s.io" | -| apiextensions | "k8s.io" | -| authentication | "k8s.io" | -| authorization | "k8s.io" | -| autoscaling | empty | -| batch | empty | -| certificates | "k8s.io" | -| coordination | "k8s.io" | -| core | empty | -| events | "k8s.io" | -| extensions | empty | -| imagepolicy | "k8s.io" | -| networking | "k8s.io" | -| node | "k8s.io" | -| metrics | "k8s.io" | -| policy | empty | -| rbac.authorization | "k8s.io" | -| scheduling | "k8s.io" | -| setting | "k8s.io" | -| storage | "k8s.io" | - -Following an example where a controller was scaffold for the core type Kind Deployment via the command `create api --group apps --version v1 --kind Deployment --controller=true --resource=false --make=false`: +|admission|"k8s.io"| +|admissionregistration|"k8s.io"| +|apps|empty| +|auditregistration|"k8s.io"| +|apiextensions|"k8s.io"| +|authentication|"k8s.io"| +|authorization|"k8s.io"| +|autoscaling|empty| +|batch|empty| +|certificates|"k8s.io"| +|coordination|"k8s.io"| +|core|empty| +|events|"k8s.io"| +|extensions|empty| +|imagepolicy|"k8s.io"| +|networking|"k8s.io"| +|node|"k8s.io"| +|metrics|"k8s.io"| +|policy|empty| +|rbac.authorization|"k8s.io"| +|scheduling|"k8s.io"| +|setting|"k8s.io"| +|storage|"k8s.io"| + +FollowinganexamplewhereacontrollerwasscaffoldforthecoretypeKindDeploymentviathecommand`createapi--groupapps--versionv1--kindDeployment--controller=true--resource=false--make=false`: ```yaml -- controller: true - group: apps - kind: Deployment - path: k8s.io/api/apps/v1 - version: v1 +-controller:true +group:apps +kind:Deployment +path:k8s.io/api/apps/v1 +version:v1 ``` -##### Add the `resources[entry].path` with the import path for the api: +#####Addthe`resources[entry].path`withtheimportpathfortheapi: - ```yaml ... resources: -- api: - ... - ... - group: webapp - kind: Guestbook - path: example/api/v1 +-api: +... +... +group:webapp +kind:Guestbook +path:example/api/v1 ``` -##### If your project is using webhooks then, add `resources[entry].webhooks.[type]: true` for each type generated and then, add `resources[entry].webhooks.webhookVersion: v1beta1`: +#####Ifyourprojectisusingwebhooksthen,add`resources[entry].webhooks.[type]:true`foreachtypegeneratedandthen,add`resources[entry].webhooks.webhookVersion:v1beta1`: - ```yaml resources: -- api: - ... - ... - group: webapp - kind: Guestbook - webhooks: - defaulting: true - validation: true - webhookVersion: v1beta1 +-api: +... +... +group:webapp +kind:Guestbook +webhooks: +defaulting:true +validation:true +webhookVersion:v1beta1 ``` -#### Check your PROJECT file +####CheckyourPROJECTfile -Now ensure that your `PROJECT` file has the same information when the manifests are generated via Kubebuilder V3 CLI. +Nowensurethatyour`PROJECT`filehasthesameinformationwhenthemanifestsaregeneratedviaKubebuilderV3CLI. -For the QuickStart example, the `PROJECT` file manually updated to use `go.kubebuilder.io/v2` would look like: +FortheQuickStartexample,the`PROJECT`filemanuallyupdatedtouse`go.kubebuilder.io/v2`wouldlooklike: ```yaml -domain: my.domain +domain:my.domain layout: -- go.kubebuilder.io/v2 -projectName: example -repo: example +-go.kubebuilder.io/v2 +projectName:example +repo:example resources: -- api: - crdVersion: v1 - namespaced: true - controller: true - domain: my.domain - group: webapp - kind: Guestbook - path: example/api/v1 - version: v1 -version: "3" +-api: +crdVersion:v1 +namespaced:true +controller:true +domain:my.domain +group:webapp +kind:Guestbook +path:example/api/v1 +version:v1 +version:"3" ``` -You can check the differences between the previous layout(`version 2`) and the current format(`version 3`) with the `go.kubebuilder.io/v2` by comparing an example scenario which involves more than one API and webhook, see: +Youcancheckthedifferencesbetweenthepreviouslayout(`version2`)andthecurrentformat(`version3`)withthe`go.kubebuilder.io/v2`bycomparinganexamplescenariowhichinvolvesmorethanoneAPIandwebhook,see: -**Example (Project version 2)** +**Example(Projectversion2)** ```yaml -domain: testproject.org -repo: sigs.k8s.io/kubebuilder/example +domain:testproject.org +repo:sigs.k8s.io/kubebuilder/example resources: -- group: crew - kind: Captain - version: v1 -- group: crew - kind: FirstMate - version: v1 -- group: crew - kind: Admiral - version: v1 -version: "2" +-group:crew +kind:Captain +version:v1 +-group:crew +kind:FirstMate +version:v1 +-group:crew +kind:Admiral +version:v1 +version:"2" ``` -**Example (Project version 3)** +**Example(Projectversion3)** ```yaml -domain: testproject.org +domain:testproject.org layout: -- go.kubebuilder.io/v2 -projectName: example -repo: sigs.k8s.io/kubebuilder/example +-go.kubebuilder.io/v2 +projectName:example +repo:sigs.k8s.io/kubebuilder/example resources: -- api: - crdVersion: v1 - namespaced: true - controller: true - domain: testproject.org - group: crew - kind: Captain - path: example/api/v1 - version: v1 - webhooks: - defaulting: true - validation: true - webhookVersion: v1 -- api: - crdVersion: v1 - namespaced: true - controller: true - domain: testproject.org - group: crew - kind: FirstMate - path: example/api/v1 - version: v1 - webhooks: - conversion: true - webhookVersion: v1 -- api: - crdVersion: v1 - controller: true - domain: testproject.org - group: crew - kind: Admiral - path: example/api/v1 - plural: admirales - version: v1 - webhooks: - defaulting: true - webhookVersion: v1 -version: "3" -``` - -### Verification - -In the steps above, you updated only the `PROJECT` file which represents the project configuration. This configuration is useful only for the CLI tool. It should not affect how your project behaves. - -There is no option to verify that you properly updated the configuration file. The best way to ensure the configuration file has the correct `V3+` fields is to initialize a project with the same API(s), controller(s), and webhook(s) in order to compare generated configuration with the manually changed configuration. - -If you made mistakes in the above process, you will likely face issues using the CLI. - - -## Update your project to use go/v3 plugin - -Migrating between project [plugins][plugins-doc] involves additions, removals, and/or changes -to files created by any plugin-supported command, e.g. `init` and `create`. A plugin supports -one or more project config versions; make sure you upgrade your project's -config version to the latest supported by your target plugin version before upgrading plugin versions. - -The following steps describe the manual changes required to modify the project's layout enabling your project to use the `go/v3` plugin. These steps will not help you address all the bug fixes of the already generated scaffolds. - - -### Steps to migrate +###Stepstomigrate -#### Update your plugin version into the PROJECT file +####UpdateyourpluginversionintothePROJECTfile -Before updating the `layout`, please ensure you have followed the above steps to upgrade your Project version to `3`. Once you have upgraded the project version, update the `layout` to the new plugin version ` go.kubebuilder.io/v3` as follows: +Beforeupdatingthe`layout`,pleaseensureyouhavefollowedtheabovestepstoupgradeyourProjectversionto`3`.Onceyouhaveupgradedtheprojectversion,updatethe`layout`tothenewpluginversion`go.kubebuilder.io/v3`asfollows: ```yaml -domain: my.domain +domain:my.domain layout: -- go.kubebuilder.io/v3 +-go.kubebuilder.io/v3 ... ``` -#### Upgrade the Go version and its dependencies: +####UpgradetheGoversionanditsdependencies: -Ensure that your `go.mod` is using Go version `1.15` and the following dependency versions: +Ensurethatyour`go.mod`isusingGoversion`1.15`andthefollowingdependencyversions: ```go -module example +moduleexample -go 1.18 +go1.18 -require ( - github.com/onsi/ginkgo/v2 v2.1.4 - github.com/onsi/gomega v1.19.0 - k8s.io/api v0.24.0 - k8s.io/apimachinery v0.24.0 - k8s.io/client-go v0.24.0 - sigs.k8s.io/controller-runtime v0.12.1 +require( +github.com/onsi/ginkgo/v2v2.1.4 +github.com/onsi/gomegav1.19.0 +k8s.io/apiv0.24.0 +k8s.io/apimachineryv0.24.0 +k8s.io/client-gov0.24.0 +sigs.k8s.io/controller-runtimev0.12.1 ) ``` -#### Update the golang image +####Updatethegolangimage -In the Dockerfile, replace: +IntheDockerfile,replace: ``` -# Build the manager binary -FROM golang:1.13 as builder +#Buildthemanagerbinary +FROMgolang:1.13asbuilder ``` With: ``` -# Build the manager binary -FROM golang:1.16 as builder +#Buildthemanagerbinary +FROMgolang:1.16asbuilder ``` -#### Update your Makefile +####UpdateyourMakefile -##### To allow controller-gen to scaffold the nw Kubernetes APIs +#####Toallowcontroller-gentoscaffoldthenwKubernetesAPIs -To allow `controller-gen` and the scaffolding tool to use the new API versions, replace: +Toallow`controller-gen`andthescaffoldingtooltousethenewAPIversions,replace: ``` -CRD_OPTIONS ?= "crd:trivialVersions=true" +CRD_OPTIONS?="crd:trivialVersions=true" ``` With: ``` -CRD_OPTIONS ?= "crd" +CRD_OPTIONS?="crd" ``` -##### To allow automatic downloads +#####Toallowautomaticdownloads -To allow downloading the newer versions of the Kubernetes binaries required by Envtest into the `testbin/` directory of your project instead of the global setup, replace: +ToallowdownloadingthenewerversionsoftheKubernetesbinariesrequiredbyEnvtestintothe`testbin/`directoryofyourprojectinsteadoftheglobalsetup,replace: ```makefile -# Run tests -test: generate fmt vet manifests - go test ./... -coverprofile cover.out +#Runtests +test:generatefmtvetmanifests +gotest./...-coverprofilecover.out ``` With: ```makefile -# 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 +#SettingSHELLtobashallowsbashcommandstobeexecutedbyrecipes. +#Optionsaresettoexitwhenarecipelineexitsnon-zeroorapipedcommandfails. +SHELL=/usr/bin/envbash-opipefail +.SHELLFLAGS=-ec -ENVTEST_ASSETS_DIR=$(shell pwd)/testbin -test: manifests generate fmt vet ## Run tests. - mkdir -p ${ENVTEST_ASSETS_DIR} - test -f ${ENVTEST_ASSETS_DIR}/setup-envtest.sh || curl -sSLo ${ENVTEST_ASSETS_DIR}/setup-envtest.sh https://raw.githubusercontent.com/kubernetes-sigs/controller-runtime/v0.8.3/hack/setup-envtest.sh - source ${ENVTEST_ASSETS_DIR}/setup-envtest.sh; fetch_envtest_tools $(ENVTEST_ASSETS_DIR); setup_envtest_env $(ENVTEST_ASSETS_DIR); go test ./... -coverprofile cover.out +ENVTEST_ASSETS_DIR=$(shellpwd)/testbin +test:manifestsgeneratefmtvet##Runtests. +mkdir-p${ENVTEST_ASSETS_DIR} +test-f${ENVTEST_ASSETS_DIR}/setup-envtest.sh||curl-sSLo${ENVTEST_ASSETS_DIR}/setup-envtest.shhttps://raw.githubusercontent.com/kubernetes-sigs/controller-runtime/v0.8.3/hack/setup-envtest.sh +source${ENVTEST_ASSETS_DIR}/setup-envtest.sh;fetch_envtest_tools$(ENVTEST_ASSETS_DIR);setup_envtest_env$(ENVTEST_ASSETS_DIR);gotest./...-coverprofilecover.out ``` - -##### To upgrade `controller-gen` and `kustomize` dependencies versions used +#####Toupgrade`controller-gen`and`kustomize`dependenciesversionsused -To upgrade the `controller-gen` and `kustomize` version used to generate the manifests replace: +Toupgradethe`controller-gen`and`kustomize`versionusedtogeneratethemanifestsreplace: ``` -# find or download controller-gen -# download controller-gen if necessary +#findordownloadcontroller-gen +#downloadcontroller-genifnecessary controller-gen: -ifeq (, $(shell which controller-gen)) - @{ \ - set -e ;\ - CONTROLLER_GEN_TMP_DIR=$$(mktemp -d) ;\ - cd $$CONTROLLER_GEN_TMP_DIR ;\ - go mod init tmp ;\ - go get sigs.k8s.io/controller-tools/cmd/controller-gen@v0.2.5 ;\ - rm -rf $$CONTROLLER_GEN_TMP_DIR ;\ - } +ifeq(,$(shellwhichcontroller-gen)) +@{\ +set-e;\ +CONTROLLER_GEN_TMP_DIR=$$(mktemp-d);\ +cd$$CONTROLLER_GEN_TMP_DIR;\ +gomodinittmp;\ +gogetsigs.k8s.io/controller-tools/cmd/controller-gen@v0.2.5;\ +rm-rf$$CONTROLLER_GEN_TMP_DIR;\ +} CONTROLLER_GEN=$(GOBIN)/controller-gen else -CONTROLLER_GEN=$(shell which controller-gen) +CONTROLLER_GEN=$(shellwhichcontroller-gen) endif ``` With: ``` -##@ Build Dependencies +##@BuildDependencies -## Location to install dependencies to -LOCALBIN ?= $(shell pwd)/bin +##Locationtoinstalldependenciesto +LOCALBIN?=$(shellpwd)/bin $(LOCALBIN): - mkdir -p $(LOCALBIN) +mkdir-p$(LOCALBIN) -## Tool Binaries -KUSTOMIZE ?= $(LOCALBIN)/kustomize -CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen -ENVTEST ?= $(LOCALBIN)/setup-envtest +##ToolBinaries +KUSTOMIZE?=$(LOCALBIN)/kustomize +CONTROLLER_GEN?=$(LOCALBIN)/controller-gen +ENVTEST?=$(LOCALBIN)/setup-envtest -## Tool Versions -KUSTOMIZE_VERSION ?= v3.8.7 -CONTROLLER_TOOLS_VERSION ?= v0.9.0 +##ToolVersions +KUSTOMIZE_VERSION?=v3.8.7 +CONTROLLER_TOOLS_VERSION?=v0.9.0 -KUSTOMIZE_INSTALL_SCRIPT ?= "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" -.PHONY: kustomize -kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary. -$(KUSTOMIZE): $(LOCALBIN) - test -s $(LOCALBIN)/kustomize || { curl -Ss $(KUSTOMIZE_INSTALL_SCRIPT) | bash -s -- $(subst v,,$(KUSTOMIZE_VERSION)) $(LOCALBIN); } +KUSTOMIZE_INSTALL_SCRIPT?="https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" +.PHONY:kustomize +kustomize:$(KUSTOMIZE)##Downloadkustomizelocallyifnecessary. +$(KUSTOMIZE):$(LOCALBIN) +test-s$(LOCALBIN)/kustomize||{curl-Ss$(KUSTOMIZE_INSTALL_SCRIPT)|bash-s--$(substv,,$(KUSTOMIZE_VERSION))$(LOCALBIN);} -.PHONY: controller-gen -controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary. -$(CONTROLLER_GEN): $(LOCALBIN) - test -s $(LOCALBIN)/controller-gen || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-tools/cmd/controller-gen@$(CONTROLLER_TOOLS_VERSION) +.PHONY:controller-gen +controller-gen:$(CONTROLLER_GEN)##Downloadcontroller-genlocallyifnecessary. +$(CONTROLLER_GEN):$(LOCALBIN) +test-s$(LOCALBIN)/controller-gen||GOBIN=$(LOCALBIN)goinstallsigs.k8s.io/controller-tools/cmd/controller-gen@$(CONTROLLER_TOOLS_VERSION) -.PHONY: envtest -envtest: $(ENVTEST) ## Download envtest-setup locally if necessary. -$(ENVTEST): $(LOCALBIN) - test -s $(LOCALBIN)/setup-envtest || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest +.PHONY:envtest +envtest:$(ENVTEST)##Downloadenvtest-setuplocallyifnecessary. +$(ENVTEST):$(LOCALBIN) +test-s$(LOCALBIN)/setup-envtest||GOBIN=$(LOCALBIN)goinstallsigs.k8s.io/controller-runtime/tools/setup-envtest@latest ``` -And then, to make your project use the `kustomize` version defined in the Makefile, replace all usage of `kustomize` with `$(KUSTOMIZE)` +Andthen,tomakeyourprojectusethe`kustomize`versiondefinedintheMakefile,replaceallusageof`kustomize`with`$(KUSTOMIZE)` - -#### Update your controllers +####Updateyourcontrollers - Replace: ```go -func (r *Reconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { - ctx := context.Background() - log := r.Log.WithValues("cronjob", req.NamespacedName) +func(r*Reconciler)Reconcile(reqctrl.Request)(ctrl.Result,error){ +ctx:=context.Background() +log:=r.Log.WithValues("cronjob",req.NamespacedName) ``` With: ```go -func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - log := r.Log.WithValues("cronjob", req.NamespacedName) +func(r*Reconciler)Reconcile(ctxcontext.Context,reqctrl.Request)(ctrl.Result,error){ +log:=r.Log.WithValues("cronjob",req.NamespacedName) ``` -#### Update your controller and webhook test suite +####Updateyourcontrollerandwebhooktestsuite - Replace: ```go - . "github.com/onsi/ginkgo" +."github.com/onsi/ginkgo" ``` With: ```go - . "github.com/onsi/ginkgo/v2" +."github.com/onsi/ginkgo/v2" ``` -Also, adjust your test suite. +Also,adjustyourtestsuite. -For Controller Suite: +ForControllerSuite: ```go - RunSpecsWithDefaultAndCustomReporters(t, - "Controller Suite", - []Reporter{printer.NewlineReporter{}}) +RunSpecsWithDefaultAndCustomReporters(t, +"ControllerSuite", +[]Reporter{printer.NewlineReporter{}}) ``` With: ```go - RunSpecs(t, "Controller Suite") +RunSpecs(t,"ControllerSuite") ``` -For Webhook Suite: +ForWebhookSuite: ```go - RunSpecsWithDefaultAndCustomReporters(t, - "Webhook Suite", - []Reporter{printer.NewlineReporter{}}) +RunSpecsWithDefaultAndCustomReporters(t, +"WebhookSuite", +[]Reporter{printer.NewlineReporter{}}) ``` With: ```go - RunSpecs(t, "Webhook Suite") +RunSpecs(t,"WebhookSuite") ``` -Last but not least, remove the timeout variable from the `BeforeSuite` blocks: +Lastbutnotleast,removethetimeoutvariablefromthe`BeforeSuite`blocks: Replace: ```go -var _ = BeforeSuite(func(done Done) { - .... -}, 60) +var_=BeforeSuite(func(doneDone){ +.... +},60) ``` With ```go -var _ = BeforeSuite(func(done Done) { - .... +var_=BeforeSuite(func(doneDone){ +.... }) ``` -#### Change Logger to use flag options +####ChangeLoggertouseflagoptions -In the `main.go` file replace: +Inthe`main.go`filereplace: ```go flag.Parse() @@ -607,8 +607,8 @@ ctrl.SetLogger(zap.New(zap.UseDevMode(true))) With: ```go -opts := zap.Options{ - Development: true, +opts:=zap.Options{ +Development:true, } opts.BindFlags(flag.CommandLine) flag.Parse() @@ -616,112 +616,112 @@ flag.Parse() ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) ``` -#### Rename the manager flags +####Renamethemanagerflags -The manager flags `--metrics-addr` and `enable-leader-election` were renamed to `--metrics-bind-address` and `--leader-elect` to be more aligned with core Kubernetes Components. More info: [#1839][issue-1893]. +Themanagerflags`--metrics-addr`and`enable-leader-election`wererenamedto`--metrics-bind-address`and`--leader-elect`tobemorealignedwithcoreKubernetesComponents.Moreinfo:[#1839][issue-1893]. -In your `main.go` file replace: +Inyour`main.go`filereplace: ```go -func main() { - var metricsAddr string - var enableLeaderElection bool - flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.") - flag.BoolVar(&enableLeaderElection, "enable-leader-election", false, - "Enable leader election for controller manager. "+ - "Enabling this will ensure there is only one active controller manager.") +funcmain(){ +varmetricsAddrstring +varenableLeaderElectionbool +flag.StringVar(&metricsAddr,"metrics-addr",":8080","Theaddressthemetricendpointbindsto.") +flag.BoolVar(&enableLeaderElection,"enable-leader-election",false, +"Enableleaderelectionforcontrollermanager."+ +"Enablingthiswillensurethereisonlyoneactivecontrollermanager.") ``` With: ```go -func main() { - var metricsAddr string - var enableLeaderElection bool - flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric 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.") +funcmain(){ +varmetricsAddrstring +varenableLeaderElectionbool +flag.StringVar(&metricsAddr,"metrics-bind-address",":8080","Theaddressthemetricendpointbindsto.") +flag.BoolVar(&enableLeaderElection,"leader-elect",false, +"Enableleaderelectionforcontrollermanager."+ +"Enablingthiswillensurethereisonlyoneactivecontrollermanager.") ``` -And then, rename the flags in the `config/default/manager_auth_proxy_patch.yaml` and `config/default/manager.yaml`: +Andthen,renametheflagsinthe`config/default/manager_auth_proxy_patch.yaml`and`config/default/manager.yaml`: ```yaml -- name: manager +-name:manager args: -- "--health-probe-bind-address=:8081" -- "--metrics-bind-address=127.0.0.1:8080" -- "--leader-elect" +-"--health-probe-bind-address=:8081" +-"--metrics-bind-address=127.0.0.1:8080" +-"--leader-elect" ``` -#### Verification +####Verification -Finally, we can run `make` and `make docker-build` to ensure things are working +Finally,wecanrun`make`and`makedocker-build`toensurethingsareworking fine. -## Change your project to remove the Kubernetes deprecated API versions usage +##ChangeyourprojecttoremovetheKubernetesdeprecatedAPIversionsusage - -The following steps describe a workflow to upgrade your project to remove the deprecated Kubernetes APIs: `apiextensions.k8s.io/v1beta1`, `admissionregistration.k8s.io/v1beta1`, `cert-manager.io/v1alpha2`. +ThefollowingstepsdescribeaworkflowtoupgradeyourprojecttoremovethedeprecatedKubernetesAPIs:`apiextensions.k8s.io/v1beta1`,`admissionregistration.k8s.io/v1beta1`,`cert-manager.io/v1alpha2`. -The Kubebuilder CLI tool does not support scaffolded resources for both Kubernetes API versions such as; an API/CRD with `apiextensions.k8s.io/v1beta1` and another one with `apiextensions.k8s.io/v1`. +TheKubebuilderCLItooldoesnotsupportscaffoldedresourcesforbothKubernetesAPIversionssuchas;anAPI/CRDwith`apiextensions.k8s.io/v1beta1`andanotheronewith`apiextensions.k8s.io/v1`. - -The first step is to update your `PROJECT` file by replacing the `api.crdVersion:v1beta` and `webhooks.WebhookVersion:v1beta` with `api.crdVersion:v1` and `webhooks.WebhookVersion:v1` which would look like: +Thefirststepistoupdateyour`PROJECT`filebyreplacingthe`api.crdVersion:v1beta`and`webhooks.WebhookVersion:v1beta`with`api.crdVersion:v1`and`webhooks.WebhookVersion:v1`whichwouldlooklike: ```yaml -domain: my.domain -layout: go.kubebuilder.io/v3 -projectName: example -repo: example +domain:my.domain +layout:go.kubebuilder.io/v3 +projectName:example +repo:example resources: -- api: - crdVersion: v1 - namespaced: true - group: webapp - kind: Guestbook - version: v1 - webhooks: - defaulting: true - webhookVersion: v1 -version: "3" +-api: +crdVersion:v1 +namespaced:true +group:webapp +kind:Guestbook +version:v1 +webhooks: +defaulting:true +webhookVersion:v1 +version:"3" ``` -You can try to re-create the APIS(CRDs) and Webhooks manifests by using the `--force` flag. +Youcantrytore-createtheAPIS(CRDs)andWebhooksmanifestsbyusingthe`--force`flag. - -Now, re-create the APIS(CRDs) and Webhooks manifests by running the `kubebuilder create api` and `kubebuilder create webhook` for the same group, kind and versions with the flag `--force`, respectively. +Now,re-createtheAPIS(CRDs)andWebhooksmanifestsbyrunningthe`kubebuildercreateapi`and`kubebuildercreatewebhook`forthesamegroup,kindandversionswiththeflag`--force`,respectively. -[migration-guide-v2-to-v3]: migration_guide_v2tov3.md -[envtest]: https://book.kubebuilder.io/reference/testing/envtest.html -[controller-releases]: https://github.com/kubernetes-sigs/controller-runtime/releases -[issue-1893]: https://github.com/kubernetes-sigs/kubebuilder/issues/1839 -[plugins-doc]: /reference/cli-plugins.md -[migration-v2vsv3]: /migration/v2vsv3.md -[custom-resource-definition-versioning]: https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definition-versioning/ -[issue-1999]: https://github.com/kubernetes-sigs/kubebuilder/issues/1999 -[project-customizations]: v2vsv3.md#project-customizations +[migration-guide-v2-to-v3]:migration_guide_v2tov3.md +[envtest]:https://book.kubebuilder.io/reference/testing/envtest.html +[controller-releases]:https://github.com/kubernetes-sigs/controller-runtime/releases +[issue-1893]:https://github.com/kubernetes-sigs/kubebuilder/issues/1839 +[plugins-doc]:/reference/cli-plugins.md +[migration-v2vsv3]:/migration/v2vsv3.md +[custom-resource-definition-versioning]:https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definition-versioning/ +[issue-1999]:https://github.com/kubernetes-sigs/kubebuilder/issues/1999 +[project-customizations]:v2vsv3.md#project-customizations [doc-envtest]:/reference/envtest.md diff --git a/docs/book/src/migration/legacy/migration_guide_v1tov2.md b/docs/book/src/migration/legacy/migration_guide_v1tov2.md index d267b9c2697..3e43d6da86a 100644 --- a/docs/book/src/migration/legacy/migration_guide_v1tov2.md +++ b/docs/book/src/migration/legacy/migration_guide_v1tov2.md @@ -1,219 +1,219 @@ -# Migration from v1 to v2 +#Migrationfromv1tov2 -Make sure you understand the [differences between Kubebuilder v1 and v2](./v1vsv2.md) -before continuing +Makesureyouunderstandthe[differencesbetweenKubebuilderv1andv2](./v1vsv2.md) +beforecontinuing -Please ensure you have followed the [installation guide](/quick-start.md#installation) -to install the required components. +Pleaseensureyouhavefollowedthe[installationguide](/quick-start.md#installation) +toinstalltherequiredcomponents. -The recommended way to migrate a v1 project is to create a new v2 project and -copy over the API and the reconciliation code. The conversion will end up with a -project that looks like a native v2 project. However, in some cases, it's -possible to do an in-place upgrade (i.e. reuse the v1 project layout, upgrading -controller-runtime and controller-tools. +Therecommendedwaytomigrateav1projectistocreateanewv2projectand +copyovertheAPIandthereconciliationcode.Theconversionwillendupwitha +projectthatlookslikeanativev2project.However,insomecases,it's +possibletodoanin-placeupgrade(i.e.reusethev1projectlayout,upgrading +controller-runtimeandcontroller-tools. -Let's take as example an V1 project and migrate it to Kubebuilder -v2. At the end, we should have something that looks like the -[example v2 project][v2-project]. +Let'stakeasexampleanV1projectandmigrateittoKubebuilder +v2.Attheend,weshouldhavesomethingthatlookslikethe +[examplev2project][v2-project]. -## Preparation +##Preparation -We'll need to figure out what the group, version, kind and domain are. +We'llneedtofigureoutwhatthegroup,version,kindanddomainare. -Let's take a look at our current v1 project structure: +Let'stakealookatourcurrentv1projectstructure: ``` pkg/ -├── apis -│   ├── addtoscheme_batch_v1.go -│   ├── apis.go -│   └── batch -│   ├── group.go -│   └── v1 -│   ├── cronjob_types.go -│   ├── cronjob_types_test.go -│   ├── doc.go -│   ├── register.go -│   ├── v1_suite_test.go -│   └── zz_generated.deepcopy.go -├── controller -└── webhook +├──apis +│├──addtoscheme_batch_v1.go +│├──apis.go +│└──batch +│├──group.go +│└──v1 +│├──cronjob_types.go +│├──cronjob_types_test.go +│├──doc.go +│├──register.go +│├──v1_suite_test.go +│└──zz_generated.deepcopy.go +├──controller +└──webhook ``` -All of our API information is stored in `pkg/apis/batch`, so we can look -there to find what we need to know. +AllofourAPIinformationisstoredin`pkg/apis/batch`,sowecanlook +theretofindwhatweneedtoknow. -In `cronjob_types.go`, we can find +In`cronjob_types.go`,wecanfind ```go -type CronJob struct {...} +typeCronJobstruct{...} ``` -In `register.go`, we can find +In`register.go`,wecanfind ```go -SchemeGroupVersion = schema.GroupVersion{Group: "batch.tutorial.kubebuilder.io", Version: "v1"} +SchemeGroupVersion=schema.GroupVersion{Group:"batch.tutorial.kubebuilder.io",Version:"v1"} ``` -Putting that together, we get `CronJob` as the kind, and `batch.tutorial.kubebuilder.io/v1` as the group-version +Puttingthattogether,weget`CronJob`asthekind,and`batch.tutorial.kubebuilder.io/v1`asthegroup-version -## Initialize a v2 Project +##Initializeav2Project -Now, we need to initialize a v2 project. Before we do that, though, we'll need -to initialize a new go module if we're not on the `gopath`: +Now,weneedtoinitializeav2project.Beforewedothat,though,we'llneed +toinitializeanewgomoduleifwe'renotonthe`gopath`: ```bash -go mod init tutorial.kubebuilder.io/project +gomodinittutorial.kubebuilder.io/project ``` -Then, we can finish initializing the project with kubebuilder: +Then,wecanfinishinitializingtheprojectwithkubebuilder: ```bash -kubebuilder init --domain tutorial.kubebuilder.io +kubebuilderinit--domaintutorial.kubebuilder.io ``` -## Migrate APIs and Controllers +##MigrateAPIsandControllers -Next, we'll re-scaffold out the API types and controllers. Since we want both, -we'll say yes to both the API and controller prompts when asked what parts we -want to scaffold: +Next,we'llre-scaffoldouttheAPItypesandcontrollers.Sincewewantboth, +we'llsayyestoboththeAPIandcontrollerpromptswhenaskedwhatpartswe +wanttoscaffold: ```bash -kubebuilder create api --group batch --version v1 --kind CronJob +kubebuildercreateapi--groupbatch--versionv1--kindCronJob ``` -If you're using multiple groups, some manual work is required to migrate. -Please follow [this](/migration/multi-group.md) for more details. +Ifyou'reusingmultiplegroups,somemanualworkisrequiredtomigrate. +Pleasefollow[this](/migration/multi-group.md)formoredetails. -### Migrate the APIs +###MigratetheAPIs -Now, let's copy the API definition from `pkg/apis/batch/v1/cronjob_types.go` to -`api/v1/cronjob_types.go`. We only need to copy the implementation of the `Spec` -and `Status` fields. +Now,let'scopytheAPIdefinitionfrom`pkg/apis/batch/v1/cronjob_types.go`to +`api/v1/cronjob_types.go`.Weonlyneedtocopytheimplementationofthe`Spec` +and`Status`fields. -We can replace the `+k8s:deepcopy-gen:interfaces=...` marker (which is -[deprecated in kubebuilder](/reference/markers/object.md)) with +Wecanreplacethe`+k8s:deepcopy-gen:interfaces=...`marker(whichis +[deprecatedinkubebuilder](/reference/markers/object.md))with `+kubebuilder:object:root=true`. -We don't need the following markers any more (they're not used anymore, and are -relics from much older versions of Kubebuilder): +Wedon'tneedthefollowingmarkersanymore(they'renotusedanymore,andare +relicsfrommucholderversionsofKubebuilder): ```go -// +genclient -// +k8s:openapi-gen=true +//+genclient +//+k8s:openapi-gen=true ``` -Our API types should look like the following: +OurAPItypesshouldlooklikethefollowing: ```go -// +kubebuilder:object:root=true -// +kubebuilder:subresource:status -// CronJob is the Schema for the cronjobs API -type CronJob struct {...} +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status +//CronJobistheSchemaforthecronjobsAPI +typeCronJobstruct{...} -// +kubebuilder:object:root=true +//+kubebuilder:object:root=true -// CronJobList contains a list of CronJob -type CronJobList struct {...} +//CronJobListcontainsalistofCronJob +typeCronJobListstruct{...} ``` -### Migrate the Controllers +###MigratetheControllers -Now, let's migrate the controller reconciler code from -`pkg/controller/cronjob/cronjob_controller.go` to +Now,let'smigratethecontrollerreconcilercodefrom +`pkg/controller/cronjob/cronjob_controller.go`to `controllers/cronjob_controller.go`. -We'll need to copy -- the fields from the `ReconcileCronJob` struct to `CronJobReconciler` -- the contents of the `Reconcile` function -- the [rbac related markers](/reference/markers/rbac.md) to the new file. -- the code under `func add(mgr manager.Manager, r reconcile.Reconciler) error` -to `func SetupWithManager` +We'llneedtocopy +-thefieldsfromthe`ReconcileCronJob`structto`CronJobReconciler` +-thecontentsofthe`Reconcile`function +-the[rbacrelatedmarkers](/reference/markers/rbac.md)tothenewfile. +-thecodeunder`funcadd(mgrmanager.Manager,rreconcile.Reconciler)error` +to`funcSetupWithManager` -## Migrate the Webhooks +##MigratetheWebhooks -If you don't have a webhook, you can skip this section. +Ifyoudon'thaveawebhook,youcanskipthissection. -### Webhooks for Core Types and External CRDs +###WebhooksforCoreTypesandExternalCRDs -If you are using webhooks for Kubernetes core types (e.g. Pods), or for an -external CRD that is not owned by you, you can refer the -[controller-runtime example for builtin types][builtin-type-example] -and do something similar. Kubebuilder doesn't scaffold much for these cases, but -you can use the library in controller-runtime. +IfyouareusingwebhooksforKubernetescoretypes(e.g.Pods),orforan +externalCRDthatisnotownedbyyou,youcanreferthe +[controller-runtimeexampleforbuiltintypes][builtin-type-example] +anddosomethingsimilar.Kubebuilderdoesn'tscaffoldmuchforthesecases,but +youcanusethelibraryincontroller-runtime. -### Scaffold Webhooks for our CRDs +###ScaffoldWebhooksforourCRDs -Now let's scaffold the webhooks for our CRD (CronJob). We'll need to run the -following command with the `--defaulting` and `--programmatic-validation` flags -(since our test project uses defaulting and validating webhooks): +Nowlet'sscaffoldthewebhooksforourCRD(CronJob).We'llneedtorunthe +followingcommandwiththe`--defaulting`and`--programmatic-validation`flags +(sinceourtestprojectusesdefaultingandvalidatingwebhooks): ```bash -kubebuilder create webhook --group batch --version v1 --kind CronJob --defaulting --programmatic-validation +kubebuildercreatewebhook--groupbatch--versionv1--kindCronJob--defaulting--programmatic-validation ``` -Depending on how many CRDs need webhooks, we may need to run the above command -multiple times with different Group-Version-Kinds. +DependingonhowmanyCRDsneedwebhooks,wemayneedtoruntheabovecommand +multipletimeswithdifferentGroup-Version-Kinds. -Now, we'll need to copy the logic for each webhook. For validating webhooks, we -can copy the contents from -`func validatingCronJobFn` in `pkg/default_server/cronjob/validating/cronjob_create_handler.go` -to `func ValidateCreate` in `api/v1/cronjob_webhook.go` and then the same for `update`. +Now,we'llneedtocopythelogicforeachwebhook.Forvalidatingwebhooks,we +cancopythecontentsfrom +`funcvalidatingCronJobFn`in`pkg/default_server/cronjob/validating/cronjob_create_handler.go` +to`funcValidateCreate`in`api/v1/cronjob_webhook.go`andthenthesamefor`update`. -Similarly, we'll copy from `func mutatingCronJobFn` to `func Default`. +Similarly,we'llcopyfrom`funcmutatingCronJobFn`to`funcDefault`. -### Webhook Markers +###WebhookMarkers -When scaffolding webhooks, Kubebuilder v2 adds the following markers: +Whenscaffoldingwebhooks,Kubebuilderv2addsthefollowingmarkers: ``` -// These are v2 markers +//Thesearev2markers -// This is for the mutating webhook -// +kubebuilder:webhook:path=/mutate-batch-tutorial-kubebuilder-io-v1-cronjob,mutating=true,failurePolicy=fail,groups=batch.tutorial.kubebuilder.io,resources=cronjobs,verbs=create;update,versions=v1,name=mcronjob.kb.io +//Thisisforthemutatingwebhook +//+kubebuilder:webhook:path=/mutate-batch-tutorial-kubebuilder-io-v1-cronjob,mutating=true,failurePolicy=fail,groups=batch.tutorial.kubebuilder.io,resources=cronjobs,verbs=create;update,versions=v1,name=mcronjob.kb.io ... -// This is for the validating webhook -// +kubebuilder:webhook:path=/validate-batch-tutorial-kubebuilder-io-v1-cronjob,mutating=false,failurePolicy=fail,groups=batch.tutorial.kubebuilder.io,resources=cronjobs,verbs=create;update,versions=v1,name=vcronjob.kb.io +//Thisisforthevalidatingwebhook +//+kubebuilder:webhook:path=/validate-batch-tutorial-kubebuilder-io-v1-cronjob,mutating=false,failurePolicy=fail,groups=batch.tutorial.kubebuilder.io,resources=cronjobs,verbs=create;update,versions=v1,name=vcronjob.kb.io ``` -The default verbs are `verbs=create;update`. We need to ensure `verbs` matches -what we need. For example, if we only want to validate creation, then we would -change it to `verbs=create`. +Thedefaultverbsare`verbs=create;update`.Weneedtoensure`verbs`matches +whatweneed.Forexample,ifweonlywanttovalidatecreation,thenwewould +changeitto`verbs=create`. -We also need to ensure `failure-policy` is still the same. +Wealsoneedtoensure`failure-policy`isstillthesame. -Markers like the following are no longer needed (since they deal with -self-deploying certificate configuration, which was removed in v2): +Markerslikethefollowingarenolongerneeded(sincetheydealwith +self-deployingcertificateconfiguration,whichwasremovedinv2): ```go -// v1 markers -// +kubebuilder:webhook:port=9876,cert-dir=/tmp/cert -// +kubebuilder:webhook:service=test-system:webhook-service,selector=app:webhook-server -// +kubebuilder:webhook:secret=test-system:webhook-server-secret -// +kubebuilder:webhook:mutating-webhook-config-name=test-mutating-webhook-cfg -// +kubebuilder:webhook:validating-webhook-config-name=test-validating-webhook-cfg +//v1markers +//+kubebuilder:webhook:port=9876,cert-dir=/tmp/cert +//+kubebuilder:webhook:service=test-system:webhook-service,selector=app:webhook-server +//+kubebuilder:webhook:secret=test-system:webhook-server-secret +//+kubebuilder:webhook:mutating-webhook-config-name=test-mutating-webhook-cfg +//+kubebuilder:webhook:validating-webhook-config-name=test-validating-webhook-cfg ``` -In v1, a single webhook marker may be split into multiple ones in the same -paragraph. In v2, each webhook must be represented by a single marker. +Inv1,asinglewebhookmarkermaybesplitintomultipleonesinthesame +paragraph.Inv2,eachwebhookmustberepresentedbyasinglemarker. -## Others +##Others -If there are any manual updates in `main.go` in v1, we need to port the changes -to the new `main.go`. We'll also need to ensure all of the needed schemes have -been registered. +Ifthereareanymanualupdatesin`main.go`inv1,weneedtoportthechanges +tothenew`main.go`.We'llalsoneedtoensurealloftheneededschemeshave +beenregistered. -If there are additional manifests added under `config` directory, port them as +Ifthereareadditionalmanifestsaddedunder`config`directory,portthemas well. -Change the image name in the Makefile if needed. +ChangetheimagenameintheMakefileifneeded. -## Verification +##Verification -Finally, we can run `make` and `make docker-build` to ensure things are working +Finally,wecanrun`make`and`makedocker-build`toensurethingsareworking fine. -[v2-project]: https://github.com/kubernetes-sigs/kubebuilder/tree/master/docs/book/src/cronjob-tutorial/testdata/project -[builtin-type-example]: https://sigs.k8s.io/controller-runtime/examples/builtins +[v2-project]:https://github.com/kubernetes-sigs/kubebuilder/tree/master/docs/book/src/cronjob-tutorial/testdata/project +[builtin-type-example]:https://sigs.k8s.io/controller-runtime/examples/builtins diff --git a/docs/book/src/migration/legacy/migration_guide_v2tov3.md b/docs/book/src/migration/legacy/migration_guide_v2tov3.md index 6ebd1e04203..0720d9a010b 100644 --- a/docs/book/src/migration/legacy/migration_guide_v2tov3.md +++ b/docs/book/src/migration/legacy/migration_guide_v2tov3.md @@ -1,180 +1,180 @@ -# Migration from v2 to v3 +#Migrationfromv2tov3 -Make sure you understand the [differences between Kubebuilder v2 and v3][v2vsv3] -before continuing. +Makesureyouunderstandthe[differencesbetweenKubebuilderv2andv3][v2vsv3] +beforecontinuing. -Please ensure you have followed the [installation guide][quick-start] -to install the required components. +Pleaseensureyouhavefollowedthe[installationguide][quick-start] +toinstalltherequiredcomponents. -The recommended way to migrate a v2 project is to create a new v3 project and -copy over the API and the reconciliation code. The conversion will end up with a -project that looks like a native v3 project. However, in some cases, it's -possible to do an in-place upgrade (i.e. reuse the v2 project layout, upgrading -[controller-runtime][controller-runtime] and [controller-tools][controller-tools]). +Therecommendedwaytomigrateav2projectistocreateanewv3projectand +copyovertheAPIandthereconciliationcode.Theconversionwillendupwitha +projectthatlookslikeanativev3project.However,insomecases,it's +possibletodoanin-placeupgrade(i.e.reusethev2projectlayout,upgrading +[controller-runtime][controller-runtime]and[controller-tools][controller-tools]). -## Initialize a v3 Project +##Initializeav3Project - -Create a new directory with the name of your project. Note that -this name is used in the scaffolds to create the name of your manager Pod and of the Namespace where the Manager is deployed by default. +Createanewdirectorywiththenameofyourproject.Notethat +thisnameisusedinthescaffoldstocreatethenameofyourmanagerPodandoftheNamespacewheretheManagerisdeployedbydefault. ```bash -$ mkdir migration-project-name -$ cd migration-project-name +$mkdirmigration-project-name +$cdmigration-project-name ``` -Now, we need to initialize a v3 project. Before we do that, though, we'll need -to initialize a new go module if we're not on the `GOPATH`. While technically this is -not needed inside `GOPATH`, it is still recommended. +Now,weneedtoinitializeav3project.Beforewedothat,though,we'llneed +toinitializeanewgomoduleifwe'renotonthe`GOPATH`.Whiletechnicallythisis +notneededinside`GOPATH`,itisstillrecommended. ```bash -go mod init tutorial.kubebuilder.io/migration-project +gomodinittutorial.kubebuilder.io/migration-project ``` - -Then, we can finish initializing the project with kubebuilder. +Then,wecanfinishinitializingtheprojectwithkubebuilder. ```bash -kubebuilder init --domain tutorial.kubebuilder.io +kubebuilderinit--domaintutorial.kubebuilder.io ``` - -## Migrate APIs and Controllers +##MigrateAPIsandControllers -Next, we'll re-scaffold out the API types and controllers. +Next,we'llre-scaffoldouttheAPItypesandcontrollers. - ```bash -kubebuilder create api --group batch --version v1 --kind CronJob +kubebuildercreateapi--groupbatch--versionv1--kindCronJob ``` - -### Migrate the APIs +###MigratetheAPIs - -Now, let's copy the API definition from `api/v1/_types.go` in our old project to the new one. +Now,let'scopytheAPIdefinitionfrom`api/v1/_types.go`inouroldprojecttothenewone. -These files have not been modified by the new plugin, so you should be able to replace your freshly scaffolded files by your old one. There may be some cosmetic changes. So you can choose to only copy the types themselves. +Thesefileshavenotbeenmodifiedbythenewplugin,soyoushouldbeabletoreplaceyourfreshlyscaffoldedfilesbyyouroldone.Theremaybesomecosmeticchanges.Soyoucanchoosetoonlycopythetypesthemselves. -### Migrate the Controllers +###MigratetheControllers -Now, let's migrate the controller code from `controllers/cronjob_controller.go` in our old project to the new one. There is a breaking change and there may be some cosmetic changes. +Now,let'smigratethecontrollercodefrom`controllers/cronjob_controller.go`inouroldprojecttothenewone.Thereisabreakingchangeandtheremaybesomecosmeticchanges. -The new `Reconcile` method receives the context as an argument now, instead of having to create it with `context.Background()`. You can copy the rest of the code in your old controller to the scaffolded methods replacing: +Thenew`Reconcile`methodreceivesthecontextasanargumentnow,insteadofhavingtocreateitwith`context.Background()`.Youcancopytherestofthecodeinyouroldcontrollertothescaffoldedmethodsreplacing: -```go -func (r *CronJobReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { - ctx := context.Background() - log := r.Log.WithValues("cronjob", req.NamespacedName) +```go +func(r*CronJobReconciler)Reconcile(reqctrl.Request)(ctrl.Result,error){ +ctx:=context.Background() +log:=r.Log.WithValues("cronjob",req.NamespacedName) ``` With: -```go -func (r *CronJobReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - log := r.Log.WithValues("cronjob", req.NamespacedName) +```go +func(r*CronJobReconciler)Reconcile(ctxcontext.Context,reqctrl.Request)(ctrl.Result,error){ +log:=r.Log.WithValues("cronjob",req.NamespacedName) ``` - -## Migrate the Webhooks +##MigratetheWebhooks - -Now let's scaffold the webhooks for our CRD (CronJob). We'll need to run the -following command with the `--defaulting` and `--programmatic-validation` flags -(since our test project uses defaulting and validating webhooks): +Nowlet'sscaffoldthewebhooksforourCRD(CronJob).We'llneedtorunthe +followingcommandwiththe`--defaulting`and`--programmatic-validation`flags +(sinceourtestprojectusesdefaultingandvalidatingwebhooks): ```bash -kubebuilder create webhook --group batch --version v1 --kind CronJob --defaulting --programmatic-validation +kubebuildercreatewebhook--groupbatch--versionv1--kindCronJob--defaulting--programmatic-validation ``` - -Now, let's copy the webhook definition from `api/v1/_webhook.go` from our old project to the new one. +Now,let'scopythewebhookdefinitionfrom`api/v1/_webhook.go`fromouroldprojecttothenewone. -## Others +##Others -If there are any manual updates in `main.go` in v2, we need to port the changes to the new `main.go`. We’ll also need to ensure all of the needed schemes have been registered. +Ifthereareanymanualupdatesin`main.go`inv2,weneedtoportthechangestothenew`main.go`.We’llalsoneedtoensurealloftheneededschemeshavebeenregistered. -If there are additional manifests added under config directory, port them as well. +Ifthereareadditionalmanifestsaddedunderconfigdirectory,portthemaswell. -Change the image name in the Makefile if needed. +ChangetheimagenameintheMakefileifneeded. -## Verification +##Verification -Finally, we can run `make` and `make docker-build` to ensure things are working +Finally,wecanrun`make`and`makedocker-build`toensurethingsareworking fine. -[v2vsv3]: v2vsv3.md -[quick-start]: /quick-start.md#installation -[controller-tools]: https://github.com/kubernetes-sigs/controller-tools/releases -[controller-runtime]: https://github.com/kubernetes-sigs/controller-runtime/releases -[multi-group]: /migration/multi-group.md \ No newline at end of file +[v2vsv3]:v2vsv3.md +[quick-start]:/quick-start.md#installation +[controller-tools]:https://github.com/kubernetes-sigs/controller-tools/releases +[controller-runtime]:https://github.com/kubernetes-sigs/controller-runtime/releases +[multi-group]:/migration/multi-group.md \ No newline at end of file diff --git a/docs/book/src/migration/legacy/v1vsv2.md b/docs/book/src/migration/legacy/v1vsv2.md index 993a29845a3..328f1348872 100644 --- a/docs/book/src/migration/legacy/v1vsv2.md +++ b/docs/book/src/migration/legacy/v1vsv2.md @@ -1,65 +1,65 @@ -# Kubebuilder v1 vs v2 (Legacy v1.0.0+ to v2.0.0 Kubebuilder CLI versions) +#Kubebuilderv1vsv2(Legacyv1.0.0+tov2.0.0KubebuilderCLIversions) -This document cover all breaking changes when migrating from v1 to v2. +Thisdocumentcoverallbreakingchangeswhenmigratingfromv1tov2. -The details of all changes (breaking or otherwise) can be found in +Thedetailsofallchanges(breakingorotherwise)canbefoundin [controller-runtime](https://github.com/kubernetes-sigs/controller-runtime/releases), [controller-tools](https://github.com/kubernetes-sigs/controller-tools/releases) -and [kubebuilder](https://github.com/kubernetes-sigs/kubebuilder/releases) -release notes. +and[kubebuilder](https://github.com/kubernetes-sigs/kubebuilder/releases) +releasenotes. -## Common changes +##Commonchanges -V2 project uses go modules. But kubebuilder will continue to support `dep` until -go 1.13 is out. +V2projectusesgomodules.Butkubebuilderwillcontinuetosupport`dep`until +go1.13isout. -## controller-runtime +##controller-runtime -- `Client.List` now uses functional options (`List(ctx, list, ...option)`) instead -of `List(ctx, ListOptions, list)`. -- `Client.DeleteAllOf` was added to the `Client` interface. +-`Client.List`nowusesfunctionaloptions(`List(ctx,list,...option)`)instead +of`List(ctx,ListOptions,list)`. +-`Client.DeleteAllOf`wasaddedtothe`Client`interface. -- Metrics are on by default now. +-Metricsareonbydefaultnow. -- A number of packages under `pkg/runtime` have been moved, with their old -locations deprecated. The old locations will be removed before -controller-runtime v1.0.0. See the [godocs][pkg-runtime-godoc] for more +-Anumberofpackagesunder`pkg/runtime`havebeenmoved,withtheirold +locationsdeprecated.Theoldlocationswillberemovedbefore +controller-runtimev1.0.0.Seethe[godocs][pkg-runtime-godoc]formore information. -#### Webhook-related +####Webhook-related -- Automatic certificate generation for webhooks has been removed, and webhooks -will no longer self-register. Use controller-tools to generate a webhook -configuration. If you need certificate generation, we recommend using -[cert-manager](https://github.com/cert-manager/cert-manager). Kubebuilder v2 will -scaffold out cert manager configs for you to use -- see the -[Webhook Tutorial](/cronjob-tutorial/webhook-implementation.md) for more details. +-Automaticcertificategenerationforwebhookshasbeenremoved,andwebhooks +willnolongerself-register.Usecontroller-toolstogenerateawebhook +configuration.Ifyouneedcertificategeneration,werecommendusing +[cert-manager](https://github.com/cert-manager/cert-manager).Kubebuilderv2will +scaffoldoutcertmanagerconfigsforyoutouse--seethe +[WebhookTutorial](/cronjob-tutorial/webhook-implementation.md)formoredetails. -- The `builder` package now has separate builders for controllers and webhooks, -which facilitates choosing which to run. +-The`builder`packagenowhasseparatebuildersforcontrollersandwebhooks, +whichfacilitateschoosingwhichtorun. -## controller-tools +##controller-tools -The generator framework has been rewritten in v2. It still works the same as -before in many cases, but be aware that there are some breaking changes. -Please check [marker documentation](/reference/markers.md) for more details. +Thegeneratorframeworkhasbeenrewritteninv2.Itstillworksthesameas +beforeinmanycases,butbeawarethattherearesomebreakingchanges. +Pleasecheck[markerdocumentation](/reference/markers.md)formoredetails. -## Kubebuilder +##Kubebuilder -- Kubebuilder v2 introduces a simplified project layout. You can find the design -doc [here](https://github.com/kubernetes-sigs/kubebuilder/blob/master/designs/simplified-scaffolding.md). +-Kubebuilderv2introducesasimplifiedprojectlayout.Youcanfindthedesign +doc[here](https://github.com/kubernetes-sigs/kubebuilder/blob/master/designs/simplified-scaffolding.md). -- In v1, the manager is deployed as a `StatefulSet`, while it's deployed as a -`Deployment` in v2. +-Inv1,themanagerisdeployedasa`StatefulSet`,whileit'sdeployedasa +`Deployment`inv2. -- The `kubebuilder create webhook` command was added to scaffold -mutating/validating/conversion webhooks. It replaces the -`kubebuilder alpha webhook` command. +-The`kubebuildercreatewebhook`commandwasaddedtoscaffold +mutating/validating/conversionwebhooks.Itreplacesthe +`kubebuilderalphawebhook`command. -- v2 uses `distroless/static` instead of Ubuntu as base image. This reduces -image size and attack surface. +-v2uses`distroless/static`insteadofUbuntuasbaseimage.Thisreduces +imagesizeandattacksurface. -- v2 requires kustomize v3.1.0+. +-v2requireskustomizev3.1.0+. -[LeaderElectionRunable]: https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/manager?tab=doc#LeaderElectionRunnable -[pkg-runtime-godoc]: https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/runtime?tab=doc +[LeaderElectionRunable]:https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/manager?tab=doc#LeaderElectionRunnable +[pkg-runtime-godoc]:https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/runtime?tab=doc diff --git a/docs/book/src/migration/legacy/v2vsv3.md b/docs/book/src/migration/legacy/v2vsv3.md index 75ec754932f..4524033b069 100644 --- a/docs/book/src/migration/legacy/v2vsv3.md +++ b/docs/book/src/migration/legacy/v2vsv3.md @@ -1,108 +1,108 @@ -# Kubebuilder v2 vs v3 (Legacy Kubebuilder v2.0.0+ layout to 3.0.0+) +#Kubebuilderv2vsv3(LegacyKubebuilderv2.0.0+layoutto3.0.0+) -This document covers all breaking changes when migrating from v2 to v3. +Thisdocumentcoversallbreakingchangeswhenmigratingfromv2tov3. -The details of all changes (breaking or otherwise) can be found in +Thedetailsofallchanges(breakingorotherwise)canbefoundin [controller-runtime][controller-runtime], [controller-tools][controller-tools] -and [kb-releases][kb-releases] release notes. +and[kb-releases][kb-releases]releasenotes. -## Common changes +##Commonchanges -v3 projects use Go modules and request Go 1.18+. Dep is no longer supported for dependency management. +v3projectsuseGomodulesandrequestGo1.18+.Depisnolongersupportedfordependencymanagement. -## Kubebuilder +##Kubebuilder -- Preliminary support for plugins was added. For more info see the [Extensible CLI and Scaffolding Plugins: phase 1][plugins-phase1-design-doc], - the [Extensible CLI and Scaffolding Plugins: phase 1.5][plugins-phase1-design-doc-1.5] and the [Extensible CLI and Scaffolding Plugins - Phase 2][plugins-phase2-design-doc] - design docs. Also, you can check the [Plugins section][plugins-section]. +-Preliminarysupportforpluginswasadded.Formoreinfoseethe[ExtensibleCLIandScaffoldingPlugins:phase1][plugins-phase1-design-doc], +the[ExtensibleCLIandScaffoldingPlugins:phase1.5][plugins-phase1-design-doc-1.5]andthe[ExtensibleCLIandScaffoldingPlugins-Phase2][plugins-phase2-design-doc] +designdocs.Also,youcancheckthe[Pluginssection][plugins-section]. -- The `PROJECT` file now has a new layout. It stores more information about what resources are in use, to better enable plugins to make useful decisions when scaffolding. - - Furthermore, the PROJECT file itself is now versioned: the `version` field corresponds to the version of the PROJECT file itself, while the `layout` field indicates the scaffolding & primary plugin version in use. - -- The version of the image `gcr.io/kubebuilder/kube-rbac-proxy`, which is an optional component enabled by default to secure the request made against the manager, was updated from `0.5.0` to `0.11.0` to address security concerns. The details of all changes can be found in [kube-rbac-proxy][kube-rbac-proxy]. - -## TL;DR of the New `go/v3` Plugin +-The`PROJECT`filenowhasanewlayout.Itstoresmoreinformationaboutwhatresourcesareinuse,tobetterenablepluginstomakeusefuldecisionswhenscaffolding. -***More details on this can be found at [here][kb-releases], but for the highlights, check below*** +Furthermore,thePROJECTfileitselfisnowversioned:the`version`fieldcorrespondstotheversionofthePROJECTfileitself,whilethe`layout`fieldindicatesthescaffolding&primarypluginversioninuse. - -- Scaffolded/Generated API version changes: - * Use `apiextensions/v1` for generated CRDs (`apiextensions/v1beta1` was deprecated in Kubernetes `1.16`) - * Use `admissionregistration.k8s.io/v1` for generated webhooks (`admissionregistration.k8s.io/v1beta1` was deprecated in Kubernetes `1.16`) - * Use `cert-manager.io/v1` for the certificate manager when webhooks are used (`cert-manager.io/v1alpha2` was deprecated in `Cert-Manager 0.14`. More info: [CertManager v1.0 docs][cert-manager-docs]) - -- Code changes: - * The manager flags `--metrics-addr` and `enable-leader-election` now are named `--metrics-bind-address` and `--leader-elect` to be more aligned with core Kubernetes Components. More info: [#1839][issue-1893] - * Liveness and Readiness probes are now added by default using [`healthz.Ping`][healthz-ping]. - * A new option to create the projects using ComponentConfig is introduced. For more info see its [enhancement proposal][enhancement proposal] and the [Component config tutorial][component-config-tutorial] - * Manager manifests now use `SecurityContext` to address security concerns. More info: [#1637][issue-1637] -- Misc: - * Support for [controller-tools][controller-tools] `v0.9.0` (for `go/v2` it is `v0.3.0` and previously it was `v0.2.5`) - * Support for [controller-runtime][controller-runtime] `v0.12.1` (for `go/v2` it is `v0.6.4` and previously it was `v0.5.0`) - * Support for [kustomize][kustomize] `v3.8.7` (for `go/v2` it is `v3.5.4` and previously it was `v3.1.0`) - * Required Envtest binaries are automatically downloaded - * The minimum Go version is now `1.18` (previously it was `1.13`). - - - -## Migrating to Kubebuilder v3 -So you want to upgrade your scaffolding to use the latest and greatest features then, follow up the following guide which will cover the steps in the most straightforward way to allow you to upgrade your project to get all latest changes and improvements. +##MigratingtoKubebuilderv3 + +Soyouwanttoupgradeyourscaffoldingtousethelatestandgreatestfeaturesthen,followupthefollowingguidewhichwillcoverthestepsinthemoststraightforwardwaytoallowyoutoupgradeyourprojecttogetalllatestchangesandimprovements. - -- [Migration Guide v2 to V3][migration-guide-v2-to-v3] **(Recommended)** - -### By updating the files manually - -So you want to use the latest version of Kubebuilder CLI without changing your scaffolding then, check the following guide which will describe the manually steps required for you to upgrade only your PROJECT version and starts to use the plugins versions. - -This way is more complex, susceptible to errors, and success cannot be assured. Also, by following these steps you will not get the improvements and bug fixes in the default generated project files. - -You will check that you can still using the previous layout by using the `go/v2` plugin which will not upgrade the [controller-runtime][controller-runtime] and [controller-tools][controller-tools] to the latest version used with `go/v3` becuase of its breaking changes. By checking this guide you know also how to manually change the files to use the `go/v3` plugin and its dependencies versions. - -- [Migrating to Kubebuilder v3 by updating the files manually][manually-upgrade] - -[plugins-phase1-design-doc]: https://github.com/kubernetes-sigs/kubebuilder/blob/master/designs/extensible-cli-and-scaffolding-plugins-phase-1.md -[plugins-phase1-design-doc-1.5]: https://github.com/kubernetes-sigs/kubebuilder/blob/master/designs/extensible-cli-and-scaffolding-plugins-phase-1-5.md -[plugins-phase2-design-doc]: https://github.com/kubernetes-sigs/kubebuilder/blob/master/designs/extensible-cli-and-scaffolding-plugins-phase-2.md -[plugins-section]: ./../../plugins/plugins.md -[manually-upgrade]: manually_migration_guide_v2_v3.md -[component-config-tutorial]: ../../component-config-tutorial/tutorial.md -[issue-1893]: https://github.com/kubernetes-sigs/kubebuilder/issues/1839 -[migration-guide-v2-to-v3]: migration_guide_v2tov3.md -[healthz-ping]: https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/healthz#CheckHandler -[controller-runtime]: https://github.com/kubernetes-sigs/controller-runtime/releases -[controller-tools]: https://github.com/kubernetes-sigs/controller-tools/releases -[kustomize]: https://github.com/kubernetes-sigs/kustomize/releases -[issue-1637]: https://github.com/kubernetes-sigs/kubebuilder/issues/1637 -[enhancement proposal]: https://github.com/kubernetes/enhancements/tree/master/keps/sig-cluster-lifecycle/wgs -[cert-manager-docs]: https://cert-manager.io/docs/installation/upgrading/ -[kb-releases]: https://github.com/kubernetes-sigs/kubebuilder/releases -[kube-rbac-proxy]: https://github.com/brancz/kube-rbac-proxy/releases -[basic-project-doc]: ../../cronjob-tutorial/basic-project.md -[kustomize]: https://github.com/kubernetes-sigs/kustomize \ No newline at end of file +-[MigrationGuidev2toV3][migration-guide-v2-to-v3]**(Recommended)** + +###Byupdatingthefilesmanually + +SoyouwanttousethelatestversionofKubebuilderCLIwithoutchangingyourscaffoldingthen,checkthefollowingguidewhichwilldescribethemanuallystepsrequiredforyoutoupgradeonlyyourPROJECTversionandstartstousethepluginsversions. + +Thiswayismorecomplex,susceptibletoerrors,andsuccesscannotbeassured.Also,byfollowingthesestepsyouwillnotgettheimprovementsandbugfixesinthedefaultgeneratedprojectfiles. + +Youwillcheckthatyoucanstillusingthepreviouslayoutbyusingthe`go/v2`pluginwhichwillnotupgradethe[controller-runtime][controller-runtime]and[controller-tools][controller-tools]tothelatestversionusedwith`go/v3`becuaseofitsbreakingchanges.Bycheckingthisguideyouknowalsohowtomanuallychangethefilestousethe`go/v3`pluginanditsdependenciesversions. + +-[MigratingtoKubebuilderv3byupdatingthefilesmanually][manually-upgrade] + +[plugins-phase1-design-doc]:https://github.com/kubernetes-sigs/kubebuilder/blob/master/designs/extensible-cli-and-scaffolding-plugins-phase-1.md +[plugins-phase1-design-doc-1.5]:https://github.com/kubernetes-sigs/kubebuilder/blob/master/designs/extensible-cli-and-scaffolding-plugins-phase-1-5.md +[plugins-phase2-design-doc]:https://github.com/kubernetes-sigs/kubebuilder/blob/master/designs/extensible-cli-and-scaffolding-plugins-phase-2.md +[plugins-section]:./../../plugins/plugins.md +[manually-upgrade]:manually_migration_guide_v2_v3.md +[component-config-tutorial]:../../component-config-tutorial/tutorial.md +[issue-1893]:https://github.com/kubernetes-sigs/kubebuilder/issues/1839 +[migration-guide-v2-to-v3]:migration_guide_v2tov3.md +[healthz-ping]:https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/healthz#CheckHandler +[controller-runtime]:https://github.com/kubernetes-sigs/controller-runtime/releases +[controller-tools]:https://github.com/kubernetes-sigs/controller-tools/releases +[kustomize]:https://github.com/kubernetes-sigs/kustomize/releases +[issue-1637]:https://github.com/kubernetes-sigs/kubebuilder/issues/1637 +[enhancementproposal]:https://github.com/kubernetes/enhancements/tree/master/keps/sig-cluster-lifecycle/wgs +[cert-manager-docs]:https://cert-manager.io/docs/installation/upgrading/ +[kb-releases]:https://github.com/kubernetes-sigs/kubebuilder/releases +[kube-rbac-proxy]:https://github.com/brancz/kube-rbac-proxy/releases +[basic-project-doc]:../../cronjob-tutorial/basic-project.md +[kustomize]:https://github.com/kubernetes-sigs/kustomize \ No newline at end of file diff --git a/docs/book/src/migration/manually_migration_guide_gov3_to_gov4.md b/docs/book/src/migration/manually_migration_guide_gov3_to_gov4.md index 1fccbb456d0..428b4e0b5e1 100644 --- a/docs/book/src/migration/manually_migration_guide_gov3_to_gov4.md +++ b/docs/book/src/migration/manually_migration_guide_gov3_to_gov4.md @@ -1,210 +1,210 @@ -# Migration from go/v3 to go/v4 by updating the files manually +#Migrationfromgo/v3togo/v4byupdatingthefilesmanually -Make sure you understand the [differences between Kubebuilder go/v3 and go/v4][v3vsv4] -before continuing. +Makesureyouunderstandthe[differencesbetweenKubebuildergo/v3andgo/v4][v3vsv4] +beforecontinuing. -Please ensure you have followed the [installation guide][quick-start] -to install the required components. +Pleaseensureyouhavefollowedthe[installationguide][quick-start] +toinstalltherequiredcomponents. -The following guide describes the manual steps required to upgrade your PROJECT config file to begin using `go/v4`. +ThefollowingguidedescribesthemanualstepsrequiredtoupgradeyourPROJECTconfigfiletobeginusing`go/v4`. -This way is more complex, susceptible to errors, and success cannot be assured. Also, by following these steps you will not get the improvements and bug fixes in the default generated project files. +Thiswayismorecomplex,susceptibletoerrors,andsuccesscannotbeassured.Also,byfollowingthesestepsyouwillnotgettheimprovementsandbugfixesinthedefaultgeneratedprojectfiles. -Usually it is suggested to do it manually if you have customized your project and deviated too much from the proposed scaffold. Before continuing, ensure that you understand the note about [project customizations][project-customizations]. Note that you might need to spend more effort to do this process manually than to organize your project customizations. The proposed layout will keep your project maintainable and upgradable with less effort in the future. +Usuallyitissuggestedtodoitmanuallyifyouhavecustomizedyourprojectanddeviatedtoomuchfromtheproposedscaffold.Beforecontinuing,ensurethatyouunderstandthenoteabout[projectcustomizations][project-customizations].Notethatyoumightneedtospendmoreefforttodothisprocessmanuallythantoorganizeyourprojectcustomizations.Theproposedlayoutwillkeepyourprojectmaintainableandupgradablewithlesseffortinthefuture. -The recommended upgrade approach is to follow the [Migration Guide go/v3 to go/v4][migration-guide-gov3-to-gov4] instead. +Therecommendedupgradeapproachistofollowthe[MigrationGuidego/v3togo/v4][migration-guide-gov3-to-gov4]instead. -## Migration from project config version "go/v3" to "go/v4" +##Migrationfromprojectconfigversion"go/v3"to"go/v4" -Update the `PROJECT` file layout which stores information about the resources that are used to enable plugins make -useful decisions while scaffolding. The `layout` field indicates the scaffolding and the primary plugin version in use. +Updatethe`PROJECT`filelayoutwhichstoresinformationabouttheresourcesthatareusedtoenablepluginsmake +usefuldecisionswhilescaffolding.The`layout`fieldindicatesthescaffoldingandtheprimarypluginversioninuse. -### Steps to migrate +###Stepstomigrate -#### Migrate the layout version into the PROJECT file +####MigratethelayoutversionintothePROJECTfile -The following steps describe the manual changes required to bring the project configuration file (`PROJECT`). -These change will add the information that Kubebuilder would add when generating the file. This file can be found in the root directory. +Thefollowingstepsdescribethemanualchangesrequiredtobringtheprojectconfigurationfile(`PROJECT`). +ThesechangewilladdtheinformationthatKubebuilderwouldaddwhengeneratingthefile.Thisfilecanbefoundintherootdirectory. -Update the PROJECT file by replacing: +UpdatethePROJECTfilebyreplacing: ```yaml layout: -- go.kubebuilder.io/v3 +-go.kubebuilder.io/v3 ``` With: ```yaml layout: -- go.kubebuilder.io/v4 +-go.kubebuilder.io/v4 ``` -#### Changes to the layout +####Changestothelayout -##### New layout: +#####Newlayout: -- The directory `apis` was renamed to `api` to follow the standard -- The `controller(s)` directory has been moved under a new directory called `internal` and renamed to singular as well `controller` -- The `main.go` previously scaffolded in the root directory has been moved under a new directory called `cmd` +-Thedirectory`apis`wasrenamedto`api`tofollowthestandard +-The`controller(s)`directoryhasbeenmovedunderanewdirectorycalled`internal`andrenamedtosingularaswell`controller` +-The`main.go`previouslyscaffoldedintherootdirectoryhasbeenmovedunderanewdirectorycalled`cmd` -Therefore, you can check the changes in the layout results into: +Therefore,youcancheckthechangesinthelayoutresultsinto: ```sh ... -├── cmd -│ └── main.go -├── internal -│ └── controller -└── api +├──cmd +│└──main.go +├──internal +│└──controller +└──api ``` -##### Migrating to the new layout: +#####Migratingtothenewlayout: -- Create a new directory `cmd` and move the `main.go` under it. -- If your project support multi-group the APIs are scaffold under a directory called `apis`. Rename this directory to `api` -- Move the `controllers` directory under the `internal` and rename it for `controller` -- Now ensure that the imports will be updated accordingly by: - - Update the `main.go` imports to look for the new path of your controllers under the `internal/controller` directory +-Createanewdirectory`cmd`andmovethe`main.go`underit. +-Ifyourprojectsupportmulti-grouptheAPIsarescaffoldunderadirectorycalled`apis`.Renamethisdirectoryto`api` +-Movethe`controllers`directoryunderthe`internal`andrenameitfor`controller` +-Nowensurethattheimportswillbeupdatedaccordinglyby: +-Updatethe`main.go`importstolookforthenewpathofyourcontrollersunderthe`internal/controller`directory -**Then, let's update the scaffolds paths** +**Then,let'supdatethescaffoldspaths** -- Update the Dockerfile to ensure that you will have: +-UpdatetheDockerfiletoensurethatyouwillhave: ``` -COPY cmd/main.go cmd/main.go -COPY api/ api/ -COPY internal/controller/ internal/controller/ +COPYcmd/main.gocmd/main.go +COPYapi/api/ +COPYinternal/controller/internal/controller/ ``` -Then, replace: +Then,replace: ``` -RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager main.go +RUNCGO_ENABLED=0GOOS=${TARGETOS:-linux}GOARCH=${TARGETARCH}gobuild-a-omanagermain.go ``` With: ``` -RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager cmd/main.go +RUNCGO_ENABLED=0GOOS=${TARGETOS:-linux}GOARCH=${TARGETARCH}gobuild-a-omanagercmd/main.go ``` -- Update the Makefile targets to build and run the manager by replacing: +-UpdatetheMakefiletargetstobuildandrunthemanagerbyreplacing: ``` -.PHONY: build -build: manifests generate fmt vet ## Build manager binary. - go build -o bin/manager main.go +.PHONY:build +build:manifestsgeneratefmtvet##Buildmanagerbinary. +gobuild-obin/managermain.go -.PHONY: run -run: manifests generate fmt vet ## Run a controller from your host. - go run ./main.go +.PHONY:run +run:manifestsgeneratefmtvet##Runacontrollerfromyourhost. +gorun./main.go ``` With: ``` -.PHONY: build -build: manifests generate fmt vet ## Build manager binary. - go build -o bin/manager cmd/main.go +.PHONY:build +build:manifestsgeneratefmtvet##Buildmanagerbinary. +gobuild-obin/managercmd/main.go -.PHONY: run -run: manifests generate fmt vet ## Run a controller from your host. - go run ./cmd/main.go +.PHONY:run +run:manifestsgeneratefmtvet##Runacontrollerfromyourhost. +gorun./cmd/main.go ``` -- Update the `internal/controller/suite_test.go` to set the path for the `CRDDirectoryPaths`: +-Updatethe`internal/controller/suite_test.go`tosetthepathforthe`CRDDirectoryPaths`: Replace: ``` -CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")}, +CRDDirectoryPaths:[]string{filepath.Join("..","config","crd","bases")}, ``` With: ``` -CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")}, +CRDDirectoryPaths:[]string{filepath.Join("..","..","config","crd","bases")}, ``` -Note that if your project has multiple groups (`multigroup:true`) then the above update should result into `"..", "..", "..",` instead of `"..",".."` +Notethatifyourprojecthasmultiplegroups(`multigroup:true`)thentheaboveupdateshouldresultinto`"..","..","..",`insteadof`"..",".."` -#### Now, let's update the PATHs in the PROJECT file accordingly +####Now,let'supdatethePATHsinthePROJECTfileaccordingly -The PROJECT tracks the paths of all APIs used in your project. Ensure that they now point to `api/...` as the following example: +ThePROJECTtracksthepathsofallAPIsusedinyourproject.Ensurethattheynowpointto`api/...`asthefollowingexample: -**Before update:** -``` - group: crew - kind: Captain - path: sigs.k8s.io/kubebuilder/testdata/project-v4/apis/crew/v1 +**Beforeupdate:** +``` +group:crew +kind:Captain +path:sigs.k8s.io/kubebuilder/testdata/project-v4/apis/crew/v1 ``` -**After Update:** +**AfterUpdate:** ``` - group: crew - kind: Captain - path: sigs.k8s.io/kubebuilder/testdata/project-v4/api/crew/v1 +group:crew +kind:Captain +path:sigs.k8s.io/kubebuilder/testdata/project-v4/api/crew/v1 ``` -### Update kustomize manifests with the changes made so far +###Updatekustomizemanifestswiththechangesmadesofar -- Update the manifest under `config/` directory with all changes performed in the default scaffold done with `go/v4` plugin. (see for example `testdata/project-v4/config/`) to get all changes in the - default scaffolds to be applied on your project -- Create `config/samples/kustomization.yaml` with all Custom Resources samples specified into `config/samples`. _(see for example `testdata/project-v4/config/samples/kustomization.yaml`)_ +-Updatethemanifestunder`config/`directorywithallchangesperformedinthedefaultscaffolddonewith`go/v4`plugin.(seeforexample`testdata/project-v4/config/`)togetallchangesinthe +defaultscaffoldstobeappliedonyourproject +-Create`config/samples/kustomization.yaml`withallCustomResourcessamplesspecifiedinto`config/samples`._(seeforexample`testdata/project-v4/config/samples/kustomization.yaml`)_ - -### If you have webhooks: +###Ifyouhavewebhooks: -Replace the import `admissionv1beta1 "k8s.io/api/admission/v1beta1"` with `admissionv1 "k8s.io/api/admission/v1"` in the webhook test files +Replacetheimport`admissionv1beta1"k8s.io/api/admission/v1beta1"`with`admissionv1"k8s.io/api/admission/v1"`inthewebhooktestfiles -### Makefile updates +###Makefileupdates -Update the Makefile with the changes which can be found in the samples under testdata for the release tag used. (see for example `testdata/project-v4/Makefile`) +UpdatetheMakefilewiththechangeswhichcanbefoundinthesamplesundertestdataforthereleasetagused.(seeforexample`testdata/project-v4/Makefile`) -### Update the dependencies +###Updatethedependencies -Update the `go.mod` with the changes which can be found in the samples under `testdata` for the release tag used. (see for example `testdata/project-v4/go.mod`). Then, run -`go mod tidy` to ensure that you get the latest dependencies and your Golang code has no breaking changes. +Updatethe`go.mod`withthechangeswhichcanbefoundinthesamplesunder`testdata`forthereleasetagused.(seeforexample`testdata/project-v4/go.mod`).Then,run +`gomodtidy`toensurethatyougetthelatestdependenciesandyourGolangcodehasnobreakingchanges. -### Verification +###Verification -In the steps above, you updated your project manually with the goal of ensuring that it follows -the changes in the layout introduced with the `go/v4` plugin that update the scaffolds. +Inthestepsabove,youupdatedyourprojectmanuallywiththegoalofensuringthatitfollows +thechangesinthelayoutintroducedwiththe`go/v4`pluginthatupdatethescaffolds. -There is no option to verify that you properly updated the `PROJECT` file of your project. -The best way to ensure that everything is updated correctly, would be to initialize a project using the `go/v4` plugin, -(ie) using `kubebuilder init --domain tutorial.kubebuilder.io plugins=go/v4` and generating the same API(s), -controller(s), and webhook(s) in order to compare the generated configuration with the manually changed configuration. +Thereisnooptiontoverifythatyouproperlyupdatedthe`PROJECT`fileofyourproject. +Thebestwaytoensurethateverythingisupdatedcorrectly,wouldbetoinitializeaprojectusingthe`go/v4`plugin, +(ie)using`kubebuilderinit--domaintutorial.kubebuilder.ioplugins=go/v4`andgeneratingthesameAPI(s), +controller(s),andwebhook(s)inordertocomparethegeneratedconfigurationwiththemanuallychangedconfiguration. -Also, after all updates you would run the following commands: +Also,afterallupdatesyouwouldrunthefollowingcommands: -- `make manifests` (to re-generate the files using the latest version of the contrller-gen after you update the Makefile) -- `make all` (to ensure that you are able to build and perform all operations) +-`makemanifests`(tore-generatethefilesusingthelatestversionofthecontrller-genafteryouupdatetheMakefile) +-`makeall`(toensurethatyouareabletobuildandperformalloperations) -[v3vsv4]: v3vsv4.md -[quick-start]: ./../quick-start.md#installation -[migration-guide-gov3-to-gov4]: migration_guide_gov3_to_gov4.md -[controller-tools]: https://github.com/kubernetes-sigs/controller-tools/releases -[controller-runtime]: https://github.com/kubernetes-sigs/controller-runtime/releases -[multi-group]: multi-group.md +[v3vsv4]:v3vsv4.md +[quick-start]:./../quick-start.md#installation +[migration-guide-gov3-to-gov4]:migration_guide_gov3_to_gov4.md +[controller-tools]:https://github.com/kubernetes-sigs/controller-tools/releases +[controller-runtime]:https://github.com/kubernetes-sigs/controller-runtime/releases +[multi-group]:multi-group.md diff --git a/docs/book/src/migration/migration_guide_gov3_to_gov4.md b/docs/book/src/migration/migration_guide_gov3_to_gov4.md index 4d714d84c09..e22e532bae8 100644 --- a/docs/book/src/migration/migration_guide_gov3_to_gov4.md +++ b/docs/book/src/migration/migration_guide_gov3_to_gov4.md @@ -1,161 +1,161 @@ -# Migration from go/v3 to go/v4 +#Migrationfromgo/v3togo/v4 -Make sure you understand the [differences between Kubebuilder go/v3 and go/v4][v3vsv4] -before continuing. +Makesureyouunderstandthe[differencesbetweenKubebuildergo/v3andgo/v4][v3vsv4] +beforecontinuing. -Please ensure you have followed the [installation guide][quick-start] -to install the required components. +Pleaseensureyouhavefollowedthe[installationguide][quick-start] +toinstalltherequiredcomponents. -The recommended way to migrate a `go/v3` project is to create a new `go/v4` project and -copy over the API and the reconciliation code. The conversion will end up with a -project that looks like a native go/v4 project layout (latest version). +Therecommendedwaytomigratea`go/v3`projectistocreateanew`go/v4`projectand +copyovertheAPIandthereconciliationcode.Theconversionwillendupwitha +projectthatlookslikeanativego/v4projectlayout(latestversion). - -However, in some cases, it's possible to do an in-place upgrade (i.e. reuse the go/v3 project layout, upgrading -the PROJECT file, and scaffolds manually). For further information see [Migration from go/v3 to go/v4 by updating the files manually][manually-upgrade] +However,insomecases,it'spossibletodoanin-placeupgrade(i.e.reusethego/v3projectlayout,upgrading +thePROJECTfile,andscaffoldsmanually).Forfurtherinformationsee[Migrationfromgo/v3togo/v4byupdatingthefilesmanually][manually-upgrade] -## Initialize a go/v4 Project +##Initializeago/v4Project - -Create a new directory with the name of your project. Note that -this name is used in the scaffolds to create the name of your manager Pod and of the Namespace where the Manager is deployed by default. +Createanewdirectorywiththenameofyourproject.Notethat +thisnameisusedinthescaffoldstocreatethenameofyourmanagerPodandoftheNamespacewheretheManagerisdeployedbydefault. ```bash -$ mkdir migration-project-name -$ cd migration-project-name +$mkdirmigration-project-name +$cdmigration-project-name ``` -Now, we need to initialize a go/v4 project. Before we do that, we'll need -to initialize a new go module if we're not on the `GOPATH`. While technically this is -not needed inside `GOPATH`, it is still recommended. +Now,weneedtoinitializeago/v4project.Beforewedothat,we'llneed +toinitializeanewgomoduleifwe'renotonthe`GOPATH`.Whiletechnicallythisis +notneededinside`GOPATH`,itisstillrecommended. ```bash -go mod init tutorial.kubebuilder.io/migration-project +gomodinittutorial.kubebuilder.io/migration-project ``` - -Now, we can finish initializing the project with kubebuilder. +Now,wecanfinishinitializingtheprojectwithkubebuilder. ```bash -kubebuilder init --domain tutorial.kubebuilder.io --plugins=go/v4 +kubebuilderinit--domaintutorial.kubebuilder.io--plugins=go/v4 ``` - -## Migrate APIs and Controllers +##MigrateAPIsandControllers -Next, we'll re-scaffold out the API types and controllers. +Next,we'llre-scaffoldouttheAPItypesandcontrollers. - ```bash -kubebuilder create api --group batch --version v1 --kind CronJob +kubebuildercreateapi--groupbatch--versionv1--kindCronJob ``` -### Migrate the APIs +###MigratetheAPIs - -Now, let's copy the API definition from `api/v1/_types.go` in our old project to the new one. +Now,let'scopytheAPIdefinitionfrom`api/v1/_types.go`inouroldprojecttothenewone. -These files have not been modified by the new plugin, so you should be able to replace your freshly scaffolded files by your old one. There may be some cosmetic changes. So you can choose to only copy the types themselves. +Thesefileshavenotbeenmodifiedbythenewplugin,soyoushouldbeabletoreplaceyourfreshlyscaffoldedfilesbyyouroldone.Theremaybesomecosmeticchanges.Soyoucanchoosetoonlycopythetypesthemselves. -### Migrate the Controllers +###MigratetheControllers -Now, let's migrate the controller code from `controllers/cronjob_controller.go` in our old project to the new one. +Now,let'smigratethecontrollercodefrom`controllers/cronjob_controller.go`inouroldprojecttothenewone. -## Migrate the Webhooks +##MigratetheWebhooks - -Now let's scaffold the webhooks for our CRD (CronJob). We'll need to run the -following command with the `--defaulting` and `--programmatic-validation` flags -(since our test project uses defaulting and validating webhooks): +Nowlet'sscaffoldthewebhooksforourCRD(CronJob).We'llneedtorunthe +followingcommandwiththe`--defaulting`and`--programmatic-validation`flags +(sinceourtestprojectusesdefaultingandvalidatingwebhooks): ```bash -kubebuilder create webhook --group batch --version v1 --kind CronJob --defaulting --programmatic-validation +kubebuildercreatewebhook--groupbatch--versionv1--kindCronJob--defaulting--programmatic-validation ``` -Now, let's copy the webhook definition from `api/v1/_webhook.go` from our old project to the new one. +Now,let'scopythewebhookdefinitionfrom`api/v1/_webhook.go`fromouroldprojecttothenewone. -## Others +##Others -If there are any manual updates in `main.go` in v3, we need to port the changes to the new `main.go`. We’ll also need to ensure all of needed controller-runtime `schemes` have been registered. +Ifthereareanymanualupdatesin`main.go`inv3,weneedtoportthechangestothenew`main.go`.We’llalsoneedtoensureallofneededcontroller-runtime`schemes`havebeenregistered. -If there are additional manifests added under config directory, port them as well. Please, be aware that -the new version go/v4 uses Kustomize v5x and no longer Kustomize v4. Therefore, if added customized -implementations in the config you need to ensure that them can work with Kustomize v5 and/if not -update/upgrade any breaking change that you might face. +Ifthereareadditionalmanifestsaddedunderconfigdirectory,portthemaswell.Please,beawarethat +thenewversiongo/v4usesKustomizev5xandnolongerKustomizev4.Therefore,ifaddedcustomized +implementationsintheconfigyouneedtoensurethatthemcanworkwithKustomizev5and/ifnot +update/upgradeanybreakingchangethatyoumightface. -In v4, installation of Kustomize has been changed from bash script to `go get`. Change the `kustomize` dependency in Makefile to +Inv4,installationofKustomizehasbeenchangedfrombashscriptto`goget`.Changethe`kustomize`dependencyinMakefileto ``` -.PHONY: kustomize -kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary. If wrong version is installed, it will be removed before downloading. -$(KUSTOMIZE): $(LOCALBIN) - @if test -x $(LOCALBIN)/kustomize && ! $(LOCALBIN)/kustomize version | grep -q $(KUSTOMIZE_VERSION); then \ - echo "$(LOCALBIN)/kustomize version is not expected $(KUSTOMIZE_VERSION). Removing it before installing."; \ - rm -rf $(LOCALBIN)/kustomize; \ - fi - test -s $(LOCALBIN)/kustomize || GOBIN=$(LOCALBIN) GO111MODULE=on go install sigs.k8s.io/kustomize/kustomize/v5@$(KUSTOMIZE_VERSION) +.PHONY:kustomize +kustomize:$(KUSTOMIZE)##Downloadkustomizelocallyifnecessary.Ifwrongversionisinstalled,itwillberemovedbeforedownloading. +$(KUSTOMIZE):$(LOCALBIN) +@iftest-x$(LOCALBIN)/kustomize&&!$(LOCALBIN)/kustomizeversion|grep-q$(KUSTOMIZE_VERSION);then\ +echo"$(LOCALBIN)/kustomizeversionisnotexpected$(KUSTOMIZE_VERSION).Removingitbeforeinstalling.";\ +rm-rf$(LOCALBIN)/kustomize;\ +fi +test-s$(LOCALBIN)/kustomize||GOBIN=$(LOCALBIN)GO111MODULE=ongoinstallsigs.k8s.io/kustomize/kustomize/v5@$(KUSTOMIZE_VERSION) ``` -Change the image name in the Makefile if needed. +ChangetheimagenameintheMakefileifneeded. -## Verification +##Verification -Finally, we can run `make` and `make docker-build` to ensure things are working +Finally,wecanrun`make`and`makedocker-build`toensurethingsareworking fine. -[v3vsv4]: v3vsv4.md -[quick-start]: ./../quick-start.md#installation -[controller-tools]: https://github.com/kubernetes-sigs/controller-tools/releases -[controller-runtime]: https://github.com/kubernetes-sigs/controller-runtime/releases -[multi-group]: multi-group.md -[manually-upgrade]: manually_migration_guide_gov3_to_gov4.md -[project-file]: ../reference/project-config.md \ No newline at end of file +[v3vsv4]:v3vsv4.md +[quick-start]:./../quick-start.md#installation +[controller-tools]:https://github.com/kubernetes-sigs/controller-tools/releases +[controller-runtime]:https://github.com/kubernetes-sigs/controller-runtime/releases +[multi-group]:multi-group.md +[manually-upgrade]:manually_migration_guide_gov3_to_gov4.md +[project-file]:../reference/project-config.md \ No newline at end of file diff --git a/docs/book/src/migration/multi-group.md b/docs/book/src/migration/multi-group.md index 6fcd1cd4aa6..6966cb1b7d6 100644 --- a/docs/book/src/migration/multi-group.md +++ b/docs/book/src/migration/multi-group.md @@ -1,124 +1,124 @@ -# Single Group to Multi-Group +#SingleGrouptoMulti-Group - -Let's migrate the [CronJob example][cronjob-tutorial]. +Let'smigratethe[CronJobexample][cronjob-tutorial]. - -To change the layout of your project to support Multi-Group run the command -`kubebuilder edit --multigroup=true`. Once you switch to a multi-group layout, the new Kinds -will be generated in the new layout but additional manual work is needed -to move the old API groups to the new layout. +TochangethelayoutofyourprojecttosupportMulti-Grouprunthecommand +`kubebuilderedit--multigroup=true`.Onceyouswitchtoamulti-grouplayout,thenewKinds +willbegeneratedinthenewlayoutbutadditionalmanualworkisneeded +tomovetheoldAPIgroupstothenewlayout. -Generally, we use the prefix for the API group as the directory name. We -can check `api/v1/groupversion_info.go` to find that out: +Generally,weusetheprefixfortheAPIgroupasthedirectoryname.We +cancheck`api/v1/groupversion_info.go`tofindthatout: ```go -// +groupName=batch.tutorial.kubebuilder.io -package v1 +//+groupName=batch.tutorial.kubebuilder.io +packagev1 ``` -Then, we'll rename move our existing APIs into a new subdirectory, "batch": +Then,we'llrenamemoveourexistingAPIsintoanewsubdirectory,"batch": ```bash -mkdir api/batch -mv api/* api/batch +mkdirapi/batch +mvapi/*api/batch ``` -After moving the APIs to a new directory, the same needs to be applied to the controllers. For go/v4: +AftermovingtheAPIstoanewdirectory,thesameneedstobeappliedtothecontrollers.Forgo/v4: ```bash -mkdir internal/controller/batch -mv internal/controller/* internal/controller/batch/ +mkdirinternal/controller/batch +mvinternal/controller/*internal/controller/batch/ ``` - + + +##Whentouseit? + +-Thispluginishelpfulforthosewhoaregettingstarted. +-IfyouarelookingtoDeployandManageanimage(Operand)using[Operatorpattern](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/)andthetoolthepluginwillcreateanAPI/controllertobereconciledtoachievethisgoal +-Ifyouarelookingtospeedup + +##Howtouseit? + +Afteryoucreateanewprojectwith`kubebuilderinit`youcancreateAPIsusingthisplugin.Ensurethatyouhavefollowedthe[quickstart](https://book.kubebuilder.io/quick-start.html)beforetryingtouseit. + +Then,byusingthispluginyoucan[createAPIs](https://book.kubebuilder.io/cronjob-tutorial/gvks.html)informingtheimage(Operand)thatyouwouldliketodeployonthecluster.Notethatyoucanoptionallyspecifythecommandthatcouldbeusedtoinitializethiscontainerviatheflag`--image-container-command`andtheportwith`--image-container-port`flag.Youcanalsospecifythe`RunAsUser`valuefortheSecurityContextofthecontainerviatheflag`--run-as-user`.,i.e: + +```sh +kubebuildercreateapi--groupexample.com--versionv1alpha1--kindMemcached--image=memcached:1.6.15-alpine--image-container-command="memcached,-m=64,modern,-v"--image-container-port="11211"--run-as-user="1001"--plugins="deploy-image/v1-alpha" +``` + + +

Usingmakerun

+ +The`makerun`willexecutethe`main.go`outsideoftheclustertoletyoutesttheprojectrunningitlocally.NotethatbyusingthisplugintheOperandimageinformedwillbestoredviaanenvironmentvariableinthe`config/manager/manager.yaml`manifest. + +Therefore,beforerun`makerun`youneedtoexportanyenvironmentvariablethatyoumighthave.Example: + +```sh +exportMEMCACHED_IMAGE="memcached:1.4.36-alpine" +``` + + + +##Subcommands + +Thedeploy-imagepluginimplementsthefollowingsubcommands: + +-createapi(`$kubebuildercreateapi[OPTIONS]`) + +##Affectedfiles + +Withthe`createapi`commandofthisplugin,inadditiontotheexistingscaffolding,thefollowingfilesareaffected: + +-`controllers/*_controller.go`(scaffoldcontrollerwithreconciliationimplemented) +-`controllers/*_controller_test.go`(scaffoldthetestsforthecontroller) +-`controllers/*_suite_test.go`(scaffold/updatethesuiteoftests) +-`api//*_types.go`(scaffoldthespecsforthenewapi) +-`config/samples/*_.yaml`(scaffolddefaultvaluesforitsCR) +-`main.go`(updatetoaddcontrollersetup) +-`config/manager/manager.yaml`(updatewithenvvartostoretheimage) + +##FurtherResources: + +-Checkout[videotoshowhowitworks](https://youtu.be/UwPuRjjnMjY) +-Seethe[desingproposaldocumentation](../../../../designs/code-generate-image-plugin.md) + +[controller-runtime]:https://github.com/kubernetes-sigs/controller-runtime +[testdata]:https://github.com/kubernetes-sigs/kubebuilder/tree/master/testdata/ +[envtest]:../reference/envtest.md diff --git a/docs/book/src/plugins/extending-cli.md b/docs/book/src/plugins/extending-cli.md index dc1b2078f6f..41c270b0893 100644 --- a/docs/book/src/plugins/extending-cli.md +++ b/docs/book/src/plugins/extending-cli.md @@ -1,212 +1,212 @@ -# Extending the CLI and Scaffolds +#ExtendingtheCLIandScaffolds -## Overview +##Overview -You can extend Kubebuilder to allow your project to have the same CLI features and provide the plugins scaffolds. +YoucanextendKubebuildertoallowyourprojecttohavethesameCLIfeaturesandprovidethepluginsscaffolds. -## CLI system +##CLIsystem -Plugins are run using a [`CLI`][cli] object, which maps a plugin type to a subcommand and calls that plugin's methods. -For example, writing a program that injects an `Init` plugin into a `CLI` then calling `CLI.Run()` will call the -plugin's [SubcommandMetadata][plugin-sub-command], [UpdatesMetadata][plugin-update-meta] and `Run` methods with information a user has passed to the -program in `kubebuilder init`. Following an example: +Pluginsarerunusinga[`CLI`][cli]object,whichmapsaplugintypetoasubcommandandcallsthatplugin'smethods. +Forexample,writingaprogramthatinjectsan`Init`pluginintoa`CLI`thencalling`CLI.Run()`willcallthe +plugin's[SubcommandMetadata][plugin-sub-command],[UpdatesMetadata][plugin-update-meta]and`Run`methodswithinformationauserhaspassedtothe +programin`kubebuilderinit`.Followinganexample: ```go -package cli +packagecli -import ( - log "github.com/sirupsen/logrus" - "github.com/spf13/cobra" +import( +log"github.com/sirupsen/logrus" +"github.com/spf13/cobra" - "sigs.k8s.io/kubebuilder/v3/pkg/cli" - cfgv3 "sigs.k8s.io/kubebuilder/v3/pkg/config/v3" - "sigs.k8s.io/kubebuilder/v3/pkg/plugin" - kustomizecommonv1 "sigs.k8s.io/kubebuilder/v3/pkg/plugins/common/kustomize/v1" - "sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang" - declarativev1 "sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/declarative/v1" - golangv3 "sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/v3" +"sigs.k8s.io/kubebuilder/v3/pkg/cli" +cfgv3"sigs.k8s.io/kubebuilder/v3/pkg/config/v3" +"sigs.k8s.io/kubebuilder/v3/pkg/plugin" +kustomizecommonv1"sigs.k8s.io/kubebuilder/v3/pkg/plugins/common/kustomize/v1" +"sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang" +declarativev1"sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/declarative/v1" +golangv3"sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/v3" ) -var ( - // The following is an example of the commands - // that you might have in your own binary - commands = []*cobra.Command{ - myExampleCommand.NewCmd(), - } - alphaCommands = []*cobra.Command{ - myExampleAlphaCommand.NewCmd(), - } +var( +//Thefollowingisanexampleofthecommands +//thatyoumighthaveinyourownbinary +commands=[]*cobra.Command{ +myExampleCommand.NewCmd(), +} +alphaCommands=[]*cobra.Command{ +myExampleAlphaCommand.NewCmd(), +} +) + +//GetPluginsCLIreturnsthepluginsbasedCLIconfiguredtobeusedinyourCLIbinary +funcGetPluginsCLI()(*cli.CLI){ +//BundlepluginwhichbuiltthegolangprojectsscaffoldbyKubebuildergo/v3 +gov3Bundle,_:=plugin.NewBundleWithOptions(plugin.WithName(golang.DefaultNameQualifier), +plugin.WithVersion(plugin.Version{Number:3}), +plugin.WithPlugins(kustomizecommonv1.Plugin{},golangv3.Plugin{}), +) + + +c,err:=cli.New( +//AddthenameofyourCLIbinary +cli.WithCommandName("example-cli"), + +//AddtheversionofyourCLIbinary +cli.WithVersion(versionString()), + +//RegisterthepluginsoptionswhichcanbeusedtodothescaffoldsviayourCLItool.SeethatweareusingasexampleherethepluginswhichareimplementedandprovidedbyKubebuilder +cli.WithPlugins( +gov3Bundle, +&declarativev1.Plugin{}, +), + +//Defineswhatwillbethedefaultpluginusedbyyourbinary.Itmeansthatwillbethepluginusedifnoinfobeprovidedsuchaswhentheuserruns`kubebuilderinit` +cli.WithDefaultPlugins(cfgv3.Version,gov3Bundle), + +//DefinethedefaultprojectconfigurationversionwhichwillbeusedbytheCLIwhennoneisinformedby--project-versionflag. +cli.WithDefaultProjectVersion(cfgv3.Version), + +//AddsyourowncommandstotheCLI +cli.WithExtraCommands(commands...), + +//AddyourownalphacommandstotheCLI +cli.WithExtraAlphaCommands(alphaCommands...), + +//AddsthecompletionoptionforyourCLI +cli.WithCompletion(), ) +iferr!=nil{ +log.Fatal(err) +} -// GetPluginsCLI returns the plugins based CLI configured to be used in your CLI binary -func GetPluginsCLI() (*cli.CLI) { - // Bundle plugin which built the golang projects scaffold by Kubebuilder go/v3 - gov3Bundle, _ := plugin.NewBundleWithOptions(plugin.WithName(golang.DefaultNameQualifier), - plugin.WithVersion(plugin.Version{Number: 3}), - plugin.WithPlugins(kustomizecommonv1.Plugin{}, golangv3.Plugin{}), - ) - - - c, err := cli.New( - // Add the name of your CLI binary - cli.WithCommandName("example-cli"), - - // Add the version of your CLI binary - cli.WithVersion(versionString()), - - // Register the plugins options which can be used to do the scaffolds via your CLI tool. See that we are using as example here the plugins which are implemented and provided by Kubebuilder - cli.WithPlugins( - gov3Bundle, - &declarativev1.Plugin{}, - ), - - // Defines what will be the default plugin used by your binary. It means that will be the plugin used if no info be provided such as when the user runs `kubebuilder init` - cli.WithDefaultPlugins(cfgv3.Version, gov3Bundle), - - // Define the default project configuration version which will be used by the CLI when none is informed by --project-version flag. - cli.WithDefaultProjectVersion(cfgv3.Version), - - // Adds your own commands to the CLI - cli.WithExtraCommands(commands...), - - // Add your own alpha commands to the CLI - cli.WithExtraAlphaCommands(alphaCommands...), - - // Adds the completion option for your CLI - cli.WithCompletion(), - ) - if err != nil { - log.Fatal(err) - } - - return c +returnc } -// versionString returns the CLI version -func versionString() string { - // return your binary project version +//versionStringreturnstheCLIversion +funcversionString()string{ +//returnyourbinaryprojectversion } ``` -This program can then be built and run in the following ways: +Thisprogramcanthenbebuiltandruninthefollowingways: -Default behavior: +Defaultbehavior: ```sh -# Initialize a project with the default Init plugin, "go.example.com/v1". -# This key is automatically written to a PROJECT config file. -$ my-bin-builder init -# Create an API and webhook with "go.example.com/v1" CreateAPI and -# CreateWebhook plugin methods. This key was read from the config file. -$ my-bin-builder create api [flags] -$ my-bin-builder create webhook [flags] +#InitializeaprojectwiththedefaultInitplugin,"go.example.com/v1". +#ThiskeyisautomaticallywrittentoaPROJECTconfigfile. +$my-bin-builderinit +#CreateanAPIandwebhookwith"go.example.com/v1"CreateAPIand +#CreateWebhookpluginmethods.Thiskeywasreadfromtheconfigfile. +$my-bin-buildercreateapi[flags] +$my-bin-buildercreatewebhook[flags] ``` -Selecting a plugin using `--plugins`: +Selectingapluginusing`--plugins`: ```sh -# Initialize a project with the "ansible.example.com/v1" Init plugin. -# Like above, this key is written to a config file. -$ my-bin-builder init --plugins ansible -# Create an API and webhook with "ansible.example.com/v1" CreateAPI -# and CreateWebhook plugin methods. This key was read from the config file. -$ my-bin-builder create api [flags] -$ my-bin-builder create webhook [flags] +#Initializeaprojectwiththe"ansible.example.com/v1"Initplugin. +#Likeabove,thiskeyiswrittentoaconfigfile. +$my-bin-builderinit--pluginsansible +#CreateanAPIandwebhookwith"ansible.example.com/v1"CreateAPI +#andCreateWebhookpluginmethods.Thiskeywasreadfromtheconfigfile. +$my-bin-buildercreateapi[flags] +$my-bin-buildercreatewebhook[flags] ``` -### CLI manages the PROJECT file +###CLImanagesthePROJECTfile -The CLI is responsible for managing the [PROJECT file config][project-file-config], representing the configuration of the projects that are scaffold by the CLI tool. +TheCLIisresponsibleformanagingthe[PROJECTfileconfig][project-file-config],representingtheconfigurationoftheprojectsthatarescaffoldbytheCLItool. -## Plugins +##Plugins -Kubebuilder provides scaffolding options via plugins. Plugins are responsible for implementing the code that will be executed when the sub-commands are called. You can create a new plugin by implementing the [Plugin interface][plugin-interface]. +Kubebuilderprovidesscaffoldingoptionsviaplugins.Pluginsareresponsibleforimplementingthecodethatwillbeexecutedwhenthesub-commandsarecalled.Youcancreateanewpluginbyimplementingthe[Plugininterface][plugin-interface]. -On top of being a `Base`, a plugin should also implement the [`SubcommandMetadata`][plugin-subc] interface so it can be run with a CLI. It optionally to set custom help text for the target command; this method can be a no-op, which will preserve the default help text set by the [cobra][cobra] command constructors. +Ontopofbeinga`Base`,apluginshouldalsoimplementthe[`SubcommandMetadata`][plugin-subc]interfacesoitcanberunwithaCLI.Itoptionallytosetcustomhelptextforthetargetcommand;thismethodcanbeano-op,whichwillpreservethedefaulthelptextsetbythe[cobra][cobra]commandconstructors. -Kubebuilder CLI plugins wrap scaffolding and CLI features in conveniently packaged Go types that are executed by the -`kubebuilder` binary, or any binary which imports them. More specifically, a plugin configures the execution of one -of the following CLI commands: +KubebuilderCLIpluginswrapscaffoldingandCLIfeaturesinconvenientlypackagedGotypesthatareexecutedbythe +`kubebuilder`binary,oranybinarywhichimportsthem.Morespecifically,apluginconfigurestheexecutionofone +ofthefollowingCLIcommands: -- `init`: project initialization. -- `create api`: scaffold Kubernetes API definitions. -- `create webhook`: scaffold Kubernetes webhooks. +-`init`:projectinitialization. +-`createapi`:scaffoldKubernetesAPIdefinitions. +-`createwebhook`:scaffoldKuberneteswebhooks. -Plugins are identified by a key of the form `/`. There are two ways to specify a plugin to run: +Pluginsareidentifiedbyakeyoftheform`/`.Therearetwowaystospecifyaplugintorun: -- Setting `kubebuilder init --plugins=`, which will initialize a project configured for plugin with key - ``. - -- A `layout: ` in the scaffolded [PROJECT configuration file][project-file]. Commands (except for `init`, which scaffolds this file) will look at this value before running to choose which plugin to run. +-Setting`kubebuilderinit--plugins=`,whichwillinitializeaprojectconfiguredforpluginwithkey +``. -By default, `` will be `go.kubebuilder.io/vX`, where `X` is some integer. +-A`layout:`inthescaffolded[PROJECTconfigurationfile][project-file].Commands(exceptfor`init`,whichscaffoldsthisfile)willlookatthisvaluebeforerunningtochoosewhichplugintorun. -For a full implementation example, check out Kubebuilder's native [`go.kubebuilder.io`][kb-go-plugin] plugin. +Bydefault,``willbe`go.kubebuilder.io/vX`,where`X`issomeinteger. -### Plugin naming +Forafullimplementationexample,checkoutKubebuilder'snative[`go.kubebuilder.io`][kb-go-plugin]plugin. -Plugin names must be DNS1123 labels and should be fully qualified, i.e. they have a suffix like -`.example.com`. For example, the base Go scaffold used with `kubebuilder` commands has name `go.kubebuilder.io`. -Qualified names prevent conflicts between plugin names; both `go.kubebuilder.io` and `go.example.com` can both scaffold -Go code and can be specified by a user. +###Pluginnaming -### Plugin versioning +PluginnamesmustbeDNS1123labelsandshouldbefullyqualified,i.e.theyhaveasuffixlike +`.example.com`.Forexample,thebaseGoscaffoldusedwith`kubebuilder`commandshasname`go.kubebuilder.io`. +Qualifiednamespreventconflictsbetweenpluginnames;both`go.kubebuilder.io`and`go.example.com`canbothscaffold +Gocodeandcanbespecifiedbyauser. -A plugin's `Version()` method returns a [`plugin.Version`][plugin-version-type] object containing an integer value -and optionally a stage string of either "alpha" or "beta". The integer denotes the current version of a plugin. -Two different integer values between versions of plugins indicate that the two plugins are incompatible. The stage -string denotes plugin stability: +###Pluginversioning -- `alpha`: should be used for plugins that are frequently changed and may break between uses. -- `beta`: should be used for plugins that are only changed in minor ways, ex. bug fixes. +Aplugin's`Version()`methodreturnsa[`plugin.Version`][plugin-version-type]objectcontaininganintegervalue +andoptionallyastagestringofeither"alpha"or"beta".Theintegerdenotesthecurrentversionofaplugin. +Twodifferentintegervaluesbetweenversionsofpluginsindicatethatthetwopluginsareincompatible.Thestage +stringdenotespluginstability: -### Breaking changes +-`alpha`:shouldbeusedforpluginsthatarefrequentlychangedandmaybreakbetweenuses. +-`beta`:shouldbeusedforpluginsthatareonlychangedinminorways,ex.bugfixes. -Any change that will break a project scaffolded by the previous plugin version is a breaking change. +###Breakingchanges -### Plugins Deprecation +Anychangethatwillbreakaprojectscaffoldedbythepreviouspluginversionisabreakingchange. -Once a plugin is deprecated, have it implement a [Deprecated][deprecate-plugin-doc] interface so a deprecation warning will be printed when it is used. +###PluginsDeprecation -## Bundle Plugins +Onceapluginisdeprecated,haveitimplementa[Deprecated][deprecate-plugin-doc]interfacesoadeprecationwarningwillbeprintedwhenitisused. -[Bundle Plugins][bundle-plugin-doc] allow you to create a plugin that is a composition of many plugins: +##BundlePlugins + +[BundlePlugins][bundle-plugin-doc]allowyoutocreateapluginthatisacompositionofmanyplugins: ```go - // see that will be like myplugin.example/v1` - myPluginBundle, _ := plugin.NewBundle(plugin.WithName(``), - plugin.WithVersion(``), - plugin.WithPlugins(pluginA.Plugin{}, pluginB.Plugin{}, pluginC.Plugin{}), - ) +//seethatwillbelikemyplugin.example/v1` +myPluginBundle,_:=plugin.NewBundle(plugin.WithName(``), +plugin.WithVersion(``), +plugin.WithPlugins(pluginA.Plugin{},pluginB.Plugin{},pluginC.Plugin{}), +) ``` -Note that it means that when a user of your CLI calls this plugin, the execution of the sub-commands will be sorted by the order to which they were added in a chain: +NotethatitmeansthatwhenauserofyourCLIcallsthisplugin,theexecutionofthesub-commandswillbesortedbytheordertowhichtheywereaddedinachain: -> `sub-command` of plugin A ➔ `sub-command` of plugin B ➔ `sub-command` of plugin C +>`sub-command`ofpluginA➔`sub-command`ofpluginB➔`sub-command`ofpluginC -Then, to initialize using this "Plugin Bundle" which will run the chain of plugins: +Then,toinitializeusingthis"PluginBundle"whichwillrunthechainofplugins: ``` -kubebuider init --plugins=myplugin.example/v1 -``` - -- Runs init `sub-command` of the plugin A -- And then, runs init `sub-command` of the plugin B -- And then, runs init `sub-command` of the plugin C - -[project-file-config]: ../reference/project-config.md -[plugin-interface]: https://pkg.go.dev/sigs.k8s.io/kubebuilder/v3/pkg/plugin#Plugin -[go-dev-doc]: https://pkg.go.dev/sigs.k8s.io/kubebuilder/v3 -[plugin-sub-command]: https://pkg.go.dev/sigs.k8s.io/kubebuilder/v3/pkg/plugin#Subcommand -[project-file]: ../reference/project-config.md -[plugin-subc]: https://pkg.go.dev/sigs.k8s.io/kubebuilder/v3/pkg/plugin#Subcommand +kubebuiderinit--plugins=myplugin.example/v1 +``` + +-Runsinit`sub-command`ofthepluginA +-Andthen,runsinit`sub-command`ofthepluginB +-Andthen,runsinit`sub-command`ofthepluginC + +[project-file-config]:../reference/project-config.md +[plugin-interface]:https://pkg.go.dev/sigs.k8s.io/kubebuilder/v3/pkg/plugin#Plugin +[go-dev-doc]:https://pkg.go.dev/sigs.k8s.io/kubebuilder/v3 +[plugin-sub-command]:https://pkg.go.dev/sigs.k8s.io/kubebuilder/v3/pkg/plugin#Subcommand +[project-file]:../reference/project-config.md +[plugin-subc]:https://pkg.go.dev/sigs.k8s.io/kubebuilder/v3/pkg/plugin#Subcommand [cobra]:https://pkg.go.dev/github.com/spf13/cobra -[kb-go-plugin]: https://pkg.go.dev/sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/v3 -[bundle-plugin-doc]: https://pkg.go.dev/sigs.k8s.io/kubebuilder/v3/pkg/plugin#Bundle -[deprecate-plugin-doc]: https://pkg.go.dev/sigs.k8s.io/kubebuilder/v3/pkg/plugin#Deprecated -[plugin-update-meta]: https://pkg.go.dev/sigs.k8s.io/kubebuilder/v3/pkg/plugin#UpdatesMetadata -[cli]: https://pkg.go.dev/sigs.k8s.io/kubebuilder/v3/pkg/cli -[plugin-version-type]: https://pkg.go.dev/sigs.k8s.io/kubebuilder/v3/pkg/plugin#Version +[kb-go-plugin]:https://pkg.go.dev/sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/v3 +[bundle-plugin-doc]:https://pkg.go.dev/sigs.k8s.io/kubebuilder/v3/pkg/plugin#Bundle +[deprecate-plugin-doc]:https://pkg.go.dev/sigs.k8s.io/kubebuilder/v3/pkg/plugin#Deprecated +[plugin-update-meta]:https://pkg.go.dev/sigs.k8s.io/kubebuilder/v3/pkg/plugin#UpdatesMetadata +[cli]:https://pkg.go.dev/sigs.k8s.io/kubebuilder/v3/pkg/cli +[plugin-version-type]:https://pkg.go.dev/sigs.k8s.io/kubebuilder/v3/pkg/plugin#Version diff --git a/docs/book/src/plugins/external-plugins.md b/docs/book/src/plugins/external-plugins.md index c8a545ae706..a7b049e3df2 100644 --- a/docs/book/src/plugins/external-plugins.md +++ b/docs/book/src/plugins/external-plugins.md @@ -1,162 +1,162 @@ -# Creating External Plugins +#CreatingExternalPlugins -## Overview +##Overview -Kubebuilder's functionality can be extended through the use of external plugins. +Kubebuilder'sfunctionalitycanbeextendedthroughtheuseofexternalplugins. -An external plugin is an executable (can be written in any language) that implements an execution pattern that Kubebuilder knows how to interact with. +Anexternalpluginisanexecutable(canbewritteninanylanguage)thatimplementsanexecutionpatternthatKubebuilderknowshowtointeractwith. -The Kubebuilder CLI loads the external plugin in the specified path and interacts with it through `stdin` & `stdout`. +TheKubebuilderCLIloadstheexternalplugininthespecifiedpathandinteractswithitthrough`stdin`&`stdout`. -## When is it useful? +##Whenisituseful? -- If you want to create helpers or addons on top of the scaffolds done by Kubebuilder's default scaffolding. +-IfyouwanttocreatehelpersoraddonsontopofthescaffoldsdonebyKubebuilder'sdefaultscaffolding. -- If you design customized layouts and want to take advantage of functions from Kubebuilder library. +-IfyoudesigncustomizedlayoutsandwanttotakeadvantageoffunctionsfromKubebuilderlibrary. -- If you are looking for implementing plugins in a language other than `Go`. +-Ifyouarelookingforimplementingpluginsinalanguageotherthan`Go`. -## How to write it? +##Howtowriteit? -The inter-process communication between your external plugin and Kubebuilder is through the standard I/O. +Theinter-processcommunicationbetweenyourexternalpluginandKubebuilderisthroughthestandardI/O. -Your external plugin can be written in any language, given it adheres to the [PluginRequest][PluginRequest] and [PluginResponse][PluginResponse] type structures. +Yourexternalplugincanbewritteninanylanguage,givenitadherestothe[PluginRequest][PluginRequest]and[PluginResponse][PluginResponse]typestructures. -`PluginRequest` encompasses all the data Kubebuilder collects from the CLI and previously executed plugins in the plugin chain. -Kubebuilder conveys the marshaled PluginRequest (a `JSON` object) to the external plugin over `stdin`. +`PluginRequest`encompassesallthedataKubebuildercollectsfromtheCLIandpreviouslyexecutedpluginsinthepluginchain. +KubebuilderconveysthemarshaledPluginRequest(a`JSON`object)totheexternalpluginover`stdin`. -Below is a sample JSON object of the `PluginRequest` type, triggered by `kubebuilder init --plugins sampleexternalplugin/v1 --domain my.domain`: +BelowisasampleJSONobjectofthe`PluginRequest`type,triggeredby`kubebuilderinit--pluginssampleexternalplugin/v1--domainmy.domain`: ```json { - "apiVersion": "v1alpha1", - "args": ["--domain", "my.domain"], - "command": "init", - "universe": {} +"apiVersion":"v1alpha1", +"args":["--domain","my.domain"], +"command":"init", +"universe":{} } ``` -`PluginResponse` represents the updated state of the project, as modified by the plugin. This data structure is serialized into `JSON` and sent back to Kubebuilder via `stdout`. +`PluginResponse`representstheupdatedstateoftheproject,asmodifiedbytheplugin.Thisdatastructureisserializedinto`JSON`andsentbacktoKubebuildervia`stdout`. -Here is a sample JSON representation of the `PluginResponse` type: +HereisasampleJSONrepresentationofthe`PluginResponse`type: ```json { - "apiVersion": "v1alpha1", - "command": "init", - "metadata": { - "description": "The `init` subcommand is meant to initialize a project via Kubebuilder. It scaffolds a single file: `initFile`", - "examples": "kubebuilder init --plugins sampleexternalplugin/v1 --domain my.domain" - }, - "universe": { - "initFile": "A simple file created with the `init` subcommand" - }, - "error": false, - "errorMsgs": [] +"apiVersion":"v1alpha1", +"command":"init", +"metadata":{ +"description":"The`init`subcommandismeanttoinitializeaprojectviaKubebuilder.Itscaffoldsasinglefile:`initFile`", +"examples":"kubebuilderinit--pluginssampleexternalplugin/v1--domainmy.domain" +}, +"universe":{ +"initFile":"Asimplefilecreatedwiththe`init`subcommand" +}, +"error":false, +"errorMsgs":[] } ``` -In this example, the `init` command of the plugin has created a new file called `initFile`. +Inthisexample,the`init`commandofthepluginhascreatedanewfilecalled`initFile`. -The content of this file is: `A simple file created with the init subcommand`, which is recorded in the `universe` field of the response. +Thecontentofthisfileis:`Asimplefilecreatedwiththeinitsubcommand`,whichisrecordedinthe`universe`fieldoftheresponse. -This output is then sent back to Kubebuilder, allowing it to incorporate the changes made by the plugin into the project. +ThisoutputisthensentbacktoKubebuilder,allowingittoincorporatethechangesmadebythepluginintotheproject. - -## How to use it? +##Howtouseit? -### Prerequisites -- kubebuilder CLI > 3.11.0 -- An executable for the external plugin. +###Prerequisites +-kubebuilderCLI>3.11.0 +-Anexecutablefortheexternalplugin. - This could be a plugin that you've created yourself, or one from an external source. -- Configuration of the external plugin's path. +Thiscouldbeapluginthatyou'vecreatedyourself,oronefromanexternalsource. +-Configurationoftheexternalplugin'spath. - This can be done by setting the `${EXTERNAL_PLUGINS_PATH}` environment variable, or by placing the plugin in a path that follows a `group-like name and version` scheme: +Thiscanbedonebysettingthe`${EXTERNAL_PLUGINS_PATH}`environmentvariable,orbyplacingtheplugininapaththatfollowsa`group-likenameandversion`scheme: ```sh -# for Linux +#forLinux $HOME/.config/kubebuilder/plugins/${name}/${version}/${name} -# for OSX -~/Library/Application Support/kubebuilder/plugins/${name}/${version}/${name} +#forOSX +~/Library/ApplicationSupport/kubebuilder/plugins/${name}/${version}/${name} ``` -As an example, if you're on Linux and you want to use `v2` of an external plugin called `foo.acme.io`, you'd place the executable in the folder `$HOME/.config/kubebuilder/plugins/foo.acme.io/v2/` with a file name that also matches the plugin name up to an (optional) file extension. -In other words, passing the flag `--plugins=foo.acme.io/v2` to `kubebuilder` would find the plugin at either of these locations -* `$HOME/.config/kubebuilder/plugins/foo.acme.io/v2/foo.acme.io` -* `$HOME/.config/kubebuilder/plugins/foo.acme.io/v2/foo.acme.io.sh` -* `$HOME/.config/kubebuilder/plugins/foo.acme.io/v2/foo.acme.io.py` -* etc... +Asanexample,ifyou'reonLinuxandyouwanttouse`v2`ofanexternalplugincalled`foo.acme.io`,you'dplacetheexecutableinthefolder`$HOME/.config/kubebuilder/plugins/foo.acme.io/v2/`withafilenamethatalsomatchesthepluginnameuptoan(optional)fileextension. +Inotherwords,passingtheflag`--plugins=foo.acme.io/v2`to`kubebuilder`wouldfindthepluginateitheroftheselocations +*`$HOME/.config/kubebuilder/plugins/foo.acme.io/v2/foo.acme.io` +*`$HOME/.config/kubebuilder/plugins/foo.acme.io/v2/foo.acme.io.sh` +*`$HOME/.config/kubebuilder/plugins/foo.acme.io/v2/foo.acme.io.py` +*etc... -### Subcommands: +###Subcommands: -The external plugin supports the same subcommands as kubebuilder already provides: -- `init`: project initialization. -- `create api`: scaffold Kubernetes API definitions. -- `create webhook`: scaffold Kubernetes webhooks. -- `edit`: update the project configuration. +Theexternalpluginsupportsthesamesubcommandsaskubebuilderalreadyprovides: +-`init`:projectinitialization. +-`createapi`:scaffoldKubernetesAPIdefinitions. +-`createwebhook`:scaffoldKuberneteswebhooks. +-`edit`:updatetheprojectconfiguration. -Also, there are **Optional** subcommands for a better user experience: -- `metadata`: add customized plugin description and examples when a `--help` flag is specified. -- `flags`: specify valid flags for Kubebuilder to pass to the external plugin. +Also,thereare**Optional**subcommandsforabetteruserexperience: +-`metadata`:addcustomizedplugindescriptionandexampleswhena`--help`flagisspecified. +-`flags`:specifyvalidflagsforKubebuildertopasstotheexternalplugin. - -### Configuration +###Configuration -You can configure your plugin path with a ENV VAR `$EXTERNAL_PLUGINS_PATH` to tell Kubebuilder where to search for the plugin binary, such as: +YoucanconfigureyourpluginpathwithaENVVAR`$EXTERNAL_PLUGINS_PATH`totellKubebuilderwheretosearchforthepluginbinary,suchas: ```sh -export EXTERNAL_PLUGINS_PATH = +exportEXTERNAL_PLUGINS_PATH= ``` -Otherwise, Kubebuilder would search for the plugins in a default path based on your OS. +Otherwise,KubebuilderwouldsearchforthepluginsinadefaultpathbasedonyourOS. -Now, you can using it by calling the CLI commands: +Now,youcanusingitbycallingtheCLIcommands: ```sh -# Initialize a new project with the external plugin named `sampleplugin` -kubebuilder init --plugins sampleplugin/v1 +#Initializeanewprojectwiththeexternalpluginnamed`sampleplugin` +kubebuilderinit--pluginssampleplugin/v1 -# Display help information of the `init` subcommand of the external plugin -kubebuilder init --plugins sampleplugin/v1 --help +#Displayhelpinformationofthe`init`subcommandoftheexternalplugin +kubebuilderinit--pluginssampleplugin/v1--help -# Create a new API with the above external plugin with a customized flag `number` -kubebuilder create api --plugins sampleplugin/v1 --number 2 +#CreateanewAPIwiththeaboveexternalpluginwithacustomizedflag`number` +kubebuildercreateapi--pluginssampleplugin/v1--number2 -# Create a webhook with the above external plugin with a customized flag `hooked` -kubebuilder create webhook --plugins sampleplugin/v1 --hooked +#Createawebhookwiththeaboveexternalpluginwithacustomizedflag`hooked` +kubebuildercreatewebhook--pluginssampleplugin/v1--hooked -# Update the project configuration with the above external plugin -kubebuilder edit --plugins sampleplugin/v1 +#Updatetheprojectconfigurationwiththeaboveexternalplugin +kubebuilderedit--pluginssampleplugin/v1 -# Create new APIs with external plugins v1 and v2 by respecting the plugin chaining order -kubebuilder create api --plugins sampleplugin/v1,sampleplugin/v2 +#CreatenewAPIswithexternalpluginsv1andv2byrespectingthepluginchainingorder +kubebuildercreateapi--pluginssampleplugin/v1,sampleplugin/v2 -# Create new APIs with the go/v4 plugin and then pass those files to the external plugin by respecting the plugin chaining order -kubebuilder create api --plugins go/v4,sampleplugin/v1 +#CreatenewAPIswiththego/v4pluginandthenpassthosefilestotheexternalpluginbyrespectingthepluginchainingorder +kubebuildercreateapi--pluginsgo/v4,sampleplugin/v1 ``` -## Further resources +##Furtherresources -- Check the [design proposal of the external plugin](https://github.com/kubernetes-sigs/kubebuilder/blob/master/designs/extensible-cli-and-scaffolding-plugins-phase-2.md) -- Check the [plugin implementation](https://github.com/kubernetes-sigs/kubebuilder/pull/2338) -- A [sample external plugin written in Go](https://github.com/kubernetes-sigs/kubebuilder/tree/master/docs/book/src/simple-external-plugin-tutorial/testdata/sampleexternalplugin/v1) -- A [sample external plugin written in Python](https://github.com/rashmigottipati/POC-Phase2-Plugins) -- A [sample external plugin written in JavaScript](https://github.com/Eileen-Yu/kb-js-plugin) +-Checkthe[designproposaloftheexternalplugin](https://github.com/kubernetes-sigs/kubebuilder/blob/master/designs/extensible-cli-and-scaffolding-plugins-phase-2.md) +-Checkthe[pluginimplementation](https://github.com/kubernetes-sigs/kubebuilder/pull/2338) +-A[sampleexternalpluginwritteninGo](https://github.com/kubernetes-sigs/kubebuilder/tree/master/docs/book/src/simple-external-plugin-tutorial/testdata/sampleexternalplugin/v1) +-A[sampleexternalpluginwritteninPython](https://github.com/rashmigottipati/POC-Phase2-Plugins) +-A[sampleexternalpluginwritteninJavaScript](https://github.com/Eileen-Yu/kb-js-plugin) -[PluginRequest]: https://github.com/kubernetes-sigs/kubebuilder/blob/master/pkg/plugin/external/types.go#L23 -[PluginResponse]: https://github.com/kubernetes-sigs/kubebuilder/blob/master/pkg/plugin/external/types.go#L42 +[PluginRequest]:https://github.com/kubernetes-sigs/kubebuilder/blob/master/pkg/plugin/external/types.go#L23 +[PluginResponse]:https://github.com/kubernetes-sigs/kubebuilder/blob/master/pkg/plugin/external/types.go#L42 diff --git a/docs/book/src/plugins/go-v2-plugin.md b/docs/book/src/plugins/go-v2-plugin.md index 3c2d3f18a23..ebdffe2b311 100644 --- a/docs/book/src/plugins/go-v2-plugin.md +++ b/docs/book/src/plugins/go-v2-plugin.md @@ -1,75 +1,75 @@ -# [Deprecated] go/v2 (go.kubebuilder.io/v2 - "Kubebuilder 2.x" layout) +#[Deprecated]go/v2(go.kubebuilder.io/v2-"Kubebuilder2.x"layout) - -The `go/v2` plugin has the purpose to scaffold Golang projects to help users -to build projects with [controllers][controller-runtime] and keep the backwards compatibility -with the default scaffold made using Kubebuilder CLI `2.x.z` releases. +The`go/v2`pluginhasthepurposetoscaffoldGolangprojectstohelpusers +tobuildprojectswith[controllers][controller-runtime]andkeepthebackwardscompatibility +withthedefaultscaffoldmadeusingKubebuilderCLI`2.x.z`releases. - -## When should I use this plugin ? +##WhenshouldIusethisplugin? -Only if you are looking to scaffold a project with the legacy layout. Otherwise, it is recommended you to use the default Golang version plugin. +Onlyifyouarelookingtoscaffoldaprojectwiththelegacylayout.Otherwise,itisrecommendedyoutousethedefaultGolangversionplugin. - -## How to use it ? +##Howtouseit? -To initialize a Golang project using the legacy layout and with this plugin run, e.g.: +ToinitializeaGolangprojectusingthelegacylayoutandwiththispluginrun,e.g.: ```sh -kubebuilder init --domain tutorial.kubebuilder.io --repo tutorial.kubebuilder.io/project --plugins=go/v2 +kubebuilderinit--domaintutorial.kubebuilder.io--repotutorial.kubebuilder.io/project--plugins=go/v2 ``` - -## Subcommands supported by the plugin ? +##Subcommandssupportedbytheplugin? -- Init - `kubebuilder init [OPTIONS]` -- Edit - `kubebuilder edit [OPTIONS]` -- Create API - `kubebuilder create api [OPTIONS]` -- Create Webhook - `kubebuilder create webhook [OPTIONS]` +-Init-`kubebuilderinit[OPTIONS]` +-Edit-`kubebuilderedit[OPTIONS]` +-CreateAPI-`kubebuildercreateapi[OPTIONS]` +-CreateWebhook-`kubebuildercreatewebhook[OPTIONS]` -## Further resources +##Furtherresources -- Check the code implementation of the [go/v2 plugin][v2-plugin]. +-Checkthecodeimplementationofthe[go/v2plugin][v2-plugin]. -[controller-runtime]: https://github.com/kubernetes-sigs/controller-runtime -[testdata]: https://github.com/kubernetes-sigs/kubebuilder/tree/master/testdata -[v2-plugin]: https://github.com/kubernetes-sigs/kubebuilder/tree/master/pkg/plugins/golang/v2 \ No newline at end of file +[controller-runtime]:https://github.com/kubernetes-sigs/controller-runtime +[testdata]:https://github.com/kubernetes-sigs/kubebuilder/tree/master/testdata +[v2-plugin]:https://github.com/kubernetes-sigs/kubebuilder/tree/master/pkg/plugins/golang/v2 \ No newline at end of file diff --git a/docs/book/src/plugins/go-v3-plugin.md b/docs/book/src/plugins/go-v3-plugin.md index 21613773f7f..9c0464051ef 100644 --- a/docs/book/src/plugins/go-v3-plugin.md +++ b/docs/book/src/plugins/go-v3-plugin.md @@ -1,70 +1,70 @@ -# [Deprecated] go/v3 (go.kubebuilder.io/v3) +#[Deprecated]go/v3(go.kubebuilder.io/v3) - -Kubebuilder tool will scaffold the go/v3 plugin by default. This plugin is a composition of the plugins ` kustomize.common.kubebuilder.io/v1` and `base.go.kubebuilder.io/v3`. By using you can scaffold the default project which is a helper to construct sets of [controllers][controller-runtime]. +Kubebuildertoolwillscaffoldthego/v3pluginbydefault.Thispluginisacompositionoftheplugins`kustomize.common.kubebuilder.io/v1`and`base.go.kubebuilder.io/v3`.Byusingyoucanscaffoldthedefaultprojectwhichisahelpertoconstructsetsof[controllers][controller-runtime]. -It basically scaffolds all the boilerplate code required to create and design controllers. Note that by following the [quickstart][quickstart] you will be using this plugin. +Itbasicallyscaffoldsalltheboilerplatecoderequiredtocreateanddesigncontrollers.Notethatbyfollowingthe[quickstart][quickstart]youwillbeusingthisplugin. - -## When to use it ? +##Whentouseit? -If you are looking to scaffold Golang projects to develop projects using [controllers][controller-runtime] +IfyouarelookingtoscaffoldGolangprojectstodevelopprojectsusing[controllers][controller-runtime] -## How to use it ? +##Howtouseit? -As `go/v3` is the default plugin there is no need to explicitly mention to Kubebuilder to use this plugin. +As`go/v3`isthedefaultpluginthereisnoneedtoexplicitlymentiontoKubebuildertousethisplugin. -To create a new project with the `go/v3` plugin the following command can be used: +Tocreateanewprojectwiththe`go/v3`pluginthefollowingcommandcanbeused: ```sh -kubebuilder init --plugins=`go/v3` --domain tutorial.kubebuilder.io --repo tutorial.kubebuilder.io/project +kubebuilderinit--plugins=`go/v3`--domaintutorial.kubebuilder.io--repotutorial.kubebuilder.io/project ``` -All the other subcommands supported by the go/v3 plugin can be executed similarly. +Alltheothersubcommandssupportedbythego/v3plugincanbeexecutedsimilarly. - + -## Subcommands supported by the plugin +##Subcommandssupportedbytheplugin -- Init - `kubebuilder init [OPTIONS]` -- Edit - `kubebuilder edit [OPTIONS]` -- Create API - `kubebuilder create api [OPTIONS]` -- Create Webhook - `kubebuilder create webhook [OPTIONS]` +-Init-`kubebuilderinit[OPTIONS]` +-Edit-`kubebuilderedit[OPTIONS]` +-CreateAPI-`kubebuildercreateapi[OPTIONS]` +-CreateWebhook-`kubebuildercreatewebhook[OPTIONS]` -## Further resources +##Furtherresources -- To check how plugins are composited by looking at this definition in the [main.go][plugins-main]. -- Check the code implementation of the [base Golang plugin `base.go.kubebuilder.io/v3`][v3-plugin]. -- Check the code implementation of the [Kustomize/v1 plugin][kustomize-plugin]. -- Check [controller-runtime][controller-runtime] to know more about controllers. +-Tocheckhowpluginsarecompositedbylookingatthisdefinitioninthe[main.go][plugins-main]. +-Checkthecodeimplementationofthe[baseGolangplugin`base.go.kubebuilder.io/v3`][v3-plugin]. +-Checkthecodeimplementationofthe[Kustomize/v1plugin][kustomize-plugin]. +-Check[controller-runtime][controller-runtime]toknowmoreaboutcontrollers. -[controller-runtime]: https://github.com/kubernetes-sigs/controller-runtime -[quickstart]: ../quick-start.md -[testdata]: https://github.com/kubernetes-sigs/kubebuilder/tree/master/testdata -[plugins-main]: https://github.com/kubernetes-sigs/kubebuilder/blob/master/cmd/main.go -[v3-plugin]: https://github.com/kubernetes-sigs/kubebuilder/tree/master/pkg/plugins/golang/v3 -[kustomize-plugin]: https://github.com/kubernetes-sigs/kubebuilder/tree/master/pkg/plugins/common/kustomize/v1 \ No newline at end of file +[controller-runtime]:https://github.com/kubernetes-sigs/controller-runtime +[quickstart]:../quick-start.md +[testdata]:https://github.com/kubernetes-sigs/kubebuilder/tree/master/testdata +[plugins-main]:https://github.com/kubernetes-sigs/kubebuilder/blob/master/cmd/main.go +[v3-plugin]:https://github.com/kubernetes-sigs/kubebuilder/tree/master/pkg/plugins/golang/v3 +[kustomize-plugin]:https://github.com/kubernetes-sigs/kubebuilder/tree/master/pkg/plugins/common/kustomize/v1 \ No newline at end of file diff --git a/docs/book/src/plugins/go-v4-plugin.md b/docs/book/src/plugins/go-v4-plugin.md index 6d7da044c21..5d2e840a0a8 100644 --- a/docs/book/src/plugins/go-v4-plugin.md +++ b/docs/book/src/plugins/go-v4-plugin.md @@ -1,60 +1,60 @@ -# [Default Scaffold] go/v4 (go.kubebuilder.io/v4) +#[DefaultScaffold]go/v4(go.kubebuilder.io/v4) -Kubebuilder will scaffold using the `go/v4` plugin only if specified when initializing the project. -This plugin is a composition of the plugins ` kustomize.common.kubebuilder.io/v2` and `base.go.kubebuilder.io/v4`. -It scaffolds a project template that helps in constructing sets of [controllers][controller-runtime]. +Kubebuilderwillscaffoldusingthe`go/v4`pluginonlyifspecifiedwheninitializingtheproject. +Thispluginisacompositionoftheplugins`kustomize.common.kubebuilder.io/v2`and`base.go.kubebuilder.io/v4`. +Itscaffoldsaprojecttemplatethathelpsinconstructingsetsof[controllers][controller-runtime]. -It scaffolds boilerplate code to create and design controllers. -Note that by following the [quickstart][quickstart] you will be using this plugin. - -## When to use it ? +##Whentouseit? -If you are looking to scaffold Golang projects to develop projects using [controllers][controller-runtime] +IfyouarelookingtoscaffoldGolangprojectstodevelopprojectsusing[controllers][controller-runtime] - -## How to use it ? +##Howtouseit? -To create a new project with the `go/v4` plugin the following command can be used: +Tocreateanewprojectwiththe`go/v4`pluginthefollowingcommandcanbeused: ```sh -kubebuilder init --domain tutorial.kubebuilder.io --repo tutorial.kubebuilder.io/project --plugins=go/v4 +kubebuilderinit--domaintutorial.kubebuilder.io--repotutorial.kubebuilder.io/project--plugins=go/v4 ``` -## Subcommands supported by the plugin +##Subcommandssupportedbytheplugin -- Init - `kubebuilder init [OPTIONS]` -- Edit - `kubebuilder edit [OPTIONS]` -- Create API - `kubebuilder create api [OPTIONS]` -- Create Webhook - `kubebuilder create webhook [OPTIONS]` +-Init-`kubebuilderinit[OPTIONS]` +-Edit-`kubebuilderedit[OPTIONS]` +-CreateAPI-`kubebuildercreateapi[OPTIONS]` +-CreateWebhook-`kubebuildercreatewebhook[OPTIONS]` -## Further resources +##Furtherresources -- To see the composition of plugins, you can check the source code for the Kubebuilder [main.go][plugins-main]. -- Check the code implementation of the [base Golang plugin `base.go.kubebuilder.io/v4`][v4-plugin]. -- Check the code implementation of the [Kustomize/v2 plugin][kustomize-plugin]. -- Check [controller-runtime][controller-runtime] to know more about controllers. +-Toseethecompositionofplugins,youcancheckthesourcecodefortheKubebuilder[main.go][plugins-main]. +-Checkthecodeimplementationofthe[baseGolangplugin`base.go.kubebuilder.io/v4`][v4-plugin]. +-Checkthecodeimplementationofthe[Kustomize/v2plugin][kustomize-plugin]. +-Check[controller-runtime][controller-runtime]toknowmoreaboutcontrollers. -[controller-runtime]: https://github.com/kubernetes-sigs/controller-runtime -[quickstart]: ../quick-start.md -[testdata]: https://github.com/kubernetes-sigs/kubebuilder/tree/master/testdata -[plugins-main]: https://github.com/kubernetes-sigs/kubebuilder/blob/master/cmd/main.go -[kustomize-plugin]: ../plugins/kustomize-v2.md -[kustomize]: https://github.com/kubernetes-sigs/kustomize -[standard-go-project]: https://github.com/golang-standards/project-layout -[v4-plugin]: https://github.com/kubernetes-sigs/kubebuilder/tree/master/pkg/plugins/golang/v4 +[controller-runtime]:https://github.com/kubernetes-sigs/controller-runtime +[quickstart]:../quick-start.md +[testdata]:https://github.com/kubernetes-sigs/kubebuilder/tree/master/testdata +[plugins-main]:https://github.com/kubernetes-sigs/kubebuilder/blob/master/cmd/main.go +[kustomize-plugin]:../plugins/kustomize-v2.md +[kustomize]:https://github.com/kubernetes-sigs/kustomize +[standard-go-project]:https://github.com/golang-standards/project-layout +[v4-plugin]:https://github.com/kubernetes-sigs/kubebuilder/tree/master/pkg/plugins/golang/v4 diff --git a/docs/book/src/plugins/grafana-v1-alpha.md b/docs/book/src/plugins/grafana-v1-alpha.md index 9f8c277be0b..a8e4403f459 100644 --- a/docs/book/src/plugins/grafana-v1-alpha.md +++ b/docs/book/src/plugins/grafana-v1-alpha.md @@ -1,243 +1,243 @@ -# Grafana Plugin (`grafana/v1-alpha`) +#GrafanaPlugin(`grafana/v1-alpha`) -The Grafana plugin is an optional plugin that can be used to scaffold Grafana Dashboards to allow you to check out the default metrics which are exported by projects using [controller-runtime][controller-runtime]. +TheGrafanapluginisanoptionalpluginthatcanbeusedtoscaffoldGrafanaDashboardstoallowyoutocheckoutthedefaultmetricswhichareexportedbyprojectsusing[controller-runtime][controller-runtime]. - -## When to use it ? +##Whentouseit? -- If you are looking to observe the metrics exported by [controller metrics][controller-metrics] and collected by Prometheus via [Grafana][grafana]. +-Ifyouarelookingtoobservethemetricsexportedby[controllermetrics][controller-metrics]andcollectedbyPrometheusvia[Grafana][grafana]. -## How to use it ? +##Howtouseit? -### Prerequisites: +###Prerequisites: -- Your project must be using [controller-runtime][controller-runtime] to expose the metrics via the [controller default metrics][controller-metrics] and they need to be collected by Prometheus. -- Access to [Prometheus][prometheus]. - - Prometheus should have an endpoint exposed. (For `prometheus-operator`, this is similar as: http://prometheus-k8s.monitoring.svc:9090 ) - - The endpoint is ready to/already become the datasource of your Grafana. See [Add a data source](https://grafana.com/docs/grafana/latest/datasources/add-a-data-source/) -- Access to [Grafana](https://grafana.com/docs/grafana/latest/setup-grafana/installation/). Make sure you have: - - [Dashboard edit permission](https://grafana.com/docs/grafana/next/administration/roles-and-permissions/#dashboard-permissions) - - Prometheus Data source - ![pre](https://user-images.githubusercontent.com/18136486/176119794-f6d69b0b-93f0-4f9e-a53c-daf9f77dadae.gif) +-Yourprojectmustbeusing[controller-runtime][controller-runtime]toexposethemetricsviathe[controllerdefaultmetrics][controller-metrics]andtheyneedtobecollectedbyPrometheus. +-Accessto[Prometheus][prometheus]. +-Prometheusshouldhaveanendpointexposed.(For`prometheus-operator`,thisissimilaras:http://prometheus-k8s.monitoring.svc:9090) +-Theendpointisreadyto/alreadybecomethedatasourceofyourGrafana.See[Addadatasource](https://grafana.com/docs/grafana/latest/datasources/add-a-data-source/) +-Accessto[Grafana](https://grafana.com/docs/grafana/latest/setup-grafana/installation/).Makesureyouhave: +-[Dashboardeditpermission](https://grafana.com/docs/grafana/next/administration/roles-and-permissions/#dashboard-permissions) +-PrometheusDatasource +![pre](https://user-images.githubusercontent.com/18136486/176119794-f6d69b0b-93f0-4f9e-a53c-daf9f77dadae.gif) - -### Basic Usage +###BasicUsage -The Grafana plugin is attached to the `init` subcommand and the `edit` subcommand: +TheGrafanapluginisattachedtothe`init`subcommandandthe`edit`subcommand: ```sh -# Initialize a new project with grafana plugin -kubebuilder init --plugins grafana.kubebuilder.io/v1-alpha +#Initializeanewprojectwithgrafanaplugin +kubebuilderinit--pluginsgrafana.kubebuilder.io/v1-alpha -# Enable grafana plugin to an existing project -kubebuilder edit --plugins grafana.kubebuilder.io/v1-alpha +#Enablegrafanaplugintoanexistingproject +kubebuilderedit--pluginsgrafana.kubebuilder.io/v1-alpha ``` -The plugin will create a new directory and scaffold the JSON files under it (i.e. `grafana/controller-runtime-metrics.json`). +ThepluginwillcreateanewdirectoryandscaffoldtheJSONfilesunderit(i.e.`grafana/controller-runtime-metrics.json`). -#### Show case: +####Showcase: -See an example of how to use the plugin in your project: +Seeanexampleofhowtousetheplugininyourproject: ![output](https://user-images.githubusercontent.com/18136486/175382307-9a6c3b8b-6cc7-4339-b221-2539d0fec042.gif) -#### Now, let's check how to use the Grafana dashboards - -1. Copy the JSON file -2. Visit `/dashboard/import` to [import a new dashboard](https://grafana.com/docs/grafana/latest/dashboards/export-import/#import-dashboard). -3. Paste the JSON content to `Import via panel json`, then press `Load` button - -4. Select the data source for Prometheus metrics - -5. Once the json is imported in Grafana, the dashboard is ready. - -### Grafana Dashboard - -#### Controller Runtime Reconciliation total & errors - -- Metrics: - - controller_runtime_reconcile_total - - controller_runtime_reconcile_errors_total -- Query: - - sum(rate(controller_runtime_reconcile_total{job="$job"}[5m])) by (instance, pod) - - sum(rate(controller_runtime_reconcile_errors_total{job="$job"}[5m])) by (instance, pod) -- Description: - - Per-second rate of total reconciliation as measured over the last 5 minutes - - Per-second rate of reconciliation errors as measured over the last 5 minutes -- Sample: - -#### Controller CPU & Memory Usage - -- Metrics: - - process_cpu_seconds_total - - process_resident_memory_bytes -- Query: - - rate(process_cpu_seconds_total{job="$job", namespace="$namespace", pod="$pod"}[5m]) \* 100 - - process_resident_memory_bytes{job="$job", namespace="$namespace", pod="$pod"} -- Description: - - Per-second rate of CPU usage as measured over the last 5 minutes - - Allocated Memory for the running controller -- Sample: - -#### Seconds of P50/90/99 Items Stay in Work Queue - -- Metrics - - workqueue_queue_duration_seconds_bucket -- Query: - - histogram_quantile(0.50, sum(rate(workqueue_queue_duration_seconds_bucket{job="$job", namespace="$namespace"}[5m])) by (instance, name, le)) -- Description - - Seconds an item stays in workqueue before being requested. -- Sample: - -#### Seconds of P50/90/99 Items Processed in Work Queue - -- Metrics - - workqueue_work_duration_seconds_bucket -- Query: - - histogram_quantile(0.50, sum(rate(workqueue_work_duration_seconds_bucket{job="$job", namespace="$namespace"}[5m])) by (instance, name, le)) -- Description - - Seconds of processing an item from workqueue takes. -- Sample: - -#### Add Rate in Work Queue - -- Metrics - - workqueue_adds_total -- Query: - - sum(rate(workqueue_adds_total{job="$job", namespace="$namespace"}[5m])) by (instance, name) -- Description - - Per-second rate of items added to work queue -- Sample: - -#### Retries Rate in Work Queue - -- Metrics - - workqueue_retries_total -- Query: - - sum(rate(workqueue_retries_total{job="$job", namespace="$namespace"}[5m])) by (instance, name) -- Description - - Per-second rate of retries handled by workqueue -- Sample: - -#### Number of Workers in Use - -- Metrics - - controller_runtime_active_workers -- Query: - - controller_runtime_active_workers{job="$job", namespace="$namespace"} -- Description - - The number of active controller workers -- Sample: - -#### WorkQueue Depth - -- Metrics - - workqueue_depth -- Query: - - workqueue_depth{job="$job", namespace="$namespace"} -- Description - - Current depth of workqueue -- Sample: - -#### Unfinished Seconds - -- Metrics - - workqueue_unfinished_work_seconds -- Query: - - rate(workqueue_unfinished_work_seconds{job="$job", namespace="$namespace"}[5m]) -- Description - - How many seconds of work has done that is in progress and hasn't been observed by work_duration. -- Sample: - -### Visualize Custom Metrics - -The Grafana plugin supports scaffolding manifests for custom metrics. - -#### Generate Config Template - -When the plugin is triggered for the first time, `grafana/custom-metrics/config.yaml` is generated. +####Now,let'scheckhowtousetheGrafanadashboards + +1.CopytheJSONfile +2.Visit`/dashboard/import`to[importanewdashboard](https://grafana.com/docs/grafana/latest/dashboards/export-import/#import-dashboard). +3.PastetheJSONcontentto`Importviapaneljson`,thenpress`Load`button + +4.SelectthedatasourceforPrometheusmetrics + +5.OncethejsonisimportedinGrafana,thedashboardisready. + +###GrafanaDashboard + +####ControllerRuntimeReconciliationtotal&errors + +-Metrics: +-controller_runtime_reconcile_total +-controller_runtime_reconcile_errors_total +-Query: +-sum(rate(controller_runtime_reconcile_total{job="$job"}[5m]))by(instance,pod) +-sum(rate(controller_runtime_reconcile_errors_total{job="$job"}[5m]))by(instance,pod) +-Description: +-Per-secondrateoftotalreconciliationasmeasuredoverthelast5minutes +-Per-secondrateofreconciliationerrorsasmeasuredoverthelast5minutes +-Sample: + +####ControllerCPU&MemoryUsage + +-Metrics: +-process_cpu_seconds_total +-process_resident_memory_bytes +-Query: +-rate(process_cpu_seconds_total{job="$job",namespace="$namespace",pod="$pod"}[5m])\*100 +-process_resident_memory_bytes{job="$job",namespace="$namespace",pod="$pod"} +-Description: +-Per-secondrateofCPUusageasmeasuredoverthelast5minutes +-AllocatedMemoryfortherunningcontroller +-Sample: + +####SecondsofP50/90/99ItemsStayinWorkQueue + +-Metrics +-workqueue_queue_duration_seconds_bucket +-Query: +-histogram_quantile(0.50,sum(rate(workqueue_queue_duration_seconds_bucket{job="$job",namespace="$namespace"}[5m]))by(instance,name,le)) +-Description +-Secondsanitemstaysinworkqueuebeforebeingrequested. +-Sample: + +####SecondsofP50/90/99ItemsProcessedinWorkQueue + +-Metrics +-workqueue_work_duration_seconds_bucket +-Query: +-histogram_quantile(0.50,sum(rate(workqueue_work_duration_seconds_bucket{job="$job",namespace="$namespace"}[5m]))by(instance,name,le)) +-Description +-Secondsofprocessinganitemfromworkqueuetakes. +-Sample: + +####AddRateinWorkQueue + +-Metrics +-workqueue_adds_total +-Query: +-sum(rate(workqueue_adds_total{job="$job",namespace="$namespace"}[5m]))by(instance,name) +-Description +-Per-secondrateofitemsaddedtoworkqueue +-Sample: + +####RetriesRateinWorkQueue + +-Metrics +-workqueue_retries_total +-Query: +-sum(rate(workqueue_retries_total{job="$job",namespace="$namespace"}[5m]))by(instance,name) +-Description +-Per-secondrateofretrieshandledbyworkqueue +-Sample: + +####NumberofWorkersinUse + +-Metrics +-controller_runtime_active_workers +-Query: +-controller_runtime_active_workers{job="$job",namespace="$namespace"} +-Description +-Thenumberofactivecontrollerworkers +-Sample: + +####WorkQueueDepth + +-Metrics +-workqueue_depth +-Query: +-workqueue_depth{job="$job",namespace="$namespace"} +-Description +-Currentdepthofworkqueue +-Sample: + +####UnfinishedSeconds + +-Metrics +-workqueue_unfinished_work_seconds +-Query: +-rate(workqueue_unfinished_work_seconds{job="$job",namespace="$namespace"}[5m]) +-Description +-Howmanysecondsofworkhasdonethatisinprogressandhasn'tbeenobservedbywork_duration. +-Sample: + +###VisualizeCustomMetrics + +TheGrafanapluginsupportsscaffoldingmanifestsforcustommetrics. + +####GenerateConfigTemplate + +Whenthepluginistriggeredforthefirsttime,`grafana/custom-metrics/config.yaml`isgenerated. ```yaml --- customMetrics: -# - metric: # Raw custom metric (required) -# type: # Metric type: counter/gauge/histogram (required) -# expr: # Prom_ql for the metric (optional) -# unit: # Unit of measurement, examples: s,none,bytes,percent,etc. (optional) +#-metric:#Rawcustommetric(required) +#type:#Metrictype:counter/gauge/histogram(required) +#expr:#Prom_qlforthemetric(optional) +#unit:#Unitofmeasurement,examples:s,none,bytes,percent,etc.(optional) ``` -#### Add Custom Metrics to Config +####AddCustomMetricstoConfig -You can enter multiple custom metrics in the file. For each element, you need to specify the `metric` and its `type`. -The Grafana plugin can automatically generate `expr` for visualization. -Alternatively, you can provide `expr` and the plugin will use the specified one directly. +Youcanentermultiplecustommetricsinthefile.Foreachelement,youneedtospecifythe`metric`andits`type`. +TheGrafanaplugincanautomaticallygenerate`expr`forvisualization. +Alternatively,youcanprovide`expr`andthepluginwillusethespecifiedonedirectly. ```yaml --- customMetrics: - - metric: memcached_operator_reconcile_total # Raw custom metric (required) - type: counter # Metric type: counter/gauge/histogram (required) - unit: none - - metric: memcached_operator_reconcile_time_seconds_bucket - type: histogram +-metric:memcached_operator_reconcile_total#Rawcustommetric(required) +type:counter#Metrictype:counter/gauge/histogram(required) +unit:none +-metric:memcached_operator_reconcile_time_seconds_bucket +type:histogram ``` -#### Scaffold Manifest +####ScaffoldManifest -Once `config.yaml` is configured, you can run `kubebuilder edit --plugins grafana.kubebuilder.io/v1-alpha` again. -This time, the plugin will generate `grafana/custom-metrics/custom-metrics-dashboard.json`, which can be imported to Grafana UI. +Once`config.yaml`isconfigured,youcanrun`kubebuilderedit--pluginsgrafana.kubebuilder.io/v1-alpha`again. +Thistime,thepluginwillgenerate`grafana/custom-metrics/custom-metrics-dashboard.json`,whichcanbeimportedtoGrafanaUI. -#### Show case: +####Showcase: -See an example of how to visualize your custom metrics: +Seeanexampleofhowtovisualizeyourcustommetrics: ![output2](https://user-images.githubusercontent.com/18136486/186933170-d2e0de71-e079-4d1b-906a-99a549d66ebf.gif) -## Subcommands +##Subcommands -The Grafana plugin implements the following subcommands: +TheGrafanapluginimplementsthefollowingsubcommands: -- edit (`$ kubebuilder edit [OPTIONS]`) +-edit(`$kubebuilderedit[OPTIONS]`) -- init (`$ kubebuilder init [OPTIONS]`) +-init(`$kubebuilderinit[OPTIONS]`) -## Affected files +##Affectedfiles -The following scaffolds will be created or updated by this plugin: +Thefollowingscaffoldswillbecreatedorupdatedbythisplugin: -- `grafana/*.json` +-`grafana/*.json` -## Further resources +##Furtherresources -- Check out [video to show how it works](https://youtu.be/-w_JjcV8jXc) -- Checkout the [video to show how the custom metrics feature works](https://youtu.be/x_0FHta2HXc) -- Refer to a sample of `servicemonitor` provided by [kustomize plugin][kustomize-plugin] -- Check the [plugin implementation][plugin-implementation] -- [Grafana Docs][grafana-docs] of importing JSON file -- The usage of servicemonitor by [Prometheus Operator][servicemonitor] +-Checkout[videotoshowhowitworks](https://youtu.be/-w_JjcV8jXc) +-Checkoutthe[videotoshowhowthecustommetricsfeatureworks](https://youtu.be/x_0FHta2HXc) +-Refertoasampleof`servicemonitor`providedby[kustomizeplugin][kustomize-plugin] +-Checkthe[pluginimplementation][plugin-implementation] +-[GrafanaDocs][grafana-docs]ofimportingJSONfile +-Theusageofservicemonitorby[PrometheusOperator][servicemonitor] -[controller-metrics]: https://book.kubebuilder.io/reference/metrics-reference.html -[controller-runtime]: https://github.com/kubernetes-sigs/controller-runtime -[grafana]: https://grafana.com/docs/grafana/next/ -[grafana-docs]: https://grafana.com/docs/grafana/latest/dashboards/export-import/#import-dashboard -[kustomize-plugin]: https://github.com/kubernetes-sigs/kubebuilder/blob/master/testdata/project-v3/config/prometheus/monitor.yaml -[kube-prometheus]: https://github.com/prometheus-operator/kube-prometheus -[plugin-implementation]: https://github.com/kubernetes-sigs/kubebuilder/tree/master/pkg/plugins/optional/grafana/alphav1 -[prometheus]: https://prometheus.io/docs/introduction/overview/ -[prom-operator]: https://prometheus-operator.dev/docs/prologue/introduction/ -[reference-metrics-doc]: https://book.kubebuilder.io/reference/metrics.html#exporting-metrics-for-prometheus -[servicemonitor]: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/user-guides/getting-started.md#related-resources -[testdata]: https://github.com/kubernetes-sigs/kubebuilder/tree/master/testdata +[controller-metrics]:https://book.kubebuilder.io/reference/metrics-reference.html +[controller-runtime]:https://github.com/kubernetes-sigs/controller-runtime +[grafana]:https://grafana.com/docs/grafana/next/ +[grafana-docs]:https://grafana.com/docs/grafana/latest/dashboards/export-import/#import-dashboard +[kustomize-plugin]:https://github.com/kubernetes-sigs/kubebuilder/blob/master/testdata/project-v3/config/prometheus/monitor.yaml +[kube-prometheus]:https://github.com/prometheus-operator/kube-prometheus +[plugin-implementation]:https://github.com/kubernetes-sigs/kubebuilder/tree/master/pkg/plugins/optional/grafana/alphav1 +[prometheus]:https://prometheus.io/docs/introduction/overview/ +[prom-operator]:https://prometheus-operator.dev/docs/prologue/introduction/ +[reference-metrics-doc]:https://book.kubebuilder.io/reference/metrics.html#exporting-metrics-for-prometheus +[servicemonitor]:https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/user-guides/getting-started.md#related-resources +[testdata]:https://github.com/kubernetes-sigs/kubebuilder/tree/master/testdata diff --git a/docs/book/src/plugins/kustomize-v1.md b/docs/book/src/plugins/kustomize-v1.md index b8c4d41351f..a61ce849836 100644 --- a/docs/book/src/plugins/kustomize-v1.md +++ b/docs/book/src/plugins/kustomize-v1.md @@ -1,124 +1,124 @@ -# [Deprecated] Kustomize (kustomize/v1) +#[Deprecated]Kustomize(kustomize/v1) - -The kustomize plugin allows you to scaffold all kustomize manifests used to work with the language plugins such as `go/v2` and `go/v3`. -By using the kustomize plugin, you can create your own language plugins and ensure that you will have the same configurations -and features provided by it. +Thekustomizepluginallowsyoutoscaffoldallkustomizemanifestsusedtoworkwiththelanguagepluginssuchas`go/v2`and`go/v3`. +Byusingthekustomizeplugin,youcancreateyourownlanguagepluginsandensurethatyouwillhavethesameconfigurations +andfeaturesprovidedbyit. - +Youmightwanttoconsiderusing[kustomize/v2](./kustomize-v2.md)ifyouarelookingtoscaffoldprojectsin +otherarchitectureenvironments.(i.e.ifyouarelookingtoscaffoldprojectswithAppleSilicon/M1(`darwin/arm64`)thisplugin +willnotwork,moreinfo:[kubernetes-sigs/kustomize#4612](https://github.com/kubernetes-sigs/kustomize/issues/4612)). + -Note that projects such as [Operator-sdk][sdk] consume the Kubebuilder project as a lib and provide options to work with other languages -like Ansible and Helm. The kustomize plugin allows them to easily keep a maintained configuration and ensure that all languages have -the same configuration. It is also helpful if you are looking to provide nice plugins which will perform changes on top of -what is scaffolded by default. With this approach we do not need to keep manually updating this configuration in all possible language plugins -which uses the same and we are also -able to create "helper" plugins which can work with many projects and languages. +Notethatprojectssuchas[Operator-sdk][sdk]consumetheKubebuilderprojectasalibandprovideoptionstoworkwithotherlanguages +likeAnsibleandHelm.Thekustomizepluginallowsthemtoeasilykeepamaintainedconfigurationandensurethatalllanguageshave +thesameconfiguration.Itisalsohelpfulifyouarelookingtoprovidenicepluginswhichwillperformchangesontopof +whatisscaffoldedbydefault.Withthisapproachwedonotneedtokeepmanuallyupdatingthisconfigurationinallpossiblelanguageplugins +whichusesthesameandwearealso +abletocreate"helper"pluginswhichcanworkwithmanyprojectsandlanguages. - + -## When to use it ? +##Whentouseit? -If you are looking to scaffold the kustomize configuration manifests for your own language plugin +Ifyouarelookingtoscaffoldthekustomizeconfigurationmanifestsforyourownlanguageplugin -## How to use it ? +##Howtouseit? -If you are looking to define that your language plugin should use kustomize use the [Bundle Plugin][bundle] -to specify that your language plugin is a composition with your plugin responsible for scaffold -all that is language specific and kustomize for its configuration, see: +Ifyouarelookingtodefinethatyourlanguagepluginshouldusekustomizeusethe[BundlePlugin][bundle] +tospecifythatyourlanguagepluginisacompositionwithyourpluginresponsibleforscaffold +allthatislanguagespecificandkustomizeforitsconfiguration,see: ```go - // Bundle plugin which built the golang projects scaffold by Kubebuilder go/v3 - // The follow code is creating a new plugin with its name and version via composition - // You can define that one plugin is composite by 1 or Many others plugins - gov3Bundle, _ := plugin.NewBundle(plugin.WithName(golang.DefaultNameQualifier), - plugin.WithVersion(plugin.Version{Number: 3}), - plugin.WithPlugins(kustomizecommonv1.Plugin{}, golangv3.Plugin{}), // scaffold the config/ directory and all kustomize files - // Scaffold the Golang files and all that specific for the language e.g. go.mod, apis, controllers - ) +//BundlepluginwhichbuiltthegolangprojectsscaffoldbyKubebuildergo/v3 +//Thefollowcodeiscreatinganewpluginwithitsnameandversionviacomposition +//Youcandefinethatonepluginiscompositeby1orManyothersplugins +gov3Bundle,_:=plugin.NewBundle(plugin.WithName(golang.DefaultNameQualifier), +plugin.WithVersion(plugin.Version{Number:3}), +plugin.WithPlugins(kustomizecommonv1.Plugin{},golangv3.Plugin{}),//scaffoldtheconfig/directoryandallkustomizefiles +//ScaffoldtheGolangfilesandallthatspecificforthelanguagee.g.go.mod,apis,controllers +) ``` -Also, with Kubebuilder, you can use kustomize alone via: +Also,withKubebuilder,youcanusekustomizealonevia: ```sh -kubebuilder init --plugins=kustomize/v1 -$ ls -la -total 24 -drwxr-xr-x 6 camilamacedo86 staff 192 31 Mar 09:56 . -drwxr-xr-x 11 camilamacedo86 staff 352 29 Mar 21:23 .. --rw------- 1 camilamacedo86 staff 129 26 Mar 12:01 .dockerignore --rw------- 1 camilamacedo86 staff 367 26 Mar 12:01 .gitignore --rw------- 1 camilamacedo86 staff 94 31 Mar 09:56 PROJECT -drwx------ 6 camilamacedo86 staff 192 31 Mar 09:56 config +kubebuilderinit--plugins=kustomize/v1 +$ls-la +total24 +drwxr-xr-x6camilamacedo86staff19231Mar09:56. +drwxr-xr-x11camilamacedo86staff35229Mar21:23.. +-rw-------1camilamacedo86staff12926Mar12:01.dockerignore +-rw-------1camilamacedo86staff36726Mar12:01.gitignore +-rw-------1camilamacedo86staff9431Mar09:56PROJECT +drwx------6camilamacedo86staff19231Mar09:56config ``` -Or combined with the base language plugins: +Orcombinedwiththebaselanguageplugins: ```sh -# Provides the same scaffold of go/v3 plugin which is a composition (kubebuilder init --plugins=go/v3) -kubebuilder init --plugins=kustomize/v1,base.go.kubebuilder.io/v3 --domain example.org --repo example.org/guestbook-operator +#Providesthesamescaffoldofgo/v3pluginwhichisacomposition(kubebuilderinit--plugins=go/v3) +kubebuilderinit--plugins=kustomize/v1,base.go.kubebuilder.io/v3--domainexample.org--repoexample.org/guestbook-operator ``` -## Subcommands +##Subcommands -The kustomize plugin implements the following subcommands: +Thekustomizepluginimplementsthefollowingsubcommands: -* init (`$ kubebuilder init [OPTIONS]`) -* create api (`$ kubebuilder create api [OPTIONS]`) -* create webhook (`$ kubebuilder create api [OPTIONS]`) +*init(`$kubebuilderinit[OPTIONS]`) +*createapi(`$kubebuildercreateapi[OPTIONS]`) +*createwebhook(`$kubebuildercreateapi[OPTIONS]`) - + -## Affected files +##Affectedfiles -The following scaffolds will be created or updated by this plugin: +Thefollowingscaffoldswillbecreatedorupdatedbythisplugin: -* `config/*` +*`config/*` -## Further resources +##Furtherresources -* Check the kustomize [plugin implementation](https://github.com/kubernetes-sigs/kubebuilder/tree/master/pkg/plugins/common/kustomize) -* Check the [kustomize documentation][kustomize-docs] -* Check the [kustomize repository][kustomize-github] +*Checkthekustomize[pluginimplementation](https://github.com/kubernetes-sigs/kubebuilder/tree/master/pkg/plugins/common/kustomize) +*Checkthe[kustomizedocumentation][kustomize-docs] +*Checkthe[kustomizerepository][kustomize-github] [sdk]:https://github.com/operator-framework/operator-sdk -[testdata]: https://github.com/kubernetes-sigs/kubebuilder/tree/master/testdata/ -[bundle]: https://github.com/kubernetes-sigs/kubebuilder/blob/master/pkg/plugin/bundle.go -[kustomize-create-api]: https://github.com/kubernetes-sigs/kubebuilder/blob/master/pkg/plugins/common/kustomize/v1/scaffolds/api.go#L72-L84 -[kustomize-docs]: https://kustomize.io/ -[kustomize-github]: https://github.com/kubernetes-sigs/kustomize \ No newline at end of file +[testdata]:https://github.com/kubernetes-sigs/kubebuilder/tree/master/testdata/ +[bundle]:https://github.com/kubernetes-sigs/kubebuilder/blob/master/pkg/plugin/bundle.go +[kustomize-create-api]:https://github.com/kubernetes-sigs/kubebuilder/blob/master/pkg/plugins/common/kustomize/v1/scaffolds/api.go#L72-L84 +[kustomize-docs]:https://kustomize.io/ +[kustomize-github]:https://github.com/kubernetes-sigs/kustomize \ No newline at end of file diff --git a/docs/book/src/plugins/kustomize-v2.md b/docs/book/src/plugins/kustomize-v2.md index b8ae3d9348d..0c39df407a6 100644 --- a/docs/book/src/plugins/kustomize-v2.md +++ b/docs/book/src/plugins/kustomize-v2.md @@ -1,116 +1,116 @@ -# [Default Scaffold] Kustomize v2 +#[DefaultScaffold]Kustomizev2 -The kustomize plugin allows you to scaffold all kustomize manifests used to work with the language base plugin `base.go.kubebuilder.io/v4`. -This plugin is used to generate the manifest under `config/` directory for the projects build within the go/v4 plugin (default scaffold). +Thekustomizepluginallowsyoutoscaffoldallkustomizemanifestsusedtoworkwiththelanguagebaseplugin`base.go.kubebuilder.io/v4`. +Thispluginisusedtogeneratethemanifestunder`config/`directoryfortheprojectsbuildwithinthego/v4plugin(defaultscaffold). -Note that projects such as [Operator-sdk][sdk] consume the Kubebuilder project as a lib and provide options to work with other languages -like Ansible and Helm. The kustomize plugin allows them to easily keep a maintained configuration and ensure that all languages have -the same configuration. It is also helpful if you are looking to provide nice plugins which will perform changes on top of -what is scaffolded by default. With this approach we do not need to keep manually updating this configuration in all possible language plugins -which uses the same and we are also -able to create "helper" plugins which can work with many projects and languages. +Notethatprojectssuchas[Operator-sdk][sdk]consumetheKubebuilderprojectasalibandprovideoptionstoworkwithotherlanguages +likeAnsibleandHelm.Thekustomizepluginallowsthemtoeasilykeepamaintainedconfigurationandensurethatalllanguageshave +thesameconfiguration.Itisalsohelpfulifyouarelookingtoprovidenicepluginswhichwillperformchangesontopof +whatisscaffoldedbydefault.Withthisapproachwedonotneedtokeepmanuallyupdatingthisconfigurationinallpossiblelanguageplugins +whichusesthesameandwearealso +abletocreate"helper"pluginswhichcanworkwithmanyprojectsandlanguages. - -## When to use it +##Whentouseit -- If you are looking to scaffold the kustomize configuration manifests for your own language plugin -- If you are looking for support on Apple Silicon (`darwin/arm64`). (_Before kustomize `4.x` the binary for this plataform is not provided_) -- If you are looking for to begin to try out the new syntax and features provide by kustomize v4 [(More info)][release-notes-v4] and v5 [(More info)][release-notes-v5] -- If you are NOT looking to build projects which will be used on Kubernetes cluster versions < `1.22` (_The new features provides by kustomize v4 are not officially supported and might not work with kubectl < `1.22`_) -- If you are NOT looking to rely on special URLs in resource fields -- If you want to use [replacements][kustomize-replacements] since [vars][kustomize-vars] are deprecated and might be removed soon +-Ifyouarelookingtoscaffoldthekustomizeconfigurationmanifestsforyourownlanguageplugin +-IfyouarelookingforsupportonAppleSilicon(`darwin/arm64`).(_Beforekustomize`4.x`thebinaryforthisplataformisnotprovided_) +-Ifyouarelookingfortobegintotryoutthenewsyntaxandfeaturesprovidebykustomizev4[(Moreinfo)][release-notes-v4]andv5[(Moreinfo)][release-notes-v5] +-IfyouareNOTlookingtobuildprojectswhichwillbeusedonKubernetesclusterversions<`1.22`(_Thenewfeaturesprovidesbykustomizev4arenotofficiallysupportedandmightnotworkwithkubectl<`1.22`_) +-IfyouareNOTlookingtorelyonspecialURLsinresourcefields +-Ifyouwanttouse[replacements][kustomize-replacements]since[vars][kustomize-vars]aredeprecatedandmightberemovedsoon -## How to use it +##Howtouseit -If you are looking to define that your language plugin should use kustomize use the [Bundle Plugin][bundle] -to specify that your language plugin is a composition with your plugin responsible for scaffold -all that is language specific and kustomize for its configuration, see: +Ifyouarelookingtodefinethatyourlanguagepluginshouldusekustomizeusethe[BundlePlugin][bundle] +tospecifythatyourlanguagepluginisacompositionwithyourpluginresponsibleforscaffold +allthatislanguagespecificandkustomizeforitsconfiguration,see: ```go -import ( +import( ... - kustomizecommonv2alpha "sigs.k8s.io/kubebuilder/v3/pkg/plugins/common/kustomize/v2" - golangv4 "sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/v4" +kustomizecommonv2alpha"sigs.k8s.io/kubebuilder/v3/pkg/plugins/common/kustomize/v2" +golangv4"sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/v4" ... ) - // Bundle plugin which built the golang projects scaffold by Kubebuilder go/v3 - // The follow code is creating a new plugin with its name and version via composition - // You can define that one plugin is composite by 1 or Many others plugins - gov3Bundle, _ := plugin.NewBundle(plugin.WithName(golang.DefaultNameQualifier), - plugin.WithVersion(plugin.Version{Number: 3}), - plugin.WithPlugins(kustomizecommonv2.Plugin{}, golangv3.Plugin{}), // scaffold the config/ directory and all kustomize files - // Scaffold the Golang files and all that specific for the language e.g. go.mod, apis, controllers - ) +//BundlepluginwhichbuiltthegolangprojectsscaffoldbyKubebuildergo/v3 +//Thefollowcodeiscreatinganewpluginwithitsnameandversionviacomposition +//Youcandefinethatonepluginiscompositeby1orManyothersplugins +gov3Bundle,_:=plugin.NewBundle(plugin.WithName(golang.DefaultNameQualifier), +plugin.WithVersion(plugin.Version{Number:3}), +plugin.WithPlugins(kustomizecommonv2.Plugin{},golangv3.Plugin{}),//scaffoldtheconfig/directoryandallkustomizefiles +//ScaffoldtheGolangfilesandallthatspecificforthelanguagee.g.go.mod,apis,controllers +) ``` -Also, with Kubebuilder, you can use kustomize/v2 alone via: +Also,withKubebuilder,youcanusekustomize/v2alonevia: ```sh -kubebuilder init --plugins=kustomize/v2 -$ ls -la -total 24 -drwxr-xr-x 6 camilamacedo86 staff 192 31 Mar 09:56 . -drwxr-xr-x 11 camilamacedo86 staff 352 29 Mar 21:23 .. --rw------- 1 camilamacedo86 staff 129 26 Mar 12:01 .dockerignore --rw------- 1 camilamacedo86 staff 367 26 Mar 12:01 .gitignore --rw------- 1 camilamacedo86 staff 94 31 Mar 09:56 PROJECT -drwx------ 6 camilamacedo86 staff 192 31 Mar 09:56 config +kubebuilderinit--plugins=kustomize/v2 +$ls-la +total24 +drwxr-xr-x6camilamacedo86staff19231Mar09:56. +drwxr-xr-x11camilamacedo86staff35229Mar21:23.. +-rw-------1camilamacedo86staff12926Mar12:01.dockerignore +-rw-------1camilamacedo86staff36726Mar12:01.gitignore +-rw-------1camilamacedo86staff9431Mar09:56PROJECT +drwx------6camilamacedo86staff19231Mar09:56config ``` -Or combined with the base language plugins: +Orcombinedwiththebaselanguageplugins: ```sh -# Provides the same scaffold of go/v3 plugin which is composition but with kustomize/v2 -kubebuilder init --plugins=kustomize/v2,base.go.kubebuilder.io/v4 --domain example.org --repo example.org/guestbook-operator +#Providesthesamescaffoldofgo/v3pluginwhichiscompositionbutwithkustomize/v2 +kubebuilderinit--plugins=kustomize/v2,base.go.kubebuilder.io/v4--domainexample.org--repoexample.org/guestbook-operator ``` -## Subcommands +##Subcommands -The kustomize plugin implements the following subcommands: +Thekustomizepluginimplementsthefollowingsubcommands: -* init (`$ kubebuilder init [OPTIONS]`) -* create api (`$ kubebuilder create api [OPTIONS]`) -* create webhook (`$ kubebuilder create api [OPTIONS]`) +*init(`$kubebuilderinit[OPTIONS]`) +*createapi(`$kubebuildercreateapi[OPTIONS]`) +*createwebhook(`$kubebuildercreateapi[OPTIONS]`) - -## Affected files +##Affectedfiles -The following scaffolds will be created or updated by this plugin: +Thefollowingscaffoldswillbecreatedorupdatedbythisplugin: -* `config/*` +*`config/*` -## Further resources +##Furtherresources -* Check the kustomize [plugin implementation](https://github.com/kubernetes-sigs/kubebuilder/tree/master/pkg/plugins/common/kustomize) -* Check the [kustomize documentation][kustomize-docs] -* Check the [kustomize repository][kustomize-github] -* Check the [release notes][release-notes-v5] for Kustomize v5.0.0 -* Check the [release notes][release-notes-v4] for Kustomuze v4.0.0 -* Also, you can compare the `config/` directory between the samples `project-v3` and `project-v4` to check the difference in the syntax of the manifests provided by default +*Checkthekustomize[pluginimplementation](https://github.com/kubernetes-sigs/kubebuilder/tree/master/pkg/plugins/common/kustomize) +*Checkthe[kustomizedocumentation][kustomize-docs] +*Checkthe[kustomizerepository][kustomize-github] +*Checkthe[releasenotes][release-notes-v5]forKustomizev5.0.0 +*Checkthe[releasenotes][release-notes-v4]forKustomuzev4.0.0 +*Also,youcancomparethe`config/`directorybetweenthesamples`project-v3`and`project-v4`tocheckthedifferenceinthesyntaxofthemanifestsprovidedbydefault [sdk]:https://github.com/operator-framework/operator-sdk -[testdata]: https://github.com/kubernetes-sigs/kubebuilder/tree/master/testdata/ -[bundle]: https://github.com/kubernetes-sigs/kubebuilder/blob/master/pkg/plugin/bundle.go -[kustomize-create-api]: https://github.com/kubernetes-sigs/kubebuilder/blob/master/pkg/plugins/common/kustomize/v2/scaffolds/api.go#L72-L84 -[kustomize-docs]: https://kustomize.io/ -[kustomize-github]: https://github.com/kubernetes-sigs/kustomize -[kustomize-replacements]: https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/replacements/ -[kustomize-vars]: https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/vars/ -[release-notes-v5]: https://github.com/kubernetes-sigs/kustomize/releases/tag/kustomize%2Fv5.0.0 -[release-notes-v4]: https://github.com/kubernetes-sigs/kustomize/releases/tag/kustomize%2Fv4.0.0 +[testdata]:https://github.com/kubernetes-sigs/kubebuilder/tree/master/testdata/ +[bundle]:https://github.com/kubernetes-sigs/kubebuilder/blob/master/pkg/plugin/bundle.go +[kustomize-create-api]:https://github.com/kubernetes-sigs/kubebuilder/blob/master/pkg/plugins/common/kustomize/v2/scaffolds/api.go#L72-L84 +[kustomize-docs]:https://kustomize.io/ +[kustomize-github]:https://github.com/kubernetes-sigs/kustomize +[kustomize-replacements]:https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/replacements/ +[kustomize-vars]:https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/vars/ +[release-notes-v5]:https://github.com/kubernetes-sigs/kustomize/releases/tag/kustomize%2Fv5.0.0 +[release-notes-v4]:https://github.com/kubernetes-sigs/kustomize/releases/tag/kustomize%2Fv4.0.0 diff --git a/docs/book/src/plugins/plugins-versioning.md b/docs/book/src/plugins/plugins-versioning.md index 8104a5ca31b..e1393fcbddd 100644 --- a/docs/book/src/plugins/plugins-versioning.md +++ b/docs/book/src/plugins/plugins-versioning.md @@ -1,53 +1,53 @@ -# Plugins Versioning +#PluginsVersioning -| Name | Example | Description | -|----------|-------------|--------| -| Kubebuilder version | `v2.2.0`, `v2.3.0`, `v2.3.1` | Tagged versions of the Kubebuilder project, representing changes to the source code in this repository. See the [releases][kb-releases] page for binary releases. | -| Project version | `"1"`, `"2"`, `"3"` | Project version defines the scheme of a `PROJECT` configuration file. This version is defined in a `PROJECT` file's `version`. | -| Plugin version | `v2`, `v3` | Represents the version of an individual plugin, as well as the corresponding scaffolding that it generates. This version is defined in a plugin key, ex. `go.kubebuilder.io/v2`. See the [design doc][cli-plugins-versioning] for more details. | +|Name|Example|Description| +|----------|-------------|--------| +|Kubebuilderversion|`v2.2.0`,`v2.3.0`,`v2.3.1`|TaggedversionsoftheKubebuilderproject,representingchangestothesourcecodeinthisrepository.Seethe[releases][kb-releases]pageforbinaryreleases.| +|Projectversion|`"1"`,`"2"`,`"3"`|Projectversiondefinestheschemeofa`PROJECT`configurationfile.Thisversionisdefinedina`PROJECT`file's`version`.| +|Pluginversion|`v2`,`v3`|Representstheversionofanindividualplugin,aswellasthecorrespondingscaffoldingthatitgenerates.Thisversionisdefinedinapluginkey,ex.`go.kubebuilder.io/v2`.Seethe[designdoc][cli-plugins-versioning]formoredetails.| -### Incrementing versions +###Incrementingversions -For more information on how Kubebuilder release versions work, see the [semver][semver] documentation. +FormoreinformationonhowKubebuilderreleaseversionswork,seethe[semver][semver]documentation. -Project versions should only be increased if a breaking change is introduced in the PROJECT file scheme itself. Changes to the Go scaffolding or the Kubebuilder CLI *do not* affect project version. +ProjectversionsshouldonlybeincreasedifabreakingchangeisintroducedinthePROJECTfileschemeitself.ChangestotheGoscaffoldingortheKubebuilderCLI*donot*affectprojectversion. -Similarly, the introduction of a new plugin version might only lead to a new minor version release of Kubebuilder, since no breaking change is being made to the CLI itself. It'd only be a breaking change to Kubebuilder if we remove support for an older plugin version. See the plugins design doc [versioning section][cli-plugins-versioning] -for more details on plugin versioning. +Similarly,theintroductionofanewpluginversionmightonlyleadtoanewminorversionreleaseofKubebuilder,sincenobreakingchangeisbeingmadetotheCLIitself.It'donlybeabreakingchangetoKubebuilderifweremovesupportforanolderpluginversion.Seethepluginsdesigndoc[versioningsection][cli-plugins-versioning] +formoredetailsonpluginversioning. - -## Introducing changes to plugins +##Introducingchangestoplugins -Changes made to plugins only require a plugin version increase if and only if a change is made to a plugin -that breaks projects scaffolded with the previous plugin version. Once a plugin version `vX` is stabilized (it doesn't -have an "alpha" or "beta" suffix), a new plugin package should be created containing a new plugin with version -`v(X+1)-alpha`. Typically this is done by (semantically) `cp -r pkg/plugins/golang/vX pkg/plugins/golang/v(X+1)` then updating -version numbers and paths. All further breaking changes to the plugin should be made in this package; the `vX` -plugin would then be frozen to breaking changes. +Changesmadetopluginsonlyrequireapluginversionincreaseifandonlyifachangeismadetoaplugin +thatbreaksprojectsscaffoldedwiththepreviouspluginversion.Onceapluginversion`vX`isstabilized(itdoesn't +havean"alpha"or"beta"suffix),anewpluginpackageshouldbecreatedcontaininganewpluginwithversion +`v(X+1)-alpha`.Typicallythisisdoneby(semantically)`cp-rpkg/plugins/golang/vXpkg/plugins/golang/v(X+1)`thenupdating +versionnumbersandpaths.Allfurtherbreakingchangestothepluginshouldbemadeinthispackage;the`vX` +pluginwouldthenbefrozentobreakingchanges. -You must also add a migration guide to the [migrations][migrations] -section of the Kubebuilder book in your PR. It should detail the steps required -for users to upgrade their projects from `vX` to `v(X+1)-alpha`. +Youmustalsoaddamigrationguidetothe[migrations][migrations] +sectionoftheKubebuilderbookinyourPR.Itshoulddetailthestepsrequired +foruserstoupgradetheirprojectsfrom`vX`to`v(X+1)-alpha`. - -[design-doc]: ./extending-cli.md +[design-doc]:./extending-cli.md [cli-plugins-versioning]:./extending-cli.md#plugin-versioning -[semver]: https://semver.org/ -[migrations]: ../migrations.md +[semver]:https://semver.org/ +[migrations]:../migrations.md [kb-releases]:https://github.com/kubernetes-sigs/kubebuilder/releases diff --git a/docs/book/src/plugins/plugins.md b/docs/book/src/plugins/plugins.md index cc341c340c1..29e27fa092c 100644 --- a/docs/book/src/plugins/plugins.md +++ b/docs/book/src/plugins/plugins.md @@ -1,40 +1,40 @@ -# Plugins +#Plugins -Since the `3.0.0` Kubebuilder version, preliminary support for plugins was added. You can [Extend the CLI and Scaffolds][extending-cli] as well. See that when users run the CLI commands to perform the scaffolds, the plugins are used: +Sincethe`3.0.0`Kubebuilderversion,preliminarysupportforpluginswasadded.Youcan[ExtendtheCLIandScaffolds][extending-cli]aswell.SeethatwhenusersruntheCLIcommandstoperformthescaffolds,thepluginsareused: -- To initialize a project with a chain of global plugins: +-Toinitializeaprojectwithachainofglobalplugins: ```sh -kubebuilder init --plugins=pluginA,pluginB +kubebuilderinit--plugins=pluginA,pluginB ``` -- To perform an optional scaffold using custom plugins: +-Toperformanoptionalscaffoldusingcustomplugins: ```sh -kubebuilder create api --plugins=pluginA,pluginB +kubebuildercreateapi--plugins=pluginA,pluginB ``` -This section details how to extend Kubebuilder and create your plugins following the same layout structures. +ThissectiondetailshowtoextendKubebuilderandcreateyourpluginsfollowingthesamelayoutstructures. - - -- [Extending the CLI and Scaffolds](extending-cli.md) -- [Creating your own plugins](creating-plugins.md) -- [Testing your plugins](testing-plugins.md) +-[ExtendingtheCLIandScaffolds](extending-cli.md) +-[Creatingyourownplugins](creating-plugins.md) +-[Testingyourplugins](testing-plugins.md) -[plugins-phase1-design-doc]: https://github.com/kubernetes-sigs/kubebuilder/blob/master/designs/extensible-cli-and-scaffolding-plugins-phase-1.md -[plugins-phase1-design-doc-1.5]: https://github.com/kubernetes-sigs/kubebuilder/blob/master/designs/extensible-cli-and-scaffolding-plugins-phase-1-5.md -[extending-cli]: extending-cli.md -[section-future-vision-plugins]: https://book.kubebuilder.io/plugins/creating-plugins.html#future-vision-for-kubebuilder-plugins +[plugins-phase1-design-doc]:https://github.com/kubernetes-sigs/kubebuilder/blob/master/designs/extensible-cli-and-scaffolding-plugins-phase-1.md +[plugins-phase1-design-doc-1.5]:https://github.com/kubernetes-sigs/kubebuilder/blob/master/designs/extensible-cli-and-scaffolding-plugins-phase-1-5.md +[extending-cli]:extending-cli.md +[section-future-vision-plugins]:https://book.kubebuilder.io/plugins/creating-plugins.html#future-vision-for-kubebuilder-plugins diff --git a/docs/book/src/plugins/testing-plugins.md b/docs/book/src/plugins/testing-plugins.md index 904039e9859..7d7e7fe828b 100644 --- a/docs/book/src/plugins/testing-plugins.md +++ b/docs/book/src/plugins/testing-plugins.md @@ -1,84 +1,84 @@ -# Test Your Plugins +#TestYourPlugins -You can test your plugin in two dimension: +Youcantestyourpluginintwodimension: -1. Validate your plugin behavior through E2E tests -2. Generate sample projects based on your plugin that can be placed in `./testdata/` +1.ValidateyourpluginbehaviorthroughE2Etests +2.Generatesampleprojectsbasedonyourpluginthatcanbeplacedin`./testdata/` -## Write E2E Tests +##WriteE2ETests -You can check [Kubebuilder/v3/test/e2e/utils](https://pkg.go.dev/sigs.k8s.io/kubebuilder/v3/test/e2e/utils) package that offers `TestContext` of rich methods: +Youcancheck[Kubebuilder/v3/test/e2e/utils](https://pkg.go.dev/sigs.k8s.io/kubebuilder/v3/test/e2e/utils)packagethatoffers`TestContext`ofrichmethods: -- [NewTestContext](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/utils/test_context.go#L51) helps define: - - Temporary folder for testing projects - - Temporary controller-manager image - - [Kubectl execution method](https://pkg.go.dev/sigs.k8s.io/kubebuilder/v3/test/e2e/utils#Kubectl) - - The cli executable (`kubebuilder`, `operator-sdk`, OR your extended-cli) +-[NewTestContext](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/utils/test_context.go#L51)helpsdefine: +-Temporaryfolderfortestingprojects +-Temporarycontroller-managerimage +-[Kubectlexecutionmethod](https://pkg.go.dev/sigs.k8s.io/kubebuilder/v3/test/e2e/utils#Kubectl) +-Thecliexecutable(`kubebuilder`,`operator-sdk`,ORyourextended-cli) -Once defined, you can use `TestContext` to: +Oncedefined,youcanuse`TestContext`to: -1. Setup testing environment, e.g: - - Clean up the environment, create temp dir. See [Prepare](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/utils/test_context.go#L97) - - Install prerequisites CRDs: See [InstallCertManager](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/utils/test_context.go#L138), [InstallPrometheusManager](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.6.0/test/e2e/utils/test_context.go#L171) -2. Validate the plugin behavior, e.g: - - Trigger the plugin's bound subcommands. See [Init](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/utils/test_context.go#L213), [CreateAPI](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.6.0/test/e2e/utils/test_context.go#L222) - - Use [PluginUtil](https://pkg.go.dev/sigs.k8s.io/kubebuilder/v3/pkg/plugin/util) to verify the scaffolded outputs. See [InsertCode](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/pkg/plugin/util/util.go#L67), [ReplaceInFile](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.6.0/pkg/plugin/util/util.go#L196), [UncommendCode](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.6.0/pkg/plugin/util/util.go#L86) -3. Further make sure the scaffolded output works, e.g: - - Execute commands in your `Makefile`. See [Make](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/utils/test_context.go#L240) - - Temporary load image of the testing controller. See [LoadImageToKindCluster](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/utils/test_context.go#L283) - - Call Kubectl to validate running resources. See [utils.Kubectl](https://pkg.go.dev/sigs.k8s.io/kubebuilder/v3/test/e2e/utils#Kubectl) -4. Delete temporary resources after testing exited, e.g: - - Uninstall prerequisites CRDs: See [UninstallPrometheusOperManager](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/utils/test_context.go#L183) - - Delete temp dir. See [Destroy](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/utils/test_context.go#L255) +1.Setuptestingenvironment,e.g: +-Cleanuptheenvironment,createtempdir.See[Prepare](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/utils/test_context.go#L97) +-InstallprerequisitesCRDs:See[InstallCertManager](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/utils/test_context.go#L138),[InstallPrometheusManager](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.6.0/test/e2e/utils/test_context.go#L171) +2.Validatethepluginbehavior,e.g: +-Triggertheplugin'sboundsubcommands.See[Init](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/utils/test_context.go#L213),[CreateAPI](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.6.0/test/e2e/utils/test_context.go#L222) +-Use[PluginUtil](https://pkg.go.dev/sigs.k8s.io/kubebuilder/v3/pkg/plugin/util)toverifythescaffoldedoutputs.See[InsertCode](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/pkg/plugin/util/util.go#L67),[ReplaceInFile](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.6.0/pkg/plugin/util/util.go#L196),[UncommendCode](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.6.0/pkg/plugin/util/util.go#L86) +3.Furthermakesurethescaffoldedoutputworks,e.g: +-Executecommandsinyour`Makefile`.See[Make](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/utils/test_context.go#L240) +-Temporaryloadimageofthetestingcontroller.See[LoadImageToKindCluster](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/utils/test_context.go#L283) +-CallKubectltovalidaterunningresources.See[utils.Kubectl](https://pkg.go.dev/sigs.k8s.io/kubebuilder/v3/test/e2e/utils#Kubectl) +4.Deletetemporaryresourcesaftertestingexited,e.g: +-UninstallprerequisitesCRDs:See[UninstallPrometheusOperManager](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/utils/test_context.go#L183) +-Deletetempdir.See[Destroy](https://github.com/kubernetes-sigs/kubebuilder/blob/v3.7.0/test/e2e/utils/test_context.go#L255) -**References:** [operator-sdk e2e tests](https://github.com/operator-framework/operator-sdk/tree/master/test/e2e/go), [kubebuiler e2e tests](https://github.com/kubernetes-sigs/kubebuilder/tree/master/test/e2e/v3) +**References:**[operator-sdke2etests](https://github.com/operator-framework/operator-sdk/tree/master/test/e2e/go),[kubebuilere2etests](https://github.com/kubernetes-sigs/kubebuilder/tree/master/test/e2e/v3) -## Generate Test Samples +##GenerateTestSamples -It can be straightforward to view content of sample projects generated by your plugin. +Itcanbestraightforwardtoviewcontentofsampleprojectsgeneratedbyyourplugin. -For example, Kubebuilder generate [sample projects](https://github.com/kubernetes-sigs/kubebuilder/tree/v3.7.0/testdata) based on different plugins to validate the layouts. +Forexample,Kubebuildergenerate[sampleprojects](https://github.com/kubernetes-sigs/kubebuilder/tree/v3.7.0/testdata)basedondifferentpluginstovalidatethelayouts. -Simply, you can also use `TextContext` to generate folders of scaffolded projects from your plugin. -The commands are very similar as mentioned in [creating-plugins](creating-plugins.md#write-e2e-tests). +Simply,youcanalsouse`TextContext`togeneratefoldersofscaffoldedprojectsfromyourplugin. +Thecommandsareverysimilarasmentionedin[creating-plugins](creating-plugins.md#write-e2e-tests). -Following is a general workflow to create a sample by the plugin `go/v3`: (`kbc` is an instance of `TextContext`) +Followingisageneralworkflowtocreateasamplebytheplugin`go/v3`:(`kbc`isaninstanceof`TextContext`) -- To initialized a project: - ```go - By("initializing a project") - err = kbc.Init( - "--plugins", "go/v3", - "--project-version", "3", - "--domain", kbc.Domain, - "--fetch-deps=false", - "--component-config=true", - ) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - ``` -- To define API: - ```go - By("creating API definition") - err = kbc.CreateAPI( - "--group", kbc.Group, - "--version", kbc.Version, - "--kind", kbc.Kind, - "--namespaced", - "--resource", - "--controller", - "--make=false", - ) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - ``` -- To scaffold webhook configurations: - ```go - By("scaffolding mutating and validating webhooks") - err = kbc.CreateWebhook( - "--group", kbc.Group, - "--version", kbc.Version, - "--kind", kbc.Kind, - "--defaulting", - "--programmatic-validation", - ) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - ``` +-Toinitializedaproject: +```go +By("initializingaproject") +err=kbc.Init( +"--plugins","go/v3", +"--project-version","3", +"--domain",kbc.Domain, +"--fetch-deps=false", +"--component-config=true", +) +ExpectWithOffset(1,err).NotTo(HaveOccurred()) +``` +-TodefineAPI: +```go +By("creatingAPIdefinition") +err=kbc.CreateAPI( +"--group",kbc.Group, +"--version",kbc.Version, +"--kind",kbc.Kind, +"--namespaced", +"--resource", +"--controller", +"--make=false", +) +ExpectWithOffset(1,err).NotTo(HaveOccurred()) +``` +-Toscaffoldwebhookconfigurations: +```go +By("scaffoldingmutatingandvalidatingwebhooks") +err=kbc.CreateWebhook( +"--group",kbc.Group, +"--version",kbc.Version, +"--kind",kbc.Kind, +"--defaulting", +"--programmatic-validation", +) +ExpectWithOffset(1,err).NotTo(HaveOccurred()) +``` diff --git a/docs/book/src/plugins/to-add-optional-features.md b/docs/book/src/plugins/to-add-optional-features.md index f62da55d2a2..af4303c4b8b 100644 --- a/docs/book/src/plugins/to-add-optional-features.md +++ b/docs/book/src/plugins/to-add-optional-features.md @@ -1,9 +1,9 @@ -## To add optional features +##Toaddoptionalfeatures -The following plugins are useful to generate code and take advantage of optional features +Thefollowingpluginsareusefultogeneratecodeandtakeadvantageofoptionalfeatures -| Plugin | Key | Description | -|-------------------------------------------------------------------------| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [declarative.go.kubebuilder.io/v1 - (Deprecated) ](declarative-v1.md) | `declarative/v1` | Optional plugin used to scaffold APIs/controllers using the [kubebuilder-declarative-pattern][kubebuilder-declarative-pattern] project. | -| [grafana.kubebuilder.io/v1-alpha](grafana-v1-alpha.md) | `grafana/v1-alpha` | Optional helper plugin which can be used to scaffold Grafana Manifests Dashboards for the default metrics which are exported by controller-runtime. | -| [deploy-image.go.kubebuilder.io/v1-alpha](deploy-image-plugin-v1-alpha) | `deploy-image/v1-alpha` | Optional helper plugin which can be used to scaffold APIs and controller with code implementation to Deploy and Manage an Operand(image). | +|Plugin|Key|Description| +|-------------------------------------------------------------------------|--------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +|[declarative.go.kubebuilder.io/v1-(Deprecated)](declarative-v1.md)|`declarative/v1`|OptionalpluginusedtoscaffoldAPIs/controllersusingthe[kubebuilder-declarative-pattern][kubebuilder-declarative-pattern]project.| +|[grafana.kubebuilder.io/v1-alpha](grafana-v1-alpha.md)|`grafana/v1-alpha`|OptionalhelperpluginwhichcanbeusedtoscaffoldGrafanaManifestsDashboardsforthedefaultmetricswhichareexportedbycontroller-runtime.| +|[deploy-image.go.kubebuilder.io/v1-alpha](deploy-image-plugin-v1-alpha)|`deploy-image/v1-alpha`|OptionalhelperpluginwhichcanbeusedtoscaffoldAPIsandcontrollerwithcodeimplementationtoDeployandManageanOperand(image).| diff --git a/docs/book/src/plugins/to-be-extended.md b/docs/book/src/plugins/to-be-extended.md index e6137bdad28..99c12496404 100644 --- a/docs/book/src/plugins/to-be-extended.md +++ b/docs/book/src/plugins/to-be-extended.md @@ -1,28 +1,28 @@ -## To help projects using Kubebuilder as Lib to composite new solutions and plugins +##TohelpprojectsusingKubebuilderasLibtocompositenewsolutionsandplugins - -Then, see that you can use the kustomize plugin, which is responsible for to scaffold the kustomize files under `config/`, as -the base language plugins which are responsible for to scaffold the Golang files to create your own plugins to work with -another languages (i.e. [Operator-SDK][sdk] does to allow users work with Ansible/Helm) or to add -helpers on top, such as [Operator-SDK][sdk] does to add their features to integrate the projects with [OLM][olm]. - -| Plugin | Key | Description | -| ---------------------------------------------------------------------------------- |-----------------------------| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [kustomize.common.kubebuilder.io/v1](https://github.com/kubernetes-sigs/kubebuilder/pull/3235/kustomize-v1.md) | kustomize/v1 (Deprecated) | Responsible for scaffolding all manifests to configure projects with [kustomize(v3)][kustomize]. (create and update the `config/` directory). This plugin is used in the composition to create the plugin (`go/v3`). | -| [kustomize.common.kubebuilder.io/v2](kustomize-v2.md) | `kustomize/v2` | It has the same purpose of `kustomize/v1`. However, it works with [kustomize][kustomize] version `v4` and addresses the required changes for future kustomize configurations. It will probably be used with the future `go/v4-alpha` plugin. | -| `base.go.kubebuilder.io/v3` | `base/v3` | Responsible for scaffolding all files that specifically require Golang. This plugin is used in composition to create the plugin (`go/v3`) | -| `base.go.kubebuilder.io/v4` | `base/v4` | Responsible for scaffolding all files which specifically requires Golang. This plugin is used in the composition to create the plugin (`go/v4`) | - -[create-plugins]: creating-plugins.md -[kubebuilder-declarative-pattern]: https://github.com/kubernetes-sigs/kubebuilder-declarative-pattern -[kustomize]: https://kustomize.io/ -[sdk]: https://github.com/operator-framework/operator-sdk -[olm]: https://olm.operatorframework.io/ +Then,seethatyoucanusethekustomizeplugin,whichisresponsiblefortoscaffoldthekustomizefilesunder`config/`,as +thebaselanguagepluginswhichareresponsiblefortoscaffoldtheGolangfilestocreateyourownpluginstoworkwith +anotherlanguages(i.e.[Operator-SDK][sdk]doestoallowusersworkwithAnsible/Helm)ortoadd +helpersontop,suchas[Operator-SDK][sdk]doestoaddtheirfeaturestointegratetheprojectswith[OLM][olm]. + +|Plugin|Key|Description| +|----------------------------------------------------------------------------------|-----------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +|[kustomize.common.kubebuilder.io/v1](https://github.com/kubernetes-sigs/kubebuilder/pull/3235/kustomize-v1.md)|kustomize/v1(Deprecated)|Responsibleforscaffoldingallmanifeststoconfigureprojectswith[kustomize(v3)][kustomize].(createandupdatethe`config/`directory).Thispluginisusedinthecompositiontocreatetheplugin(`go/v3`).| +|[kustomize.common.kubebuilder.io/v2](kustomize-v2.md)|`kustomize/v2`|Ithasthesamepurposeof`kustomize/v1`.However,itworkswith[kustomize][kustomize]version`v4`andaddressestherequiredchangesforfuturekustomizeconfigurations.Itwillprobablybeusedwiththefuture`go/v4-alpha`plugin.| +|`base.go.kubebuilder.io/v3`|`base/v3`|ResponsibleforscaffoldingallfilesthatspecificallyrequireGolang.Thispluginisusedincompositiontocreatetheplugin(`go/v3`)| +|`base.go.kubebuilder.io/v4`|`base/v4`|ResponsibleforscaffoldingallfileswhichspecificallyrequiresGolang.Thispluginisusedinthecompositiontocreatetheplugin(`go/v4`)| + +[create-plugins]:creating-plugins.md +[kubebuilder-declarative-pattern]:https://github.com/kubernetes-sigs/kubebuilder-declarative-pattern +[kustomize]:https://kustomize.io/ +[sdk]:https://github.com/operator-framework/operator-sdk +[olm]:https://olm.operatorframework.io/ diff --git a/docs/book/src/plugins/to-scaffold-project.md b/docs/book/src/plugins/to-scaffold-project.md index c2c9235e2b5..5057a0abce5 100644 --- a/docs/book/src/plugins/to-scaffold-project.md +++ b/docs/book/src/plugins/to-scaffold-project.md @@ -1,9 +1,9 @@ -## To scaffold the projects +##Toscaffoldtheprojects -The following plugins are useful to scaffold the whole project with the tool. +Thefollowingpluginsareusefultoscaffoldthewholeprojectwiththetool. -| Plugin | Key | Description | -| ---------------------------------------------------------------------------------- | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [go.kubebuilder.io/v2 - (Deprecated)](go-v2-plugin.md) | `go/v2` | Golang plugin responsible for scaffolding the legacy layout provided with Kubebuilder CLI >= `2.0.0` and < `3.0.0`. | -| [go.kubebuilder.io/v3 - (Default scaffold with Kubebuilder init)](go-v3-plugin.md) | `go/v3` | Default scaffold used for creating a project when no plugin(s) are provided. Responsible for scaffolding Golang projects and its configurations. | -| [go.kubebuilder.io/v4-alpha - (Add Apple Silicon Support)](go-v4-plugin.md) | `go/v4` | Scaffold composite by `base.go.kubebuilder.io/v3` and [kustomize.common.kubebuilder.io/v2](kustomize-v2.md). Responsible for scaffolding Golang projects and its configurations. | +|Plugin|Key|Description| +|----------------------------------------------------------------------------------|--------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +|[go.kubebuilder.io/v2-(Deprecated)](go-v2-plugin.md)|`go/v2`|GolangpluginresponsibleforscaffoldingthelegacylayoutprovidedwithKubebuilderCLI>=`2.0.0`and<`3.0.0`.| +|[go.kubebuilder.io/v3-(DefaultscaffoldwithKubebuilderinit)](go-v3-plugin.md)|`go/v3`|Defaultscaffoldusedforcreatingaprojectwhennoplugin(s)areprovided.ResponsibleforscaffoldingGolangprojectsanditsconfigurations.| +|[go.kubebuilder.io/v4-alpha-(AddAppleSiliconSupport)](go-v4-plugin.md)|`go/v4`|Scaffoldcompositeby`base.go.kubebuilder.io/v3`and[kustomize.common.kubebuilder.io/v2](kustomize-v2.md).ResponsibleforscaffoldingGolangprojectsanditsconfigurations.| diff --git a/docs/book/src/quick-start.md b/docs/book/src/quick-start.md index 2abb74fab1f..71e0640861c 100644 --- a/docs/book/src/quick-start.md +++ b/docs/book/src/quick-start.md @@ -1,147 +1,147 @@ -# Quick Start +#QuickStart -This Quick Start guide will cover: +ThisQuickStartguidewillcover: -- [Creating a project](#create-a-project) -- [Creating an API](#create-an-api) -- [Running locally](#test-it-out) -- [Running in-cluster](#run-it-on-the-cluster) +-[Creatingaproject](#create-a-project) +-[CreatinganAPI](#create-an-api) +-[Runninglocally](#test-it-out) +-[Runningin-cluster](#run-it-on-the-cluster) -## Prerequisites +##Prerequisites -- [go](https://golang.org/dl/) version v1.20.0+ -- [docker](https://docs.docker.com/install/) version 17.03+. -- [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) version v1.11.3+. -- Access to a Kubernetes v1.11.3+ cluster. +-[go](https://golang.org/dl/)versionv1.20.0+ +-[docker](https://docs.docker.com/install/)version17.03+. +-[kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/)versionv1.11.3+. +-AccesstoaKubernetesv1.11.3+cluster. - -## Installation +##Installation -Install [kubebuilder](https://sigs.k8s.io/kubebuilder): +Install[kubebuilder](https://sigs.k8s.io/kubebuilder): ```bash -# download kubebuilder and install locally. -curl -L -o kubebuilder "https://go.kubebuilder.io/dl/latest/$(go env GOOS)/$(go env GOARCH)" -chmod +x kubebuilder && mv kubebuilder /usr/local/bin/ +#downloadkubebuilderandinstalllocally. +curl-L-okubebuilder"https://go.kubebuilder.io/dl/latest/$(goenvGOOS)/$(goenvGOARCH)" +chmod+xkubebuilder&&mvkubebuilder/usr/local/bin/ ``` - - -## Create a Project +##CreateaProject -Create a directory, and then run the init command inside of it to initialize a new project. Follows an example. +Createadirectory,andthenruntheinitcommandinsideofittoinitializeanewproject.Followsanexample. ```bash -mkdir -p ~/projects/guestbook -cd ~/projects/guestbook -kubebuilder init --domain my.domain --repo my.domain/guestbook +mkdir-p~/projects/guestbook +cd~/projects/guestbook +kubebuilderinit--domainmy.domain--repomy.domain/guestbook ``` - -## Create an API +##CreateanAPI -Run the following command to create a new API (group/version) as `webapp/v1` and the new Kind(CRD) `Guestbook` on it: +RunthefollowingcommandtocreateanewAPI(group/version)as`webapp/v1`andthenewKind(CRD)`Guestbook`onit: ```bash -kubebuilder create api --group webapp --version v1 --kind Guestbook +kubebuildercreateapi--groupwebapp--versionv1--kindGuestbook ``` - -**OPTIONAL:** Edit the API definition and the reconciliation business -logic. For more info see [Designing an API](/cronjob-tutorial/api-design.md) and [What's in -a Controller](cronjob-tutorial/controller-overview.md). +**OPTIONAL:**EdittheAPIdefinitionandthereconciliationbusiness +logic.Formoreinfosee[DesigninganAPI](/cronjob-tutorial/api-design.md)and[What'sin +aController](cronjob-tutorial/controller-overview.md). -If you are editing the API definitions, generate the manifests such as Custom Resources (CRs) or Custom Resource Definitions (CRDs) using +IfyouareeditingtheAPIdefinitions,generatethemanifestssuchasCustomResources(CRs)orCustomResourceDefinitions(CRDs)using ```bash -make manifests +makemanifests ``` -
Click here to see an example. (api/v1/guestbook_types.go) +
Clickheretoseeanexample.(api/v1/guestbook_types.go)

```go -// GuestbookSpec defines the desired state of Guestbook -type GuestbookSpec struct { - // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - // Important: Run "make" to regenerate code after modifying this file - - // Quantity of instances - // +kubebuilder:validation:Minimum=1 - // +kubebuilder:validation:Maximum=10 - Size int32 `json:"size"` - - // Name of the ConfigMap for GuestbookSpec's configuration - // +kubebuilder:validation:MaxLength=15 - // +kubebuilder:validation:MinLength=1 - ConfigMapName string `json:"configMapName"` - - // +kubebuilder:validation:Enum=Phone;Address;Name - Type string `json:"alias,omitempty"` +//GuestbookSpecdefinesthedesiredstateofGuestbook +typeGuestbookSpecstruct{ +//INSERTADDITIONALSPECFIELDS-desiredstateofcluster +//Important:Run"make"toregeneratecodeaftermodifyingthisfile + +//Quantityofinstances +//+kubebuilder:validation:Minimum=1 +//+kubebuilder:validation:Maximum=10 +Sizeint32`json:"size"` + +//NameoftheConfigMapforGuestbookSpec'sconfiguration +//+kubebuilder:validation:MaxLength=15 +//+kubebuilder:validation:MinLength=1 +ConfigMapNamestring`json:"configMapName"` + +//+kubebuilder:validation:Enum=Phone;Address;Name +Typestring`json:"alias,omitempty"` } -// GuestbookStatus defines the observed state of Guestbook -type GuestbookStatus struct { - // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - // Important: Run "make" to regenerate code after modifying this file +//GuestbookStatusdefinestheobservedstateofGuestbook +typeGuestbookStatusstruct{ +//INSERTADDITIONALSTATUSFIELD-defineobservedstateofcluster +//Important:Run"make"toregeneratecodeaftermodifyingthisfile - // PodName of the active Guestbook node. - Active string `json:"active"` +//PodNameoftheactiveGuestbooknode. +Activestring`json:"active"` - // PodNames of the standby Guestbook nodes. - Standby []string `json:"standby"` +//PodNamesofthestandbyGuestbooknodes. +Standby[]string`json:"standby"` } -// +kubebuilder:object:root=true -// +kubebuilder:subresource:status -// +kubebuilder:resource:scope=Cluster +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status +//+kubebuilder:resource:scope=Cluster -// Guestbook is the Schema for the guestbooks API -type Guestbook struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` +//GuestbookistheSchemafortheguestbooksAPI +typeGuestbookstruct{ +metav1.TypeMeta`json:",inline"` +metav1.ObjectMeta`json:"metadata,omitempty"` - Spec GuestbookSpec `json:"spec,omitempty"` - Status GuestbookStatus `json:"status,omitempty"` +SpecGuestbookSpec`json:"spec,omitempty"` +StatusGuestbookStatus`json:"status,omitempty"` } ``` @@ -149,104 +149,104 @@ type Guestbook struct {

-## Test It Out +##TestItOut -You'll need a Kubernetes cluster to run against. You can use -[KIND](https://sigs.k8s.io/kind) to get a local cluster for testing, or -run against a remote cluster. +You'llneedaKubernetesclustertorunagainst.Youcanuse +[KIND](https://sigs.k8s.io/kind)togetalocalclusterfortesting,or +runagainstaremotecluster. - -Install the CRDs into the cluster: +InstalltheCRDsintothecluster: ```bash -make install +makeinstall ``` -For quick feedback and code-level debugging, run your controller (this will run in the foreground, so switch to a new -terminal if you want to leave it running): +Forquickfeedbackandcode-leveldebugging,runyourcontroller(thiswillrunintheforeground,soswitchtoanew +terminalifyouwanttoleaveitrunning): ```bash -make run +makerun ``` -## Install Instances of Custom Resources +##InstallInstancesofCustomResources -If you pressed `y` for Create Resource [y/n] then you created a CR for your CRD in your samples (make sure to edit them first if you've changed the -API definition): +Ifyoupressed`y`forCreateResource[y/n]thenyoucreatedaCRforyourCRDinyoursamples(makesuretoeditthemfirstifyou'vechangedthe +APIdefinition): ```bash -kubectl apply -k config/samples/ +kubectlapply-kconfig/samples/ ``` -## Run It On the Cluster -When your controller is ready to be packaged and tested in other clusters. +##RunItOntheCluster +Whenyourcontrollerisreadytobepackagedandtestedinotherclusters. -Build and push your image to the location specified by `IMG`: +Buildandpushyourimagetothelocationspecifiedby`IMG`: ```bash -make docker-build docker-push IMG=/:tag +makedocker-builddocker-pushIMG=/:tag ``` -Deploy the controller to the cluster with image specified by `IMG`: +Deploythecontrollertotheclusterwithimagespecifiedby`IMG`: ```bash -make deploy IMG=/:tag +makedeployIMG=/:tag ``` - -## Uninstall CRDs +##UninstallCRDs -To delete your CRDs from the cluster: +TodeleteyourCRDsfromthecluster: ```bash -make uninstall +makeuninstall ``` -## Undeploy controller +##Undeploycontroller -Undeploy the controller to the cluster: +Undeploythecontrollertothecluster: ```bash -make undeploy +makeundeploy ``` -## Next Step +##NextStep -Now, see the [architecture concept diagram][architecture-concept-diagram] for a better overview and follow up the -[CronJob tutorial][cronjob-tutorial] to better understand how it works by developing a -demo example project. +Now,seethe[architectureconceptdiagram][architecture-concept-diagram]forabetteroverviewandfollowupthe +[CronJobtutorial][cronjob-tutorial]tobetterunderstandhowitworksbydevelopinga +demoexampleproject. - -[pre-rbc-gke]: https://cloud.google.com/kubernetes-engine/docs/how-to/role-based-access-control#iam-rolebinding-bootstrap -[cronjob-tutorial]: https://book.kubebuilder.io/cronjob-tutorial/cronjob-tutorial.html -[GOPATH-golang-docs]: https://golang.org/doc/code.html#GOPATH -[go-modules-blogpost]: https://blog.golang.org/using-go-modules -[envtest]: https://book.kubebuilder.io/reference/testing/envtest.html -[architecture-concept-diagram]: architecture.md -[kustomize]: https://github.com/kubernetes-sigs/kustomize +[pre-rbc-gke]:https://cloud.google.com/kubernetes-engine/docs/how-to/role-based-access-control#iam-rolebinding-bootstrap +[cronjob-tutorial]:https://book.kubebuilder.io/cronjob-tutorial/cronjob-tutorial.html +[GOPATH-golang-docs]:https://golang.org/doc/code.html#GOPATH +[go-modules-blogpost]:https://blog.golang.org/using-go-modules +[envtest]:https://book.kubebuilder.io/reference/testing/envtest.html +[architecture-concept-diagram]:architecture.md +[kustomize]:https://github.com/kubernetes-sigs/kustomize diff --git a/docs/book/src/reference/admission-webhook.md b/docs/book/src/reference/admission-webhook.md index 6ae2b950b89..278728b15ec 100644 --- a/docs/book/src/reference/admission-webhook.md +++ b/docs/book/src/reference/admission-webhook.md @@ -1,101 +1,101 @@ -# Admission Webhooks +#AdmissionWebhooks -[Admission webhooks](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#what-are-admission-webhooks) are HTTP callbacks that receive admission requests, process -them and return admission responses. +[Admissionwebhooks](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#what-are-admission-webhooks)areHTTPcallbacksthatreceiveadmissionrequests,process +themandreturnadmissionresponses. -Kubernetes provides the following types of admission webhooks: +Kubernetesprovidesthefollowingtypesofadmissionwebhooks: -- **Mutating Admission Webhook**: -These can mutate the object while it's being created or updated, before it gets -stored. It can be used to default fields in a resource requests, e.g. fields in -Deployment that are not specified by the user. It can be used to inject sidecar +-**MutatingAdmissionWebhook**: +Thesecanmutatetheobjectwhileit'sbeingcreatedorupdated,beforeitgets +stored.Itcanbeusedtodefaultfieldsinaresourcerequests,e.g.fieldsin +Deploymentthatarenotspecifiedbytheuser.Itcanbeusedtoinjectsidecar containers. -- **Validating Admission Webhook**: -These can validate the object while it's being created or updated, before it gets -stored. It allows more complex validation than pure schema-based validation. -e.g. cross-field validation and pod image whitelisting. +-**ValidatingAdmissionWebhook**: +Thesecanvalidatetheobjectwhileit'sbeingcreatedorupdated,beforeitgets +stored.Itallowsmorecomplexvalidationthanpureschema-basedvalidation. +e.g.cross-fieldvalidationandpodimagewhitelisting. -The apiserver by default doesn't authenticate itself to the webhooks. However, -if you want to authenticate the clients, you can configure the apiserver to use -basic auth, bearer token, or a cert to authenticate itself to the webhooks. -You can find detailed steps +Theapiserverbydefaultdoesn'tauthenticateitselftothewebhooks.However, +ifyouwanttoauthenticatetheclients,youcanconfiguretheapiservertouse +basicauth,bearertoken,oracerttoauthenticateitselftothewebhooks. +Youcanfinddetailedsteps [here](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#authenticate-apiservers). - -## Handling Resource Status in Admission Webhooks +##HandlingResourceStatusinAdmissionWebhooks - -### Understanding Why: +###UnderstandingWhy: -#### Mutating Admission Webhooks +####MutatingAdmissionWebhooks -Mutating Admission Webhooks are primarily designed to intercept and modify requests concerning the creation, -modification, or deletion of objects. Though they possess the capability to modify an object's specification, -directly altering its status isn't deemed a standard practice, -often leading to unintended results. +MutatingAdmissionWebhooksareprimarilydesignedtointerceptandmodifyrequestsconcerningthecreation, +modification,ordeletionofobjects.Thoughtheypossessthecapabilitytomodifyanobject'sspecification, +directlyalteringitsstatusisn'tdeemedastandardpractice, +oftenleadingtounintendedresults. ```go -// MutatingWebhookConfiguration allows for modification of objects. -// However, direct modification of the status might result in unexpected behavior. -type MutatingWebhookConfiguration struct { - ... +//MutatingWebhookConfigurationallowsformodificationofobjects. +//However,directmodificationofthestatusmightresultinunexpectedbehavior. +typeMutatingWebhookConfigurationstruct{ +... } ``` -#### Setting Initial Status +####SettingInitialStatus -For those diving into custom controllers for custom resources, it's imperative to grasp the concept of setting an -initial status. This initialization typically takes place within the controller itself. The moment the controller -identifies a new instance of its managed resource, primarily through a watch mechanism, it holds the authority -to assign an initial status to that resource. +Forthosedivingintocustomcontrollersforcustomresources,it'simperativetograsptheconceptofsettingan +initialstatus.Thisinitializationtypicallytakesplacewithinthecontrolleritself.Themomentthecontroller +identifiesanewinstanceofitsmanagedresource,primarilythroughawatchmechanism,itholdstheauthority +toassignaninitialstatustothatresource. ```go -// Custom controller's reconcile function might look something like this: -func (r *ReconcileMyResource) Reconcile(request reconcile.Request) (reconcile.Result, error) { - // ... - // Upon discovering a new instance, set the initial status - instance.Status = SomeInitialStatus - // ... +//Customcontroller'sreconcilefunctionmightlooksomethinglikethis: +func(r*ReconcileMyResource)Reconcile(requestreconcile.Request)(reconcile.Result,error){ +//... +//Upondiscoveringanewinstance,settheinitialstatus +instance.Status=SomeInitialStatus +//... } ``` -#### Status Subresource +####StatusSubresource -Delving into Kubernetes custom resources, a clear demarcation exists between the spec (depicting the desired state) -and the status (illustrating the observed state). Activating the /status subresource for a custom resource definition -(CRD) bifurcates the `status` and `spec`, each assigned to its respective API endpoint. -This separation ensures that changes introduced by users, such as modifying the spec, and system-driven updates, -like status alterations, remain distinct. Leveraging a mutating webhook to tweak the status during a spec-modifying -operation might not pan out as expected, courtesy of this isolation. +DelvingintoKubernetescustomresources,acleardemarcationexistsbetweenthespec(depictingthedesiredstate) +andthestatus(illustratingtheobservedstate).Activatingthe/statussubresourceforacustomresourcedefinition +(CRD)bifurcatesthe`status`and`spec`,eachassignedtoitsrespectiveAPIendpoint. +Thisseparationensuresthatchangesintroducedbyusers,suchasmodifyingthespec,andsystem-drivenupdates, +likestatusalterations,remaindistinct.Leveragingamutatingwebhooktotweakthestatusduringaspec-modifying +operationmightnotpanoutasexpected,courtesyofthisisolation. ```yaml -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition +apiVersion:apiextensions.k8s.io/v1 +kind:CustomResourceDefinition metadata: - name: myresources.mygroup.mydomain +name:myresources.mygroup.mydomain spec: - ... - subresources: - status: {} # Enables the /status subresource +... +subresources: +status:{}#Enablesthe/statussubresource ``` -#### Conclusion +####Conclusion -While certain edge scenarios might allow a mutating webhook to seamlessly modify the status, treading this path isn't a -universally acclaimed or recommended strategy. Entrusting the controller logic with status updates remains the -most advocated approach. +Whilecertainedgescenariosmightallowamutatingwebhooktoseamlesslymodifythestatus,treadingthispathisn'ta +universallyacclaimedorrecommendedstrategy.Entrustingthecontrollerlogicwithstatusupdatesremainsthe +mostadvocatedapproach. diff --git a/docs/book/src/reference/artifacts.md b/docs/book/src/reference/artifacts.md index f1a5275fb6c..5fc7e068ddc 100644 --- a/docs/book/src/reference/artifacts.md +++ b/docs/book/src/reference/artifacts.md @@ -1,16 +1,16 @@ -# Artifacts +#Artifacts -Kubebuilder publishes test binaries and container images in addition -to the main binary releases. +Kubebuilderpublishestestbinariesandcontainerimagesinaddition +tothemainbinaryreleases. -## Test Binaries +##TestBinaries -You can find test binary tarballs for all Kubernetes versions and host platforms at `https://go.kubebuilder.io/test-tools`. -You can find a test binary tarball for a particular Kubernetes version and host platform at `https://go.kubebuilder.io/test-tools/${version}/${os}/${arch}`. +YoucanfindtestbinarytarballsforallKubernetesversionsandhostplatformsat`https://go.kubebuilder.io/test-tools`. +YoucanfindatestbinarytarballforaparticularKubernetesversionandhostplatformat`https://go.kubebuilder.io/test-tools/${version}/${os}/${arch}`. -## Container Images +##ContainerImages -You can find all container image versions for a particular platform at `https://go.kubebuilder.io/images/${os}/${arch}` -or at `gcr.io/kubebuilder/thirdparty-${os}-${arch}`. -You can find the container image for a particular Kubernetes version and host platform at `https://go.kubebuilder.io/images/${os}/${arch}/${version}` -or at `gcr.io/kubebuilder/thirdparty-${os}-${arch}:${version}`. +Youcanfindallcontainerimageversionsforaparticularplatformat`https://go.kubebuilder.io/images/${os}/${arch}` +orat`gcr.io/kubebuilder/thirdparty-${os}-${arch}`. +YoucanfindthecontainerimageforaparticularKubernetesversionandhostplatformat`https://go.kubebuilder.io/images/${os}/${arch}/${version}` +orat`gcr.io/kubebuilder/thirdparty-${os}-${arch}:${version}`. diff --git a/docs/book/src/reference/completion.md b/docs/book/src/reference/completion.md index eaeead7cd78..fd712a130fb 100644 --- a/docs/book/src/reference/completion.md +++ b/docs/book/src/reference/completion.md @@ -1,44 +1,44 @@ -# Enabling shell autocompletion -The Kubebuilder completion script can be generated with the command `kubebuilder completion [bash|fish|powershell|zsh]`. -Note that sourcing the completion script in your shell enables Kubebuilder autocompletion. +#Enablingshellautocompletion +TheKubebuildercompletionscriptcanbegeneratedwiththecommand`kubebuildercompletion[bash|fish|powershell|zsh]`. +NotethatsourcingthecompletionscriptinyourshellenablesKubebuilderautocompletion. - -- Once installed, go ahead and add the path `/usr/local/bin/bash` in the `/etc/shells`. +-Onceinstalled,goaheadandaddthepath`/usr/local/bin/bash`inthe`/etc/shells`. - `echo “/usr/local/bin/bash” > /etc/shells` +`echo“/usr/local/bin/bash”>/etc/shells` -- Make sure to use installed shell by current user. +-Makesuretouseinstalledshellbycurrentuser. - `chsh -s /usr/local/bin/bash` +`chsh-s/usr/local/bin/bash` -- Add following content in /.bash_profile or ~/.bashrc +-Addfollowingcontentin/.bash_profileor~/.bashrc ``` -# kubebuilder autocompletion -if [ -f /usr/local/share/bash-completion/bash_completion ]; then -. /usr/local/share/bash-completion/bash_completion +#kubebuilderautocompletion +if[-f/usr/local/share/bash-completion/bash_completion];then +./usr/local/share/bash-completion/bash_completion fi -. <(kubebuilder completion bash) +.<(kubebuildercompletionbash) ``` -- Restart terminal for the changes to be reflected or `source` the changed bash file. +-Restartterminalforthechangestobereflectedor`source`thechangedbashfile. - - diff --git a/docs/book/src/reference/controller-gen.md b/docs/book/src/reference/controller-gen.md index 97225650ca3..8cc83c72ce0 100644 --- a/docs/book/src/reference/controller-gen.md +++ b/docs/book/src/reference/controller-gen.md @@ -1,72 +1,72 @@ -# controller-gen CLI +#controller-genCLI -Kubebuilder makes use of a tool called +Kubebuildermakesuseofatoolcalled [controller-gen](https://sigs.k8s.io/controller-tools/cmd/controller-gen) -for generating utility code and Kubernetes YAML. This code and config -generation is controlled by the presence of special ["marker -comments"](/reference/markers.md) in Go code. +forgeneratingutilitycodeandKubernetesYAML.Thiscodeandconfig +generationiscontrolledbythepresenceofspecial["marker +comments"](/reference/markers.md)inGocode. -controller-gen is built out of different "generators" (which specify what -to generate) and "output rules" (which specify how and where to write the +controller-genisbuiltoutofdifferent"generators"(whichspecifywhat +togenerate)and"outputrules"(whichspecifyhowandwheretowritethe results). -Both are configured through command line options specified in [marker +Bothareconfiguredthroughcommandlineoptionsspecifiedin[marker format](/reference/markers.md). -For instance, the following command: +Forinstance,thefollowingcommand: ```shell -controller-gen paths=./... crd:trivialVersions=true rbac:roleName=controller-perms output:crd:artifacts:config=config/crd/bases +controller-genpaths=./...crd:trivialVersions=truerbac:roleName=controller-permsoutput:crd:artifacts:config=config/crd/bases ``` -generates CRDs and RBAC, and specifically stores the generated CRD YAML in -`config/crd/bases`. For the RBAC, it uses the default output rules -(`config/rbac`). It considers every package in the current directory tree -(as per the normal rules of the go `...` wildcard). +generatesCRDsandRBAC,andspecificallystoresthegeneratedCRDYAMLin +`config/crd/bases`.FortheRBAC,itusesthedefaultoutputrules +(`config/rbac`).Itconsiderseverypackageinthecurrentdirectorytree +(asperthenormalrulesofthego`...`wildcard). -## Generators +##Generators -Each different generator is configured through a CLI option. Multiple -generators may be used in a single invocation of `controller-gen`. +EachdifferentgeneratorisconfiguredthroughaCLIoption.Multiple +generatorsmaybeusedinasingleinvocationof`controller-gen`. -{{#markerdocs CLI: generators}} +{{#markerdocsCLI:generators}} -## Output Rules +##OutputRules -Output rules configure how a given generator outputs its results. There is -always one global "fallback" output rule (specified as `output:`), -plus per-generator overrides (specified as `output::`). +Outputrulesconfigurehowagivengeneratoroutputsitsresults.Thereis +alwaysoneglobal"fallback"outputrule(specifiedas`output:`), +plusper-generatoroverrides(specifiedas`output::`). - -For brevity, the per-generator output rules (`output::`) -are omitted below. They are equivalent to the global fallback options -listed here. +Forbrevity,theper-generatoroutputrules(`output::`) +areomittedbelow.Theyareequivalenttotheglobalfallbackoptions +listedhere. -{{#markerdocs CLI: output rules (optionally as output::...)}} +{{#markerdocsCLI:outputrules(optionallyasoutput::...)}} -## Other Options +##OtherOptions -{{#markerdocs CLI: generic}} +{{#markerdocsCLI:generic}} diff --git a/docs/book/src/reference/envtest.md b/docs/book/src/reference/envtest.md index b314b4f2977..3da0156a23a 100644 --- a/docs/book/src/reference/envtest.md +++ b/docs/book/src/reference/envtest.md @@ -1,326 +1,326 @@ -# Configuring envtest for integration tests +#Configuringenvtestforintegrationtests -The [`controller-runtime/pkg/envtest`][envtest] Go library helps write integration tests for your controllers by setting up and starting an instance of etcd and the -Kubernetes API server, without kubelet, controller-manager or other components. +The[`controller-runtime/pkg/envtest`][envtest]Golibraryhelpswriteintegrationtestsforyourcontrollersbysettingupandstartinganinstanceofetcdandthe +KubernetesAPIserver,withoutkubelet,controller-managerorothercomponents. -## Installation +##Installation -Installing the binaries is as a simple as running `make envtest`. `envtest` will download the Kubernetes API server binaries to the `bin/` folder in your project -by default. `make test` is the one-stop shop for downloading the binaries, setting up the test environment, and running the tests. +Installingthebinariesisasasimpleasrunning`makeenvtest`.`envtest`willdownloadtheKubernetesAPIserverbinariestothe`bin/`folderinyourproject +bydefault.`maketest`istheone-stopshopfordownloadingthebinaries,settingupthetestenvironment,andrunningthetests. -The make targets require `bash` to run. +Themaketargetsrequire`bash`torun. -## Installation in Air Gapped/disconnected environments -If you would like to download the tarball containing the binaries, to use in a disconnected environment you can use -[`setup-envtest`][setup-envtest] to download the required binaries locally. There are a lot of ways to configure `setup-envtest` to avoid talking to -the internet you can read about them [here](https://github.com/kubernetes-sigs/controller-runtime/tree/master/tools/setup-envtest#what-if-i-dont-want-to-talk-to-the-internet). -The examples below will show how to install the Kubernetes API binaries using mostly defaults set by `setup-envtest`. +##InstallationinAirGapped/disconnectedenvironments +Ifyouwouldliketodownloadthetarballcontainingthebinaries,touseinadisconnectedenvironmentyoucanuse +[`setup-envtest`][setup-envtest]todownloadtherequiredbinarieslocally.Therearealotofwaystoconfigure`setup-envtest`toavoidtalkingto +theinternetyoucanreadaboutthem[here](https://github.com/kubernetes-sigs/controller-runtime/tree/master/tools/setup-envtest#what-if-i-dont-want-to-talk-to-the-internet). +TheexamplesbelowwillshowhowtoinstalltheKubernetesAPIbinariesusingmostlydefaultssetby`setup-envtest`. -### Download the binaries -`make envtest` will download the `setup-envtest` binary to `./bin/`. +###Downloadthebinaries +`makeenvtest`willdownloadthe`setup-envtest`binaryto`./bin/`. ```shell -make envtest +makeenvtest ``` -Installing the binaries using `setup-envtest` stores the binary in OS specific locations, you can read more about them +Installingthebinariesusing`setup-envtest`storesthebinaryinOSspecificlocations,youcanreadmoreaboutthem [here](https://github.com/kubernetes-sigs/controller-runtime/tree/master/tools/setup-envtest#where-does-it-put-all-those-binaries) ```sh -./bin/setup-envtest use 1.21.2 +./bin/setup-envtestuse1.21.2 ``` -### Update the test make target -Once these binaries are installed, change the `test` make target to include a `-i` like below. `-i` will only check for locally installed -binaries and not reach out to remote resources. You could also set the `ENVTEST_INSTALLED_ONLY` env variable. +###Updatethetestmaketarget +Oncethesebinariesareinstalled,changethe`test`maketargettoincludea`-i`likebelow.`-i`willonlycheckforlocallyinstalled +binariesandnotreachouttoremoteresources.Youcouldalsosetthe`ENVTEST_INSTALLED_ONLY`envvariable. ```makefile -test: manifests generate fmt vet - KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -i --bin-dir $(LOCALBIN) -p path)" go test ./... -coverprofile cover.out +test:manifestsgeneratefmtvet +KUBEBUILDER_ASSETS="$(shell$(ENVTEST)use$(ENVTEST_K8S_VERSION)-i--bin-dir$(LOCALBIN)-ppath)"gotest./...-coverprofilecover.out ``` -NOTE: The `ENVTEST_K8S_VERSION` needs to match the `setup-envtest` you downloaded above. Otherwise, you will see an error like the below +NOTE:The`ENVTEST_K8S_VERSION`needstomatchthe`setup-envtest`youdownloadedabove.Otherwise,youwillseeanerrorlikethebelow ```sh -no such version (1.24.5) exists on disk for this architecture (darwin/amd64) -- try running `list -i` to see what's on disk +nosuchversion(1.24.5)existsondiskforthisarchitecture(darwin/amd64)--tryrunning`list-i`toseewhat'sondisk ``` -## Kubernetes 1.20 and 1.21 binary issues +##Kubernetes1.20and1.21binaryissues -There have been many reports of the `kube-apiserver` or `etcd` binary [hanging during cleanup][cr-1571] -or misbehaving in other ways. We recommend using the 1.19.2 tools version to circumvent such issues, -which do not seem to arise in 1.22+. This is likely NOT the cause of a `fork/exec: permission denied` -or `fork/exec: not found` error, which is caused by improper tools installation. +Therehavebeenmanyreportsofthe`kube-apiserver`or`etcd`binary[hangingduringcleanup][cr-1571] +ormisbehavinginotherways.Werecommendusingthe1.19.2toolsversiontocircumventsuchissues, +whichdonotseemtoarisein1.22+.ThisislikelyNOTthecauseofa`fork/exec:permissiondenied` +or`fork/exec:notfound`error,whichiscausedbyimpropertoolsinstallation. [cr-1571]:https://github.com/kubernetes-sigs/controller-runtime/issues/1571 -## Writing tests +##Writingtests -Using `envtest` in integration tests follows the general flow of: +Using`envtest`inintegrationtestsfollowsthegeneralflowof: ```go -import sigs.k8s.io/controller-runtime/pkg/envtest +importsigs.k8s.io/controller-runtime/pkg/envtest -//specify testEnv configuration -testEnv = &envtest.Environment{ - CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")}, +//specifytestEnvconfiguration +testEnv=&envtest.Environment{ +CRDDirectoryPaths:[]string{filepath.Join("..","config","crd","bases")}, } -//start testEnv -cfg, err = testEnv.Start() +//starttestEnv +cfg,err=testEnv.Start() -//write test logic +//writetestlogic -//stop testEnv -err = testEnv.Stop() +//stoptestEnv +err=testEnv.Stop() ``` -`kubebuilder` does the boilerplate setup and teardown of testEnv for you, in the ginkgo test suite that it generates under the `/controllers` directory. +`kubebuilder`doestheboilerplatesetupandteardownoftestEnvforyou,intheginkgotestsuitethatitgeneratesunderthe`/controllers`directory. -Logs from the test runs are prefixed with `test-env`. +Logsfromthetestrunsareprefixedwith`test-env`. - -### Configuring your test control plane +###Configuringyourtestcontrolplane -Controller-runtime’s [envtest][envtest] framework requires `kubectl`, `kube-apiserver`, and `etcd` binaries be present locally to simulate the API portions of a real cluster. +Controller-runtime’s[envtest][envtest]frameworkrequires`kubectl`,`kube-apiserver`,and`etcd`binariesbepresentlocallytosimulatetheAPIportionsofarealcluster. -The `make test` command will install these binaries to the `bin/` directory and use them when running tests that use `envtest`. +The`maketest`commandwillinstallthesebinariestothe`bin/`directoryandusethemwhenrunningteststhatuse`envtest`. Ie, ```shell ./bin/k8s/ -└── 1.25.0-darwin-amd64 - ├── etcd - ├── kube-apiserver - └── kubectl +└──1.25.0-darwin-amd64 +├──etcd +├──kube-apiserver +└──kubectl -1 directory, 3 files +1directory,3files ``` -You can use environment variables and/or flags to specify the `kubectl`,`api-server` and `etcd` setup within your integration tests. +Youcanuseenvironmentvariablesand/orflagstospecifythe`kubectl`,`api-server`and`etcd`setupwithinyourintegrationtests. -### Environment Variables +###EnvironmentVariables -| Variable name | Type | When to use | -| --- | :--- | :--- | -| `USE_EXISTING_CLUSTER` | boolean | Instead of setting up a local control plane, point to the control plane of an existing cluster. | -| `KUBEBUILDER_ASSETS` | path to directory | Point integration tests to a directory containing all binaries (api-server, etcd and kubectl). | -| `TEST_ASSET_KUBE_APISERVER`, `TEST_ASSET_ETCD`, `TEST_ASSET_KUBECTL` | paths to, respectively, api-server, etcd and kubectl binaries | Similar to `KUBEBUILDER_ASSETS`, but more granular. Point integration tests to use binaries other than the default ones. These environment variables can also be used to ensure specific tests run with expected versions of these binaries. | -| `KUBEBUILDER_CONTROLPLANE_START_TIMEOUT` and `KUBEBUILDER_CONTROLPLANE_STOP_TIMEOUT` | durations in format supported by [`time.ParseDuration`](https://golang.org/pkg/time/#ParseDuration) | Specify timeouts different from the default for the test control plane to (respectively) start and stop; any test run that exceeds them will fail. | -| `KUBEBUILDER_ATTACH_CONTROL_PLANE_OUTPUT` | boolean | Set to `true` to attach the control plane's stdout and stderr to os.Stdout and os.Stderr. This can be useful when debugging test failures, as output will include output from the control plane. | +|Variablename|Type|Whentouse| +|---|:---|:---| +|`USE_EXISTING_CLUSTER`|boolean|Insteadofsettingupalocalcontrolplane,pointtothecontrolplaneofanexistingcluster.| +|`KUBEBUILDER_ASSETS`|pathtodirectory|Pointintegrationteststoadirectorycontainingallbinaries(api-server,etcdandkubectl).| +|`TEST_ASSET_KUBE_APISERVER`,`TEST_ASSET_ETCD`,`TEST_ASSET_KUBECTL`|pathsto,respectively,api-server,etcdandkubectlbinaries|Similarto`KUBEBUILDER_ASSETS`,butmoregranular.Pointintegrationteststousebinariesotherthanthedefaultones.Theseenvironmentvariablescanalsobeusedtoensurespecifictestsrunwithexpectedversionsofthesebinaries.| +|`KUBEBUILDER_CONTROLPLANE_START_TIMEOUT`and`KUBEBUILDER_CONTROLPLANE_STOP_TIMEOUT`|durationsinformatsupportedby[`time.ParseDuration`](https://golang.org/pkg/time/#ParseDuration)|Specifytimeoutsdifferentfromthedefaultforthetestcontrolplaneto(respectively)startandstop;anytestrunthatexceedsthemwillfail.| +|`KUBEBUILDER_ATTACH_CONTROL_PLANE_OUTPUT`|boolean|Setto`true`toattachthecontrolplane'sstdoutandstderrtoos.Stdoutandos.Stderr.Thiscanbeusefulwhendebuggingtestfailures,asoutputwillincludeoutputfromthecontrolplane.| -See that the `test` makefile target will ensure that all is properly setup when you are using it. However, if you would like to run the tests without use the Makefile targets, for example via an IDE, then you can set the environment variables directly in the code of your `suite_test.go`: +Seethatthe`test`makefiletargetwillensurethatallisproperlysetupwhenyouareusingit.However,ifyouwouldliketorunthetestswithoutusetheMakefiletargets,forexampleviaanIDE,thenyoucansettheenvironmentvariablesdirectlyinthecodeofyour`suite_test.go`: ```go -var _ = BeforeSuite(func(done Done) { - Expect(os.Setenv("TEST_ASSET_KUBE_APISERVER", "../bin/k8s/1.25.0-darwin-amd64/kube-apiserver")).To(Succeed()) - Expect(os.Setenv("TEST_ASSET_ETCD", "../bin/k8s/1.25.0-darwin-amd64/etcd")).To(Succeed()) - Expect(os.Setenv("TEST_ASSET_KUBECTL", "../bin/k8s/1.25.0-darwin-amd64/kubectl")).To(Succeed()) - // OR - Expect(os.Setenv("KUBEBUILDER_ASSETS", "../bin/k8s/1.25.0-darwin-amd64")).To(Succeed()) +var_=BeforeSuite(func(doneDone){ +Expect(os.Setenv("TEST_ASSET_KUBE_APISERVER","../bin/k8s/1.25.0-darwin-amd64/kube-apiserver")).To(Succeed()) +Expect(os.Setenv("TEST_ASSET_ETCD","../bin/k8s/1.25.0-darwin-amd64/etcd")).To(Succeed()) +Expect(os.Setenv("TEST_ASSET_KUBECTL","../bin/k8s/1.25.0-darwin-amd64/kubectl")).To(Succeed()) +//OR +Expect(os.Setenv("KUBEBUILDER_ASSETS","../bin/k8s/1.25.0-darwin-amd64")).To(Succeed()) - logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) - testenv = &envtest.Environment{} +logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter),zap.UseDevMode(true))) +testenv=&envtest.Environment{} - _, err := testenv.Start() - Expect(err).NotTo(HaveOccurred()) +_,err:=testenv.Start() +Expect(err).NotTo(HaveOccurred()) - close(done) -}, 60) +close(done) +},60) -var _ = AfterSuite(func() { - Expect(testenv.Stop()).To(Succeed()) +var_=AfterSuite(func(){ +Expect(testenv.Stop()).To(Succeed()) - Expect(os.Unsetenv("TEST_ASSET_KUBE_APISERVER")).To(Succeed()) - Expect(os.Unsetenv("TEST_ASSET_ETCD")).To(Succeed()) - Expect(os.Unsetenv("TEST_ASSET_KUBECTL")).To(Succeed()) +Expect(os.Unsetenv("TEST_ASSET_KUBE_APISERVER")).To(Succeed()) +Expect(os.Unsetenv("TEST_ASSET_ETCD")).To(Succeed()) +Expect(os.Unsetenv("TEST_ASSET_KUBECTL")).To(Succeed()) }) ``` - -### Flags -Here's an example of modifying the flags with which to start the API server in your integration tests, compared to the default values in `envtest.DefaultKubeAPIServerFlags`: +###Flags +Here'sanexampleofmodifyingtheflagswithwhichtostarttheAPIserverinyourintegrationtests,comparedtothedefaultvaluesin`envtest.DefaultKubeAPIServerFlags`: ```go -customApiServerFlags := []string{ - "--secure-port=6884", - "--admission-control=MutatingAdmissionWebhook", +customApiServerFlags:=[]string{ +"--secure-port=6884", +"--admission-control=MutatingAdmissionWebhook", } -apiServerFlags := append([]string(nil), envtest.DefaultKubeAPIServerFlags...) -apiServerFlags = append(apiServerFlags, customApiServerFlags...) +apiServerFlags:=append([]string(nil),envtest.DefaultKubeAPIServerFlags...) +apiServerFlags=append(apiServerFlags,customApiServerFlags...) -testEnv = &envtest.Environment{ - CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")}, - KubeAPIServerFlags: apiServerFlags, +testEnv=&envtest.Environment{ +CRDDirectoryPaths:[]string{filepath.Join("..","config","crd","bases")}, +KubeAPIServerFlags:apiServerFlags, } ``` -## Testing considerations +##Testingconsiderations -Unless you're using an existing cluster, keep in mind that no built-in controllers are running in the test context. In some ways, the test control plane will behave differently from "real" clusters, and that might have an impact on how you write tests. One common example is garbage collection; because there are no controllers monitoring built-in resources, objects do not get deleted, even if an `OwnerReference` is set up. +Unlessyou'reusinganexistingcluster,keepinmindthatnobuilt-incontrollersarerunninginthetestcontext.Insomeways,thetestcontrolplanewillbehavedifferentlyfrom"real"clusters,andthatmighthaveanimpactonhowyouwritetests.Onecommonexampleisgarbagecollection;becausetherearenocontrollersmonitoringbuilt-inresources,objectsdonotgetdeleted,evenifan`OwnerReference`issetup. -To test that the deletion lifecycle works, test the ownership instead of asserting on existence. For example: +Totestthatthedeletionlifecycleworks,testtheownershipinsteadofassertingonexistence.Forexample: ```go -expectedOwnerReference := v1.OwnerReference{ - Kind: "MyCoolCustomResource", - APIVersion: "my.api.example.com/v1beta1", - UID: "d9607e19-f88f-11e6-a518-42010a800195", - Name: "userSpecifiedResourceName", +expectedOwnerReference:=v1.OwnerReference{ +Kind:"MyCoolCustomResource", +APIVersion:"my.api.example.com/v1beta1", +UID:"d9607e19-f88f-11e6-a518-42010a800195", +Name:"userSpecifiedResourceName", } Expect(deployment.ObjectMeta.OwnerReferences).To(ContainElement(expectedOwnerReference)) ``` - -## Cert-Manager and Prometheus options +##Cert-ManagerandPrometheusoptions -Projects scaffolded with Kubebuilder can enable the [`metrics`][metrics] and the [`cert-manager`][cert-manager] options. Note that when we are using the ENV TEST we are looking to test the controllers and their reconciliation. It is considered an integrated test because the ENV TEST API will do the test against a cluster and because of this the binaries are downloaded and used to configure its pre-requirements, however, its purpose is mainly to `unit` test the controllers. +ProjectsscaffoldedwithKubebuildercanenablethe[`metrics`][metrics]andthe[`cert-manager`][cert-manager]options.NotethatwhenweareusingtheENVTESTwearelookingtotestthecontrollersandtheirreconciliation.ItisconsideredanintegratedtestbecausetheENVTESTAPIwilldothetestagainstaclusterandbecauseofthisthebinariesaredownloadedandusedtoconfigureitspre-requirements,however,itspurposeismainlyto`unit`testthecontrollers. -Therefore, to test a reconciliation in common cases you do not need to care about these options. However, if you would like to do tests with the Prometheus and the Cert-manager installed you can add the required steps to install them before running the tests. -Following an example. +Therefore,totestareconciliationincommoncasesyoudonotneedtocareabouttheseoptions.However,ifyouwouldliketodotestswiththePrometheusandtheCert-managerinstalledyoucanaddtherequiredstepstoinstallthembeforerunningthetests. +Followinganexample. ```go - // Add the operations to install the Prometheus operator and the cert-manager - // before the tests. - BeforeEach(func() { - By("installing prometheus operator") - Expect(utils.InstallPrometheusOperator()).To(Succeed()) - - By("installing the cert-manager") - Expect(utils.InstallCertManager()).To(Succeed()) - }) - - // You can also remove them after the tests:: - AfterEach(func() { - By("uninstalling the Prometheus manager bundle") - utils.UninstallPrometheusOperManager() - - By("uninstalling the cert-manager bundle") - utils.UninstallCertManager() - }) +//AddtheoperationstoinstallthePrometheusoperatorandthecert-manager +//beforethetests. +BeforeEach(func(){ +By("installingprometheusoperator") +Expect(utils.InstallPrometheusOperator()).To(Succeed()) + +By("installingthecert-manager") +Expect(utils.InstallCertManager()).To(Succeed()) +}) + +//Youcanalsoremovethemafterthetests:: +AfterEach(func(){ +By("uninstallingthePrometheusmanagerbundle") +utils.UninstallPrometheusOperManager() + +By("uninstallingthecert-managerbundle") +utils.UninstallCertManager() +}) ``` -Check the following example of how you can implement the above operations: +Checkthefollowingexampleofhowyoucanimplementtheaboveoperations: ```go -const ( - prometheusOperatorVersion = "0.51" - prometheusOperatorURL = "https://raw.githubusercontent.com/prometheus-operator/" + "prometheus-operator/release-%s/bundle.yaml" - certmanagerVersion = "v1.5.3" - certmanagerURLTmpl = "https://github.com/cert-manager/cert-manager/releases/download/%s/cert-manager.yaml" +const( +prometheusOperatorVersion="0.51" +prometheusOperatorURL="https://raw.githubusercontent.com/prometheus-operator/"+"prometheus-operator/release-%s/bundle.yaml" +certmanagerVersion="v1.5.3" +certmanagerURLTmpl="https://github.com/cert-manager/cert-manager/releases/download/%s/cert-manager.yaml" ) -func warnError(err error) { - fmt.Fprintf(GinkgoWriter, "warning: %v\n", err) +funcwarnError(errerror){ +fmt.Fprintf(GinkgoWriter,"warning:%v\n",err) +} + +//InstallPrometheusOperatorinstallstheprometheusOperatortobeusedtoexporttheenabledmetrics. +funcInstallPrometheusOperator()error{ +url:=fmt.Sprintf(prometheusOperatorURL,prometheusOperatorVersion) +cmd:=exec.Command("kubectl","apply","-f",url) +_,err:=Run(cmd) +returnerr +} + +//UninstallPrometheusOperatoruninstallstheprometheus +funcUninstallPrometheusOperator(){ +url:=fmt.Sprintf(prometheusOperatorURL,prometheusOperatorVersion) +cmd:=exec.Command("kubectl","delete","-f",url) +if_,err:=Run(cmd);err!=nil{ +warnError(err) +} } -// 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", "apply", "-f", url) - _, err := Run(cmd) - return err +//UninstallCertManageruninstallsthecertmanager +funcUninstallCertManager(){ +url:=fmt.Sprintf(certmanagerURLTmpl,certmanagerVersion) +cmd:=exec.Command("kubectl","delete","-f",url) +if_,err:=Run(cmd);err!=nil{ +warnError(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) - } +//InstallCertManagerinstallsthecertmanagerbundle. +funcInstallCertManager()error{ +url:=fmt.Sprintf(certmanagerURLTmpl,certmanagerVersion) +cmd:=exec.Command("kubectl","apply","-f",url) +if_,err:=Run(cmd);err!=nil{ +returnerr } +//Waitforcert-manager-webhooktobeready,whichcantaketimeifcert-manager +//wasre-installedafteruninstallingonacluster. +cmd=exec.Command("kubectl","wait","deployment.apps/cert-manager-webhook", +"--for","condition=Available", +"--namespace","cert-manager", +"--timeout","5m", +) -// 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) - } +_,err:=Run(cmd) +returnerr } -// 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 +//LoadImageToKindClusterloadsalocaldockerimagetothekindcluster +funcLoadImageToKindClusterWithName(namestring)error{ +cluster:="kind" +ifv,ok:=os.LookupEnv("KIND_CLUSTER");ok{ +cluster=v } -// LoadImageToKindCluster 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 +kindOptions:=[]string{"load","docker-image",name,"--name",cluster} +cmd:=exec.Command("kind",kindOptions...) +_,err:=Run(cmd) +returnerr } ``` -However, see that tests for the metrics and cert-manager might fit better well as e2e tests and not under the tests done using ENV TEST for the controllers. You might want to give a look at the [sample example][sdk-e2e-sample-example] implemented into [Operator-SDK][sdk] repository to know how you can write your e2e tests to ensure the basic workflows of your project. -Also, see that you can run the tests against a cluster where you have some configurations in place they can use the option to test using an existing cluster: +However,seethattestsforthemetricsandcert-managermightfitbetterwellase2etestsandnotunderthetestsdoneusingENVTESTforthecontrollers.Youmightwanttogivealookatthe[sampleexample][sdk-e2e-sample-example]implementedinto[Operator-SDK][sdk]repositorytoknowhowyoucanwriteyoure2eteststoensurethebasicworkflowsofyourproject. +Also,seethatyoucanrunthetestsagainstaclusterwhereyouhavesomeconfigurationsinplacetheycanusetheoptiontotestusinganexistingcluster: ```go -testEnv = &envtest.Environment{ - UseExistingCluster: true, +testEnv=&envtest.Environment{ +UseExistingCluster:true, } ``` -[metrics]: https://book.kubebuilder.io/reference/metrics.html -[envtest]: https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/envtest -[setup-envtest]: https://pkg.go.dev/sigs.k8s.io/controller-runtime/tools/setup-envtest -[cert-manager]: https://book.kubebuilder.io/cronjob-tutorial/cert-manager.html -[sdk-e2e-sample-example]: https://github.com/operator-framework/operator-sdk/tree/master/testdata/go/v3/memcached-operator/test/e2e -[sdk]: https://github.com/operator-framework/operator-sdk +[metrics]:https://book.kubebuilder.io/reference/metrics.html +[envtest]:https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/envtest +[setup-envtest]:https://pkg.go.dev/sigs.k8s.io/controller-runtime/tools/setup-envtest +[cert-manager]:https://book.kubebuilder.io/cronjob-tutorial/cert-manager.html +[sdk-e2e-sample-example]:https://github.com/operator-framework/operator-sdk/tree/master/testdata/go/v3/memcached-operator/test/e2e +[sdk]:https://github.com/operator-framework/operator-sdk diff --git a/docs/book/src/reference/generating-crd.md b/docs/book/src/reference/generating-crd.md index 3fd12cc8f25..1f72ac22db8 100644 --- a/docs/book/src/reference/generating-crd.md +++ b/docs/book/src/reference/generating-crd.md @@ -1,243 +1,243 @@ -# Generating CRDs +#GeneratingCRDs -Kubebuilder uses a tool called [`controller-gen`][controller-tools] to -generate utility code and Kubernetes object YAML, like +Kubebuilderusesatoolcalled[`controller-gen`][controller-tools]to +generateutilitycodeandKubernetesobjectYAML,like CustomResourceDefinitions. -To do this, it makes use of special "marker comments" (comments that start -with `// +`) to indicate additional information about fields, types, and -packages. In the case of CRDs, these are generally pulled from your -`_types.go` files. For more information on markers, see the [marker -reference docs][marker-ref]. +Todothis,itmakesuseofspecial"markercomments"(commentsthatstart +with`//+`)toindicateadditionalinformationaboutfields,types,and +packages.InthecaseofCRDs,thesearegenerallypulledfromyour +`_types.go`files.Formoreinformationonmarkers,seethe[marker +referencedocs][marker-ref]. -Kubebuilder provides a `make` target to run controller-gen and generate -CRDs: `make manifests`. +Kubebuilderprovidesa`make`targettoruncontroller-genandgenerate +CRDs:`makemanifests`. -When you run `make manifests`, you should see CRDs generated under the -`config/crd/bases` directory. `make manifests` can generate a number of -other artifacts as well -- see the [marker reference docs][marker-ref] for -more details. +Whenyourun`makemanifests`,youshouldseeCRDsgeneratedunderthe +`config/crd/bases`directory.`makemanifests`cangenerateanumberof +otherartifactsaswell--seethe[markerreferencedocs][marker-ref]for +moredetails. -## Validation +##Validation -CRDs support [declarative validation][kube-validation] using an [OpenAPI -v3 schema][openapi-schema] in the `validation` section. +CRDssupport[declarativevalidation][kube-validation]usingan[OpenAPI +v3schema][openapi-schema]inthe`validation`section. -In general, [validation markers](./markers/crd-validation.md) may be -attached to fields or to types. If you're defining complex validation, if -you need to re-use validation, or if you need to validate slice elements, -it's often best to define a new type to describe your validation. +Ingeneral,[validationmarkers](./markers/crd-validation.md)maybe +attachedtofieldsortotypes.Ifyou'redefiningcomplexvalidation,if +youneedtore-usevalidation,orifyouneedtovalidatesliceelements, +it'softenbesttodefineanewtypetodescribeyourvalidation. -For example: +Forexample: ```go -type ToySpec struct { - // +kubebuilder:validation:MaxLength=15 - // +kubebuilder:validation:MinLength=1 - Name string `json:"name,omitempty"` - - // +kubebuilder:validation:MaxItems=500 - // +kubebuilder:validation:MinItems=1 - // +kubebuilder:validation:UniqueItems=true - Knights []string `json:"knights,omitempty"` - - Alias Alias `json:"alias,omitempty"` - Rank Rank `json:"rank"` +typeToySpecstruct{ +//+kubebuilder:validation:MaxLength=15 +//+kubebuilder:validation:MinLength=1 +Namestring`json:"name,omitempty"` + +//+kubebuilder:validation:MaxItems=500 +//+kubebuilder:validation:MinItems=1 +//+kubebuilder:validation:UniqueItems=true +Knights[]string`json:"knights,omitempty"` + +AliasAlias`json:"alias,omitempty"` +RankRank`json:"rank"` } -// +kubebuilder:validation:Enum=Lion;Wolf;Dragon -type Alias string +//+kubebuilder:validation:Enum=Lion;Wolf;Dragon +typeAliasstring -// +kubebuilder:validation:Minimum=1 -// +kubebuilder:validation:Maximum=3 -// +kubebuilder:validation:ExclusiveMaximum=false -type Rank int32 +//+kubebuilder:validation:Minimum=1 +//+kubebuilder:validation:Maximum=3 +//+kubebuilder:validation:ExclusiveMaximum=false +typeRankint32 ``` -## Additional Printer Columns +##AdditionalPrinterColumns -Starting with Kubernetes 1.11, `kubectl get` can ask the server what -columns to display. For CRDs, this can be used to provide useful, -type-specific information with `kubectl get`, similar to the information -provided for built-in types. +StartingwithKubernetes1.11,`kubectlget`canasktheserverwhat +columnstodisplay.ForCRDs,thiscanbeusedtoprovideuseful, +type-specificinformationwith`kubectlget`,similartotheinformation +providedforbuilt-intypes. -The information that gets displayed can be controlled with the -[additionalPrinterColumns field][kube-additional-printer-columns] on your -CRD, which is controlled by the -[`+kubebuilder:printcolumn`][crd-markers] marker on the Go type for -your CRD. +Theinformationthatgetsdisplayedcanbecontrolledwiththe +[additionalPrinterColumnsfield][kube-additional-printer-columns]onyour +CRD,whichiscontrolledbythe +[`+kubebuilder:printcolumn`][crd-markers]markerontheGotypefor +yourCRD. -For instance, in the following example, we add fields to display -information about the knights, rank, and alias fields from the validation +Forinstance,inthefollowingexample,weaddfieldstodisplay +informationabouttheknights,rank,andaliasfieldsfromthevalidation example: ```go -// +kubebuilder:printcolumn:name="Alias",type=string,JSONPath=`.spec.alias` -// +kubebuilder:printcolumn:name="Rank",type=integer,JSONPath=`.spec.rank` -// +kubebuilder:printcolumn:name="Bravely Run Away",type=boolean,JSONPath=`.spec.knights[?(@ == "Sir Robin")]`,description="when danger rears its ugly head, he bravely turned his tail and fled",priority=10 -// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp" -type Toy struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec ToySpec `json:"spec,omitempty"` - Status ToyStatus `json:"status,omitempty"` +//+kubebuilder:printcolumn:name="Alias",type=string,JSONPath=`.spec.alias` +//+kubebuilder:printcolumn:name="Rank",type=integer,JSONPath=`.spec.rank` +//+kubebuilder:printcolumn:name="BravelyRunAway",type=boolean,JSONPath=`.spec.knights[?(@=="SirRobin")]`,description="whendangerrearsitsuglyhead,hebravelyturnedhistailandfled",priority=10 +//+kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp" +typeToystruct{ +metav1.TypeMeta`json:",inline"` +metav1.ObjectMeta`json:"metadata,omitempty"` + +SpecToySpec`json:"spec,omitempty"` +StatusToyStatus`json:"status,omitempty"` } ``` -## Subresources +##Subresources -CRDs can choose to implement the `/status` and `/scale` -[subresources][kube-subresources] as of Kubernetes 1.13. +CRDscanchoosetoimplementthe`/status`and`/scale` +[subresources][kube-subresources]asofKubernetes1.13. -It's generally recommended that you make use of the `/status` subresource -on all resources that have a status field. +It'sgenerallyrecommendedthatyoumakeuseofthe`/status`subresource +onallresourcesthathaveastatusfield. -Both subresources have a corresponding [marker][crd-markers]. +Bothsubresourceshaveacorresponding[marker][crd-markers]. -### Status +###Status -The status subresource is enabled via `+kubebuilder:subresource:status`. -When enabled, updates at the main resource will not change status. -Similarly, updates to the status subresource cannot change anything but -the status field. +Thestatussubresourceisenabledvia`+kubebuilder:subresource:status`. +Whenenabled,updatesatthemainresourcewillnotchangestatus. +Similarly,updatestothestatussubresourcecannotchangeanythingbut +thestatusfield. -For example: +Forexample: ```go -// +kubebuilder:subresource:status -type Toy struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` +//+kubebuilder:subresource:status +typeToystruct{ +metav1.TypeMeta`json:",inline"` +metav1.ObjectMeta`json:"metadata,omitempty"` - Spec ToySpec `json:"spec,omitempty"` - Status ToyStatus `json:"status,omitempty"` +SpecToySpec`json:"spec,omitempty"` +StatusToyStatus`json:"status,omitempty"` } ``` -### Scale +###Scale -The scale subresource is enabled via `+kubebuilder:subresource:scale`. -When enabled, users will be able to use `kubectl scale` with your -resource. If the `selectorpath` argument pointed to the string form of -a label selector, the HorizontalPodAutoscaler will be able to autoscale -your resource. +Thescalesubresourceisenabledvia`+kubebuilder:subresource:scale`. +Whenenabled,userswillbeabletouse`kubectlscale`withyour +resource.Ifthe`selectorpath`argumentpointedtothestringformof +alabelselector,theHorizontalPodAutoscalerwillbeabletoautoscale +yourresource. -For example: +Forexample: ```go -type CustomSetSpec struct { - Replicas *int32 `json:"replicas"` +typeCustomSetSpecstruct{ +Replicas*int32`json:"replicas"` } -type CustomSetStatus struct { - Replicas int32 `json:"replicas"` - Selector string `json:"selector"` // this must be the string form of the selector +typeCustomSetStatusstruct{ +Replicasint32`json:"replicas"` +Selectorstring`json:"selector"`//thismustbethestringformoftheselector } -// +kubebuilder:subresource:status -// +kubebuilder:subresource:scale:specpath=.spec.replicas,statuspath=.status.replicas,selectorpath=.status.selector -type CustomSet struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` +//+kubebuilder:subresource:status +//+kubebuilder:subresource:scale:specpath=.spec.replicas,statuspath=.status.replicas,selectorpath=.status.selector +typeCustomSetstruct{ +metav1.TypeMeta`json:",inline"` +metav1.ObjectMeta`json:"metadata,omitempty"` - Spec CustomSetSpec `json:"spec,omitempty"` - Status CustomSetStatus `json:"status,omitempty"` +SpecCustomSetSpec`json:"spec,omitempty"` +StatusCustomSetStatus`json:"status,omitempty"` } ``` -## Multiple Versions +##MultipleVersions -As of Kubernetes 1.13, you can have multiple versions of your Kind defined -in your CRD, and use a webhook to convert between them. +AsofKubernetes1.13,youcanhavemultipleversionsofyourKinddefined +inyourCRD,anduseawebhooktoconvertbetweenthem. -For more details on this process, see the [multiversion +Formoredetailsonthisprocess,seethe[multiversion tutorial](/multiversion-tutorial/tutorial.md). -By default, Kubebuilder disables generating different validation for -different versions of the Kind in your CRD, to be compatible with older -Kubernetes versions. +Bydefault,Kubebuilderdisablesgeneratingdifferentvalidationfor +differentversionsoftheKindinyourCRD,tobecompatiblewitholder +Kubernetesversions. -You'll need to enable this by switching the line in your makefile that -says `CRD_OPTIONS ?= "crd:trivialVersions=true,preserveUnknownFields=false` -to `CRD_OPTIONS ?= crd:preserveUnknownFields=false` if using v1beta CRDs, -and `CRD_OPTIONS ?= crd` if using v1 (recommended). +You'llneedtoenablethisbyswitchingthelineinyourmakefilethat +says`CRD_OPTIONS?="crd:trivialVersions=true,preserveUnknownFields=false` +to`CRD_OPTIONS?=crd:preserveUnknownFields=false`ifusingv1betaCRDs, +and`CRD_OPTIONS?=crd`ifusingv1(recommended). -Then, you can use the `+kubebuilder:storageversion` [marker][crd-markers] -to indicate the [GVK](/cronjob-tutorial/gvks.md "Group-Version-Kind") that -should be used to store data by the API server. +Then,youcanusethe`+kubebuilder:storageversion`[marker][crd-markers] +toindicatethe[GVK](/cronjob-tutorial/gvks.md"Group-Version-Kind")that +shouldbeusedtostoredatabytheAPIserver. -### Supporting older cluster versions +###Supportingolderclusterversions -By default, `kubebuilder create api` will create CRDs of API version `v1`, -a version introduced in Kubernetes v1.16. If your project intends to support -Kubernetes cluster versions older than v1.16, you must use the `v1beta1` API version: +Bydefault,`kubebuildercreateapi`willcreateCRDsofAPIversion`v1`, +aversionintroducedinKubernetesv1.16.Ifyourprojectintendstosupport +Kubernetesclusterversionsolderthanv1.16,youmustusethe`v1beta1`APIversion: ```sh -kubebuilder create api --crd-version v1beta1 ... +kubebuildercreateapi--crd-versionv1beta1... ``` -To support Kubernetes clusters of version v1.14 or lower, you'll also need to -remove the controller-gen option `preserveUnknownFields=false` from your Makefile. -This is done by switching the line that says -`CRD_OPTIONS ?= "crd:trivialVersions=true,preserveUnknownFields=false` -to `CRD_OPTIONS ?= crd:trivialVersions=true` +TosupportKubernetesclustersofversionv1.14orlower,you'llalsoneedto +removethecontroller-genoption`preserveUnknownFields=false`fromyourMakefile. +Thisisdonebyswitchingthelinethatsays +`CRD_OPTIONS?="crd:trivialVersions=true,preserveUnknownFields=false` +to`CRD_OPTIONS?=crd:trivialVersions=true` - -## Under the hood +##Underthehood -Kubebuilder scaffolds out make rules to run `controller-gen`. The rules -will automatically install controller-gen if it's not on your path using -`go install` with Go modules. +Kubebuilderscaffoldsoutmakerulestorun`controller-gen`.Therules +willautomaticallyinstallcontroller-genifit'snotonyourpathusing +`goinstall`withGomodules. -You can also run `controller-gen` directly, if you want to see what it's +Youcanalsorun`controller-gen`directly,ifyouwanttoseewhatit's doing. -Each controller-gen "generator" is controlled by an option to -controller-gen, using the same syntax as markers. controller-gen -also supports different output "rules" to control how and where output goes. -Notice the `manifests` make rule (condensed slightly to only generate CRDs): +Eachcontroller-gen"generator"iscontrolledbyanoptionto +controller-gen,usingthesamesyntaxasmarkers.controller-gen +alsosupportsdifferentoutput"rules"tocontrolhowandwhereoutputgoes. +Noticethe`manifests`makerule(condensedslightlytoonlygenerateCRDs): ```makefile -# Generate manifests for CRDs -manifests: controller-gen - $(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases +#GeneratemanifestsforCRDs +manifests:controller-gen +$(CONTROLLER_GEN)rbac:roleName=manager-rolecrdwebhookpaths="./..."output:crd:artifacts:config=config/crd/bases ``` -It uses the `output:crd:artifacts` output rule to indicate that -CRD-related config (non-code) artifacts should end up in -`config/crd/bases` instead of `config/crd`. +Itusesthe`output:crd:artifacts`outputruletoindicatethat +CRD-relatedconfig(non-code)artifactsshouldendupin +`config/crd/bases`insteadof`config/crd`. -To see all the options including generators for `controller-gen`, run +Toseealltheoptionsincludinggeneratorsfor`controller-gen`,run ```shell -$ controller-gen -h +$controller-gen-h ``` -or, for more details: +or,formoredetails: ```shell -$ controller-gen -hhh +$controller-gen-hhh ``` -[marker-ref]: ./markers.md "Markers for Config/Code Generation" +[marker-ref]:./markers.md"MarkersforConfig/CodeGeneration" -[kube-validation]: https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/#validation "Custom Resource Definitions: Validation" +[kube-validation]:https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/#validation"CustomResourceDefinitions:Validation" -[openapi-schema]: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#schemaObject "OpenAPI v3" +[openapi-schema]:https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#schemaObject"OpenAPIv3" -[kube-additional-printer-columns]: https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/#additional-printer-columns "Custom Resource Definitions: Additional Printer Columns" +[kube-additional-printer-columns]:https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/#additional-printer-columns"CustomResourceDefinitions:AdditionalPrinterColumns" -[kube-subresources]: https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/#status-subresource "Custom Resource Definitions: Status Subresource" +[kube-subresources]:https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/#status-subresource"CustomResourceDefinitions:StatusSubresource" -[crd-markers]: ./markers/crd.md "CRD Generation" +[crd-markers]:./markers/crd.md"CRDGeneration" -[controller-tools]: https://sigs.k8s.io/controller-tools "Controller Tools" +[controller-tools]:https://sigs.k8s.io/controller-tools"ControllerTools" diff --git a/docs/book/src/reference/good-practices.md b/docs/book/src/reference/good-practices.md index 08def0b8128..dc38cfae64a 100644 --- a/docs/book/src/reference/good-practices.md +++ b/docs/book/src/reference/good-practices.md @@ -1,87 +1,87 @@ -# Good Practices +#GoodPractices -## What is "Reconciliation" in Operators? +##Whatis"Reconciliation"inOperators? -When you create a project using Kubebuilder, see the scaffolded code generated under `cmd/main.go`. This code initializes a [Manager][controller-runtime-manager], and the project relies on the [controller-runtime][controller-runtime] framework. The Manager manages [Controllers][controllers], which offer a reconcile function that synchronizes resources until the desired state is achieved within the cluster. +WhenyoucreateaprojectusingKubebuilder,seethescaffoldedcodegeneratedunder`cmd/main.go`.Thiscodeinitializesa[Manager][controller-runtime-manager],andtheprojectreliesonthe[controller-runtime][controller-runtime]framework.TheManagermanages[Controllers][controllers],whichofferareconcilefunctionthatsynchronizesresourcesuntilthedesiredstateisachievedwithinthecluster. -Reconciliation is an ongoing loop that executes necessary operations to maintain the desired state, adhering to Kubernetes principles, such as the [control loop][k8s-control-loop]. For further information, check out the [Operator patterns][k8s-operator-pattern] documentation from Kubernetes to better understand those concepts. +Reconciliationisanongoingloopthatexecutesnecessaryoperationstomaintainthedesiredstate,adheringtoKubernetesprinciples,suchasthe[controlloop][k8s-control-loop].Forfurtherinformation,checkoutthe[Operatorpatterns][k8s-operator-pattern]documentationfromKubernetestobetterunderstandthoseconcepts. -## Why should reconciliations be idempotent? +##Whyshouldreconciliationsbeidempotent? -When developing operators, the controller’s reconciliation loop needs to be idempotent. By following the [Operator pattern][operator-pattern] we create [controllers][controllers] that provide a reconcile function responsible for synchronizing resources until the desired state is reached on the cluster. Developing idempotent solutions will allow the reconciler to correctly respond to generic or unexpected events, easily deal with application startup or upgrade. More explanation on this is available [here][controller-runtime-topic]. +Whendevelopingoperators,thecontroller’sreconciliationloopneedstobeidempotent.Byfollowingthe[Operatorpattern][operator-pattern]wecreate[controllers][controllers]thatprovideareconcilefunctionresponsibleforsynchronizingresourcesuntilthedesiredstateisreachedonthecluster.Developingidempotentsolutionswillallowthereconcilertocorrectlyrespondtogenericorunexpectedevents,easilydealwithapplicationstartuporupgrade.Moreexplanationonthisisavailable[here][controller-runtime-topic]. -Writing reconciliation logic according to specific events, breaks the recommendation of operator pattern and goes against the design principles of [controller-runtime][controller-runtime]. This may lead to unforeseen consequences, such as resources becoming stuck and requiring manual intervention. +Writingreconciliationlogicaccordingtospecificevents,breakstherecommendationofoperatorpatternandgoesagainstthedesignprinciplesof[controller-runtime][controller-runtime].Thismayleadtounforeseenconsequences,suchasresourcesbecomingstuckandrequiringmanualintervention. -## Understanding Kubernetes APIs and following API conventions +##UnderstandingKubernetesAPIsandfollowingAPIconventions -Building your operator commonly involves extending the Kubernetes API itself. It is helpful to understand precisely how Custom Resource Definitions (CRDs) interact with the Kubernetes API. Also, the [Kubebuilder documentation][docs] on Groups and Versions and Kinds may be helpful to understand these concepts better as they relate to operators. +BuildingyouroperatorcommonlyinvolvesextendingtheKubernetesAPIitself.ItishelpfultounderstandpreciselyhowCustomResourceDefinitions(CRDs)interactwiththeKubernetesAPI.Also,the[Kubebuilderdocumentation][docs]onGroupsandVersionsandKindsmaybehelpfultounderstandtheseconceptsbetterastheyrelatetooperators. -Additionally, we recommend checking the documentation on [Operator patterns][operator-pattern] from Kubernetes to better understand the purpose of the standard solutions built with KubeBuilder. +Additionally,werecommendcheckingthedocumentationon[Operatorpatterns][operator-pattern]fromKubernetestobetterunderstandthepurposeofthestandardsolutionsbuiltwithKubeBuilder. -## Why you should adhere to the Kubernetes API conventions and standards +##WhyyoushouldadheretotheKubernetesAPIconventionsandstandards -Embracing the [Kubernetes API conventions and standards][k8s-api-conventions] is crucial for maximizing the potential of your applications and deployments. By adhering to these established practices, you can benefit in several ways. +Embracingthe[KubernetesAPIconventionsandstandards][k8s-api-conventions]iscrucialformaximizingthepotentialofyourapplicationsanddeployments.Byadheringtotheseestablishedpractices,youcanbenefitinseveralways. -Firstly, adherence ensures seamless interoperability within the Kubernetes ecosystem. Following conventions allows your applications to work harmoniously with other components, reducing compatibility issues and promoting a consistent user experience. +Firstly,adherenceensuresseamlessinteroperabilitywithintheKubernetesecosystem.Followingconventionsallowsyourapplicationstoworkharmoniouslywithothercomponents,reducingcompatibilityissuesandpromotingaconsistentuserexperience. -Secondly, sticking to API standards enhances the maintainability and troubleshooting of your applications. Adopting familiar patterns and structures makes debugging and supporting your deployments easier, leading to more efficient operations and quicker issue resolution. +Secondly,stickingtoAPIstandardsenhancesthemaintainabilityandtroubleshootingofyourapplications.Adoptingfamiliarpatternsandstructuresmakesdebuggingandsupportingyourdeploymentseasier,leadingtomoreefficientoperationsandquickerissueresolution. -Furthermore, leveraging the Kubernetes API conventions empowers you to harness the platform's full capabilities. By working within the defined framework, you can leverage the rich set of features and resources offered by Kubernetes, enabling scalability, performance optimization, and resilience. +Furthermore,leveragingtheKubernetesAPIconventionsempowersyoutoharnesstheplatform'sfullcapabilities.Byworkingwithinthedefinedframework,youcanleveragetherichsetoffeaturesandresourcesofferedbyKubernetes,enablingscalability,performanceoptimization,andresilience. -Lastly, embracing these standards future-proofs your native solutions. By aligning with the evolving Kubernetes ecosystem, you ensure compatibility with future updates, new features, and enhancements introduced by the vibrant Kubernetes community. +Lastly,embracingthesestandardsfuture-proofsyournativesolutions.ByaligningwiththeevolvingKubernetesecosystem,youensurecompatibilitywithfutureupdates,newfeatures,andenhancementsintroducedbythevibrantKubernetescommunity. -In summary, by adhering to the Kubernetes API conventions and standards, you unlock the potential for seamless integration, simplified maintenance, optimal performance, and future-readiness, all contributing to the success of your applications and deployments. +Insummary,byadheringtotheKubernetesAPIconventionsandstandards,youunlockthepotentialforseamlessintegration,simplifiedmaintenance,optimalperformance,andfuture-readiness,allcontributingtothesuccessofyourapplicationsanddeployments. -## Why should one avoid a system design where a single controller is responsible for managing multiple CRDs (Custom Resource Definitions)(for example, an _'install_all_controller.go'_)? +##WhyshouldoneavoidasystemdesignwhereasinglecontrollerisresponsibleformanagingmultipleCRDs(CustomResourceDefinitions)(forexample,an_'install_all_controller.go'_)? -Avoid a design solution where the same controller reconciles more than one Kind. Having many Kinds (such as CRDs), that are all managed by the same controller, usually goes against the design proposed by controller-runtime. Furthermore, this might hurt concepts such as encapsulation, the Single Responsibility Principle, and Cohesion. Damaging these concepts may cause unexpected side effects and increase the difficulty of extending, reusing, or maintaining the operator. -Having one controller manage many Custom Resources (CRs) in an Operator can lead to several issues: +AvoidadesignsolutionwherethesamecontrollerreconcilesmorethanoneKind.HavingmanyKinds(suchasCRDs),thatareallmanagedbythesamecontroller,usuallygoesagainstthedesignproposedbycontroller-runtime.Furthermore,thismighthurtconceptssuchasencapsulation,theSingleResponsibilityPrinciple,andCohesion.Damagingtheseconceptsmaycauseunexpectedsideeffectsandincreasethedifficultyofextending,reusing,ormaintainingtheoperator. +HavingonecontrollermanagemanyCustomResources(CRs)inanOperatorcanleadtoseveralissues: -- **Complexity**: A single controller managing multiple CRs can increase the complexity of the code, making it harder to understand, maintain, and debug. -- **Scalability**: Each controller typically manages a single kind of CR for scalability. If a single controller handles multiple CRs, it could become a bottleneck, reducing the overall efficiency and responsiveness of your system. -- **Single Responsibility Principle**: Following this principle from software engineering, each controller should ideally have only one job. This approach simplifies development and debugging, and makes the system more robust. -- **Error Isolation**: If one controller manages multiple CRs and an error occurs, it could potentially impact all the CRs it manages. Having a single controller per CR ensures that an issue with one controller or CR does not directly affect others. -- **Concurrency and Synchronization**: A single controller managing multiple CRs could lead to race conditions and require complex synchronization, especially if the CRs have interdependencies. +-**Complexity**:AsinglecontrollermanagingmultipleCRscanincreasethecomplexityofthecode,makingithardertounderstand,maintain,anddebug. +-**Scalability**:EachcontrollertypicallymanagesasinglekindofCRforscalability.IfasinglecontrollerhandlesmultipleCRs,itcouldbecomeabottleneck,reducingtheoverallefficiencyandresponsivenessofyoursystem. +-**SingleResponsibilityPrinciple**:Followingthisprinciplefromsoftwareengineering,eachcontrollershouldideallyhaveonlyonejob.Thisapproachsimplifiesdevelopmentanddebugging,andmakesthesystemmorerobust. +-**ErrorIsolation**:IfonecontrollermanagesmultipleCRsandanerroroccurs,itcouldpotentiallyimpactalltheCRsitmanages.HavingasinglecontrollerperCRensuresthatanissuewithonecontrollerorCRdoesnotdirectlyaffectothers. +-**ConcurrencyandSynchronization**:AsinglecontrollermanagingmultipleCRscouldleadtoraceconditionsandrequirecomplexsynchronization,especiallyiftheCRshaveinterdependencies. -In conclusion, while it might seem efficient to have a single controller manage multiple CRs, it often leads to higher complexity, lower scalability, and potential stability issues. It's generally better to adhere to the single responsibility principle, where each CR is managed by its own controller. +Inconclusion,whileitmightseemefficienttohaveasinglecontrollermanagemultipleCRs,itoftenleadstohighercomplexity,lowerscalability,andpotentialstabilityissues.It'sgenerallybettertoadheretothesingleresponsibilityprinciple,whereeachCRismanagedbyitsowncontroller. -## Why is it recommended to avoid a scenario where multiple controllers are updating the same Custom Resource (CR)? +##WhyisitrecommendedtoavoidascenariowheremultiplecontrollersareupdatingthesameCustomResource(CR)? -Managing a single Custom Resource (CR) with multiple controllers can lead to several challenges: -- **Race conditions**: When multiple controllers attempt to reconcile the same CR concurrently, race conditions can emerge. These conditions can produce inconsistent or unpredictable outcomes. For example, if we try to update the CR to add a status condition, we may encounter a range of errors such as “the object has been modified; please apply your changes to the latest version and try again”, triggering a repetitive reconciliation process. -- **Concurrency issues**: When controllers have different interpretations of the CR’s state, they may constantly overwrite each other’s changes. This conflict can create a loop, with the controllers ceaselessly disputing the CR’s state. -- **Maintenance and support difficulties**: Coordinating the logic for multiple controllers operating on the same CR can increase system complexity, making it more challenging to understand or troubleshoot. Typically, a system’s behavior is easier to comprehend when each CR is managed by a single controller. -- **Status tracking complications**: We may struggle to work adequately with status conditions to accurately track the state of each component managed by the Installer. -- **Performance issues**: If multiple controllers are watching and reconciling the Installer Kind, redundant operations may occur, leading to unnecessary resource usage. -These challenges underline the importance of assigning each controller the single responsibility of managing its own CR. This will streamline our processes and ensure a more reliable system. +ManagingasingleCustomResource(CR)withmultiplecontrollerscanleadtoseveralchallenges: +-**Raceconditions**:WhenmultiplecontrollersattempttoreconcilethesameCRconcurrently,raceconditionscanemerge.Theseconditionscanproduceinconsistentorunpredictableoutcomes.Forexample,ifwetrytoupdatetheCRtoaddastatuscondition,wemayencounterarangeoferrorssuchas“theobjecthasbeenmodified;pleaseapplyyourchangestothelatestversionandtryagain”,triggeringarepetitivereconciliationprocess. +-**Concurrencyissues**:WhencontrollershavedifferentinterpretationsoftheCR’sstate,theymayconstantlyoverwriteeachother’schanges.Thisconflictcancreatealoop,withthecontrollersceaselesslydisputingtheCR’sstate. +-**Maintenanceandsupportdifficulties**:CoordinatingthelogicformultiplecontrollersoperatingonthesameCRcanincreasesystemcomplexity,makingitmorechallengingtounderstandortroubleshoot.Typically,asystem’sbehavioriseasiertocomprehendwheneachCRismanagedbyasinglecontroller. +-**Statustrackingcomplications**:WemaystruggletoworkadequatelywithstatusconditionstoaccuratelytrackthestateofeachcomponentmanagedbytheInstaller. +-**Performanceissues**:IfmultiplecontrollersarewatchingandreconcilingtheInstallerKind,redundantoperationsmayoccur,leadingtounnecessaryresourceusage. +ThesechallengesunderlinetheimportanceofassigningeachcontrollerthesingleresponsibilityofmanagingitsownCR.Thiswillstreamlineourprocessesandensureamorereliablesystem. -## Why You Should Adopt Status Conditions +##WhyYouShouldAdoptStatusConditions -We recommend you manage your solutions using Status Conditionals following the [K8s Api conventions][k8s-api-conventions] because: +WerecommendyoumanageyoursolutionsusingStatusConditionalsfollowingthe[K8sApiconventions][k8s-api-conventions]because: -- **Standardization**: Conditions provide a standardized way to represent the state of an Operator's custom resources, making it easier for users and tools to understand and interpret the resource's status. -- **Readability**: Conditions can clearly express complex states by using a combination of multiple conditions, making it easier for users to understand the current state and progress of the resource. -- **Extensibility**: As new features or states are added to your Operator, conditions can be easily extended to represent these new states without requiring significant changes to the existing API or structure. -- **Observability**: Status conditions can be monitored and tracked by cluster administrators and external monitoring tools, enabling better visibility into the state of the custom resources managed by the Operator. -- **Compatibility**: By adopting the common pattern of using conditions in Kubernetes APIs, Operator authors ensure their custom resources align with the broader ecosystem, which helps users to have a consistent experience when interacting with multiple Operators and resources in their clusters. +-**Standardization**:ConditionsprovideastandardizedwaytorepresentthestateofanOperator'scustomresources,makingiteasierforusersandtoolstounderstandandinterprettheresource'sstatus. +-**Readability**:Conditionscanclearlyexpresscomplexstatesbyusingacombinationofmultipleconditions,makingiteasierforuserstounderstandthecurrentstateandprogressoftheresource. +-**Extensibility**:AsnewfeaturesorstatesareaddedtoyourOperator,conditionscanbeeasilyextendedtorepresentthesenewstateswithoutrequiringsignificantchangestotheexistingAPIorstructure. +-**Observability**:Statusconditionscanbemonitoredandtrackedbyclusteradministratorsandexternalmonitoringtools,enablingbettervisibilityintothestateofthecustomresourcesmanagedbytheOperator. +-**Compatibility**:ByadoptingthecommonpatternofusingconditionsinKubernetesAPIs,Operatorauthorsensuretheircustomresourcesalignwiththebroaderecosystem,whichhelpsuserstohaveaconsistentexperiencewheninteractingwithmultipleOperatorsandresourcesintheirclusters. - -[docs]: /cronjob-tutorial/gvks.html -[operator-pattern]: https://kubernetes.io/docs/concepts/extend-kubernetes/operator/ -[controllers]: https://kubernetes.io/docs/concepts/architecture/controller/ -[controller-runtime-topic]: https://github.com/kubernetes-sigs/controller-runtime/blob/main/FAQ.md#q-how-do-i-have-different-logic-in-my-reconciler-for-different-types-of-events-eg-create-update-delete -[controller-runtime]: https://github.com/kubernetes-sigs/controller-runtime -[deploy-image]: /plugins/deploy-image-plugin-v1-alpha.md -[controller-runtime-manager]: https://github.com/kubernetes-sigs/controller-runtime/blob/304027bcbe4b3f6d582180aec5759eb4db3f17fd/pkg/manager/manager.go#L53 -[k8s-api-conventions]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md -[k8s-control-loop]: https://kubernetes.io/docs/concepts/architecture/controller/ -[k8s-operator-pattern]: https://kubernetes.io/docs/concepts/extend-kubernetes/operator/ +[docs]:/cronjob-tutorial/gvks.html +[operator-pattern]:https://kubernetes.io/docs/concepts/extend-kubernetes/operator/ +[controllers]:https://kubernetes.io/docs/concepts/architecture/controller/ +[controller-runtime-topic]:https://github.com/kubernetes-sigs/controller-runtime/blob/main/FAQ.md#q-how-do-i-have-different-logic-in-my-reconciler-for-different-types-of-events-eg-create-update-delete +[controller-runtime]:https://github.com/kubernetes-sigs/controller-runtime +[deploy-image]:/plugins/deploy-image-plugin-v1-alpha.md +[controller-runtime-manager]:https://github.com/kubernetes-sigs/controller-runtime/blob/304027bcbe4b3f6d582180aec5759eb4db3f17fd/pkg/manager/manager.go#L53 +[k8s-api-conventions]:https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md +[k8s-control-loop]:https://kubernetes.io/docs/concepts/architecture/controller/ +[k8s-operator-pattern]:https://kubernetes.io/docs/concepts/extend-kubernetes/operator/ diff --git a/docs/book/src/reference/kind.md b/docs/book/src/reference/kind.md index f2ad85bd2ca..f43381791ac 100644 --- a/docs/book/src/reference/kind.md +++ b/docs/book/src/reference/kind.md @@ -1,52 +1,52 @@ -# Kind Cluster +#KindCluster -This only cover the basics to use a kind cluster. You can find more details at -[kind documentation](https://kind.sigs.k8s.io/). +Thisonlycoverthebasicstouseakindcluster.Youcanfindmoredetailsat +[kinddocumentation](https://kind.sigs.k8s.io/). -## Installation +##Installation -You can follow [this](https://kind.sigs.k8s.io/#installation-and-usage) to -install `kind`. +Youcanfollow[this](https://kind.sigs.k8s.io/#installation-and-usage)to +install`kind`. -## Create a Cluster +##CreateaCluster -You can simply create a `kind` cluster by +Youcansimplycreatea`kind`clusterby ```bash -kind create cluster +kindcreatecluster ``` -To customize your cluster, you can provide additional configuration. -For example, the following is a sample `kind` configuration. +Tocustomizeyourcluster,youcanprovideadditionalconfiguration. +Forexample,thefollowingisasample`kind`configuration. ```yaml -{{#include ./kind-config.yaml}} +{{#include./kind-config.yaml}} ``` -Using the configuration above, run the following command will give you a k8s -v1.17.2 cluster with 1 control-plane node and 3 worker nodes. +Usingtheconfigurationabove,runthefollowingcommandwillgiveyouak8s +v1.17.2clusterwith1control-planenodeand3workernodes. ```bash -kind create cluster --config hack/kind-config.yaml --image=kindest/node:v1.17.2 +kindcreatecluster--confighack/kind-config.yaml--image=kindest/node:v1.17.2 ``` -You can use `--image` flag to specify the cluster version you want, e.g. -`--image=kindest/node:v1.17.2`, the supported version are listed +Youcanuse`--image`flagtospecifytheclusterversionyouwant,e.g. +`--image=kindest/node:v1.17.2`,thesupportedversionarelisted [here](https://hub.docker.com/r/kindest/node/tags). -## Load Docker Image into the Cluster +##LoadDockerImageintotheCluster -When developing with a local kind cluster, loading docker images to the cluster -is a very useful feature. You can avoid using a container registry. +Whendevelopingwithalocalkindcluster,loadingdockerimagestothecluster +isaveryusefulfeature.Youcanavoidusingacontainerregistry. ```bash -kind load docker-image your-image-name:your-tag +kindloaddocker-imageyour-image-name:your-tag ``` -See [Load a local image into a kind cluster](https://kind.sigs.k8s.io/docs/user/quick-start/#loading-an-image-into-your-cluster) for more information. +See[Loadalocalimageintoakindcluster](https://kind.sigs.k8s.io/docs/user/quick-start/#loading-an-image-into-your-cluster)formoreinformation. -## Delete a Cluster +##DeleteaCluster ```bash -kind delete cluster +kinddeletecluster ``` diff --git a/docs/book/src/reference/makefile-helpers.md b/docs/book/src/reference/makefile-helpers.md index 984c4a9f2f5..9c23e02f229 100644 --- a/docs/book/src/reference/makefile-helpers.md +++ b/docs/book/src/reference/makefile-helpers.md @@ -1,49 +1,49 @@ -# Makefile Helpers +#MakefileHelpers -By default, the projects are scaffolded with a `Makefile`. You can customize and update this file as please you. Here, you will find some helpers that can be useful. +Bydefault,theprojectsarescaffoldedwitha`Makefile`.Youcancustomizeandupdatethisfileaspleaseyou.Here,youwillfindsomehelpersthatcanbeuseful. -## To debug with go-delve +##Todebugwithgo-delve -The projects are built with Go and you have a lot of ways to do that. One of the options would be use [go-delve](https://github.com/go-delve/delve) for it: +TheprojectsarebuiltwithGoandyouhavealotofwaystodothat.Oneoftheoptionswouldbeuse[go-delve](https://github.com/go-delve/delve)forit: ```makefile -# Run with Delve for development purposes against the configured Kubernetes cluster in ~/.kube/config -# Delve is a debugger for the Go programming language. More info: https://github.com/go-delve/delve -run-delve: generate fmt vet manifests - go build -gcflags "all=-trimpath=$(shell go env GOPATH)" -o bin/manager main.go - dlv --listen=:2345 --headless=true --api-version=2 --accept-multiclient exec ./bin/manager +#RunwithDelvefordevelopmentpurposesagainsttheconfiguredKubernetesclusterin~/.kube/config +#DelveisadebuggerfortheGoprogramminglanguage.Moreinfo:https://github.com/go-delve/delve +run-delve:generatefmtvetmanifests +gobuild-gcflags"all=-trimpath=$(shellgoenvGOPATH)"-obin/managermain.go +dlv--listen=:2345--headless=true--api-version=2--accept-multiclientexec./bin/manager ``` -## To change the version of CRDs +##TochangetheversionofCRDs -The `controller-gen` program (from [controller-tools](https://github.com/kubernetes-sigs/controller-tools)) -generates CRDs for kubebuilder projects, wrapped in the following `make` rule: +The`controller-gen`program(from[controller-tools](https://github.com/kubernetes-sigs/controller-tools)) +generatesCRDsforkubebuilderprojects,wrappedinthefollowing`make`rule: ```makefile -manifests: controller-gen - $(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases +manifests:controller-gen +$(CONTROLLER_GEN)rbac:roleName=manager-rolecrdwebhookpaths="./..."output:crd:artifacts:config=config/crd/bases ``` -`controller-gen` lets you specify what CRD API version to generate (either "v1", the default, or "v1beta1"). -You can direct it to generate a specific version by adding `crd:crdVersions={}` to your `CRD_OPTIONS`, -found at the top of your Makefile: +`controller-gen`letsyouspecifywhatCRDAPIversiontogenerate(either"v1",thedefault,or"v1beta1"). +Youcandirectittogenerateaspecificversionbyadding`crd:crdVersions={}`toyour`CRD_OPTIONS`, +foundatthetopofyourMakefile: ```makefile -CRD_OPTIONS ?= "crd:crdVersions={v1beta1},preserveUnknownFields=false" +CRD_OPTIONS?="crd:crdVersions={v1beta1},preserveUnknownFields=false" -manifests: controller-gen - $(CONTROLLER_GEN) rbac:roleName=manager-role $(CRD_OPTIONS) webhook paths="./..." output:crd:artifacts:config=config/crd/bases +manifests:controller-gen +$(CONTROLLER_GEN)rbac:roleName=manager-role$(CRD_OPTIONS)webhookpaths="./..."output:crd:artifacts:config=config/crd/bases ``` -## To get all the manifests without deploying +##Togetallthemanifestswithoutdeploying -By adding `make dry-run` you can get the patched manifests in the dry-run folder, unlike `make depĺoy` which runs `kustomize` and `kubectl apply`. +Byadding`makedry-run`youcangetthepatchedmanifestsinthedry-runfolder,unlike`makedepĺoy`whichruns`kustomize`and`kubectlapply`. -To accomplish this, add the following lines to the Makefile: +Toaccomplishthis,addthefollowinglinestotheMakefile: ```makefile -dry-run: manifests - cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG} - mkdir -p dry-run - $(KUSTOMIZE) build config/default > dry-run/manifests.yaml +dry-run:manifests +cdconfig/manager&&$(KUSTOMIZE)editsetimagecontroller=${IMG} +mkdir-pdry-run +$(KUSTOMIZE)buildconfig/default>dry-run/manifests.yaml ``` diff --git a/docs/book/src/reference/markers.md b/docs/book/src/reference/markers.md index 0520717b0f2..2be5ce472a8 100644 --- a/docs/book/src/reference/markers.md +++ b/docs/book/src/reference/markers.md @@ -1,106 +1,106 @@ -# Markers for Config/Code Generation +#MarkersforConfig/CodeGeneration -Kubebuilder makes use of a tool called -[controller-gen](/reference/controller-gen.md) for -generating utility code and Kubernetes YAML. This code and config -generation is controlled by the presence of special "marker comments" in -Go code. +Kubebuildermakesuseofatoolcalled +[controller-gen](/reference/controller-gen.md)for +generatingutilitycodeandKubernetesYAML.Thiscodeandconfig +generationiscontrolledbythepresenceofspecial"markercomments"in +Gocode. -Markers are single-line comments that start with a plus, followed by -a marker name, optionally followed by some marker specific configuration: +Markersaresingle-linecommentsthatstartwithaplus,followedby +amarkername,optionallyfollowedbysomemarkerspecificconfiguration: ```go -// +kubebuilder:validation:Optional -// +kubebuilder:validation:MaxItems=2 -// +kubebuilder:printcolumn:JSONPath=".status.replicas",name=Replicas,type=string +//+kubebuilder:validation:Optional +//+kubebuilder:validation:MaxItems=2 +//+kubebuilder:printcolumn:JSONPath=".status.replicas",name=Replicas,type=string ``` - -See each subsection for information about different types of code and YAML +SeeeachsubsectionforinformationaboutdifferenttypesofcodeandYAML generation. -## Generating Code & Artifacts in Kubebuilder +##GeneratingCode&ArtifactsinKubebuilder -Kubebuilder projects have two `make` targets that make use of +Kubebuilderprojectshavetwo`make`targetsthatmakeuseof controller-gen: -- `make manifests` generates Kubernetes object YAML, like - [CustomResourceDefinitions](./markers/crd.md), - [WebhookConfigurations](./markers/webhook.md), and [RBAC - roles](./markers/rbac.md). +-`makemanifests`generatesKubernetesobjectYAML,like +[CustomResourceDefinitions](./markers/crd.md), +[WebhookConfigurations](./markers/webhook.md),and[RBAC +roles](./markers/rbac.md). -- `make generate` generates code, like [runtime.Object/DeepCopy - implementations](./markers/object.md). +-`makegenerate`generatescode,like[runtime.Object/DeepCopy +implementations](./markers/object.md). -See [Generating CRDs](./generating-crd.md) for a comprehensive overview. +See[GeneratingCRDs](./generating-crd.md)foracomprehensiveoverview. -## Marker Syntax +##MarkerSyntax -Exact syntax is described in the [godocs for +Exactsyntaxisdescribedinthe[godocsfor controller-tools](https://pkg.go.dev/sigs.k8s.io/controller-tools/pkg/markers?tab=doc). -In general, markers may either be: +Ingeneral,markersmayeitherbe: -- **Empty** (`+kubebuilder:validation:Optional`): empty markers are like boolean flags on the command line - -- just specifying them enables some behavior. +-**Empty**(`+kubebuilder:validation:Optional`):emptymarkersarelikebooleanflagsonthecommandline +--justspecifyingthemenablessomebehavior. -- **Anonymous** (`+kubebuilder:validation:MaxItems=2`): anonymous markers take - a single value as their argument. +-**Anonymous**(`+kubebuilder:validation:MaxItems=2`):anonymousmarkerstake +asinglevalueastheirargument. -- **Multi-option** - (`+kubebuilder:printcolumn:JSONPath=".status.replicas",name=Replicas,type=string`): multi-option - markers take one or more named arguments. The first argument is - separated from the name by a colon, and latter arguments are - comma-separated. Order of arguments doesn't matter. Some arguments may - be optional. +-**Multi-option** +(`+kubebuilder:printcolumn:JSONPath=".status.replicas",name=Replicas,type=string`):multi-option +markerstakeoneormorenamedarguments.Thefirstargumentis +separatedfromthenamebyacolon,andlatterargumentsare +comma-separated.Orderofargumentsdoesn'tmatter.Someargumentsmay +beoptional. -Marker arguments may be strings, ints, bools, slices, or maps thereof. -Strings, ints, and bools follow their Go syntax: +Markerargumentsmaybestrings,ints,bools,slices,ormapsthereof. +Strings,ints,andboolsfollowtheirGosyntax: ```go -// +kubebuilder:validation:ExclusiveMaximum=false -// +kubebuilder:validation:Format="date-time" -// +kubebuilder:validation:Maximum=42 +//+kubebuilder:validation:ExclusiveMaximum=false +//+kubebuilder:validation:Format="date-time" +//+kubebuilder:validation:Maximum=42 ``` -For convenience, in simple cases the quotes may be omitted from strings, -although this is not encouraged for anything other than single-word +Forconvenience,insimplecasesthequotesmaybeomittedfromstrings, +althoughthisisnotencouragedforanythingotherthansingle-word strings: ```go -// +kubebuilder:validation:Type=string +//+kubebuilder:validation:Type=string ``` -Slices may be specified either by surrounding them with curly braces and -separating with commas: +Slicesmaybespecifiedeitherbysurroundingthemwithcurlybracesand +separatingwithcommas: ```go -// +kubebuilder:webhooks:Enum={"crackers, Gromit, we forgot the crackers!","not even wensleydale?"} +//+kubebuilder:webhooks:Enum={"crackers,Gromit,weforgotthecrackers!","notevenwensleydale?"} ``` -or, in simple cases, by separating with semicolons: +or,insimplecases,byseparatingwithsemicolons: ```go -// +kubebuilder:validation:Enum=Wallace;Gromit;Chicken +//+kubebuilder:validation:Enum=Wallace;Gromit;Chicken ``` -Maps are specified with string keys and values of any type (effectively -`map[string]interface{}`). A map is surrounded by curly braces (`{}`), -each key and value is separated by a colon (`:`), and each key-value -pair is separated by a comma: +Mapsarespecifiedwithstringkeysandvaluesofanytype(effectively +`map[string]interface{}`).Amapissurroundedbycurlybraces(`{}`), +eachkeyandvalueisseparatedbyacolon(`:`),andeachkey-value +pairisseparatedbyacomma: ```go -// +kubebuilder:default={magic: {numero: 42, stringified: forty-two}} +//+kubebuilder:default={magic:{numero:42,stringified:forty-two}} ``` diff --git a/docs/book/src/reference/markers/crd-processing.md b/docs/book/src/reference/markers/crd-processing.md index ec3cd22cdae..79a5738dcd0 100644 --- a/docs/book/src/reference/markers/crd-processing.md +++ b/docs/book/src/reference/markers/crd-processing.md @@ -1,8 +1,8 @@ -# CRD Processing +#CRDProcessing -These markers help control how the Kubernetes API server processes API -requests involving your custom resources. +ThesemarkershelpcontrolhowtheKubernetesAPIserverprocessesAPI +requestsinvolvingyourcustomresources. -See [Generating CRDs](/reference/generating-crd.md) for examples. +See[GeneratingCRDs](/reference/generating-crd.md)forexamples. -{{#markerdocs CRD processing}} +{{#markerdocsCRDprocessing}} diff --git a/docs/book/src/reference/markers/crd-validation.md b/docs/book/src/reference/markers/crd-validation.md index 3307cc6b5d1..10922dfd413 100644 --- a/docs/book/src/reference/markers/crd-validation.md +++ b/docs/book/src/reference/markers/crd-validation.md @@ -1,9 +1,9 @@ -# CRD Validation +#CRDValidation -These markers modify how the CRD validation schema is produced for the -types and fields they modify. Each corresponds roughly to an OpenAPI/JSON -schema option. +ThesemarkersmodifyhowtheCRDvalidationschemaisproducedforthe +typesandfieldstheymodify.EachcorrespondsroughlytoanOpenAPI/JSON +schemaoption. -See [Generating CRDs](/reference/generating-crd.md) for examples. +See[GeneratingCRDs](/reference/generating-crd.md)forexamples. -{{#markerdocs CRD validation}} +{{#markerdocsCRDvalidation}} diff --git a/docs/book/src/reference/markers/crd.md b/docs/book/src/reference/markers/crd.md index 71846cbae51..10ca803d7cf 100644 --- a/docs/book/src/reference/markers/crd.md +++ b/docs/book/src/reference/markers/crd.md @@ -1,9 +1,9 @@ -# CRD Generation +#CRDGeneration -These markers describe how to construct a custom resource definition from -a series of Go types and packages. Generation of the actual validation -schema is described by the [validation markers](./crd-validation.md). +Thesemarkersdescribehowtoconstructacustomresourcedefinitionfrom +aseriesofGotypesandpackages.Generationoftheactualvalidation +schemaisdescribedbythe[validationmarkers](./crd-validation.md). -See [Generating CRDs](../generating-crd.md) for examples. +See[GeneratingCRDs](../generating-crd.md)forexamples. -{{#markerdocs CRD}} +{{#markerdocsCRD}} diff --git a/docs/book/src/reference/markers/object.md b/docs/book/src/reference/markers/object.md index c719f0eb7f7..12d57171d2d 100644 --- a/docs/book/src/reference/markers/object.md +++ b/docs/book/src/reference/markers/object.md @@ -1,6 +1,6 @@ -# Object/DeepCopy +#Object/DeepCopy -These markers control when `DeepCopy` and `runtime.Object` implementation -methods are generated. +Thesemarkerscontrolwhen`DeepCopy`and`runtime.Object`implementation +methodsaregenerated. -{{#markerdocs object}} +{{#markerdocsobject}} diff --git a/docs/book/src/reference/markers/rbac.md b/docs/book/src/reference/markers/rbac.md index 650aad970d6..446c21c1564 100644 --- a/docs/book/src/reference/markers/rbac.md +++ b/docs/book/src/reference/markers/rbac.md @@ -1,9 +1,9 @@ -# RBAC +#RBAC -These markers cause an [RBAC +Thesemarkerscausean[RBAC ClusterRole](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#role-and-clusterrole) -to be generated. This allows you to describe the permissions that your -controller requires alongside the code that makes use of those +tobegenerated.Thisallowsyoutodescribethepermissionsthatyour +controllerrequiresalongsidethecodethatmakesuseofthose permissions. -{{#markerdocs RBAC}} +{{#markerdocsRBAC}} diff --git a/docs/book/src/reference/markers/webhook.md b/docs/book/src/reference/markers/webhook.md index 033f574386f..496d5c5591b 100644 --- a/docs/book/src/reference/markers/webhook.md +++ b/docs/book/src/reference/markers/webhook.md @@ -1,7 +1,7 @@ -# Webhook +#Webhook -These markers describe how [webhook configuration](../webhook-overview.md) is generated. -Use these to keep the description of your webhooks close to the code that -implements them. +Thesemarkersdescribehow[webhookconfiguration](../webhook-overview.md)isgenerated. +Usethesetokeepthedescriptionofyourwebhooksclosetothecodethat +implementsthem. -{{#markerdocs Webhook}} +{{#markerdocsWebhook}} diff --git a/docs/book/src/reference/metrics-reference.md b/docs/book/src/reference/metrics-reference.md index 4e437a17658..5199ab36874 100644 --- a/docs/book/src/reference/metrics-reference.md +++ b/docs/book/src/reference/metrics-reference.md @@ -1,23 +1,23 @@ -# Default Exported Metrics References +#DefaultExportedMetricsReferences -Following the metrics which are exported and provided by [controller-runtime](https://github.com/kubernetes-sigs/controller-runtime) by default: +Followingthemetricswhichareexportedandprovidedby[controller-runtime](https://github.com/kubernetes-sigs/controller-runtime)bydefault: -| Metrics name | Type | Description | -| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [workqueue_depth](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/pkg/metrics/workqueue.go#L41) | Gauge | Current depth of workqueue. | -| [workqueue_adds_total](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/pkg/metrics/workqueue.go#L47) | Counter | Total number of adds handled by workqueue. | -| [workqueue_queue_duration_seconds](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/pkg/metrics/workqueue.go#L53) | Histogram | How long in seconds an item stays in workqueue before being requested. | -| [workqueue_work_duration_seconds](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/pkg/metrics/workqueue.go#L60) | Histogram | How long in seconds processing an item from workqueue takes. | -| [workqueue_unfinished_work_seconds](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/pkg/metrics/workqueue.go#L67) | Gauge | How many seconds of work has been done that is in progress and hasn't been observed by work_duration. Large values indicate stuck threads. One can deduce the number of stuck threads by observing the rate at which this increases. | -| [workqueue_longest_running_processor_seconds](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/pkg/metrics/workqueue.go#L76) | Gauge | How many seconds has the longest running processor for workqueue been running. | -| [workqueue_retries_total](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/pkg/metrics/workqueue.go#L83) | Counter | Total number of retries handled by workqueue. | -| [rest_client_requests_total ](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/pkg/metrics/client_go_adapter.go#L33) | Counter | Number of HTTP requests, partitioned by status code, method, and host. | -| [controller_runtime_reconcile_total ](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/pkg/internal/controller/metrics/metrics.go#L30) | Counter | Total number of reconciliations per controller. | -| [controller_runtime_reconcile_errors_total ](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/pkg/internal/controller/metrics/metrics.go#L37) | Counter | Total number of reconciliation errors per controller. | -| [controller_runtime_terminal_reconcile_errors_total ](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/pkg/internal/controller/metrics/metrics.go#L44) | Counter | Total number of terminal errors from the reconciler. | -| [controller_runtime_reconcile_time_seconds ](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/pkg/internal/controller/metrics/metrics.go#L51) | Histogram | Length of time per reconciliation per controller. | -| [controller_runtime_max_concurrent_reconciles ](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/pkg/internal/controller/metrics/metrics.go#L60) | Gauge | Maximum number of concurrent reconciles per controller. | -| [controller_runtime_active_workers ](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/pkg/internal/controller/metrics/metrics.go#L67) | Gauge | Number of currently used workers per controller. | -| [controller_runtime_webhook_latency_seconds ](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/pkg/webhook/internal/metrics/metrics.go#L31) | Histogram | Histogram of the latency of processing admission requests. | -| [controller_runtime_webhook_requests_total ](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/pkg/webhook/internal/metrics/metrics.go#L40) | Counter | Total number of admission requests by HTTP status code. | -| [controller_runtime_webhook_requests_in_flight](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/pkg/webhook/internal/metrics/metrics.go#L51) | Gauge | Current number of admission requests being served. | +|Metricsname|Type|Description| +|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +|[workqueue_depth](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/pkg/metrics/workqueue.go#L41)|Gauge|Currentdepthofworkqueue.| +|[workqueue_adds_total](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/pkg/metrics/workqueue.go#L47)|Counter|Totalnumberofaddshandledbyworkqueue.| +|[workqueue_queue_duration_seconds](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/pkg/metrics/workqueue.go#L53)|Histogram|Howlonginsecondsanitemstaysinworkqueuebeforebeingrequested.| +|[workqueue_work_duration_seconds](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/pkg/metrics/workqueue.go#L60)|Histogram|Howlonginsecondsprocessinganitemfromworkqueuetakes.| +|[workqueue_unfinished_work_seconds](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/pkg/metrics/workqueue.go#L67)|Gauge|Howmanysecondsofworkhasbeendonethatisinprogressandhasn'tbeenobservedbywork_duration.Largevaluesindicatestuckthreads.Onecandeducethenumberofstuckthreadsbyobservingtherateatwhichthisincreases.| +|[workqueue_longest_running_processor_seconds](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/pkg/metrics/workqueue.go#L76)|Gauge|Howmanysecondshasthelongestrunningprocessorforworkqueuebeenrunning.| +|[workqueue_retries_total](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/pkg/metrics/workqueue.go#L83)|Counter|Totalnumberofretrieshandledbyworkqueue.| +|[rest_client_requests_total](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/pkg/metrics/client_go_adapter.go#L33)|Counter|NumberofHTTPrequests,partitionedbystatuscode,method,andhost.| +|[controller_runtime_reconcile_total](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/pkg/internal/controller/metrics/metrics.go#L30)|Counter|Totalnumberofreconciliationspercontroller.| +|[controller_runtime_reconcile_errors_total](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/pkg/internal/controller/metrics/metrics.go#L37)|Counter|Totalnumberofreconciliationerrorspercontroller.| +|[controller_runtime_terminal_reconcile_errors_total](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/pkg/internal/controller/metrics/metrics.go#L44)|Counter|Totalnumberofterminalerrorsfromthereconciler.| +|[controller_runtime_reconcile_time_seconds](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/pkg/internal/controller/metrics/metrics.go#L51)|Histogram|Lengthoftimeperreconciliationpercontroller.| +|[controller_runtime_max_concurrent_reconciles](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/pkg/internal/controller/metrics/metrics.go#L60)|Gauge|Maximumnumberofconcurrentreconcilespercontroller.| +|[controller_runtime_active_workers](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/pkg/internal/controller/metrics/metrics.go#L67)|Gauge|Numberofcurrentlyusedworkerspercontroller.| +|[controller_runtime_webhook_latency_seconds](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/pkg/webhook/internal/metrics/metrics.go#L31)|Histogram|Histogramofthelatencyofprocessingadmissionrequests.| +|[controller_runtime_webhook_requests_total](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/pkg/webhook/internal/metrics/metrics.go#L40)|Counter|TotalnumberofadmissionrequestsbyHTTPstatuscode.| +|[controller_runtime_webhook_requests_in_flight](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.16.3/pkg/webhook/internal/metrics/metrics.go#L51)|Gauge|Currentnumberofadmissionrequestsbeingserved.| diff --git a/docs/book/src/reference/metrics.md b/docs/book/src/reference/metrics.md index 33e7e3b0a13..a26d63132a3 100644 --- a/docs/book/src/reference/metrics.md +++ b/docs/book/src/reference/metrics.md @@ -1,144 +1,144 @@ -# Metrics +#Metrics -By default, controller-runtime builds a global prometheus registry and -publishes [a collection of performance metrics](/reference/metrics-reference.md) for each controller. +Bydefault,controller-runtimebuildsaglobalprometheusregistryand +publishes[acollectionofperformancemetrics](/reference/metrics-reference.md)foreachcontroller. -## Protecting the Metrics +##ProtectingtheMetrics -These metrics are protected by [kube-rbac-proxy](https://github.com/brancz/kube-rbac-proxy) -by default if using kubebuilder. Kubebuilder v2.2.0+ scaffold a clusterrole which -can be found at `config/rbac/auth_proxy_client_clusterrole.yaml`. +Thesemetricsareprotectedby[kube-rbac-proxy](https://github.com/brancz/kube-rbac-proxy) +bydefaultifusingkubebuilder.Kubebuilderv2.2.0+scaffoldaclusterrolewhich +canbefoundat`config/rbac/auth_proxy_client_clusterrole.yaml`. -You will need to grant permissions to your Prometheus server so that it can -scrape the protected metrics. To achieve that, you can create a -`clusterRoleBinding` to bind the `clusterRole` to the service account that your -Prometheus server uses. If you are using [kube-prometheus](https://github.com/prometheus-operator/kube-prometheus), -this cluster binding already exists. +YouwillneedtograntpermissionstoyourPrometheusserversothatitcan +scrapetheprotectedmetrics.Toachievethat,youcancreatea +`clusterRoleBinding`tobindthe`clusterRole`totheserviceaccountthatyour +Prometheusserveruses.Ifyouareusing[kube-prometheus](https://github.com/prometheus-operator/kube-prometheus), +thisclusterbindingalreadyexists. -You can either run the following command, or apply the example yaml file provided below to create `clusterRoleBinding`. +Youcaneitherrunthefollowingcommand,orapplytheexampleyamlfileprovidedbelowtocreate`clusterRoleBinding`. -If using kubebuilder -`` is the `namePrefix` field in `config/default/kustomization.yaml`. +Ifusingkubebuilder +``isthe`namePrefix`fieldin`config/default/kustomization.yaml`. ```bash -kubectl create clusterrolebinding metrics --clusterrole=-metrics-reader --serviceaccount=: +kubectlcreateclusterrolebindingmetrics--clusterrole=-metrics-reader--serviceaccount=: ``` -You can also apply the following `ClusterRoleBinding`: +Youcanalsoapplythefollowing`ClusterRoleBinding`: ```yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding +apiVersion:rbac.authorization.k8s.io/v1 +kind:ClusterRoleBinding metadata: - name: prometheus-k8s-rolebinding +name:prometheus-k8s-rolebinding roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: prometheus-k8s-role +apiGroup:rbac.authorization.k8s.io +kind:ClusterRole +name:prometheus-k8s-role subjects: - - kind: ServiceAccount - name: - namespace: +-kind:ServiceAccount +name: +namespace: ``` -The `prometheus-k8s-role` referenced here should provide the necessary permissions to allow prometheus scrape metrics from operator pods. +The`prometheus-k8s-role`referencedhereshouldprovidethenecessarypermissionstoallowprometheusscrapemetricsfromoperatorpods. -## Exporting Metrics for Prometheus +##ExportingMetricsforPrometheus -Follow the steps below to export the metrics using the Prometheus Operator: +FollowthestepsbelowtoexportthemetricsusingthePrometheusOperator: -1. Install Prometheus and Prometheus Operator. - We recommend using [kube-prometheus](https://github.com/coreos/kube-prometheus#installing) - in production if you don't have your own monitoring system. - If you are just experimenting, you can only install Prometheus and Prometheus Operator. +1.InstallPrometheusandPrometheusOperator. +Werecommendusing[kube-prometheus](https://github.com/coreos/kube-prometheus#installing) +inproductionifyoudon'thaveyourownmonitoringsystem. +Ifyouarejustexperimenting,youcanonlyinstallPrometheusandPrometheusOperator. -2. Uncomment the line `- ../prometheus` in the `config/default/kustomization.yaml`. - It creates the `ServiceMonitor` resource which enables exporting the metrics. +2.Uncommenttheline`-../prometheus`inthe`config/default/kustomization.yaml`. +Itcreatesthe`ServiceMonitor`resourcewhichenablesexportingthemetrics. ```yaml -# [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'. -- ../prometheus +#[PROMETHEUS]Toenableprometheusmonitor,uncommentallsectionswith'PROMETHEUS'. +-../prometheus ``` -Note that, when you install your project in the cluster, it will create the -`ServiceMonitor` to export the metrics. To check the ServiceMonitor, -run `kubectl get ServiceMonitor -n -system`. See an example: +Notethat,whenyouinstallyourprojectinthecluster,itwillcreatethe +`ServiceMonitor`toexportthemetrics.TochecktheServiceMonitor, +run`kubectlgetServiceMonitor-n-system`.Seeanexample: ``` -$ kubectl get ServiceMonitor -n monitor-system -NAME AGE -monitor-controller-manager-metrics-monitor 2m8s +$kubectlgetServiceMonitor-nmonitor-system +NAMEAGE +monitor-controller-manager-metrics-monitor2m8s ``` - -Also, notice that the metrics are exported by default through port `8443`. In this way, -you are able to check the Prometheus metrics in its dashboard. To verify it, search -for the metrics exported from the namespace where the project is running -`{namespace="-system"}`. See an example: +Also,noticethatthemetricsareexportedbydefaultthroughport`8443`.Inthisway, +youareabletocheckthePrometheusmetricsinitsdashboard.Toverifyit,search +forthemetricsexportedfromthenamespacewheretheprojectisrunning +`{namespace="-system"}`.Seeanexample: -Screenshot 2019-10-02 at 13 07 13 + -## Publishing Additional Metrics +##PublishingAdditionalMetrics -If you wish to publish additional metrics from your controllers, this -can be easily achieved by using the global registry from +Ifyouwishtopublishadditionalmetricsfromyourcontrollers,this +canbeeasilyachievedbyusingtheglobalregistryfrom `controller-runtime/pkg/metrics`. -One way to achieve this is to declare your collectors as global variables and then register them using `init()` in the controller's package. +Onewaytoachievethisistodeclareyourcollectorsasglobalvariablesandthenregisterthemusing`init()`inthecontroller'spackage. -For example: +Forexample: ```go -import ( - "github.com/prometheus/client_golang/prometheus" - "sigs.k8s.io/controller-runtime/pkg/metrics" +import( +"github.com/prometheus/client_golang/prometheus" +"sigs.k8s.io/controller-runtime/pkg/metrics" ) -var ( - goobers = prometheus.NewCounter( - prometheus.CounterOpts{ - Name: "goobers_total", - Help: "Number of goobers proccessed", - }, - ) - gooberFailures = prometheus.NewCounter( - prometheus.CounterOpts{ - Name: "goober_failures_total", - Help: "Number of failed goobers", - }, - ) +var( +goobers=prometheus.NewCounter( +prometheus.CounterOpts{ +Name:"goobers_total", +Help:"Numberofgoobersproccessed", +}, +) +gooberFailures=prometheus.NewCounter( +prometheus.CounterOpts{ +Name:"goober_failures_total", +Help:"Numberoffailedgoobers", +}, +) ) -func init() { - // Register custom metrics with the global prometheus registry - metrics.Registry.MustRegister(goobers, gooberFailures) +funcinit(){ +//Registercustommetricswiththeglobalprometheusregistry +metrics.Registry.MustRegister(goobers,gooberFailures) } ``` -You may then record metrics to those collectors from any part of your -reconcile loop. These metrics can be evaluated from anywhere in the operator code. +Youmaythenrecordmetricstothosecollectorsfromanypartofyour +reconcileloop.Thesemetricscanbeevaluatedfromanywhereintheoperatorcode. - -Those metrics will be available for prometheus or -other openmetrics systems to scrape. +Thosemetricswillbeavailableforprometheusor +otheropenmetricssystemstoscrape. -![Screen Shot 2021-06-14 at 10 15 59 AM](https://user-images.githubusercontent.com/37827279/121932262-8843cd80-ccf9-11eb-9c8e-98d0eda80169.png) +![ScreenShot2021-06-14at101559AM](https://user-images.githubusercontent.com/37827279/121932262-8843cd80-ccf9-11eb-9c8e-98d0eda80169.png) diff --git a/docs/book/src/reference/platform.md b/docs/book/src/reference/platform.md index b8c93cfab68..5b1be16ec17 100644 --- a/docs/book/src/reference/platform.md +++ b/docs/book/src/reference/platform.md @@ -1,237 +1,237 @@ -# Platforms Supported +#PlatformsSupported -Kubebuilder produces solutions that by default can work on multiple platforms or specific ones, depending on how you -build and configure your workloads. This guide aims to help you properly configure your projects according to your needs. +Kubebuilderproducessolutionsthatbydefaultcanworkonmultipleplatformsorspecificones,dependingonhowyou +buildandconfigureyourworkloads.Thisguideaimstohelpyouproperlyconfigureyourprojectsaccordingtoyourneeds. -## Overview +##Overview -To provide support on specific or multiple platforms, you must ensure that all images used in workloads are built to -support the desired platforms. Note that they may not be the same as the platform where you develop your solutions and use KubeBuilder, but instead the platform(s) where your solution should run and be distributed. -It is recommended to build solutions that work on multiple platforms so that your project works -on any Kubernetes cluster regardless of the underlying operating system and architecture. +Toprovidesupportonspecificormultipleplatforms,youmustensurethatallimagesusedinworkloadsarebuiltto +supportthedesiredplatforms.NotethattheymaynotbethesameastheplatformwhereyoudevelopyoursolutionsanduseKubeBuilder,butinsteadtheplatform(s)whereyoursolutionshouldrunandbedistributed. +Itisrecommendedtobuildsolutionsthatworkonmultipleplatformssothatyourprojectworks +onanyKubernetesclusterregardlessoftheunderlyingoperatingsystemandarchitecture. -## How to define which platforms are supported +##Howtodefinewhichplatformsaresupported -The following covers what you need to do to provide the support for one or more platforms or architectures. +Thefollowingcoverswhatyouneedtodotoprovidethesupportforoneormoreplatformsorarchitectures. -### 1) Build workload images to provide the support for other platform(s) +###1)Buildworkloadimagestoprovidethesupportforotherplatform(s) -The images used in workloads such as in your Pods/Deployments will need to provide the support for this other platform. -You can inspect the images using a ManifestList of supported platforms using the command -[docker manifest inspect ][docker-manifest], i.e.: +TheimagesusedinworkloadssuchasinyourPods/Deploymentswillneedtoprovidethesupportforthisotherplatform. +YoucaninspecttheimagesusingaManifestListofsupportedplatformsusingthecommand +[dockermanifestinspect][docker-manifest],i.e.: ```shell -$ docker manifest inspect myresgystry/example/myimage:v0.0.1 +$dockermanifestinspectmyresgystry/example/myimage:v0.0.1 { - "schemaVersion": 2, - "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json", - "manifests": [ - { - "mediaType": "application/vnd.docker.distribution.manifest.v2+json", - "size": 739, - "digest": "sha256:a274a1a2af811a1daf3fd6b48ff3d08feb757c2c3f3e98c59c7f85e550a99a32", - "platform": { - "architecture": "arm64", - "os": "linux" - } - }, - { - "mediaType": "application/vnd.docker.distribution.manifest.v2+json", - "size": 739, - "digest": "sha256:d801c41875f12ffd8211fffef2b3a3d1a301d99f149488d31f245676fa8bc5d9", - "platform": { - "architecture": "amd64", - "os": "linux" - } - }, - { - "mediaType": "application/vnd.docker.distribution.manifest.v2+json", - "size": 739, - "digest": "sha256:f4423c8667edb5372fb0eafb6ec599bae8212e75b87f67da3286f0291b4c8732", - "platform": { - "architecture": "s390x", - "os": "linux" - } - }, - { - "mediaType": "application/vnd.docker.distribution.manifest.v2+json", - "size": 739, - "digest": "sha256:621288f6573c012d7cf6642f6d9ab20dbaa35de3be6ac2c7a718257ec3aff333", - "platform": { - "architecture": "ppc64le", - "os": "linux" - } - }, - ] +"schemaVersion":2, +"mediaType":"application/vnd.docker.distribution.manifest.list.v2+json", +"manifests":[ +{ +"mediaType":"application/vnd.docker.distribution.manifest.v2+json", +"size":739, +"digest":"sha256:a274a1a2af811a1daf3fd6b48ff3d08feb757c2c3f3e98c59c7f85e550a99a32", +"platform":{ +"architecture":"arm64", +"os":"linux" +} +}, +{ +"mediaType":"application/vnd.docker.distribution.manifest.v2+json", +"size":739, +"digest":"sha256:d801c41875f12ffd8211fffef2b3a3d1a301d99f149488d31f245676fa8bc5d9", +"platform":{ +"architecture":"amd64", +"os":"linux" +} +}, +{ +"mediaType":"application/vnd.docker.distribution.manifest.v2+json", +"size":739, +"digest":"sha256:f4423c8667edb5372fb0eafb6ec599bae8212e75b87f67da3286f0291b4c8732", +"platform":{ +"architecture":"s390x", +"os":"linux" +} +}, +{ +"mediaType":"application/vnd.docker.distribution.manifest.v2+json", +"size":739, +"digest":"sha256:621288f6573c012d7cf6642f6d9ab20dbaa35de3be6ac2c7a718257ec3aff333", +"platform":{ +"architecture":"ppc64le", +"os":"linux" +} +}, +] } ``` -### 2) (Recommended as a Best Practice) Ensure that node affinity expressions are set to match the supported platforms +###2)(RecommendedasaBestPractice)Ensurethatnodeaffinityexpressionsaresettomatchthesupportedplatforms -Kubernetes provides a mechanism called [nodeAffinity][node-affinity] which can be used to limit the possible node -targets where a pod can be scheduled. This is especially important to ensure correct scheduling behavior in clusters -with nodes that span across multiple platforms (i.e. heterogeneous clusters). +Kubernetesprovidesamechanismcalled[nodeAffinity][node-affinity]whichcanbeusedtolimitthepossiblenode +targetswhereapodcanbescheduled.Thisisespeciallyimportanttoensurecorrectschedulingbehaviorinclusters +withnodesthatspanacrossmultipleplatforms(i.e.heterogeneousclusters). -**Kubernetes manifest example** +**Kubernetesmanifestexample** ```yaml affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/arch - operator: In - values: - - amd64 - - arm64 - - ppc64le - - s390x - - key: kubernetes.io/os - operator: In - values: - - linux +nodeAffinity: +requiredDuringSchedulingIgnoredDuringExecution: +nodeSelectorTerms: +-matchExpressions: +-key:kubernetes.io/arch +operator:In +values: +-amd64 +-arm64 +-ppc64le +-s390x +-key:kubernetes.io/os +operator:In +values: +-linux ``` -**Golang Example** - -```go -Template: corev1.PodTemplateSpec{ - ... - Spec: corev1.PodSpec{ - Affinity: &corev1.Affinity{ - NodeAffinity: &corev1.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ - NodeSelectorTerms: []corev1.NodeSelectorTerm{ - { - MatchExpressions: []corev1.NodeSelectorRequirement{ - { - Key: "kubernetes.io/arch", - Operator: "In", - Values: []string{"amd64"}, - }, - { - Key: "kubernetes.io/os", - Operator: "In", - Values: []string{"linux"}, - }, - }, - }, - }, - }, - }, - }, - SecurityContext: &corev1.PodSecurityContext{ - ... - }, - Containers: []corev1.Container{{ - ... - }}, - }, +**GolangExample** + +```go +Template:corev1.PodTemplateSpec{ +... +Spec:corev1.PodSpec{ +Affinity:&corev1.Affinity{ +NodeAffinity:&corev1.NodeAffinity{ +RequiredDuringSchedulingIgnoredDuringExecution:&corev1.NodeSelector{ +NodeSelectorTerms:[]corev1.NodeSelectorTerm{ +{ +MatchExpressions:[]corev1.NodeSelectorRequirement{ +{ +Key:"kubernetes.io/arch", +Operator:"In", +Values:[]string{"amd64"}, +}, +{ +Key:"kubernetes.io/os", +Operator:"In", +Values:[]string{"linux"}, +}, +}, +}, +}, +}, +}, +}, +SecurityContext:&corev1.PodSecurityContext{ +... +}, +Containers:[]corev1.Container{{ +... +}}, +}, ``` - -## Producing projects that support multiple platforms +##Producingprojectsthatsupportmultipleplatforms -You can use [`docker buildx`][buildx] to cross-compile via emulation ([QEMU](https://www.qemu.org/)) to build the manager image. -See that projects scaffold with the latest versions of Kubebuilder have the Makefile target `docker-buildx`. +Youcanuse[`dockerbuildx`][buildx]tocross-compileviaemulation([QEMU](https://www.qemu.org/))tobuildthemanagerimage. +SeethatprojectsscaffoldwiththelatestversionsofKubebuilderhavetheMakefiletarget`docker-buildx`. -**Example of Usage** +**ExampleofUsage** ```shell -$ make docker-buildx IMG=myregistry/myoperator:v0.0.1 +$makedocker-buildxIMG=myregistry/myoperator:v0.0.1 ``` -Note that you need to ensure that all images and workloads required and used by your project will provide the same -support as recommended above, and that you properly configure the [nodeAffinity][node-affinity] for all your workloads. -Therefore, ensure that you uncomment the following code in the `config/manager/manager.yaml` file +Notethatyouneedtoensurethatallimagesandworkloadsrequiredandusedbyyourprojectwillprovidethesame +supportasrecommendedabove,andthatyouproperlyconfigurethe[nodeAffinity][node-affinity]forallyourworkloads. +Therefore,ensurethatyouuncommentthefollowingcodeinthe`config/manager/manager.yaml`file ```yaml - # 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 +#TODO(user):UncommentthefollowingcodetoconfigurethenodeAffinityexpression +#accordingtotheplatformswhicharesupportedbyyoursolution. +#Itisconsideredbestpracticetosupportmultiplearchitectures.Youcan +#buildyourmanagerimageusingthemakefiletargetdocker-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 ``` - -## Which (workload) images are created by default? +##Which(workload)imagesarecreatedbydefault? -Projects created with the Kubebuilder CLI have two workloads which are: +ProjectscreatedwiththeKubebuilderCLIhavetwoworkloadswhichare: -### Manager +###Manager -The container to run the manager implementation is configured in the `config/manager/manager.yaml` file. -This image is built with the Dockerfile file scaffolded by default and contains the binary of the project \ -which will be built via the command `go build -a -o manager main.go`. +Thecontainertorunthemanagerimplementationisconfiguredinthe`config/manager/manager.yaml`file. +ThisimageisbuiltwiththeDockerfilefilescaffoldedbydefaultandcontainsthebinaryoftheproject\ +whichwillbebuiltviathecommand`gobuild-a-omanagermain.go`. -Note that when you run `make docker-build` OR `make docker-build IMG=myregistry/myprojectname:` -an image will be built from the client host (local environment) and produce an image for -the client os/arch, which is commonly linux/amd64 or linux/arm64. +Notethatwhenyourun`makedocker-build`OR`makedocker-buildIMG=myregistry/myprojectname:` +animagewillbebuiltfromtheclienthost(localenvironment)andproduceanimagefor +theclientos/arch,whichiscommonlylinux/amd64orlinux/arm64. - -### Kube RBAC Proxy +###KubeRBACProxy -A workload will be created to run the image [gcr.io/kubebuilder/kube-rbac-proxy:][proxy-images] which is -configured in the `config/default/manager_auth_proxy_patch.yaml` manifest. It is a side-car proxy whose purpose -is to protect the manager from malicious attacks. You can learn more about its motivations by looking at -the README of this project [github.com/brancz/kube-rbac-proxy](https://github.com/brancz/kube-rbac-proxy). +Aworkloadwillbecreatedtoruntheimage[gcr.io/kubebuilder/kube-rbac-proxy:][proxy-images]whichis +configuredinthe`config/default/manager_auth_proxy_patch.yaml`manifest.Itisaside-carproxywhosepurpose +istoprotectthemanagerfrommaliciousattacks.Youcanlearnmoreaboutitsmotivationsbylookingat +theREADMEofthisproject[github.com/brancz/kube-rbac-proxy](https://github.com/brancz/kube-rbac-proxy). -Kubebuilder has been building this image with support for multiple architectures by default.( Check it [here][proxy-images] ). -If you need to address any edge case scenario where you want to produce a project that -only provides support for a specific architecture platform, you can customize your -configuration manifests to use the specific architecture types built for this image. +Kubebuilderhasbeenbuildingthisimagewithsupportformultiplearchitecturesbydefault.(Checkit[here][proxy-images]). +Ifyouneedtoaddressanyedgecasescenariowhereyouwanttoproduceaprojectthat +onlyprovidessupportforaspecificarchitectureplatform,youcancustomizeyour +configurationmanifeststousethespecificarchitecturetypesbuiltforthisimage. -[node-affinity]: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity -[docker-manifest]: https://docs.docker.com/engine/reference/commandline/manifest/ -[proxy-images]: https://console.cloud.google.com/gcr/images/kubebuilder/GLOBAL/kube-rbac-proxy -[buildx]: https://docs.docker.com/build/buildx/ -[goreleaser-buildx]: https://goreleaser.com/customization/docker/#use-a-specific-builder-with-docker-buildx \ No newline at end of file +[node-affinity]:https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity +[docker-manifest]:https://docs.docker.com/engine/reference/commandline/manifest/ +[proxy-images]:https://console.cloud.google.com/gcr/images/kubebuilder/GLOBAL/kube-rbac-proxy +[buildx]:https://docs.docker.com/build/buildx/ +[goreleaser-buildx]:https://goreleaser.com/customization/docker/#use-a-specific-builder-with-docker-buildx \ No newline at end of file diff --git a/docs/book/src/reference/project-config.md b/docs/book/src/reference/project-config.md index c335d4ff3fa..b4bffda2e1f 100644 --- a/docs/book/src/reference/project-config.md +++ b/docs/book/src/reference/project-config.md @@ -1,143 +1,143 @@ -# Project Config +#ProjectConfig -## Overview +##Overview -The Project Config represents the configuration of a KubeBuilder project. All projects that are scaffolded with the CLI (KB version 3.0 and higher) will generate the `PROJECT` file in the projects' root directory. Therefore, it will store all plugins and input data used to generate the project and APIs to better enable plugins to make useful decisions when scaffolding. +TheProjectConfigrepresentstheconfigurationofaKubeBuilderproject.AllprojectsthatarescaffoldedwiththeCLI(KBversion3.0andhigher)willgeneratethe`PROJECT`fileintheprojects'rootdirectory.Therefore,itwillstoreallpluginsandinputdatausedtogeneratetheprojectandAPIstobetterenablepluginstomakeusefuldecisionswhenscaffolding. -## Example +##Example -Following is an example of a PROJECT config file which is the result of a project generated with two APIs using the [Deploy Image Plugin][deploy-image-plugin]. +FollowingisanexampleofaPROJECTconfigfilewhichistheresultofaprojectgeneratedwithtwoAPIsusingthe[DeployImagePlugin][deploy-image-plugin]. ```yaml -# 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: testproject.org +#Codegeneratedbytool.DONOTEDIT. +#Thisfileisusedtotracktheinfousedtoscaffoldyourproject +#andallowthepluginsproperlywork. +#Moreinfo:https://book.kubebuilder.io/reference/project-config.html +domain:testproject.org layout: - - go.kubebuilder.io/v4 +-go.kubebuilder.io/v4 plugins: - deploy-image.go.kubebuilder.io/v1-alpha: - resources: - - domain: testproject.org - group: example.com - kind: Memcached - options: - containerCommand: memcached,-m=64,-o,modern,-v - containerPort: "11211" - image: memcached:1.4.36-alpine - runAsUser: "1001" - version: v1alpha1 - - domain: testproject.org - group: example.com - kind: Busybox - options: - image: busybox:1.28 - version: v1alpha1 -projectName: project-v4-with-deploy-image -repo: sigs.k8s.io/kubebuilder/testdata/project-v4-with-deploy-image +deploy-image.go.kubebuilder.io/v1-alpha: resources: - - api: - crdVersion: v1 - namespaced: true - controller: true - domain: testproject.org - group: example.com - kind: Memcached - path: sigs.k8s.io/kubebuilder/testdata/project-v4-with-deploy-image/api/v1alpha1 - version: v1alpha1 - webhooks: - validation: true - webhookVersion: v1 - - api: - crdVersion: v1 - namespaced: true - controller: true - domain: testproject.org - group: example.com - kind: Busybox - path: sigs.k8s.io/kubebuilder/testdata/project-v4-with-deploy-image/api/v1alpha1 - version: v1alpha1 -version: "3" +-domain:testproject.org +group:example.com +kind:Memcached +options: +containerCommand:memcached,-m=64,-o,modern,-v +containerPort:"11211" +image:memcached:1.4.36-alpine +runAsUser:"1001" +version:v1alpha1 +-domain:testproject.org +group:example.com +kind:Busybox +options: +image:busybox:1.28 +version:v1alpha1 +projectName:project-v4-with-deploy-image +repo:sigs.k8s.io/kubebuilder/testdata/project-v4-with-deploy-image +resources: +-api: +crdVersion:v1 +namespaced:true +controller:true +domain:testproject.org +group:example.com +kind:Memcached +path:sigs.k8s.io/kubebuilder/testdata/project-v4-with-deploy-image/api/v1alpha1 +version:v1alpha1 +webhooks: +validation:true +webhookVersion:v1 +-api: +crdVersion:v1 +namespaced:true +controller:true +domain:testproject.org +group:example.com +kind:Busybox +path:sigs.k8s.io/kubebuilder/testdata/project-v4-with-deploy-image/api/v1alpha1 +version:v1alpha1 +version:"3" ``` -## Why do we need to store the plugins and data used? +##Whydoweneedtostorethepluginsanddataused? -Following some examples of motivations to track the input used: -- check if a plugin can or cannot be scaffolded on top of an existing plugin (i.e.) plugin compatibility while chaining multiple of them together. -- what operations can or cannot be done such as verify if the layout allow API(s) for different groups to be scaffolded for the current configuration or not. -- verify what data can or not be used in the CLI operations such as to ensure that WebHooks can only be created for pre-existent API(s) +Followingsomeexamplesofmotivationstotracktheinputused: +-checkifaplugincanorcannotbescaffoldedontopofanexistingplugin(i.e.)plugincompatibilitywhilechainingmultipleofthemtogether. +-whatoperationscanorcannotbedonesuchasverifyifthelayoutallowAPI(s)fordifferentgroupstobescaffoldedforthecurrentconfigurationornot. +-verifywhatdatacanornotbeusedintheCLIoperationssuchastoensurethatWebHookscanonlybecreatedforpre-existentAPI(s) -Note that KubeBuilder is not only a CLI tool but can also be used as a library to allow users to create their plugins/tools, provide helpers and customizations on top of their existing projects - an example of which is [Operator-SDK][operator-sdk]. SDK leverages KubeBuilder to create plugins to allow users to work with other languages and provide helpers for their users to integrate their projects with, for example, the [Operator Framework solutions/OLM][olm]. You can check the [plugin's documentation][plugins-doc] to know more about creating custom plugins. +NotethatKubeBuilderisnotonlyaCLItoolbutcanalsobeusedasalibrarytoallowuserstocreatetheirplugins/tools,providehelpersandcustomizationsontopoftheirexistingprojects-anexampleofwhichis[Operator-SDK][operator-sdk].SDKleveragesKubeBuildertocreatepluginstoallowuserstoworkwithotherlanguagesandprovidehelpersfortheiruserstointegratetheirprojectswith,forexample,the[OperatorFrameworksolutions/OLM][olm].Youcancheckthe[plugin'sdocumentation][plugins-doc]toknowmoreaboutcreatingcustomplugins. -Additionally, another motivation for the PROJECT file is to help us to create a feature that allows users to easily upgrade their projects by providing helpers that automatically re-scaffold the project. By having all the required metadata regarding the APIs, their configurations and versions in the PROJECT file. For example, it can be used to automate the process of re-scaffolding while migrating between plugin versions. ([More info][doc-design-helper]). +Additionally,anothermotivationforthePROJECTfileistohelpustocreateafeaturethatallowsuserstoeasilyupgradetheirprojectsbyprovidinghelpersthatautomaticallyre-scaffoldtheproject.ByhavingalltherequiredmetadataregardingtheAPIs,theirconfigurationsandversionsinthePROJECTfile.Forexample,itcanbeusedtoautomatetheprocessofre-scaffoldingwhilemigratingbetweenpluginversions.([Moreinfo][doc-design-helper]). -## Versioning +##Versioning -The Project config is versioned according to its layout. For further information see [Versioning][versioning]. +TheProjectconfigisversionedaccordingtoitslayout.Forfurtherinformationsee[Versioning][versioning]. -## Layout Definition +##LayoutDefinition -The `PROJECT` version `3` layout looks like: +The`PROJECT`version`3`layoutlookslike: ```yaml -domain: testproject.org +domain:testproject.org layout: - - go.kubebuilder.io/v3 +-go.kubebuilder.io/v3 plugins: - declarative.go.kubebuilder.io/v1: - resources: - - domain: testproject.org - group: crew - kind: FirstMate - version: v1 -projectName: example -repo: sigs.k8s.io/kubebuilder/example +declarative.go.kubebuilder.io/v1: +resources: +-domain:testproject.org +group:crew +kind:FirstMate +version:v1 +projectName:example +repo:sigs.k8s.io/kubebuilder/example resources: - - api: - crdVersion: v1 - namespaced: true - controller: true - domain: testproject.org - group: crew - kind: Captain - path: sigs.k8s.io/kubebuilder/example/api/v1 - version: v1 - webhooks: - defaulting: true - validation: true - webhookVersion: v1 +-api: +crdVersion:v1 +namespaced:true +controller:true +domain:testproject.org +group:crew +kind:Captain +path:sigs.k8s.io/kubebuilder/example/api/v1 +version:v1 +webhooks: +defaulting:true +validation:true +webhookVersion:v1 ``` -Now let's check its layout fields definition: +Nowlet'scheckitslayoutfieldsdefinition: -| Field | Description | +|Field|Description| |----------|-------------| -| `layout` | Defines the global plugins, e.g. a project `init` with `--plugins="go/v3,declarative"` means that any sub-command used will always call its implementation for both plugins in a chain. | -| `domain` | Store the domain of the project. This information can be provided by the user when the project is generate with the `init` sub-command and the `domain` flag. | -| `plugins` | Defines the plugins used to do custom scaffolding, e.g. to use the optional `declarative` plugin to do scaffolding for just a specific api via the command `kubebuider create api [options] --plugins=declarative/v1`. | -| `projectName` | The name of the project. This will be used to scaffold the manager data. By default it is the name of the project directory, however, it can be provided by the user in the `init` sub-command via the `--project-name` flag. | -| `repo` | The project repository which is the Golang module, e.g `github.com/example/myproject-operator`. | -| `resources` | An array of all resources which were scaffolded in the project. | -| `resources.api` | The API scaffolded in the project via the sub-command `create api`. | -| `resources.api.crdVersion` | The Kubernetes API version (`apiVersion`) used to do the scaffolding for the CRD resource. | -| `resources.api.namespaced` | The API RBAC permissions which can be namespaced or cluster scoped. | -| `resources.controller` | Indicates whether a controller was scaffolded for the API. | -| `resources.domain` | The domain of the resource which is provided by the `--domain` flag when the sub-command `create api` is used. | -| `resources.group` | The GKV group of the resource which is provided by the `--group` flag when the sub-command `create api` is used. | -| `resources.version` | The GKV version of the resource which is provided by the `--version` flag when the sub-command `create api` is used. | -| `resources.kind` | Store GKV Kind of the resource which is provided by the `--kind` flag when the sub-command `create api` is used. | -| `resources.path` | The import path for the API resource. It will be `/api/` unless the API added to the project is an external or core-type. For the core-types scenarios, the paths used are mapped [here][core-types]. | -| `resources.webhooks`| Store the webhooks data when the sub-command `create webhook` is used. | -| `resources.webhooks.webhookVersion` | The Kubernetes API version (`apiVersion`) used to scaffold the webhook resource. | -| `resources.webhooks.conversion` | It is `true` when the webhook was scaffold with the `--conversion` flag which means that is a conversion webhook. | -| `resources.webhooks.defaulting` | It is `true` when the webhook was scaffold with the `--defaulting` flag which means that is a defaulting webhook. | -| `resources.webhooks.validation` | It is `true` when the webhook was scaffold with the `--programmatic-validation` flag which means that is a validation webhook. | - -[project]: https://github.com/kubernetes-sigs/kubebuilder/blob/master/testdata/project-v3/PROJECT -[versioning]: https://github.com/kubernetes-sigs/kubebuilder/blob/master/VERSIONING.md#Versioning -[core-types]: https://github.com/kubernetes-sigs/kubebuilder/blob/master/pkg/plugins/golang/options.go -[deploy-image-plugin]: ../plugins/deploy-image-plugin-v1-alpha.md -[olm]: https://olm.operatorframework.io/ -[plugins-doc]: ../plugins/creating-plugins.html#why-use-the-kubebuilder-style -[doc-design-helper]: https://github.com/kubernetes-sigs/kubebuilder/blob/master/designs/helper_to_upgrade_projects_by_rescaffolding.md -[operator-sdk]: https://sdk.operatorframework.io/ \ No newline at end of file +|`layout`|Definestheglobalplugins,e.g.aproject`init`with`--plugins="go/v3,declarative"`meansthatanysub-commandusedwillalwayscallitsimplementationforbothpluginsinachain.| +|`domain`|Storethedomainoftheproject.Thisinformationcanbeprovidedbytheuserwhentheprojectisgeneratewiththe`init`sub-commandandthe`domain`flag.| +|`plugins`|Definesthepluginsusedtodocustomscaffolding,e.g.tousetheoptional`declarative`plugintodoscaffoldingforjustaspecificapiviathecommand`kubebuidercreateapi[options]--plugins=declarative/v1`.| +|`projectName`|Thenameoftheproject.Thiswillbeusedtoscaffoldthemanagerdata.Bydefaultitisthenameoftheprojectdirectory,however,itcanbeprovidedbytheuserinthe`init`sub-commandviathe`--project-name`flag.| +|`repo`|TheprojectrepositorywhichistheGolangmodule,e.g`github.com/example/myproject-operator`.| +|`resources`|Anarrayofallresourceswhichwerescaffoldedintheproject.| +|`resources.api`|TheAPIscaffoldedintheprojectviathesub-command`createapi`.| +|`resources.api.crdVersion`|TheKubernetesAPIversion(`apiVersion`)usedtodothescaffoldingfortheCRDresource.| +|`resources.api.namespaced`|TheAPIRBACpermissionswhichcanbenamespacedorclusterscoped.| +|`resources.controller`|IndicateswhetheracontrollerwasscaffoldedfortheAPI.| +|`resources.domain`|Thedomainoftheresourcewhichisprovidedbythe`--domain`flagwhenthesub-command`createapi`isused.| +|`resources.group`|TheGKVgroupoftheresourcewhichisprovidedbythe`--group`flagwhenthesub-command`createapi`isused.| +|`resources.version`|TheGKVversionoftheresourcewhichisprovidedbythe`--version`flagwhenthesub-command`createapi`isused.| +|`resources.kind`|StoreGKVKindoftheresourcewhichisprovidedbythe`--kind`flagwhenthesub-command`createapi`isused.| +|`resources.path`|TheimportpathfortheAPIresource.Itwillbe`/api/`unlesstheAPIaddedtotheprojectisanexternalorcore-type.Forthecore-typesscenarios,thepathsusedaremapped[here][core-types].| +|`resources.webhooks`|Storethewebhooksdatawhenthesub-command`createwebhook`isused.| +|`resources.webhooks.webhookVersion`|TheKubernetesAPIversion(`apiVersion`)usedtoscaffoldthewebhookresource.| +|`resources.webhooks.conversion`|Itis`true`whenthewebhookwasscaffoldwiththe`--conversion`flagwhichmeansthatisaconversionwebhook.| +|`resources.webhooks.defaulting`|Itis`true`whenthewebhookwasscaffoldwiththe`--defaulting`flagwhichmeansthatisadefaultingwebhook.| +|`resources.webhooks.validation`|Itis`true`whenthewebhookwasscaffoldwiththe`--programmatic-validation`flagwhichmeansthatisavalidationwebhook.| + +[project]:https://github.com/kubernetes-sigs/kubebuilder/blob/master/testdata/project-v3/PROJECT +[versioning]:https://github.com/kubernetes-sigs/kubebuilder/blob/master/VERSIONING.md#Versioning +[core-types]:https://github.com/kubernetes-sigs/kubebuilder/blob/master/pkg/plugins/golang/options.go +[deploy-image-plugin]:../plugins/deploy-image-plugin-v1-alpha.md +[olm]:https://olm.operatorframework.io/ +[plugins-doc]:../plugins/creating-plugins.html#why-use-the-kubebuilder-style +[doc-design-helper]:https://github.com/kubernetes-sigs/kubebuilder/blob/master/designs/helper_to_upgrade_projects_by_rescaffolding.md +[operator-sdk]:https://sdk.operatorframework.io/ \ No newline at end of file diff --git a/docs/book/src/reference/raising-events.md b/docs/book/src/reference/raising-events.md index a9a698703e0..c877254a5e0 100644 --- a/docs/book/src/reference/raising-events.md +++ b/docs/book/src/reference/raising-events.md @@ -1,113 +1,113 @@ -# Creating Events +#CreatingEvents -It is often useful to publish *Event* objects from the controller Reconcile function as they allow users or any automated processes to see what is going on with a particular object and respond to them. +Itisoftenusefultopublish*Event*objectsfromthecontrollerReconcilefunctionastheyallowusersoranyautomatedprocessestoseewhatisgoingonwithaparticularobjectandrespondtothem. - Recent Events for an object can be viewed by running `$ kubectl describe `. Also, they can be checked by running `$ kubectl get events`. +RecentEventsforanobjectcanbeviewedbyrunning`$kubectldescribe`.Also,theycanbecheckedbyrunning`$kubectlgetevents`. - -## Writing Events +##WritingEvents -Anatomy of an Event: +AnatomyofanEvent: ```go -Event(object runtime.Object, eventtype, reason, message string) +Event(objectruntime.Object,eventtype,reason,messagestring) ``` -- `object` is the object this event is about. -- `eventtype` is this event type, and is either *Normal* or *Warning*. ([More info][Event-Example]) -- `reason` is the reason this event is generated. It should be short and unique with `UpperCamelCase` format. The value could appear in *switch* statements by automation. ([More info][Reason-Example]) -- `message` is intended to be consumed by humans. ([More info][Message-Example]) +-`object`istheobjectthiseventisabout. +-`eventtype`isthiseventtype,andiseither*Normal*or*Warning*.([Moreinfo][Event-Example]) +-`reason`isthereasonthiseventisgenerated.Itshouldbeshortanduniquewith`UpperCamelCase`format.Thevaluecouldappearin*switch*statementsbyautomation.([Moreinfo][Reason-Example]) +-`message`isintendedtobeconsumedbyhumans.([Moreinfo][Message-Example]) - -### How to be able to raise Events? +###HowtobeabletoraiseEvents? -Following are the steps with examples to help you raise events in your controller's reconciliations. -Events are published from a Controller using an [EventRecorder][Events]`type CorrelatorOptions struct`, -which can be created for a Controller by calling `GetRecorder(name string)` on a Manager. See that we will change the implementation scaffolded in `cmd/main.go`: +Followingarethestepswithexamplestohelpyouraiseeventsinyourcontroller'sreconciliations. +EventsarepublishedfromaControllerusingan[EventRecorder][Events]`typeCorrelatorOptionsstruct`, +whichcanbecreatedforaControllerbycalling`GetRecorder(namestring)`onaManager.Seethatwewillchangetheimplementationscaffoldedin`cmd/main.go`: ```go - if err = (&controller.MyKindReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - // Note that we added the following line: - Recorder: mgr.GetEventRecorderFor("mykind-controller"), - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "MyKind") - os.Exit(1) - } +iferr=(&controller.MyKindReconciler{ +Client:mgr.GetClient(), +Scheme:mgr.GetScheme(), +//Notethatweaddedthefollowingline: +Recorder:mgr.GetEventRecorderFor("mykind-controller"), +}).SetupWithManager(mgr);err!=nil{ +setupLog.Error(err,"unabletocreatecontroller","controller","MyKind") +os.Exit(1) +} ``` -### Allowing usage of EventRecorder on the Controller +###AllowingusageofEventRecorderontheController -To raise an event, you must have access to `record.EventRecorder` in the Controller. Therefore, firstly let's update the controller implementation: +Toraiseanevent,youmusthaveaccessto`record.EventRecorder`intheController.Therefore,firstlylet'supdatethecontrollerimplementation: ```go -import ( - ... - "k8s.io/client-go/tools/record" - ... +import( +... +"k8s.io/client-go/tools/record" +... ) -// MyKindReconciler reconciles a MyKind object -type MyKindReconciler struct { - client.Client - Scheme *runtime.Scheme - // See that we added the following code to allow us to pass the record.EventRecorder - Recorder record.EventRecorder +//MyKindReconcilerreconcilesaMyKindobject +typeMyKindReconcilerstruct{ +client.Client +Scheme*runtime.Scheme +//Seethatweaddedthefollowingcodetoallowustopasstherecord.EventRecorder +Recorderrecord.EventRecorder } ``` -### Passing the EventRecorder to the Controller +###PassingtheEventRecordertotheController -Events are published from a Controller using an [EventRecorder]`type CorrelatorOptions struct`, -which can be created for a Controller by calling `GetRecorder(name string)` on a Manager. See that we will change the implementation scaffolded in `cmd/main.go`: +EventsarepublishedfromaControllerusingan[EventRecorder]`typeCorrelatorOptionsstruct`, +whichcanbecreatedforaControllerbycalling`GetRecorder(namestring)`onaManager.Seethatwewillchangetheimplementationscaffoldedin`cmd/main.go`: ```go - if err = (&controller.MyKindReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - // Note that we added the following line: - Recorder: mgr.GetEventRecorderFor("mykind-controller"), - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "MyKind") - os.Exit(1) - } +iferr=(&controller.MyKindReconciler{ +Client:mgr.GetClient(), +Scheme:mgr.GetScheme(), +//Notethatweaddedthefollowingline: +Recorder:mgr.GetEventRecorderFor("mykind-controller"), +}).SetupWithManager(mgr);err!=nil{ +setupLog.Error(err,"unabletocreatecontroller","controller","MyKind") +os.Exit(1) +} ``` -### Granting the required permissions +###Grantingtherequiredpermissions -You must also grant the RBAC rules permissions to allow your project to create Events. Therefore, ensure that you add the [RBAC][rbac-markers] into your controller: +YoumustalsogranttheRBACrulespermissionstoallowyourprojecttocreateEvents.Therefore,ensurethatyouaddthe[RBAC][rbac-markers]intoyourcontroller: ```go ... //+kubebuilder:rbac:groups=core,resources=events,verbs=create;patch ... -func (r *MyKindReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { +func(r*MyKindReconciler)Reconcile(ctxcontext.Context,reqctrl.Request)(ctrl.Result,error){ ``` -And then, run `$ make manifests` to update the rules under `config/rbac/role.yaml`. - -[Events]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#events -[Event-Example]: https://github.com/kubernetes/api/blob/6c11c9e4685cc62e4ddc8d4aaa824c46150c9148/core/v1/types.go#L6019-L6024 -[Reason-Example]: https://github.com/kubernetes/api/blob/6c11c9e4685cc62e4ddc8d4aaa824c46150c9148/core/v1/types.go#L6048 -[Message-Example]: https://github.com/kubernetes/api/blob/6c11c9e4685cc62e4ddc8d4aaa824c46150c9148/core/v1/types.go#L6053 -[rbac-markers]: ./markers/rbac.md \ No newline at end of file +Andthen,run`$makemanifests`toupdatetherulesunder`config/rbac/role.yaml`. + +[Events]:https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#events +[Event-Example]:https://github.com/kubernetes/api/blob/6c11c9e4685cc62e4ddc8d4aaa824c46150c9148/core/v1/types.go#L6019-L6024 +[Reason-Example]:https://github.com/kubernetes/api/blob/6c11c9e4685cc62e4ddc8d4aaa824c46150c9148/core/v1/types.go#L6048 +[Message-Example]:https://github.com/kubernetes/api/blob/6c11c9e4685cc62e4ddc8d4aaa824c46150c9148/core/v1/types.go#L6053 +[rbac-markers]:./markers/rbac.md \ No newline at end of file diff --git a/docs/book/src/reference/reference.md b/docs/book/src/reference/reference.md index 1d9026777d8..b01772b35f3 100644 --- a/docs/book/src/reference/reference.md +++ b/docs/book/src/reference/reference.md @@ -1,42 +1,42 @@ -# Reference +#Reference - - [Generating CRDs](generating-crd.md) - - [Using Finalizers](using-finalizers.md) - Finalizers are a mechanism to - execute any custom logic related to a resource before it gets deleted from - Kubernetes cluster. - - [Watching Resources](watching-resources.md) - Watch resources in the Kubernetes cluster to be informed and take actions on changes. - - [Resources Managed by the Operator](watching-resources/operator-managed.md) - - [Externally Managed Resources](watching-resources/externally-managed.md) - Controller Runtime provides the ability to watch additional resources relevant to the controlled ones. - - [Kind cluster](kind.md) - - [What's a webhook?](webhook-overview.md) - Webhooks are HTTP callbacks, there are 3 - types of webhooks in k8s: 1) admission webhook 2) CRD conversion webhook 3) - authorization webhook - - [Admission webhook](admission-webhook.md) - Admission webhooks are HTTP - callbacks for mutating or validating resources before the API server admit - them. - - [Markers for Config/Code Generation](markers.md) +-[GeneratingCRDs](generating-crd.md) +-[UsingFinalizers](using-finalizers.md) +Finalizersareamechanismto +executeanycustomlogicrelatedtoaresourcebeforeitgetsdeletedfrom +Kubernetescluster. +-[WatchingResources](watching-resources.md) +WatchresourcesintheKubernetesclustertobeinformedandtakeactionsonchanges. +-[ResourcesManagedbytheOperator](watching-resources/operator-managed.md) +-[ExternallyManagedResources](watching-resources/externally-managed.md) +ControllerRuntimeprovidestheabilitytowatchadditionalresourcesrelevanttothecontrolledones. +-[Kindcluster](kind.md) +-[What'sawebhook?](webhook-overview.md) +WebhooksareHTTPcallbacks,thereare3 +typesofwebhooksink8s:1)admissionwebhook2)CRDconversionwebhook3) +authorizationwebhook +-[Admissionwebhook](admission-webhook.md) +AdmissionwebhooksareHTTP +callbacksformutatingorvalidatingresourcesbeforetheAPIserveradmit +them. +-[MarkersforConfig/CodeGeneration](markers.md) - - [CRD Generation](markers/crd.md) - - [CRD Validation](markers/crd-validation.md) - - [Webhook](markers/webhook.md) - - [Object/DeepCopy](markers/object.md) - - [RBAC](markers/rbac.md) +-[CRDGeneration](markers/crd.md) +-[CRDValidation](markers/crd-validation.md) +-[Webhook](markers/webhook.md) +-[Object/DeepCopy](markers/object.md) +-[RBAC](markers/rbac.md) - - [controller-gen CLI](controller-gen.md) - - [completion](completion.md) - - [Artifacts](artifacts.md) - - [Platform Support](platform.md) +-[controller-genCLI](controller-gen.md) +-[completion](completion.md) +-[Artifacts](artifacts.md) +-[PlatformSupport](platform.md) - - [Sub-Module Layouts](submodule-layouts.md) - - [Using an external Type / API](using_an_external_type.md) +-[Sub-ModuleLayouts](submodule-layouts.md) +-[UsinganexternalType/API](using_an_external_type.md) - - [Metrics](metrics.md) - - [Reference](metrics-reference.md) +-[Metrics](metrics.md) +-[Reference](metrics-reference.md) - - [Makefile Helpers](makefile-helpers.md) - - [CLI plugins](../plugins/plugins.md) +-[MakefileHelpers](makefile-helpers.md) +-[CLIplugins](../plugins/plugins.md) diff --git a/docs/book/src/reference/rescaffold.md b/docs/book/src/reference/rescaffold.md index 2b075cefa5c..26c308f94f0 100644 --- a/docs/book/src/reference/rescaffold.md +++ b/docs/book/src/reference/rescaffold.md @@ -1,53 +1,53 @@ -# Project Upgrade Assistant +#ProjectUpgradeAssistant -## Overview +##Overview -Please note that all input utilized via the Kubebuilder tool is tracked in the PROJECT file ([example][example]). -This file is responsible for storing essential information, representing various facets of the Project such as its layout, -plugins, APIs, and more. ([More info][more-info]). +PleasenotethatallinpututilizedviatheKubebuildertoolistrackedinthePROJECTfile([example][example]). +Thisfileisresponsibleforstoringessentialinformation,representingvariousfacetsoftheProjectsuchasitslayout, +plugins,APIs,andmore.([Moreinfo][more-info]). -With the release of new plugin versions/layouts or even a new Kubebuilder CLI version with scaffold changes, -an easy way to upgrade your project is by re-scaffolding. This process allows users to employ tools like IDEs to compare -changes, enabling them to overlay their code implementation on the new scaffold or integrate these changes into their existing projects. +Withthereleaseofnewpluginversions/layoutsorevenanewKubebuilderCLIversionwithscaffoldchanges, +aneasywaytoupgradeyourprojectisbyre-scaffolding.ThisprocessallowsuserstoemploytoolslikeIDEstocompare +changes,enablingthemtooverlaytheircodeimplementationonthenewscaffoldorintegratethesechangesintotheirexistingprojects. -## When to use it ? +##Whentouseit? -This command is useful when you want to upgrade an existing project to the latest version of the Kubebuilder project layout. -It makes it easier for the users to migrate their operator projects to the new scaffolding. +ThiscommandisusefulwhenyouwanttoupgradeanexistingprojecttothelatestversionoftheKubebuilderprojectlayout. +Itmakesiteasierfortheuserstomigratetheiroperatorprojectstothenewscaffolding. -## How to use it ? +##Howtouseit? -**To upgrade the scaffold of your project to use a new plugin version:** +**Toupgradethescaffoldofyourprojecttouseanewpluginversion:** ```sh -kubebuilder alpha generate --plugins="pluginkey/version" +kubebuilderalphagenerate--plugins="pluginkey/version" ``` -**To upgrade the scaffold of your project to get the latest changes:** +**Toupgradethescaffoldofyourprojecttogetthelatestchanges:** -Currently, it supports two optional params, `input-dir` and `output-dir`. +Currently,itsupportstwooptionalparams,`input-dir`and`output-dir`. -`input-dir` is the path to the existing project that you want to re-scaffold. Default is the current working directory. +`input-dir`isthepathtotheexistingprojectthatyouwanttore-scaffold.Defaultisthecurrentworkingdirectory. -`output-dir` is the path to the directory where you want to generate the new project. Default is a subdirectory in the current working directory. +`output-dir`isthepathtothedirectorywhereyouwanttogeneratethenewproject.Defaultisasubdirectoryinthecurrentworkingdirectory. ```sh -kubebuilder alpha generate --input-dir=/path/to/existing/project --output-dir=/path/to/new/project +kubebuilderalphagenerate--input-dir=/path/to/existing/project--output-dir=/path/to/new/project ``` - -## Further Resources: +##FurtherResources: -- Check out [video to show how it works](https://youtu.be/7997RIbx8kw?si=ODYMud5lLycz7osp) -- See the [desing proposal documentation](../../../../designs/helper_to_upgrade_projects_by_rescaffolding.md) +-Checkout[videotoshowhowitworks](https://youtu.be/7997RIbx8kw?si=ODYMud5lLycz7osp) +-Seethe[desingproposaldocumentation](../../../../designs/helper_to_upgrade_projects_by_rescaffolding.md) -[example]: ./../../../../testdata/project-v4-with-deploy-image/PROJECT -[more-info]: ./../reference/project-config.md \ No newline at end of file +[example]:./../../../../testdata/project-v4-with-deploy-image/PROJECT +[more-info]:./../reference/project-config.md \ No newline at end of file diff --git a/docs/book/src/reference/submodule-layouts.md b/docs/book/src/reference/submodule-layouts.md index 69fd1df8f92..6c8e5f9c966 100644 --- a/docs/book/src/reference/submodule-layouts.md +++ b/docs/book/src/reference/submodule-layouts.md @@ -1,248 +1,248 @@ -# Sub-Module Layouts +#Sub-ModuleLayouts -This part describes how to modify a scaffolded project for use with multiple `go.mod` files for APIs and Controllers. +Thispartdescribeshowtomodifyascaffoldedprojectforusewithmultiple`go.mod`filesforAPIsandControllers. -Sub-Module Layouts (in a way you could call them a special form of [Monorepo's][monorepo]) are a special use case and can help in scenarios that involve reuse of APIs without introducing indirect dependencies that should not be available in the project consuming the API externally. +Sub-ModuleLayouts(inawayyoucouldcallthemaspecialformof[Monorepo's][monorepo])areaspecialusecaseandcanhelpinscenariosthatinvolvereuseofAPIswithoutintroducingindirectdependenciesthatshouldnotbeavailableintheprojectconsumingtheAPIexternally. - + -## Overview +##Overview -Separate `go.mod` modules for APIs and Controllers can help for the following cases: +Separate`go.mod`modulesforAPIsandControllerscanhelpforthefollowingcases: -- There is an enterprise version of an operator available that wants to reuse APIs from the Community Version -- There are many (possibly external) modules depending on the API and you want to have a more strict separation of transitive dependencies -- If you want to reduce impact of transitive dependencies on your API being included in other projects -- If you are looking to separately manage the lifecycle of your API release process from your controller release process. -- If you are looking to modularize your codebase without splitting your code between multiple repositories. +-ThereisanenterpriseversionofanoperatoravailablethatwantstoreuseAPIsfromtheCommunityVersion +-Therearemany(possiblyexternal)modulesdependingontheAPIandyouwanttohaveamorestrictseparationoftransitivedependencies +-IfyouwanttoreduceimpactoftransitivedependenciesonyourAPIbeingincludedinotherprojects +-IfyouarelookingtoseparatelymanagethelifecycleofyourAPIreleaseprocessfromyourcontrollerreleaseprocess. +-Ifyouarelookingtomodularizeyourcodebasewithoutsplittingyourcodebetweenmultiplerepositories. -They introduce however multiple caveats into typical projects which is one of the main factors that makes them hard to recommend in a generic use-case or plugin: +Theyintroducehowevermultiplecaveatsintotypicalprojectswhichisoneofthemainfactorsthatmakesthemhardtorecommendinagenericuse-caseorplugin: -- Multiple `go.mod` modules are not recommended as a go best practice and [multiple modules are mostly discouraged][multi-module-repositories] -- There is always the possibility to extract your APIs into a new repository and arguably also have more control over the release process in a project spanning multiple repos relying on the same API types. -- It requires at least one [replace directive][replace-directives] either through `go.work` which is at least 2 more files plus an environment variable for build environments without GO_WORK or through `go.mod` replace, which has to be manually dropped and added for every release. +-Multiple`go.mod`modulesarenotrecommendedasagobestpracticeand[multiplemodulesaremostlydiscouraged][multi-module-repositories] +-ThereisalwaysthepossibilitytoextractyourAPIsintoanewrepositoryandarguablyalsohavemorecontroloverthereleaseprocessinaprojectspanningmultiplereposrelyingonthesameAPItypes. +-Itrequiresatleastone[replacedirective][replace-directives]eitherthrough`go.work`whichisatleast2morefilesplusanenvironmentvariableforbuildenvironmentswithoutGO_WORKorthrough`go.mod`replace,whichhastobemanuallydroppedandaddedforeveryrelease. - -## Adjusting your Project +##AdjustingyourProject -For a proper Sub-Module layout, we will use the generated APIs as a starting point. +ForaproperSub-Modulelayout,wewillusethegeneratedAPIsasastartingpoint. -For the steps below, we will assume you created your project in your `GOPATH` with +Forthestepsbelow,wewillassumeyoucreatedyourprojectinyour`GOPATH`with ```shell -kubebuilder init +kubebuilderinit ``` -and created an API & controller with +andcreatedanAPI&controllerwith ```shell -kubebuilder create api --group operator --version v1alpha1 --kind Sample --resource --controller --make +kubebuildercreateapi--groupoperator--versionv1alpha1--kindSample--resource--controller--make ``` -### Creating a second module for your API +###CreatingasecondmoduleforyourAPI -Now that we have a base layout in place, we will enable you for multiple modules. +Nowthatwehaveabaselayoutinplace,wewillenableyouformultiplemodules. -1. Navigate to `api/v1alpha1` -2. Run `go mod init` to create a new submodule -3. Run `go mod tidy` to resolve the dependencies +1.Navigateto`api/v1alpha1` +2.Run`gomodinit`tocreateanewsubmodule +3.Run`gomodtidy`toresolvethedependencies -Your api go.mod file could now look like this: +Yourapigo.modfilecouldnowlooklikethis: ```go.mod -module YOUR_GO_PATH/test-operator/api/v1alpha1 +moduleYOUR_GO_PATH/test-operator/api/v1alpha1 -go 1.21.0 +go1.21.0 -require ( - k8s.io/apimachinery v0.28.4 - sigs.k8s.io/controller-runtime v0.16.3 +require( +k8s.io/apimachineryv0.28.4 +sigs.k8s.io/controller-runtimev0.16.3 ) -require ( - github.com/go-logr/logr v1.2.4 // indirect - github.com/gogo/protobuf v1.3.2 // indirect - github.com/google/gofuzz v1.2.0 // indirect - github.com/json-iterator/go v1.1.12 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/text v0.13.0 // indirect - gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect - k8s.io/klog/v2 v2.100.1 // indirect - k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect - sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect +require( +github.com/go-logr/logrv1.2.4//indirect +github.com/gogo/protobufv1.3.2//indirect +github.com/google/gofuzzv1.2.0//indirect +github.com/json-iterator/gov1.1.12//indirect +github.com/modern-go/concurrentv0.0.0-20180306012644-bacd9c7ef1dd//indirect +github.com/modern-go/reflect2v1.0.2//indirect +golang.org/x/netv0.17.0//indirect +golang.org/x/textv0.13.0//indirect +gopkg.in/inf.v0v0.9.1//indirect +gopkg.in/yaml.v2v2.4.0//indirect +k8s.io/klog/v2v2.100.1//indirect +k8s.io/utilsv0.0.0-20230406110748-d93618cff8a2//indirect +sigs.k8s.io/jsonv0.0.0-20221116044647-bc3834ca7abd//indirect +sigs.k8s.io/structured-merge-diff/v4v4.2.3//indirect ) ``` -As you can see it only includes apimachinery and controller-runtime as dependencies and any dependencies you have -declared in your controller are not taken over into the indirect imports. +Asyoucanseeitonlyincludesapimachineryandcontroller-runtimeasdependenciesandanydependenciesyouhave +declaredinyourcontrollerarenottakenoverintotheindirectimports. -### Using replace directives for development +###Usingreplacedirectivesfordevelopment -When trying to resolve your main module in the root folder of the operator, you will notice an error if you use a VCS path: +Whentryingtoresolveyourmainmoduleintherootfolderoftheoperator,youwillnoticeanerrorifyouuseaVCSpath: ```shell -go mod tidy -go: finding module for package YOUR_GO_PATH/test-operator/api/v1alpha1 -YOUR_GO_PATH/test-operator imports - YOUR_GO_PATH/test-operator/api/v1alpha1: cannot find module providing package YOUR_GO_PATH/test-operator/api/v1alpha1: module YOUR_GO_PATH/test-operator/api/v1alpha1: git ls-remote -q origin in LOCALVCSPATH: exit status 128: - remote: Repository not found. - fatal: repository 'https://YOUR_GO_PATH/test-operator/' not found +gomodtidy +go:findingmoduleforpackageYOUR_GO_PATH/test-operator/api/v1alpha1 +YOUR_GO_PATH/test-operatorimports +YOUR_GO_PATH/test-operator/api/v1alpha1:cannotfindmoduleprovidingpackageYOUR_GO_PATH/test-operator/api/v1alpha1:moduleYOUR_GO_PATH/test-operator/api/v1alpha1:gitls-remote-qorigininLOCALVCSPATH:exitstatus128: +remote:Repositorynotfound. +fatal:repository'https://YOUR_GO_PATH/test-operator/'notfound ``` -The reason for this is that you may have not pushed your modules into the VCS yet and resolving the main module will fail as it can no longer -directly access the API types as a package but only as a module. +ThereasonforthisisthatyoumayhavenotpushedyourmodulesintotheVCSyetandresolvingthemainmodulewillfailasitcannolonger +directlyaccesstheAPItypesasapackagebutonlyasamodule. -To solve this issue, we will have to tell the go tooling to properly `replace` the API module with a local reference to your path. +Tosolvethisissue,wewillhavetotellthegotoolingtoproperly`replace`theAPImodulewithalocalreferencetoyourpath. -You can do this with 2 different approaches: go modules and go workspaces. +Youcandothiswith2differentapproaches:gomodulesandgoworkspaces. -#### Using go modules +####Usinggomodules -For go modules, you will edit the main `go.mod` file of your project and issue a replace directive. +Forgomodules,youwilleditthemain`go.mod`fileofyourprojectandissueareplacedirective. -You can do this by editing the `go.mod` with +Youcandothisbyeditingthe`go.mod`with `` ```shell -go mod edit -require YOUR_GO_PATH/test-operator/api/v1alpha1@v0.0.0 # Only if you didn't already resolve the module -go mod edit -replace YOUR_GO_PATH/test-operator/api/v1alpha1@v0.0.0=./api/v1alpha1 -go mod tidy +gomodedit-requireYOUR_GO_PATH/test-operator/api/v1alpha1@v0.0.0#Onlyifyoudidn'talreadyresolvethemodule +gomodedit-replaceYOUR_GO_PATH/test-operator/api/v1alpha1@v0.0.0=./api/v1alpha1 +gomodtidy ``` -Note that we used the placeholder version `v0.0.0` of the API Module. In case you already released your API module once, -you can use the real version as well. However this will only work if the API Module is already available in the VCS. +Notethatweusedtheplaceholderversion`v0.0.0`oftheAPIModule.IncaseyoualreadyreleasedyourAPImoduleonce, +youcanusetherealversionaswell.HoweverthiswillonlyworkiftheAPIModuleisalreadyavailableintheVCS. - -#### Using go workspaces +####Usinggoworkspaces -For go workspaces, you will not edit the `go.mod` files yourself, but rely on the workspace support in go. +Forgoworkspaces,youwillnoteditthe`go.mod`filesyourself,butrelyontheworkspacesupportingo. -To initialize a workspace for your project, run `go work init` in the project root. +Toinitializeaworkspaceforyourproject,run`goworkinit`intheprojectroot. -Now let us include both modules in our workspace: +Nowletusincludebothmodulesinourworkspace: ```shell -go work use . # This includes the main module with the controller -go work use api/v1alpha1 # This is the API submodule -go work sync +goworkuse.#Thisincludesthemainmodulewiththecontroller +goworkuseapi/v1alpha1#ThisistheAPIsubmodule +goworksync ``` -This will lead to commands such as `go run` or `go build` to respect the workspace and make sure that local resolution is used. +Thiswillleadtocommandssuchas`gorun`or`gobuild`torespecttheworkspaceandmakesurethatlocalresolutionisused. -You will be able to work with this locally without having to build your module. +Youwillbeabletoworkwiththislocallywithouthavingtobuildyourmodule. -When using `go.work` files, it is recommended to not commit them into the repository and add them to `.gitignore`. +Whenusing`go.work`files,itisrecommendedtonotcommitthemintotherepositoryandaddthemto`.gitignore`. ```gitignore go.work go.work.sum ``` -When releasing with a present `go.work` file, make sure to set the environment variable `GOWORK=off` (verifiable with `go env GOWORK`) to make sure the release process does not get impeded by a potentially commited `go.work` file. +Whenreleasingwithapresent`go.work`file,makesuretosettheenvironmentvariable`GOWORK=off`(verifiablewith`goenvGOWORK`)tomakesurethereleaseprocessdoesnotgetimpededbyapotentiallycommited`go.work`file. -#### Adjusting the Dockerfile +####AdjustingtheDockerfile -When building your controller image, kubebuilder by default is not able to work with multiple modules. -You will have to manually add the new API module into the download of dependencies: +Whenbuildingyourcontrollerimage,kubebuilderbydefaultisnotabletoworkwithmultiplemodules. +YouwillhavetomanuallyaddthenewAPImoduleintothedownloadofdependencies: ```dockerfile -# Build the manager binary -FROM golang:1.20 as builder -ARG TARGETOS -ARG TARGETARCH - -WORKDIR /workspace -# Copy the Go Modules manifests -COPY go.mod go.mod -COPY go.sum go.sum -# Copy the Go Sub-Module manifests -COPY api/v1alpha1/go.mod api/go.mod -COPY api/v1alpha1/go.sum api/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/controller/ internal/controller/ - -# 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"] +#Buildthemanagerbinary +FROMgolang:1.20asbuilder +ARGTARGETOS +ARGTARGETARCH + +WORKDIR/workspace +#CopytheGoModulesmanifests +COPYgo.modgo.mod +COPYgo.sumgo.sum +#CopytheGoSub-Modulemanifests +COPYapi/v1alpha1/go.modapi/go.mod +COPYapi/v1alpha1/go.sumapi/go.sum +#cachedepsbeforebuildingandcopyingsourcesothatwedon'tneedtore-downloadasmuch +#andsothatsourcechangesdon'tinvalidateourdownloadedlayer +RUNgomoddownload + +#Copythegosource +COPYcmd/main.gocmd/main.go +COPYapi/api/ +COPYinternal/controller/internal/controller/ + +#Build +#theGOARCHhasnotadefaultvaluetoallowthebinarybebuiltaccordingtothehostwherethecommand +#wascalled.Forexample,ifwecallmakedocker-buildinalocalenvwhichhastheAppleSiliconM1SO +#thedockerBUILDPLATFORMargwillbelinux/arm64whenforApplex86itwillbelinux/amd64.Therefore, +#byleavingitemptywecanensurethatthecontainerandbinaryshippedonitwillhavethesameplatform. +RUNCGO_ENABLED=0GOOS=${TARGETOS:-linux}GOARCH=${TARGETARCH}gobuild-a-omanagercmd/main.go + +#Usedistrolessasminimalbaseimagetopackagethemanagerbinary +#Refertohttps://github.com/GoogleContainerTools/distrolessformoredetails +FROMgcr.io/distroless/static:nonroot +WORKDIR/ +COPY--from=builder/workspace/manager. +USER65532:65532 + +ENTRYPOINT["/manager"] ``` -### Creating a new API and controller release +###CreatinganewAPIandcontrollerrelease -Because you adjusted the default layout, before releasing your first version of your operator, make sure to [familiarize yourself with mono-repo/multi-module releases][multi-module-repositories] with multiple `go.mod` files in different subdirectories. +Becauseyouadjustedthedefaultlayout,beforereleasingyourfirstversionofyouroperator,makesureto[familiarizeyourselfwithmono-repo/multi-modulereleases][multi-module-repositories]withmultiple`go.mod`filesindifferentsubdirectories. -Assuming a single API was created, the release process could look like this: +AssumingasingleAPIwascreated,thereleaseprocesscouldlooklikethis: ```sh -git commit -git tag v1.0.0 # this is your main module release -git tag api/v1.0.0 # this is your api release -go mod edit -require YOUR_GO_PATH/test-operator/api@v1.0.0 # now we depend on the api module in the main module -go mod edit -dropreplace YOUR_GO_PATH/test-operator/api/v1alpha1 # this will drop the replace directive for local development in case you use go modules, meaning the sources from the VCS will be used instead of the ones in your monorepo checked out locally. -git push origin main v1.0.0 api/v1.0.0 +gitcommit +gittagv1.0.0#thisisyourmainmodulerelease +gittagapi/v1.0.0#thisisyourapirelease +gomodedit-requireYOUR_GO_PATH/test-operator/api@v1.0.0#nowwedependontheapimoduleinthemainmodule +gomodedit-dropreplaceYOUR_GO_PATH/test-operator/api/v1alpha1#thiswilldropthereplacedirectiveforlocaldevelopmentincaseyouusegomodules,meaningthesourcesfromtheVCSwillbeusedinsteadoftheonesinyourmonorepocheckedoutlocally. +gitpushoriginmainv1.0.0api/v1.0.0 ``` -After this, your modules will be available in VCS and you do not need a local replacement anymore. However if youre making local changes, -make sure to adopt your behavior with `replace` directives accordingly. +Afterthis,yourmoduleswillbeavailableinVCSandyoudonotneedalocalreplacementanymore.Howeverifyouremakinglocalchanges, +makesuretoadoptyourbehaviorwith`replace`directivesaccordingly. -### Reusing your extracted API module +###ReusingyourextractedAPImodule -Whenever you want to reuse your API module with a separate kubebuilder, we will assume you follow the guide for [using an external Type](/reference/using_an_external_type.md). -When you get to the step `Edit the API files` simply import the dependency with +WheneveryouwanttoreuseyourAPImodulewithaseparatekubebuilder,wewillassumeyoufollowtheguidefor[usinganexternalType](/reference/using_an_external_type.md). +Whenyougettothestep`EdittheAPIfiles`simplyimportthedependencywith ```shell -go get YOUR_GO_PATH/test-operator/api@v1.0.0 +gogetYOUR_GO_PATH/test-operator/api@v1.0.0 ``` -and then use it as explained in the guide. +andthenuseitasexplainedintheguide. -[monorepo]: https://en.wikipedia.org/wiki/Monorepo -[replace-directives]: https://go.dev/ref/mod#go-mod-file-replace -[multi-module-repositories]: https://github.com/golang/go/wiki/Modules#faqs--multi-module-repositories \ No newline at end of file +[monorepo]:https://en.wikipedia.org/wiki/Monorepo +[replace-directives]:https://go.dev/ref/mod#go-mod-file-replace +[multi-module-repositories]:https://github.com/golang/go/wiki/Modules#faqs--multi-module-repositories \ No newline at end of file diff --git a/docs/book/src/reference/using-finalizers.md b/docs/book/src/reference/using-finalizers.md index 52c8f3cdbd8..9b42c103a1a 100644 --- a/docs/book/src/reference/using-finalizers.md +++ b/docs/book/src/reference/using-finalizers.md @@ -1,25 +1,25 @@ -# Using Finalizers +#UsingFinalizers -`Finalizers` allow controllers to implement asynchronous pre-delete hooks. Let's -say you create an external resource (such as a storage bucket) for each object of -your API type, and you want to delete the associated external resource -on object's deletion from Kubernetes, you can use a finalizer to do that. +`Finalizers`allowcontrollerstoimplementasynchronouspre-deletehooks.Let's +sayyoucreateanexternalresource(suchasastoragebucket)foreachobjectof +yourAPItype,andyouwanttodeletetheassociatedexternalresource +onobject'sdeletionfromKubernetes,youcanuseafinalizertodothat. -You can read more about the finalizers in the [Kubernetes reference docs](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#finalizers). The section below demonstrates how to register and trigger pre-delete hooks -in the `Reconcile` method of a controller. +Youcanreadmoreaboutthefinalizersinthe[Kubernetesreferencedocs](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#finalizers).Thesectionbelowdemonstrateshowtoregisterandtriggerpre-deletehooks +inthe`Reconcile`methodofacontroller. -The key point to note is that a finalizer causes "delete" on the object to become -an "update" to set deletion timestamp. Presence of deletion timestamp on the object -indicates that it is being deleted. Otherwise, without finalizers, a delete -shows up as a reconcile where the object is missing from the cache. +Thekeypointtonoteisthatafinalizercauses"delete"ontheobjecttobecome +an"update"tosetdeletiontimestamp.Presenceofdeletiontimestampontheobject +indicatesthatitisbeingdeleted.Otherwise,withoutfinalizers,adelete +showsupasareconcilewheretheobjectismissingfromthecache. Highlights: -- If the object is not being deleted and does not have the finalizer registered, - then add the finalizer and update the object in Kubernetes. -- If object is being deleted and the finalizer is still present in finalizers list, - then execute the pre-delete logic and remove the finalizer and update the - object. -- Ensure that the pre-delete logic is idempotent. +-Iftheobjectisnotbeingdeletedanddoesnothavethefinalizerregistered, +thenaddthefinalizerandupdatetheobjectinKubernetes. +-Ifobjectisbeingdeletedandthefinalizerisstillpresentinfinalizerslist, +thenexecutethepre-deletelogicandremovethefinalizerandupdatethe +object. +-Ensurethatthepre-deletelogicisidempotent. -{{#literatego ../cronjob-tutorial/testdata/finalizer_example.go}} +{{#literatego../cronjob-tutorial/testdata/finalizer_example.go}} diff --git a/docs/book/src/reference/using_an_external_type.md b/docs/book/src/reference/using_an_external_type.md index 14fcd522048..67db6642674 100644 --- a/docs/book/src/reference/using_an_external_type.md +++ b/docs/book/src/reference/using_an_external_type.md @@ -1,275 +1,275 @@ -# Using an External Type - -There are several different external types that may be referenced when writing a controller. -* Custom Resource Definitions (CRDs) that are defined in the current project (such as via `kubebuilder create api`). -* Core Kubernetes Resources (e.g. Deployments or Pods). -* CRDs that are created and installed in another project. -* A custom API defined via the aggregation layer, served by an extension API server for which the primary API server acts as a proxy. - -Currently, kubebuilder handles the first two, CRDs and Core Resources, seamlessly. You must scaffold the latter two, External CRDs and APIs created via aggregation, manually. - -In order to use a Kubernetes Custom Resource that has been defined in another project -you will need to have several items of information. -* The Domain of the CR -* The Group under the Domain -* The Go import path of the CR Type definition -* The Custom Resource Type you want to depend on. - -The Domain and Group variables have been discussed in other parts of the documentation. The import path would be located in the project that installs the CR. -The Custom Resource Type is usually a Go Type of the same name as the CustomResourceDefinition in kubernetes, e.g. for a `Pod` there will be a type `Pod` in the `v1` group. -For Kubernetes Core Types, the domain can be omitted. +#UsinganExternalType + +Thereareseveraldifferentexternaltypesthatmaybereferencedwhenwritingacontroller. +*CustomResourceDefinitions(CRDs)thataredefinedinthecurrentproject(suchasvia`kubebuildercreateapi`). +*CoreKubernetesResources(e.g.DeploymentsorPods). +*CRDsthatarecreatedandinstalledinanotherproject. +*AcustomAPIdefinedviatheaggregationlayer,servedbyanextensionAPIserverforwhichtheprimaryAPIserveractsasaproxy. + +Currently,kubebuilderhandlesthefirsttwo,CRDsandCoreResources,seamlessly.Youmustscaffoldthelattertwo,ExternalCRDsandAPIscreatedviaaggregation,manually. + +InordertouseaKubernetesCustomResourcethathasbeendefinedinanotherproject +youwillneedtohaveseveralitemsofinformation. +*TheDomainoftheCR +*TheGroupundertheDomain +*TheGoimportpathoftheCRTypedefinition +*TheCustomResourceTypeyouwanttodependon. + +TheDomainandGroupvariableshavebeendiscussedinotherpartsofthedocumentation.TheimportpathwouldbelocatedintheprojectthatinstallstheCR. +TheCustomResourceTypeisusuallyaGoTypeofthesamenameastheCustomResourceDefinitioninkubernetes,e.g.fora`Pod`therewillbeatype`Pod`inthe`v1`group. +ForKubernetesCoreTypes,thedomaincanbeomitted. `` -This document uses `my` and `their` prefixes as a naming convention for repos, groups, and types to clearly distinguish between your own project and the external one you are referencing. +Thisdocumentuses`my`and`their`prefixesasanamingconventionforrepos,groups,andtypestoclearlydistinguishbetweenyourownprojectandtheexternaloneyouarereferencing. -In our example we will assume the following external API Type: +InourexamplewewillassumethefollowingexternalAPIType: -`github.com/theiruser/theirproject` is another kubebuilder project on whose CRD we want to depend and extend on. -Thus, it contains a `go.mod` in its repository root. The import path for the go types would be `github.com/theiruser/theirproject/api/theirgroup/v1alpha1`. +`github.com/theiruser/theirproject`isanotherkubebuilderprojectonwhoseCRDwewanttodependandextendon. +Thus,itcontainsa`go.mod`initsrepositoryroot.Theimportpathforthegotypeswouldbe`github.com/theiruser/theirproject/api/theirgroup/v1alpha1`. -The Domain of the CR is `theirs.com`, the Group is `theirgroup` and the kind and go type would be `ExternalType`. +TheDomainoftheCRis`theirs.com`,theGroupis`theirgroup`andthekindandgotypewouldbe`ExternalType`. -If there is an interest to have multiple Controllers running in different Groups (e.g. because one is an owned CRD and one is an external Type), please first -reconfigure the Project to use a multi-group layout as described in the [Multi-Group documentation](../migration/multi-group.md). +IfthereisaninteresttohavemultipleControllersrunningindifferentGroups(e.g.becauseoneisanownedCRDandoneisanexternalType),pleasefirst +reconfiguretheProjecttouseamulti-grouplayoutasdescribedinthe[Multi-Groupdocumentation](../migration/multi-group.md). -### Prerequisites +###Prerequisites -The following guide assumes that you have already created a project using `kubebuilder init` in a directory in the GOPATH. Please reference the [Getting Started Guide](../getting-started.md) for more information. +Thefollowingguideassumesthatyouhavealreadycreatedaprojectusing`kubebuilderinit`inadirectoryintheGOPATH.Pleasereferencethe[GettingStartedGuide](../getting-started.md)formoreinformation. -Note that if you did not pass `--domain` to `kubebuilder init` you will need to modify it for the individual api types as the default is `my.domain`, not `theirs.com`. -Similarly, if you intend to use your own domain, please configure your own domain with `kubebuilder init` and do not use `theirs.com for the domain. +Notethatifyoudidnotpass`--domain`to`kubebuilderinit`youwillneedtomodifyitfortheindividualapitypesasthedefaultis`my.domain`,not`theirs.com`. +Similarly,ifyouintendtouseyourowndomain,pleaseconfigureyourowndomainwith`kubebuilderinit`anddonotuse`theirs.comforthedomain. -### Add a controller for the external Type +###AddacontrollerfortheexternalType -Run the command `create api` to scaffold only the controller to manage the external type: +Runthecommand`createapi`toscaffoldonlythecontrollertomanagetheexternaltype: ```shell -kubebuilder create api --group --version v1alpha1 --kind --controller --resource=false +kubebuildercreateapi--group--versionv1alpha1--kind--controller--resource=false ``` -Note that the `resource` argument is set to false, as we are not attempting to create our own CustomResourceDefinition, -but instead rely on an external one. +Notethatthe`resource`argumentissettofalse,aswearenotattemptingtocreateourownCustomResourceDefinition, +butinsteadrelyonanexternalone. -This will result in a `PROJECT` entry with the default domain of the `PROJECT` (`my.domain` if not specified in `kubebuilder init`). -For use of other domains, such as `theirs.com`, one will have to manually adjust the `PROJECT` file with the correct domain for the entry: +Thiswillresultina`PROJECT`entrywiththedefaultdomainofthe`PROJECT`(`my.domain`ifnotspecifiedin`kubebuilderinit`). +Foruseofotherdomains,suchas`theirs.com`,onewillhavetomanuallyadjustthe`PROJECT`filewiththecorrectdomainfortheentry: - -file: PROJECT +file:PROJECT ``` -domain: my.domain +domain:my.domain layout: -- go.kubebuilder.io/v4 -projectName: testkube -repo: example.com +-go.kubebuilder.io/v4 +projectName:testkube +repo:example.com resources: -- controller: true - domain: my.domain ## <- Replace the domain with theirs.com domain - group: mygroup - kind: ExternalType - version: v1alpha1 -version: "3" +-controller:true +domain:my.domain##<-Replacethedomainwiththeirs.comdomain +group:mygroup +kind:ExternalType +version:v1alpha1 +version:"3" ``` -At the same time, the generated RBAC manifests need to be adjusted: +Atthesametime,thegeneratedRBACmanifestsneedtobeadjusted: -file: internal/controller/externaltype_controller.go +file:internal/controller/externaltype_controller.go ```go -// ExternalTypeReconciler reconciles a ExternalType object -type ExternalTypeReconciler struct { - client.Client - Scheme *runtime.Scheme +//ExternalTypeReconcilerreconcilesaExternalTypeobject +typeExternalTypeReconcilerstruct{ +client.Client +Scheme*runtime.Scheme } -// external types can be added like this +//externaltypescanbeaddedlikethis //+kubebuilder:rbac:groups=theirgroup.theirs.com,resources=externaltypes,verbs=get;list;watch;create;update;patch;delete //+kubebuilder:rbac:groups=theirgroup.theirs.com,resources=externaltypes/status,verbs=get;update;patch //+kubebuilder:rbac:groups=theirgroup.theirs.com,resources=externaltypes/finalizers,verbs=update -// core types can be added like this +//coretypescanbeaddedlikethis //+kubebuilder:rbac:groups=core,resources=pods,verbs=get;list;watch;create;update;patch;delete //+kubebuilder:rbac:groups=core,resources=pods/status,verbs=get;list;watch;create;update;patch;delete //+kubebuilder:rbac:groups=core,resources=pods/finalizers,verbs=update ``` -### Register your Types +###RegisteryourTypes - -Edit the following lines to the main.go file to register the external types: +Editthefollowinglinestothemain.gofiletoregistertheexternaltypes: -file: cmd/main.go +file:cmd/main.go ```go -package apis +packageapis -import ( - theirgroupv1alpha1 "github.com/theiruser/theirproject/apis/theirgroup/v1alpha1" +import( +theirgroupv1alpha1"github.com/theiruser/theirproject/apis/theirgroup/v1alpha1" ) -func init() { - utilruntime.Must(clientgoscheme.AddToScheme(scheme)) - utilruntime.Must(theirgroupv1alpha1.AddToScheme(scheme)) // this contains the external API types - //+kubebuilder:scaffold:scheme -} +funcinit(){ +utilruntime.Must(clientgoscheme.AddToScheme(scheme)) +utilruntime.Must(theirgroupv1alpha1.AddToScheme(scheme))//thiscontainstheexternalAPItypes +//+kubebuilder:scaffold:scheme +} ``` -## Edit the Controller `SetupWithManager` function +##EdittheController`SetupWithManager`function -### Use the correct imports for your API and uncomment the controlled resource +###UsethecorrectimportsforyourAPIanduncommentthecontrolledresource -file: internal/controllers/externaltype_controllers.go +file:internal/controllers/externaltype_controllers.go ```go -package controllers +packagecontrollers -import ( - theirgroupv1alpha1 "github.com/theiruser/theirproject/apis/theirgroup/v1alpha1" +import( +theirgroupv1alpha1"github.com/theiruser/theirproject/apis/theirgroup/v1alpha1" ) //... -// SetupWithManager sets up the controller with the Manager. -func (r *ExternalTypeReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&theirgroupv1alpha1.ExternalType{}). - Complete(r) +//SetupWithManagersetsupthecontrollerwiththeManager. +func(r*ExternalTypeReconciler)SetupWithManager(mgrctrl.Manager)error{ +returnctrl.NewControllerManagedBy(mgr). +For(&theirgroupv1alpha1.ExternalType{}). +Complete(r) } ``` -Note that core resources may simply be imported by depending on the API's from upstream Kubernetes and do not need additional `AddToScheme` registrations: +NotethatcoreresourcesmaysimplybeimportedbydependingontheAPI'sfromupstreamKubernetesanddonotneedadditional`AddToScheme`registrations: -file: internal/controllers/externaltype_controllers.go +file:internal/controllers/externaltype_controllers.go ```go -package controllers -// contains core resources like Deployment -import ( - v1 "k8s.io/api/apps/v1" +packagecontrollers +//containscoreresourceslikeDeployment +import( +v1"k8s.io/api/apps/v1" ) -// SetupWithManager sets up the controller with the Manager. -func (r *ExternalTypeReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&v1.Pod{}). - Complete(r) +//SetupWithManagersetsupthecontrollerwiththeManager. +func(r*ExternalTypeReconciler)SetupWithManager(mgrctrl.Manager)error{ +returnctrl.NewControllerManagedBy(mgr). +For(&v1.Pod{}). +Complete(r) } ``` -### Update dependencies +###Updatedependencies ``` -go mod tidy +gomodtidy ``` -### Generate RBACs with updated Groups and Resources +###GenerateRBACswithupdatedGroupsandResources ``` -make manifests -``` +makemanifests +``` -## Prepare for testing +##Preparefortesting -### Register your resource in the Scheme +###RegisteryourresourceintheScheme -Edit the `CRDDirectoryPaths` in your test suite and add the correct `AddToScheme` entry during suite initialization: +Editthe`CRDDirectoryPaths`inyourtestsuiteandaddthecorrect`AddToScheme`entryduringsuiteinitialization: -file: internal/controllers/suite_test.go +file:internal/controllers/suite_test.go ```go -package controller - -import ( - "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" - //+kubebuilder:scaffold:imports - theirgroupv1alpha1 "github.com/theiruser/theirproject/apis/theirgroup/v1alpha1" +packagecontroller + +import( +"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" +//+kubebuilder:scaffold:imports +theirgroupv1alpha1"github.com/theiruser/theirproject/apis/theirgroup/v1alpha1" ) -var cfg *rest.Config -var k8sClient client.Client -var testEnv *envtest.Environment +varcfg*rest.Config +vark8sClientclient.Client +vartestEnv*envtest.Environment -func TestControllers(t *testing.T) { - RegisterFailHandler(Fail) +funcTestControllers(t*testing.T){ +RegisterFailHandler(Fail) - RunSpecs(t, "Controller Suite") +RunSpecs(t,"ControllerSuite") } -var _ = BeforeSuite(func() { - //... - By("bootstrapping test environment") - testEnv = &envtest.Environment{ - CRDDirectoryPaths: []string{ - // if you are using vendoring and rely on a kubebuilder based project, you can simply rely on the vendored config directory - filepath.Join("..", "..", "..", "vendor", "github.com", "theiruser", "theirproject", "config", "crds"), - // otherwise you can simply download the CRD from any source and place it within the config/crd/bases directory, - filepath.Join("..", "..", "config", "crd", "bases"), - }, - ErrorIfCRDPathMissing: false, - - // 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.28.3-%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()) - - //+kubebuilder:scaffold:scheme - Expect(theirgroupv1alpha1.AddToScheme(scheme.Scheme)).To(Succeed()) - - k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) - Expect(err).NotTo(HaveOccurred()) - Expect(k8sClient).NotTo(BeNil()) +var_=BeforeSuite(func(){ +//... +By("bootstrappingtestenvironment") +testEnv=&envtest.Environment{ +CRDDirectoryPaths:[]string{ +//ifyouareusingvendoringandrelyonakubebuilderbasedproject,youcansimplyrelyonthevendoredconfigdirectory +filepath.Join("..","..","..","vendor","github.com","theiruser","theirproject","config","crds"), +//otherwiseyoucansimplydownloadtheCRDfromanysourceandplaceitwithintheconfig/crd/basesdirectory, +filepath.Join("..","..","config","crd","bases"), +}, +ErrorIfCRDPathMissing:false, + +//TheBinaryAssetsDirectoryisonlyrequiredifyouwanttorunthetestsdirectly +//withoutcallthemakefiletargettest.Ifnotinformeditwilllookforthe +//defaultpathdefinedincontroller-runtimewhichis/usr/local/kubebuilder/. +//Notethatyoumusthavetherequiredbinariessetupunderthebindirectorytoperform +//thetestsdirectly.Whenwerunmaketestitwillbesetupandusedautomatically. +BinaryAssetsDirectory:filepath.Join("..","..","bin","k8s", +fmt.Sprintf("1.28.3-%s-%s",runtime.GOOS,runtime.GOARCH)), +} + +varerrerror +//cfgisdefinedinthisfileglobally. +cfg,err=testEnv.Start() +Expect(err).NotTo(HaveOccurred()) +Expect(cfg).NotTo(BeNil()) + +//+kubebuilder:scaffold:scheme +Expect(theirgroupv1alpha1.AddToScheme(scheme.Scheme)).To(Succeed()) + +k8sClient,err=client.New(cfg,client.Options{Scheme:scheme.Scheme}) +Expect(err).NotTo(HaveOccurred()) +Expect(k8sClient).NotTo(BeNil()) }) ``` -### Verifying API Availability in the Cluster +###VerifyingAPIAvailabilityintheCluster -Since we are now using external types, you will now have to rely on them being installed into the cluster. -If the APIs are not available at the time the manager starts, all informers listening to the non-available types -will fail, causing the manager to exit with an error similar to +Sincewearenowusingexternaltypes,youwillnowhavetorelyonthembeinginstalledintothecluster. +IftheAPIsarenotavailableatthetimethemanagerstarts,allinformerslisteningtothenon-availabletypes +willfail,causingthemanagertoexitwithanerrorsimilarto ``` -failed to get informer from cache {"error": "Timeout: failed waiting for *v1alpha1.ExternalType Informer to sync"} +failedtogetinformerfromcache{"error":"Timeout:failedwaitingfor*v1alpha1.ExternalTypeInformertosync"} ``` -This will signal that the API Server is not yet ready to serve the external types. +ThiswillsignalthattheAPIServerisnotyetreadytoservetheexternaltypes. -## Helpful Tips +##HelpfulTips -### Locate your domain and group variables +###Locateyourdomainandgroupvariables -The following kubectl commands may be useful +Thefollowingkubectlcommandsmaybeuseful ```shell -kubectl api-resources --verbs=list -o name -kubectl api-resources --verbs=list -o name | grep my.domain +kubectlapi-resources--verbs=list-oname +kubectlapi-resources--verbs=list-oname|grepmy.domain ``` diff --git a/docs/book/src/reference/watching-resources.md b/docs/book/src/reference/watching-resources.md index 85c73959368..e8352462edc 100644 --- a/docs/book/src/reference/watching-resources.md +++ b/docs/book/src/reference/watching-resources.md @@ -1,16 +1,16 @@ -# Watching Resources +#WatchingResources -Inside a `Reconcile()` control loop, you are looking to do a collection of operations until it has the desired state on the cluster. -Therefore, it can be necessary to know when a resource that you care about is changed. -In the case that there is an action (create, update, edit, delete, etc.) on a watched resource, `Reconcile()` should be called for the resources watching it. +Insidea`Reconcile()`controlloop,youarelookingtodoacollectionofoperationsuntilithasthedesiredstateonthecluster. +Therefore,itcanbenecessarytoknowwhenaresourcethatyoucareaboutischanged. +Inthecasethatthereisanaction(create,update,edit,delete,etc.)onawatchedresource,`Reconcile()`shouldbecalledfortheresourceswatchingit. -[Controller Runtime libraries](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/builder) provide many ways for resources to be managed and watched. -This ranges from the easy and obvious use cases, such as watching the resources which were created and managed by the controller, to more unique and advanced use cases. +[ControllerRuntimelibraries](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/builder)providemanywaysforresourcestobemanagedandwatched. +Thisrangesfromtheeasyandobvioususecases,suchaswatchingtheresourceswhichwerecreatedandmanagedbythecontroller,tomoreuniqueandadvancedusecases. -See each subsection for explanations and examples of the different ways in which your controller can _Watch_ the resources it cares about. +Seeeachsubsectionforexplanationsandexamplesofthedifferentwaysinwhichyourcontrollercan_Watch_theresourcesitcaresabout. -- [Watching Operator Managed Resources](watching-resources/operator-managed.md) - - These resources are created and managed by the same operator as the resource watching them. - This section covers both if they are managed by the same controller or separate controllers. -- [Watching Externally Managed Resources](watching-resources/externally-managed.md) - - These resources could be manually created, or managed by other operators/controllers or the Kubernetes control plane. \ No newline at end of file +-[WatchingOperatorManagedResources](watching-resources/operator-managed.md)- +Theseresourcesarecreatedandmanagedbythesameoperatorastheresourcewatchingthem. +Thissectioncoversbothiftheyaremanagedbythesamecontrollerorseparatecontrollers. +-[WatchingExternallyManagedResources](watching-resources/externally-managed.md)- +Theseresourcescouldbemanuallycreated,ormanagedbyotheroperators/controllersortheKubernetescontrolplane. \ No newline at end of file diff --git a/docs/book/src/reference/watching-resources/externally-managed.md b/docs/book/src/reference/watching-resources/externally-managed.md index 3f64b5aed90..8a4700a366f 100644 --- a/docs/book/src/reference/watching-resources/externally-managed.md +++ b/docs/book/src/reference/watching-resources/externally-managed.md @@ -1,31 +1,31 @@ -# Watching Externally Managed Resources +#WatchingExternallyManagedResources -By default, Kubebuilder and the Controller Runtime libraries allow for controllers -to easily watch the resources that they manage as well as dependent resources that are `Owned` by the controller. -However, those are not always the only resources that need to be watched in the cluster. +Bydefault,KubebuilderandtheControllerRuntimelibrariesallowforcontrollers +toeasilywatchtheresourcesthattheymanageaswellasdependentresourcesthatare`Owned`bythecontroller. +However,thosearenotalwaystheonlyresourcesthatneedtobewatchedinthecluster. -## User Specified Resources +##UserSpecifiedResources -There are many examples of Resource Specs that allow users to reference external resources. -- Ingresses have references to Service objects -- Pods have references to ConfigMaps, Secrets and Volumes -- Deployments and Services have references to Pods +TherearemanyexamplesofResourceSpecsthatallowuserstoreferenceexternalresources. +-IngresseshavereferencestoServiceobjects +-PodshavereferencestoConfigMaps,SecretsandVolumes +-DeploymentsandServiceshavereferencestoPods -This same functionality can be added to CRDs and custom controllers. -This will allow for resources to be reconciled when another resource it references is changed. +ThissamefunctionalitycanbeaddedtoCRDsandcustomcontrollers. +Thiswillallowforresourcestobereconciledwhenanotherresourceitreferencesischanged. -As an example, we are going to create a `ConfigDeployment` resource. -The `ConfigDeployment`'s purpose is to manage a `Deployment` whose pods are always using the latest version of a `ConfigMap`. -While ConfigMaps are auto-updated within Pods, applications may not always be able to auto-refresh config from the file system. -Some applications require restarts to apply configuration updates. -- The `ConfigDeployment` CRD will hold a reference to a ConfigMap inside its Spec. -- The `ConfigDeployment` controller will be in charge of creating a deployment with Pods that use the ConfigMap. -These pods should be updated anytime that the referenced ConfigMap changes, therefore the ConfigDeployments will need to be reconciled on changes to the referenced ConfigMap. +Asanexample,wearegoingtocreatea`ConfigDeployment`resource. +The`ConfigDeployment`'spurposeistomanagea`Deployment`whosepodsarealwaysusingthelatestversionofa`ConfigMap`. +WhileConfigMapsareauto-updatedwithinPods,applicationsmaynotalwaysbeabletoauto-refreshconfigfromthefilesystem. +Someapplicationsrequirerestartstoapplyconfigurationupdates. +-The`ConfigDeployment`CRDwillholdareferencetoaConfigMapinsideitsSpec. +-The`ConfigDeployment`controllerwillbeinchargeofcreatingadeploymentwithPodsthatusetheConfigMap. +ThesepodsshouldbeupdatedanytimethatthereferencedConfigMapchanges,thereforetheConfigDeploymentswillneedtobereconciledonchangestothereferencedConfigMap. -### Allow for linking of resources in the `Spec` +###Allowforlinkingofresourcesinthe`Spec` -{{#literatego ./testdata/external-indexed-field/api.go}} +{{#literatego./testdata/external-indexed-field/api.go}} -### Watch linked resources +###Watchlinkedresources -{{#literatego ./testdata/external-indexed-field/controller.go}} +{{#literatego./testdata/external-indexed-field/controller.go}} diff --git a/docs/book/src/reference/watching-resources/operator-managed.md b/docs/book/src/reference/watching-resources/operator-managed.md index 6853ade2dba..52eda9319a5 100644 --- a/docs/book/src/reference/watching-resources/operator-managed.md +++ b/docs/book/src/reference/watching-resources/operator-managed.md @@ -1,25 +1,25 @@ -# Watching Operator Managed Resources +#WatchingOperatorManagedResources -Kubebuilder and the Controller Runtime libraries allow for controllers -to implement the logic of their CRD through easy management of Kubernetes resources. +KubebuilderandtheControllerRuntimelibrariesallowforcontrollers +toimplementthelogicoftheirCRDthrougheasymanagementofKubernetesresources. -## Controlled & Owned Resources +##Controlled&OwnedResources -Managing dependency resources is fundamental to a controller, and it's not possible to manage them without watching for changes to their state. -- Deployments must know when the ReplicaSets that they manage are changed -- ReplicaSets must know when their Pods are deleted, or change from healthy to unhealthy. +Managingdependencyresourcesisfundamentaltoacontroller,andit'snotpossibletomanagethemwithoutwatchingforchangestotheirstate. +-DeploymentsmustknowwhentheReplicaSetsthattheymanagearechanged +-ReplicaSetsmustknowwhentheirPodsaredeleted,orchangefromhealthytounhealthy. -Through the `Owns()` functionality, Controller Runtime provides an easy way to watch dependency resources for changes. -A resource can be defined as dependent on another resource through the 'ownerReferences' field. +Throughthe`Owns()`functionality,ControllerRuntimeprovidesaneasywaytowatchdependencyresourcesforchanges. +Aresourcecanbedefinedasdependentonanotherresourcethroughthe'ownerReferences'field. -As an example, we are going to create a `SimpleDeployment` resource. -The `SimpleDeployment`'s purpose is to manage a `Deployment` that users can change certain aspects of, through the `SimpleDeployment` Spec. -The `SimpleDeployment` controller's purpose is to make sure that it's owned `Deployment` (has an ownerReference which points to `SimpleDeployment` resource) always uses the settings provided by the user. +Asanexample,wearegoingtocreatea`SimpleDeployment`resource. +The`SimpleDeployment`'spurposeistomanagea`Deployment`thatuserscanchangecertainaspectsof,throughthe`SimpleDeployment`Spec. +The`SimpleDeployment`controller'spurposeistomakesurethatit'sowned`Deployment`(hasanownerReferencewhichpointsto`SimpleDeployment`resource)alwaysusesthesettingsprovidedbytheuser. -### Provide basic templating in the `Spec` +###Providebasictemplatinginthe`Spec` -{{#literatego ./testdata/owned-resource/api.go}} +{{#literatego./testdata/owned-resource/api.go}} -### Manage the Owned Resource +###ManagetheOwnedResource -{{#literatego ./testdata/owned-resource/controller.go}} \ No newline at end of file +{{#literatego./testdata/owned-resource/controller.go}} \ No newline at end of file diff --git a/docs/book/src/reference/webhook-for-core-types.md b/docs/book/src/reference/webhook-for-core-types.md index dd0258a44c9..ee5ec9c5180 100644 --- a/docs/book/src/reference/webhook-for-core-types.md +++ b/docs/book/src/reference/webhook-for-core-types.md @@ -1,77 +1,77 @@ -# Admission Webhook for Core Types +#AdmissionWebhookforCoreTypes -It is very easy to build admission webhooks for CRDs, which has been covered in -the [CronJob tutorial][cronjob-tutorial]. Given that kubebuilder doesn't support webhook scaffolding -for core types, you have to use the library from controller-runtime to handle it. -There is an [example](https://github.com/kubernetes-sigs/controller-runtime/tree/master/examples/builtins) -in controller-runtime. +ItisveryeasytobuildadmissionwebhooksforCRDs,whichhasbeencoveredin +the[CronJobtutorial][cronjob-tutorial].Giventhatkubebuilderdoesn'tsupportwebhookscaffolding +forcoretypes,youhavetousethelibraryfromcontroller-runtimetohandleit. +Thereisan[example](https://github.com/kubernetes-sigs/controller-runtime/tree/master/examples/builtins) +incontroller-runtime. -It is suggested to use kubebuilder to initialize a project, and then you can -follow the steps below to add admission webhooks for core types. +Itissuggestedtousekubebuildertoinitializeaproject,andthenyoucan +followthestepsbelowtoaddadmissionwebhooksforcoretypes. -## Implement Your Handler +##ImplementYourHandler -You need to have your handler implements the +Youneedtohaveyourhandlerimplementsthe [admission.Handler](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/webhook/admission?tab=doc#Handler) interface. ```go -type podAnnotator struct { - Client client.Client - decoder *admission.Decoder +typepodAnnotatorstruct{ +Clientclient.Client +decoder*admission.Decoder } -func (a *podAnnotator) Handle(ctx context.Context, req admission.Request) admission.Response { - pod := &corev1.Pod{} - err := a.decoder.Decode(req, pod) - if err != nil { - return admission.Errored(http.StatusBadRequest, err) - } +func(a*podAnnotator)Handle(ctxcontext.Context,reqadmission.Request)admission.Response{ +pod:=&corev1.Pod{} +err:=a.decoder.Decode(req,pod) +iferr!=nil{ +returnadmission.Errored(http.StatusBadRequest,err) +} - // mutate the fields in pod +//mutatethefieldsinpod - marshaledPod, err := json.Marshal(pod) - if err != nil { - return admission.Errored(http.StatusInternalServerError, err) - } - return admission.PatchResponseFromRaw(req.Object.Raw, marshaledPod) +marshaledPod,err:=json.Marshal(pod) +iferr!=nil{ +returnadmission.Errored(http.StatusInternalServerError,err) +} +returnadmission.PatchResponseFromRaw(req.Object.Raw,marshaledPod) } ``` -**Note**: in order to have controller-gen generate the webhook configuration for -you, you need to add markers. For example, -`// +kubebuilder:webhook:path=/mutate-v1-pod,mutating=true,failurePolicy=fail,groups="",resources=pods,verbs=create;update,versions=v1,name=mpod.kb.io` +**Note**:inordertohavecontroller-gengeneratethewebhookconfigurationfor +you,youneedtoaddmarkers.Forexample, +`//+kubebuilder:webhook:path=/mutate-v1-pod,mutating=true,failurePolicy=fail,groups="",resources=pods,verbs=create;update,versions=v1,name=mpod.kb.io` -## Update main.go +##Updatemain.go -Now you need to register your handler in the webhook server. +Nowyouneedtoregisteryourhandlerinthewebhookserver. ```go -mgr.GetWebhookServer().Register("/mutate-v1-pod", &webhook.Admission{Handler: &podAnnotator{Client: mgr.GetClient()}}) +mgr.GetWebhookServer().Register("/mutate-v1-pod",&webhook.Admission{Handler:&podAnnotator{Client:mgr.GetClient()}}) ``` -You need to ensure the path here match the path in the marker. +Youneedtoensurethepathherematchthepathinthemarker. -### Client/Decoder +###Client/Decoder -If you need a client and/or decoder, just pass them in at struct construction time. +Ifyouneedaclientand/ordecoder,justpasstheminatstructconstructiontime. ```go -mgr.GetWebhookServer().Register("/mutate-v1-pod", &webhook.Admission{ - Handler: &podAnnotator{ - Client: mgr.GetClient(), - decoder: admission.NewDecoder(mgr.GetScheme()), - }, +mgr.GetWebhookServer().Register("/mutate-v1-pod",&webhook.Admission{ +Handler:&podAnnotator{ +Client:mgr.GetClient(), +decoder:admission.NewDecoder(mgr.GetScheme()), +}, }) ``` -## Deploy +##Deploy -Deploying it is just like deploying a webhook server for CRD. You need to -1) provision the serving certificate -2) deploy the server +DeployingitisjustlikedeployingawebhookserverforCRD.Youneedto +1)provisiontheservingcertificate +2)deploytheserver -You can follow the [tutorial](/cronjob-tutorial/running.md). +Youcanfollowthe[tutorial](/cronjob-tutorial/running.md). -[cronjob-tutorial]: /cronjob-tutorial/cronjob-tutorial.md \ No newline at end of file +[cronjob-tutorial]:/cronjob-tutorial/cronjob-tutorial.md \ No newline at end of file diff --git a/docs/book/src/reference/webhook-overview.md b/docs/book/src/reference/webhook-overview.md index 8fffb8914ed..df0f82c3670 100644 --- a/docs/book/src/reference/webhook-overview.md +++ b/docs/book/src/reference/webhook-overview.md @@ -1,35 +1,35 @@ -# Webhook +#Webhook -Webhooks are requests for information sent in a blocking fashion. A web -application implementing webhooks will send a HTTP request to other applications -when a certain event happens. +Webhooksarerequestsforinformationsentinablockingfashion.Aweb +applicationimplementingwebhookswillsendaHTTPrequesttootherapplications +whenacertaineventhappens. -In the kubernetes world, there are 3 kinds of webhooks: -[admission webhook](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#admission-webhooks), -[authorization webhook](https://kubernetes.io/docs/reference/access-authn-authz/webhook/) and -[CRD conversion webhook](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definition-versioning/#webhook-conversion). +Inthekubernetesworld,thereare3kindsofwebhooks: +[admissionwebhook](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#admission-webhooks), +[authorizationwebhook](https://kubernetes.io/docs/reference/access-authn-authz/webhook/)and +[CRDconversionwebhook](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definition-versioning/#webhook-conversion). -In [controller-runtime](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/webhook?tab=doc) -libraries, we support admission webhooks and CRD conversion webhooks. +In[controller-runtime](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/webhook?tab=doc) +libraries,wesupportadmissionwebhooksandCRDconversionwebhooks. -Kubernetes supports these dynamic admission webhooks as of version 1.9 (when the -feature entered beta). +Kubernetessupportsthesedynamicadmissionwebhooksasofversion1.9(whenthe +featureenteredbeta). -Kubernetes supports the conversion webhooks as of version 1.15 (when the -feature entered beta). +Kubernetessupportstheconversionwebhooksasofversion1.15(whenthe +featureenteredbeta). -### Supporting older cluster versions +###Supportingolderclusterversions -By default, `kubebuilder create webhook` will create webhook configs of API version `v1`, -a version introduced in Kubernetes v1.16. If your project intends to support -Kubernetes cluster versions older than v1.16, you must use the `v1beta1` API version: +Bydefault,`kubebuildercreatewebhook`willcreatewebhookconfigsofAPIversion`v1`, +aversionintroducedinKubernetesv1.16.Ifyourprojectintendstosupport +Kubernetesclusterversionsolderthanv1.16,youmustusethe`v1beta1`APIversion: ```sh -kubebuilder create webhook --webhook-version v1beta1 ... +kubebuildercreatewebhook--webhook-versionv1beta1... ``` - diff --git a/docs/kubebuilder_annotation.md b/docs/kubebuilder_annotation.md index ed7a2d80293..bf0749cb6ba 100644 --- a/docs/kubebuilder_annotation.md +++ b/docs/kubebuilder_annotation.md @@ -1,73 +1,73 @@ -# Kubebuilder Annotation +#KubebuilderAnnotation -If you have been using Kubebuilder, you must have seen comments such as `// +kubebuilder:rbac: ....` , `// +kubebuilder:resource:...` in scaffolder Go files. These special comments are used by kubebuilder tools (controller-tools) to generate CRD, RBAC, webhook manifests. In kubebuilder, these special comments are `Kubebuilder Annotation`, a.k.a `annotation`. It is designed for this kind of use case: To use kubebuilder tools, all you have to do is focus on writing your code, and put instructions with parameters as annotations along with your code, so that everything will be handled based on these annotations instructions by kubebuilder. This document illustrates the syntax of these annotations. +IfyouhavebeenusingKubebuilder,youmusthaveseencommentssuchas`//+kubebuilder:rbac:....`,`//+kubebuilder:resource:...`inscaffolderGofiles.Thesespecialcommentsareusedbykubebuildertools(controller-tools)togenerateCRD,RBAC,webhookmanifests.Inkubebuilder,thesespecialcommentsare`KubebuilderAnnotation`,a.k.a`annotation`.Itisdesignedforthiskindofusecase:Tousekubebuildertools,allyouhavetodoisfocusonwritingyourcode,andputinstructionswithparametersasannotationsalongwithyourcode,sothateverythingwillbehandledbasedontheseannotationsinstructionsbykubebuilder.Thisdocumentillustratesthesyntaxoftheseannotations. -## Kubebuilder Annotation Syntax +##KubebuilderAnnotationSyntax -Kubebuilder Annotation has a series of tokens separated by colons into groups from left to right. Each **Token** is a string identifier in an annotation instance. It has meaning by its position in token slice, in the form of -**+[header]:[module]:[submodule]:[key-value elements]** -Go Annotation starts with `+` (e.g. `// +kubebuilder`) to differentiate from regular go comments. +KubebuilderAnnotationhasaseriesoftokensseparatedbycolonsintogroupsfromlefttoright.Each**Token**isastringidentifierinanannotationinstance.Ithasmeaningbyitspositionintokenslice,intheformof +**+[header]:[module]:[submodule]:[key-valueelements]** +GoAnnotationstartswith`+`(e.g.`//+kubebuilder`)todifferentiatefromregulargocomments. -## Token types +##Tokentypes -- **header** is the identifier of a group of annotations. It helps user know which project provides this annotation. For example, in Kubernetes project, headers like `kubebuilder`, `k8s`, `genclient`, etc. are all project identifiers. A header is required for all annotations, since you may use multiple annotations from different projects in the same codebase. +-**header**istheidentifierofagroupofannotations.Ithelpsuserknowwhichprojectprovidesthisannotation.Forexample,inKubernetesproject,headerslike`kubebuilder`,`k8s`,`genclient`,etc.areallprojectidentifiers.Aheaderisrequiredforallannotations,sinceyoumayusemultipleannotationsfromdifferentprojectsinthesamecodebase. -- **module** is the identifier of functional module in an annotation. An annotation may have a group of modules, each of which performs a particular function. +-**module**istheidentifieroffunctionalmoduleinanannotation.Anannotationmayhaveagroupofmodules,eachofwhichperformsaparticularfunction. -- **submodule** (optional) In some cases, the module has a big functional scope, split into fine-grained sub modules, which provide the flexibility of extending module functionality. For example: **module:submodule1:submodule2:submodule3** submodule can be multiple following one by one. +-**submodule**(optional)Insomecases,themodulehasabigfunctionalscope,splitintofine-grainedsubmodules,whichprovidetheflexibilityofextendingmodulefunctionality.Forexample:**module:submodule1:submodule2:submodule3**submodulecanbemultiplefollowingonebyone. -## Levels of symbols +##Levelsofsymbols -Delimiter symbols are distinguished to work in different levels from top-down for splitting values string in tokens, which provides readability and efficiency. +Delimitersymbolsaredistinguishedtoworkindifferentlevelsfromtop-downforsplittingvaluesstringintokens,whichprovidesreadabilityandefficiency. -- **Colon** +-**Colon** - Colon `:` is the 1st level delimiter (to annotation) only for separate tokens. Tokens on different sides of the colon should refer to different token types. +Colon`:`isthe1stleveldelimiter(toannotation)onlyforseparatetokens.Tokensondifferentsidesofthecolonshouldrefertodifferenttokentypes. -- **Comma** +-**Comma** - Comma `,` is the 2nd level delimiter (to annotation) for splitting key-value pairs in **key-value elements** which is normally the last token in annotation. e.g. `+kubebuilder:printcolumn:name=,type=,description=,JSONPath:<.spec.Name>,priority=,format=` It works within token which is the 2nd level of annotation, so it is called "2nd level delimiter" +Comma`,`isthe2ndleveldelimiter(toannotation)forsplittingkey-valuepairsin**key-valueelements**whichisnormallythelasttokeninannotation.e.g.`+kubebuilder:printcolumn:name=,type=,description=,JSONPath:<.spec.Name>,priority=,format=`Itworkswithintokenwhichisthe2ndlevelofannotation,soitiscalled"2ndleveldelimiter" -- **Equal sign** +-**Equalsign** - Equal sign `=` is the 3rd level delimiter (to annotation) for identifying key and value. Since the `key=value` parts are splitted from single token (2nd level), its inner delimiter `=` works for next level (3rd level) +Equalsign`=`isthe3rdleveldelimiter(toannotation)foridentifyingkeyandvalue.Sincethe`key=value`partsaresplittedfromsingletoken(2ndlevel),itsinnerdelimiter`=`worksfornextlevel(3rdlevel) -- **Semicolon sign** +-**Semicolonsign** - Semicolon sign `;` is the 4th level delimiter, which works on the `value` part (4th level) of `key=value`(3rd level) for splitting individual values. e.g. `key1=value1;value2;value3` +Semicolonsign`;`isthe4thleveldelimiter,whichworksonthe`value`part(4thlevel)of`key=value`(3rdlevel)forsplittingindividualvalues.e.g.`key1=value1;value2;value3` -- **Pipe sign or Vertical bar** +-**PipesignorVerticalbar** - Pipe sign `|` is the 5th level delimiter, which works inside the single `value` part (4th level) indicating key and value in case of the single value has nested key-value structure. e.g. `outerkey=innerkey1|innervalue1` +Pipesign`|`isthe5thleveldelimiter,whichworksinsidethesingle`value`part(4thlevel)indicatingkeyandvalueincaseofthesinglevaluehasnestedkey-valuestructure.e.g.`outerkey=innerkey1|innervalue1` -### Examples +###Examples -#### Webhook annotation examples +####Webhookannotationexamples -**[header]** is `kubebuilder`, -**[module]** is `webhook`, -**[submodule]** is `admission` or `serveroption` +**[header]**is`kubebuilder`, +**[module]**is`webhook`, +**[submodule]**is`admission`or`serveroption` ```golang -// +kubebuilder:webhook:admission:groups=apps,resources=deployments,verbs=CREATE;UPDATE,name=bar-webhook,path=/bar,type=mutating,failure-policy=Fail +//+kubebuilder:webhook:admission:groups=apps,resources=deployments,verbs=CREATE;UPDATE,name=bar-webhook,path=/bar,type=mutating,failure-policy=Fail -// +kubebuilder:webhook:serveroption:port=7890,cert-dir=/tmp/test-cert,service=test-system|webhook-service,selector=app|webhook-server,secret=test-system|webhook-secret,mutating-webhook-config-name=test-mutating-webhook-cfg,validating-webhook-config-name=test-validating-webhook-cfg +//+kubebuilder:webhook:serveroption:port=7890,cert-dir=/tmp/test-cert,service=test-system|webhook-service,selector=app|webhook-server,secret=test-system|webhook-secret,mutating-webhook-config-name=test-mutating-webhook-cfg,validating-webhook-config-name=test-validating-webhook-cfg ``` **Notes:** -1. Separate two `submodule` (categories) under `webhook`: 1) `admission`and 2) `serveroption`, handling webhookTags and serverTags separately. -2. For each submodule, all key-values should put in the same comment line. -3. using `|` for splitting key-value of `lables` +1.Separatetwo`submodule`(categories)under`webhook`:1)`admission`and2)`serveroption`,handlingwebhookTagsandserverTagsseparately. +2.Foreachsubmodule,allkey-valuesshouldputinthesamecommentline. +3.using`|`forsplittingkey-valueof`lables` -#### RBAC Annotation examples +####RBACAnnotationexamples -**[header]** is `kubebuilder` -**[module]** is `rbac` -No submodule at this moment, support annotations like : `// +rbac`, `// +kubebuilder:rbac` +**[header]**is`kubebuilder` +**[module]**is`rbac` +Nosubmoduleatthismoment,supportannotationslike:`//+rbac`,`//+kubebuilder:rbac` ```golang -// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;delete +//+kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;delete -// +rbac:groups=apps,resources=deployments,verbs=get;list;watch;delete +//+rbac:groups=apps,resources=deployments,verbs=get;list;watch;delete ``` \ No newline at end of file diff --git a/docs/kubebuilder_v0_v1_difference.md b/docs/kubebuilder_v0_v1_difference.md index dd8736322da..19c17543d34 100644 --- a/docs/kubebuilder_v0_v1_difference.md +++ b/docs/kubebuilder_v0_v1_difference.md @@ -1,56 +1,56 @@ -# Kubebuilder v0 v.s. v1 +#Kubebuilderv0v.s.v1 -Kubebuilder 1.0 adds a new flag `--project-version`, it accepts two different values, `v0` and `v1`. When `v0` is used, the kubebuilder behavior and workflow is the same as kubebuilder 0.*. When `v1` is specified, the generated v1 project layout is architecturally different from v0 project. v1 project uses [controller-runtime](https://github.com/kubernetes-sigs/controller-runtime) set of libraries for controller implementation and used tools under [controller-tools](https://github.com/kubernetes-sigs/controller-tools) for scaffolding and generation. +Kubebuilder1.0addsanewflag`--project-version`,itacceptstwodifferentvalues,`v0`and`v1`.When`v0`isused,thekubebuilderbehaviorandworkflowisthesameaskubebuilder0.*.When`v1`isspecified,thegeneratedv1projectlayoutisarchitecturallydifferentfromv0project.v1projectuses[controller-runtime](https://github.com/kubernetes-sigs/controller-runtime)setoflibrariesforcontrollerimplementationandusedtoolsunder[controller-tools](https://github.com/kubernetes-sigs/controller-tools)forscaffoldingandgeneration. -## Command difference - - kubebuilder v0 has `init`, `create controller`, `create resource`, `create config`, `generate` commands and the workflow is: +##Commanddifference +-kubebuilderv0has`init`,`createcontroller`,`createresource`,`createconfig`,`generate`commandsandtheworkflowis: ``` - kubebuilder init --domain example.com - kubebuilder create resource --group --version --kind - GOBIN=${PWD}/bin go install ${PWD#$GOPATH/src/}/cmd/controller-manager - bin/controller-manager --kubeconfig ~/.kube/config - - kubectl apply -f hack/sample/.yaml - docker build -f Dockerfile.controller . -t - docker push - kubebuilder create config --controller-image --name - kubectl apply -f hack/install.yaml +kubebuilderinit--domainexample.com +kubebuildercreateresource--group--version--kind +GOBIN=${PWD}/bingoinstall${PWD#$GOPATH/src/}/cmd/controller-manager +bin/controller-manager--kubeconfig~/.kube/config + +kubectlapply-fhack/sample/.yaml +dockerbuild-fDockerfile.controller.-t +dockerpush +kubebuildercreateconfig--controller-image--name +kubectlapply-fhack/install.yaml ``` - Every time the resource or controller is updated, users need to run `kubebuilder generate` to regenerate the project. - - kubebuilder v1 has `init`, `create api` commands and the workflow is - +Everytimetheresourceorcontrollerisupdated,usersneedtorun`kubebuildergenerate`toregeneratetheproject. +-kubebuilderv1has`init`,`createapi`commandsandtheworkflowis + ``` - kubebuilder init --domain example.com --license apache2 --owner "The Kubernetes authors" - kubebuilder create api --group ship --version v1beta1 --kind Frigate - make install - make run +kubebuilderinit--domainexample.com--licenseapache2--owner"TheKubernetesauthors" +kubebuildercreateapi--groupship--versionv1beta1--kindFrigate +makeinstall +makerun ``` - - In a v1 project, there is no generate command. When the resource or controller is updated, users don't need to regenerate the project. - -## Scaffolding difference - -- v0 project contains a directory `pkg/client` while v1 project doesn't -- v0 project contains a directory `inject` while v1 project doesn't -- v0 project layout follows predefined directory layout `pkg/apis` and `pkg/controller` while v1 project accepts user specified path -- In v1 project, there is a `init()` function for every api and controller. - -## Library difference -### Controller libraries - - v0 projects import the controller library from kubebuilder `kubebuilder/pkg/controller`. It provides a `GenericController` type with a list of functions. - - - v1 projects import the controller libraries from controller-runtime, such as `controller-runtime/pkg/controller`, `controller-runtime/pkg/reconcile`. - -### Client libraries - - - In v0 projects, the client libraries is generated by `kubebuilder generate` under directory `pkg/client` and imported wherever they are used in the project. - - - v1 projects import the dynamic client library from controller-runtime `controller-runtime/pkg/client`. - -## Wiring difference -Wiring refers to the mechanics of integrating controllers to controller-manager and injecting the dependencies in them. - - v0 projects have a `inject` package and it provides functions for adding the controller to controller-manager as well as registering CRDs. - - v1 projects don't have a `inject` package, the controller is added to controller-manager by a `init` function inside add_.go file inside the controller directory. The types are registered by a `init` function inside _types.go file inside the apis directory. \ No newline at end of file + +Inav1project,thereisnogeneratecommand.Whentheresourceorcontrollerisupdated,usersdon'tneedtoregeneratetheproject. + +##Scaffoldingdifference + +-v0projectcontainsadirectory`pkg/client`whilev1projectdoesn't +-v0projectcontainsadirectory`inject`whilev1projectdoesn't +-v0projectlayoutfollowspredefineddirectorylayout`pkg/apis`and`pkg/controller`whilev1projectacceptsuserspecifiedpath +-Inv1project,thereisa`init()`functionforeveryapiandcontroller. + +##Librarydifference +###Controllerlibraries +-v0projectsimportthecontrollerlibraryfromkubebuilder`kubebuilder/pkg/controller`.Itprovidesa`GenericController`typewithalistoffunctions. + +-v1projectsimportthecontrollerlibrariesfromcontroller-runtime,suchas`controller-runtime/pkg/controller`,`controller-runtime/pkg/reconcile`. + +###Clientlibraries + +-Inv0projects,theclientlibrariesisgeneratedby`kubebuildergenerate`underdirectory`pkg/client`andimportedwherevertheyareusedintheproject. + +-v1projectsimportthedynamicclientlibraryfromcontroller-runtime`controller-runtime/pkg/client`. + +##Wiringdifference +Wiringreferstothemechanicsofintegratingcontrollerstocontroller-managerandinjectingthedependenciesinthem. +-v0projectshavea`inject`packageanditprovidesfunctionsforaddingthecontrollertocontroller-manageraswellasregisteringCRDs. +-v1projectsdon'thavea`inject`package,thecontrollerisaddedtocontroller-managerbya`init`functioninsideadd_.gofileinsidethecontrollerdirectory.Thetypesareregisteredbya`init`functioninside_types.gofileinsidetheapisdirectory. \ No newline at end of file diff --git a/docs/migration_guide.md b/docs/migration_guide.md index 0e59ff4421a..7ae43df35c6 100644 --- a/docs/migration_guide.md +++ b/docs/migration_guide.md @@ -1,146 +1,146 @@ -# Migration guide from v0 project to v1 project +#Migrationguidefromv0projecttov1project -This document describes how to migrate a project created by kubebuilder v0 to a project created by kubebuilder v1. Before jumping into the detailed instructions, please take a look at the list of [major differences between kubebuilder v0 and kubebuilder v1](kubebuilder_v0_v1_difference.md). +Thisdocumentdescribeshowtomigrateaprojectcreatedbykubebuilderv0toaprojectcreatedbykubebuilderv1.Beforejumpingintothedetailedinstructions,pleasetakealookatthelistof[majordifferencesbetweenkubebuilderv0andkubebuilderv1](kubebuilder_v0_v1_difference.md). -The recommended way of migrating a v0 project to a v1 project is to create a new v1 project and copy/modify the code from v0 project to it. +Therecommendedwayofmigratingav0projecttoav1projectistocreateanewv1projectandcopy/modifythecodefromv0projecttoit. -## Init a v1 project -Find project's domain name from the old project's pkg/apis/doc.go and use it to initiate a new project with -`kubebuilder init --project-version v1 --domain ` +##Initav1project +Findproject'sdomainnamefromtheoldproject'spkg/apis/doc.goanduseittoinitiateanewprojectwith +`kubebuilderinit--project-versionv1--domain` -## Create api -Find the group/version/kind names from the project's pkg/apis. The group and version names are directory names while the kind name can be found from *_types.go. Note that the kind name should be capitalized. +##Createapi +Findthegroup/version/kindnamesfromtheproject'spkg/apis.Thegroupandversionnamesaredirectorynameswhilethekindnamecanbefoundfrom*_types.go.Notethatthekindnameshouldbecapitalized. -Create api in the new project with -`kubebuilder create api --group --version --kind ` +Createapiinthenewprojectwith +`kubebuildercreateapi--group--version--kind` -If there are several resources in the old project, repeat the `kubebuilder create api` command to create all of them. +Ifthereareseveralresourcesintheoldproject,repeatthe`kubebuildercreateapi`commandtocreateallofthem. -## Copy types.go -Copy the content of `_types.go` from the old project into the file `_types.go` in the new project. -Note that in the v1 project, there is a section containing `List` and `init` function. Please keep this section. +##Copytypes.go +Copythecontentof`_types.go`fromtheoldprojectintothefile`_types.go`inthenewproject. +Notethatinthev1project,thereisasectioncontaining`List`and`init`function.Pleasekeepthissection. ``` -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -// +genclient:nonNamespaced - -// HelloList contains a list of Hello -type HelloList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []Hello `json:"items"` +//+k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +//+genclient:nonNamespaced + +//HelloListcontainsalistofHello +typeHelloListstruct{ +metav1.TypeMeta`json:",inline"` +metav1.ListMeta`json:"metadata,omitempty"` +Items[]Hello`json:"items"` } -func init() { - SchemeBuilder.Register(&Hello{}, &HelloList{}) +funcinit(){ +SchemeBuilder.Register(&Hello{},&HelloList{}) } ``` -## Copy and modify controller code +##Copyandmodifycontrollercode -### copy and update reconcile function -Note that in v0 and v1 projects, the `Reconcile` -functions have different arguments and return types. +###copyandupdatereconcilefunction +Notethatinv0andv1projects,the`Reconcile` +functionshavedifferentargumentsandreturntypes. -- `Reconcile` function in v0 project: `func (bc *Controller) Reconcile(k types.ReconcileKey) error` +-`Reconcile`functioninv0project:`func(bc*Controller)Reconcile(ktypes.ReconcileKey)error` -- `Reconcile` function in v1 project: `func (r *Reconcile) Reconcile(request reconcile.Request) (reconcile.Result, error)` +-`Reconcile`functioninv1project:`func(r*Reconcile)Reconcile(requestreconcile.Request)(reconcile.Result,error)` -Remove the original body of `Reconcile` function inside the v1 project and copy the body of the `Reconcile` function from the v0 project to the v1 project. Then apply following changes: -- add `reconcile.Result{}` as the first value in every `return` statement -- change the call of client functions such as `Get`, `Create`, `Update`. In v0 projects, the call of client functions has the format like `bc.Lister.().Get()` or `bc.KubernetesClientSet....Get()`. They can be replaced by `r.Client` functions. Here are several examples of updating the client function from v0 project to v1 project: +Removetheoriginalbodyof`Reconcile`functioninsidethev1projectandcopythebodyofthe`Reconcile`functionfromthev0projecttothev1project.Thenapplyfollowingchanges: +-add`reconcile.Result{}`asthefirstvalueinevery`return`statement +-changethecallofclientfunctionssuchas`Get`,`Create`,`Update`.Inv0projects,thecallofclientfunctionshastheformatlike`bc.Lister.().Get()`or`bc.KubernetesClientSet....Get()`.Theycanbereplacedby`r.Client`functions.Hereareseveralexamplesofupdatingtheclientfunctionfromv0projecttov1project: ``` -# in v0 project -mc, err := bc.memcachedLister.Memcacheds(k.Namespace).Get(k.Name) -# in v1 project, change to -mc := &myappsv1alpha1.Memcached{} -err := r.Client.Get(context.TODO(), request.NamespacedName, mc) +#inv0project +mc,err:=bc.memcachedLister.Memcacheds(k.Namespace).Get(k.Name) +#inv1project,changeto +mc:=&myappsv1alpha1.Memcached{} +err:=r.Client.Get(context.TODO(),request.NamespacedName,mc) -# in v0 project -dp, err := bc.KubernetesInformers.Apps().V1().Deployments().Lister().Deployments(mc.Namespace).Get(mc.Name) -# in v1 project, change to -dp := &appsv1.Deployment{} -err := r.Client.Get(context.TODO(), request.NamespacedName, dp) +#inv0project +dp,err:=bc.KubernetesInformers.Apps().V1().Deployments().Lister().Deployments(mc.Namespace).Get(mc.Name) +#inv1project,changeto +dp:=&appsv1.Deployment{} +err:=r.Client.Get(context.TODO(),request.NamespacedName,dp) -dep := &appsv1.Deployment{...} -# in v0 project -dp, err := bc.KubernetesClientSet.AppsV1().Deployments(mc.Namespace).Create(dep) -# in v1 project, change to -err := r.Client.Create(context.TODO(), dep) +dep:=&appsv1.Deployment{...} +#inv0project +dp,err:=bc.KubernetesClientSet.AppsV1().Deployments(mc.Namespace).Create(dep) +#inv1project,changeto +err:=r.Client.Create(context.TODO(),dep) -dep := &appsv1.Deployment{...} -# in v0 project -dp, err = bc.KubernetesClientSet.AppsV1().Deployments(mc.Namespace).Update(deploymentForMemcached(mc)) -# in v1 project, change to -err := r.Client.Update(context.TODO(), dep) +dep:=&appsv1.Deployment{...} +#inv0project +dp,err=bc.KubernetesClientSet.AppsV1().Deployments(mc.Namespace).Update(deploymentForMemcached(mc)) +#inv1project,changeto +err:=r.Client.Update(context.TODO(),dep) -labelSelector := labels.SelectorFrom{...} -# in v0 project -pods, err := bc.KubernetesInformers.Core().V1().Pods().Lister().Pods(mc.Namespace).List(labelSelector) -# in v1 project, change to -pods := &v1.PodList{} -err = r.Client.List(context.TODO(), &client.ListOptions{LabelSelector: labelSelector}, pods) +labelSelector:=labels.SelectorFrom{...} +#inv0project +pods,err:=bc.KubernetesInformers.Core().V1().Pods().Lister().Pods(mc.Namespace).List(labelSelector) +#inv1project,changeto +pods:=&v1.PodList{} +err=r.Client.List(context.TODO(),&client.ListOptions{LabelSelector:labelSelector},pods) ``` -- add library imports used in the v0 project to v1 project such as log, fmt or k8s libraries. Note that libraries from kubebuilder or from the old project's client package shouldn't be added. +-addlibraryimportsusedinthev0projecttov1projectsuchaslog,fmtork8slibraries.Notethatlibrariesfromkubebuilderorfromtheoldproject'sclientpackageshouldn'tbeadded. -### update add function +###updateaddfunction -In a v0 project controller file, there is a `ProvideController` function creating a controller and adding some watches. In v1 projects, the corresponding function is `add`. For this part, you don't need to copy any code from v0 project to v1 project. You need to add some watchers in v1 project's `add` function based on what `watch` functions are called in v0 project's `ProvideController` function. +Inav0projectcontrollerfile,thereisa`ProvideController`functioncreatingacontrollerandaddingsomewatches.Inv1projects,thecorrespondingfunctionis`add`.Forthispart,youdon'tneedtocopyanycodefromv0projecttov1project.Youneedtoaddsomewatchersinv1project's`add`functionbasedonwhat`watch`functionsarecalledinv0project's`ProvideController`function. -Here are several examples: +Hereareseveralexamples: ``` -gc := &controller.GenericController{...} +gc:=&controller.GenericController{...} gc.Watch(&myappsv1alpha1.Memcached{}) -gc.WatchControllerOf(&v1.Pod{}, eventhandlers.Path{bc.LookupRS, bc.LookupDeployment, bc.LookupMemcached}) +gc.WatchControllerOf(&v1.Pod{},eventhandlers.Path{bc.LookupRS,bc.LookupDeployment,bc.LookupMemcached}) ``` -need to be changed to: +needtobechangedto: ``` -c, err := controller.New{...} -c.Watch(&source.Kind{Type: &myappsv1alpha1.Memcached{}}, &handler.EnqueueRequestForObject{}) -c.Watch(&source.Kind{Type: &appsv1.Deployment{}}, &handler.EnqueueRequestForOwner{ - IsController: true, - OwnerType: &myappsv1alpha1.Memcached{}, - }) +c,err:=controller.New{...} +c.Watch(&source.Kind{Type:&myappsv1alpha1.Memcached{}},&handler.EnqueueRequestForObject{}) +c.Watch(&source.Kind{Type:&appsv1.Deployment{}},&handler.EnqueueRequestForOwner{ +IsController:true, +OwnerType:&myappsv1alpha1.Memcached{}, +}) ``` -### copy other functions -If `reconcile` function depends on some other user defined functions, copy those function as well into the v1 project. +###copyotherfunctions +If`reconcile`functiondependsonsomeotheruserdefinedfunctions,copythosefunctionaswellintothev1project. -## Copy user libraries -If there are some user defined libraries in the old project, make sure to copy them as well into the new project. +##Copyuserlibraries +Iftherearesomeuserdefinedlibrariesintheoldproject,makesuretocopythemaswellintothenewproject. -## Update dependency +##Updatedependency -Open the Gopkg.toml file in the old project and find if there is user defined dependency in this block: +OpentheGopkg.tomlfileintheoldprojectandfindifthereisuserdefineddependencyinthisblock: ``` -# Users add deps lines here +#Usersadddepslineshere [prune] - go-tests = true - #unused-packages = true +go-tests=true +#unused-packages=true -# Note: Stanzas below are generated by Kubebuilder and may be rewritten when -# upgrading kubebuilder versions. +#Note:StanzasbelowaregeneratedbyKubebuilderandmayberewrittenwhen +#upgradingkubebuilderversions. -# DO NOT MODIFY BELOW THIS LINE. +#DONOTMODIFYBELOWTHISLINE. ``` -Copy those dependencies into the new project's Gopkg.toml file **before** the line +Copythosedependenciesintothenewproject'sGopkg.tomlfile**before**theline ``` -# STANZAS BELOW ARE GENERATED AND MAY BE WRITTEN - DO NOT MODIFY BELOW THIS LINE. +#STANZASBELOWAREGENERATEDANDMAYBEWRITTEN-DONOTMODIFYBELOWTHISLINE. ``` -## Copy other user files -If there are other user created files in the old project, such as any build scripts, README.md files. Copy those files into the new project. +##Copyotheruserfiles +Ifthereareotherusercreatedfilesintheoldproject,suchasanybuildscripts,README.mdfiles.Copythosefilesintothenewproject. -## Confirmation -Run `make` to make sure the new project can build and pass all the tests. -Run `make install` and `make run` to make sure the api and controller work well on cluster. +##Confirmation +Run`make`tomakesurethenewprojectcanbuildandpassallthetests. +Run`makeinstall`and`makerun`tomakesuretheapiandcontrollerworkwelloncluster. diff --git a/docs/testing/e2e.md b/docs/testing/e2e.md index f4ba7840ff3..d6686a53352 100644 --- a/docs/testing/e2e.md +++ b/docs/testing/e2e.md @@ -1,65 +1,65 @@ -**Running End-to-end Tests on Remote Clusters** +**RunningEnd-to-endTestsonRemoteClusters** -**This document is for kubebuilder v1 only** +**Thisdocumentisforkubebuilderv1only** -This article outlines steps to run e2e tests on remote clusters for controllers created using `kubebuilder`. For example, after developing a database controller, the developer may want to run some e2e tests on a GKE cluster to verify the controller is working as expected. Currently, `kubebuilder` does not provide a template for running the e2e tests. This article serves to address this deficit. +Thisarticleoutlinesstepstorune2etestsonremoteclustersforcontrollerscreatedusing`kubebuilder`.Forexample,afterdevelopingadatabasecontroller,thedevelopermaywanttorunsomee2etestsonaGKEclustertoverifythecontrollerisworkingasexpected.Currently,`kubebuilder`doesnotprovideatemplateforrunningthee2etests.Thisarticleservestoaddressthisdeficit. -The steps are as follow: -1. Create a test file named `_test.go` populated with template below (referring [this](https://github.com/foxish/application/blob/master/e2e/main_test.go)): +Thestepsareasfollow: +1.Createatestfilenamed`_test.go`populatedwithtemplatebelow(referring[this](https://github.com/foxish/application/blob/master/e2e/main_test.go)): ``` -import ( - "k8s.io/client-go/tools/clientcmd" - clientset "k8s.io/redis-operator/pkg/client/clientset/versioned/typed//" - ...... +import( +"k8s.io/client-go/tools/clientcmd" +clientset"k8s.io/redis-operator/pkg/client/clientset/versioned/typed//" +...... ) -// Specify kubeconfig file -func getClientConfig() (*rest.Config, error) { - return clientcmd.BuildConfigFromFlags("", path.Join(os.Getenv("HOME"), "")) +//Specifykubeconfigfile +funcgetClientConfig()(*rest.Config,error){ +returnclientcmd.BuildConfigFromFlags("",path.Join(os.Getenv("HOME"),"")) } -// Set up test environment -var _ = Describe(" should work", func() { - config, err := getClientConfig() - if err != nil { - ...... - } +//Setuptestenvironment +var_=Describe("shouldwork",func(){ +config,err:=getClientConfig() +iferr!=nil{ +...... +} + +//Constructkubernetesclient +k8sClient,err:=kubernetes.NewForConfig(config) +iferr!=nil{ +...... +} - // Construct kubernetes client - k8sClient, err := kubernetes.NewForConfig(config) - if err != nil { - ...... - } +//Constructcontrollerclient +client,err:=clientset.NewForConfig(config) +iferr!=nil{ +...... +} - // Construct controller client - client, err := clientset.NewForConfig(config) - if err != nil { - ...... - } +BeforeEach(func(){ +//Createenvironment-specificresourcessuchascontrollerimageStatefulSet, +//CRDsetc.Note:refer"install.yaml"createdvia"kubebuildercreateconfig" +//commandtohaveanideaofwhatresourcestobecreated. +...... +}) - BeforeEach(func() { - // Create environment-specific resources such as controller image StatefulSet, - // CRDs etc. Note: refer "install.yaml" created via "kubebuilder create config" - // command to have an idea of what resources to be created. - ...... - }) +AfterEach(func(){ +//Deletealltest-specificresources +...... - AfterEach(func() { - // Delete all test-specific resources - ...... +//Deleteallenvironment-specificresources +...... +}) - // Delete all environment-specific resources - ...... - }) +//Declarealistoftestingspecificationswithcorrespondingtestfunctions +//Note:test-specificresourcesarenormallycreatedwithinthetestfunctions +It("shoulddosomething",func(){ +testDoSomething(k8sClient,roClient) +}) - // Declare a list of testing specifications with corresponding test functions - // Note: test-specific resources are normally created within the test functions - It("should do something", func() { - testDoSomething(k8sClient, roClient) - }) - - ...... +...... ``` -2. Write some controller-specific e2e tests -3. Build controller image and upload it to an image storage website such as [gcr.io](https://cloud.google.com/container-registry/) -4. `go test ` +2.Writesomecontroller-specifice2etests +3.Buildcontrollerimageanduploadittoanimagestoragewebsitesuchas[gcr.io](https://cloud.google.com/container-registry/) +4.`gotest` diff --git a/docs/testing/integration.md b/docs/testing/integration.md index 4c456c60ddc..09190334987 100644 --- a/docs/testing/integration.md +++ b/docs/testing/integration.md @@ -1,82 +1,82 @@ -**Writing and Running Integration Tests** +**WritingandRunningIntegrationTests** -**This document is for kubebuilder v1 only** +**Thisdocumentisforkubebuilderv1only** -This article explores steps to write and run integration tests for controllers created using Kubebuilder. Kubebuilder provides a template for writing integration tests. You can simply run all integration (and unit) tests within the project by running: `make test` +ThisarticleexploresstepstowriteandrunintegrationtestsforcontrollerscreatedusingKubebuilder.Kubebuilderprovidesatemplateforwritingintegrationtests.Youcansimplyrunallintegration(andunit)testswithintheprojectbyrunning:`maketest` -For example, there is a controller watching *Parent* objects. The *Parent* objects create *Child* objects. Note that the *Child* objects must have their `.ownerReferences` field setting to the `Parent` objects. You can find the template under `pkg/controllers/parent/parent_controller_test.go`: +Forexample,thereisacontrollerwatching*Parent*objects.The*Parent*objectscreate*Child*objects.Notethatthe*Child*objectsmusthavetheir`.ownerReferences`fieldsettingtothe`Parent`objects.Youcanfindthetemplateunder`pkg/controllers/parent/parent_controller_test.go`: ``` -package parent +packageparent -import ( - _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" - childapis "k8s.io/child/pkg/apis" - childv1alpha1 "k8s.io/childrepo/pkg/apis/child/v1alpha1" - parentapis "k8s.io/parent/pkg/apis" - parentv1alpha1 "k8s.io/parentrepo/pkg/apis/parent/v1alpha1" +import( +_"k8s.io/client-go/plugin/pkg/client/auth/gcp" +childapis"k8s.io/child/pkg/apis" +childv1alpha1"k8s.io/childrepo/pkg/apis/child/v1alpha1" +parentapis"k8s.io/parent/pkg/apis" +parentv1alpha1"k8s.io/parentrepo/pkg/apis/parent/v1alpha1" - ...... +...... ) -const timeout = time.Second * 5 - -var c client.Client -var expectedRequest = reconcile.Request{NamespacedName: types.NamespacedName{Name: "parent", Namespace: "default"}} -var childKey = types.NamespacedName{Name: "child", Namespace: "default"} - -func TestReconcile(t *testing.T) { - g := gomega.NewGomegaWithT(t) - - // Parent instance to be created. - parent := &parentv1alpha1.Parent{ - ObjectMeta: metav1.ObjectMeta{ - Name: "parent", - Namespace: "default", - }, - Spec: metav1.ParentSpec{ - SomeSpecField: "SomeSpecValue", - AnotherSpecField: "AnotherSpecValue", - }, - } - - // Setup the Manager and Controller. Wrap the Controller Reconcile function - // so it writes each request to a channel when it is finished. - mgr, err := manager.New(cfg, manager.Options{}) - - // Setup Scheme for all resources. - if err = parentapis.AddToScheme(mgr.GetScheme()); err != nil { - t.Logf("failed to add Parent scheme: %v", err) - } - if err = childapis.AddToScheme(mgr.GetScheme()); err != nil { - t.Logf("failed to add Child scheme: %v", err) - } - - // Set up and start test manager. - reconciler, err := newReconciler(mgr) - g.Expect(err).NotTo(gomega.HaveOccurred()) - recFn, requests := SetupTestReconcile(reconciler) - g.Expect(add(mgr, recFn)).NotTo(gomega.HaveOccurred()) - defer close(StartTestManager(mgr, g)) - - // Create the Parent object and expect the Reconcile and Child to be created. - c = mgr.GetClient() - err = c.Create(context.TODO(), parent) - g.Expect(err).NotTo(gomega.HaveOccurred()) - defer c.Delete(context.TODO(), parent) - g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedRequest))) - - // Verify Child is created. - child := &childv1alpha1.Child{} - g.Eventually(func() error { return c.Get(context.TODO(), childKey, child) }, timeout). - Should(gomega.Succeed()) - - // Manually delete Child since GC isn't enabled in the test control plane. - g.Expect(c.Delete(context.TODO(), child)).To(gomega.Succeed()) +consttimeout=time.Second*5 + +varcclient.Client +varexpectedRequest=reconcile.Request{NamespacedName:types.NamespacedName{Name:"parent",Namespace:"default"}} +varchildKey=types.NamespacedName{Name:"child",Namespace:"default"} + +funcTestReconcile(t*testing.T){ +g:=gomega.NewGomegaWithT(t) + +//Parentinstancetobecreated. +parent:=&parentv1alpha1.Parent{ +ObjectMeta:metav1.ObjectMeta{ +Name:"parent", +Namespace:"default", +}, +Spec:metav1.ParentSpec{ +SomeSpecField:"SomeSpecValue", +AnotherSpecField:"AnotherSpecValue", +}, +} + +//SetuptheManagerandController.WraptheControllerReconcilefunction +//soitwriteseachrequesttoachannelwhenitisfinished. +mgr,err:=manager.New(cfg,manager.Options{}) + +//SetupSchemeforallresources. +iferr=parentapis.AddToScheme(mgr.GetScheme());err!=nil{ +t.Logf("failedtoaddParentscheme:%v",err) +} +iferr=childapis.AddToScheme(mgr.GetScheme());err!=nil{ +t.Logf("failedtoaddChildscheme:%v",err) +} + +//Setupandstarttestmanager. +reconciler,err:=newReconciler(mgr) +g.Expect(err).NotTo(gomega.HaveOccurred()) +recFn,requests:=SetupTestReconcile(reconciler) +g.Expect(add(mgr,recFn)).NotTo(gomega.HaveOccurred()) +deferclose(StartTestManager(mgr,g)) + +//CreatetheParentobjectandexpecttheReconcileandChildtobecreated. +c=mgr.GetClient() +err=c.Create(context.TODO(),parent) +g.Expect(err).NotTo(gomega.HaveOccurred()) +deferc.Delete(context.TODO(),parent) +g.Eventually(requests,timeout).Should(gomega.Receive(gomega.Equal(expectedRequest))) + +//VerifyChildiscreated. +child:=&childv1alpha1.Child{} +g.Eventually(func()error{returnc.Get(context.TODO(),childKey,child)},timeout). +Should(gomega.Succeed()) + +//ManuallydeleteChildsinceGCisn'tenabledinthetestcontrolplane. +g.Expect(c.Delete(context.TODO(),child)).To(gomega.Succeed()) } ``` -`SetupTestReconcile` function above brings up an API server and etcd instance. Note that there is no any node creation for integration testing environment. If you want to test your controller on a real node, you should write end-to-end tests. +`SetupTestReconcile`functionabovebringsupanAPIserverandetcdinstance.Notethatthereisnoanynodecreationforintegrationtestingenvironment.Ifyouwanttotestyourcontrolleronarealnode,youshouldwriteend-to-endtests. -The manager is started as part of the test itself (`StartTestManager` function). +Themanagerisstartedaspartofthetestitself(`StartTestManager`function). -Both functions are located in `pkg/controllers/parent/parent_controller_suite_test.go` file. The file also contains a `TestMain` function that allows you to specify CRD directory paths for the testing environment. +Bothfunctionsarelocatedin`pkg/controllers/parent/parent_controller_suite_test.go`file.Thefilealsocontainsa`TestMain`functionthatallowsyoutospecifyCRDdirectorypathsforthetestingenvironment. diff --git a/pkg/plugins/golang/v4/scaffolds/internal/templates/readme.go b/pkg/plugins/golang/v4/scaffolds/internal/templates/readme.go index f718f1b07b0..6cc9a530af5 100644 --- a/pkg/plugins/golang/v4/scaffolds/internal/templates/readme.go +++ b/pkg/plugins/golang/v4/scaffolds/internal/templates/readme.go @@ -80,8 +80,8 @@ const readmeFileTemplate = `# {{ .ProjectName }} %s -**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. +**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:** @@ -92,7 +92,7 @@ Make sure you have the proper permission to the registry if the above commands d %s -> **NOTE**: If you encounter RBAC errors, you may need to grant yourself cluster-admin +> **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** diff --git a/scripts/demo/README.md b/scripts/demo/README.md index 96f6fe6e4a1..a7e31170ad3 100644 --- a/scripts/demo/README.md +++ b/scripts/demo/README.md @@ -1,33 +1,33 @@ -This directory contains scripts to run a quick demo of Kubebuilder. +ThisdirectorycontainsscriptstorunaquickdemoofKubebuilder. -Steps to run demo: +Stepstorundemo: ```sh -mkdir /tmp/kb-demo -cd /tmp/kb-demo -DEMO_AUTO_RUN=1 ./run.sh +mkdir/tmp/kb-demo +cd/tmp/kb-demo +DEMO_AUTO_RUN=1./run.sh ``` -Instructions for producing the demo movie: +Instructionsforproducingthedemomovie: ```sh -# Create temporary directory -mkdir /tmp/kb-demo -cd /tmp/kb-demo +#Createtemporarydirectory +mkdir/tmp/kb-demo +cd/tmp/kb-demo -asciinema rec +asciinemarec /scripts/demo/run.sh -# After each step, press to proceed to the next step +#Aftereachstep,presstoproceedtothenextstep - to terminate the script - to terminate the asciinema recording - to save the recording locally +toterminatethescript +toterminatetheasciinemarecording +tosavetherecordinglocally -# Edit the recorded file by editing the controller-gen path -# Once you are happy with the recording, use svg-term program to generate the svg +#Edittherecordedfilebyeditingthecontroller-genpath +#Onceyouarehappywiththerecording,usesvg-termprogramtogeneratethesvg -svg-term --in= --out demo.svg --window +svg-term--in=--outdemo.svg--window ``` diff --git a/test/check_spaces.sh b/test/check_spaces.sh new file mode 100755 index 00000000000..edd9f00c30b --- /dev/null +++ b/test/check_spaces.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +# Copyright 2024 The Kubernetes Authors. +# +# 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. + +function validate_docs_trailing_spaces { + if find . -type f -name "*.md" -exec grep -Hn '[[:space:]]$' {} +; then + echo "Trailing spaces were found in docs files" + exit 1 + fi + +} + +validate_docs_trailing_spaces diff --git a/testdata/project-v3/README.md b/testdata/project-v3/README.md index a968e958d3d..459f333d9f6 100644 --- a/testdata/project-v3/README.md +++ b/testdata/project-v3/README.md @@ -1,94 +1,94 @@ -# project-v3 -// TODO(user): Add simple overview of use/purpose +#project-v3 +//TODO(user):Addsimpleoverviewofuse/purpose -## Description -// TODO(user): An in-depth paragraph about your project and overview of use +##Description +//TODO(user):Anin-depthparagraphaboutyourprojectandoverviewofuse -## Getting Started -You’ll need a Kubernetes cluster to run against. You can use [KIND](https://sigs.k8s.io/kind) to get a local cluster for testing, or run against a remote cluster. -**Note:** Your controller will automatically use the current context in your kubeconfig file (i.e. whatever cluster `kubectl cluster-info` shows). +##GettingStarted +You’llneedaKubernetesclustertorunagainst.Youcanuse[KIND](https://sigs.k8s.io/kind)togetalocalclusterfortesting,orrunagainstaremotecluster. +**Note:**Yourcontrollerwillautomaticallyusethecurrentcontextinyourkubeconfigfile(i.e.whatevercluster`kubectlcluster-info`shows). -### Running on the cluster -1. Install Instances of Custom Resources: +###Runningonthecluster +1.InstallInstancesofCustomResources: ```sh -kubectl apply -k config/samples/ +kubectlapply-kconfig/samples/ ``` -2. Build and push your image to the location specified by `IMG`: +2.Buildandpushyourimagetothelocationspecifiedby`IMG`: ```sh -make docker-build docker-push IMG=/project-v3:tag +makedocker-builddocker-pushIMG=/project-v3:tag ``` -3. Deploy the controller to the cluster with the image specified by `IMG`: +3.Deploythecontrollertotheclusterwiththeimagespecifiedby`IMG`: ```sh -make deploy IMG=/project-v3:tag +makedeployIMG=/project-v3:tag ``` -### Uninstall CRDs -To delete the CRDs from the cluster: +###UninstallCRDs +TodeletetheCRDsfromthecluster: ```sh -make uninstall +makeuninstall ``` -### Undeploy controller -UnDeploy the controller from the cluster: +###Undeploycontroller +UnDeploythecontrollerfromthecluster: ```sh -make undeploy +makeundeploy ``` -## Contributing -// TODO(user): Add detailed information on how you would like others to contribute to this project +##Contributing +//TODO(user):Adddetailedinformationonhowyouwouldlikeotherstocontributetothisproject -### How it works -This project aims to follow the Kubernetes [Operator pattern](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/). +###Howitworks +ThisprojectaimstofollowtheKubernetes[Operatorpattern](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/). -It uses [Controllers](https://kubernetes.io/docs/concepts/architecture/controller/), -which provide a reconcile function responsible for synchronizing resources until the desired state is reached on the cluster. +Ituses[Controllers](https://kubernetes.io/docs/concepts/architecture/controller/), +whichprovideareconcilefunctionresponsibleforsynchronizingresourcesuntilthedesiredstateisreachedonthecluster. -### Test It Out -1. Install the CRDs into the cluster: +###TestItOut +1.InstalltheCRDsintothecluster: ```sh -make install +makeinstall ``` -2. Run your controller (this will run in the foreground, so switch to a new terminal if you want to leave it running): +2.Runyourcontroller(thiswillrunintheforeground,soswitchtoanewterminalifyouwanttoleaveitrunning): ```sh -make run +makerun ``` -**NOTE:** You can also run this in one step by running: `make install run` +**NOTE:**Youcanalsorunthisinonestepbyrunning:`makeinstallrun` -### Modifying the API definitions -If you are editing the API definitions, generate the manifests such as CRs or CRDs using: +###ModifyingtheAPIdefinitions +IfyouareeditingtheAPIdefinitions,generatethemanifestssuchasCRsorCRDsusing: ```sh -make manifests +makemanifests ``` -**NOTE:** Run `make --help` for more information on all potential `make` targets +**NOTE:**Run`make--help`formoreinformationonallpotential`make`targets -More information can be found via the [Kubebuilder Documentation](https://book.kubebuilder.io/introduction.html) +Moreinformationcanbefoundviathe[KubebuilderDocumentation](https://book.kubebuilder.io/introduction.html) -## License +##License -Copyright 2024 The Kubernetes authors. +Copyright2024TheKubernetesauthors. -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 +LicensedundertheApacheLicense,Version2.0(the"License"); +youmaynotusethisfileexceptincompliancewiththeLicense. +YoumayobtainacopyoftheLicenseat - http://www.apache.org/licenses/LICENSE-2.0 +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. +Unlessrequiredbyapplicablelaworagreedtoinwriting,software +distributedundertheLicenseisdistributedonan"ASIS"BASIS, +WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied. +SeetheLicenseforthespecificlanguagegoverningpermissionsand +limitationsundertheLicense. diff --git a/testdata/project-v4-multigroup-with-deploy-image/README.md b/testdata/project-v4-multigroup-with-deploy-image/README.md index b6543d55d83..5642074cd7a 100644 --- a/testdata/project-v4-multigroup-with-deploy-image/README.md +++ b/testdata/project-v4-multigroup-with-deploy-image/README.md @@ -1,114 +1,114 @@ -# project-v4-multigroup-with-deploy-image -// TODO(user): Add simple overview of use/purpose +#project-v4-multigroup-with-deploy-image +//TODO(user):Addsimpleoverviewofuse/purpose -## Description -// TODO(user): An in-depth paragraph about your project and overview of use +##Description +//TODO(user):Anin-depthparagraphaboutyourprojectandoverviewofuse -## Getting Started +##GettingStarted -### Prerequisites -- go version v1.21.0+ -- docker version 17.03+. -- kubectl version v1.11.3+. -- Access to a Kubernetes v1.11.3+ cluster. +###Prerequisites +-goversionv1.21.0+ +-dockerversion17.03+. +-kubectlversionv1.11.3+. +-AccesstoaKubernetesv1.11.3+cluster. -### To Deploy on the cluster -**Build and push your image to the location specified by `IMG`:** +###ToDeployonthecluster +**Buildandpushyourimagetothelocationspecifiedby`IMG`:** ```sh -make docker-build docker-push IMG=/project-v4-multigroup-with-deploy-image:tag +makedocker-builddocker-pushIMG=/project-v4-multigroup-with-deploy-image: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. +**NOTE:**Thisimageoughttobepublishedinthepersonalregistryyouspecified. +Anditisrequiredtohaveaccesstopulltheimagefromtheworkingenvironment. +Makesureyouhavetheproperpermissiontotheregistryiftheabovecommandsdon’twork. -**Install the CRDs into the cluster:** +**InstalltheCRDsintothecluster:** ```sh -make install +makeinstall ``` -**Deploy the Manager to the cluster with the image specified by `IMG`:** +**DeploytheManagertotheclusterwiththeimagespecifiedby`IMG`:** ```sh -make deploy IMG=/project-v4-multigroup-with-deploy-image:tag +makedeployIMG=/project-v4-multigroup-with-deploy-image:tag ``` -> **NOTE**: If you encounter RBAC errors, you may need to grant yourself cluster-admin -privileges or be logged in as admin. +>**NOTE**:IfyouencounterRBACerrors,youmayneedtograntyourselfcluster-admin +privilegesorbeloggedinasadmin. -**Create instances of your solution** -You can apply the samples (examples) from the config/sample: +**Createinstancesofyoursolution** +Youcanapplythesamples(examples)fromtheconfig/sample: ```sh -kubectl apply -k config/samples/ +kubectlapply-kconfig/samples/ ``` ->**NOTE**: Ensure that the samples has default values to test it out. +>**NOTE**:Ensurethatthesampleshasdefaultvaluestotestitout. -### To Uninstall -**Delete the instances (CRs) from the cluster:** +###ToUninstall +**Deletetheinstances(CRs)fromthecluster:** ```sh -kubectl delete -k config/samples/ +kubectldelete-kconfig/samples/ ``` -**Delete the APIs(CRDs) from the cluster:** +**DeletetheAPIs(CRDs)fromthecluster:** ```sh -make uninstall +makeuninstall ``` -**UnDeploy the controller from the cluster:** +**UnDeploythecontrollerfromthecluster:** ```sh -make undeploy +makeundeploy ``` -## Project Distribution +##ProjectDistribution -Following are the steps to build the installer and distribute this project to users. +Followingarethestepstobuildtheinstalleranddistributethisprojecttousers. -1. Build the installer for the image built and published in the registry: +1.Buildtheinstallerfortheimagebuiltandpublishedintheregistry: ```sh -make build-installer IMG=/project-v4-multigroup-with-deploy-image:tag +makebuild-installerIMG=/project-v4-multigroup-with-deploy-image: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. +NOTE:Themakefiletargetmentionedabovegeneratesan'install.yaml' +fileinthedistdirectory.Thisfilecontainsalltheresourcesbuilt +withKustomize,whicharenecessarytoinstallthisprojectwithout +itsdependencies. -2. Using the installer +2.Usingtheinstaller -Users can just run kubectl apply -f to install the project, i.e.: +Userscanjustrunkubectlapply-ftoinstalltheproject,i.e.: ```sh -kubectl apply -f https://raw.githubusercontent.com//project-v4-multigroup-with-deploy-image//dist/install.yaml +kubectlapply-fhttps://raw.githubusercontent.com//project-v4-multigroup-with-deploy-image//dist/install.yaml ``` -## Contributing -// TODO(user): Add detailed information on how you would like others to contribute to this project +##Contributing +//TODO(user):Adddetailedinformationonhowyouwouldlikeotherstocontributetothisproject -**NOTE:** Run `make help` for more information on all potential `make` targets +**NOTE:**Run`makehelp`formoreinformationonallpotential`make`targets -More information can be found via the [Kubebuilder Documentation](https://book.kubebuilder.io/introduction.html) +Moreinformationcanbefoundviathe[KubebuilderDocumentation](https://book.kubebuilder.io/introduction.html) -## License +##License -Copyright 2024 The Kubernetes authors. +Copyright2024TheKubernetesauthors. -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 +LicensedundertheApacheLicense,Version2.0(the"License"); +youmaynotusethisfileexceptincompliancewiththeLicense. +YoumayobtainacopyoftheLicenseat - http://www.apache.org/licenses/LICENSE-2.0 +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. +Unlessrequiredbyapplicablelaworagreedtoinwriting,software +distributedundertheLicenseisdistributedonan"ASIS"BASIS, +WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied. +SeetheLicenseforthespecificlanguagegoverningpermissionsand +limitationsundertheLicense. diff --git a/testdata/project-v4-multigroup/README.md b/testdata/project-v4-multigroup/README.md index 99be2f2b12b..aae56fc16a8 100644 --- a/testdata/project-v4-multigroup/README.md +++ b/testdata/project-v4-multigroup/README.md @@ -1,114 +1,114 @@ -# project-v4-multigroup -// TODO(user): Add simple overview of use/purpose +#project-v4-multigroup +//TODO(user):Addsimpleoverviewofuse/purpose -## Description -// TODO(user): An in-depth paragraph about your project and overview of use +##Description +//TODO(user):Anin-depthparagraphaboutyourprojectandoverviewofuse -## Getting Started +##GettingStarted -### Prerequisites -- go version v1.21.0+ -- docker version 17.03+. -- kubectl version v1.11.3+. -- Access to a Kubernetes v1.11.3+ cluster. +###Prerequisites +-goversionv1.21.0+ +-dockerversion17.03+. +-kubectlversionv1.11.3+. +-AccesstoaKubernetesv1.11.3+cluster. -### To Deploy on the cluster -**Build and push your image to the location specified by `IMG`:** +###ToDeployonthecluster +**Buildandpushyourimagetothelocationspecifiedby`IMG`:** ```sh -make docker-build docker-push IMG=/project-v4-multigroup:tag +makedocker-builddocker-pushIMG=/project-v4-multigroup: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. +**NOTE:**Thisimageoughttobepublishedinthepersonalregistryyouspecified. +Anditisrequiredtohaveaccesstopulltheimagefromtheworkingenvironment. +Makesureyouhavetheproperpermissiontotheregistryiftheabovecommandsdon’twork. -**Install the CRDs into the cluster:** +**InstalltheCRDsintothecluster:** ```sh -make install +makeinstall ``` -**Deploy the Manager to the cluster with the image specified by `IMG`:** +**DeploytheManagertotheclusterwiththeimagespecifiedby`IMG`:** ```sh -make deploy IMG=/project-v4-multigroup:tag +makedeployIMG=/project-v4-multigroup:tag ``` -> **NOTE**: If you encounter RBAC errors, you may need to grant yourself cluster-admin -privileges or be logged in as admin. +>**NOTE**:IfyouencounterRBACerrors,youmayneedtograntyourselfcluster-admin +privilegesorbeloggedinasadmin. -**Create instances of your solution** -You can apply the samples (examples) from the config/sample: +**Createinstancesofyoursolution** +Youcanapplythesamples(examples)fromtheconfig/sample: ```sh -kubectl apply -k config/samples/ +kubectlapply-kconfig/samples/ ``` ->**NOTE**: Ensure that the samples has default values to test it out. +>**NOTE**:Ensurethatthesampleshasdefaultvaluestotestitout. -### To Uninstall -**Delete the instances (CRs) from the cluster:** +###ToUninstall +**Deletetheinstances(CRs)fromthecluster:** ```sh -kubectl delete -k config/samples/ +kubectldelete-kconfig/samples/ ``` -**Delete the APIs(CRDs) from the cluster:** +**DeletetheAPIs(CRDs)fromthecluster:** ```sh -make uninstall +makeuninstall ``` -**UnDeploy the controller from the cluster:** +**UnDeploythecontrollerfromthecluster:** ```sh -make undeploy +makeundeploy ``` -## Project Distribution +##ProjectDistribution -Following are the steps to build the installer and distribute this project to users. +Followingarethestepstobuildtheinstalleranddistributethisprojecttousers. -1. Build the installer for the image built and published in the registry: +1.Buildtheinstallerfortheimagebuiltandpublishedintheregistry: ```sh -make build-installer IMG=/project-v4-multigroup:tag +makebuild-installerIMG=/project-v4-multigroup: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. +NOTE:Themakefiletargetmentionedabovegeneratesan'install.yaml' +fileinthedistdirectory.Thisfilecontainsalltheresourcesbuilt +withKustomize,whicharenecessarytoinstallthisprojectwithout +itsdependencies. -2. Using the installer +2.Usingtheinstaller -Users can just run kubectl apply -f to install the project, i.e.: +Userscanjustrunkubectlapply-ftoinstalltheproject,i.e.: ```sh -kubectl apply -f https://raw.githubusercontent.com//project-v4-multigroup//dist/install.yaml +kubectlapply-fhttps://raw.githubusercontent.com//project-v4-multigroup//dist/install.yaml ``` -## Contributing -// TODO(user): Add detailed information on how you would like others to contribute to this project +##Contributing +//TODO(user):Adddetailedinformationonhowyouwouldlikeotherstocontributetothisproject -**NOTE:** Run `make help` for more information on all potential `make` targets +**NOTE:**Run`makehelp`formoreinformationonallpotential`make`targets -More information can be found via the [Kubebuilder Documentation](https://book.kubebuilder.io/introduction.html) +Moreinformationcanbefoundviathe[KubebuilderDocumentation](https://book.kubebuilder.io/introduction.html) -## License +##License -Copyright 2024 The Kubernetes authors. +Copyright2024TheKubernetesauthors. -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 +LicensedundertheApacheLicense,Version2.0(the"License"); +youmaynotusethisfileexceptincompliancewiththeLicense. +YoumayobtainacopyoftheLicenseat - http://www.apache.org/licenses/LICENSE-2.0 +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. +Unlessrequiredbyapplicablelaworagreedtoinwriting,software +distributedundertheLicenseisdistributedonan"ASIS"BASIS, +WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied. +SeetheLicenseforthespecificlanguagegoverningpermissionsand +limitationsundertheLicense. diff --git a/testdata/project-v4-with-deploy-image/README.md b/testdata/project-v4-with-deploy-image/README.md index d400311c086..bbadb7d1449 100644 --- a/testdata/project-v4-with-deploy-image/README.md +++ b/testdata/project-v4-with-deploy-image/README.md @@ -1,114 +1,114 @@ -# project-v4-with-deploy-image -// TODO(user): Add simple overview of use/purpose +#project-v4-with-deploy-image +//TODO(user):Addsimpleoverviewofuse/purpose -## Description -// TODO(user): An in-depth paragraph about your project and overview of use +##Description +//TODO(user):Anin-depthparagraphaboutyourprojectandoverviewofuse -## Getting Started +##GettingStarted -### Prerequisites -- go version v1.21.0+ -- docker version 17.03+. -- kubectl version v1.11.3+. -- Access to a Kubernetes v1.11.3+ cluster. +###Prerequisites +-goversionv1.21.0+ +-dockerversion17.03+. +-kubectlversionv1.11.3+. +-AccesstoaKubernetesv1.11.3+cluster. -### To Deploy on the cluster -**Build and push your image to the location specified by `IMG`:** +###ToDeployonthecluster +**Buildandpushyourimagetothelocationspecifiedby`IMG`:** ```sh -make docker-build docker-push IMG=/project-v4-with-deploy-image:tag +makedocker-builddocker-pushIMG=/project-v4-with-deploy-image: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. +**NOTE:**Thisimageoughttobepublishedinthepersonalregistryyouspecified. +Anditisrequiredtohaveaccesstopulltheimagefromtheworkingenvironment. +Makesureyouhavetheproperpermissiontotheregistryiftheabovecommandsdon’twork. -**Install the CRDs into the cluster:** +**InstalltheCRDsintothecluster:** ```sh -make install +makeinstall ``` -**Deploy the Manager to the cluster with the image specified by `IMG`:** +**DeploytheManagertotheclusterwiththeimagespecifiedby`IMG`:** ```sh -make deploy IMG=/project-v4-with-deploy-image:tag +makedeployIMG=/project-v4-with-deploy-image:tag ``` -> **NOTE**: If you encounter RBAC errors, you may need to grant yourself cluster-admin -privileges or be logged in as admin. +>**NOTE**:IfyouencounterRBACerrors,youmayneedtograntyourselfcluster-admin +privilegesorbeloggedinasadmin. -**Create instances of your solution** -You can apply the samples (examples) from the config/sample: +**Createinstancesofyoursolution** +Youcanapplythesamples(examples)fromtheconfig/sample: ```sh -kubectl apply -k config/samples/ +kubectlapply-kconfig/samples/ ``` ->**NOTE**: Ensure that the samples has default values to test it out. +>**NOTE**:Ensurethatthesampleshasdefaultvaluestotestitout. -### To Uninstall -**Delete the instances (CRs) from the cluster:** +###ToUninstall +**Deletetheinstances(CRs)fromthecluster:** ```sh -kubectl delete -k config/samples/ +kubectldelete-kconfig/samples/ ``` -**Delete the APIs(CRDs) from the cluster:** +**DeletetheAPIs(CRDs)fromthecluster:** ```sh -make uninstall +makeuninstall ``` -**UnDeploy the controller from the cluster:** +**UnDeploythecontrollerfromthecluster:** ```sh -make undeploy +makeundeploy ``` -## Project Distribution +##ProjectDistribution -Following are the steps to build the installer and distribute this project to users. +Followingarethestepstobuildtheinstalleranddistributethisprojecttousers. -1. Build the installer for the image built and published in the registry: +1.Buildtheinstallerfortheimagebuiltandpublishedintheregistry: ```sh -make build-installer IMG=/project-v4-with-deploy-image:tag +makebuild-installerIMG=/project-v4-with-deploy-image: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. +NOTE:Themakefiletargetmentionedabovegeneratesan'install.yaml' +fileinthedistdirectory.Thisfilecontainsalltheresourcesbuilt +withKustomize,whicharenecessarytoinstallthisprojectwithout +itsdependencies. -2. Using the installer +2.Usingtheinstaller -Users can just run kubectl apply -f to install the project, i.e.: +Userscanjustrunkubectlapply-ftoinstalltheproject,i.e.: ```sh -kubectl apply -f https://raw.githubusercontent.com//project-v4-with-deploy-image//dist/install.yaml +kubectlapply-fhttps://raw.githubusercontent.com//project-v4-with-deploy-image//dist/install.yaml ``` -## Contributing -// TODO(user): Add detailed information on how you would like others to contribute to this project +##Contributing +//TODO(user):Adddetailedinformationonhowyouwouldlikeotherstocontributetothisproject -**NOTE:** Run `make help` for more information on all potential `make` targets +**NOTE:**Run`makehelp`formoreinformationonallpotential`make`targets -More information can be found via the [Kubebuilder Documentation](https://book.kubebuilder.io/introduction.html) +Moreinformationcanbefoundviathe[KubebuilderDocumentation](https://book.kubebuilder.io/introduction.html) -## License +##License -Copyright 2024 The Kubernetes authors. +Copyright2024TheKubernetesauthors. -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 +LicensedundertheApacheLicense,Version2.0(the"License"); +youmaynotusethisfileexceptincompliancewiththeLicense. +YoumayobtainacopyoftheLicenseat - http://www.apache.org/licenses/LICENSE-2.0 +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. +Unlessrequiredbyapplicablelaworagreedtoinwriting,software +distributedundertheLicenseisdistributedonan"ASIS"BASIS, +WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied. +SeetheLicenseforthespecificlanguagegoverningpermissionsand +limitationsundertheLicense. diff --git a/testdata/project-v4-with-grafana/README.md b/testdata/project-v4-with-grafana/README.md index 96ea5aefcd6..ca7dcb7e904 100644 --- a/testdata/project-v4-with-grafana/README.md +++ b/testdata/project-v4-with-grafana/README.md @@ -1,114 +1,114 @@ -# project-v4-with-grafana -// TODO(user): Add simple overview of use/purpose +#project-v4-with-grafana +//TODO(user):Addsimpleoverviewofuse/purpose -## Description -// TODO(user): An in-depth paragraph about your project and overview of use +##Description +//TODO(user):Anin-depthparagraphaboutyourprojectandoverviewofuse -## Getting Started +##GettingStarted -### Prerequisites -- go version v1.21.0+ -- docker version 17.03+. -- kubectl version v1.11.3+. -- Access to a Kubernetes v1.11.3+ cluster. +###Prerequisites +-goversionv1.21.0+ +-dockerversion17.03+. +-kubectlversionv1.11.3+. +-AccesstoaKubernetesv1.11.3+cluster. -### To Deploy on the cluster -**Build and push your image to the location specified by `IMG`:** +###ToDeployonthecluster +**Buildandpushyourimagetothelocationspecifiedby`IMG`:** ```sh -make docker-build docker-push IMG=/project-v4-with-grafana:tag +makedocker-builddocker-pushIMG=/project-v4-with-grafana: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. +**NOTE:**Thisimageoughttobepublishedinthepersonalregistryyouspecified. +Anditisrequiredtohaveaccesstopulltheimagefromtheworkingenvironment. +Makesureyouhavetheproperpermissiontotheregistryiftheabovecommandsdon’twork. -**Install the CRDs into the cluster:** +**InstalltheCRDsintothecluster:** ```sh -make install +makeinstall ``` -**Deploy the Manager to the cluster with the image specified by `IMG`:** +**DeploytheManagertotheclusterwiththeimagespecifiedby`IMG`:** ```sh -make deploy IMG=/project-v4-with-grafana:tag +makedeployIMG=/project-v4-with-grafana:tag ``` -> **NOTE**: If you encounter RBAC errors, you may need to grant yourself cluster-admin -privileges or be logged in as admin. +>**NOTE**:IfyouencounterRBACerrors,youmayneedtograntyourselfcluster-admin +privilegesorbeloggedinasadmin. -**Create instances of your solution** -You can apply the samples (examples) from the config/sample: +**Createinstancesofyoursolution** +Youcanapplythesamples(examples)fromtheconfig/sample: ```sh -kubectl apply -k config/samples/ +kubectlapply-kconfig/samples/ ``` ->**NOTE**: Ensure that the samples has default values to test it out. +>**NOTE**:Ensurethatthesampleshasdefaultvaluestotestitout. -### To Uninstall -**Delete the instances (CRs) from the cluster:** +###ToUninstall +**Deletetheinstances(CRs)fromthecluster:** ```sh -kubectl delete -k config/samples/ +kubectldelete-kconfig/samples/ ``` -**Delete the APIs(CRDs) from the cluster:** +**DeletetheAPIs(CRDs)fromthecluster:** ```sh -make uninstall +makeuninstall ``` -**UnDeploy the controller from the cluster:** +**UnDeploythecontrollerfromthecluster:** ```sh -make undeploy +makeundeploy ``` -## Project Distribution +##ProjectDistribution -Following are the steps to build the installer and distribute this project to users. +Followingarethestepstobuildtheinstalleranddistributethisprojecttousers. -1. Build the installer for the image built and published in the registry: +1.Buildtheinstallerfortheimagebuiltandpublishedintheregistry: ```sh -make build-installer IMG=/project-v4-with-grafana:tag +makebuild-installerIMG=/project-v4-with-grafana: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. +NOTE:Themakefiletargetmentionedabovegeneratesan'install.yaml' +fileinthedistdirectory.Thisfilecontainsalltheresourcesbuilt +withKustomize,whicharenecessarytoinstallthisprojectwithout +itsdependencies. -2. Using the installer +2.Usingtheinstaller -Users can just run kubectl apply -f to install the project, i.e.: +Userscanjustrunkubectlapply-ftoinstalltheproject,i.e.: ```sh -kubectl apply -f https://raw.githubusercontent.com//project-v4-with-grafana//dist/install.yaml +kubectlapply-fhttps://raw.githubusercontent.com//project-v4-with-grafana//dist/install.yaml ``` -## Contributing -// TODO(user): Add detailed information on how you would like others to contribute to this project +##Contributing +//TODO(user):Adddetailedinformationonhowyouwouldlikeotherstocontributetothisproject -**NOTE:** Run `make help` for more information on all potential `make` targets +**NOTE:**Run`makehelp`formoreinformationonallpotential`make`targets -More information can be found via the [Kubebuilder Documentation](https://book.kubebuilder.io/introduction.html) +Moreinformationcanbefoundviathe[KubebuilderDocumentation](https://book.kubebuilder.io/introduction.html) -## License +##License -Copyright 2024 The Kubernetes authors. +Copyright2024TheKubernetesauthors. -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 +LicensedundertheApacheLicense,Version2.0(the"License"); +youmaynotusethisfileexceptincompliancewiththeLicense. +YoumayobtainacopyoftheLicenseat - http://www.apache.org/licenses/LICENSE-2.0 +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. +Unlessrequiredbyapplicablelaworagreedtoinwriting,software +distributedundertheLicenseisdistributedonan"ASIS"BASIS, +WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied. +SeetheLicenseforthespecificlanguagegoverningpermissionsand +limitationsundertheLicense. diff --git a/testdata/project-v4/README.md b/testdata/project-v4/README.md index 390e8a64031..84b38fc0964 100644 --- a/testdata/project-v4/README.md +++ b/testdata/project-v4/README.md @@ -1,114 +1,114 @@ -# project-v4 -// TODO(user): Add simple overview of use/purpose +#project-v4 +//TODO(user):Addsimpleoverviewofuse/purpose -## Description -// TODO(user): An in-depth paragraph about your project and overview of use +##Description +//TODO(user):Anin-depthparagraphaboutyourprojectandoverviewofuse -## Getting Started +##GettingStarted -### Prerequisites -- go version v1.21.0+ -- docker version 17.03+. -- kubectl version v1.11.3+. -- Access to a Kubernetes v1.11.3+ cluster. +###Prerequisites +-goversionv1.21.0+ +-dockerversion17.03+. +-kubectlversionv1.11.3+. +-AccesstoaKubernetesv1.11.3+cluster. -### To Deploy on the cluster -**Build and push your image to the location specified by `IMG`:** +###ToDeployonthecluster +**Buildandpushyourimagetothelocationspecifiedby`IMG`:** ```sh -make docker-build docker-push IMG=/project-v4:tag +makedocker-builddocker-pushIMG=/project-v4: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. +**NOTE:**Thisimageoughttobepublishedinthepersonalregistryyouspecified. +Anditisrequiredtohaveaccesstopulltheimagefromtheworkingenvironment. +Makesureyouhavetheproperpermissiontotheregistryiftheabovecommandsdon’twork. -**Install the CRDs into the cluster:** +**InstalltheCRDsintothecluster:** ```sh -make install +makeinstall ``` -**Deploy the Manager to the cluster with the image specified by `IMG`:** +**DeploytheManagertotheclusterwiththeimagespecifiedby`IMG`:** ```sh -make deploy IMG=/project-v4:tag +makedeployIMG=/project-v4:tag ``` -> **NOTE**: If you encounter RBAC errors, you may need to grant yourself cluster-admin -privileges or be logged in as admin. +>**NOTE**:IfyouencounterRBACerrors,youmayneedtograntyourselfcluster-admin +privilegesorbeloggedinasadmin. -**Create instances of your solution** -You can apply the samples (examples) from the config/sample: +**Createinstancesofyoursolution** +Youcanapplythesamples(examples)fromtheconfig/sample: ```sh -kubectl apply -k config/samples/ +kubectlapply-kconfig/samples/ ``` ->**NOTE**: Ensure that the samples has default values to test it out. +>**NOTE**:Ensurethatthesampleshasdefaultvaluestotestitout. -### To Uninstall -**Delete the instances (CRs) from the cluster:** +###ToUninstall +**Deletetheinstances(CRs)fromthecluster:** ```sh -kubectl delete -k config/samples/ +kubectldelete-kconfig/samples/ ``` -**Delete the APIs(CRDs) from the cluster:** +**DeletetheAPIs(CRDs)fromthecluster:** ```sh -make uninstall +makeuninstall ``` -**UnDeploy the controller from the cluster:** +**UnDeploythecontrollerfromthecluster:** ```sh -make undeploy +makeundeploy ``` -## Project Distribution +##ProjectDistribution -Following are the steps to build the installer and distribute this project to users. +Followingarethestepstobuildtheinstalleranddistributethisprojecttousers. -1. Build the installer for the image built and published in the registry: +1.Buildtheinstallerfortheimagebuiltandpublishedintheregistry: ```sh -make build-installer IMG=/project-v4:tag +makebuild-installerIMG=/project-v4: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. +NOTE:Themakefiletargetmentionedabovegeneratesan'install.yaml' +fileinthedistdirectory.Thisfilecontainsalltheresourcesbuilt +withKustomize,whicharenecessarytoinstallthisprojectwithout +itsdependencies. -2. Using the installer +2.Usingtheinstaller -Users can just run kubectl apply -f to install the project, i.e.: +Userscanjustrunkubectlapply-ftoinstalltheproject,i.e.: ```sh -kubectl apply -f https://raw.githubusercontent.com//project-v4//dist/install.yaml +kubectlapply-fhttps://raw.githubusercontent.com//project-v4//dist/install.yaml ``` -## Contributing -// TODO(user): Add detailed information on how you would like others to contribute to this project +##Contributing +//TODO(user):Adddetailedinformationonhowyouwouldlikeotherstocontributetothisproject -**NOTE:** Run `make help` for more information on all potential `make` targets +**NOTE:**Run`makehelp`formoreinformationonallpotential`make`targets -More information can be found via the [Kubebuilder Documentation](https://book.kubebuilder.io/introduction.html) +Moreinformationcanbefoundviathe[KubebuilderDocumentation](https://book.kubebuilder.io/introduction.html) -## License +##License -Copyright 2024 The Kubernetes authors. +Copyright2024TheKubernetesauthors. -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 +LicensedundertheApacheLicense,Version2.0(the"License"); +youmaynotusethisfileexceptincompliancewiththeLicense. +YoumayobtainacopyoftheLicenseat - http://www.apache.org/licenses/LICENSE-2.0 +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. +Unlessrequiredbyapplicablelaworagreedtoinwriting,software +distributedundertheLicenseisdistributedonan"ASIS"BASIS, +WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied. +SeetheLicenseforthespecificlanguagegoverningpermissionsand +limitationsundertheLicense.