From f1c2f37197a5b05e172fe88d12f3d3a4aa8c4366 Mon Sep 17 00:00:00 2001 From: Camila Macedo Date: Mon, 1 Jun 2020 12:53:02 +0100 Subject: [PATCH] feat: add plugin v3 to fix controller typo alias and improve its logs (only V3) --- cmd/main.go | 3 + docs/book/src/quick-start.md | 2 +- docs/testing/integration.md | 4 +- docs/using_an_external_type.md | 2 +- go.mod | 1 - go.sum | 2 - internal/config/config_suite_test.go | 29 -- pkg/plugin/v2/plugin.go | 2 +- pkg/plugin/v2/scaffolds/api.go | 8 +- pkg/plugin/v2/scaffolds/init.go | 12 +- .../{internal => }/templates/authproxyrole.go | 0 .../templates/authproxyrolebinding.go | 0 .../{internal => }/templates/boilerplate.go | 0 .../templates/certmanager/certificate.go | 0 .../templates/certmanager/kustomize.go | 0 .../templates/certmanager/kustomizeconfig.go | 0 .../templates/controller/controller.go | 0 .../controller/controller_suitetest.go | 0 .../templates/crd/enablecainjection_patch.go | 0 .../templates/crd/enablewebhook_patch.go | 0 .../templates/crd/kustomization.go | 0 .../templates/crd/kustomizeconfig.go | 0 .../templates/crd_editor_rbac.go | 0 .../{internal => }/templates/crd_sample.go | 0 .../templates/crd_viewer_rbac.go | 0 .../{internal => }/templates/dockerfile.go | 0 .../{internal => }/templates/gitignore.go | 0 .../{internal => }/templates/gomod.go | 0 .../{internal => }/templates/group.go | 0 .../{internal => }/templates/kustomize.go | 0 .../templates/leaderelectionrole.go | 0 .../templates/leaderelectionrolebinding.go | 0 .../{internal => }/templates/main.go | 6 - .../{internal => }/templates/makefile.go | 0 .../templates/manager/config.go | 0 .../templates/manager/kustomization.go | 0 .../templates/metricsauth/auth_proxy_patch.go | 0 .../templates/metricsauth/authproxyservice.go | 0 .../metricsauth/clientclusterrole.go | 0 .../templates/mgrrolebinding.go | 0 .../templates/prometheus/kustomize.go | 0 .../templates/prometheus/monitor.go | 0 .../{internal => }/templates/rbac.go | 0 .../{internal => }/templates/types.go | 0 .../webhook/enablecainection_patch.go | 0 .../templates/webhook/kustomization.go | 0 .../templates/webhook/kustomizeconfig.go | 0 .../templates/webhook/service.go | 0 .../templates/webhook/webhook.go | 0 .../templates/webhook_manager_patch.go | 0 pkg/plugin/v2/scaffolds/webhook.go | 6 +- pkg/plugin/v3/api.go | 204 ++++++++++++++ pkg/plugin/v3/init.go | 166 ++++++++++++ pkg/plugin/v3/plugin.go | 49 ++++ pkg/plugin/v3/scaffolds/api.go | 136 ++++++++++ pkg/plugin/v3/scaffolds/templates/main.go | 253 ++++++++++++++++++ pkg/plugin/v3/scaffolds/webhook.go | 96 +++++++ pkg/plugin/v3/webhook.go | 115 ++++++++ testdata/project-v3-addon/PROJECT | 2 +- testdata/project-v3-multigroup/PROJECT | 2 +- testdata/project-v3-multigroup/main.go | 36 +-- testdata/project-v3/PROJECT | 2 +- 62 files changed, 1061 insertions(+), 77 deletions(-) delete mode 100644 internal/config/config_suite_test.go rename pkg/plugin/v2/scaffolds/{internal => }/templates/authproxyrole.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/authproxyrolebinding.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/boilerplate.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/certmanager/certificate.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/certmanager/kustomize.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/certmanager/kustomizeconfig.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/controller/controller.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/controller/controller_suitetest.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/crd/enablecainjection_patch.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/crd/enablewebhook_patch.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/crd/kustomization.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/crd/kustomizeconfig.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/crd_editor_rbac.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/crd_sample.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/crd_viewer_rbac.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/dockerfile.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/gitignore.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/gomod.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/group.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/kustomize.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/leaderelectionrole.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/leaderelectionrolebinding.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/main.go (92%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/makefile.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/manager/config.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/manager/kustomization.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/metricsauth/auth_proxy_patch.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/metricsauth/authproxyservice.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/metricsauth/clientclusterrole.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/mgrrolebinding.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/prometheus/kustomize.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/prometheus/monitor.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/rbac.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/types.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/webhook/enablecainection_patch.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/webhook/kustomization.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/webhook/kustomizeconfig.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/webhook/service.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/webhook/webhook.go (100%) rename pkg/plugin/v2/scaffolds/{internal => }/templates/webhook_manager_patch.go (100%) create mode 100644 pkg/plugin/v3/api.go create mode 100644 pkg/plugin/v3/init.go create mode 100644 pkg/plugin/v3/plugin.go create mode 100644 pkg/plugin/v3/scaffolds/api.go create mode 100644 pkg/plugin/v3/scaffolds/templates/main.go create mode 100644 pkg/plugin/v3/scaffolds/webhook.go create mode 100644 pkg/plugin/v3/webhook.go diff --git a/cmd/main.go b/cmd/main.go index fbb114185e6..dd0388c4254 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -22,15 +22,18 @@ import ( "sigs.k8s.io/kubebuilder/cmd/version" "sigs.k8s.io/kubebuilder/pkg/cli" pluginv2 "sigs.k8s.io/kubebuilder/pkg/plugin/v2" + pluginv3 "sigs.k8s.io/kubebuilder/pkg/plugin/v3" ) func main() { c, err := cli.New( cli.WithPlugins( &pluginv2.Plugin{}, + &pluginv3.Plugin{}, ), cli.WithDefaultPlugins( &pluginv2.Plugin{}, + &pluginv3.Plugin{}, ), cli.WithExtraCommands( newEditCmd(), diff --git a/docs/book/src/quick-start.md b/docs/book/src/quick-start.md index d5c1c13719c..b4586890169 100644 --- a/docs/book/src/quick-start.md +++ b/docs/book/src/quick-start.md @@ -87,7 +87,7 @@ kubebuilder create api --group webapp --version v1 --kind Guestbook

Press Options

If you press `y` for Create Resource [y/n] and for Create Controller [y/n] then this will create the files `api/v1/guestbook_types.go` where the API is defined -and the `controller/guestbook_controller.go` where the reconciliation business logic is implemented for this Kind(CRD). +and the `controllers/guestbook_controller.go` where the reconciliation business logic is implemented for this Kind(CRD). diff --git a/docs/testing/integration.md b/docs/testing/integration.md index 300066fd0dc..1be29a1931e 100644 --- a/docs/testing/integration.md +++ b/docs/testing/integration.md @@ -4,7 +4,7 @@ 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` -For example, there is a controller watches *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/controller/parent/parent_controller_test.go`: +For example, there is a controller watches *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 `controllers/parent/parent_controller_test.go`: ``` package parent @@ -79,4 +79,4 @@ func TestReconcile(t *testing.T) { The manager is started as part of the test itself (`StartTestManager` function). -Both functions are located in `pkg/controller/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. +Both functions are located in `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. diff --git a/docs/using_an_external_type.md b/docs/using_an_external_type.md index 9c36acaf334..13f0044d500 100644 --- a/docs/using_an_external_type.md +++ b/docs/using_an_external_type.md @@ -105,7 +105,7 @@ dep ensure --add Edit the `CRDDirectoryPaths` in your test suite by appending the path to their CRDs: -file pkg/controller/my_kind_controller_suite_test.go +file pkg/controllers/my_kind_controller_suite_test.go ``` var cfg *rest.Config diff --git a/go.mod b/go.mod index 8c59c2381a7..43a9f7fdbfe 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,6 @@ module sigs.k8s.io/kubebuilder go 1.13 require ( - github.com/blang/semver v3.5.1+incompatible github.com/gobuffalo/flect v0.2.1 github.com/onsi/ginkgo v1.12.0 github.com/onsi/gomega v1.9.0 diff --git a/go.sum b/go.sum index 2428bcf31a9..1803d356506 100644 --- a/go.sum +++ b/go.sum @@ -6,8 +6,6 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= -github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= diff --git a/internal/config/config_suite_test.go b/internal/config/config_suite_test.go deleted file mode 100644 index fffe2f8bb2f..00000000000 --- a/internal/config/config_suite_test.go +++ /dev/null @@ -1,29 +0,0 @@ -/* -Copyright 2020 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. -*/ - -package config - -import ( - "testing" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -func TestCLI(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Config Suite") -} diff --git a/pkg/plugin/v2/plugin.go b/pkg/plugin/v2/plugin.go index 3eb7a3bcace..a74dc658b79 100644 --- a/pkg/plugin/v2/plugin.go +++ b/pkg/plugin/v2/plugin.go @@ -24,7 +24,7 @@ import ( const pluginName = "go" + plugin.DefaultNameQualifier var ( - supportedProjectVersions = []string{config.Version2, config.Version3Alpha} + supportedProjectVersions = []string{config.Version2} pluginVersion = plugin.Version{Number: 2} ) diff --git a/pkg/plugin/v2/scaffolds/api.go b/pkg/plugin/v2/scaffolds/api.go index bd9da07f861..8e382740b84 100644 --- a/pkg/plugin/v2/scaffolds/api.go +++ b/pkg/plugin/v2/scaffolds/api.go @@ -24,9 +24,9 @@ import ( "sigs.k8s.io/kubebuilder/pkg/model/resource" "sigs.k8s.io/kubebuilder/pkg/plugin/internal/machinery" "sigs.k8s.io/kubebuilder/pkg/plugin/scaffold" - "sigs.k8s.io/kubebuilder/pkg/plugin/v2/scaffolds/internal/templates" - "sigs.k8s.io/kubebuilder/pkg/plugin/v2/scaffolds/internal/templates/controller" - "sigs.k8s.io/kubebuilder/pkg/plugin/v2/scaffolds/internal/templates/crd" + "sigs.k8s.io/kubebuilder/pkg/plugin/v2/scaffolds/templates" + "sigs.k8s.io/kubebuilder/pkg/plugin/v2/scaffolds/templates/controller" + "sigs.k8s.io/kubebuilder/pkg/plugin/v2/scaffolds/templates/crd" ) // (used only to gen api with --pattern=addon) @@ -72,7 +72,7 @@ func (s *apiScaffolder) Scaffold() error { fmt.Println("Writing scaffold for you to edit...") switch { - case s.config.IsV2(), s.config.IsV3(): + case s.config.IsV2(): return s.scaffold() default: return fmt.Errorf("unknown project version %v", s.config.Version) diff --git a/pkg/plugin/v2/scaffolds/init.go b/pkg/plugin/v2/scaffolds/init.go index 0df668111b2..56dd11e07bd 100644 --- a/pkg/plugin/v2/scaffolds/init.go +++ b/pkg/plugin/v2/scaffolds/init.go @@ -25,12 +25,12 @@ import ( "sigs.k8s.io/kubebuilder/pkg/model/config" "sigs.k8s.io/kubebuilder/pkg/plugin/internal/machinery" "sigs.k8s.io/kubebuilder/pkg/plugin/scaffold" - "sigs.k8s.io/kubebuilder/pkg/plugin/v2/scaffolds/internal/templates" - "sigs.k8s.io/kubebuilder/pkg/plugin/v2/scaffolds/internal/templates/certmanager" - "sigs.k8s.io/kubebuilder/pkg/plugin/v2/scaffolds/internal/templates/manager" - "sigs.k8s.io/kubebuilder/pkg/plugin/v2/scaffolds/internal/templates/metricsauth" - "sigs.k8s.io/kubebuilder/pkg/plugin/v2/scaffolds/internal/templates/prometheus" - "sigs.k8s.io/kubebuilder/pkg/plugin/v2/scaffolds/internal/templates/webhook" + "sigs.k8s.io/kubebuilder/pkg/plugin/v2/scaffolds/templates" + "sigs.k8s.io/kubebuilder/pkg/plugin/v2/scaffolds/templates/certmanager" + "sigs.k8s.io/kubebuilder/pkg/plugin/v2/scaffolds/templates/manager" + "sigs.k8s.io/kubebuilder/pkg/plugin/v2/scaffolds/templates/metricsauth" + "sigs.k8s.io/kubebuilder/pkg/plugin/v2/scaffolds/templates/prometheus" + "sigs.k8s.io/kubebuilder/pkg/plugin/v2/scaffolds/templates/webhook" ) const ( diff --git a/pkg/plugin/v2/scaffolds/internal/templates/authproxyrole.go b/pkg/plugin/v2/scaffolds/templates/authproxyrole.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/authproxyrole.go rename to pkg/plugin/v2/scaffolds/templates/authproxyrole.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/authproxyrolebinding.go b/pkg/plugin/v2/scaffolds/templates/authproxyrolebinding.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/authproxyrolebinding.go rename to pkg/plugin/v2/scaffolds/templates/authproxyrolebinding.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/boilerplate.go b/pkg/plugin/v2/scaffolds/templates/boilerplate.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/boilerplate.go rename to pkg/plugin/v2/scaffolds/templates/boilerplate.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/certmanager/certificate.go b/pkg/plugin/v2/scaffolds/templates/certmanager/certificate.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/certmanager/certificate.go rename to pkg/plugin/v2/scaffolds/templates/certmanager/certificate.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/certmanager/kustomize.go b/pkg/plugin/v2/scaffolds/templates/certmanager/kustomize.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/certmanager/kustomize.go rename to pkg/plugin/v2/scaffolds/templates/certmanager/kustomize.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/certmanager/kustomizeconfig.go b/pkg/plugin/v2/scaffolds/templates/certmanager/kustomizeconfig.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/certmanager/kustomizeconfig.go rename to pkg/plugin/v2/scaffolds/templates/certmanager/kustomizeconfig.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/controller/controller.go b/pkg/plugin/v2/scaffolds/templates/controller/controller.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/controller/controller.go rename to pkg/plugin/v2/scaffolds/templates/controller/controller.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/controller/controller_suitetest.go b/pkg/plugin/v2/scaffolds/templates/controller/controller_suitetest.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/controller/controller_suitetest.go rename to pkg/plugin/v2/scaffolds/templates/controller/controller_suitetest.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/crd/enablecainjection_patch.go b/pkg/plugin/v2/scaffolds/templates/crd/enablecainjection_patch.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/crd/enablecainjection_patch.go rename to pkg/plugin/v2/scaffolds/templates/crd/enablecainjection_patch.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/crd/enablewebhook_patch.go b/pkg/plugin/v2/scaffolds/templates/crd/enablewebhook_patch.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/crd/enablewebhook_patch.go rename to pkg/plugin/v2/scaffolds/templates/crd/enablewebhook_patch.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/crd/kustomization.go b/pkg/plugin/v2/scaffolds/templates/crd/kustomization.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/crd/kustomization.go rename to pkg/plugin/v2/scaffolds/templates/crd/kustomization.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/crd/kustomizeconfig.go b/pkg/plugin/v2/scaffolds/templates/crd/kustomizeconfig.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/crd/kustomizeconfig.go rename to pkg/plugin/v2/scaffolds/templates/crd/kustomizeconfig.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/crd_editor_rbac.go b/pkg/plugin/v2/scaffolds/templates/crd_editor_rbac.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/crd_editor_rbac.go rename to pkg/plugin/v2/scaffolds/templates/crd_editor_rbac.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/crd_sample.go b/pkg/plugin/v2/scaffolds/templates/crd_sample.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/crd_sample.go rename to pkg/plugin/v2/scaffolds/templates/crd_sample.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/crd_viewer_rbac.go b/pkg/plugin/v2/scaffolds/templates/crd_viewer_rbac.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/crd_viewer_rbac.go rename to pkg/plugin/v2/scaffolds/templates/crd_viewer_rbac.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/dockerfile.go b/pkg/plugin/v2/scaffolds/templates/dockerfile.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/dockerfile.go rename to pkg/plugin/v2/scaffolds/templates/dockerfile.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/gitignore.go b/pkg/plugin/v2/scaffolds/templates/gitignore.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/gitignore.go rename to pkg/plugin/v2/scaffolds/templates/gitignore.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/gomod.go b/pkg/plugin/v2/scaffolds/templates/gomod.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/gomod.go rename to pkg/plugin/v2/scaffolds/templates/gomod.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/group.go b/pkg/plugin/v2/scaffolds/templates/group.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/group.go rename to pkg/plugin/v2/scaffolds/templates/group.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/kustomize.go b/pkg/plugin/v2/scaffolds/templates/kustomize.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/kustomize.go rename to pkg/plugin/v2/scaffolds/templates/kustomize.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/leaderelectionrole.go b/pkg/plugin/v2/scaffolds/templates/leaderelectionrole.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/leaderelectionrole.go rename to pkg/plugin/v2/scaffolds/templates/leaderelectionrole.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/leaderelectionrolebinding.go b/pkg/plugin/v2/scaffolds/templates/leaderelectionrolebinding.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/leaderelectionrolebinding.go rename to pkg/plugin/v2/scaffolds/templates/leaderelectionrolebinding.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/main.go b/pkg/plugin/v2/scaffolds/templates/main.go similarity index 92% rename from pkg/plugin/v2/scaffolds/internal/templates/main.go rename to pkg/plugin/v2/scaffolds/templates/main.go index 6443e5d4630..aed461118e6 100644 --- a/pkg/plugin/v2/scaffolds/internal/templates/main.go +++ b/pkg/plugin/v2/scaffolds/templates/main.go @@ -108,9 +108,6 @@ const ( ` controllerImportCodeFragment = `"%s/controllers" ` - // TODO(v3): `&%scontrollers` should be used instead of `&%scontroller` as there may be multiple - // controller for different Kinds in the same group. However, this is a backwards incompatible - // change, and thus should be done for next project version. multiGroupControllerImportCodeFragment = `%scontroller "%s/controllers/%s" ` addschemeCodeFragment = `utilruntime.Must(%s.AddToScheme(scheme)) @@ -124,9 +121,6 @@ const ( os.Exit(1) } ` - // TODO(v3): loggers for the same Kind controllers from different groups use the same logger. - // `.WithName("controllers").WithName(GROUP).WithName(KIND)` should be used instead. However, - // this is a backwards incompatible change, and thus should be done for next project version. multiGroupReconcilerSetupCodeFragment = `if err = (&%scontroller.%sReconciler{ Client: mgr.GetClient(), Log: ctrl.Log.WithName("controllers").WithName("%s"), diff --git a/pkg/plugin/v2/scaffolds/internal/templates/makefile.go b/pkg/plugin/v2/scaffolds/templates/makefile.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/makefile.go rename to pkg/plugin/v2/scaffolds/templates/makefile.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/manager/config.go b/pkg/plugin/v2/scaffolds/templates/manager/config.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/manager/config.go rename to pkg/plugin/v2/scaffolds/templates/manager/config.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/manager/kustomization.go b/pkg/plugin/v2/scaffolds/templates/manager/kustomization.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/manager/kustomization.go rename to pkg/plugin/v2/scaffolds/templates/manager/kustomization.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/metricsauth/auth_proxy_patch.go b/pkg/plugin/v2/scaffolds/templates/metricsauth/auth_proxy_patch.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/metricsauth/auth_proxy_patch.go rename to pkg/plugin/v2/scaffolds/templates/metricsauth/auth_proxy_patch.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/metricsauth/authproxyservice.go b/pkg/plugin/v2/scaffolds/templates/metricsauth/authproxyservice.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/metricsauth/authproxyservice.go rename to pkg/plugin/v2/scaffolds/templates/metricsauth/authproxyservice.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/metricsauth/clientclusterrole.go b/pkg/plugin/v2/scaffolds/templates/metricsauth/clientclusterrole.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/metricsauth/clientclusterrole.go rename to pkg/plugin/v2/scaffolds/templates/metricsauth/clientclusterrole.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/mgrrolebinding.go b/pkg/plugin/v2/scaffolds/templates/mgrrolebinding.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/mgrrolebinding.go rename to pkg/plugin/v2/scaffolds/templates/mgrrolebinding.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/prometheus/kustomize.go b/pkg/plugin/v2/scaffolds/templates/prometheus/kustomize.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/prometheus/kustomize.go rename to pkg/plugin/v2/scaffolds/templates/prometheus/kustomize.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/prometheus/monitor.go b/pkg/plugin/v2/scaffolds/templates/prometheus/monitor.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/prometheus/monitor.go rename to pkg/plugin/v2/scaffolds/templates/prometheus/monitor.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/rbac.go b/pkg/plugin/v2/scaffolds/templates/rbac.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/rbac.go rename to pkg/plugin/v2/scaffolds/templates/rbac.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/types.go b/pkg/plugin/v2/scaffolds/templates/types.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/types.go rename to pkg/plugin/v2/scaffolds/templates/types.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/webhook/enablecainection_patch.go b/pkg/plugin/v2/scaffolds/templates/webhook/enablecainection_patch.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/webhook/enablecainection_patch.go rename to pkg/plugin/v2/scaffolds/templates/webhook/enablecainection_patch.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/webhook/kustomization.go b/pkg/plugin/v2/scaffolds/templates/webhook/kustomization.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/webhook/kustomization.go rename to pkg/plugin/v2/scaffolds/templates/webhook/kustomization.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/webhook/kustomizeconfig.go b/pkg/plugin/v2/scaffolds/templates/webhook/kustomizeconfig.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/webhook/kustomizeconfig.go rename to pkg/plugin/v2/scaffolds/templates/webhook/kustomizeconfig.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/webhook/service.go b/pkg/plugin/v2/scaffolds/templates/webhook/service.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/webhook/service.go rename to pkg/plugin/v2/scaffolds/templates/webhook/service.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/webhook/webhook.go b/pkg/plugin/v2/scaffolds/templates/webhook/webhook.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/webhook/webhook.go rename to pkg/plugin/v2/scaffolds/templates/webhook/webhook.go diff --git a/pkg/plugin/v2/scaffolds/internal/templates/webhook_manager_patch.go b/pkg/plugin/v2/scaffolds/templates/webhook_manager_patch.go similarity index 100% rename from pkg/plugin/v2/scaffolds/internal/templates/webhook_manager_patch.go rename to pkg/plugin/v2/scaffolds/templates/webhook_manager_patch.go diff --git a/pkg/plugin/v2/scaffolds/webhook.go b/pkg/plugin/v2/scaffolds/webhook.go index fab3385a76e..9b27a070818 100644 --- a/pkg/plugin/v2/scaffolds/webhook.go +++ b/pkg/plugin/v2/scaffolds/webhook.go @@ -24,8 +24,8 @@ import ( "sigs.k8s.io/kubebuilder/pkg/model/resource" "sigs.k8s.io/kubebuilder/pkg/plugin/internal/machinery" "sigs.k8s.io/kubebuilder/pkg/plugin/scaffold" - "sigs.k8s.io/kubebuilder/pkg/plugin/v2/scaffolds/internal/templates" - "sigs.k8s.io/kubebuilder/pkg/plugin/v2/scaffolds/internal/templates/webhook" + "sigs.k8s.io/kubebuilder/pkg/plugin/v2/scaffolds/templates" + "sigs.k8s.io/kubebuilder/pkg/plugin/v2/scaffolds/templates/webhook" ) var _ scaffold.Scaffolder = &webhookScaffolder{} @@ -63,7 +63,7 @@ func (s *webhookScaffolder) Scaffold() error { fmt.Println("Writing scaffold for you to edit...") switch { - case s.config.IsV2(), s.config.IsV3(): + case s.config.IsV2(): return s.scaffold() default: return fmt.Errorf("unknown project version %v", s.config.Version) diff --git a/pkg/plugin/v3/api.go b/pkg/plugin/v3/api.go new file mode 100644 index 00000000000..103fc914b35 --- /dev/null +++ b/pkg/plugin/v3/api.go @@ -0,0 +1,204 @@ +/* +Copyright 2020 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. +*/ + +package v3 + +import ( + "bufio" + "errors" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strings" + + "github.com/spf13/pflag" + + "sigs.k8s.io/kubebuilder/internal/cmdutil" + "sigs.k8s.io/kubebuilder/pkg/model" + "sigs.k8s.io/kubebuilder/pkg/model/config" + "sigs.k8s.io/kubebuilder/pkg/model/resource" + "sigs.k8s.io/kubebuilder/pkg/plugin" + "sigs.k8s.io/kubebuilder/pkg/plugin/internal/util" + "sigs.k8s.io/kubebuilder/pkg/plugin/scaffold" + scaffoldsv3 "sigs.k8s.io/kubebuilder/pkg/plugin/v3/scaffolds" + "sigs.k8s.io/kubebuilder/plugins/addon" +) + +type createAPIPlugin struct { + config *config.Config + + // pattern indicates that we should use a plugin to build according to a pattern + pattern string + + resource *resource.Options + + // Check if we have to scaffold resource and/or controller + resourceFlag *pflag.Flag + controllerFlag *pflag.Flag + doResource bool + doController bool + + // force indicates that the resource should be created even if it already exists + force bool + + // runMake indicates whether to run make or not after scaffolding APIs + runMake bool +} + +var ( + _ plugin.CreateAPI = &createAPIPlugin{} + _ cmdutil.RunOptions = &createAPIPlugin{} +) + +func (p createAPIPlugin) UpdateContext(ctx *plugin.Context) { + ctx.Description = `Scaffold a Kubernetes API by creating a Resource definition and / or a Controller. + +create resource will prompt the user for if it should scaffold the Resource and / or Controller. To only +scaffold a Controller for an existing Resource, select "n" for Resource. To only define +the schema for a Resource without writing a Controller, select "n" for Controller. + +After the scaffold is written, api will run make on the project. +` + ctx.Examples = fmt.Sprintf(` # Create a frigates API with Group: ship, Version: v1beta1 and Kind: Frigate + %s create api --group ship --version v1beta1 --kind Frigate + + # Edit the API Scheme + nano api/v1beta1/frigate_types.go + + # Edit the Controller + nano controllers/frigate/frigate_controller.go + + # Edit the Controller Test + nano controllers/frigate/frigate_controller_test.go + + # Install CRDs into the Kubernetes cluster using kubectl apply + make install + + # Regenerate code and run against the Kubernetes cluster configured by ~/.kube/config + make run + `, + ctx.CommandName) +} + +func (p *createAPIPlugin) BindFlags(fs *pflag.FlagSet) { + fs.BoolVar(&p.runMake, "make", true, "if true, run make after generating files") + + fs.BoolVar(&p.doResource, "resource", true, + "if set, generate the resource without prompting the user") + p.resourceFlag = fs.Lookup("resource") + fs.BoolVar(&p.doController, "controller", true, + "if set, generate the controller without prompting the user") + p.controllerFlag = fs.Lookup("controller") + + if os.Getenv("KUBEBUILDER_ENABLE_PLUGINS") != "" { + fs.StringVar(&p.pattern, "pattern", "", + "generates an API following an extension pattern (addon)") + } + + fs.BoolVar(&p.force, "force", false, + "attempt to create resource even if it already exists") + p.resource = &resource.Options{} + fs.StringVar(&p.resource.Kind, "kind", "", "resource Kind") + fs.StringVar(&p.resource.Group, "group", "", "resource Group") + fs.StringVar(&p.resource.Version, "version", "", "resource Version") + fs.BoolVar(&p.resource.Namespaced, "namespaced", true, "resource is namespaced") +} + +func (p *createAPIPlugin) InjectConfig(c *config.Config) { + p.config = c +} + +func (p *createAPIPlugin) Run() error { + return cmdutil.Run(p) +} + +func (p *createAPIPlugin) Validate() error { + if err := p.resource.Validate(); err != nil { + return err + } + + reader := bufio.NewReader(os.Stdin) + if !p.resourceFlag.Changed { + fmt.Println("Create Resource [y/n]") + p.doResource = util.YesNo(reader) + } + if !p.controllerFlag.Changed { + fmt.Println("Create Controller [y/n]") + p.doController = util.YesNo(reader) + } + + // In case we want to scaffold a resource API we need to do some checks + if p.doResource { + // Check that resource doesn't exist or flag force was set + if !p.force && p.config.HasResource(p.resource.GVK()) { + return errors.New("API resource already exists") + } + + // Check that the provided group can be added to the project + if !p.config.MultiGroup && len(p.config.Resources) != 0 && !p.config.HasGroup(p.resource.Group) { + return fmt.Errorf("multiple groups are not allowed by default, to enable multi-group visit %s", + "kubebuilder.io/migration/multi-group.html") + } + } + + return nil +} + +func (p *createAPIPlugin) GetScaffolder() (scaffold.Scaffolder, error) { + // Load the boilerplate + bp, err := ioutil.ReadFile(filepath.Join("hack", "boilerplate.go.txt")) // nolint:gosec + if err != nil { + return nil, fmt.Errorf("unable to load boilerplate: %v", err) + } + + // Load the requested plugins + plugins := make([]model.Plugin, 0) + switch strings.ToLower(p.pattern) { + case "": + // Default pattern + case "addon": + plugins = append(plugins, &addon.Plugin{}) + default: + return nil, fmt.Errorf("unknown pattern %q", p.pattern) + } + + // Create the actual resource from the resource options + res := p.resource.NewResource(p.config, p.doResource) + return scaffoldsv3.NewAPIScaffolder(p.config, string(bp), res, p.doResource, p.doController, plugins), nil +} + +func (p *createAPIPlugin) PostScaffold() error { + // Load the requested plugins + switch strings.ToLower(p.pattern) { + case "": + // Default pattern + case "addon": + // Ensure that we are pinning sigs.k8s.io/kubebuilder-declarative-pattern version + err := util.RunCmd("Get controller runtime", "go", "get", + "sigs.k8s.io/kubebuilder-declarative-pattern@"+scaffoldsv3.KbDeclarativePattern) + if err != nil { + return err + } + default: + return fmt.Errorf("unknown pattern %q", p.pattern) + } + + if p.runMake { + return util.RunCmd("Running make", "make") + } + return nil +} diff --git a/pkg/plugin/v3/init.go b/pkg/plugin/v3/init.go new file mode 100644 index 00000000000..e8bb0f51822 --- /dev/null +++ b/pkg/plugin/v3/init.go @@ -0,0 +1,166 @@ +/* +Copyright 2020 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. +*/ + +package v3 + +import ( + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/spf13/pflag" + + "sigs.k8s.io/kubebuilder/internal/cmdutil" + "sigs.k8s.io/kubebuilder/pkg/internal/validation" + "sigs.k8s.io/kubebuilder/pkg/model/config" + "sigs.k8s.io/kubebuilder/pkg/plugin" + "sigs.k8s.io/kubebuilder/pkg/plugin/internal/util" + "sigs.k8s.io/kubebuilder/pkg/plugin/scaffold" + "sigs.k8s.io/kubebuilder/pkg/plugin/v2/scaffolds" +) + +type initPlugin struct { + config *config.Config + // For help text. + commandName string + + // boilerplate options + license string + owner string + + // flags + fetchDeps bool + skipGoVersionCheck bool +} + +var ( + _ plugin.Init = &initPlugin{} + _ cmdutil.RunOptions = &initPlugin{} +) + +func (p *initPlugin) UpdateContext(ctx *plugin.Context) { + ctx.Description = `Initialize a new project including vendor/ directory and Go package directories. + +Writes the following files: +- a boilerplate license file +- a PROJECT file with the domain and repo +- a Makefile to build the project +- a go.mod with project dependencies +- a Kustomization.yaml for customizating manifests +- a Patch file for customizing image for manager manifests +- a Patch file for enabling prometheus metrics +- a cmd/manager/main.go to run + +project will prompt the user to run 'dep ensure' after writing the project files. +` + ctx.Examples = fmt.Sprintf(` # Scaffold a project using the apache2 license with "The Kubernetes authors" as owners + %s init --project-version=2 --domain example.org --license apache2 --owner "The Kubernetes authors" +`, + ctx.CommandName) + + p.commandName = ctx.CommandName +} + +func (p *initPlugin) BindFlags(fs *pflag.FlagSet) { + fs.BoolVar(&p.skipGoVersionCheck, "skip-go-version-check", + false, "if specified, skip checking the Go version") + + // dependency args + fs.BoolVar(&p.fetchDeps, "fetch-deps", true, "ensure dependencies are downloaded") + + // boilerplate args + fs.StringVar(&p.license, "license", "apache2", + "license to use to boilerplate, may be one of 'apache2', 'none'") + fs.StringVar(&p.owner, "owner", "", "owner to add to the copyright") + + // project args + fs.StringVar(&p.config.Repo, "repo", "", "name to use for go module (e.g., github.com/user/repo), "+ + "defaults to the go package of the current working directory.") + fs.StringVar(&p.config.Domain, "domain", "my.domain", "domain for groups") +} + +func (p *initPlugin) InjectConfig(c *config.Config) { + // v3 project configs get a 'layout' value. + c.Layout = plugin.KeyFor(Plugin{}) + p.config = c +} + +func (p *initPlugin) Run() error { + return cmdutil.Run(p) +} + +func (p *initPlugin) Validate() error { + // Requires go1.11+ + if !p.skipGoVersionCheck { + if err := util.ValidateGoVersion(); err != nil { + return err + } + } + + // Check if the project name is a valid namespace according to k8s + dir, err := os.Getwd() + if err != nil { + return fmt.Errorf("error to get the current path: %v", err) + } + projectName := filepath.Base(dir) + if err := validation.IsDNS1123Label(strings.ToLower(projectName)); err != nil { + return fmt.Errorf("project name (%s) is invalid: %v", projectName, err) + } + + // Try to guess repository if flag is not set. + if p.config.Repo == "" { + repoPath, err := util.FindCurrentRepo() + if err != nil { + return fmt.Errorf("error finding current repository: %v", err) + } + p.config.Repo = repoPath + } + + return nil +} + +func (p *initPlugin) GetScaffolder() (scaffold.Scaffolder, error) { + return scaffolds.NewInitScaffolder(p.config, p.license, p.owner), nil +} + +func (p *initPlugin) PostScaffold() error { + if !p.fetchDeps { + fmt.Println("Skipping fetching dependencies.") + return nil + } + + // Ensure that we are pinning controller-runtime version + // xref: https://github.com/kubernetes-sigs/kubebuilder/issues/997 + err := util.RunCmd("Get controller runtime", "go", "get", + "sigs.k8s.io/controller-runtime@"+scaffolds.ControllerRuntimeVersion) + if err != nil { + return err + } + + err = util.RunCmd("Update go.mod", "go", "mod", "tidy") + if err != nil { + return err + } + + err = util.RunCmd("Running make", "make") + if err != nil { + return err + } + + fmt.Printf("Next: define a resource with:\n$ %s create api\n", p.commandName) + return nil +} diff --git a/pkg/plugin/v3/plugin.go b/pkg/plugin/v3/plugin.go new file mode 100644 index 00000000000..64d80991c41 --- /dev/null +++ b/pkg/plugin/v3/plugin.go @@ -0,0 +1,49 @@ +/* +Copyright 2020 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. +*/ + +package v3 + +import ( + "sigs.k8s.io/kubebuilder/pkg/model/config" + "sigs.k8s.io/kubebuilder/pkg/plugin" +) + +const pluginName = "go" + plugin.DefaultNameQualifier + +var ( + supportedProjectVersions = []string{config.Version3Alpha} + pluginVersion = plugin.Version{Number: 3, Stage: plugin.AlphaStage} +) + +var ( + _ plugin.Base = Plugin{} + _ plugin.InitPluginGetter = Plugin{} + _ plugin.CreateAPIPluginGetter = Plugin{} + _ plugin.CreateWebhookPluginGetter = Plugin{} +) + +type Plugin struct { + initPlugin + createAPIPlugin + createWebhookPlugin +} + +func (Plugin) Name() string { return pluginName } +func (Plugin) Version() plugin.Version { return pluginVersion } +func (Plugin) SupportedProjectVersions() []string { return supportedProjectVersions } +func (p Plugin) GetInitPlugin() plugin.Init { return &p.initPlugin } +func (p Plugin) GetCreateAPIPlugin() plugin.CreateAPI { return &p.createAPIPlugin } +func (p Plugin) GetCreateWebhookPlugin() plugin.CreateWebhook { return &p.createWebhookPlugin } diff --git a/pkg/plugin/v3/scaffolds/api.go b/pkg/plugin/v3/scaffolds/api.go new file mode 100644 index 00000000000..72cf18bd673 --- /dev/null +++ b/pkg/plugin/v3/scaffolds/api.go @@ -0,0 +1,136 @@ +/* +Copyright 2019 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. +*/ + +package scaffolds + +import ( + "fmt" + + "sigs.k8s.io/kubebuilder/pkg/model" + "sigs.k8s.io/kubebuilder/pkg/model/config" + "sigs.k8s.io/kubebuilder/pkg/model/resource" + "sigs.k8s.io/kubebuilder/pkg/plugin/internal/machinery" + "sigs.k8s.io/kubebuilder/pkg/plugin/scaffold" + "sigs.k8s.io/kubebuilder/pkg/plugin/v2/scaffolds/templates" + templatesv3 "sigs.k8s.io/kubebuilder/pkg/plugin/v3/scaffolds/templates" + "sigs.k8s.io/kubebuilder/pkg/plugin/v2/scaffolds/templates/controller" + "sigs.k8s.io/kubebuilder/pkg/plugin/v2/scaffolds/templates/crd" +) + +// (used only to gen api with --pattern=addon) +// KbDeclarativePattern is the sigs.k8s.io/kubebuilder-declarative-pattern version +const KbDeclarativePattern = "v0.0.0-20200522144838-848d48e5b073" + +var _ scaffold.Scaffolder = &apiScaffolder{} + +// apiScaffolder contains configuration for generating scaffolding for Go type +// representing the API and controller that implements the behavior for the API. +type apiScaffolder struct { + config *config.Config + boilerplate string + resource *resource.Resource + // plugins is the list of plugins we should allow to transform our generated scaffolding + plugins []model.Plugin + // doResource indicates whether to scaffold API Resource or not + doResource bool + // doController indicates whether to scaffold controller files or not + doController bool +} + +// NewAPIScaffolder returns a new Scaffolder for API/controller creation operations +func NewAPIScaffolder( + config *config.Config, + boilerplate string, + res *resource.Resource, + doResource, doController bool, + plugins []model.Plugin, +) scaffold.Scaffolder { + return &apiScaffolder{ + config: config, + boilerplate: boilerplate, + resource: res, + plugins: plugins, + doResource: doResource, + doController: doController, + } +} + +// Scaffold implements Scaffolder +func (s *apiScaffolder) Scaffold() error { + fmt.Println("Writing scaffold for you to edit...") + + switch { + case s.config.IsV3(): + return s.scaffold() + default: + return fmt.Errorf("unknown project version %v", s.config.Version) + } +} + +func (s *apiScaffolder) newUniverse() *model.Universe { + return model.NewUniverse( + model.WithConfig(s.config), + model.WithBoilerplate(s.boilerplate), + model.WithResource(s.resource), + ) +} + +func (s *apiScaffolder) scaffold() error { + if s.doResource { + s.config.AddResource(s.resource.GVK()) + + if err := machinery.NewScaffold(s.plugins...).Execute( + s.newUniverse(), + &templates.Types{}, + &templates.Group{}, + &templates.CRDSample{}, + &templates.CRDEditorRole{}, + &templates.CRDViewerRole{}, + &crd.EnableWebhookPatch{}, + &crd.EnableCAInjectionPatch{}, + ); err != nil { + return fmt.Errorf("error scaffolding APIs: %v", err) + } + + if err := machinery.NewScaffold().Execute( + s.newUniverse(), + &crd.Kustomization{}, + &crd.KustomizeConfig{}, + ); err != nil { + return fmt.Errorf("error scaffolding kustomization: %v", err) + } + + } + + if s.doController { + if err := machinery.NewScaffold(s.plugins...).Execute( + s.newUniverse(), + &controller.SuiteTest{}, + &controller.Controller{}, + ); err != nil { + return fmt.Errorf("error scaffolding controller: %v", err) + } + } + + if err := machinery.NewScaffold(s.plugins...).Execute( + s.newUniverse(), + &templatesv3.MainUpdater{WireResource: s.doResource, WireController: s.doController}, + ); err != nil { + return fmt.Errorf("error updating main.go: %v", err) + } + + return nil +} diff --git a/pkg/plugin/v3/scaffolds/templates/main.go b/pkg/plugin/v3/scaffolds/templates/main.go new file mode 100644 index 00000000000..fc58fba7a9a --- /dev/null +++ b/pkg/plugin/v3/scaffolds/templates/main.go @@ -0,0 +1,253 @@ +/* +Copyright 2019 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. +*/ + +package templates + +import ( + "fmt" + "hash/fnv" + "path/filepath" + "text/template" + + "sigs.k8s.io/kubebuilder/pkg/model/file" +) + +const defaultMainPath = "main.go" + +var _ file.Template = &Main{} +var _ file.UseCustomFuncMap = &Main{} + +// Main scaffolds the controller manager entry point +type Main struct { + file.TemplateMixin + file.BoilerplateMixin + file.DomainMixin + file.RepositoryMixin +} + +// SetTemplateDefaults implements file.Template +func (f *Main) SetTemplateDefaults() error { + if f.Path == "" { + f.Path = filepath.Join(defaultMainPath) + } + + f.TemplateBody = fmt.Sprintf(mainTemplate, + file.NewMarkerFor(f.Path, importMarker), + file.NewMarkerFor(f.Path, addSchemeMarker), + file.NewMarkerFor(f.Path, setupMarker), + ) + + return nil +} + +func hash(s string) (string, error) { + hasher := fnv.New32a() + hasher.Write([]byte(s)) // nolint:errcheck + return fmt.Sprintf("%x", hasher.Sum(nil)), nil +} + +// GetFuncMap implements file.UseCustomFuncMap +func (f *Main) GetFuncMap() template.FuncMap { + fm := file.DefaultFuncMap() + fm["hash"] = hash + return fm +} + +var _ file.Inserter = &MainUpdater{} + +// MainUpdater updates main.go to run Controllers +type MainUpdater struct { //nolint:maligned + file.RepositoryMixin + file.MultiGroupMixin + file.ResourceMixin + + // Flags to indicate which parts need to be included when updating the file + WireResource, WireController, WireWebhook bool +} + +// GetPath implements Builder +func (*MainUpdater) GetPath() string { + return defaultMainPath +} + +// GetIfExistsAction implements Builder +func (*MainUpdater) GetIfExistsAction() file.IfExistsAction { + return file.Overwrite +} + +const ( + importMarker = "imports" + addSchemeMarker = "scheme" + setupMarker = "builder" +) + +// GetMarkers implements file.Inserter +func (f *MainUpdater) GetMarkers() []file.Marker { + return []file.Marker{ + file.NewMarkerFor(defaultMainPath, importMarker), + file.NewMarkerFor(defaultMainPath, addSchemeMarker), + file.NewMarkerFor(defaultMainPath, setupMarker), + } +} + +const ( + apiImportCodeFragment = `%s "%s" +` + controllerImportCodeFragment = `"%s/controllers" +` + multiGroupControllerImportCodeFragment = `%scontrollers "%s/controllers/%s" +` + addschemeCodeFragment = `utilruntime.Must(%s.AddToScheme(scheme)) +` + reconcilerSetupCodeFragment = `if err = (&controllers.%sReconciler{ + Client: mgr.GetClient(), + Log: ctrl.Log.WithName("controllers").WithName("%s"), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "%s") + os.Exit(1) + } +` + multiGroupReconcilerSetupCodeFragment = `if err = (&%scontrollers.%sReconciler{ + Client: mgr.GetClient(), + Log: ctrl.Log.WithName("controllers").WithName("%s").WithName("%s"), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "%s") + os.Exit(1) + } +` + webhookSetupCodeFragment = `if err = (&%s.%s{}).SetupWebhookWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create webhook", "webhook", "%s") + os.Exit(1) + } +` +) + +// GetCodeFragments implements file.Inserter +func (f *MainUpdater) GetCodeFragments() file.CodeFragmentsMap { + fragments := make(file.CodeFragmentsMap, 3) + + // If resource is not being provided we are creating the file, not updating it + if f.Resource == nil { + return fragments + } + + // Generate import code fragments + imports := make([]string, 0) + imports = append(imports, fmt.Sprintf(apiImportCodeFragment, f.Resource.ImportAlias, f.Resource.Package)) + if f.WireController { + if !f.MultiGroup { + imports = append(imports, fmt.Sprintf(controllerImportCodeFragment, f.Repo)) + } else { + imports = append(imports, fmt.Sprintf(multiGroupControllerImportCodeFragment, + f.Resource.GroupPackageName, f.Repo, f.Resource.Group)) + } + } + + // Generate add scheme code fragments + addScheme := make([]string, 0) + addScheme = append(addScheme, fmt.Sprintf(addschemeCodeFragment, f.Resource.ImportAlias)) + + // Generate setup code fragments + setup := make([]string, 0) + if f.WireController { + if !f.MultiGroup { + setup = append(setup, fmt.Sprintf(reconcilerSetupCodeFragment, + f.Resource.Kind, f.Resource.Kind, f.Resource.Kind)) + } else { + setup = append(setup, fmt.Sprintf(multiGroupReconcilerSetupCodeFragment, + f.Resource.GroupPackageName, f.Resource.Kind, f.Resource.Group, f.Resource.Kind, f.Resource.Kind)) + } + } + if f.WireWebhook { + setup = append(setup, fmt.Sprintf(webhookSetupCodeFragment, + f.Resource.ImportAlias, f.Resource.Kind, f.Resource.Kind)) + } + + // Only store code fragments in the map if the slices are non-empty + if len(imports) != 0 { + fragments[file.NewMarkerFor(defaultMainPath, importMarker)] = imports + } + if len(addScheme) != 0 { + fragments[file.NewMarkerFor(defaultMainPath, addSchemeMarker)] = addScheme + } + if len(setup) != 0 { + fragments[file.NewMarkerFor(defaultMainPath, setupMarker)] = setup + } + + return fragments +} + +var mainTemplate = `{{ .Boilerplate }} + +package main + +import ( + "flag" + "os" + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + %s +) + +var ( + scheme = runtime.NewScheme() + setupLog = ctrl.Log.WithName("setup") +) + +func init() { + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + + %s +} + +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.") + flag.Parse() + + ctrl.SetLogger(zap.New(zap.UseDevMode(true))) + + mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ + Scheme: scheme, + MetricsBindAddress: metricsAddr, + Port: 9443, + LeaderElection: enableLeaderElection, + LeaderElectionID: "{{ hash .Repo }}.{{ .Domain }}", + }) + if err != nil { + setupLog.Error(err, "unable to start manager") + os.Exit(1) + } + + %s + + setupLog.Info("starting manager") + if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { + setupLog.Error(err, "problem running manager") + os.Exit(1) + } +} +` diff --git a/pkg/plugin/v3/scaffolds/webhook.go b/pkg/plugin/v3/scaffolds/webhook.go new file mode 100644 index 00000000000..374ee727a8f --- /dev/null +++ b/pkg/plugin/v3/scaffolds/webhook.go @@ -0,0 +1,96 @@ +/* +Copyright 2020 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. +*/ + +package scaffolds + +import ( + "fmt" + + "sigs.k8s.io/kubebuilder/pkg/model" + "sigs.k8s.io/kubebuilder/pkg/model/config" + "sigs.k8s.io/kubebuilder/pkg/model/resource" + "sigs.k8s.io/kubebuilder/pkg/plugin/internal/machinery" + "sigs.k8s.io/kubebuilder/pkg/plugin/scaffold" + templatesv3 "sigs.k8s.io/kubebuilder/pkg/plugin/v3/scaffolds/templates" + "sigs.k8s.io/kubebuilder/pkg/plugin/v2/scaffolds/templates/webhook" +) + +var _ scaffold.Scaffolder = &webhookScaffolder{} + +type webhookScaffolder struct { + config *config.Config + boilerplate string + resource *resource.Resource + + // v2 + defaulting, validation, conversion bool +} + +// NewWebhookScaffolder returns a new Scaffolder for v2 webhook creation operations +func NewWebhookScaffolder( + config *config.Config, + boilerplate string, + resource *resource.Resource, + defaulting bool, + validation bool, + conversion bool, +) scaffold.Scaffolder { + return &webhookScaffolder{ + config: config, + boilerplate: boilerplate, + resource: resource, + defaulting: defaulting, + validation: validation, + conversion: conversion, + } +} + +// Scaffold implements Scaffolder +func (s *webhookScaffolder) Scaffold() error { + fmt.Println("Writing scaffold for you to edit...") + + switch { + case s.config.IsV3(): + return s.scaffold() + default: + return fmt.Errorf("unknown project version %v", s.config.Version) + } +} + +func (s *webhookScaffolder) newUniverse() *model.Universe { + return model.NewUniverse( + model.WithConfig(s.config), + model.WithBoilerplate(s.boilerplate), + model.WithResource(s.resource), + ) +} + +func (s *webhookScaffolder) scaffold() error { + if s.conversion { + fmt.Println(`Webhook server has been set up for you. +You need to implement the conversion.Hub and conversion.Convertible interfaces for your CRD types.`) + } + + if err := machinery.NewScaffold().Execute( + s.newUniverse(), + &webhook.Webhook{Defaulting: s.defaulting, Validating: s.validation}, + &templatesv3.MainUpdater{WireWebhook: true}, + ); err != nil { + return err + } + + return nil +} diff --git a/pkg/plugin/v3/webhook.go b/pkg/plugin/v3/webhook.go new file mode 100644 index 00000000000..9fd6f2ebb90 --- /dev/null +++ b/pkg/plugin/v3/webhook.go @@ -0,0 +1,115 @@ +/* +Copyright 2020 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. +*/ + +package v3 + +import ( + "fmt" + "io/ioutil" + "path/filepath" + "github.com/spf13/pflag" + + "sigs.k8s.io/kubebuilder/internal/cmdutil" + "sigs.k8s.io/kubebuilder/pkg/model/config" + "sigs.k8s.io/kubebuilder/pkg/model/resource" + "sigs.k8s.io/kubebuilder/pkg/plugin" + "sigs.k8s.io/kubebuilder/pkg/plugin/scaffold" + scaffoldsv3 "sigs.k8s.io/kubebuilder/pkg/plugin/v3/scaffolds" +) + +type createWebhookPlugin struct { + config *config.Config + // For help text. + commandName string + + resource *resource.Options + defaulting bool + validation bool + conversion bool +} + +var ( + _ plugin.CreateWebhook = &createWebhookPlugin{} + _ cmdutil.RunOptions = &createAPIPlugin{} +) + +func (p *createWebhookPlugin) UpdateContext(ctx *plugin.Context) { + ctx.Description = `Scaffold a webhook for an API resource. You can choose to scaffold defaulting, +validating and (or) conversion webhooks. +` + ctx.Examples = fmt.Sprintf(` # Create defaulting and validating webhooks for CRD of group crew, version v1 + # and kind FirstMate. + %s create webhook --group crew --version v1 --kind FirstMate --defaulting --programmatic-validation + + # Create conversion webhook for CRD of group crew, version v1 and kind FirstMate. + %s create webhook --group crew --version v1 --kind FirstMate --conversion +`, + ctx.CommandName, ctx.CommandName) + + p.commandName = ctx.CommandName +} + +func (p *createWebhookPlugin) BindFlags(fs *pflag.FlagSet) { + p.resource = &resource.Options{} + fs.StringVar(&p.resource.Group, "group", "", "resource Group") + fs.StringVar(&p.resource.Version, "version", "", "resource Version") + fs.StringVar(&p.resource.Kind, "kind", "", "resource Kind") + fs.StringVar(&p.resource.Plural, "resource", "", "resource Resource") + + fs.BoolVar(&p.defaulting, "defaulting", false, + "if set, scaffold the defaulting webhook") + fs.BoolVar(&p.validation, "programmatic-validation", false, + "if set, scaffold the validating webhook") + fs.BoolVar(&p.conversion, "conversion", false, + "if set, scaffold the conversion webhook") +} + +func (p *createWebhookPlugin) InjectConfig(c *config.Config) { + p.config = c +} + +func (p *createWebhookPlugin) Run() error { + return cmdutil.Run(p) +} + +func (p *createWebhookPlugin) Validate() error { + if err := p.resource.Validate(); err != nil { + return err + } + + if !p.defaulting && !p.validation && !p.conversion { + return fmt.Errorf("%s create webhook requires at least one of --defaulting,"+ + " --programmatic-validation and --conversion to be true", p.commandName) + } + + return nil +} + +func (p *createWebhookPlugin) GetScaffolder() (scaffold.Scaffolder, error) { + // Load the boilerplate + bp, err := ioutil.ReadFile(filepath.Join("hack", "boilerplate.go.txt")) // nolint:gosec + if err != nil { + return nil, fmt.Errorf("unable to load boilerplate: %v", err) + } + + // Create the actual resource from the resource options + res := p.resource.NewResource(p.config, false) + return scaffoldsv3.NewWebhookScaffolder(p.config, string(bp), res, p.defaulting, p.validation, p.conversion), nil +} + +func (p *createWebhookPlugin) PostScaffold() error { + return nil +} diff --git a/testdata/project-v3-addon/PROJECT b/testdata/project-v3-addon/PROJECT index 14d827d5709..e76966fd5c8 100644 --- a/testdata/project-v3-addon/PROJECT +++ b/testdata/project-v3-addon/PROJECT @@ -1,5 +1,5 @@ domain: testproject.org -layout: go.kubebuilder.io/v2 +layout: go.kubebuilder.io/v3-alpha repo: sigs.k8s.io/kubebuilder/testdata/project-v3-addon resources: - group: crew diff --git a/testdata/project-v3-multigroup/PROJECT b/testdata/project-v3-multigroup/PROJECT index ec2d164be44..a5a4e01ce04 100644 --- a/testdata/project-v3-multigroup/PROJECT +++ b/testdata/project-v3-multigroup/PROJECT @@ -1,5 +1,5 @@ domain: testproject.org -layout: go.kubebuilder.io/v2 +layout: go.kubebuilder.io/v3-alpha multigroup: true repo: sigs.k8s.io/kubebuilder/testdata/project-v3-multigroup resources: diff --git a/testdata/project-v3-multigroup/main.go b/testdata/project-v3-multigroup/main.go index 2e456b5a3c1..6212af4eded 100644 --- a/testdata/project-v3-multigroup/main.go +++ b/testdata/project-v3-multigroup/main.go @@ -34,10 +34,10 @@ import ( shipv1 "sigs.k8s.io/kubebuilder/testdata/project-v3-multigroup/apis/ship/v1" shipv1beta1 "sigs.k8s.io/kubebuilder/testdata/project-v3-multigroup/apis/ship/v1beta1" shipv2alpha1 "sigs.k8s.io/kubebuilder/testdata/project-v3-multigroup/apis/ship/v2alpha1" - crewcontroller "sigs.k8s.io/kubebuilder/testdata/project-v3-multigroup/controllers/crew" - foopolicycontroller "sigs.k8s.io/kubebuilder/testdata/project-v3-multigroup/controllers/foo.policy" - seacreaturescontroller "sigs.k8s.io/kubebuilder/testdata/project-v3-multigroup/controllers/sea-creatures" - shipcontroller "sigs.k8s.io/kubebuilder/testdata/project-v3-multigroup/controllers/ship" + crewcontrollers "sigs.k8s.io/kubebuilder/testdata/project-v3-multigroup/controllers/crew" + foopolicycontrollers "sigs.k8s.io/kubebuilder/testdata/project-v3-multigroup/controllers/foo.policy" + seacreaturescontrollers "sigs.k8s.io/kubebuilder/testdata/project-v3-multigroup/controllers/sea-creatures" + shipcontrollers "sigs.k8s.io/kubebuilder/testdata/project-v3-multigroup/controllers/ship" // +kubebuilder:scaffold:imports ) @@ -82,9 +82,9 @@ func main() { os.Exit(1) } - if err = (&crewcontroller.CaptainReconciler{ + if err = (&crewcontrollers.CaptainReconciler{ Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controllers").WithName("Captain"), + Log: ctrl.Log.WithName("controllers").WithName("crew").WithName("Captain"), Scheme: mgr.GetScheme(), }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "Captain") @@ -94,9 +94,9 @@ func main() { setupLog.Error(err, "unable to create webhook", "webhook", "Captain") os.Exit(1) } - if err = (&shipcontroller.FrigateReconciler{ + if err = (&shipcontrollers.FrigateReconciler{ Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controllers").WithName("Frigate"), + Log: ctrl.Log.WithName("controllers").WithName("ship").WithName("Frigate"), Scheme: mgr.GetScheme(), }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "Frigate") @@ -106,41 +106,41 @@ func main() { setupLog.Error(err, "unable to create webhook", "webhook", "Frigate") os.Exit(1) } - if err = (&shipcontroller.DestroyerReconciler{ + if err = (&shipcontrollers.DestroyerReconciler{ Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controllers").WithName("Destroyer"), + Log: ctrl.Log.WithName("controllers").WithName("ship").WithName("Destroyer"), Scheme: mgr.GetScheme(), }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "Destroyer") os.Exit(1) } - if err = (&shipcontroller.CruiserReconciler{ + if err = (&shipcontrollers.CruiserReconciler{ Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controllers").WithName("Cruiser"), + Log: ctrl.Log.WithName("controllers").WithName("ship").WithName("Cruiser"), Scheme: mgr.GetScheme(), }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "Cruiser") os.Exit(1) } - if err = (&seacreaturescontroller.KrakenReconciler{ + if err = (&seacreaturescontrollers.KrakenReconciler{ Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controllers").WithName("Kraken"), + Log: ctrl.Log.WithName("controllers").WithName("sea-creatures").WithName("Kraken"), Scheme: mgr.GetScheme(), }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "Kraken") os.Exit(1) } - if err = (&seacreaturescontroller.LeviathanReconciler{ + if err = (&seacreaturescontrollers.LeviathanReconciler{ Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controllers").WithName("Leviathan"), + Log: ctrl.Log.WithName("controllers").WithName("sea-creatures").WithName("Leviathan"), Scheme: mgr.GetScheme(), }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "Leviathan") os.Exit(1) } - if err = (&foopolicycontroller.HealthCheckPolicyReconciler{ + if err = (&foopolicycontrollers.HealthCheckPolicyReconciler{ Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controllers").WithName("HealthCheckPolicy"), + Log: ctrl.Log.WithName("controllers").WithName("foo.policy").WithName("HealthCheckPolicy"), Scheme: mgr.GetScheme(), }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "HealthCheckPolicy") diff --git a/testdata/project-v3/PROJECT b/testdata/project-v3/PROJECT index 52263f80c0b..3c9fd6b0113 100644 --- a/testdata/project-v3/PROJECT +++ b/testdata/project-v3/PROJECT @@ -1,5 +1,5 @@ domain: testproject.org -layout: go.kubebuilder.io/v2 +layout: go.kubebuilder.io/v3-alpha repo: sigs.k8s.io/kubebuilder/testdata/project-v3 resources: - group: crew