Skip to content

Commit

Permalink
Add url marker for webhook manifests
Browse files Browse the repository at this point in the history
  • Loading branch information
rikatz committed Jun 16, 2023
1 parent 89530d9 commit 6ea883f
Show file tree
Hide file tree
Showing 5 changed files with 259 additions and 0 deletions.
17 changes: 17 additions & 0 deletions pkg/webhook/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,13 @@ type Config struct {
// an object, and mutating webhooks can specify a reinvocationPolicy to control
// whether they are reinvoked as well.
ReinvocationPolicy string `marker:"reinvocationPolicy,optional"`

// URL allows mutating webhooks configuration to specify an external URL when generating
// the manifests, instead of using the internal service communication. Should be in format of
// https://address:port/ and will have the path specified on Path field appended to it.
// When this option is specified, the serviceConfig.Service is removed from webhook the manifest.
// The URL configuration should be between quotes
URL string `marker:"url,optional"`
}

// verbToAPIVariant converts a marker's verb to the proper value for the API.
Expand Down Expand Up @@ -253,6 +260,16 @@ func (c Config) matchPolicy() (*admissionregv1.MatchPolicyType, error) {
// clientConfig returns the client config for a webhook.
func (c Config) clientConfig() admissionregv1.WebhookClientConfig {
path := c.Path

if c.URL != "" {
var url string
path = strings.TrimPrefix(c.Path, "/")
url = fmt.Sprintf("%s/%s", c.URL, path)
return admissionregv1.WebhookClientConfig{
URL: &url,
}
}

return admissionregv1.WebhookClientConfig{
Service: &admissionregv1.ServiceReference{
Name: "webhook-service",
Expand Down
45 changes: 45 additions & 0 deletions pkg/webhook/parser_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,51 @@ var _ = Describe("Webhook Generation From Parsing to CustomResourceDefinition",
assertSame(actualManifest, expectedManifest)
}
})

It("should properly generate the webhook definition with url instead of service", func() {
By("switching into testdata to appease go modules")
cwd, err := os.Getwd()
Expect(err).NotTo(HaveOccurred())
Expect(os.Chdir("./testdata/valid-url")).To(Succeed()) // go modules are directory-sensitive
defer func() { Expect(os.Chdir(cwd)).To(Succeed()) }()

By("loading the roots")
pkgs, err := loader.LoadRoots(".")
Expect(err).NotTo(HaveOccurred())
Expect(pkgs).To(HaveLen(1))

By("setting up the parser")
reg := &markers.Registry{}
Expect(reg.Register(webhook.ConfigDefinition)).To(Succeed())

By("requesting that the manifest be generated")
outputDir, err := ioutil.TempDir("", "webhook-integration-test")
Expect(err).NotTo(HaveOccurred())
defer os.RemoveAll(outputDir)
genCtx := &genall.GenerationContext{
Collector: &markers.Collector{Registry: reg},
Roots: pkgs,
OutputRule: genall.OutputToDirectory(outputDir),
}
Expect(webhook.Generator{}.Generate(genCtx)).To(Succeed())
for _, r := range genCtx.Roots {
Expect(r.Errors).To(HaveLen(0))
}

By("loading the generated v1 YAML")
actualFile, err := ioutil.ReadFile(path.Join(outputDir, "manifests.yaml"))
Expect(err).NotTo(HaveOccurred())
actualMutating, actualValidating := unmarshalBothV1(actualFile)

By("loading the desired v1 YAML")
expectedFile, err := ioutil.ReadFile("manifests.yaml")
Expect(err).NotTo(HaveOccurred())
expectedMutating, expectedValidating := unmarshalBothV1(expectedFile)

By("comparing the two")
assertSame(actualMutating, expectedMutating)
assertSame(actualValidating, expectedValidating)
})
})

