Skip to content

Commit

Permalink
feat: allow customizing generated webhook's name
Browse files Browse the repository at this point in the history
closes #865
  • Loading branch information
davidxia committed Jul 11, 2024
1 parent b07ad66 commit 1006456
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 9 deletions.
106 changes: 97 additions & 9 deletions pkg/webhook/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/sets"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-tools/pkg/genall"
"sigs.k8s.io/controller-tools/pkg/markers"
)
Expand All @@ -42,16 +43,31 @@ const (
)

var (
// ConfigDefinition s a marker for defining Webhook manifests.
// ConfigDefinition is a marker for defining Webhook manifests.
// Call ToWebhook on the value to get a Kubernetes Webhook.
ConfigDefinition = markers.Must(markers.MakeDefinition("kubebuilder:webhook", markers.DescribesPackage, Config{}))
// WebhookConfigDefinition is a marker for defining MutatingWebhookConfiguration or ValidatingWebhookConfiguration manifests.
WebhookConfigDefinition = markers.Must(markers.MakeDefinition("kubebuilder:webhookconfiguration", markers.DescribesPackage, WebhookConfig{}))
)

// supportedWebhookVersions returns currently supported API version of {Mutating,Validating}WebhookConfiguration.
func supportedWebhookVersions() []string {
return []string{defaultWebhookVersion}
}

// +controllertools:marker:generateHelp

type WebhookConfig struct {
// Mutating marks this as a mutating webhook (it's validating only if false)
//
// Mutating webhooks are allowed to change the object in their response,
// and are called *before* all validating webhooks. Mutating webhooks may
// choose to reject an object, similarly to a validating webhook.
Mutating bool
// Name indicates the name of the K8s MutatingWebhookConfiguration or ValidatingWebhookConfiguration object.
Name string `marker:"name,optional"`
}

// +controllertools:marker:generateHelp:category=Webhook

// Config specifies how a webhook should be served.
Expand Down Expand Up @@ -154,6 +170,32 @@ func verbToAPIVariant(verbRaw string) admissionregv1.OperationType {
}
}

// ToMutatingWebhookConfiguration converts this WebhookConfig to its Kubernetes API form.
func (c WebhookConfig) ToMutatingWebhookConfiguration() (admissionregv1.MutatingWebhookConfiguration, error) {
if !c.Mutating {
return admissionregv1.MutatingWebhookConfiguration{}, fmt.Errorf("%s is a validating webhook", c.Name)
}

return admissionregv1.MutatingWebhookConfiguration{
ObjectMeta: metav1.ObjectMeta{
Name: c.Name,
},
}, nil
}

// ToValidatingWebhookConfiguration converts this WebhookConfig to its Kubernetes API form.
func (c WebhookConfig) ToValidatingWebhookConfiguration() (admissionregv1.ValidatingWebhookConfiguration, error) {
if c.Mutating {
return admissionregv1.ValidatingWebhookConfiguration{}, fmt.Errorf("%s is a mutating webhook", c.Name)
}

return admissionregv1.ValidatingWebhookConfiguration{
ObjectMeta: metav1.ObjectMeta{
Name: c.Name,
},
}, nil
}

