Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ require (
github.com/onsi/gomega v1.8.1
github.com/openshift/api v0.0.0-20200526144822-34f54f12813a
github.com/openshift/client-go v0.0.0-20200521150516-05eb9880269c // indirect
github.com/openshift/cluster-api-provider-gcp v0.0.1-0.20200618110630-09cef98ae787
github.com/openshift/cluster-api-provider-gcp v0.0.1-0.20200701112720-3a7d727c9a10
github.com/openshift/cluster-autoscaler-operator v0.0.0-20190627103136-350eb7249737
github.com/openshift/library-go v0.0.0-20200512120242-21a1ff978534
github.com/openshift/machine-api-operator v0.2.1-0.20200611014855-9a69f85c32dd
github.com/openshift/machine-api-operator v0.2.1-0.20200716183840-c9a1f7584b4b
k8s.io/api v0.18.3
k8s.io/apimachinery v0.18.3
k8s.io/client-go v0.18.3
Expand Down
8 changes: 6 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -346,14 +346,16 @@ github.com/openshift/cluster-api-provider-aws v0.2.1-0.20200618031251-e16dd65fdd
github.com/openshift/cluster-api-provider-aws v0.2.1-0.20200618031251-e16dd65fdd85/go.mod h1:FxIU+vzZ4b5A7kGKootyJeTI3xafRTljVJF7/+4Iz4s=
github.com/openshift/cluster-api-provider-azure v0.1.0-alpha.3.0.20200620092221-ff90663025f1 h1:6vdftjpQCXgwnr9DDzWulKhqzpanJn6a73wXbIAX3xI=
github.com/openshift/cluster-api-provider-azure v0.1.0-alpha.3.0.20200620092221-ff90663025f1/go.mod h1:8vKZivzPGX/U1Tb/VSTrso1edG+4U35+betP72fGKf0=
github.com/openshift/cluster-api-provider-gcp v0.0.1-0.20200618110630-09cef98ae787 h1:B2o/NlzkKoByS26kgCv3PIgTxhJ1w5p6USmeZSPCmYQ=
github.com/openshift/cluster-api-provider-gcp v0.0.1-0.20200618110630-09cef98ae787/go.mod h1:wgkZrOlcIMWTzo8khB4Js2PoDJDlIUUdzCBm7BuDdqw=
github.com/openshift/cluster-api-provider-gcp v0.0.1-0.20200701112720-3a7d727c9a10 h1:AZczulAAkBuMm058BGtk5id9lhupszVQXvZFdKmSHEE=
github.com/openshift/cluster-api-provider-gcp v0.0.1-0.20200701112720-3a7d727c9a10/go.mod h1:wgkZrOlcIMWTzo8khB4Js2PoDJDlIUUdzCBm7BuDdqw=
github.com/openshift/cluster-autoscaler-operator v0.0.0-20190627103136-350eb7249737 h1:9H+z/IHRxNcr3AAS9TJpgLB+Jq31oAXK6pSbQ9zFVtU=
github.com/openshift/cluster-autoscaler-operator v0.0.0-20190627103136-350eb7249737/go.mod h1:/XmV44Fh28Vo3Ye93qFrxAbcFJ/Uy+7LPD+jGjmfJYc=
github.com/openshift/library-go v0.0.0-20200512120242-21a1ff978534 h1:RhurNEKr5RBIcnddxfoLVuB86TZRdNq8PH51/1ZAxv4=
github.com/openshift/library-go v0.0.0-20200512120242-21a1ff978534/go.mod h1:2kWwXTkpoQJUN3jZ3QW88EIY1hdRMqxgRs2hheEW/pg=
github.com/openshift/machine-api-operator v0.2.1-0.20200611014855-9a69f85c32dd h1:DSKbDT7nkLuoidsw0MAXjVaSZULy/alBARdN0/VV4OU=
github.com/openshift/machine-api-operator v0.2.1-0.20200611014855-9a69f85c32dd/go.mod h1:6vMi+R3xqznBdq5rgeal9N3ak3sOpy50t0fdRCcQXjE=
github.com/openshift/machine-api-operator v0.2.1-0.20200716183840-c9a1f7584b4b h1:IUvIzdwmsMXRegVUACv0eMi8YnhIeeUZlODgxEfS5n8=
github.com/openshift/machine-api-operator v0.2.1-0.20200716183840-c9a1f7584b4b/go.mod h1:qJEyw9X55AQOYTofkS/9sCCiWua29iL8QJk+OQXhIyw=
github.com/operator-framework/operator-sdk v0.5.1-0.20190301204940-c2efe6f74e7b/go.mod h1:iVyukRkam5JZa8AnjYf+/G3rk7JI1+M6GsU0sq0B9NA=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
Expand Down Expand Up @@ -513,6 +515,8 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
Expand Down
160 changes: 160 additions & 0 deletions pkg/framework/webhooks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
package framework

import (
"context"
"fmt"

mapiv1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1"
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
"k8s.io/apimachinery/pkg/api/equality"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/klog"
"sigs.k8s.io/controller-runtime/pkg/client"
)

// DefaultValidatingWebhookConfiguration is a default validating webhook configuration resource provided by MAO
var DefaultValidatingWebhookConfiguration = mapiv1.NewValidatingWebhookConfiguration()

// DefaultMutatingWebhookConfiguration is a default mutating webhook configuration resource provided by MAO
var DefaultMutatingWebhookConfiguration = mapiv1.NewMutatingWebhookConfiguration()

// GetMutatingWebhookConfiguration gets MutatingWebhookConfiguration object by name
func GetMutatingWebhookConfiguration(c client.Client, name string) (*admissionregistrationv1.MutatingWebhookConfiguration, error) {
key := client.ObjectKey{Name: name}
existing := &admissionregistrationv1.MutatingWebhookConfiguration{}

if err := wait.PollImmediate(RetryShort, WaitShort, func() (bool, error) {
if err := c.Get(context.TODO(), key, existing); err != nil {
klog.Errorf("Error querying api for MutatingWebhookConfiguration object %q: %v, retrying...", name, err)
return false, nil
}
return true, nil
}); err != nil {
return nil, fmt.Errorf("error getting MutatingWebhookConfiguration %q: %v", name, err)
}
return existing, nil
}

// GetValidatingWebhookConfiguration gets ValidatingWebhookConfiguration object by name
func GetValidatingWebhookConfiguration(c client.Client, name string) (*admissionregistrationv1.ValidatingWebhookConfiguration, error) {
key := client.ObjectKey{Name: name}
existing := &admissionregistrationv1.ValidatingWebhookConfiguration{}

if err := wait.PollImmediate(RetryShort, WaitShort, func() (bool, error) {
if err := c.Get(context.TODO(), key, existing); err != nil {
klog.Errorf("Error querying api for ValidatingWebhookConfiguration object %q: %v, retrying...", name, err)
return false, nil
}
return true, nil
}); err != nil {
return nil, fmt.Errorf("error getting ValidatingWebhookConfiguration %q: %v", name, err)
}
return existing, nil
}

// DeleteValidatingWebhookConfiguration deletes the specified ValidatingWebhookConfiguration object
func DeleteValidatingWebhookConfiguration(c client.Client, webhookConfiguraiton *admissionregistrationv1.ValidatingWebhookConfiguration) error {
return wait.PollImmediate(RetryShort, WaitShort, func() (bool, error) {
if err := c.Delete(context.TODO(), webhookConfiguraiton); apierrors.IsNotFound(err) {
return true, nil
} else if err != nil {
klog.Errorf("error querying api for ValidatingWebhookConfiguration object %q: %v, retrying...", webhookConfiguraiton.Name, err)
return false, nil
}
return true, nil
})
}

// DeleteMutatingWebhookConfiguration deletes the specified MutatingWebhookConfiguration object
func DeleteMutatingWebhookConfiguration(c client.Client, webhookConfiguraiton *admissionregistrationv1.MutatingWebhookConfiguration) error {
return wait.PollImmediate(RetryShort, WaitShort, func() (bool, error) {
if err := c.Delete(context.TODO(), webhookConfiguraiton); apierrors.IsNotFound(err) {
return true, nil
} else if err != nil {
klog.Errorf("error querying api for MutatingWebhookConfiguration object %q: %v, retrying...", webhookConfiguraiton.Name, err)
return false, nil
}
return true, nil
})
}

// UpdateMutatingWebhookConfiguration updates the specified mutating webhook configuration
func UpdateMutatingWebhookConfiguration(c client.Client, updated *admissionregistrationv1.MutatingWebhookConfiguration) error {
return wait.PollImmediate(RetryShort, WaitShort, func() (bool, error) {
existing, err := GetMutatingWebhookConfiguration(c, updated.Name)
if err != nil {
klog.Errorf("Error getting MutatingWebhookConfiguration: %v", err)
return false, nil
}
if err := c.Patch(context.TODO(), existing, client.MergeFrom(updated)); err != nil {
klog.Errorf("error patching MutatingWebhookConfiguration object %q: %v, retrying...", updated.Name, err)
return false, nil
}
return true, nil
})
}

// UpdateValidatingWebhookConfiguration updates the specified mutating webhook configuration
func UpdateValidatingWebhookConfiguration(c client.Client, updated *admissionregistrationv1.ValidatingWebhookConfiguration) error {
return wait.PollImmediate(RetryShort, WaitShort, func() (bool, error) {
existing, err := GetValidatingWebhookConfiguration(c, updated.Name)
if err != nil {
klog.Errorf("Error getting ValidatingWebhookConfiguration: %v", err)
return false, nil
}
if err := c.Patch(context.TODO(), existing, client.MergeFrom(updated)); err != nil {
klog.Errorf("error patching ValidatingWebhookConfiguration object %q: %v, retrying...", updated.Name, err)
return false, nil
}
return true, nil
})
}

// IsMutatingWebhookConfigurationSynced expects a matching MutatingWebhookConfiguration to be present in the cluster
func IsMutatingWebhookConfigurationSynced(c client.Client) bool {
if err := wait.PollImmediate(RetryShort, WaitMedium, func() (bool, error) {
existing, err := GetMutatingWebhookConfiguration(c, DefaultMutatingWebhookConfiguration.Name)
if err != nil {
klog.Errorf("Error getting MutatingWebhookConfiguration: %v", err)
return false, nil
}

// Due to caBundle injection by service-ca-operator, we have to use DeepDerivative,
// which will ignore change in spec.webhooks[x].serviceReference.caBundle in comparison
// to empty value, as the default webhook configuration does not have this field set
equal := equality.Semantic.DeepDerivative(DefaultMutatingWebhookConfiguration.Webhooks, existing.Webhooks)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be worth a note that this will should the CABundle field that has been set by the injector and that's why we are using DeepDerivative

if !equal {
klog.Infof("MutatingWebhookConfiguration is not yet equal, retrying...")
}
return equal, nil
}); err != nil {
klog.Errorf("Error waiting for match with expected MutatingWebhookConfigurationMatched: %v", err)
return false
}
return true
}

// IsValidatingWebhookConfigurationSynced expects a matching MutatingWebhookConfiguration to be present in the cluster
func IsValidatingWebhookConfigurationSynced(c client.Client) bool {
if err := wait.PollImmediate(RetryShort, WaitMedium, func() (bool, error) {
existing, err := GetValidatingWebhookConfiguration(c, DefaultValidatingWebhookConfiguration.Name)
if err != nil {
klog.Errorf("Error getting MutatingWebhookConfiguration: %v", err)
return false, nil
}

// Due to caBundle injection by service-ca-operator, we have to use DeepDerivative,
// which will ignore change in spec.webhooks[x].serviceReference.caBundle in comparison
// to empty value, as the default webhook configuration does not have this field set
equal := equality.Semantic.DeepDerivative(DefaultValidatingWebhookConfiguration.Webhooks, existing.Webhooks)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be worth a note that this will should the CABundle field that has been set by the injector and that's why we are using DeepDerivative

if !equal {
klog.Infof("ValidatingWebhookConfiguration is not yet equal, retrying...")
}
return equal, nil
}); err != nil {
klog.Errorf("Error waiting for match with expected ValidatingWebhookConfigurationMatched: %v", err)
return false
}
return true
}
88 changes: 88 additions & 0 deletions pkg/operators/machine-api-operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ var (
maoDeployment = "machine-api-operator"
maoManagedDeployment = "machine-api-controllers"
)

var _ = Describe("[Feature:Operators] Machine API operator deployment should", func() {
defer GinkgoRecover()

Expand Down Expand Up @@ -65,6 +66,93 @@ var _ = Describe("[Feature:Operators] Machine API operator deployment should", f
Expect(framework.IsDeploymentAvailable(client, maoManagedDeployment, framework.MachineAPINamespace)).To(BeTrue())

})

It("reconcile mutating webhook configuration", func() {
client, err := framework.LoadClient()
Expect(err).NotTo(HaveOccurred())

Expect(framework.IsMutatingWebhookConfigurationSynced(client)).To(BeTrue())
})

It("reconcile validating webhook configuration", func() {
client, err := framework.LoadClient()
Expect(err).NotTo(HaveOccurred())

Expect(framework.IsValidatingWebhookConfigurationSynced(client)).To(BeTrue())
})

It("recover after validating webhook configuration deletion", func() {
client, err := framework.LoadClient()
Expect(err).NotTo(HaveOccurred())

Expect(framework.DeleteValidatingWebhookConfiguration(client, framework.DefaultValidatingWebhookConfiguration)).To(Succeed())

Expect(framework.IsValidatingWebhookConfigurationSynced(client)).To(BeTrue())
})

It("recover after mutating webhook configuration deletion", func() {
client, err := framework.LoadClient()
Expect(err).NotTo(HaveOccurred())

Expect(framework.DeleteMutatingWebhookConfiguration(client, framework.DefaultMutatingWebhookConfiguration)).To(Succeed())

Expect(framework.IsMutatingWebhookConfigurationSynced(client)).To(BeTrue())
})

It("maintains spec after mutating webhook configuration change and preserve caBundle", func() {
client, err := framework.LoadClient()
Expect(err).NotTo(HaveOccurred())

initial, err := framework.GetMutatingWebhookConfiguration(client, framework.DefaultMutatingWebhookConfiguration.Name)
Expect(initial).ToNot(BeNil())
Expect(err).To(Succeed())

toUpdate := initial.DeepCopy()
for _, webhook := range toUpdate.Webhooks {
webhook.ClientConfig.CABundle = []byte("test")
webhook.AdmissionReviewVersions = []string{"test"}
}

Expect(framework.UpdateMutatingWebhookConfiguration(client, toUpdate)).To(Succeed())

Expect(framework.IsMutatingWebhookConfigurationSynced(client)).To(BeTrue())

updated, err := framework.GetMutatingWebhookConfiguration(client, framework.DefaultMutatingWebhookConfiguration.Name)
Expect(updated).ToNot(BeNil())
Expect(err).To(Succeed())

for i, webhook := range updated.Webhooks {
Expect(webhook.ClientConfig.CABundle).To(Equal(initial.Webhooks[i].ClientConfig.CABundle))
}
})

It("maintains spec after validating webhook configuration change and preserve caBundle", func() {
client, err := framework.LoadClient()
Expect(err).NotTo(HaveOccurred())

initial, err := framework.GetValidatingWebhookConfiguration(client, framework.DefaultValidatingWebhookConfiguration.Name)
Expect(initial).ToNot(BeNil())
Expect(err).To(Succeed())

toUpdate := initial.DeepCopy()
for _, webhook := range toUpdate.Webhooks {
webhook.ClientConfig.CABundle = []byte("test")
webhook.AdmissionReviewVersions = []string{"test"}
}

Expect(framework.UpdateValidatingWebhookConfiguration(client, toUpdate)).To(Succeed())

Expect(framework.IsValidatingWebhookConfigurationSynced(client)).To(BeTrue())

updated, err := framework.GetValidatingWebhookConfiguration(client, framework.DefaultValidatingWebhookConfiguration.Name)
Expect(updated).ToNot(BeNil())
Expect(err).To(Succeed())

for i, webhook := range updated.Webhooks {
Expect(webhook.ClientConfig.CABundle).To(Equal(initial.Webhooks[i].ClientConfig.CABundle))
}
})

})

var _ = Describe("[Feature:Operators] Machine API cluster operator status should", func() {
Expand Down
Loading