func unmarshalBothV1(in []byte) (mutating admissionregv1.MutatingWebhookConfiguration, validating admissionregv1.ValidatingWebhookConfiguration) {
Expand Down
71 changes: 71 additions & 0 deletions pkg/webhook/testdata/valid-url/cronjob_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

//go:generate ../../../../.run-controller-gen.sh webhook paths=. output:dir=.

// +groupName=testdata.kubebuilder.io
// +versionName=v1
package cronjob

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.

// CronJobSpec defines the desired state of CronJob
type CronJobSpec struct {
// The schedule in Cron format, see https://en.wikipedia.org/wiki/Cron.
Schedule string `json:"schedule"`
}

// CronJobStatus defines the observed state of CronJob
type CronJobStatus struct {
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
// Important: Run "make" to regenerate code after modifying this file

// Information when was the last time the job was successfully scheduled.
// +optional
LastScheduleTime *metav1.Time `json:"lastScheduleTime,omitempty"`
}

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:resource:singular=mycronjob

// CronJob is the Schema for the cronjobs API
type CronJob struct {
/*
*/
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

Spec CronJobSpec `json:"spec,omitempty"`
Status CronJobStatus `json:"status,omitempty"`
}

// +kubebuilder:object:root=true

// CronJobList contains a list of CronJob
type CronJobList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []CronJob `json:"items"`
}

func init() {
SchemeBuilder.Register(&CronJob{}, &CronJobList{})
}
76 changes: 76 additions & 0 deletions pkg/webhook/testdata/valid-url/manifests.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
---
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
name: mutating-webhook-configuration
webhooks:
- admissionReviewVersions:
- v1
- v1beta1
clientConfig:
service:
name: webhook-service
namespace: system
path: /mutate-testdata-kubebuilder-io-v1-cronjob
failurePolicy: Fail
matchPolicy: Equivalent
name: default.cronjob.testdata.kubebuilder.io
rules:
- apiGroups:
- testdata.kubebuiler.io
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- cronjobs
sideEffects: None
timeoutSeconds: 10
reinvocationPolicy: IfNeeded
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: validating-webhook-configuration
webhooks:
- admissionReviewVersions:
- v1
- v1beta1
clientConfig:
url: https://somewebhook:9443/validate-testdata-kubebuilder-io-v1-cronjob
failurePolicy: Fail
matchPolicy: Equivalent
name: validation.cronjob.testdata.kubebuilder.io
rules:
- apiGroups:
- testdata.kubebuiler.io
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- cronjobs
sideEffects: None
timeoutSeconds: 10
- admissionReviewVersions:
- v1
- v1beta1
clientConfig:
url: https://anothersomewebhook:9443/validate-testdata-kubebuilder-io-v1-cronjob
failurePolicy: Fail
matchPolicy: Equivalent
name: validation.cronjob.testdata.kubebuilder.io
rules:
- apiGroups:
- testdata.kubebuiler.io
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- cronjobs
sideEffects: NoneOnDryRun
timeoutSeconds: 10
50 changes: 50 additions & 0 deletions pkg/webhook/testdata/valid-url/webhook.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cronjob

import (
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/webhook"
)

func (c *CronJob) SetupWebhookWithManager(mgr ctrl.Manager) error {
return ctrl.NewWebhookManagedBy(mgr).
For(c).
Complete()
}

// +kubebuilder:webhook:webhookVersions=v1,verbs=create;update,path=/validate-testdata-kubebuilder-io-v1-cronjob,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=validation.cronjob.testdata.kubebuilder.io,sideEffects=None,timeoutSeconds=10,admissionReviewVersions=v1;v1beta1,url="https://somewebhook:9443"
// +kubebuilder:webhook:url="https://anothersomewebhook:9443",verbs=create;update,path=/validate-testdata-kubebuilder-io-v1-cronjob,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=validation.cronjob.testdata.kubebuilder.io,sideEffects=NoneOnDryRun,timeoutSeconds=10,admissionReviewVersions=v1;v1beta1
// +kubebuilder:webhook:webhookVersions=v1,verbs=create;update,path=/mutate-testdata-kubebuilder-io-v1-cronjob,mutating=true,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=default.cronjob.testdata.kubebuilder.io,sideEffects=None,timeoutSeconds=10,admissionReviewVersions=v1;v1beta1,reinvocationPolicy=IfNeeded

var _ webhook.Defaulter = &CronJob{}
var _ webhook.Validator = &CronJob{}

func (c *CronJob) Default() {
}

func (c *CronJob) ValidateCreate() error {
return nil
}

func (c *CronJob) ValidateUpdate(_ runtime.Object) error {
return nil
}

func (c *CronJob) ValidateDelete() error {
return nil
}

0 comments on commit 6ea883f

Please sign in to comment.