Skip to content

Commit

Permalink
Merge pull request #4203 from camilamacedo86/webhooks-core-types
Browse files Browse the repository at this point in the history
✨ Add support to scaffold controllers for External Types
  • Loading branch information
k8s-ci-robot authored Oct 18, 2024
2 parents bde03b7 + 1be2b8b commit 891df0b
Show file tree
Hide file tree
Showing 22 changed files with 743 additions and 6 deletions.
8 changes: 8 additions & 0 deletions docs/book/src/reference/using_an_external_resource.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ Also, the RBAC role:
This scaffolds a controller for the external type but skips creating new resource
definitions since the type is defined in an external project.

### Creating a Webhook to Manage an External Type

Following an example:

```shell
kubebuilder create webhook --group certmanager --version v1 --kind Issuer --defaulting --programmatic-validation --external-api-path=github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1 --external-api-domain=cert-manager.io
```

## Managing Core Types

Core Kubernetes API types, such as `Pods`, `Services`, and `Deployments`, are predefined by Kubernetes.
Expand Down
11 changes: 8 additions & 3 deletions pkg/plugins/common/kustomize/v2/scaffolds/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func (s *webhookScaffolder) Scaffold() error {
return fmt.Errorf("error updating resource: %w", err)
}

if err := scaffold.Execute(
buildScaffold := []machinery.Builder{
&kdefault.ManagerWebhookPatch{},
&webhook.Kustomization{Force: s.force},
&webhook.KustomizeConfig{},
Expand All @@ -84,8 +84,13 @@ func (s *webhookScaffolder) Scaffold() error {
&patches.EnableWebhookPatch{},
&patches.EnableCAInjectionPatch{},
&network_policy.NetworkPolicyAllowWebhooks{},
&crd.Kustomization{},
); err != nil {
}

if !s.resource.External {
buildScaffold = append(buildScaffold, &crd.Kustomization{})
}

if err := scaffold.Execute(buildScaffold...); err != nil {
return fmt.Errorf("error scaffolding kustomize webhook manifests: %v", err)
}

Expand Down
32 changes: 29 additions & 3 deletions pkg/plugins/golang/v4/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package v4

import (
"errors"
"fmt"

"github.com/spf13/pflag"
Expand Down Expand Up @@ -82,6 +83,14 @@ func (p *createWebhookSubcommand) BindFlags(fs *pflag.FlagSet) {
"[DEPRECATED] Attempts to create resource under the API directory (legacy path). "+
"This option will be removed in future versions.")

fs.StringVar(&p.options.ExternalAPIPath, "external-api-path", "",
"Specify the Go package import path for the external API. This is used to scaffold controllers for resources "+
"defined outside this project (e.g., github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1).")

fs.StringVar(&p.options.ExternalAPIDomain, "external-api-domain", "",
"Specify the domain name for the external API. This domain is used to generate accurate RBAC "+
"markers and permissions for the external resources (e.g., cert-manager.io).")

fs.BoolVar(&p.force, "force", false,
"attempt to create resource even if it already exists")
}
Expand All @@ -94,6 +103,19 @@ func (p *createWebhookSubcommand) InjectConfig(c config.Config) error {
func (p *createWebhookSubcommand) InjectResource(res *resource.Resource) error {
p.resource = res

// Ensure that if any external API flag is set, both must be provided.
if len(p.options.ExternalAPIPath) != 0 || len(p.options.ExternalAPIDomain) != 0 {
if len(p.options.ExternalAPIPath) == 0 || len(p.options.ExternalAPIDomain) == 0 {
return errors.New("Both '--external-api-path' and '--external-api-domain' must be " +
"specified together when referencing an external API.")
}
}

if len(p.options.ExternalAPIPath) != 0 && len(p.options.ExternalAPIDomain) != 0 && p.isLegacyPath {
return errors.New("You cannot scaffold webhooks for external types " +
"using the legacy path")
}

p.options.UpdateResource(p.resource, p.config)

if err := p.resource.Validate(); err != nil {
Expand All @@ -106,9 +128,13 @@ func (p *createWebhookSubcommand) InjectResource(res *resource.Resource) error {
}

// check if resource exist to create webhook
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 {
resValue, err := p.config.GetResource(p.resource.GVK)
res = &resValue
if err != nil {
if !p.resource.External {
return fmt.Errorf("%s create webhook requires a previously created API ", p.commandName)
}
} else if res.Webhooks != nil && !res.Webhooks.IsEmpty() && !p.force {
return fmt.Errorf("webhook resource already exists")
}

Expand Down
4 changes: 4 additions & 0 deletions test/testdata/generate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ function scaffold_test_project {
$kb create webhook --group crew --version v1 --kind Admiral --plural=admirales --defaulting
# Controller for External types
$kb create api --group certmanager --version v1 --kind Certificate --controller=true --resource=false --make=false --external-api-path=github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1 --external-api-domain=cert-manager.io
# Webhook for External types
$kb create webhook --group certmanager --version v1 --kind Issuer --defaulting --external-api-path=github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1 --external-api-domain=cert-manager.io
fi

if [[ $project =~ multigroup ]]; then
Expand All @@ -73,6 +75,8 @@ function scaffold_test_project {
$kb create api --group fiz --version v1 --kind Bar --controller=true --resource=true --make=false
# Controller for External types
$kb create api --group certmanager --version v1 --kind Certificate --controller=true --resource=false --make=false --external-api-path=github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1 --external-api-domain=cert-manager.io
# Webhook for External types
$kb create webhook --group certmanager --version v1 --kind Issuer --defaulting --programmatic-validation --external-api-path=github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1 --external-api-domain=cert-manager.io
fi

if [[ $project =~ multigroup ]] || [[ $project =~ with-plugins ]] ; then
Expand Down
10 changes: 10 additions & 0 deletions testdata/project-v4-multigroup/PROJECT
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,16 @@ resources:
kind: Certificate
path: github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1
version: v1
- domain: cert-manager.io
external: true
group: certmanager
kind: Issuer
path: github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1
version: v1
webhooks:
defaulting: true
validation: true
webhookVersion: v1
- api:
crdVersion: v1
namespaced: true
Expand Down
8 changes: 8 additions & 0 deletions testdata/project-v4-multigroup/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import (
foopolicycontroller "sigs.k8s.io/kubebuilder/testdata/project-v4-multigroup/internal/controller/foo.policy"
seacreaturescontroller "sigs.k8s.io/kubebuilder/testdata/project-v4-multigroup/internal/controller/sea-creatures"
shipcontroller "sigs.k8s.io/kubebuilder/testdata/project-v4-multigroup/internal/controller/ship"
webhookcertmanagerv1 "sigs.k8s.io/kubebuilder/testdata/project-v4-multigroup/internal/webhook/certmanager/v1"
webhookcrewv1 "sigs.k8s.io/kubebuilder/testdata/project-v4-multigroup/internal/webhook/crew/v1"
webhookexamplecomv1alpha1 "sigs.k8s.io/kubebuilder/testdata/project-v4-multigroup/internal/webhook/example.com/v1alpha1"
webhookshipv1 "sigs.k8s.io/kubebuilder/testdata/project-v4-multigroup/internal/webhook/ship/v1"
Expand Down Expand Up @@ -283,6 +284,13 @@ func main() {
setupLog.Error(err, "unable to create controller", "controller", "Certificate")
os.Exit(1)
}
// nolint:goconst
if os.Getenv("ENABLE_WEBHOOKS") != "false" {
if err = webhookcertmanagerv1.SetupIssuerWebhookWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create webhook", "webhook", "Issuer")
os.Exit(1)
}
}
if err = (&examplecomcontroller.MemcachedReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# The following patch adds a directive for certmanager to inject CA into the CRD
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME
name: issuers.certmanager.cert-manager.io
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# The following patch enables a conversion webhook for the CRD
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: issuers.certmanager.cert-manager.io
spec:
conversion:
strategy: Webhook
webhook:
clientConfig:
service:
namespace: system
name: webhook-service
path: /convert
conversionReviewVersions:
- v1
40 changes: 40 additions & 0 deletions testdata/project-v4-multigroup/config/webhook/manifests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,26 @@ kind: MutatingWebhookConfiguration
metadata:
name: mutating-webhook-configuration
webhooks:
- admissionReviewVersions:
- v1
clientConfig:
service:
name: webhook-service
namespace: system
path: /mutate-certmanager-cert-manager-io-v1-issuer
failurePolicy: Fail
name: missuer-v1.kb.io
rules:
- apiGroups:
- certmanager.cert-manager.io
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- issuers
sideEffects: None
- admissionReviewVersions:
- v1
clientConfig:
Expand Down Expand Up @@ -50,6 +70,26 @@ kind: ValidatingWebhookConfiguration
metadata:
name: validating-webhook-configuration
webhooks:
- admissionReviewVersions:
- v1
clientConfig:
service:
name: webhook-service
namespace: system
path: /validate-certmanager-cert-manager-io-v1-issuer
failurePolicy: Fail
name: vissuer-v1.kb.io
rules:
- apiGroups:
- certmanager.cert-manager.io
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- issuers
sideEffects: None
- admissionReviewVersions:
- v1
clientConfig:
Expand Down
40 changes: 40 additions & 0 deletions testdata/project-v4-multigroup/dist/install.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1814,6 +1814,26 @@ kind: MutatingWebhookConfiguration
metadata:
name: project-v4-multigroup-mutating-webhook-configuration
webhooks:
- admissionReviewVersions:
- v1
clientConfig:
service:
name: project-v4-multigroup-webhook-service
namespace: project-v4-multigroup-system
path: /mutate-certmanager-cert-manager-io-v1-issuer
failurePolicy: Fail
name: missuer-v1.kb.io
rules:
- apiGroups:
- certmanager.cert-manager.io
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- issuers
sideEffects: None
- admissionReviewVersions:
- v1
clientConfig:
Expand Down Expand Up @@ -1860,6 +1880,26 @@ kind: ValidatingWebhookConfiguration
metadata:
name: project-v4-multigroup-validating-webhook-configuration
webhooks:
- admissionReviewVersions:
- v1
clientConfig:
service:
name: project-v4-multigroup-webhook-service
namespace: project-v4-multigroup-system
path: /validate-certmanager-cert-manager-io-v1-issuer
failurePolicy: Fail
name: vissuer-v1.kb.io
rules:
- apiGroups:
- certmanager.cert-manager.io
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- issuers
sideEffects: None
- admissionReviewVersions:
- v1
clientConfig:
Expand Down
Loading

0 comments on commit 891df0b

Please sign in to comment.