// ToMutatingWebhook converts this rule to its Kubernetes API form.
func (c Config) ToMutatingWebhook() (admissionregv1.MutatingWebhook, error) {
if !c.Mutating {
Expand Down Expand Up @@ -362,20 +404,54 @@ func (Generator) RegisterMarkers(into *markers.Registry) error {
if err := into.Register(ConfigDefinition); err != nil {
return err
}
if err := into.Register(WebhookConfigDefinition); err != nil {
return err
}
into.AddHelp(ConfigDefinition, Config{}.Help())
into.AddHelp(WebhookConfigDefinition, Config{}.Help())
return nil
}

func (g Generator) Generate(ctx *genall.GenerationContext) error {
supportedWebhookVersions := supportedWebhookVersions()
mutatingCfgs := make(map[string][]admissionregv1.MutatingWebhook, len(supportedWebhookVersions))
validatingCfgs := make(map[string][]admissionregv1.ValidatingWebhook, len(supportedWebhookVersions))
mutatingWebhookCfgs := make(map[string]admissionregv1.MutatingWebhookConfiguration, len(supportedWebhookVersions))
validatingWebhookCfgs := make(map[string]admissionregv1.ValidatingWebhookConfiguration, len(supportedWebhookVersions))

for _, root := range ctx.Roots {
markerSet, err := markers.PackageMarkers(ctx.Collector, root)
if err != nil {
root.AddError(err)
}

webhookCfgs := markerSet[WebhookConfigDefinition.Name]
sort.SliceStable(webhookCfgs, func(i, j int) bool {
return webhookCfgs[i].(WebhookConfig).Name < webhookCfgs[j].(WebhookConfig).Name
})

for _, webhookCfg := range webhookCfgs {
webhookCfg := webhookCfg.(WebhookConfig)

if webhookCfg.Mutating {
w, err := webhookCfg.ToMutatingWebhookConfiguration()
if err != nil {
return err
}
for _, webhookVersion := range supportedWebhookVersions {
mutatingWebhookCfgs[webhookVersion] = w
}
} else {
w, err := webhookCfg.ToValidatingWebhookConfiguration()
if err != nil {
return err
}
for _, webhookVersion := range supportedWebhookVersions {
validatingWebhookCfgs[webhookVersion] = w
}
}
}

cfgs := markerSet[ConfigDefinition.Name]
sort.SliceStable(cfgs, func(i, j int) bool {
return cfgs[i].(Config).Name < cfgs[j].(Config).Name
Expand Down Expand Up @@ -410,16 +486,22 @@ func (g Generator) Generate(ctx *genall.GenerationContext) error {
versionedWebhooks := make(map[string][]interface{}, len(supportedWebhookVersions))
for _, version := range supportedWebhookVersions {
if cfgs, ok := mutatingCfgs[version]; ok {
// The only possible version in supportedWebhookVersions is v1,
// so use it for all versioned types in this context.
objRaw := &admissionregv1.MutatingWebhookConfiguration{}
var objRaw *admissionregv1.MutatingWebhookConfiguration
if mutatingWebhookCfg, ok := mutatingWebhookCfgs[version]; ok {
objRaw = &mutatingWebhookCfg
} else {
// The only possible version in supportedWebhookVersions is v1,
// so use it for all versioned types in this context.
objRaw = &admissionregv1.MutatingWebhookConfiguration{}
objRaw.SetName("mutating-webhook-configuration")
}
objRaw.SetGroupVersionKind(schema.GroupVersionKind{
Group: admissionregv1.SchemeGroupVersion.Group,
Version: version,
Kind: "MutatingWebhookConfiguration",
})
objRaw.SetName("mutating-webhook-configuration")
objRaw.Webhooks = cfgs

for i := range objRaw.Webhooks {
// SideEffects is required in admissionregistration/v1, if this is not set or set to `Some` or `Known`,
// return an error
Expand All @@ -441,16 +523,22 @@ func (g Generator) Generate(ctx *genall.GenerationContext) error {
}

if cfgs, ok := validatingCfgs[version]; ok {
// The only possible version in supportedWebhookVersions is v1,
// so use it for all versioned types in this context.
objRaw := &admissionregv1.ValidatingWebhookConfiguration{}
var objRaw *admissionregv1.ValidatingWebhookConfiguration
if validatingWebhookCfg, ok := validatingWebhookCfgs[version]; ok {
objRaw = &validatingWebhookCfg
} else {
// The only possible version in supportedWebhookVersions is v1,
// so use it for all versioned types in this context.
objRaw = &admissionregv1.ValidatingWebhookConfiguration{}
objRaw.SetName("validating-webhook-configuration")
}
objRaw.SetGroupVersionKind(schema.GroupVersionKind{
Group: admissionregv1.SchemeGroupVersion.Group,
Version: version,
Kind: "ValidatingWebhookConfiguration",
})
objRaw.SetName("validating-webhook-configuration")
objRaw.Webhooks = cfgs

for i := range objRaw.Webhooks {
// SideEffects is required in admissionregistration/v1, if this is not set or set to `Some` or `Known`,
// return an error
Expand Down
20 changes: 20 additions & 0 deletions pkg/webhook/zz_generated.markerhelp.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 1006456

Please sign in to comment.