Skip to content

Commit

Permalink
Upgrade resource to keep more and better structured information
Browse files Browse the repository at this point in the history
Signed-off-by: Adrian Orive <[email protected]>
  • Loading branch information
Adirio committed Dec 2, 2020
1 parent a0e0782 commit 6d37b49
Show file tree
Hide file tree
Showing 41 changed files with 452 additions and 543 deletions.
97 changes: 44 additions & 53 deletions pkg/model/resource/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,13 @@ type Options struct {
CRDVersion string
// WebhookVersion holds the {Validating,Mutating}WebhookConfiguration API version used for the Options.
WebhookVersion string

// Flags that define which parts should be scaffolded
DoDefinition bool
DoController bool
DoDefaulting bool
DoValidation bool
DoConversion bool
}

// ValidateV2 verifies that V2 project has all the fields have valid values
Expand Down Expand Up @@ -182,6 +189,8 @@ func (opts *Options) Validate() error {
validationErrors = append(validationErrors, "kind must start with an uppercase character")
}

// TODO: check that at least one of Domain and Group are non-empty

validationErrors = append(validationErrors, validation.IsDNS1035Label(strings.ToLower(opts.Kind))...)

if len(validationErrors) != 0 {
Expand Down Expand Up @@ -216,79 +225,61 @@ func (opts *Options) GVK() config.GVK {
}
}

// safeImport returns a cleaned version of the provided string that can be used for imports
func (opts *Options) safeImport(unsafe string) string {
safe := unsafe

// Remove dashes and dots
safe = strings.Replace(safe, "-", "", -1)
safe = strings.Replace(safe, ".", "", -1)

return safe
}

