Skip to content

Commit 891df0b

Browse files
authored
Merge pull request #4203 from camilamacedo86/webhooks-core-types
✨ Add support to scaffold controllers for External Types
2 parents bde03b7 + 1be2b8b commit 891df0b

File tree

22 files changed

+743
-6
lines changed

22 files changed

+743
-6
lines changed

docs/book/src/reference/using_an_external_resource.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,14 @@ Also, the RBAC role:
7373
This scaffolds a controller for the external type but skips creating new resource
7474
definitions since the type is defined in an external project.
7575

76+
### Creating a Webhook to Manage an External Type
77+
78+
Following an example:
79+
80+
```shell
81+
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
82+
```
83+
7684
## Managing Core Types
7785

7886
Core Kubernetes API types, such as `Pods`, `Services`, and `Deployments`, are predefined by Kubernetes.

pkg/plugins/common/kustomize/v2/scaffolds/webhook.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func (s *webhookScaffolder) Scaffold() error {
7373
return fmt.Errorf("error updating resource: %w", err)
7474
}
7575

76-
if err := scaffold.Execute(
76+
buildScaffold := []machinery.Builder{
7777
&kdefault.ManagerWebhookPatch{},
7878
&webhook.Kustomization{Force: s.force},
7979
&webhook.KustomizeConfig{},
@@ -84,8 +84,13 @@ func (s *webhookScaffolder) Scaffold() error {
8484
&patches.EnableWebhookPatch{},
8585
&patches.EnableCAInjectionPatch{},
8686
&network_policy.NetworkPolicyAllowWebhooks{},
87-
&crd.Kustomization{},
88-
); err != nil {
87+
}
88+
89+
if !s.resource.External {
90+
buildScaffold = append(buildScaffold, &crd.Kustomization{})
91+
}
92+
93+
if err := scaffold.Execute(buildScaffold...); err != nil {
8994
return fmt.Errorf("error scaffolding kustomize webhook manifests: %v", err)
9095
}
9196

pkg/plugins/golang/v4/webhook.go

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package v4
1818

1919
import (
20+
"errors"
2021
"fmt"
2122

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

86+
fs.StringVar(&p.options.ExternalAPIPath, "external-api-path", "",
87+
"Specify the Go package import path for the external API. This is used to scaffold controllers for resources "+
88+
"defined outside this project (e.g., github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1).")
89+
90+
fs.StringVar(&p.options.ExternalAPIDomain, "external-api-domain", "",
91+
"Specify the domain name for the external API. This domain is used to generate accurate RBAC "+
92+
"markers and permissions for the external resources (e.g., cert-manager.io).")
93+
8594
fs.BoolVar(&p.force, "force", false,
8695
"attempt to create resource even if it already exists")
8796
}
@@ -94,6 +103,19 @@ func (p *createWebhookSubcommand) InjectConfig(c config.Config) error {
94103
func (p *createWebhookSubcommand) InjectResource(res *resource.Resource) error {
95104
p.resource = res
96105

106+
// Ensure that if any external API flag is set, both must be provided.
107+
if len(p.options.ExternalAPIPath) != 0 || len(p.options.ExternalAPIDomain) != 0 {
108+
if len(p.options.ExternalAPIPath) == 0 || len(p.options.ExternalAPIDomain) == 0 {
109+
return errors.New("Both '--external-api-path' and '--external-api-domain' must be " +
110+
"specified together when referencing an external API.")
111+
}
112+
}
113+
114+
if len(p.options.ExternalAPIPath) != 0 && len(p.options.ExternalAPIDomain) != 0 && p.isLegacyPath {
115+
return errors.New("You cannot scaffold webhooks for external types " +
116+
"using the legacy path")
117+
}
118+
97119
p.options.UpdateResource(p.resource, p.config)
98120

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

108130
// check if resource exist to create webhook
109-
if r, err := p.config.GetResource(p.resource.GVK); err != nil {
110-
return fmt.Errorf("%s create webhook requires a previously created API ", p.commandName)
111-
} else if r.Webhooks != nil && !r.Webhooks.IsEmpty() && !p.force {
131+
resValue, err := p.config.GetResource(p.resource.GVK)
132+
res = &resValue
133+
if err != nil {
134+
if !p.resource.External {
135+
return fmt.Errorf("%s create webhook requires a previously created API ", p.commandName)
136+
}
137+
} else if res.Webhooks != nil && !res.Webhooks.IsEmpty() && !p.force {
112138
return fmt.Errorf("webhook resource already exists")
113139
}
114140

test/testdata/generate.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ function scaffold_test_project {
4747
$kb create webhook --group crew --version v1 --kind Admiral --plural=admirales --defaulting
4848
# Controller for External types
4949
$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
50+
# Webhook for External types
51+
$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
5052
fi
5153

5254
if [[ $project =~ multigroup ]]; then
@@ -73,6 +75,8 @@ function scaffold_test_project {
7375
$kb create api --group fiz --version v1 --kind Bar --controller=true --resource=true --make=false
7476
# Controller for External types
7577
$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
78+
# Webhook for External types
79+
$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
7680
fi
7781

7882
if [[ $project =~ multigroup ]] || [[ $project =~ with-plugins ]] ; then

testdata/project-v4-multigroup/PROJECT

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,16 @@ resources:
132132
kind: Certificate
133133
path: github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1
134134
version: v1
135+
- domain: cert-manager.io
136+
external: true
137+
group: certmanager
138+
kind: Issuer
139+
path: github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1
140+
version: v1
141+
webhooks:
142+
defaulting: true
143+
validation: true
144+
webhookVersion: v1
135145
- api:
136146
crdVersion: v1
137147
namespaced: true

testdata/project-v4-multigroup/cmd/main.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ import (
5656
foopolicycontroller "sigs.k8s.io/kubebuilder/testdata/project-v4-multigroup/internal/controller/foo.policy"
5757
seacreaturescontroller "sigs.k8s.io/kubebuilder/testdata/project-v4-multigroup/internal/controller/sea-creatures"
5858
shipcontroller "sigs.k8s.io/kubebuilder/testdata/project-v4-multigroup/internal/controller/ship"
59+
webhookcertmanagerv1 "sigs.k8s.io/kubebuilder/testdata/project-v4-multigroup/internal/webhook/certmanager/v1"
5960
webhookcrewv1 "sigs.k8s.io/kubebuilder/testdata/project-v4-multigroup/internal/webhook/crew/v1"
6061
webhookexamplecomv1alpha1 "sigs.k8s.io/kubebuilder/testdata/project-v4-multigroup/internal/webhook/example.com/v1alpha1"
6162
webhookshipv1 "sigs.k8s.io/kubebuilder/testdata/project-v4-multigroup/internal/webhook/ship/v1"
@@ -283,6 +284,13 @@ func main() {
283284
setupLog.Error(err, "unable to create controller", "controller", "Certificate")
284285
os.Exit(1)
285286
}
287+
// nolint:goconst
288+
if os.Getenv("ENABLE_WEBHOOKS") != "false" {
289+
if err = webhookcertmanagerv1.SetupIssuerWebhookWithManager(mgr); err != nil {
290+
setupLog.Error(err, "unable to create webhook", "webhook", "Issuer")
291+
os.Exit(1)
292+
}
293+
}
286294
if err = (&examplecomcontroller.MemcachedReconciler{
287295
Client: mgr.GetClient(),
288296
Scheme: mgr.GetScheme(),
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# The following patch adds a directive for certmanager to inject CA into the CRD
2+
apiVersion: apiextensions.k8s.io/v1
3+
kind: CustomResourceDefinition
4+
metadata:
5+
annotations:
6+
cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME
7+
name: issuers.certmanager.cert-manager.io
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# The following patch enables a conversion webhook for the CRD
2+
apiVersion: apiextensions.k8s.io/v1
3+
kind: CustomResourceDefinition
4+
metadata:
5+
name: issuers.certmanager.cert-manager.io
6+
spec:
7+
conversion:
8+
strategy: Webhook
9+
webhook:
10+
clientConfig:
11+
service:
12+
namespace: system
13+
name: webhook-service
14+
path: /convert
15+
conversionReviewVersions:
16+
- v1

testdata/project-v4-multigroup/config/webhook/manifests.yaml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,26 @@ kind: MutatingWebhookConfiguration
44
metadata:
55
name: mutating-webhook-configuration
66
webhooks:
7+
- admissionReviewVersions:
8+
- v1
9+
clientConfig:
10+
service:
11+
name: webhook-service
12+
namespace: system
13+
path: /mutate-certmanager-cert-manager-io-v1-issuer
14+
failurePolicy: Fail
15+
name: missuer-v1.kb.io
16+
rules:
17+
- apiGroups:
18+
- certmanager.cert-manager.io
19+
apiVersions:
20+
- v1
21+
operations:
22+
- CREATE
23+
- UPDATE
24+
resources:
25+
- issuers
26+
sideEffects: None
727
- admissionReviewVersions:
828
- v1
929
clientConfig:
@@ -50,6 +70,26 @@ kind: ValidatingWebhookConfiguration
5070
metadata:
5171
name: validating-webhook-configuration
5272
webhooks:
73+
- admissionReviewVersions:
74+
- v1
75+
clientConfig:
76+
service:
77+
name: webhook-service
78+
namespace: system
79+
path: /validate-certmanager-cert-manager-io-v1-issuer
80+
failurePolicy: Fail
81+
name: vissuer-v1.kb.io
82+
rules:
83+
- apiGroups:
84+
- certmanager.cert-manager.io
85+
apiVersions:
86+
- v1
87+
operations:
88+
- CREATE
89+
- UPDATE
90+
resources:
91+
- issuers
92+
sideEffects: None
5393
- admissionReviewVersions:
5494
- v1
5595
clientConfig:

testdata/project-v4-multigroup/dist/install.yaml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1814,6 +1814,26 @@ kind: MutatingWebhookConfiguration
18141814
metadata:
18151815
name: project-v4-multigroup-mutating-webhook-configuration
18161816
webhooks:
1817+
- admissionReviewVersions:
1818+
- v1
1819+
clientConfig:
1820+
service:
1821+
name: project-v4-multigroup-webhook-service
1822+
namespace: project-v4-multigroup-system
1823+
path: /mutate-certmanager-cert-manager-io-v1-issuer
1824+
failurePolicy: Fail
1825+
name: missuer-v1.kb.io
1826+
rules:
1827+
- apiGroups:
1828+
- certmanager.cert-manager.io
1829+
apiVersions:
1830+
- v1
1831+
operations:
1832+
- CREATE
1833+
- UPDATE
1834+
resources:
1835+
- issuers
1836+
sideEffects: None
18171837
- admissionReviewVersions:
18181838
- v1
18191839
clientConfig:
@@ -1860,6 +1880,26 @@ kind: ValidatingWebhookConfiguration
18601880
metadata:
18611881
name: project-v4-multigroup-validating-webhook-configuration
18621882
webhooks:
1883+
- admissionReviewVersions:
1884+
- v1
1885+
clientConfig:
1886+
service:
1887+
name: project-v4-multigroup-webhook-service
1888+
namespace: project-v4-multigroup-system
1889+
path: /validate-certmanager-cert-manager-io-v1-issuer
1890+
failurePolicy: Fail
1891+
name: vissuer-v1.kb.io
1892+
rules:
1893+
- apiGroups:
1894+
- certmanager.cert-manager.io
1895+
apiVersions:
1896+
- v1
1897+
operations:
1898+
- CREATE
1899+
- UPDATE
1900+
resources:
1901+
- issuers
1902+
sideEffects: None
18631903
- admissionReviewVersions:
18641904
- v1
18651905
clientConfig:

0 commit comments

Comments
 (0)