Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🐛 (config/v3) Track in the project configuration file resources without API #2003

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion generate_testdata.sh
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ scaffold_test_project() {

$kb create api --group foo.policy --version v1 --kind HealthCheckPolicy --controller=true --resource=true --make=false

$kb create api --group apps --version v1 --kind Pod --controller=true --resource=false --make=false
$kb create api --group apps --version v1 --kind Deployment --controller=true --resource=false --make=false
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pod is not part of the apps group, it is part of the core group: link.

Replaced for Deployment which is part of the apps group: link.


if [ $project == "project-v3-multigroup" ]; then
$kb create api --version v1 --kind Lakers --controller=true --resource=true --make=false
Expand Down
12 changes: 9 additions & 3 deletions pkg/model/file/funcmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,18 @@ import (
// DefaultFuncMap returns the default template.FuncMap for rendering the template.
func DefaultFuncMap() template.FuncMap {
return template.FuncMap{
"title": strings.Title,
"lower": strings.ToLower,
"hashFNV": hashFNV,
"title": strings.Title,
"lower": strings.ToLower,
"isEmptyStr": isEmptyString,
"hashFNV": hashFNV,
}
}

// isEmptyString returns whether the string is empty
func isEmptyString(s string) bool {
return s == ""
}

// hashFNV will generate a random string useful for generating a unique string
func hashFNV(s string) (string, error) {
hasher := fnv.New32a()
Expand Down
8 changes: 6 additions & 2 deletions pkg/model/resource/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,12 @@ func (r *Resource) Update(other Resource) error {
return fmt.Errorf("unable to update Resource with another with non-matching Plural")
}

if r.Path != other.Path {
return fmt.Errorf("unable to update Resource with another with non-matching Path")
if other.Path != "" && r.Path != other.Path {
if r.Path == "" {
r.Path = other.Path
} else {
return fmt.Errorf("unable to update Resource with another with non-matching Path")
}
}

// Update API.
Expand Down
7 changes: 5 additions & 2 deletions pkg/plugins/golang/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,6 @@ func (opts Options) GVK() resource.GVK {
func (opts Options) NewResource(c newconfig.Config) resource.Resource {
res := resource.Resource{
GVK: opts.GVK(),
Path: resource.APIPackagePath(c.GetRepository(), opts.Group, opts.Version, c.IsMultiGroup()),
Controller: opts.DoController,
}

Expand All @@ -149,6 +148,7 @@ func (opts Options) NewResource(c newconfig.Config) resource.Resource {
}

if opts.DoAPI {
res.Path = resource.APIPackagePath(c.GetRepository(), opts.Group, opts.Version, c.IsMultiGroup())
res.API = &resource.API{
CRDVersion: opts.CRDVersion,
Namespaced: opts.Namespaced,
Expand All @@ -159,6 +159,7 @@ func (opts Options) NewResource(c newconfig.Config) resource.Resource {
}

if opts.DoDefaulting || opts.DoValidation || opts.DoConversion {
res.Path = resource.APIPackagePath(c.GetRepository(), opts.Group, opts.Version, c.IsMultiGroup())
res.Webhooks = &resource.Webhooks{
WebhookVersion: opts.WebhookVersion,
Defaulting: opts.DoDefaulting,
Expand All @@ -177,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)
Expand Down
56 changes: 45 additions & 11 deletions pkg/plugins/golang/options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ var _ = Describe("Options", func() {
for _, multiGroup := range []bool{false, true} {
if multiGroup {
Expect(cfg.SetMultiGroup()).To(Succeed())
} else {
Expect(cfg.ClearMultiGroup()).To(Succeed())
}

resource := options.NewResource(cfg)
Expand All @@ -70,19 +72,36 @@ var _ = Describe("Options", func() {
Expect(resource.Domain).To(Equal(options.Domain))
Expect(resource.Version).To(Equal(options.Version))
Expect(resource.Kind).To(Equal(options.Kind))
if multiGroup {
Expect(resource.Path).To(Equal(
path.Join(cfg.GetRepository(), "apis", options.Group, options.Version)))
Expect(resource.API).NotTo(BeNil())
if options.DoAPI || options.DoDefaulting || options.DoValidation || options.DoConversion {
if multiGroup {
Expect(resource.Path).To(Equal(
path.Join(cfg.GetRepository(), "apis", options.Group, options.Version)))
} else {
Expect(resource.Path).To(Equal(path.Join(cfg.GetRepository(), "api", options.Version)))
}
} else {
Expect(resource.Path).To(Equal(path.Join(cfg.GetRepository(), "api", options.Version)))
// Core-resources have a path despite not having an API/Webhook but they are not tested here
Expect(resource.Path).To(Equal(""))
}
if options.DoAPI {
Expect(resource.API.CRDVersion).To(Equal(options.CRDVersion))
Expect(resource.API.Namespaced).To(Equal(options.Namespaced))
Expect(resource.API.IsEmpty()).To(BeFalse())
} else {
Expect(resource.API.IsEmpty()).To(BeTrue())
}
Expect(resource.API.CRDVersion).To(Equal(options.CRDVersion))
Expect(resource.API.Namespaced).To(Equal(options.Namespaced))
Expect(resource.Controller).To(Equal(options.DoController))
Expect(resource.Webhooks.WebhookVersion).To(Equal(options.WebhookVersion))
Expect(resource.Webhooks.Defaulting).To(Equal(options.DoDefaulting))
Expect(resource.Webhooks.Validation).To(Equal(options.DoValidation))
Expect(resource.Webhooks.Conversion).To(Equal(options.DoConversion))
Expect(resource.Webhooks).NotTo(BeNil())
if options.DoDefaulting || options.DoValidation || options.DoConversion {
Expect(resource.Webhooks.WebhookVersion).To(Equal(options.WebhookVersion))
Expect(resource.Webhooks.Defaulting).To(Equal(options.DoDefaulting))
Expect(resource.Webhooks.Validation).To(Equal(options.DoValidation))
Expect(resource.Webhooks.Conversion).To(Equal(options.DoConversion))
Expect(resource.Webhooks.IsEmpty()).To(BeFalse())
} else {
Expect(resource.Webhooks.IsEmpty()).To(BeTrue())
}
Expect(resource.QualifiedGroup()).To(Equal(options.Group + "." + options.Domain))
Expect(resource.PackageName()).To(Equal(options.Group))
Expect(resource.ImportAlias()).To(Equal(options.Group + options.Version))
Expand Down Expand Up @@ -130,6 +149,8 @@ var _ = Describe("Options", func() {
for _, multiGroup := range []bool{false, true} {
if multiGroup {
Expect(cfg.SetMultiGroup()).To(Succeed())
} else {
Expect(cfg.ClearMultiGroup()).To(Succeed())
}

resource := options.NewResource(cfg)
Expand All @@ -150,6 +171,8 @@ var _ = Describe("Options", func() {
for _, multiGroup := range []bool{false, true} {
if multiGroup {
Expect(cfg.SetMultiGroup()).To(Succeed())
} else {
Expect(cfg.ClearMultiGroup()).To(Succeed())
}

resource := options.NewResource(cfg)
Expand All @@ -168,12 +191,15 @@ var _ = Describe("Options", func() {
Domain: "test.io",
Version: "v1",
Kind: "FirstMate",
DoAPI: true, // Scaffold the API so that the path is saved
}
Expect(options.Validate()).To(Succeed())

for _, multiGroup := range []bool{false, true} {
if multiGroup {
Expect(cfg.SetMultiGroup()).To(Succeed())
} else {
Expect(cfg.ClearMultiGroup()).To(Succeed())
}

resource := options.NewResource(cfg)
Expand Down Expand Up @@ -201,6 +227,8 @@ var _ = Describe("Options", func() {
for _, multiGroup := range []bool{false, true} {
if multiGroup {
Expect(cfg.SetMultiGroup()).To(Succeed())
} else {
Expect(cfg.ClearMultiGroup()).To(Succeed())
}

resource := options.NewResource(cfg)
Expand All @@ -222,12 +250,15 @@ var _ = Describe("Options", func() {
for _, multiGroup := range []bool{false, true} {
if multiGroup {
Expect(cfg.SetMultiGroup()).To(Succeed())
} else {
Expect(cfg.ClearMultiGroup()).To(Succeed())
}

resource := options.NewResource(cfg)
Expect(resource.Validate()).To(Succeed())
Expect(resource.Path).To(Equal(path.Join("k8s.io", "api", options.Group, options.Version)))
Expect(resource.API.CRDVersion).To(Equal(""))
Expect(resource.API).NotTo(BeNil())
Expect(resource.API.IsEmpty()).To(BeTrue())
Expect(resource.QualifiedGroup()).To(Equal(qualified))
}
},
Expand All @@ -242,12 +273,15 @@ var _ = Describe("Options", func() {
Domain: "test.io",
Version: "v1",
Kind: "FirstMate",
DoAPI: true, // Scaffold the API so that the path is saved
}
Expect(options.Validate()).To(Succeed())

for _, multiGroup := range []bool{false, true} {
if multiGroup {
Expect(cfg.SetMultiGroup()).To(Succeed())
} else {
Expect(cfg.ClearMultiGroup()).To(Succeed())
}

resource := options.NewResource(cfg)
Expand Down
6 changes: 3 additions & 3 deletions pkg/plugins/golang/v2/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}

Expand Down
13 changes: 11 additions & 2 deletions pkg/plugins/golang/v2/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand Down Expand Up @@ -137,7 +138,6 @@ func (opts Options) GVK() resource.GVK {
func (opts Options) NewResource(c newconfig.Config) resource.Resource {
res := resource.Resource{
GVK: opts.GVK(),
Path: resource.APIPackagePath(c.GetRepository(), opts.Group, opts.Version, c.IsMultiGroup()),
Controller: opts.DoController,
}

Expand All @@ -149,6 +149,7 @@ func (opts Options) NewResource(c newconfig.Config) resource.Resource {
}

if opts.DoAPI {
res.Path = resource.APIPackagePath(c.GetRepository(), opts.Group, opts.Version, c.IsMultiGroup())
res.API = &resource.API{
CRDVersion: opts.CRDVersion,
Namespaced: opts.Namespaced,
Expand All @@ -159,6 +160,7 @@ func (opts Options) NewResource(c newconfig.Config) resource.Resource {
}

if opts.DoDefaulting || opts.DoValidation || opts.DoConversion {
res.Path = resource.APIPackagePath(c.GetRepository(), opts.Group, opts.Version, c.IsMultiGroup())
res.Webhooks = &resource.Webhooks{
WebhookVersion: opts.WebhookVersion,
Defaulting: opts.DoDefaulting,
Expand All @@ -177,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)
Expand Down
53 changes: 42 additions & 11 deletions pkg/plugins/golang/v2/options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ var _ = Describe("Options", func() {
for _, multiGroup := range []bool{false, true} {
if multiGroup {
Expect(cfg.SetMultiGroup()).To(Succeed())
} else {
Expect(cfg.ClearMultiGroup()).To(Succeed())
}

resource := options.NewResource(cfg)
Expand All @@ -69,19 +71,36 @@ var _ = Describe("Options", func() {
Expect(resource.Domain).To(Equal(options.Domain))
Expect(resource.Version).To(Equal(options.Version))
Expect(resource.Kind).To(Equal(options.Kind))
if multiGroup {
Expect(resource.Path).To(Equal(
path.Join(cfg.GetRepository(), "apis", options.Group, options.Version)))
Expect(resource.API).NotTo(BeNil())
if options.DoAPI || options.DoDefaulting || options.DoValidation || options.DoConversion {
if multiGroup {
Expect(resource.Path).To(Equal(
path.Join(cfg.GetRepository(), "apis", options.Group, options.Version)))
} else {
Expect(resource.Path).To(Equal(path.Join(cfg.GetRepository(), "api", options.Version)))
}
} else {
Expect(resource.Path).To(Equal(path.Join(cfg.GetRepository(), "api", options.Version)))
// Core-resources have a path despite not having an API/Webhook but they are not tested here
Expect(resource.Path).To(Equal(""))
}
if options.DoAPI {
Expect(resource.API.CRDVersion).To(Equal(options.CRDVersion))
Expect(resource.API.Namespaced).To(Equal(options.Namespaced))
Expect(resource.API.IsEmpty()).To(BeFalse())
} else {
Expect(resource.API.IsEmpty()).To(BeTrue())
}
Expect(resource.API.CRDVersion).To(Equal(options.CRDVersion))
Expect(resource.API.Namespaced).To(Equal(options.Namespaced))
Expect(resource.Controller).To(Equal(options.DoController))
Expect(resource.Webhooks.WebhookVersion).To(Equal(options.WebhookVersion))
Expect(resource.Webhooks.Defaulting).To(Equal(options.DoDefaulting))
Expect(resource.Webhooks.Validation).To(Equal(options.DoValidation))
Expect(resource.Webhooks.Conversion).To(Equal(options.DoConversion))
Expect(resource.Webhooks).NotTo(BeNil())
if options.DoDefaulting || options.DoValidation || options.DoConversion {
Expect(resource.Webhooks.WebhookVersion).To(Equal(options.WebhookVersion))
Expect(resource.Webhooks.Defaulting).To(Equal(options.DoDefaulting))
Expect(resource.Webhooks.Validation).To(Equal(options.DoValidation))
Expect(resource.Webhooks.Conversion).To(Equal(options.DoConversion))
Expect(resource.Webhooks.IsEmpty()).To(BeFalse())
} else {
Expect(resource.Webhooks.IsEmpty()).To(BeTrue())
}
Expect(resource.QualifiedGroup()).To(Equal(options.Group + "." + options.Domain))
Expect(resource.PackageName()).To(Equal(options.Group))
Expect(resource.ImportAlias()).To(Equal(options.Group + options.Version))
Expand Down Expand Up @@ -129,6 +148,8 @@ var _ = Describe("Options", func() {
for _, multiGroup := range []bool{false, true} {
if multiGroup {
Expect(cfg.SetMultiGroup()).To(Succeed())
} else {
Expect(cfg.ClearMultiGroup()).To(Succeed())
}

resource := options.NewResource(cfg)
Expand All @@ -149,6 +170,8 @@ var _ = Describe("Options", func() {
for _, multiGroup := range []bool{false, true} {
if multiGroup {
Expect(cfg.SetMultiGroup()).To(Succeed())
} else {
Expect(cfg.ClearMultiGroup()).To(Succeed())
}

resource := options.NewResource(cfg)
Expand All @@ -167,12 +190,15 @@ var _ = Describe("Options", func() {
Domain: "test.io",
Version: "v1",
Kind: "FirstMate",
DoAPI: true, // Scaffold the API so that the path is saved
}
Expect(options.Validate()).To(Succeed())

for _, multiGroup := range []bool{false, true} {
if multiGroup {
Expect(cfg.SetMultiGroup()).To(Succeed())
} else {
Expect(cfg.ClearMultiGroup()).To(Succeed())
}

resource := options.NewResource(cfg)
Expand Down Expand Up @@ -200,6 +226,8 @@ var _ = Describe("Options", func() {
for _, multiGroup := range []bool{false, true} {
if multiGroup {
Expect(cfg.SetMultiGroup()).To(Succeed())
} else {
Expect(cfg.ClearMultiGroup()).To(Succeed())
}

resource := options.NewResource(cfg)
Expand All @@ -221,12 +249,15 @@ var _ = Describe("Options", func() {
for _, multiGroup := range []bool{false, true} {
if multiGroup {
Expect(cfg.SetMultiGroup()).To(Succeed())
} else {
Expect(cfg.ClearMultiGroup()).To(Succeed())
}

resource := options.NewResource(cfg)
Expect(resource.Validate()).To(Succeed())
Expect(resource.Path).To(Equal(path.Join("k8s.io", "api", options.Group, options.Version)))
Expect(resource.API.CRDVersion).To(Equal(""))
Expect(resource.API).NotTo(BeNil())
Expect(resource.API.IsEmpty()).To(BeTrue())
Expect(resource.QualifiedGroup()).To(Equal(qualified))
}
},
Expand Down
Loading