// NewResource creates a new resource from the options
func (opts *Options) NewResource(c *config.Config, doResource bool) *Resource {
res := opts.newResource()
func (opts *Options) NewResource(c *config.Config) *Resource {
// If not provided, compute a plural for for Kind
plural := opts.Plural
if plural == "" {
plural = flect.Pluralize(strings.ToLower(opts.Kind))
}

replacer := res.Replacer()
res := &Resource{
Group: opts.Group,
Version: opts.Version,
Kind: opts.Kind,
Plural: plural,
Domain: c.Domain,
API: &API{
Version: opts.CRDVersion,
Namespaced: opts.Namespaced,
},
Controller: opts.DoController,
Webhooks: &Webhooks{
Version: opts.WebhookVersion,
Defaulting: opts.DoDefaulting,
Validation: opts.DoValidation,
Conversion: opts.DoConversion,
},
}

pkg := replacer.Replace(path.Join(c.Repo, "api", "%[version]"))
// Group, Version, Kind, Plural and Domain are already set,
// so we can already create a replacer that is needed for path.
replacer := res.Replacer()
if c.MultiGroup {
if opts.Group != "" {
pkg = replacer.Replace(path.Join(c.Repo, "apis", "%[group]", "%[version]"))
res.Path = replacer.Replace(path.Join(c.Repo, "apis", "%[group]", "%[version]"))
} else {
pkg = replacer.Replace(path.Join(c.Repo, "apis", "%[version]"))
res.Path = replacer.Replace(path.Join(c.Repo, "apis", "%[version]"))
}
} else {
res.Path = replacer.Replace(path.Join(c.Repo, "api", "%[version]"))
}
domain := c.Domain

// pkg and domain may need to be changed in case we are referring to a builtin core resource:
// - Check if we are scaffolding the resource now => project resource
// - Check if we already scaffolded the resource => project resource
// - Check if the resource group is a well-known core group => builtin core resource
// - In any other case, default to => project resource
// TODO: need to support '--resource-pkg-path' flag for specifying resourcePath
if !doResource {
if !opts.DoDefinition {
if !c.HasResource(opts.GVK()) {
if coreDomain, found := coreGroups[opts.Group]; found {
pkg = replacer.Replace(path.Join("k8s.io", "api", "%[group]", "%[version]"))
domain = coreDomain
res.Path = replacer.Replace(path.Join("k8s.io", "api", "%[group]", "%[version]"))
res.Domain = coreDomain
res.API = &API{External: true}
}
}
}

res.Package = pkg
res.Domain = opts.Group
if domain != "" && opts.Group != "" {
res.Domain += "." + domain
} else if opts.Group == "" && !c.IsV2() {
// Empty group overrides the default values provided by newResource().
// GroupPackageName and ImportAlias includes domain instead of group name as user provided group is empty.
res.Domain = domain
res.GroupPackageName = opts.safeImport(domain)
res.ImportAlias = opts.safeImport(domain + opts.Version)
}

return res
}

func (opts *Options) newResource() *Resource {
// If not provided, compute a plural for for Kind
plural := opts.Plural
if plural == "" {
plural = flect.Pluralize(strings.ToLower(opts.Kind))
}

return &Resource{
Namespaced: opts.Namespaced,
Group: opts.Group,
GroupPackageName: opts.safeImport(opts.Group),
Version: opts.Version,
Kind: opts.Kind,
Plural: plural,
ImportAlias: opts.safeImport(opts.Group + opts.Version),
CRDVersion: opts.CRDVersion,
WebhookVersion: opts.WebhookVersion,
}
}
94 changes: 73 additions & 21 deletions pkg/model/resource/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,37 +25,62 @@ import (

// Resource contains the information required to scaffold files for a resource.
type Resource struct {
// Group is the API Group. Does not contain the domain.
// Group is the API group. Does not contain the domain.
Group string `json:"group,omitempty"`

// GroupPackageName is the API Group cleaned to be used as the package name.
GroupPackageName string `json:"-"`

// Version is the API version.
Version string `json:"version,omitempty"`

// Kind is the API Kind.
// Kind is the API kind.
Kind string `json:"kind,omitempty"`

// Plural is the API Kind plural form.
// Plural is the API kind plural form.
Plural string `json:"plural,omitempty"`

// ImportAlias is a cleaned concatenation of Group and Version.
ImportAlias string `json:"-"`

// Package is the go package of the Resource.
Package string `json:"package,omitempty"`
// Path is the path to the go package where the types are defined.
Path string `json:"path,omitempty"`

// Domain is the Group + "." + Domain of the Resource.
// Domain is the API group domain.
Domain string `json:"domain,omitempty"`

// Namespaced is true if the resource is namespaced.
Namespaced bool `json:"namespaced,omitempty"`
// API holds the information related to the resource API.
API *API `json:"api,omitempty"`

// CRDVersion holds the CustomResourceDefinition API version used for the Resource.
CRDVersion string `json:"crdVersion,omitempty"`
// WebhookVersion holds the {Validating,Mutating}WebhookConfiguration API version used for the Resource.
WebhookVersion string `json:"webhookVersion,omitempty"`
// Controller specifies if a controller has been scaffolded.
Controller bool `json:"controller,omitempty"`

// Webhooks holds the information related to the associated webhooks.
Webhooks *Webhooks `json:"webhooks,omitempty"`
}

// QualifiedGroup returns the fully qualified group name with the available information.
func (r Resource) QualifiedGroup() string {
switch "" {
case r.Domain:
return r.Group
case r.Group:
return r.Domain
default:
return fmt.Sprintf("%s.%s", r.Group, r.Domain)
}
}

// PackageName returns a name valid to be used por go packages.
func (r Resource) PackageName() string {
if r.Group == "" {
return safeImport(r.Domain)
}

return safeImport(r.Group)
}

// ImportAlias returns a identifier usable as an import alias for this resource.
func (r Resource) ImportAlias() string {
if r.Group == "" {
return safeImport(r.Domain + r.Version)
}

return safeImport(r.Group + r.Version)
}

// GVK returns the group-version-kind information to check against tracked resources in the configuration file
Expand All @@ -64,8 +89,8 @@ func (r *Resource) GVK() config.GVK {
Group: r.Group,
Version: r.Version,
Kind: r.Kind,
CRDVersion: r.CRDVersion,
WebhookVersion: r.WebhookVersion,
CRDVersion: r.API.Version,
WebhookVersion: r.Webhooks.Version,
}
}

Expand All @@ -78,10 +103,37 @@ func (r Resource) Replacer() *strings.Replacer {
var replacements []string

replacements = append(replacements, wrapKey("group"), r.Group)
replacements = append(replacements, wrapKey("group-package-name"), r.GroupPackageName)
replacements = append(replacements, wrapKey("version"), r.Version)
replacements = append(replacements, wrapKey("kind"), strings.ToLower(r.Kind))
replacements = append(replacements, wrapKey("plural"), strings.ToLower(r.Plural))
replacements = append(replacements, wrapKey("package-name"), r.PackageName())

return strings.NewReplacer(replacements...)
}

// API holds the information related to the golang type definition and the CRD.
type API struct {
// Version holds the CustomResourceDefinition API version used for the Resource.
Version string `json:"version,omitempty"`

// Namespaced is true if the resource is namespaced.
Namespaced bool `json:"namespaced,omitempty"`

// External specifies if the type definition is located in an external project.
External bool `json:"external,omitempty"`
}

// Webhooks holds the information related to the associated webhooks.
type Webhooks struct {
// Version holds the {Validating,Mutating}WebhookConfiguration API version used for the Resource.
Version string `json:"version,omitempty"`

// Defaulting specifies if a defaulting webhook is associated to the Resource.
Defaulting bool `json:"mutating,omitempty"`

// Validation specifies if a validation webhook is associated to the Resource.
Validation bool `json:"validating,omitempty"`

// Conversion specifies if a conversion webhook is associated to the Resource.
Conversion bool `json:"conversion,omitempty"`
}
Loading

0 comments on commit 6d37b49

Please sign in to comment.