From 7bcbb70f6e83e83caffc826032d9202cfb72eb93 Mon Sep 17 00:00:00 2001 From: Adrian Orive Date: Wed, 10 Feb 2021 15:45:16 +0100 Subject: [PATCH] Track external resources Signed-off-by: Adrian Orive --- pkg/plugins/golang/options.go | 4 +++- pkg/plugins/golang/v2/api.go | 6 +++--- pkg/plugins/golang/v2/options.go | 10 +++++++++- pkg/plugins/golang/v2/scaffolds/api.go | 13 +++++++++++-- pkg/plugins/golang/v2/webhook.go | 13 +++++++++++-- pkg/plugins/golang/v3/api.go | 4 ++-- pkg/plugins/golang/v3/scaffolds/api.go | 8 ++++---- pkg/plugins/golang/v3/webhook.go | 3 +-- testdata/project-v3-config/PROJECT | 5 +++++ testdata/project-v3-multigroup/PROJECT | 5 +++++ testdata/project-v3/PROJECT | 5 +++++ 11 files changed, 59 insertions(+), 17 deletions(-) diff --git a/pkg/plugins/golang/options.go b/pkg/plugins/golang/options.go index a6cb1a01f5c..892217da7ca 100644 --- a/pkg/plugins/golang/options.go +++ b/pkg/plugins/golang/options.go @@ -178,7 +178,9 @@ func (opts Options) NewResource(c newconfig.Config) resource.Resource { // - In any other case, default to => project resource // TODO: need to support '--resource-pkg-path' flag for specifying resourcePath if !opts.DoAPI { - if !c.HasResource(opts.GVK()) { + loadedRes, err := c.GetResource(opts.GVK()) + alreadyHasAPI := err == nil && loadedRes.HasAPI() + if !alreadyHasAPI { if domain, found := coreGroups[opts.Group]; found { res.Domain = domain res.Path = path.Join("k8s.io", "api", opts.Group, opts.Version) diff --git a/pkg/plugins/golang/v2/api.go b/pkg/plugins/golang/v2/api.go index 0c224a07d4a..bdca3497512 100644 --- a/pkg/plugins/golang/v2/api.go +++ b/pkg/plugins/golang/v2/api.go @@ -154,9 +154,9 @@ func (p *createAPISubcommand) Validate() error { } // In case we want to scaffold a resource API we need to do some checks - if p.resource.HasAPI() { - // Check that resource doesn't exist or flag force was set - if !p.force && p.config.HasResource(p.resource.GVK) { + if p.options.DoAPI { + // Check that resource doesn't have the API scaffolded or flag force was set + if res, err := p.config.GetResource(p.resource.GVK); err == nil && res.HasAPI() && !p.force { return errors.New("API resource already exists") } diff --git a/pkg/plugins/golang/v2/options.go b/pkg/plugins/golang/v2/options.go index 55fba1b8e6b..52f4410b838 100644 --- a/pkg/plugins/golang/v2/options.go +++ b/pkg/plugins/golang/v2/options.go @@ -22,6 +22,7 @@ import ( "strings" newconfig "sigs.k8s.io/kubebuilder/v3/pkg/config" + cfgv2 "sigs.k8s.io/kubebuilder/v3/pkg/config/v2" "sigs.k8s.io/kubebuilder/v3/pkg/model/resource" ) @@ -178,7 +179,14 @@ func (opts Options) NewResource(c newconfig.Config) resource.Resource { // - In any other case, default to => project resource // TODO: need to support '--resource-pkg-path' flag for specifying resourcePath if !opts.DoAPI { - if !c.HasResource(opts.GVK()) { + var alreadyHasAPI bool + if c.GetVersion().Compare(cfgv2.Version) == 0 { + alreadyHasAPI = c.HasResource(opts.GVK()) + } else { + loadedRes, err := c.GetResource(opts.GVK()) + alreadyHasAPI = err == nil && loadedRes.HasAPI() + } + if !alreadyHasAPI { if domain, found := coreGroups[opts.Group]; found { res.Domain = domain res.Path = path.Join("k8s.io", "api", opts.Group, opts.Version) diff --git a/pkg/plugins/golang/v2/scaffolds/api.go b/pkg/plugins/golang/v2/scaffolds/api.go index e4abc4d9ae6..353aac0e5f0 100644 --- a/pkg/plugins/golang/v2/scaffolds/api.go +++ b/pkg/plugins/golang/v2/scaffolds/api.go @@ -20,6 +20,7 @@ import ( "fmt" "sigs.k8s.io/kubebuilder/v3/pkg/config" + cfgv2 "sigs.k8s.io/kubebuilder/v3/pkg/config/v2" "sigs.k8s.io/kubebuilder/v3/pkg/model" "sigs.k8s.io/kubebuilder/v3/pkg/model/resource" "sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/v2/scaffolds/internal/templates" @@ -89,11 +90,19 @@ func (s *apiScaffolder) scaffold() error { doAPI := s.resource.HasAPI() doController := s.resource.HasController() - if doAPI { - + // Project version v2 only tracked GVK triplets of each resource. + // As they were only tracked when the API was scaffolded, the presence of a + // resource in the config file was used in webhook creation to verify that + // the API had been scaffolded previously. From project version v3 onwards + // this information is stored in the API field of the resource, so we can + // update the resources except for project version 2 when no API was scaffolded. + if doAPI || s.config.GetVersion().Compare(cfgv2.Version) == 1 { if err := s.config.UpdateResource(s.resource); err != nil { return fmt.Errorf("error updating resource: %w", err) } + } + + if doAPI { if err := machinery.NewScaffold(s.plugins...).Execute( s.newUniverse(), diff --git a/pkg/plugins/golang/v2/webhook.go b/pkg/plugins/golang/v2/webhook.go index 2c4b2f8bb7e..735c48c68df 100644 --- a/pkg/plugins/golang/v2/webhook.go +++ b/pkg/plugins/golang/v2/webhook.go @@ -24,6 +24,7 @@ import ( "github.com/spf13/pflag" newconfig "sigs.k8s.io/kubebuilder/v3/pkg/config" + cfgv2 "sigs.k8s.io/kubebuilder/v3/pkg/config/v2" "sigs.k8s.io/kubebuilder/v3/pkg/model/resource" "sigs.k8s.io/kubebuilder/v3/pkg/plugin" "sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/v2/scaffolds" @@ -104,8 +105,16 @@ func (p *createWebhookSubcommand) Validate() error { } // check if resource exist to create webhook - if !p.config.HasResource(p.resource.GVK) { - return fmt.Errorf("%s create webhook requires a previously created API ", p.commandName) + if p.config.GetVersion().Compare(cfgv2.Version) == 0 { + if !p.config.HasResource(p.resource.GVK) { + return fmt.Errorf("%s create webhook requires a previously created API ", p.commandName) + } + } else { + if r, err := p.config.GetResource(p.resource.GVK); err != nil { + return fmt.Errorf("%s create webhook requires a previously created API ", p.commandName) + } else if r.Webhooks != nil && !r.Webhooks.IsEmpty() { + return fmt.Errorf("webhook resource already exists") + } } return nil diff --git a/pkg/plugins/golang/v3/api.go b/pkg/plugins/golang/v3/api.go index 98a6462e40b..f71bc7e5e4f 100644 --- a/pkg/plugins/golang/v3/api.go +++ b/pkg/plugins/golang/v3/api.go @@ -176,8 +176,8 @@ func (p *createAPISubcommand) Validate() error { } // In case we want to scaffold a resource API we need to do some checks - if p.resource.HasAPI() { - // Check that resource doesn't exist or flag force was set + if p.options.DoAPI { + // Check that resource doesn't have the API scaffolded or flag force was set if res, err := p.config.GetResource(p.resource.GVK); err == nil && res.HasAPI() && !p.force { return errors.New("API resource already exists") } diff --git a/pkg/plugins/golang/v3/scaffolds/api.go b/pkg/plugins/golang/v3/scaffolds/api.go index 0265d705b60..1d9698cafc3 100644 --- a/pkg/plugins/golang/v3/scaffolds/api.go +++ b/pkg/plugins/golang/v3/scaffolds/api.go @@ -86,11 +86,11 @@ func (s *apiScaffolder) scaffold() error { doAPI := s.resource.HasAPI() doController := s.resource.HasController() - if doAPI { + if err := s.config.UpdateResource(s.resource); err != nil { + return fmt.Errorf("error updating resource: %w", err) + } - if err := s.config.UpdateResource(s.resource); err != nil { - return fmt.Errorf("error updating resource: %w", err) - } + if doAPI { if err := machinery.NewScaffold(s.plugins...).Execute( s.newUniverse(), diff --git a/pkg/plugins/golang/v3/webhook.go b/pkg/plugins/golang/v3/webhook.go index 0139225b878..7c81b017fae 100644 --- a/pkg/plugins/golang/v3/webhook.go +++ b/pkg/plugins/golang/v3/webhook.go @@ -17,7 +17,6 @@ limitations under the License. package v3 import ( - "errors" "fmt" "io/ioutil" "path/filepath" @@ -119,7 +118,7 @@ func (p *createWebhookSubcommand) Validate() error { if r, err := p.config.GetResource(p.resource.GVK); err != nil { return fmt.Errorf("%s create webhook requires a previously created API ", p.commandName) } else if r.Webhooks != nil && !r.Webhooks.IsEmpty() && !p.force { - return errors.New("webhook resource already exists") + return fmt.Errorf("webhook resource already exists") } if !p.config.IsWebhookVersionCompatible(p.resource.Webhooks.WebhookVersion) { diff --git a/testdata/project-v3-config/PROJECT b/testdata/project-v3-config/PROJECT index 144702d87c3..804ab898289 100644 --- a/testdata/project-v3-config/PROJECT +++ b/testdata/project-v3-config/PROJECT @@ -40,4 +40,9 @@ resources: webhooks: defaulting: true webhookVersion: v1 +- controller: true + domain: testproject.org + group: crew + kind: Laker + version: v1 version: "3" diff --git a/testdata/project-v3-multigroup/PROJECT b/testdata/project-v3-multigroup/PROJECT index 30a6a0ddfa7..4d23fb47636 100644 --- a/testdata/project-v3-multigroup/PROJECT +++ b/testdata/project-v3-multigroup/PROJECT @@ -78,6 +78,11 @@ resources: kind: HealthCheckPolicy path: sigs.k8s.io/kubebuilder/testdata/project-v3-multigroup/apis/foo.policy/v1 version: v1 +- controller: true + group: apps + kind: Deployment + path: k8s.io/api/apps/v1 + version: v1 - api: crdVersion: v1 namespaced: true diff --git a/testdata/project-v3/PROJECT b/testdata/project-v3/PROJECT index b30361d9899..8dde5b76ffe 100644 --- a/testdata/project-v3/PROJECT +++ b/testdata/project-v3/PROJECT @@ -40,4 +40,9 @@ resources: webhooks: defaulting: true webhookVersion: v1 +- controller: true + domain: testproject.org + group: crew + kind: Laker + version: v1 version: "3"